Skip to content

Commit

Permalink
8189441: Define algorithm names for keys derived from KeyAgreement
Browse files Browse the repository at this point in the history
Reviewed-by: mullan
  • Loading branch information
wangweij committed Jan 27, 2025
1 parent 03106eb commit aba60a9
Show file tree
Hide file tree
Showing 10 changed files with 162 additions and 46 deletions.
Original file line number Diff line number Diff line change
@@ -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
Expand Down Expand Up @@ -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();
Expand Down Expand Up @@ -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);
}
}
}
24 changes: 18 additions & 6 deletions src/java.base/share/classes/javax/crypto/KeyAgreement.java
Original file line number Diff line number Diff line change
Expand Up @@ -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
* <a href="{@docRoot}/../specs/security/standard-names.html#secretkey-algorithms">
* Java Security Standard Algorithm Names Specification</a>
* 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,
Expand Down
24 changes: 18 additions & 6 deletions src/java.base/share/classes/javax/crypto/KeyAgreementSpi.java
Original file line number Diff line number Diff line change
@@ -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
Expand Down Expand Up @@ -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
* <a href="{@docRoot}/../specs/security/standard-names.html#secretkey-algorithms">
* Java Security Standard Algorithm Names Specification</a>
* 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,
Expand Down
Original file line number Diff line number Diff line change
@@ -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
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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
Expand Down
Original file line number Diff line number Diff line change
@@ -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
Expand All @@ -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;
Expand Down Expand Up @@ -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);
}
Expand Down
5 changes: 5 additions & 0 deletions src/java.base/share/classes/sun/security/util/KeyUtil.java
Original file line number Diff line number Diff line change
Expand Up @@ -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");
}
}

Original file line number Diff line number Diff line change
@@ -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
Expand Down Expand Up @@ -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.*;

/**
Expand Down Expand Up @@ -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);
}
Expand Down
Original file line number Diff line number Diff line change
@@ -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
Expand Down Expand Up @@ -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();
Expand All @@ -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);
Expand Down Expand Up @@ -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
Expand Down
79 changes: 79 additions & 0 deletions test/jdk/java/security/KeyAgreement/Generic.java
Original file line number Diff line number Diff line change
@@ -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;
}
}
2 changes: 2 additions & 0 deletions test/jdk/sun/security/pkcs11/nss/p11-nss-sensitive.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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
}

0 comments on commit aba60a9

Please sign in to comment.