jdk/src/share/classes/sun/security/ssl/DHCrypt.java
Print this page
rev 5679 : 7192392: Better validation of client keys
Summary: Also reviewed by Andrew Gross<Andrew.Gross@Oracle.COM>
Reviewed-by: vinnie
*** 1,7 ****
/*
! * Copyright (c) 1996, 2008, 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
--- 1,7 ----
/*
! * 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
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
*** 26,41 ****
package sun.security.ssl;
import java.math.BigInteger;
import java.security.*;
!
import javax.crypto.SecretKey;
import javax.crypto.KeyAgreement;
import javax.crypto.interfaces.DHPublicKey;
import javax.crypto.spec.*;
/**
* This class implements the Diffie-Hellman key exchange algorithm.
* D-H means combining your private key with your partners public key to
* generate a number. The peer does the same with its private key and our
* public key. Through the magic of Diffie-Hellman we both come up with the
--- 26,44 ----
package sun.security.ssl;
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
* generate a number. The peer does the same with its private key and our
* public key. Through the magic of Diffie-Hellman we both come up with the
*** 52,62 ****
*
* General usage of this class (TLS DHE case):
* . 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.
* . send parameters and public value to remote peer
* . receive peers ephemeral public key
* . call getAgreedSecret() to calculate the shared secret
*
* In TLS the server chooses the parameter values itself, the client must use
--- 55,66 ----
*
* General usage of this class (TLS DHE case):
* . 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.
* . send parameters and public value to remote peer
* . receive peers ephemeral public key
* . call getAgreedSecret() to calculate the shared secret
*
* In TLS the server chooses the parameter values itself, the client must use
*** 81,100 ****
private PrivateKey privateKey;
// public component of our key, X = (g ^ x) mod p
private BigInteger publicValue; // X (aka y)
/**
* Generate a Diffie-Hellman keypair of the specified size.
*/
DHCrypt(int keyLength, SecureRandom random) {
try {
KeyPairGenerator kpg = JsseJce.getKeyPairGenerator("DiffieHellman");
kpg.initialize(keyLength, random);
! KeyPair kp = kpg.generateKeyPair();
! privateKey = kp.getPrivate();
! DHPublicKeySpec spec = getDHPublicKeySpec(kp.getPublic());
publicValue = spec.getY();
modulus = spec.getP();
base = spec.getG();
} catch (GeneralSecurityException e) {
throw new RuntimeException("Could not generate DH keypair", e);
--- 85,110 ----
private PrivateKey privateKey;
// 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.
*/
DHCrypt(int keyLength, SecureRandom random) {
try {
KeyPairGenerator kpg = JsseJce.getKeyPairGenerator("DiffieHellman");
kpg.initialize(keyLength, random);
!
! DHPublicKeySpec spec = generateDHPublicKeySpec(kpg);
! if (spec == null) {
! throw new RuntimeException("Could not generate DH keypair");
! }
!
publicValue = spec.getY();
modulus = spec.getP();
base = spec.getG();
} catch (GeneralSecurityException e) {
throw new RuntimeException("Could not generate DH keypair", e);
*** 113,136 ****
this.base = base;
try {
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());
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());
}
try {
KeyFactory factory = JsseJce.getKeyFactory("DH");
return factory.getKeySpec(key, DHPublicKeySpec.class);
} catch (Exception e) {
--- 123,151 ----
this.base = base;
try {
KeyPairGenerator kpg = JsseJce.getKeyPairGenerator("DiffieHellman");
DHParameterSpec params = new DHParameterSpec(modulus, base);
kpg.initialize(params, random);
!
! 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());
}
try {
KeyFactory factory = JsseJce.getKeyFactory("DH");
return factory.getKeySpec(key, DHPublicKeySpec.class);
} catch (Exception e) {
*** 165,188 ****
*
* <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.
*/
! SecretKey getAgreedSecret(BigInteger peerPublicValue) {
try {
KeyFactory kf = JsseJce.getKeyFactory("DiffieHellman");
DHPublicKeySpec spec =
new DHPublicKeySpec(peerPublicValue, modulus, base);
PublicKey publicKey = kf.generatePublic(spec);
KeyAgreement ka = JsseJce.getKeyAgreement("DiffieHellman");
ka.init(privateKey);
ka.doPhase(publicKey, true);
return ka.generateSecret("TlsPremasterSecret");
} catch (GeneralSecurityException e) {
throw new RuntimeException("Could not generate secret", e);
}
}
}
--- 180,247 ----
*
* <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.
! * @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,
! 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");
} catch (GeneralSecurityException e) {
throw new RuntimeException("Could not generate secret", e);
}
}
+ // 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;
+ }
}