Skip to content

Commit a35269f

Browse files
committed
Tidied the CMS key agreement recipient and generator: the agreement is now run once after the parameters are chosen, the mandatory-ukm check for static-static DH and GOST is made once up front, KeyMaterialGenerator is documented, and the jdk1.1 generator gains the GOST agreement and key wrap the jdk1.1 recipient already supported.
1 parent cfadddd commit a35269f

5 files changed

Lines changed: 113 additions & 101 deletions

File tree

‎pkix/src/main/java/org/bouncycastle/cms/jcajce/JceKeyAgreeRecipient.java‎

Lines changed: 22 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
import java.security.PrivateKey;
1010
import java.security.Provider;
1111
import java.security.PublicKey;
12+
import java.security.spec.AlgorithmParameterSpec;
1213
import java.security.spec.InvalidKeySpecException;
1314
import java.security.spec.X509EncodedKeySpec;
1415
import java.util.HashSet;
@@ -198,9 +199,13 @@ private SecretKey calculateAgreedWrapKey(AlgorithmIdentifier keyEncAlg, Algorith
198199
PublicKey senderPublicKey, ASN1OctetString userKeyingMaterial, PrivateKey receiverPrivateKey, KeyMaterialGenerator kmGen)
199200
throws CMSException, GeneralSecurityException, IOException
200201
{
202+
ASN1ObjectIdentifier agreeAlgOID = keyEncAlg.getAlgorithm();
203+
201204
receiverPrivateKey = CMSUtils.cleanPrivateKey(receiverPrivateKey);
202205

203-
if (isMQV(keyEncAlg.getAlgorithm()))
206+
AlgorithmParameterSpec initParams = null;
207+
208+
if (isMQV(agreeAlgOID))
204209
{
205210
MQVuserKeyingMaterial ukm = MQVuserKeyingMaterial.getInstance(userKeyingMaterial.getOctets());
206211

@@ -209,29 +214,20 @@ private SecretKey calculateAgreedWrapKey(AlgorithmIdentifier keyEncAlg, Algorith
209214
ukm.getEphemeralPublicKey().getPublicKeyData());
210215

211216
X509EncodedKeySpec pubSpec = new X509EncodedKeySpec(pubInfo.getEncoded());
212-
KeyFactory fact = helper.createKeyFactory(keyEncAlg.getAlgorithm());
217+
KeyFactory fact = helper.createKeyFactory(agreeAlgOID);
213218
PublicKey ephemeralKey = fact.generatePublic(pubSpec);
214219

215-
KeyAgreement agreement = helper.createKeyAgreement(keyEncAlg.getAlgorithm());
216-
217220
byte[] ukmKeyingMaterial = (ukm.getAddedukm() != null) ? ukm.getAddedukm().getOctets() : null;
218221
if (kmGen == old_ecc_cms_Generator)
219222
{
220223
ukmKeyingMaterial = old_ecc_cms_Generator.generateKDFMaterial(wrapAlg, keySizeProvider.getKeySize(wrapAlg), ukmKeyingMaterial);
221224
}
222225

223-
agreement.init(receiverPrivateKey, new MQVParameterSpec(receiverPrivateKey, ephemeralKey, ukmKeyingMaterial));
224-
agreement.doPhase(senderPublicKey, true);
225-
226-
return agreement.generateSecret(wrapAlg.getAlgorithm().getId());
226+
initParams = new MQVParameterSpec(receiverPrivateKey, ephemeralKey, ukmKeyingMaterial);
227227
}
228228
else
229229
{
230-
KeyAgreement agreement = helper.createKeyAgreement(keyEncAlg.getAlgorithm());
231-
232-
UserKeyingMaterialSpec userKeyingMaterialSpec = null;
233-
234-
if (isEC(keyEncAlg.getAlgorithm()))
230+
if (isEC(agreeAlgOID))
235231
{
236232
byte[] ukmKeyingMaterial;
237233
if (userKeyingMaterial != null)
@@ -244,40 +240,41 @@ private SecretKey calculateAgreedWrapKey(AlgorithmIdentifier keyEncAlg, Algorith
244240
}
245241
// RFC 8418 sec. 2.2: for the HKDF schemes a ukm is both the entityUInfo of the
246242
// ECC-CMS-SharedInfo and the HKDF salt
247-
if (userKeyingMaterial != null && isHKDF(keyEncAlg.getAlgorithm()))
243+
if (userKeyingMaterial != null && isHKDF(agreeAlgOID))
248244
{
249-
userKeyingMaterialSpec = new UserKeyingMaterialSpec(ukmKeyingMaterial, userKeyingMaterial.getOctets());
245+
initParams = new UserKeyingMaterialSpec(ukmKeyingMaterial, userKeyingMaterial.getOctets());
250246
}
251247
else
252248
{
253-
userKeyingMaterialSpec = new UserKeyingMaterialSpec(ukmKeyingMaterial);
249+
initParams = new UserKeyingMaterialSpec(ukmKeyingMaterial);
254250
}
255251
}
256-
else if (isRFC2631(keyEncAlg.getAlgorithm()))
252+
else if (isRFC2631(agreeAlgOID))
257253
{
258254
if (userKeyingMaterial != null)
259255
{
260-
userKeyingMaterialSpec = new UserKeyingMaterialSpec(userKeyingMaterial.getOctets());
256+
initParams = new UserKeyingMaterialSpec(userKeyingMaterial.getOctets());
261257
}
262258
}
263-
else if (isGOST(keyEncAlg.getAlgorithm()))
259+
else if (isGOST(agreeAlgOID))
264260
{
265261
if (userKeyingMaterial != null)
266262
{
267-
userKeyingMaterialSpec = new UserKeyingMaterialSpec(userKeyingMaterial.getOctets());
263+
initParams = new UserKeyingMaterialSpec(userKeyingMaterial.getOctets());
268264
}
269265
}
270266
else
271267
{
272-
throw new CMSException("Unknown key agreement algorithm: " + keyEncAlg.getAlgorithm());
268+
throw new CMSException("Unknown key agreement algorithm: " + agreeAlgOID);
273269
}
270+
}
274271

275-
agreement.init(receiverPrivateKey, userKeyingMaterialSpec);
272+
KeyAgreement agreement = helper.createKeyAgreement(agreeAlgOID);
276273

277-
agreement.doPhase(senderPublicKey, true);
274+
agreement.init(receiverPrivateKey, initParams);
275+
agreement.doPhase(senderPublicKey, true);
278276

279-
return agreement.generateSecret(wrapAlg.getAlgorithm().getId());
280-
}
277+
return agreement.generateSecret(wrapAlg.getAlgorithm().getId());
281278
}
282279

