Skip to content

Commit aba60a9

Browse files
committedJan 27, 2025
8189441: Define algorithm names for keys derived from KeyAgreement
Reviewed-by: mullan
1 parent 03106eb commit aba60a9

File tree

10 files changed

+162
-46
lines changed

10 files changed

+162
-46
lines changed
 

‎src/java.base/share/classes/com/sun/crypto/provider/DHKeyAgreement.java

+14-11
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 1997, 2024, Oracle and/or its affiliates. All rights reserved.
2+
* Copyright (c) 1997, 2025, Oracle and/or its affiliates. All rights reserved.
33
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
44
*
55
* This code is free software; you can redistribute it and/or modify it
@@ -379,11 +379,10 @@ protected SecretKey engineGenerateSecret(String algorithm)
379379
throw new NoSuchAlgorithmException("null algorithm");
380380
}
381381

382-
if (!algorithm.equalsIgnoreCase("TlsPremasterSecret") &&
383-
!AllowKDF.VALUE) {
384-
385-
throw new NoSuchAlgorithmException("Unsupported secret key "
386-
+ "algorithm: " + algorithm);
382+
if (!KeyUtil.isSupportedKeyAgreementOutputAlgorithm(algorithm) &&
383+
!AllowKDF.VALUE) {
384+
throw new NoSuchAlgorithmException(
385+
"Unsupported secret key algorithm: " + algorithm);
387386
}
388387

389388
byte[] secret = engineGenerateSecret();
@@ -419,13 +418,17 @@ protected SecretKey engineGenerateSecret(String algorithm)
419418
throw new InvalidKeyException("Key material is too short");
420419
}
421420
return skey;
422-
} else if (algorithm.equals("TlsPremasterSecret")) {
423-
// remove leading zero bytes per RFC 5246 Section 8.1.2
424-
return new SecretKeySpec(
421+
} else if (KeyUtil.isSupportedKeyAgreementOutputAlgorithm(algorithm)) {
422+
if (algorithm.equalsIgnoreCase("TlsPremasterSecret")) {
423+
// remove leading zero bytes per RFC 5246 Section 8.1.2
424+
return new SecretKeySpec(
425425
KeyUtil.trimZeroes(secret), "TlsPremasterSecret");
426+
} else {
427+
return new SecretKeySpec(secret, algorithm);
428+
}
426429
} else {
427-
throw new NoSuchAlgorithmException("Unsupported secret key "
428-
+ "algorithm: "+ algorithm);
430+
throw new NoSuchAlgorithmException(
431+
"Unsupported secret key algorithm: " + algorithm);
429432
}
430433
}
431434
}

‎src/java.base/share/classes/javax/crypto/KeyAgreement.java

+18-6
Original file line numberDiff line numberDiff line change
@@ -666,18 +666,30 @@ public final int generateSecret(byte[] sharedSecret, int offset)
666666
* {@code generateSecret} to change the private information used in
667667
* subsequent operations.
668668
*
669-
* @param algorithm the requested secret-key algorithm
670-
*
671-
* @return the shared secret key
669+
* @param algorithm the requested secret key algorithm. This is different
670+
* from the {@code KeyAgreement} algorithm provided to the
671+
* {@code getInstance} method. See the SecretKey Algorithms section in the
672+
* <a href="{@docRoot}/../specs/security/standard-names.html#secretkey-algorithms">
673+
* Java Security Standard Algorithm Names Specification</a>
674+
* for information about standard secret key algorithm names.
675+
* Specify "Generic" if the output will be used as the input keying
676+
* material of a key derivation function (KDF).
677+
*
678+
* @return the shared secret key. The length of the key material
679+
* may be adjusted to be compatible with the specified algorithm,
680+
* regardless of whether the key is extractable. If {@code algorithm}
681+
* is specified as "Generic" and it is supported by the implementation,
682+
* the full shared secret is returned.
672683
*
673684
* @exception IllegalStateException if this key agreement has not been
674685
* initialized or if {@code doPhase} has not been called to supply the
675686
* keys for all parties in the agreement
676-
* @exception NoSuchAlgorithmException if the specified secret-key
677-
* algorithm is not available
678-
* @exception InvalidKeyException if the shared secret-key material cannot
687+
* @exception NoSuchAlgorithmException if the specified secret key
688+
* algorithm is not supported
689+
* @exception InvalidKeyException if the shared secret key material cannot
679690
* be used to generate a secret key of the specified algorithm (e.g.,
680691
* the key material is too short)
692+
* @spec security/standard-names.html Java Security Standard Algorithm Names
681693
*/
682694
public final SecretKey generateSecret(String algorithm)
683695
throws IllegalStateException, NoSuchAlgorithmException,

