1
1
package org .bouncycastle .bcpg ;
2
2
3
+ import org .bouncycastle .util .io .Streams ;
4
+
3
5
import java .io .ByteArrayOutputStream ;
4
6
import java .io .IOException ;
5
7
6
8
/**
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>
8
25
*/
9
26
public class OnePassSignaturePacket
10
27
extends ContainedPacket
11
28
{
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
+ */
19
46
OnePassSignaturePacket (
20
47
BCPGInputStream in )
21
48
throws IOException
@@ -26,19 +53,58 @@ public class OnePassSignaturePacket
26
53
sigType = in .read ();
27
54
hashAlgorithm = in .read ();
28
55
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
+
39
91
isContaining = in .read ();
40
92
}
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
+ */
42
108
public OnePassSignaturePacket (
43
109
int sigType ,
44
110
int hashAlgorithm ,
@@ -48,14 +114,63 @@ public OnePassSignaturePacket(
48
114
{
49
115
super (ONE_PASS_SIGNATURE );
50
116
51
- this .version = 3 ;
117
+ this .version = VERSION_3 ;
52
118
this .sigType = sigType ;
53
119
this .hashAlgorithm = hashAlgorithm ;
54
120
this .keyAlgorithm = keyAlgorithm ;
55
121
this .keyID = keyID ;
122
+ this .fingerprint = null ;
123
+ this .salt = null ;
56
124
this .isContaining = (isNested ) ? 0 : 1 ;
57
125
}
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
+
59
174
/**
60
175
* Return the signature type.
61
176
* @return the signature type
@@ -66,32 +181,53 @@ public int getSignatureType()
66
181
}
67
182
68
183
/**
69
- * return the encryption algorithm tag
184
+ * Return the ID of the public key encryption algorithm.
185
+ * @return public key algorithm tag
70
186
*/
71
187
public int getKeyAlgorithm ()
72
188
{
73
189
return keyAlgorithm ;
74
190
}
75
191
76
192
/**
77
- * return the hashAlgorithm tag
193
+ * Return the algorithm ID of the hash algorithm.
194
+ * @return hash algorithm tag
78
195
*/
79
196
public int getHashAlgorithm ()
80
197
{
81
198
return hashAlgorithm ;
82
199
}
83
200
84
201
/**
85
- * @return long
202
+ * Return the key-id of the signing key.
203
+ * @return key id
86
204
*/
87
205
public long getKeyID ()
88
206
{
89
207
return keyID ;
90
208
}
91
209
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
+
92
228
/**
93
229
* 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
95
231
* and its corresponding signature (it is an attestation for encapsulated signatures).
96
232
*
97
233
* @return true if encapsulating, false otherwise
@@ -102,7 +238,9 @@ public boolean isContaining()
102
238
}
103
239
104
240
/**
105
- *
241
+ * Encode the contents of this packet into the given packet output stream.
242
+ *
243
+ * @param out OpenPGP packet output stream
106
244
*/
107
245
public void encode (
108
246
BCPGOutputStream out )
@@ -116,7 +254,16 @@ public void encode(
116
254
pOut .write (hashAlgorithm );
117
255
pOut .write (keyAlgorithm );
118
256
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
+ }
120
267
121
268
pOut .write (isContaining );
122
269
0 commit comments