7192392: Better validation of client keys
Summary: Also reviewed by Andrew Gross<Andrew.Gross@Oracle.COM>
Reviewed-by: vinnie
--- a/jdk/src/share/classes/com/sun/crypto/provider/DHKeyAgreement.java Wed Aug 22 21:40:19 2012 -0400
+++ b/jdk/src/share/classes/com/sun/crypto/provider/DHKeyAgreement.java Mon Oct 22 07:28:51 2012 -0700
@@ -41,6 +41,8 @@
import javax.crypto.SecretKey;
import javax.crypto.spec.*;
+import sun.security.util.KeyUtil;
+
/**
* This class implements the Diffie-Hellman key agreement protocol between
* any number of parties.
@@ -200,6 +202,9 @@
throw new InvalidKeyException("Incompatible parameters");
}
+ // validate the Diffie-Hellman public key
+ KeyUtil.validate(dhPubKey);
+
// store the y value
this.y = dhPubKey.getY();
--- a/jdk/src/share/classes/sun/security/pkcs11/P11KeyAgreement.java Wed Aug 22 21:40:19 2012 -0400
+++ b/jdk/src/share/classes/sun/security/pkcs11/P11KeyAgreement.java Mon Oct 22 07:28:51 2012 -0700
@@ -37,6 +37,7 @@
import static sun.security.pkcs11.TemplateManager.*;
import sun.security.pkcs11.wrapper.*;
import static sun.security.pkcs11.wrapper.PKCS11Constants.*;
+import sun.security.util.KeyUtil;
/**
* KeyAgreement implementation class. This class currently supports
@@ -134,6 +135,10 @@
BigInteger p, g, y;
if (key instanceof DHPublicKey) {
DHPublicKey dhKey = (DHPublicKey)key;
+
+ // validate the Diffie-Hellman public key
+ KeyUtil.validate(dhKey);
+
y = dhKey.getY();
DHParameterSpec params = dhKey.getParams();
p = params.getP();
@@ -145,6 +150,10 @@
try {
DHPublicKeySpec spec = kf.engineGetKeySpec(
key, DHPublicKeySpec.class);
+
+ // validate the Diffie-Hellman public key
+ KeyUtil.validate(spec);
+
y = spec.getY();
p = spec.getP();
g = spec.getG();
--- a/jdk/src/share/classes/sun/security/ssl/ClientHandshaker.java Wed Aug 22 21:40:19 2012 -0400
+++ b/jdk/src/share/classes/sun/security/ssl/ClientHandshaker.java Mon Oct 22 07:28:51 2012 -0700
@@ -192,8 +192,12 @@
}
break;
case K_DH_ANON:
- this.serverKeyExchange(new DH_ServerKeyExchange(
+ try {
+ this.serverKeyExchange(new DH_ServerKeyExchange(
input, protocolVersion));
+ } catch (GeneralSecurityException e) {
+ throwSSLException("Server key", e);
+ }
break;
case K_DHE_DSS:
case K_DHE_RSA:
@@ -921,7 +925,7 @@
case K_DHE_RSA:
case K_DHE_DSS:
case K_DH_ANON:
- preMasterSecret = dh.getAgreedSecret(serverDH);
+ preMasterSecret = dh.getAgreedSecret(serverDH, true);
break;
case K_ECDHE_RSA:
case K_ECDHE_ECDSA:
--- a/jdk/src/share/classes/sun/security/ssl/DHClientKeyExchange.java Wed Aug 22 21:40:19 2012 -0400
+++ b/jdk/src/share/classes/sun/security/ssl/DHClientKeyExchange.java Mon Oct 22 07:28:51 2012 -0700
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1997, 2007, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2012, 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,7 +29,7 @@
import java.io.IOException;
import java.io.PrintStream;
import java.math.BigInteger;
-
+import javax.net.ssl.SSLHandshakeException;
/*
* Message used by clients to send their Diffie-Hellman public
@@ -50,7 +50,7 @@
private byte dh_Yc[]; // 1 to 2^16 -1 bytes
BigInteger getClientPublicKey() {
- return new BigInteger(1, dh_Yc);
+ return dh_Yc == null ? null : new BigInteger(1, dh_Yc);
}
/*
@@ -72,7 +72,14 @@
* but that's what the protocol spec requires.)
*/
DHClientKeyExchange(HandshakeInStream input) throws IOException {
- dh_Yc = input.getBytes16();
+ if (input.available() >= 2) {
+ dh_Yc = input.getBytes16();
+ } else {
+ // currently, we don't support cipher suites that requires
+ // implicit public key of client.
+ throw new SSLHandshakeException(
+ "Unsupported implicit client DiffieHellman public key");
+ }
}
int messageLength() {
@@ -84,7 +91,9 @@
}
void send(HandshakeOutStream s) throws IOException {
- s.putBytes16(dh_Yc);
+ if (dh_Yc != null && dh_Yc.length != 0) {
+ s.putBytes16(dh_Yc);
+ }
}
void print(PrintStream s) throws IOException {
--- a/jdk/src/share/classes/sun/security/ssl/DHCrypt.java Wed Aug 22 21:40:19 2012 -0400
+++ b/jdk/src/share/classes/sun/security/ssl/DHCrypt.java Mon Oct 22 07:28:51 2012 -0700
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1996, 2008, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1996, 2012, 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
@@ -28,12 +28,15 @@
import java.math.BigInteger;
import java.security.*;
-
+import java.io.IOException;
+import javax.net.ssl.SSLHandshakeException;
import javax.crypto.SecretKey;
import javax.crypto.KeyAgreement;
import javax.crypto.interfaces.DHPublicKey;
import javax.crypto.spec.*;
+import sun.security.util.KeyUtil;
+
/**
* This class implements the Diffie-Hellman key exchange algorithm.
* D-H means combining your private key with your partners public key to
@@ -54,7 +57,8 @@
* . if we are server, call DHCrypt(keyLength,random). This generates
* an ephemeral keypair of the request length.
* . if we are client, call DHCrypt(modulus, base, random). This
- * generates an ephemeral keypair using the parameters specified by the server.
+ * generates an ephemeral keypair using the parameters specified by
+ * the server.
* . send parameters and public value to remote peer
* . receive peers ephemeral public key
* . call getAgreedSecret() to calculate the shared secret
@@ -83,6 +87,9 @@
// public component of our key, X = (g ^ x) mod p
private BigInteger publicValue; // X (aka y)
+ // the times to recove from failure if public key validation
+ private static int MAX_FAILOVER_TIMES = 2;
+
/**
* Generate a Diffie-Hellman keypair of the specified size.
*/
@@ -90,9 +97,12 @@
try {
KeyPairGenerator kpg = JsseJce.getKeyPairGenerator("DiffieHellman");
kpg.initialize(keyLength, random);
- KeyPair kp = kpg.generateKeyPair();
- privateKey = kp.getPrivate();
- DHPublicKeySpec spec = getDHPublicKeySpec(kp.getPublic());
+
+ DHPublicKeySpec spec = generateDHPublicKeySpec(kpg);
+ if (spec == null) {
+ throw new RuntimeException("Could not generate DH keypair");
+ }
+
publicValue = spec.getY();
modulus = spec.getP();
base = spec.getG();
@@ -115,20 +125,25 @@
KeyPairGenerator kpg = JsseJce.getKeyPairGenerator("DiffieHellman");
DHParameterSpec params = new DHParameterSpec(modulus, base);
kpg.initialize(params, random);
- KeyPair kp = kpg.generateKeyPair();
- privateKey = kp.getPrivate();
- DHPublicKeySpec spec = getDHPublicKeySpec(kp.getPublic());
+
+ DHPublicKeySpec spec = generateDHPublicKeySpec(kpg);
+ if (spec == null) {
+ throw new RuntimeException("Could not generate DH keypair");
+ }
+
publicValue = spec.getY();
} catch (GeneralSecurityException e) {
throw new RuntimeException("Could not generate DH keypair", e);
}
}
+
static DHPublicKeySpec getDHPublicKeySpec(PublicKey key) {
if (key instanceof DHPublicKey) {
DHPublicKey dhKey = (DHPublicKey)key;
DHParameterSpec params = dhKey.getParams();
- return new DHPublicKeySpec(dhKey.getY(), params.getP(), params.getG());
+ return new DHPublicKeySpec(dhKey.getY(),
+ params.getP(), params.getG());
}
try {
KeyFactory factory = JsseJce.getKeyFactory("DH");
@@ -166,17 +181,32 @@
* <P>It is illegal to call this member function if the private key
* has not been set (or generated).
*
- * @param peerPublicKey the peer's public key.
- * @returns the secret, which is an unsigned big-endian integer
- * the same size as the Diffie-Hellman modulus.
+ * @param peerPublicKey the peer's public key.
+ * @param keyIsValidated whether the {@code peerPublicKey} has beed
+ * validated
+ * @return the secret, which is an unsigned big-endian integer
+ * the same size as the Diffie-Hellman modulus.
*/
- SecretKey getAgreedSecret(BigInteger peerPublicValue) {
+ SecretKey getAgreedSecret(BigInteger peerPublicValue,
+ boolean keyIsValidated) throws IOException {
try {
KeyFactory kf = JsseJce.getKeyFactory("DiffieHellman");
DHPublicKeySpec spec =
new DHPublicKeySpec(peerPublicValue, modulus, base);
PublicKey publicKey = kf.generatePublic(spec);
KeyAgreement ka = JsseJce.getKeyAgreement("DiffieHellman");
+
+ // validate the Diffie-Hellman public key
+ if (!keyIsValidated &&
+ !KeyUtil.isOracleJCEProvider(ka.getProvider().getName())) {
+ try {
+ KeyUtil.validate(spec);
+ } catch (InvalidKeyException ike) {
+ // prefer handshake_failure alert to internal_error alert
+ throw new SSLHandshakeException(ike.getMessage());
+ }
+ }
+
ka.init(privateKey);
ka.doPhase(publicKey, true);
return ka.generateSecret("TlsPremasterSecret");
@@ -185,4 +215,33 @@
}
}
+ // Generate and validate DHPublicKeySpec
+ private DHPublicKeySpec generateDHPublicKeySpec(KeyPairGenerator kpg)
+ throws GeneralSecurityException {
+
+ boolean doExtraValiadtion =
+ (!KeyUtil.isOracleJCEProvider(kpg.getProvider().getName()));
+ for (int i = 0; i <= MAX_FAILOVER_TIMES; i++) {
+ KeyPair kp = kpg.generateKeyPair();
+ privateKey = kp.getPrivate();
+ DHPublicKeySpec spec = getDHPublicKeySpec(kp.getPublic());
+
+ // validate the Diffie-Hellman public key
+ if (doExtraValiadtion) {
+ try {
+ KeyUtil.validate(spec);
+ } catch (InvalidKeyException ivke) {
+ if (i == MAX_FAILOVER_TIMES) {
+ throw ivke;
+ }
+ // otherwise, ignore the exception and try the next one
+ continue;
+ }
+ }
+
+ return spec;
+ }
+
+ return null;
+ }
}
--- a/jdk/src/share/classes/sun/security/ssl/HandshakeMessage.java Wed Aug 22 21:40:19 2012 -0400
+++ b/jdk/src/share/classes/sun/security/ssl/HandshakeMessage.java Mon Oct 22 07:28:51 2012 -0700
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1996, 2011, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1996, 2012, 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
@@ -41,12 +41,14 @@
import javax.crypto.KeyGenerator;
import javax.crypto.SecretKey;
+import javax.crypto.spec.DHPublicKeySpec;
import javax.net.ssl.*;
import sun.security.internal.spec.TlsPrfParameterSpec;
import sun.security.ssl.CipherSuite.*;
import static sun.security.ssl.CipherSuite.PRF.*;
+import sun.security.util.KeyUtil;
/**
* Many data structures are involved in the handshake messages. These
@@ -702,6 +704,7 @@
this.protocolVersion = protocolVersion;
this.preferableSignatureAlgorithm = null;
+ // The DH key has been validated in the constructor of DHCrypt.
setValues(obj);
signature = null;
}
@@ -718,6 +721,7 @@
this.protocolVersion = protocolVersion;
+ // The DH key has been validated in the constructor of DHCrypt.
setValues(obj);
Signature sig;
@@ -744,7 +748,8 @@
* DH_anon key exchange
*/
DH_ServerKeyExchange(HandshakeInStream input,
- ProtocolVersion protocolVersion) throws IOException {
+ ProtocolVersion protocolVersion)
+ throws IOException, GeneralSecurityException {
this.protocolVersion = protocolVersion;
this.preferableSignatureAlgorithm = null;
@@ -752,6 +757,10 @@
dh_p = input.getBytes16();
dh_g = input.getBytes16();
dh_Ys = input.getBytes16();
+ KeyUtil.validate(new DHPublicKeySpec(new BigInteger(1, dh_Ys),
+ new BigInteger(1, dh_p),
+ new BigInteger(1, dh_g)));
+
signature = null;
}
@@ -772,6 +781,9 @@
dh_p = input.getBytes16();
dh_g = input.getBytes16();
dh_Ys = input.getBytes16();
+ KeyUtil.validate(new DHPublicKeySpec(new BigInteger(1, dh_Ys),
+ new BigInteger(1, dh_p),
+ new BigInteger(1, dh_g)));
// read the signature and hash algorithm
if (protocolVersion.v >= ProtocolVersion.TLS12.v) {
--- a/jdk/src/share/classes/sun/security/ssl/RSAClientKeyExchange.java Wed Aug 22 21:40:19 2012 -0400
+++ b/jdk/src/share/classes/sun/security/ssl/RSAClientKeyExchange.java Mon Oct 22 07:28:51 2012 -0700
@@ -36,7 +36,7 @@
import javax.net.ssl.*;
import sun.security.internal.spec.TlsRsaPremasterSecretParameterSpec;
-import sun.security.util.KeyLength;
+import sun.security.util.KeyUtil;
/**
* This is the client key exchange message (CLIENT --> SERVER) used with
@@ -193,7 +193,7 @@
"unable to get the plaintext of the premaster secret");
}
- int keySize = KeyLength.getKeySize(secretKey);
+ int keySize = KeyUtil.getKeySize(secretKey);
if (keySize > 0 && keySize != 384) { // 384 = 48 * 8
if (debug != null && Debug.isOn("handshake")) {
System.out.println(
--- a/jdk/src/share/classes/sun/security/ssl/ServerHandshaker.java Wed Aug 22 21:40:19 2012 -0400
+++ b/jdk/src/share/classes/sun/security/ssl/ServerHandshaker.java Mon Oct 22 07:28:51 2012 -0700
@@ -1365,7 +1365,7 @@
if (debug != null && Debug.isOn("handshake")) {
mesg.print(System.out);
}
- return dh.getAgreedSecret(mesg.getClientPublicKey());
+ return dh.getAgreedSecret(mesg.getClientPublicKey(), false);
}
private SecretKey clientKeyExchange(ECDHClientKeyExchange mesg)
--- a/jdk/src/share/classes/sun/security/ssl/SignatureAndHashAlgorithm.java Wed Aug 22 21:40:19 2012 -0400
+++ b/jdk/src/share/classes/sun/security/ssl/SignatureAndHashAlgorithm.java Mon Oct 22 07:28:51 2012 -0700
@@ -38,7 +38,7 @@
import java.util.Collections;
import java.util.ArrayList;
-import sun.security.util.KeyLength;
+import sun.security.util.KeyUtil;
/**
* Signature and hash algorithm.
@@ -279,7 +279,7 @@
* If key size is less than 512, the digest length should be
* less than or equal to 20 bytes.
*/
- int keySize = KeyLength.getKeySize(signingKey);
+ int keySize = KeyUtil.getKeySize(signingKey);
if (keySize >= 768) {
maxDigestLength = HashAlgorithm.SHA512.length;
} else if ((keySize >= 512) && (keySize < 768)) {
--- a/jdk/src/share/classes/sun/security/util/DisabledAlgorithmConstraints.java Wed Aug 22 21:40:19 2012 -0400
+++ b/jdk/src/share/classes/sun/security/util/DisabledAlgorithmConstraints.java Mon Oct 22 07:28:51 2012 -0700
@@ -440,7 +440,7 @@
// Does this key constraint disable the specified key?
public boolean disables(Key key) {
- int size = KeyLength.getKeySize(key);
+ int size = KeyUtil.getKeySize(key);
if (size == 0) {
return true; // we don't allow any key of size 0.
--- a/jdk/src/share/classes/sun/security/util/KeyLength.java Wed Aug 22 21:40:19 2012 -0400
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,91 +0,0 @@
-/*
- * Copyright (c) 2012, 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. Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * 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.
- */
-
-package sun.security.util;
-
-import java.security.Key;
-import java.security.PrivilegedAction;
-import java.security.AccessController;
-import java.security.interfaces.ECKey;
-import java.security.interfaces.RSAKey;
-import java.security.interfaces.DSAKey;
-import javax.crypto.SecretKey;
-import javax.crypto.interfaces.DHKey;
-
-/**
- * A utility class to get key length
- */
-public final class KeyLength {
-
- /**
- * Returns the key size of the given key object in bits.
- *
- * @param key the key object, cannot be null
- * @return the key size of the given key object in bits, or -1 if the
- * key size is not accessible
- */
- final public static int getKeySize(Key key) {
- int size = -1;
-
- if (key instanceof Length) {
- try {
- Length ruler = (Length)key;
- size = ruler.length();
- } catch (UnsupportedOperationException usoe) {
- // ignore the exception
- }
-
- if (size >= 0) {
- return size;
- }
- }
-
- // try to parse the length from key specification
- if (key instanceof SecretKey) {
- SecretKey sk = (SecretKey)key;
- String format = sk.getFormat();
- if ("RAW".equals(format) && sk.getEncoded() != null) {
- size = (sk.getEncoded().length * 8);
- } // Otherwise, it may be a unextractable key of PKCS#11, or
- // a key we are not able to handle.
- } else if (key instanceof RSAKey) {
- RSAKey pubk = (RSAKey)key;
- size = pubk.getModulus().bitLength();
- } else if (key instanceof ECKey) {
- ECKey pubk = (ECKey)key;
- size = pubk.getParams().getOrder().bitLength();
- } else if (key instanceof DSAKey) {
- DSAKey pubk = (DSAKey)key;
- size = pubk.getParams().getP().bitLength();
- } else if (key instanceof DHKey) {
- DHKey pubk = (DHKey)key;
- size = pubk.getParams().getP().bitLength();
- } // Otherwise, it may be a unextractable key of PKCS#11, or
- // a key we are not able to handle.
-
- return size;
- }
-}
-
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/sun/security/util/KeyUtil.java Mon Oct 22 07:28:51 2012 -0700
@@ -0,0 +1,204 @@
+/*
+ * Copyright (c) 2012, 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. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * 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.
+ */
+
+package sun.security.util;
+
+import java.security.Key;
+import java.security.PrivilegedAction;
+import java.security.AccessController;
+import java.security.InvalidKeyException;
+import java.security.interfaces.ECKey;
+import java.security.interfaces.RSAKey;
+import java.security.interfaces.DSAKey;
+import java.security.spec.KeySpec;
+import javax.crypto.SecretKey;
+import javax.crypto.interfaces.DHKey;
+import javax.crypto.interfaces.DHPublicKey;
+import javax.crypto.spec.DHParameterSpec;
+import javax.crypto.spec.DHPublicKeySpec;
+import java.math.BigInteger;
+
+/**
+ * A utility class to get key length, valiate keys, etc.
+ */
+public final class KeyUtil {
+
+ /**
+ * Returns the key size of the given key object in bits.
+ *
+ * @param key the key object, cannot be null
+ * @return the key size of the given key object in bits, or -1 if the
+ * key size is not accessible
+ */
+ public static final int getKeySize(Key key) {
+ int size = -1;
+
+ if (key instanceof Length) {
+ try {
+ Length ruler = (Length)key;
+ size = ruler.length();
+ } catch (UnsupportedOperationException usoe) {
+ // ignore the exception
+ }
+
+ if (size >= 0) {
+ return size;
+ }
+ }
+
+ // try to parse the length from key specification
+ if (key instanceof SecretKey) {
+ SecretKey sk = (SecretKey)key;
+ String format = sk.getFormat();
+ if ("RAW".equals(format) && sk.getEncoded() != null) {
+ size = (sk.getEncoded().length * 8);
+ } // Otherwise, it may be a unextractable key of PKCS#11, or
+ // a key we are not able to handle.
+ } else if (key instanceof RSAKey) {
+ RSAKey pubk = (RSAKey)key;
+ size = pubk.getModulus().bitLength();
+ } else if (key instanceof ECKey) {
+ ECKey pubk = (ECKey)key;
+ size = pubk.getParams().getOrder().bitLength();
+ } else if (key instanceof DSAKey) {
+ DSAKey pubk = (DSAKey)key;
+ size = pubk.getParams().getP().bitLength();
+ } else if (key instanceof DHKey) {
+ DHKey pubk = (DHKey)key;
+ size = pubk.getParams().getP().bitLength();
+ } // Otherwise, it may be a unextractable key of PKCS#11, or
+ // a key we are not able to handle.
+
+ return size;
+ }
+
+ /**
+ * Returns whether the key is valid or not.
+ * <P>
+ * Note that this method is only apply to DHPublicKey at present.
+ *
+ * @param publicKey
+ * the key object, cannot be null
+ *
+ * @throws NullPointerException if {@code publicKey} is null
+ * @throws InvalidKeyException if {@code publicKey} is invalid
+ */
+ public static final void validate(Key key)
+ throws InvalidKeyException {
+ if (key == null) {
+ throw new NullPointerException(
+ "The key to be validated cannot be null");
+ }
+
+ if (key instanceof DHPublicKey) {
+ validateDHPublicKey((DHPublicKey)key);
+ }
+ }
+
+
+ /**
+ * Returns whether the key spec is valid or not.
+ * <P>
+ * Note that this method is only apply to DHPublicKeySpec at present.
+ *
+ * @param keySpec
+ * the key spec object, cannot be null
+ *
+ * @throws NullPointerException if {@code keySpec} is null
+ * @throws InvalidKeyException if {@code keySpec} is invalid
+ */
+ public static final void validate(KeySpec keySpec)
+ throws InvalidKeyException {
+ if (keySpec == null) {
+ throw new NullPointerException(
+ "The key spec to be validated cannot be null");
+ }
+
+ if (keySpec instanceof DHPublicKeySpec) {
+ validateDHPublicKey((DHPublicKeySpec)keySpec);
+ }
+ }
+
+ /**
+ * Returns whether the specified provider is Oracle provider or not.
+ * <P>
+ * Note that this method is only apply to SunJCE and SunPKCS11 at present.
+ *
+ * @param providerName
+ * the provider name
+ * @return true if, and only if, the provider of the specified
+ * {@code providerName} is Oracle provider
+ */
+ public static final boolean isOracleJCEProvider(String providerName) {
+ return providerName != null && (providerName.equals("SunJCE") ||
+ providerName.startsWith("SunPKCS11"));
+ }
+
+ /**
+ * Returns whether the Diffie-Hellman public key is valid or not.
+ *
+ * Per RFC 2631 and NIST SP800-56A, the following algorithm is used to
+ * validate Diffie-Hellman public keys:
+ * 1. Verify that y lies within the interval [2,p-1]. If it does not,
+ * the key is invalid.
+ * 2. Compute y^q mod p. If the result == 1, the key is valid.
+ * Otherwise the key is invalid.
+ */
+ private static void validateDHPublicKey(DHPublicKey publicKey)
+ throws InvalidKeyException {
+ DHParameterSpec paramSpec = publicKey.getParams();
+
+ BigInteger p = paramSpec.getP();
+ BigInteger g = paramSpec.getG();
+ BigInteger y = publicKey.getY();
+
+ validateDHPublicKey(p, g, y);
+ }
+
+ private static void validateDHPublicKey(DHPublicKeySpec publicKeySpec)
+ throws InvalidKeyException {
+ validateDHPublicKey(publicKeySpec.getP(),
+ publicKeySpec.getG(), publicKeySpec.getY());
+ }
+
+ private static void validateDHPublicKey(BigInteger p,
+ BigInteger g, BigInteger y) throws InvalidKeyException {
+
+ // For better interoperability, the interval is limited to [2, p-2].
+ BigInteger leftOpen = BigInteger.ONE;
+ BigInteger rightOpen = p.subtract(BigInteger.ONE);
+ if (y.compareTo(leftOpen) <= 0) {
+ throw new InvalidKeyException(
+ "Diffie-Hellman public key is too small");
+ }
+ if (y.compareTo(rightOpen) >= 0) {
+ throw new InvalidKeyException(
+ "Diffie-Hellman public key is too large");
+ }
+
+ // Don't bother to check against the y^q mod p if safe primes are used.
+ }
+}
+
--- a/jdk/test/sun/security/mscapi/ShortRSAKeyWithinTLS.java Wed Aug 22 21:40:19 2012 -0400
+++ b/jdk/test/sun/security/mscapi/ShortRSAKeyWithinTLS.java Mon Oct 22 07:28:51 2012 -0700
@@ -29,7 +29,7 @@
import javax.net.ssl.*;
import java.lang.reflect.*;
-import sun.security.util.KeyLength;
+import sun.security.util.KeyUtil;
public class ShortRSAKeyWithinTLS {
@@ -175,13 +175,13 @@
privateKey = (PrivateKey)ks.getKey(keyAlias, null);
publicKey = (PublicKey)ks.getCertificate(keyAlias).getPublicKey();
- int privateKeySize = KeyLength.getKeySize(privateKey);
+ int privateKeySize = KeyUtil.getKeySize(privateKey);
if (privateKeySize != keySize) {
throw new Exception("Expected key size is " + keySize +
", but the private key size is " + privateKeySize);
}
- int publicKeySize = KeyLength.getKeySize(publicKey);
+ int publicKeySize = KeyUtil.getKeySize(publicKey);
if (publicKeySize != keySize) {
throw new Exception("Expected key size is " + keySize +
", but the public key size is " + publicKeySize);