‎src/java.base/share/classes/javax/crypto/KeyAgreementSpi.java

+18-6
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 1997, 2022, Oracle and/or its affiliates. All rights reserved.
2+
* Copyright (c) 1997, 2025, Oracle and/or its affiliates. All rights reserved.
33
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
44
*
55
* This code is free software; you can redistribute it and/or modify it
@@ -205,18 +205,30 @@ protected abstract int engineGenerateSecret(byte[] sharedSecret,
205205
* {@code generateSecret} to change the private information used in
206206
* subsequent operations.
207207
*
208-
* @param algorithm the requested secret key algorithm
209-
*
210-
* @return the shared secret key
208+
* @param algorithm the requested secret key algorithm. This is different
209+
* from the {@code KeyAgreement} algorithm provided to the
210+
* {@code getInstance} method. See the SecretKey Algorithms section in the
211+
* <a href="{@docRoot}/../specs/security/standard-names.html#secretkey-algorithms">
212+
* Java Security Standard Algorithm Names Specification</a>
213+
* for information about standard secret key algorithm names.
214+
* Specify "Generic" if the output will be used as the input keying
215+
* material of a key derivation function (KDF).
216+
*
217+
* @return the shared secret key. The length of the key material
218+
* may be adjusted to be compatible with the specified algorithm,
219+
* regardless of whether the key is extractable. If {@code algorithm}
220+
* is specified as "Generic" and it is supported by the implementation,
221+
* the full shared secret is returned.
211222
*
212223
* @exception IllegalStateException if this key agreement has not been
213224
* initialized or if {@code doPhase} has not been called to supply the
214225
* keys for all parties in the agreement
215-
* @exception NoSuchAlgorithmException if the requested secret key
216-
* algorithm is not available
226+
* @exception NoSuchAlgorithmException if the specified secret key
227+
* algorithm is not supported
217228
* @exception InvalidKeyException if the shared secret key material cannot
218229
* be used to generate a secret key of the requested algorithm type (e.g.,
219230
* the key material is too short)
231+
* @spec security/standard-names.html Java Security Standard Algorithm Names
220232
*/
221233
protected abstract SecretKey engineGenerateSecret(String algorithm)
222234
throws IllegalStateException, NoSuchAlgorithmException,

‎src/java.base/share/classes/sun/security/ec/ECDHKeyAgreement.java

+6-5
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2009, 2024, Oracle and/or its affiliates. All rights reserved.
2+
* Copyright (c) 2009, 2025, Oracle and/or its affiliates. All rights reserved.
33
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
44
*
55
* This code is free software; you can redistribute it and/or modify it
@@ -29,6 +29,7 @@
2929
import sun.security.util.ArrayUtil;
3030
import sun.security.util.CurveDB;
3131
import sun.security.util.ECUtil;
32+
import sun.security.util.KeyUtil;
3233
import sun.security.util.NamedCurve;
3334
import sun.security.util.math.IntegerFieldModuloP;
3435
import sun.security.util.math.IntegerMontgomeryFieldModuloP;
@@ -254,11 +255,11 @@ protected SecretKey engineGenerateSecret(String algorithm)
254255
if (algorithm == null) {
255256
throw new NoSuchAlgorithmException("Algorithm must not be null");
256257
}
257-
if (!(algorithm.equals("TlsPremasterSecret"))) {
258-
throw new NoSuchAlgorithmException
259-
("Only supported for algorithm TlsPremasterSecret");
258+
if (!KeyUtil.isSupportedKeyAgreementOutputAlgorithm(algorithm)) {
259+
throw new NoSuchAlgorithmException(
260+
"Unsupported secret key algorithm: " + algorithm);
260261
}
261-
return new SecretKeySpec(engineGenerateSecret(), "TlsPremasterSecret");
262+
return new SecretKeySpec(engineGenerateSecret(), algorithm);
262263
}
263264

264265
private static

‎src/java.base/share/classes/sun/security/ec/XDHKeyAgreement.java

+5-3
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2018, 2019, Oracle and/or its affiliates. All rights reserved.
2+
* Copyright (c) 2018, 2025, Oracle and/or its affiliates. All rights reserved.
33
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
44
*
55
* This code is free software; you can redistribute it and/or modify it
@@ -25,6 +25,8 @@
2525

2626
package sun.security.ec;
2727

28+
import sun.security.util.KeyUtil;
29+
2830
import java.security.InvalidAlgorithmParameterException;
2931
import java.security.InvalidKeyException;
3032
import java.security.NoSuchAlgorithmException;
@@ -207,9 +209,9 @@ protected SecretKey engineGenerateSecret(String algorithm)
207209
throw new NoSuchAlgorithmException("Algorithm must not be null");
208210
}
209211

