11package org .bouncycastle .bcpg ;
22
3+ import org .bouncycastle .util .io .Streams ;
4+
35import java .io .ByteArrayOutputStream ;
46import java .io .IOException ;
57
68/**
7- * generic signature object
9+ * One-Pass-Signature packet.
10+ * OPS packets are used to enable verification of signed messages in one-pass by providing necessary metadata
11+ * about the signed data up front, so the consumer can start processing the signed data without needing
12+ * to process the signature packet at the end of the data stream first.
13+ * <b>
14+ * There are two versions of this packet currently defined.
15+ * Version 3 OPS packets are used with {@link SignaturePacket SignaturePackets} of version 3 and 4.
16+ * Version 6 OPS packets are used with {@link SignaturePacket SignaturePackets} of version 6.
17+ * It is not clear to me, which version of the OPS packet is intended to be used with version 5 signatures.
18+ *
19+ * @see <a href="https://www.rfc-editor.org/rfc/rfc4880.html#section-5.4">
20+ * Definition of version 3 OPS packets in RFC4880</a>
21+ * @see <a href="https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-13.html#name-one-pass-signature-packet-t">
22+ * Definition of version 3 and 6 OPS packets in crypto-refresh</a>
23+ * @see <a href="https://www.ietf.org/archive/id/draft-koch-librepgp-00.html#section-5.4">
24+ * Definition of version 3 and 6 OPS packets in librepgp</a>
825 */
926public class OnePassSignaturePacket
1027 extends ContainedPacket
1128{
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-
29+ public static final int VERSION_3 = 3 ;
30+ public static final int VERSION_6 = 6 ;
31+
32+ private final int version ;
33+ private final int sigType ;
34+ private final int hashAlgorithm ;
35+ private final int keyAlgorithm ;
36+ private final long keyID ;
37+ private final byte [] fingerprint ;
38+ private final byte [] salt ;
39+ private final int isContaining ;
40+
41+ /**
42+ * Parse a {@link OnePassSignaturePacket} from an OpenPGP packet input stream.
43+ * @param in OpenPGP packet input stream
44+ * @throws IOException when the end of stream is prematurely reached, or when the packet is malformed
45+ */
1946 OnePassSignaturePacket (
2047 BCPGInputStream in )
2148 throws IOException
@@ -26,19 +53,58 @@ public class OnePassSignaturePacket
2653 sigType = in .read ();
2754 hashAlgorithm = in .read ();
2855 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-
56+
57+ if (version == VERSION_3 )
58+ {
59+ keyID = StreamUtil .readKeyID (in );
60+ fingerprint = null ;
61+ salt = null ;
62+ }
63+ else if (version == VERSION_6 )
64+ {
65+ int saltLen = in .read ();
66+ if (saltLen < 0 ) {
67+ throw new IOException ("Version 6 OPS packet has invalid salt length." );
68+ }
69+ salt = new byte [saltLen ];
70+ in .readFully (salt );
71+
72+ fingerprint = new byte [32 ];
73+ in .readFully (fingerprint );
74+
75+ // TODO: Replace with FingerprintUtil
76+ keyID = ((fingerprint [0 ] & 0xffL ) << 56 ) |
77+ ((fingerprint [1 ] & 0xffL ) << 48 ) |
78+ ((fingerprint [2 ] & 0xffL ) << 40 ) |
79+ ((fingerprint [3 ] & 0xffL ) << 32 ) |
80+ ((fingerprint [4 ] & 0xffL ) << 24 ) |
81+ ((fingerprint [5 ] & 0xffL ) << 16 ) |
82+ ((fingerprint [6 ] & 0xffL ) << 8 ) |
83+ ((fingerprint [7 ] & 0xffL ));
84+ }
85+ else
86+ {
87+ Streams .drain (in );
88+ throw new UnsupportedPacketVersionException ("Unsupported OnePassSignature packet version encountered: " + version );
89+ }
90+
3991 isContaining = in .read ();
4092 }
41-
93+
94+ /**
95+ * Create a version 3 {@link OnePassSignaturePacket}.
96+ * Version 3 OPS packets are used with version 3 and version 4 {@link SignaturePacket SignaturePackets}.
97+ * <b>
98+ * To create an OPS packet for use with a version 6 {@link SignaturePacket},
99+ * see {@link OnePassSignaturePacket#OnePassSignaturePacket(int, int, int, byte[], byte[], boolean)}.
100+ *
101+ * @param sigType signature type
102+ * @param hashAlgorithm hash algorithm tag
103+ * @param keyAlgorithm public key algorithm tag
104+ * @param keyID id of the signing key
105+ * @param isNested if false, there is another OPS packet after this one, which applies to the same data.
106+ * it true, the corresponding signature is calculated also over succeeding additional OPS packets.
107+ */
42108 public OnePassSignaturePacket (
43109 int sigType ,
44110 int hashAlgorithm ,
@@ -48,14 +114,63 @@ public OnePassSignaturePacket(
48114 {
49115 super (ONE_PASS_SIGNATURE );
50116
51- this .version = 3 ;
117+ this .version = VERSION_3 ;
52118 this .sigType = sigType ;
53119 this .hashAlgorithm = hashAlgorithm ;
54120 this .keyAlgorithm = keyAlgorithm ;
55121 this .keyID = keyID ;
122+ this .fingerprint = null ;
123+ this .salt = null ;
56124 this .isContaining = (isNested ) ? 0 : 1 ;
57125 }
58-
126+
127+ /**
128+ * Create a version 6 {@link OnePassSignaturePacket}.
129+ *
130+ * @param sigType signature type
131+ * @param hashAlgorithm hash algorithm tag
132+ * @param keyAlgorithm public key algorithm tag
133+ * @param salt random salt. The length of this array depends on the hash algorithm in use.
134+ * @param fingerprint 32 octet fingerprint of the (v6) signing key
135+ * @param isNested if false, there is another OPS packet after this one, which applies to the same data.
136+ * it true, the corresponding signature is calculated also over succeeding additional OPS packets.
137+ */
138+ public OnePassSignaturePacket (
139+ int sigType ,
140+ int hashAlgorithm ,
141+ int keyAlgorithm ,
142+ byte [] salt ,
143+ byte [] fingerprint ,
144+ boolean isNested )
145+ {
146+ super (ONE_PASS_SIGNATURE );
147+
148+ this .version = VERSION_6 ;
149+ this .sigType = sigType ;
150+ this .hashAlgorithm = hashAlgorithm ;
151+ this .keyAlgorithm = keyAlgorithm ;
152+ this .salt = salt ;
153+ this .fingerprint = fingerprint ;
154+ this .isContaining = (isNested ) ? 0 : 1 ;
155+ // TODO: Replace with FingerprintUtil
156+ keyID = ((fingerprint [0 ] & 0xffL ) << 56 ) |
157+ ((fingerprint [1 ] & 0xffL ) << 48 ) |
158+ ((fingerprint [2 ] & 0xffL ) << 40 ) |
159+ ((fingerprint [3 ] & 0xffL ) << 32 ) |
160+ ((fingerprint [4 ] & 0xffL ) << 24 ) |
161+ ((fingerprint [5 ] & 0xffL ) << 16 ) |
162+ ((fingerprint [6 ] & 0xffL ) << 8 ) |
163+ ((fingerprint [7 ] & 0xffL ));
164+ }
165+
166+ /**
167+ * Return the packet version.
168+ * @return version
169+ */
170+ public int getVersion () {
171+ return version ;
172+ }
173+
59174 /**
60175 * Return the signature type.
61176 * @return the signature type
@@ -66,32 +181,53 @@ public int getSignatureType()
66181 }
67182
68183 /**
69- * return the encryption algorithm tag
184+ * Return the ID of the public key encryption algorithm.
185+ * @return public key algorithm tag
70186 */
71187 public int getKeyAlgorithm ()
72188 {
73189 return keyAlgorithm ;
74190 }
75191
76192 /**
77- * return the hashAlgorithm tag
193+ * Return the algorithm ID of the hash algorithm.
194+ * @return hash algorithm tag
78195 */
79196 public int getHashAlgorithm ()
80197 {
81198 return hashAlgorithm ;
82199 }
83200
84201 /**
85- * @return long
202+ * Return the key-id of the signing key.
203+ * @return key id
86204 */
87205 public long getKeyID ()
88206 {
89207 return keyID ;
90208 }
91209
210+ /**
211+ * Return the version 6 fingerprint of the issuer.
212+ * Only for version 6 packets.
213+ * @return 32 bytes issuer fingerprint
214+ */
215+ public byte [] getFingerprint () {
216+ return fingerprint ;
217+ }
218+
219+ /**
220+ * Return the salt used in the signature.
221+ * Only for version 6 packets.
222+ * @return salt
223+ */
224+ public byte [] getSalt () {
225+ return salt ;
226+ }
227+
92228 /**
93229 * 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
230+ * A bracketing OPS is followed by additional OPS packets and is calculated over all the data between itself
95231 * and its corresponding signature (it is an attestation for encapsulated signatures).
96232 *
97233 * @return true if encapsulating, false otherwise
@@ -102,7 +238,9 @@ public boolean isContaining()
102238 }
103239
104240 /**
105- *
241+ * Encode the contents of this packet into the given packet output stream.
242+ *
243+ * @param out OpenPGP packet output stream
106244 */
107245 public void encode (
108246 BCPGOutputStream out )
@@ -116,7 +254,16 @@ public void encode(
116254 pOut .write (hashAlgorithm );
117255 pOut .write (keyAlgorithm );
118256
119- StreamUtil .writeKeyID (pOut , keyID );
257+ if (version == VERSION_3 )
258+ {
259+ StreamUtil .writeKeyID (pOut , keyID );
260+ }
261+ else if (version == VERSION_6 )
262+ {
263+ pOut .write (salt .length );
264+ pOut .write (salt );
265+ pOut .write (fingerprint );
266+ }
120267
121268 pOut .write (isContaining );
122269
0 commit comments