11package org .bouncycastle .bcpg ;
22
3+ import org .bouncycastle .util .Arrays ;
4+ import org .bouncycastle .util .io .Streams ;
5+
36import java .io .ByteArrayOutputStream ;
47import java .io .IOException ;
58
69/**
7- * generic signature object
10+ * One-Pass-Signature packet.
11+ * OPS packets are used to enable verification of signed messages in one-pass by providing necessary metadata
12+ * about the signed data up front, so the consumer can start processing the signed data without needing
13+ * to process the signature packet at the end of the data stream first.
14+ * <b>
15+ * There are two versions of this packet currently defined.
16+ * Version 3 OPS packets are used with {@link SignaturePacket SignaturePackets} of version 3 and 4.
17+ * Version 6 OPS packets are used with {@link SignaturePacket SignaturePackets} of version 6.
18+ * It is not clear to me, which version of the OPS packet is intended to be used with version 5 signatures.
19+ *
20+ * @see <a href="https://www.rfc-editor.org/rfc/rfc4880.html#section-5.4">
21+ * Definition of version 3 OPS packets in RFC4880</a>
22+ * @see <a href="https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-13.html#name-one-pass-signature-packet-t">
23+ * Definition of version 3 and 6 OPS packets in crypto-refresh</a>
24+ * @see <a href="https://www.ietf.org/archive/id/draft-koch-librepgp-00.html#section-5.4">
25+ * Definition of version 3 and 6 OPS packets in librepgp</a>
826 */
927public class OnePassSignaturePacket
1028 extends ContainedPacket
1129{
12- private int version ;
13- private int sigType ;
14- private int hashAlgorithm ;
15- private int keyAlgorithm ;
16- private long keyID ;
17- private int isContaining ;
18-
30+ public static final int VERSION_3 = 3 ;
31+ public static final int VERSION_6 = 6 ;
32+
33+ private final int version ;
34+ private final int sigType ;
35+ private final int hashAlgorithm ;
36+ private final int keyAlgorithm ;
37+ private final long keyID ;
38+ private final byte [] fingerprint ;
39+ private final byte [] salt ;
40+ private final int isContaining ;
41+
42+ /**
43+ * Parse a {@link OnePassSignaturePacket} from an OpenPGP packet input stream.
44+ * @param in OpenPGP packet input stream
45+ * @throws IOException when the end of stream is prematurely reached, or when the packet is malformed
46+ */
1947 OnePassSignaturePacket (
2048 BCPGInputStream in )
2149 throws IOException
@@ -26,19 +54,59 @@ public class OnePassSignaturePacket
2654 sigType = in .read ();
2755 hashAlgorithm = in .read ();
2856 keyAlgorithm = in .read ();
29-
30- keyID |= (long )in .read () << 56 ;
31- keyID |= (long )in .read () << 48 ;
32- keyID |= (long )in .read () << 40 ;
33- keyID |= (long )in .read () << 32 ;
34- keyID |= (long )in .read () << 24 ;
35- keyID |= (long )in .read () << 16 ;
36- keyID |= (long )in .read () << 8 ;
37- keyID |= in .read ();
38-
57+
58+ if (version == VERSION_3 )
59+ {
60+ keyID = StreamUtil .readKeyID (in );
61+ fingerprint = null ;
62+ salt = null ;
63+ }
64+ else if (version == VERSION_6 )
65+ {
66+ int saltLen = in .read ();
67+ if (saltLen < 0 )
68+ {
69+ throw new IOException ("Version 6 OPS packet has invalid salt length." );
70+ }
71+ salt = new byte [saltLen ];
72+ in .readFully (salt );
73+
74+ fingerprint = new byte [32 ];
75+ in .readFully (fingerprint );
76+
77+ // TODO: Replace with FingerprintUtil
78+ keyID = ((fingerprint [0 ] & 0xffL ) << 56 ) |
79+ ((fingerprint [1 ] & 0xffL ) << 48 ) |
80+ ((fingerprint [2 ] & 0xffL ) << 40 ) |
81+ ((fingerprint [3 ] & 0xffL ) << 32 ) |
82+ ((fingerprint [4 ] & 0xffL ) << 24 ) |
83+ ((fingerprint [5 ] & 0xffL ) << 16 ) |
84+ ((fingerprint [6 ] & 0xffL ) << 8 ) |
85+ ((fingerprint [7 ] & 0xffL ));
86+ }
87+ else
88+ {
89+ Streams .drain (in );
90+ throw new UnsupportedPacketVersionException ("Unsupported OnePassSignature packet version encountered: " + version );
91+ }
92+
3993 isContaining = in .read ();
4094 }
41-
95+
96+ /**
97+ * Create a version 3 {@link OnePassSignaturePacket}.
98+ * Version 3 OPS packets are used with version 3 and version 4 {@link SignaturePacket SignaturePackets}.
99+ * <b>
100+ * To create an OPS packet for use with a version 6 {@link SignaturePacket},
101+ * see {@link OnePassSignaturePacket#OnePassSignaturePacket(int, int, int, byte[], byte[], boolean)}.
102+ *
103+ * @param sigType signature type
104+ * @param hashAlgorithm hash algorithm tag
105+ * @param keyAlgorithm public key algorithm tag
106+ * @param keyID id of the signing key
107+ * @param isNested if false, there is another OPS packet after this one, which applies to the same data.
108+ * it true, the corresponding signature is calculated also over succeeding additional OPS packets.
109+ */
42110 public OnePassSignaturePacket (
43111 int sigType ,
44112 int hashAlgorithm ,
@@ -48,14 +116,64 @@ public OnePassSignaturePacket(
48116 {
49117 super (ONE_PASS_SIGNATURE );
50118
51- this .version = 3 ;
119+ this .version = VERSION_3 ;
52120 this .sigType = sigType ;
53121 this .hashAlgorithm = hashAlgorithm ;
54122 this .keyAlgorithm = keyAlgorithm ;
55123 this .keyID = keyID ;
124+ this .fingerprint = null ;
125+ this .salt = null ;
56126 this .isContaining = (isNested ) ? 0 : 1 ;
57127 }
58-
128+
129+ /**
130+ * Create a version 6 {@link OnePassSignaturePacket}.
131+ *
132+ * @param sigType signature type
133+ * @param hashAlgorithm hash algorithm tag
134+ * @param keyAlgorithm public key algorithm tag
135+ * @param salt random salt. The length of this array depends on the hash algorithm in use.
136+ * @param fingerprint 32 octet fingerprint of the (v6) signing key
137+ * @param isNested if false, there is another OPS packet after this one, which applies to the same data.
138+ * it true, the corresponding signature is calculated also over succeeding additional OPS packets.
139+ */
140+ public OnePassSignaturePacket (
141+ int sigType ,
142+ int hashAlgorithm ,
143+ int keyAlgorithm ,
144+ byte [] salt ,
145+ byte [] fingerprint ,
146+ boolean isNested )
147+ {
148+ super (ONE_PASS_SIGNATURE );
149+
150+ this .version = VERSION_6 ;
151+ this .sigType = sigType ;
152+ this .hashAlgorithm = hashAlgorithm ;
153+ this .keyAlgorithm = keyAlgorithm ;
154+ this .salt = salt ;
155+ this .fingerprint = fingerprint ;
156+ this .isContaining = (isNested ) ? 0 : 1 ;
157+ // TODO: Replace with FingerprintUtil
158+ keyID = ((fingerprint [0 ] & 0xffL ) << 56 ) |
159+ ((fingerprint [1 ] & 0xffL ) << 48 ) |
160+ ((fingerprint [2 ] & 0xffL ) << 40 ) |
161+ ((fingerprint [3 ] & 0xffL ) << 32 ) |
162+ ((fingerprint [4 ] & 0xffL ) << 24 ) |
163+ ((fingerprint [5 ] & 0xffL ) << 16 ) |
164+ ((fingerprint [6 ] & 0xffL ) << 8 ) |
165+ ((fingerprint [7 ] & 0xffL ));
166+ }
167+
168+ /**
169+ * Return the packet version.
170+ * @return version
171+ */
172+ public int getVersion ()
173+ {
174+ return version ;
175+ }
176+
59177 /**
60178 * Return the signature type.
61179 * @return the signature type
@@ -66,32 +184,55 @@ public int getSignatureType()
66184 }
67185
68186 /**
69- * return the encryption algorithm tag
187+ * Return the ID of the public key encryption algorithm.
188+ * @return public key algorithm tag
70189 */
71190 public int getKeyAlgorithm ()
72191 {
73192 return keyAlgorithm ;
74193 }
75194
76195 /**
77- * return the hashAlgorithm tag
196+ * Return the algorithm ID of the hash algorithm.
197+ * @return hash algorithm tag
78198 */
79199 public int getHashAlgorithm ()
80200 {
81201 return hashAlgorithm ;
82202 }
83203
84204 /**
85- * @return long
205+ * Return the key-id of the signing key.
206+ * @return key id
86207 */
87208 public long getKeyID ()
88209 {
89210 return keyID ;
90211 }
91212
213+ /**
214+ * Return the version 6 fingerprint of the issuer.
215+ * Only for version 6 packets.
216+ * @return 32 bytes issuer fingerprint
217+ */
218+ public byte [] getFingerprint ()
219+ {
220+ return Arrays .clone (fingerprint );
221+ }
222+
223+ /**
224+ * Return the salt used in the signature.
225+ * Only for version 6 packets.
226+ * @return salt
227+ */
228+ public byte [] getSalt ()
229+ {
230+ return Arrays .clone (salt );
231+ }
232+
92233 /**
93234 * Return true, if the signature contains any signatures that follow.
94- * An bracketing OPS is followed by additional OPS packets and is calculated over all the data between itself
235+ * A bracketing OPS is followed by additional OPS packets and is calculated over all the data between itself
95236 * and its corresponding signature (it is an attestation for encapsulated signatures).
96237 *
97238 * @return true if encapsulating, false otherwise
@@ -102,7 +243,9 @@ public boolean isContaining()
102243 }
103244
104245 /**
105- *
246+ * Encode the contents of this packet into the given packet output stream.
247+ *
248+ * @param out OpenPGP packet output stream
106249 */
107250 public void encode (
108251 BCPGOutputStream out )
@@ -116,7 +259,16 @@ public void encode(
116259 pOut .write (hashAlgorithm );
117260 pOut .write (keyAlgorithm );
118261
119- StreamUtil .writeKeyID (pOut , keyID );
262+ if (version == VERSION_3 )
263+ {
264+ StreamUtil .writeKeyID (pOut , keyID );
265+ }
266+ else if (version == VERSION_6 )
267+ {
268+ pOut .write (salt .length );
269+ pOut .write (salt );
270+ pOut .write (fingerprint );
271+ }
120272
121273 pOut .write (isContaining );
122274
0 commit comments