diff --git a/src/java.base/share/classes/com/sun/crypto/provider/DHKeyAgreement.java b/src/java.base/share/classes/com/sun/crypto/provider/DHKeyAgreement.java
index e13eec429057c..2d9ad93d2fa29 100644
--- a/src/java.base/share/classes/com/sun/crypto/provider/DHKeyAgreement.java
+++ b/src/java.base/share/classes/com/sun/crypto/provider/DHKeyAgreement.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1997, 2024, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2025, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -379,11 +379,10 @@ protected SecretKey engineGenerateSecret(String algorithm)
throw new NoSuchAlgorithmException("null algorithm");
}
- if (!algorithm.equalsIgnoreCase("TlsPremasterSecret") &&
- !AllowKDF.VALUE) {
-
- throw new NoSuchAlgorithmException("Unsupported secret key "
- + "algorithm: " + algorithm);
+ if (!KeyUtil.isSupportedKeyAgreementOutputAlgorithm(algorithm) &&
+ !AllowKDF.VALUE) {
+ throw new NoSuchAlgorithmException(
+ "Unsupported secret key algorithm: " + algorithm);
}
byte[] secret = engineGenerateSecret();
@@ -419,13 +418,17 @@ protected SecretKey engineGenerateSecret(String algorithm)
throw new InvalidKeyException("Key material is too short");
}
return skey;
- } else if (algorithm.equals("TlsPremasterSecret")) {
- // remove leading zero bytes per RFC 5246 Section 8.1.2
- return new SecretKeySpec(
+ } else if (KeyUtil.isSupportedKeyAgreementOutputAlgorithm(algorithm)) {
+ if (algorithm.equalsIgnoreCase("TlsPremasterSecret")) {
+ // remove leading zero bytes per RFC 5246 Section 8.1.2
+ return new SecretKeySpec(
KeyUtil.trimZeroes(secret), "TlsPremasterSecret");
+ } else {
+ return new SecretKeySpec(secret, algorithm);
+ }
} else {
- throw new NoSuchAlgorithmException("Unsupported secret key "
- + "algorithm: "+ algorithm);
+ throw new NoSuchAlgorithmException(
+ "Unsupported secret key algorithm: " + algorithm);
}
}
}
diff --git a/src/java.base/share/classes/javax/crypto/KeyAgreement.java b/src/java.base/share/classes/javax/crypto/KeyAgreement.java
index e3a68e88d03d4..4b3a3fd1cf7b8 100644
--- a/src/java.base/share/classes/javax/crypto/KeyAgreement.java
+++ b/src/java.base/share/classes/javax/crypto/KeyAgreement.java
@@ -666,18 +666,30 @@ public final int generateSecret(byte[] sharedSecret, int offset)
* {@code generateSecret} to change the private information used in
* subsequent operations.
*
- * @param algorithm the requested secret-key algorithm
- *
- * @return the shared secret key
+ * @param algorithm the requested secret key algorithm. This is different
+ * from the {@code KeyAgreement} algorithm provided to the
+ * {@code getInstance} method. See the SecretKey Algorithms section in the
+ *
+ * Java Security Standard Algorithm Names Specification
+ * for information about standard secret key algorithm names.
+ * Specify "Generic" if the output will be used as the input keying
+ * material of a key derivation function (KDF).
+ *
+ * @return the shared secret key. The length of the key material
+ * may be adjusted to be compatible with the specified algorithm,
+ * regardless of whether the key is extractable. If {@code algorithm}
+ * is specified as "Generic" and it is supported by the implementation,
+ * the full shared secret is returned.
*
* @exception IllegalStateException if this key agreement has not been
* initialized or if {@code doPhase} has not been called to supply the
* keys for all parties in the agreement
- * @exception NoSuchAlgorithmException if the specified secret-key
- * algorithm is not available
- * @exception InvalidKeyException if the shared secret-key material cannot
+ * @exception NoSuchAlgorithmException if the specified secret key
+ * algorithm is not supported
+ * @exception InvalidKeyException if the shared secret key material cannot
* be used to generate a secret key of the specified algorithm (e.g.,
* the key material is too short)
+ * @spec security/standard-names.html Java Security Standard Algorithm Names
*/
public final SecretKey generateSecret(String algorithm)
throws IllegalStateException, NoSuchAlgorithmException,
diff --git a/src/java.base/share/classes/javax/crypto/KeyAgreementSpi.java b/src/java.base/share/classes/javax/crypto/KeyAgreementSpi.java
index a4c242e46cca5..84d68a39725cf 100644
--- a/src/java.base/share/classes/javax/crypto/KeyAgreementSpi.java
+++ b/src/java.base/share/classes/javax/crypto/KeyAgreementSpi.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1997, 2022, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2025, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -205,18 +205,30 @@ protected abstract int engineGenerateSecret(byte[] sharedSecret,
* {@code generateSecret} to change the private information used in
* subsequent operations.
*
- * @param algorithm the requested secret key algorithm
- *
- * @return the shared secret key
+ * @param algorithm the requested secret key algorithm. This is different
+ * from the {@code KeyAgreement} algorithm provided to the
+ * {@code getInstance} method. See the SecretKey Algorithms section in the
+ *
+ * Java Security Standard Algorithm Names Specification
+ * for information about standard secret key algorithm names.
+ * Specify "Generic" if the output will be used as the input keying
+ * material of a key derivation function (KDF).
+ *
+ * @return the shared secret key. The length of the key material
+ * may be adjusted to be compatible with the specified algorithm,
+ * regardless of whether the key is extractable. If {@code algorithm}
+ * is specified as "Generic" and it is supported by the implementation,
+ * the full shared secret is returned.
*
* @exception IllegalStateException if this key agreement has not been
* initialized or if {@code doPhase} has not been called to supply the
* keys for all parties in the agreement
- * @exception NoSuchAlgorithmException if the requested secret key
- * algorithm is not available
+ * @exception NoSuchAlgorithmException if the specified secret key
+ * algorithm is not supported
* @exception InvalidKeyException if the shared secret key material cannot
* be used to generate a secret key of the requested algorithm type (e.g.,
* the key material is too short)
+ * @spec security/standard-names.html Java Security Standard Algorithm Names
*/
protected abstract SecretKey engineGenerateSecret(String algorithm)
throws IllegalStateException, NoSuchAlgorithmException,
diff --git a/src/java.base/share/classes/sun/security/ec/ECDHKeyAgreement.java b/src/java.base/share/classes/sun/security/ec/ECDHKeyAgreement.java
index be3bdfdd63990..8f6bdb8d80ae1 100644
--- a/src/java.base/share/classes/sun/security/ec/ECDHKeyAgreement.java
+++ b/src/java.base/share/classes/sun/security/ec/ECDHKeyAgreement.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2009, 2024, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2009, 2025, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -29,6 +29,7 @@
import sun.security.util.ArrayUtil;
import sun.security.util.CurveDB;
import sun.security.util.ECUtil;
+import sun.security.util.KeyUtil;
import sun.security.util.NamedCurve;
import sun.security.util.math.IntegerFieldModuloP;
import sun.security.util.math.IntegerMontgomeryFieldModuloP;
@@ -254,11 +255,11 @@ protected SecretKey engineGenerateSecret(String algorithm)
if (algorithm == null) {
throw new NoSuchAlgorithmException("Algorithm must not be null");
}
- if (!(algorithm.equals("TlsPremasterSecret"))) {
- throw new NoSuchAlgorithmException
- ("Only supported for algorithm TlsPremasterSecret");
+ if (!KeyUtil.isSupportedKeyAgreementOutputAlgorithm(algorithm)) {
+ throw new NoSuchAlgorithmException(
+ "Unsupported secret key algorithm: " + algorithm);
}
- return new SecretKeySpec(engineGenerateSecret(), "TlsPremasterSecret");
+ return new SecretKeySpec(engineGenerateSecret(), algorithm);
}
private static
diff --git a/src/java.base/share/classes/sun/security/ec/XDHKeyAgreement.java b/src/java.base/share/classes/sun/security/ec/XDHKeyAgreement.java
index e2a625a55d9b2..01dce4c53e905 100644
--- a/src/java.base/share/classes/sun/security/ec/XDHKeyAgreement.java
+++ b/src/java.base/share/classes/sun/security/ec/XDHKeyAgreement.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2018, 2019, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2018, 2025, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -25,6 +25,8 @@
package sun.security.ec;
+import sun.security.util.KeyUtil;
+
import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
@@ -207,9 +209,9 @@ protected SecretKey engineGenerateSecret(String algorithm)
throw new NoSuchAlgorithmException("Algorithm must not be null");
}
- if (!(algorithm.equals("TlsPremasterSecret"))) {
+ if (!KeyUtil.isSupportedKeyAgreementOutputAlgorithm(algorithm)) {
throw new NoSuchAlgorithmException(
- "Only supported for algorithm TlsPremasterSecret");
+ "Unsupported secret key algorithm: " + algorithm);
}
return new SecretKeySpec(engineGenerateSecret(), algorithm);
}
diff --git a/src/java.base/share/classes/sun/security/util/KeyUtil.java b/src/java.base/share/classes/sun/security/util/KeyUtil.java
index 6eb5acfade3fd..224167653f789 100644
--- a/src/java.base/share/classes/sun/security/util/KeyUtil.java
+++ b/src/java.base/share/classes/sun/security/util/KeyUtil.java
@@ -424,5 +424,10 @@ public static String hashAlgFromHSS(PublicKey publicKey)
throw new NoSuchAlgorithmException("Cannot decode public key", e);
}
}
+
+ public static boolean isSupportedKeyAgreementOutputAlgorithm(String alg) {
+ return alg.equalsIgnoreCase("TlsPremasterSecret")
+ || alg.equalsIgnoreCase("Generic");
+ }
}
diff --git a/src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/P11ECDHKeyAgreement.java b/src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/P11ECDHKeyAgreement.java
index 53728219d8bb2..ec5e03cc15a67 100644
--- a/src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/P11ECDHKeyAgreement.java
+++ b/src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/P11ECDHKeyAgreement.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2006, 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2006, 2025, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -33,6 +33,8 @@
import static sun.security.pkcs11.TemplateManager.*;
import sun.security.pkcs11.wrapper.*;
+import sun.security.util.KeyUtil;
+
import static sun.security.pkcs11.wrapper.PKCS11Constants.*;
/**
@@ -168,9 +170,9 @@ protected SecretKey engineGenerateSecret(String algorithm)
if (algorithm == null) {
throw new NoSuchAlgorithmException("Algorithm must not be null");
}
- if (!algorithm.equals("TlsPremasterSecret")) {
- throw new NoSuchAlgorithmException
- ("Only supported for algorithm TlsPremasterSecret");
+ if (!KeyUtil.isSupportedKeyAgreementOutputAlgorithm(algorithm)) {
+ throw new NoSuchAlgorithmException(
+ "Unsupported secret key algorithm: " + algorithm);
}
return nativeGenerateSecret(algorithm);
}
diff --git a/src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/P11KeyAgreement.java b/src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/P11KeyAgreement.java
index 6c010a4a5130e..183135ce7e126 100644
--- a/src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/P11KeyAgreement.java
+++ b/src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/P11KeyAgreement.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2003, 2024, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2003, 2025, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -268,20 +268,19 @@ protected SecretKey engineGenerateSecret(String algorithm)
throw new NoSuchAlgorithmException("Algorithm must not be null");
}
- if (algorithm.equals("TlsPremasterSecret")) {
+ if (KeyUtil.isSupportedKeyAgreementOutputAlgorithm(algorithm)) {
// For now, only perform native derivation for TlsPremasterSecret
- // as that is required for FIPS compliance.
+ // and Generic algorithms. TlsPremasterSecret is required for
+ // FIPS compliance and Generic is required for input to KDF.
// For other algorithms, there are unresolved issues regarding
// how this should work in JCE plus a Solaris truncation bug.
// (bug not yet filed).
return nativeGenerateSecret(algorithm);
}
- if (!algorithm.equalsIgnoreCase("TlsPremasterSecret") &&
- !AllowKDF.VALUE) {
-
- throw new NoSuchAlgorithmException("Unsupported secret key "
- + "algorithm: " + algorithm);
+ if (!AllowKDF.VALUE) {
+ throw new NoSuchAlgorithmException(
+ "Unsupported secret key algorithm: " + algorithm);
}
byte[] secret = engineGenerateSecret();
@@ -295,8 +294,6 @@ protected SecretKey engineGenerateSecret(String algorithm)
keyLen = 24;
} else if (algorithm.equalsIgnoreCase("Blowfish")) {
keyLen = Math.min(56, secret.length);
- } else if (algorithm.equalsIgnoreCase("TlsPremasterSecret")) {
- keyLen = secret.length;
} else {
throw new NoSuchAlgorithmException
("Unknown algorithm " + algorithm);
@@ -340,7 +337,8 @@ private SecretKey nativeGenerateSecret(String algorithm)
int keyLen = (int)lenAttributes[0].getLong();
SecretKey key = P11Key.secretKey
(session, keyID, algorithm, keyLen << 3, attributes);
- if ("RAW".equals(key.getFormat())) {
+ if ("RAW".equals(key.getFormat())
+ && algorithm.equalsIgnoreCase("TlsPremasterSecret")) {
// Workaround for Solaris bug 6318543.
// Strip leading zeroes ourselves if possible (key not sensitive).
// This should be removed once the Solaris fix is available
diff --git a/test/jdk/java/security/KeyAgreement/Generic.java b/test/jdk/java/security/KeyAgreement/Generic.java
new file mode 100644
index 0000000000000..dcf212dbffe7c
--- /dev/null
+++ b/test/jdk/java/security/KeyAgreement/Generic.java
@@ -0,0 +1,79 @@
+/*
+ * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @bug 8189441
+ * @library /test/lib /test/jdk/sun/security/pkcs11
+ * @summary make sure Generic is accepted by all KeyAgreement implementations
+ * @run main Generic builtin
+ * @run main/othervm Generic nss
+ * @run main/othervm -DCUSTOM_P11_CONFIG_NAME=p11-nss-sensitive.txt Generic nss
+ */
+import jdk.test.lib.Asserts;
+
+import javax.crypto.KeyAgreement;
+import java.security.KeyPairGenerator;
+import java.security.Provider;
+import java.security.Security;
+import java.util.List;
+
+public class Generic {
+
+ public static void main(String[] args) throws Exception {
+ if (args[0].equals("nss")) {
+ test(PKCS11Test.getSunPKCS11(PKCS11Test.getNssConfig()));
+ } else {
+ for (var p : Security.getProviders()) {
+ test(p);
+ }
+ }
+ }
+
+ static void test(Provider p) throws Exception {
+ for (var s : p.getServices()) {
+ if (s.getType().equalsIgnoreCase("KeyAgreement")) {
+ try {
+ System.out.println(s.getProvider().getName() + "." + s.getAlgorithm());
+ var g = KeyPairGenerator.getInstance(ka2kpg(s.getAlgorithm()), p);
+ var kp1 = g.generateKeyPair();
+ var kp2 = g.generateKeyPair();
+ var ka = KeyAgreement.getInstance(s.getAlgorithm(), s.getProvider());
+ for (var alg : List.of("TlsPremasterSecret", "Generic")) {
+ ka.init(kp1.getPrivate());
+ ka.doPhase(kp2.getPublic(), true);
+ Asserts.assertEquals(
+ ka.generateSecret(alg).getAlgorithm(), alg);
+ }
+ } catch (Exception e) {
+ throw e;
+ }
+ }
+ }
+ }
+
+ // Find key algorithm from KeyAgreement algorithm
+ private static String ka2kpg(String ka) {
+ return ka.equals("ECDH") ? "EC" : ka;
+ }
+}
diff --git a/test/jdk/sun/security/pkcs11/nss/p11-nss-sensitive.txt b/test/jdk/sun/security/pkcs11/nss/p11-nss-sensitive.txt
index 4579dd593982d..df891c7097a0f 100644
--- a/test/jdk/sun/security/pkcs11/nss/p11-nss-sensitive.txt
+++ b/test/jdk/sun/security/pkcs11/nss/p11-nss-sensitive.txt
@@ -49,10 +49,12 @@ attributes(*,CKO_PRIVATE_KEY,CKK_DH) = {
# Make all private keys sensitive
attributes(*,CKO_PRIVATE_KEY,*) = {
CKA_SENSITIVE = true
+ CKA_EXTRACTABLE = false
}
# Make all secret keys sensitive
attributes(*,CKO_SECRET_KEY,*) = {
CKA_SENSITIVE = true
+ CKA_EXTRACTABLE = false
}