210-
if (!(algorithm.equals("TlsPremasterSecret"))) {
212+
if (!KeyUtil.isSupportedKeyAgreementOutputAlgorithm(algorithm)) {
211213
throw new NoSuchAlgorithmException(
212-
"Only supported for algorithm TlsPremasterSecret");
214+
"Unsupported secret key algorithm: " + algorithm);
213215
}
214216
return new SecretKeySpec(engineGenerateSecret(), algorithm);
215217
}

‎src/java.base/share/classes/sun/security/util/KeyUtil.java

+5
Original file line numberDiff line numberDiff line change
@@ -424,5 +424,10 @@ public static String hashAlgFromHSS(PublicKey publicKey)
424424
throw new NoSuchAlgorithmException("Cannot decode public key", e);
425425
}
426426
}
427+
428+
public static boolean isSupportedKeyAgreementOutputAlgorithm(String alg) {
429+
return alg.equalsIgnoreCase("TlsPremasterSecret")
430+
|| alg.equalsIgnoreCase("Generic");
431+
}
427432
}
428433

‎src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/P11ECDHKeyAgreement.java

+6-4
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2006, 2018, Oracle and/or its affiliates. All rights reserved.
2+
* Copyright (c) 2006, 2025, Oracle and/or its affiliates. All rights reserved.
33
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
44
*
55
* This code is free software; you can redistribute it and/or modify it
@@ -33,6 +33,8 @@
3333

3434
import static sun.security.pkcs11.TemplateManager.*;
3535
import sun.security.pkcs11.wrapper.*;
36+
import sun.security.util.KeyUtil;
37+
3638
import static sun.security.pkcs11.wrapper.PKCS11Constants.*;
3739

