Skip to content

Commit 7d3efae

Browse files
committed
Merge branch 'pgpainless-sigv6_2'
2 parents 5f5f887 + c5ef9e7 commit 7d3efae

File tree

12 files changed

+1499
-169
lines changed

12 files changed

+1499
-169
lines changed

pg/src/main/java/org/bouncycastle/bcpg/OnePassSignaturePacket.java

Lines changed: 179 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,49 @@
11
package org.bouncycastle.bcpg;
22

3+
import org.bouncycastle.util.Arrays;
4+
import org.bouncycastle.util.io.Streams;
5+
36
import java.io.ByteArrayOutputStream;
47
import 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
*/
927
public 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

Comments
 (0)