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