3840
/**
@@ -168,9 +170,9 @@ protected SecretKey engineGenerateSecret(String algorithm)
168170
if (algorithm == null) {
169171
throw new NoSuchAlgorithmException("Algorithm must not be null");
170172
}
171-
if (!algorithm.equals("TlsPremasterSecret")) {
172-
throw new NoSuchAlgorithmException
173-
("Only supported for algorithm TlsPremasterSecret");
173+
if (!KeyUtil.isSupportedKeyAgreementOutputAlgorithm(algorithm)) {
174+
throw new NoSuchAlgorithmException(
175+
"Unsupported secret key algorithm: " + algorithm);
174176
}
175177
return nativeGenerateSecret(algorithm);
176178
}

‎src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/P11KeyAgreement.java

+9-11
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2003, 2024, Oracle and/or its affiliates. All rights reserved.
2+
* Copyright (c) 2003, 2025, Oracle and/or its affiliates. All rights reserved.
33
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
44
*
55
* This code is free software; you can redistribute it and/or modify it
@@ -268,20 +268,19 @@ protected SecretKey engineGenerateSecret(String algorithm)
268268
throw new NoSuchAlgorithmException("Algorithm must not be null");
269269
}
270270

271-
if (algorithm.equals("TlsPremasterSecret")) {
271+
if (KeyUtil.isSupportedKeyAgreementOutputAlgorithm(algorithm)) {
272272
// For now, only perform native derivation for TlsPremasterSecret
273-
// as that is required for FIPS compliance.
273+
// and Generic algorithms. TlsPremasterSecret is required for
274+
// FIPS compliance and Generic is required for input to KDF.
274275
// For other algorithms, there are unresolved issues regarding
275276
// how this should work in JCE plus a Solaris truncation bug.
276277
// (bug not yet filed).
277278
return nativeGenerateSecret(algorithm);
278279
}
279280

280-
if (!algorithm.equalsIgnoreCase("TlsPremasterSecret") &&
281-
!AllowKDF.VALUE) {
282-
283-
throw new NoSuchAlgorithmException("Unsupported secret key "
284-
+ "algorithm: " + algorithm);
281+
if (!AllowKDF.VALUE) {
282+
throw new NoSuchAlgorithmException(
283+
"Unsupported secret key algorithm: " + algorithm);
285284
}
286285

287286
byte[] secret = engineGenerateSecret();
@@ -295,8 +294,6 @@ protected SecretKey engineGenerateSecret(String algorithm)
295294
keyLen = 24;
296295
} else if (algorithm.equalsIgnoreCase("Blowfish")) {
297296
keyLen = Math.min(56, secret.length);
298-
} else if (algorithm.equalsIgnoreCase("TlsPremasterSecret")) {
299-
keyLen = secret.length;
300297
} else {
301298
throw new NoSuchAlgorithmException
302299
("Unknown algorithm " + algorithm);
@@ -340,7 +337,8 @@ private SecretKey nativeGenerateSecret(String algorithm)
340337
int keyLen = (int)lenAttributes[0].getLong();
341338
SecretKey key = P11Key.secretKey
342339
(session, keyID, algorithm, keyLen << 3, attributes);
343-
if ("RAW".equals(key.getFormat())) {
340+
if ("RAW".equals(key.getFormat())
341+
&& algorithm.equalsIgnoreCase("TlsPremasterSecret")) {
344342
// Workaround for Solaris bug 6318543.
345343
// Strip leading zeroes ourselves if possible (key not sensitive).
346344
// This should be removed once the Solaris fix is available
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
/*
2+
* Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved.
3+
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4+
*
5+
* This code is free software; you can redistribute it and/or modify it
6+
* under the terms of the GNU General Public License version 2 only, as
7+
* published by the Free Software Foundation.
8+
*
9+
* This code is distributed in the hope that it will be useful, but WITHOUT
10+
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11+
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
12+
* version 2 for more details (a copy is included in the LICENSE file that
13+
* accompanied this code).
14+
*
15+
* You should have received a copy of the GNU General Public License version
16+
* 2 along with this work; if not, write to the Free Software Foundation,
17+
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18+
*
19+
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20+
* or visit www.oracle.com if you need additional information or have any
21+
* questions.
22+
*/
23+
24+
/*
25+
* @test
26+
* @bug 8189441
27+
* @library /test/lib /test/jdk/sun/security/pkcs11
28+
* @summary make sure Generic is accepted by all KeyAgreement implementations
29+
* @run main Generic builtin
30+
* @run main/othervm Generic nss
31+
* @run main/othervm -DCUSTOM_P11_CONFIG_NAME=p11-nss-sensitive.txt Generic nss
32+
*/
33+
import jdk.test.lib.Asserts;
34+
35+
import javax.crypto.KeyAgreement;
36+
import java.security.KeyPairGenerator;
37+
import java.security.Provider;
38+
import java.security.Security;
39+
import java.util.List;
40+
41+
public class Generic {
42+
43+
public static void main(String[] args) throws Exception {
44+
if (args[0].equals("nss")) {
45+
test(PKCS11Test.getSunPKCS11(PKCS11Test.getNssConfig()));
46+
} else {
47+
for (var p : Security.getProviders()) {
48+
test(p);
49+
}
50+
}
51+
}
52+
53+
static void test(Provider p) throws Exception {
54+
for (var s : p.getServices()) {
55+
if (s.getType().equalsIgnoreCase("KeyAgreement")) {
56+
try {
57+
System.out.println(s.getProvider().getName() + "." + s.getAlgorithm());
58+
var g = KeyPairGenerator.getInstance(ka2kpg(s.getAlgorithm()), p);
59+
var kp1 = g.generateKeyPair();
60+
var kp2 = g.generateKeyPair();
61+
var ka = KeyAgreement.getInstance(s.getAlgorithm(), s.getProvider());
62+
for (var alg : List.of("TlsPremasterSecret", "Generic")) {
63+
ka.init(kp1.getPrivate());
64+
ka.doPhase(kp2.getPublic(), true);
65+
Asserts.assertEquals(
66+
ka.generateSecret(alg).getAlgorithm(), alg);
67+
}
68+
} catch (Exception e) {
69+
throw e;
70+
}
71+
}
72+
}
73+
}
74+
75+
// Find key algorithm from KeyAgreement algorithm
76+
private static String ka2kpg(String ka) {
77+
return ka.equals("ECDH") ? "EC" : ka;
78+
}
79+
}

‎test/jdk/sun/security/pkcs11/nss/p11-nss-sensitive.txt

+2
Original file line numberDiff line numberDiff line change
@@ -49,10 +49,12 @@ attributes(*,CKO_PRIVATE_KEY,CKK_DH) = {
4949
# Make all private keys sensitive
5050
attributes(*,CKO_PRIVATE_KEY,*) = {
5151
CKA_SENSITIVE = true
52+
CKA_EXTRACTABLE = false
5253
}
5354

5455

5556
# Make all secret keys sensitive
5657
attributes(*,CKO_SECRET_KEY,*) = {
5758
CKA_SENSITIVE = true
59+
CKA_EXTRACTABLE = false
5860
}

0 commit comments

Comments
 (0)
Please sign in to comment.