283280
protected Key unwrapSessionKey(ASN1ObjectIdentifier wrapAlg, SecretKey agreedKey, ASN1ObjectIdentifier contentEncryptionAlgorithm, byte[] encryptedContentEncryptionKey)

‎pkix/src/main/java/org/bouncycastle/cms/jcajce/JceKeyAgreeRecipientInfoGenerator.java‎

Lines changed: 11 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -156,6 +156,14 @@ public ASN1Sequence generateRecipientEncryptedKeys(AlgorithmIdentifier keyAgreeA
156156

157157
ASN1ObjectIdentifier keyAgreementOID = keyAgreeAlgorithm.getAlgorithm();
158158

159+
// RFC 3370 sec. 4.1.2 (static-static DH) and RFC 4490 sec. 4.1.1 (GOST): the ukm MUST be present
160+
// TODO Consider delegating to an OID classifier for static-key agreement schemes
161+
if (userKeyingMaterial == null
162+
&& (PKCSObjectIdentifiers.id_alg_SSDH.equals(keyAgreementOID) || isGOST(keyAgreementOID)))
163+
{
164+
throw new CMSException("User keying material must be set for static keys.");
165+
}
166+
159167
init(keyAgreementOID);
160168

161169
PrivateKey senderPrivateKey = this.senderPrivateKey;
@@ -168,7 +176,7 @@ public ASN1Sequence generateRecipientEncryptedKeys(AlgorithmIdentifier keyAgreeA
168176

169177
try
170178
{
171-
AlgorithmParameterSpec agreementParamSpec;
179+
AlgorithmParameterSpec agreementParamSpec = null;
172180
ASN1ObjectIdentifier keyEncryptionOID = keyEncryptionAlgorithm.getAlgorithm();
173181

174182
if (isMQV(keyAgreementOID))
@@ -191,31 +199,13 @@ else if (isEC(keyAgreementOID))
191199
agreementParamSpec = new UserKeyingMaterialSpec(ukmKeyingMaterial);
192200
}
193201
}
194-
else if (isRFC2631(keyAgreementOID))
202+
else if (isGOST(keyAgreementOID) ||
203+
isRFC2631(keyAgreementOID))
195204
{
196205
if (userKeyingMaterial != null)
197206
{
198207
agreementParamSpec = new UserKeyingMaterialSpec(userKeyingMaterial);
199208
}
200-
else
201-
{
202-
if (keyAgreementOID.equals(PKCSObjectIdentifiers.id_alg_SSDH))
203-
{
204-
throw new CMSException("User keying material must be set for static keys.");
205-
}
206-
agreementParamSpec = null;
207-
}
208-
}
209-
else if (isGOST(keyAgreementOID))
210-
{
211-
if (userKeyingMaterial != null)
212-
{
213-
agreementParamSpec = new UserKeyingMaterialSpec(userKeyingMaterial);
214-
}
215-
else
216-
{
217-
throw new CMSException("User keying material must be set for static keys.");
218-
}
219209
}
220210
else
221211
{

‎pkix/src/main/java/org/bouncycastle/cms/jcajce/KeyMaterialGenerator.java‎

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,5 +4,18 @@
44

55
interface KeyMaterialGenerator
66
{
7+
/**
8+
* Generate the KDF "other info" material for a key agreement, typically a DER-encoded
9+
* ECC-CMS-SharedInfo (RFC 5753).
10+
*
11+
* @param keyAlgorithm the algorithm identifier of the key being derived (the key wrap algorithm);
12+
* an implementation may bind this into the material, or ignore it.
13+
* @param keySize the size of the key being derived, in bits; an implementation may bind this into
14+
* the material, or ignore it. It does not determine the length of the derived key.
15+
* @param userKeyMaterialParameters the user keying material (ukm) from the message, or null if there is none.
16+
* @return the KDF material, or null if there is none. An implementation may return
17+
* userKeyMaterialParameters itself rather than a copy, which calling code should take into
18+
* consideration in determining ownership of the result.
19+
*/
720
byte[] generateKDFMaterial(AlgorithmIdentifier keyAlgorithm, int keySize, byte[] userKeyMaterialParameters);
821
}

‎pkix/src/main/jdk1.1/org/bouncycastle/cms/jcajce/JceKeyAgreeRecipient.java‎

Lines changed: 25 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
import java.security.PrivateKey;
1010
import java.security.Provider;
1111
import java.security.PublicKey;
12+
import java.security.spec.AlgorithmParameterSpec;
1213
import java.security.spec.InvalidKeySpecException;
1314
import java.security.spec.X509EncodedKeySpec;
1415
import java.util.HashSet;
@@ -138,9 +139,13 @@ private SecretKey calculateAgreedWrapKey(AlgorithmIdentifier keyEncAlg, Algorith
138139
PublicKey senderPublicKey, ASN1OctetString userKeyingMaterial, PrivateKey receiverPrivateKey, KeyMaterialGenerator kmGen)
139140
throws CMSException, GeneralSecurityException, IOException
140141
{
142+
ASN1ObjectIdentifier agreeAlgOID = keyEncAlg.getAlgorithm();
143+
141144
receiverPrivateKey = CMSUtils.cleanPrivateKey(receiverPrivateKey);
142145

143-
if (CMSUtils.isMQV(keyEncAlg.getAlgorithm()))
146+
AlgorithmParameterSpec initParams = null;
147+
148+
if (CMSUtils.isMQV(agreeAlgOID))
144149
{
145150
MQVuserKeyingMaterial ukm = MQVuserKeyingMaterial.getInstance(userKeyingMaterial.getOctets());
146151

@@ -149,81 +154,66 @@ private SecretKey calculateAgreedWrapKey(AlgorithmIdentifier keyEncAlg, Algorith
149154
ukm.getEphemeralPublicKey().getPublicKey().getBytes());
150155

151156
X509EncodedKeySpec pubSpec = new X509EncodedKeySpec(pubInfo.getEncoded());
152-
KeyFactory fact = helper.createKeyFactory(keyEncAlg.getAlgorithm());
157+
KeyFactory fact = helper.createKeyFactory(agreeAlgOID);
153158
PublicKey ephemeralKey = fact.generatePublic(pubSpec);
154159

155-
KeyAgreement agreement = helper.createKeyAgreement(keyEncAlg.getAlgorithm());
156-
157160
byte[] ukmKeyingMaterial = (ukm.getAddedukm() != null) ? ukm.getAddedukm().getOctets() : null;
158161
if (kmGen == old_ecc_cms_Generator)
159162
{
160163
ukmKeyingMaterial = old_ecc_cms_Generator.generateKDFMaterial(wrapAlg, keySizeProvider.getKeySize(wrapAlg), ukmKeyingMaterial);
161164
}
162165

163-
try
164-
{
165-
agreement.init(receiverPrivateKey, new MQVParameterSpec(receiverPrivateKey, ephemeralKey, ukmKeyingMaterial));
166-
agreement.doPhase(senderPublicKey, true);
167-
168-
return agreement.generateSecret(wrapAlg.getAlgorithm().getId());
169-
}
170-
catch (Exception e)
171-
{
172-
throw new GeneralSecurityException(e.toString());
173-
}
166+
initParams = new MQVParameterSpec(receiverPrivateKey, ephemeralKey, ukmKeyingMaterial);
174167
}
175168
else
176169
{
177-
KeyAgreement agreement = helper.createKeyAgreement(keyEncAlg.getAlgorithm());
178-
179-
UserKeyingMaterialSpec userKeyingMaterialSpec = null;
180-
181-
if (CMSUtils.isEC(keyEncAlg.getAlgorithm()))
170+
if (CMSUtils.isEC(agreeAlgOID))
182171
{
183172
if (userKeyingMaterial != null)
184173
{
185174
byte[] ukmKeyingMaterial = kmGen.generateKDFMaterial(wrapAlg, keySizeProvider.getKeySize(wrapAlg), userKeyingMaterial.getOctets());
186175

187-
userKeyingMaterialSpec = new UserKeyingMaterialSpec(ukmKeyingMaterial);
176+
initParams = new UserKeyingMaterialSpec(ukmKeyingMaterial);
188177
}
189178
else
190179
{
191180
byte[] ukmKeyingMaterial = kmGen.generateKDFMaterial(wrapAlg, keySizeProvider.getKeySize(wrapAlg), null);
192181

193-
userKeyingMaterialSpec = new UserKeyingMaterialSpec(ukmKeyingMaterial);
182+
initParams = new UserKeyingMaterialSpec(ukmKeyingMaterial);
194183
}
195184
}
196-
else if (CMSUtils.isRFC2631(keyEncAlg.getAlgorithm()))
185+
else if (CMSUtils.isRFC2631(agreeAlgOID))
197186
{
198187
if (userKeyingMaterial != null)
199188
{
200-
userKeyingMaterialSpec = new UserKeyingMaterialSpec(userKeyingMaterial.getOctets());
189+
initParams = new UserKeyingMaterialSpec(userKeyingMaterial.getOctets());
201190
}
202191
}
203-
else if (CMSUtils.isGOST(keyEncAlg.getAlgorithm()))
192+
else if (CMSUtils.isGOST(agreeAlgOID))
204193
{
205194
if (userKeyingMaterial != null)
206195
{
207-
userKeyingMaterialSpec = new UserKeyingMaterialSpec(userKeyingMaterial.getOctets());
196+
initParams = new UserKeyingMaterialSpec(userKeyingMaterial.getOctets());
208197
}
209198
}
210199
else
211200
{
212-
throw new CMSException("Unknown key agreement algorithm: " + keyEncAlg.getAlgorithm());
201+
throw new CMSException("Unknown key agreement algorithm: " + agreeAlgOID);
213202
}
203+
}
214204

215-
try
216-
{
217-
agreement.init(receiverPrivateKey, userKeyingMaterialSpec);
205+
KeyAgreement agreement = helper.createKeyAgreement(agreeAlgOID);
218206

207+
try
208+
{
209+
agreement.init(receiverPrivateKey, initParams);
219210
agreement.doPhase(senderPublicKey, true);
220211

221212
return agreement.generateSecret(wrapAlg.getAlgorithm().getId());
222-
}
223-
catch (Exception e)
224-
{
225-
throw new GeneralSecurityException(e.toString());
226-
}
213+
}
214+
catch (Exception e)
215+
{
216+
throw new GeneralSecurityException(e.toString());
227217
}
228218
}
229219

0 commit comments

Comments
 (0)