8028192: Use of PKCS11-NSS provider in FIPS mode broken
Reviewed-by: ahgross, ascarpino, asmotrak
This commit is contained in:
parent
8962e7ee34
commit
2f501cd8a5
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2003, 2014, 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
|
||||
@ -39,6 +39,8 @@ import javax.crypto.spec.OAEPParameterSpec;
|
||||
|
||||
import sun.security.rsa.*;
|
||||
import sun.security.jca.Providers;
|
||||
import sun.security.internal.spec.TlsRsaPremasterSecretParameterSpec;
|
||||
import sun.security.util.KeyUtil;
|
||||
|
||||
/**
|
||||
* RSA cipher implementation. Supports RSA en/decryption and signing/verifying
|
||||
@ -91,8 +93,8 @@ public final class RSACipher extends CipherSpi {
|
||||
// padding object
|
||||
private RSAPadding padding;
|
||||
|
||||
// cipher parameter for OAEP padding
|
||||
private OAEPParameterSpec spec = null;
|
||||
// cipher parameter for OAEP padding and TLS RSA premaster secret
|
||||
private AlgorithmParameterSpec spec = null;
|
||||
|
||||
// buffer for the data
|
||||
private byte[] buffer;
|
||||
@ -110,6 +112,9 @@ public final class RSACipher extends CipherSpi {
|
||||
// hash algorithm for OAEP
|
||||
private String oaepHashAlgorithm = "SHA-1";
|
||||
|
||||
// the source of randomness
|
||||
private SecureRandom random;
|
||||
|
||||
public RSACipher() {
|
||||
paddingType = PAD_PKCS1;
|
||||
}
|
||||
@ -175,7 +180,7 @@ public final class RSACipher extends CipherSpi {
|
||||
|
||||
// see JCE spec
|
||||
protected AlgorithmParameters engineGetParameters() {
|
||||
if (spec != null) {
|
||||
if (spec != null && spec instanceof OAEPParameterSpec) {
|
||||
try {
|
||||
AlgorithmParameters params =
|
||||
AlgorithmParameters.getInstance("OAEP",
|
||||
@ -276,8 +281,13 @@ public final class RSACipher extends CipherSpi {
|
||||
buffer = new byte[n];
|
||||
} else if (paddingType == PAD_PKCS1) {
|
||||
if (params != null) {
|
||||
throw new InvalidAlgorithmParameterException
|
||||
("Parameters not supported");
|
||||
if (!(params instanceof TlsRsaPremasterSecretParameterSpec)) {
|
||||
throw new InvalidAlgorithmParameterException(
|
||||
"Parameters not supported");
|
||||
}
|
||||
|
||||
spec = params;
|
||||
this.random = random; // for TLS RSA premaster secret
|
||||
}
|
||||
int blockType = (mode <= MODE_DECRYPT) ? RSAPadding.PAD_BLOCKTYPE_2
|
||||
: RSAPadding.PAD_BLOCKTYPE_1;
|
||||
@ -293,19 +303,18 @@ public final class RSACipher extends CipherSpi {
|
||||
throw new InvalidKeyException
|
||||
("OAEP cannot be used to sign or verify signatures");
|
||||
}
|
||||
OAEPParameterSpec myParams;
|
||||
if (params != null) {
|
||||
if (!(params instanceof OAEPParameterSpec)) {
|
||||
throw new InvalidAlgorithmParameterException
|
||||
("Wrong Parameters for OAEP Padding");
|
||||
}
|
||||
myParams = (OAEPParameterSpec) params;
|
||||
spec = params;
|
||||
} else {
|
||||
myParams = new OAEPParameterSpec(oaepHashAlgorithm, "MGF1",
|
||||
spec = new OAEPParameterSpec(oaepHashAlgorithm, "MGF1",
|
||||
MGF1ParameterSpec.SHA1, PSource.PSpecified.DEFAULT);
|
||||
}
|
||||
padding = RSAPadding.getInstance(RSAPadding.PAD_OAEP_MGF1, n,
|
||||
random, myParams);
|
||||
random, (OAEPParameterSpec)spec);
|
||||
if (encrypt) {
|
||||
int k = padding.getMaxDataSize();
|
||||
buffer = new byte[k];
|
||||
@ -420,17 +429,40 @@ public final class RSACipher extends CipherSpi {
|
||||
if (wrappedKey.length > buffer.length) {
|
||||
throw new InvalidKeyException("Key is too long for unwrapping");
|
||||
}
|
||||
|
||||
boolean isTlsRsaPremasterSecret =
|
||||
algorithm.equals("TlsRsaPremasterSecret");
|
||||
Exception failover = null;
|
||||
byte[] encoded = null;
|
||||
|
||||
update(wrappedKey, 0, wrappedKey.length);
|
||||
try {
|
||||
byte[] encoded = doFinal();
|
||||
return ConstructKeys.constructKey(encoded, algorithm, type);
|
||||
encoded = doFinal();
|
||||
} catch (BadPaddingException e) {
|
||||
// should not occur
|
||||
throw new InvalidKeyException("Unwrapping failed", e);
|
||||
if (isTlsRsaPremasterSecret) {
|
||||
failover = e;
|
||||
} else {
|
||||
throw new InvalidKeyException("Unwrapping failed", e);
|
||||
}
|
||||
} catch (IllegalBlockSizeException e) {
|
||||
// should not occur, handled with length check above
|
||||
throw new InvalidKeyException("Unwrapping failed", e);
|
||||
}
|
||||
|
||||
if (isTlsRsaPremasterSecret) {
|
||||
if (!(spec instanceof TlsRsaPremasterSecretParameterSpec)) {
|
||||
throw new IllegalStateException(
|
||||
"No TlsRsaPremasterSecretParameterSpec specified");
|
||||
}
|
||||
|
||||
// polish the TLS premaster secret
|
||||
encoded = KeyUtil.checkTlsPreMasterSecretKey(
|
||||
((TlsRsaPremasterSecretParameterSpec)spec).getClientVersion(),
|
||||
((TlsRsaPremasterSecretParameterSpec)spec).getServerVersion(),
|
||||
random, encoded, (failover != null));
|
||||
}
|
||||
|
||||
return ConstructKeys.constructKey(encoded, algorithm, type);
|
||||
}
|
||||
|
||||
// see JCE spec
|
||||
@ -438,5 +470,4 @@ public final class RSACipher extends CipherSpi {
|
||||
RSAKey rsaKey = RSAKeyFactory.toRSAKey(key);
|
||||
return rsaKey.getModulus().bitLength();
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2005, 2013, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2005, 2014, 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
|
||||
@ -56,7 +56,7 @@ public final class TlsRsaPremasterSecretGenerator extends KeyGeneratorSpi {
|
||||
|
||||
protected void engineInit(AlgorithmParameterSpec params,
|
||||
SecureRandom random) throws InvalidAlgorithmParameterException {
|
||||
if (params instanceof TlsRsaPremasterSecretParameterSpec == false) {
|
||||
if (!(params instanceof TlsRsaPremasterSecretParameterSpec)) {
|
||||
throw new InvalidAlgorithmParameterException(MSG);
|
||||
}
|
||||
this.spec = (TlsRsaPremasterSecretParameterSpec)params;
|
||||
@ -67,21 +67,20 @@ public final class TlsRsaPremasterSecretGenerator extends KeyGeneratorSpi {
|
||||
throw new InvalidParameterException(MSG);
|
||||
}
|
||||
|
||||
// Only can be used in client side to generate TLS RSA premaster secret.
|
||||
protected SecretKey engineGenerateKey() {
|
||||
if (spec == null) {
|
||||
throw new IllegalStateException(
|
||||
"TlsRsaPremasterSecretGenerator must be initialized");
|
||||
}
|
||||
byte[] b = spec.getEncodedSecret();
|
||||
if (b == null) {
|
||||
if (random == null) {
|
||||
random = new SecureRandom();
|
||||
}
|
||||
b = new byte[48];
|
||||
random.nextBytes(b);
|
||||
b[0] = (byte)spec.getMajorVersion();
|
||||
b[1] = (byte)spec.getMinorVersion();
|
||||
|
||||
if (random == null) {
|
||||
random = new SecureRandom();
|
||||
}
|
||||
byte[] b = new byte[48];
|
||||
random.nextBytes(b);
|
||||
b[0] = (byte)spec.getMajorVersion();
|
||||
b[1] = (byte)spec.getMinorVersion();
|
||||
|
||||
return new SecretKeySpec(b, "TlsRsaPremasterSecret");
|
||||
}
|
||||
|
@ -26,11 +26,11 @@
|
||||
package sun.security.internal.spec;
|
||||
|
||||
import java.security.spec.AlgorithmParameterSpec;
|
||||
import java.security.AccessController;
|
||||
import java.security.PrivilegedAction;
|
||||
|
||||
/**
|
||||
* Parameters for SSL/TLS RSA Premaster secret generation.
|
||||
* This class is used by SSL/TLS client to initialize KeyGenerators of the
|
||||
* type "TlsRsaPremasterSecret".
|
||||
* Parameters for SSL/TLS RSA premaster secret.
|
||||
*
|
||||
* <p>Instances of this class are immutable.
|
||||
*
|
||||
@ -43,90 +43,108 @@ import java.security.spec.AlgorithmParameterSpec;
|
||||
public class TlsRsaPremasterSecretParameterSpec
|
||||
implements AlgorithmParameterSpec {
|
||||
|
||||
private final int majorVersion;
|
||||
private final int minorVersion;
|
||||
private final byte[] encodedSecret;
|
||||
/*
|
||||
* The TLS spec says that the version in the RSA premaster secret must
|
||||
* be the maximum version supported by the client (i.e. the version it
|
||||
* requested in its client hello version). However, we (and other
|
||||
* implementations) used to send the active negotiated version. The
|
||||
* system property below allows to toggle the behavior.
|
||||
*/
|
||||
private final static String PROP_NAME =
|
||||
"com.sun.net.ssl.rsaPreMasterSecretFix";
|
||||
|
||||
/*
|
||||
* Default is "false" (old behavior) for compatibility reasons in
|
||||
* SSLv3/TLSv1. Later protocols (TLSv1.1+) do not use this property.
|
||||
*/
|
||||
private final static boolean rsaPreMasterSecretFix =
|
||||
AccessController.doPrivileged(new PrivilegedAction<Boolean>() {
|
||||
public Boolean run() {
|
||||
String value = System.getProperty(PROP_NAME);
|
||||
if (value != null && value.equalsIgnoreCase("true")) {
|
||||
return Boolean.TRUE;
|
||||
}
|
||||
|
||||
return Boolean.FALSE;
|
||||
}
|
||||
});
|
||||
|
||||
private final int clientVersion;
|
||||
private final int serverVersion;
|
||||
|
||||
/**
|
||||
* Constructs a new TlsRsaPremasterSecretParameterSpec.
|
||||
* <P>
|
||||
* The version numbers will be placed inside the premaster secret to
|
||||
* detect version rollbacks attacks as described in the TLS specification.
|
||||
* Note that they do not indicate the protocol version negotiated for
|
||||
* the handshake.
|
||||
*
|
||||
* @param majorVersion the major number of the protocol version
|
||||
* @param minorVersion the minor number of the protocol version
|
||||
* @param clientVersion the version of the TLS protocol by which the
|
||||
* client wishes to communicate during this session
|
||||
* @param serverVersion the negotiated version of the TLS protocol which
|
||||
* contains the lower of that suggested by the client in the client
|
||||
* hello and the highest supported by the server.
|
||||
*
|
||||
* @throws IllegalArgumentException if minorVersion or majorVersion are
|
||||
* negative or larger than 255
|
||||
* @throws IllegalArgumentException if clientVersion or serverVersion are
|
||||
* negative or larger than (2^16 - 1)
|
||||
*/
|
||||
public TlsRsaPremasterSecretParameterSpec(int majorVersion,
|
||||
int minorVersion) {
|
||||
this.majorVersion =
|
||||
TlsMasterSecretParameterSpec.checkVersion(majorVersion);
|
||||
this.minorVersion =
|
||||
TlsMasterSecretParameterSpec.checkVersion(minorVersion);
|
||||
this.encodedSecret = null;
|
||||
public TlsRsaPremasterSecretParameterSpec(
|
||||
int clientVersion, int serverVersion) {
|
||||
|
||||
this.clientVersion = checkVersion(clientVersion);
|
||||
this.serverVersion = checkVersion(serverVersion);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a new TlsRsaPremasterSecretParameterSpec.
|
||||
* <P>
|
||||
* The version numbers will be placed inside the premaster secret to
|
||||
* detect version rollbacks attacks as described in the TLS specification.
|
||||
* Note that they do not indicate the protocol version negotiated for
|
||||
* the handshake.
|
||||
* <P>
|
||||
* Usually, the encoded secret key is a random number that acts as
|
||||
* dummy pre_master_secret to avoid vulnerabilities described by
|
||||
* section 7.4.7.1, RFC 5246.
|
||||
* Returns the version of the TLS protocol by which the client wishes to
|
||||
* communicate during this session.
|
||||
*
|
||||
* @param majorVersion the major number of the protocol version
|
||||
* @param minorVersion the minor number of the protocol version
|
||||
* @param encodedSecret the encoded secret key
|
||||
*
|
||||
* @throws IllegalArgumentException if minorVersion or majorVersion are
|
||||
* negative or larger than 255, or encodedSecret is not exactly 48 bytes.
|
||||
* @return the version of the TLS protocol in ClientHello message
|
||||
*/
|
||||
public TlsRsaPremasterSecretParameterSpec(int majorVersion,
|
||||
int minorVersion, byte[] encodedSecret) {
|
||||
this.majorVersion =
|
||||
TlsMasterSecretParameterSpec.checkVersion(majorVersion);
|
||||
this.minorVersion =
|
||||
TlsMasterSecretParameterSpec.checkVersion(minorVersion);
|
||||
|
||||
if (encodedSecret == null || encodedSecret.length != 48) {
|
||||
throw new IllegalArgumentException(
|
||||
"Encoded secret is not exactly 48 bytes");
|
||||
}
|
||||
this.encodedSecret = encodedSecret.clone();
|
||||
public int getClientVersion() {
|
||||
return clientVersion;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the major version.
|
||||
* Returns the negotiated version of the TLS protocol which contains the
|
||||
* lower of that suggested by the client in the client hello and the
|
||||
* highest supported by the server.
|
||||
*
|
||||
* @return the major version.
|
||||
* @return the negotiated version of the TLS protocol in ServerHello message
|
||||
*/
|
||||
public int getServerVersion() {
|
||||
return serverVersion;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the major version used in RSA premaster secret.
|
||||
*
|
||||
* @return the major version used in RSA premaster secret.
|
||||
*/
|
||||
public int getMajorVersion() {
|
||||
return majorVersion;
|
||||
if (rsaPreMasterSecretFix || clientVersion >= 0x0302) {
|
||||
// 0x0302: TLSv1.1
|
||||
return (clientVersion >>> 8) & 0xFF;
|
||||
}
|
||||
|
||||
return (serverVersion >>> 8) & 0xFF;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the minor version.
|
||||
* Returns the minor version used in RSA premaster secret.
|
||||
*
|
||||
* @return the minor version.
|
||||
* @return the minor version used in RSA premaster secret.
|
||||
*/
|
||||
public int getMinorVersion() {
|
||||
return minorVersion;
|
||||
if (rsaPreMasterSecretFix || clientVersion >= 0x0302) {
|
||||
// 0x0302: TLSv1.1
|
||||
return clientVersion & 0xFF;
|
||||
}
|
||||
|
||||
return serverVersion & 0xFF;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the encoded secret.
|
||||
*
|
||||
* @return the encoded secret, may be null if no encoded secret.
|
||||
*/
|
||||
public byte[] getEncodedSecret() {
|
||||
return encodedSecret == null ? null : encodedSecret.clone();
|
||||
private int checkVersion(int version) {
|
||||
if ((version < 0) || (version > 0xFFFF)) {
|
||||
throw new IllegalArgumentException(
|
||||
"Version must be between 0 and 65,535");
|
||||
}
|
||||
return version;
|
||||
}
|
||||
}
|
||||
|
@ -37,6 +37,8 @@ import javax.crypto.spec.*;
|
||||
import static sun.security.pkcs11.TemplateManager.*;
|
||||
import sun.security.pkcs11.wrapper.*;
|
||||
import static sun.security.pkcs11.wrapper.PKCS11Constants.*;
|
||||
import sun.security.internal.spec.TlsRsaPremasterSecretParameterSpec;
|
||||
import sun.security.util.KeyUtil;
|
||||
|
||||
/**
|
||||
* RSA Cipher implementation class. We currently only support
|
||||
@ -102,6 +104,12 @@ final class P11RSACipher extends CipherSpi {
|
||||
// maximum output size. this is the length of the key
|
||||
private int outputSize;
|
||||
|
||||
// cipher parameter for TLS RSA premaster secret
|
||||
private AlgorithmParameterSpec spec = null;
|
||||
|
||||
// the source of randomness
|
||||
private SecureRandom random;
|
||||
|
||||
P11RSACipher(Token token, String algorithm, long mechanism)
|
||||
throws PKCS11Exception {
|
||||
super();
|
||||
@ -165,8 +173,12 @@ final class P11RSACipher extends CipherSpi {
|
||||
AlgorithmParameterSpec params, SecureRandom random)
|
||||
throws InvalidKeyException, InvalidAlgorithmParameterException {
|
||||
if (params != null) {
|
||||
throw new InvalidAlgorithmParameterException
|
||||
("Parameters not supported");
|
||||
if (!(params instanceof TlsRsaPremasterSecretParameterSpec)) {
|
||||
throw new InvalidAlgorithmParameterException(
|
||||
"Parameters not supported");
|
||||
}
|
||||
spec = params;
|
||||
this.random = random; // for TLS RSA premaster secret
|
||||
}
|
||||
implInit(opmode, key);
|
||||
}
|
||||
@ -176,8 +188,8 @@ final class P11RSACipher extends CipherSpi {
|
||||
SecureRandom random)
|
||||
throws InvalidKeyException, InvalidAlgorithmParameterException {
|
||||
if (params != null) {
|
||||
throw new InvalidAlgorithmParameterException
|
||||
("Parameters not supported");
|
||||
throw new InvalidAlgorithmParameterException(
|
||||
"Parameters not supported");
|
||||
}
|
||||
implInit(opmode, key);
|
||||
}
|
||||
@ -452,21 +464,101 @@ final class P11RSACipher extends CipherSpi {
|
||||
protected Key engineUnwrap(byte[] wrappedKey, String algorithm,
|
||||
int type) throws InvalidKeyException, NoSuchAlgorithmException {
|
||||
|
||||
// XXX implement unwrap using C_Unwrap() for all keys
|
||||
implInit(Cipher.DECRYPT_MODE, p11Key);
|
||||
if (wrappedKey.length > maxInputSize) {
|
||||
throw new InvalidKeyException("Key is too long for unwrapping");
|
||||
boolean isTlsRsaPremasterSecret =
|
||||
algorithm.equals("TlsRsaPremasterSecret");
|
||||
Exception failover = null;
|
||||
|
||||
SecureRandom secureRandom = random;
|
||||
if (secureRandom == null && isTlsRsaPremasterSecret) {
|
||||
secureRandom = new SecureRandom();
|
||||
}
|
||||
implUpdate(wrappedKey, 0, wrappedKey.length);
|
||||
try {
|
||||
byte[] encoded = doFinal();
|
||||
|
||||
// Should C_Unwrap be preferred for non-TLS RSA premaster secret?
|
||||
if (token.supportsRawSecretKeyImport()) {
|
||||
// XXX implement unwrap using C_Unwrap() for all keys
|
||||
implInit(Cipher.DECRYPT_MODE, p11Key);
|
||||
if (wrappedKey.length > maxInputSize) {
|
||||
throw new InvalidKeyException("Key is too long for unwrapping");
|
||||
}
|
||||
|
||||
byte[] encoded = null;
|
||||
implUpdate(wrappedKey, 0, wrappedKey.length);
|
||||
try {
|
||||
encoded = doFinal();
|
||||
} catch (BadPaddingException e) {
|
||||
if (isTlsRsaPremasterSecret) {
|
||||
failover = e;
|
||||
} else {
|
||||
throw new InvalidKeyException("Unwrapping failed", e);
|
||||
}
|
||||
} catch (IllegalBlockSizeException e) {
|
||||
// should not occur, handled with length check above
|
||||
throw new InvalidKeyException("Unwrapping failed", e);
|
||||
}
|
||||
|
||||
if (isTlsRsaPremasterSecret) {
|
||||
if (!(spec instanceof TlsRsaPremasterSecretParameterSpec)) {
|
||||
throw new IllegalStateException(
|
||||
"No TlsRsaPremasterSecretParameterSpec specified");
|
||||
}
|
||||
|
||||
// polish the TLS premaster secret
|
||||
TlsRsaPremasterSecretParameterSpec psps =
|
||||
(TlsRsaPremasterSecretParameterSpec)spec;
|
||||
encoded = KeyUtil.checkTlsPreMasterSecretKey(
|
||||
psps.getClientVersion(), psps.getServerVersion(),
|
||||
secureRandom, encoded, (failover != null));
|
||||
}
|
||||
|
||||
return ConstructKeys.constructKey(encoded, algorithm, type);
|
||||
} catch (BadPaddingException e) {
|
||||
// should not occur
|
||||
throw new InvalidKeyException("Unwrapping failed", e);
|
||||
} catch (IllegalBlockSizeException e) {
|
||||
// should not occur, handled with length check above
|
||||
throw new InvalidKeyException("Unwrapping failed", e);
|
||||
} else {
|
||||
Session s = null;
|
||||
SecretKey secretKey = null;
|
||||
try {
|
||||
try {
|
||||
s = token.getObjSession();
|
||||
long keyType = CKK_GENERIC_SECRET;
|
||||
CK_ATTRIBUTE[] attributes = new CK_ATTRIBUTE[] {
|
||||
new CK_ATTRIBUTE(CKA_CLASS, CKO_SECRET_KEY),
|
||||
new CK_ATTRIBUTE(CKA_KEY_TYPE, keyType),
|
||||
};
|
||||
attributes = token.getAttributes(
|
||||
O_IMPORT, CKO_SECRET_KEY, keyType, attributes);
|
||||
long keyID = token.p11.C_UnwrapKey(s.id(),
|
||||
new CK_MECHANISM(mechanism), p11Key.keyID,
|
||||
wrappedKey, attributes);
|
||||
secretKey = P11Key.secretKey(s, keyID,
|
||||
algorithm, 48 << 3, attributes);
|
||||
} catch (PKCS11Exception e) {
|
||||
if (isTlsRsaPremasterSecret) {
|
||||
failover = e;
|
||||
} else {
|
||||
throw new InvalidKeyException("unwrap() failed", e);
|
||||
}
|
||||
}
|
||||
|
||||
if (isTlsRsaPremasterSecret) {
|
||||
byte[] replacer = new byte[48];
|
||||
if (failover == null) {
|
||||
// Does smart compiler dispose this operation?
|
||||
secureRandom.nextBytes(replacer);
|
||||
}
|
||||
|
||||
TlsRsaPremasterSecretParameterSpec psps =
|
||||
(TlsRsaPremasterSecretParameterSpec)spec;
|
||||
|
||||
// Please use the tricky failover and replacer byte array
|
||||
// as the parameters so that smart compiler won't dispose
|
||||
// the unused variable .
|
||||
secretKey = polishPreMasterSecretKey(token, s,
|
||||
failover, replacer, secretKey,
|
||||
psps.getClientVersion(), psps.getServerVersion());
|
||||
}
|
||||
|
||||
return secretKey;
|
||||
} finally {
|
||||
token.releaseSession(s);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -475,6 +567,34 @@ final class P11RSACipher extends CipherSpi {
|
||||
int n = P11KeyFactory.convertKey(token, key, algorithm).length();
|
||||
return n;
|
||||
}
|
||||
|
||||
private static SecretKey polishPreMasterSecretKey(
|
||||
Token token, Session session,
|
||||
Exception failover, byte[] replacer, SecretKey secretKey,
|
||||
int clientVersion, int serverVersion) {
|
||||
|
||||
if (failover != null) {
|
||||
CK_VERSION version = new CK_VERSION(
|
||||
(clientVersion >>> 8) & 0xFF, clientVersion & 0xFF);
|
||||
try {
|
||||
CK_ATTRIBUTE[] attributes = token.getAttributes(
|
||||
O_GENERATE, CKO_SECRET_KEY,
|
||||
CKK_GENERIC_SECRET, new CK_ATTRIBUTE[0]);
|
||||
long keyID = token.p11.C_GenerateKey(session.id(),
|
||||
// new CK_MECHANISM(CKM_TLS_PRE_MASTER_KEY_GEN, version),
|
||||
new CK_MECHANISM(CKM_SSL3_PRE_MASTER_KEY_GEN, version),
|
||||
attributes);
|
||||
return P11Key.secretKey(session,
|
||||
keyID, "TlsRsaPremasterSecret", 48 << 3, attributes);
|
||||
} catch (PKCS11Exception e) {
|
||||
throw new ProviderException(
|
||||
"Could not generate premaster secret", e);
|
||||
}
|
||||
}
|
||||
|
||||
return secretKey;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
final class ConstructKeys {
|
||||
|
@ -73,7 +73,7 @@ final class P11TlsRsaPremasterSecretGenerator extends KeyGeneratorSpi {
|
||||
|
||||
protected void engineInit(AlgorithmParameterSpec params,
|
||||
SecureRandom random) throws InvalidAlgorithmParameterException {
|
||||
if (params instanceof TlsRsaPremasterSecretParameterSpec == false) {
|
||||
if (!(params instanceof TlsRsaPremasterSecretParameterSpec)) {
|
||||
throw new InvalidAlgorithmParameterException(MSG);
|
||||
}
|
||||
this.spec = (TlsRsaPremasterSecretParameterSpec)params;
|
||||
@ -83,38 +83,32 @@ final class P11TlsRsaPremasterSecretGenerator extends KeyGeneratorSpi {
|
||||
throw new InvalidParameterException(MSG);
|
||||
}
|
||||
|
||||
// Only can be used in client side to generate TLS RSA premaster secret.
|
||||
protected SecretKey engineGenerateKey() {
|
||||
if (spec == null) {
|
||||
throw new IllegalStateException
|
||||
("TlsRsaPremasterSecretGenerator must be initialized");
|
||||
}
|
||||
|
||||
byte[] b = spec.getEncodedSecret();
|
||||
if (b == null) {
|
||||
CK_VERSION version = new CK_VERSION(
|
||||
CK_VERSION version = new CK_VERSION(
|
||||
spec.getMajorVersion(), spec.getMinorVersion());
|
||||
Session session = null;
|
||||
try {
|
||||
session = token.getObjSession();
|
||||
CK_ATTRIBUTE[] attributes = token.getAttributes(
|
||||
O_GENERATE, CKO_SECRET_KEY,
|
||||
CKK_GENERIC_SECRET, new CK_ATTRIBUTE[0]);
|
||||
long keyID = token.p11.C_GenerateKey(session.id(),
|
||||
new CK_MECHANISM(mechanism, version), attributes);
|
||||
SecretKey key = P11Key.secretKey(session,
|
||||
keyID, "TlsRsaPremasterSecret", 48 << 3, attributes);
|
||||
return key;
|
||||
} catch (PKCS11Exception e) {
|
||||
throw new ProviderException(
|
||||
"Could not generate premaster secret", e);
|
||||
} finally {
|
||||
token.releaseSession(session);
|
||||
}
|
||||
Session session = null;
|
||||
try {
|
||||
session = token.getObjSession();
|
||||
CK_ATTRIBUTE[] attributes = token.getAttributes(
|
||||
O_GENERATE, CKO_SECRET_KEY,
|
||||
CKK_GENERIC_SECRET, new CK_ATTRIBUTE[0]);
|
||||
long keyID = token.p11.C_GenerateKey(session.id(),
|
||||
new CK_MECHANISM(mechanism, version), attributes);
|
||||
SecretKey key = P11Key.secretKey(session,
|
||||
keyID, "TlsRsaPremasterSecret", 48 << 3, attributes);
|
||||
return key;
|
||||
} catch (PKCS11Exception e) {
|
||||
throw new ProviderException(
|
||||
"Could not generate premaster secret", e);
|
||||
} finally {
|
||||
token.releaseSession(session);
|
||||
}
|
||||
|
||||
// Won't worry, the TlsRsaPremasterSecret will be soon converted to
|
||||
// TlsMasterSecret.
|
||||
return new SecretKeySpec(b, "TlsRsaPremasterSecret");
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -36,6 +36,7 @@ import javax.security.auth.login.LoginException;
|
||||
import sun.security.jca.JCAUtil;
|
||||
|
||||
import sun.security.pkcs11.wrapper.*;
|
||||
import static sun.security.pkcs11.TemplateManager.*;
|
||||
import static sun.security.pkcs11.wrapper.PKCS11Constants.*;
|
||||
|
||||
/**
|
||||
@ -122,6 +123,9 @@ class Token implements Serializable {
|
||||
private final static CK_MECHANISM_INFO INVALID_MECH =
|
||||
new CK_MECHANISM_INFO(0, 0, 0);
|
||||
|
||||
// flag indicating whether the token supports raw secret key material import
|
||||
private Boolean supportsRawSecretKeyImport;
|
||||
|
||||
Token(SunPKCS11 provider) throws PKCS11Exception {
|
||||
this.provider = provider;
|
||||
this.removable = provider.removable;
|
||||
@ -160,6 +164,36 @@ class Token implements Serializable {
|
||||
return writeProtected;
|
||||
}
|
||||
|
||||
// return whether the token supports raw secret key material import
|
||||
boolean supportsRawSecretKeyImport() {
|
||||
if (supportsRawSecretKeyImport == null) {
|
||||
SecureRandom random = JCAUtil.getSecureRandom();
|
||||
byte[] encoded = new byte[48];
|
||||
random.nextBytes(encoded);
|
||||
|
||||
CK_ATTRIBUTE[] attributes = new CK_ATTRIBUTE[3];
|
||||
attributes[0] = new CK_ATTRIBUTE(CKA_CLASS, CKO_SECRET_KEY);
|
||||
attributes[1] = new CK_ATTRIBUTE(CKA_KEY_TYPE, CKK_GENERIC_SECRET);
|
||||
attributes[2] = new CK_ATTRIBUTE(CKA_VALUE, encoded);
|
||||
|
||||
Session session = null;
|
||||
try {
|
||||
attributes = getAttributes(O_IMPORT,
|
||||
CKO_SECRET_KEY, CKK_GENERIC_SECRET, attributes);
|
||||
session = getObjSession();
|
||||
long keyID = p11.C_CreateObject(session.id(), attributes);
|
||||
|
||||
supportsRawSecretKeyImport = Boolean.TRUE;
|
||||
} catch (PKCS11Exception e) {
|
||||
supportsRawSecretKeyImport = Boolean.FALSE;
|
||||
} finally {
|
||||
releaseSession(session);
|
||||
}
|
||||
}
|
||||
|
||||
return supportsRawSecretKeyImport;
|
||||
}
|
||||
|
||||
// return whether we are logged in
|
||||
// uses cached result if current. session is optional and may be null
|
||||
boolean isLoggedIn(Session session) throws PKCS11Exception {
|
||||
|
@ -48,23 +48,6 @@ import sun.security.util.KeyUtil;
|
||||
*/
|
||||
final class RSAClientKeyExchange extends HandshakeMessage {
|
||||
|
||||
/**
|
||||
* The TLS spec says that the version in the RSA premaster secret must
|
||||
* be the maximum version supported by the client (i.e. the version it
|
||||
* requested in its client hello version). However, we (and other
|
||||
* implementations) used to send the active negotiated version. The
|
||||
* system property below allows to toggle the behavior.
|
||||
*/
|
||||
private final static String PROP_NAME =
|
||||
"com.sun.net.ssl.rsaPreMasterSecretFix";
|
||||
|
||||
/*
|
||||
* Default is "false" (old behavior) for compatibility reasons in
|
||||
* SSLv3/TLSv1. Later protocols (TLSv1.1+) do not use this property.
|
||||
*/
|
||||
private final static boolean rsaPreMasterSecretFix =
|
||||
Debug.getBooleanProperty(PROP_NAME, false);
|
||||
|
||||
/*
|
||||
* The following field values were encrypted with the server's public
|
||||
* key (or temp key from server key exchange msg) and are presented
|
||||
@ -88,22 +71,12 @@ final class RSAClientKeyExchange extends HandshakeMessage {
|
||||
}
|
||||
this.protocolVersion = protocolVersion;
|
||||
|
||||
int major, minor;
|
||||
|
||||
if (rsaPreMasterSecretFix || maxVersion.v >= ProtocolVersion.TLS11.v) {
|
||||
major = maxVersion.major;
|
||||
minor = maxVersion.minor;
|
||||
} else {
|
||||
major = protocolVersion.major;
|
||||
minor = protocolVersion.minor;
|
||||
}
|
||||
|
||||
try {
|
||||
String s = ((protocolVersion.v >= ProtocolVersion.TLS12.v) ?
|
||||
"SunTls12RsaPremasterSecret" : "SunTlsRsaPremasterSecret");
|
||||
KeyGenerator kg = JsseJce.getKeyGenerator(s);
|
||||
kg.init(new TlsRsaPremasterSecretParameterSpec(major, minor),
|
||||
generator);
|
||||
kg.init(new TlsRsaPremasterSecretParameterSpec(
|
||||
maxVersion.v, protocolVersion.v), generator);
|
||||
preMaster = kg.generateKey();
|
||||
|
||||
Cipher cipher = JsseJce.getCipher(JsseJce.CIPHER_RSA_PKCS1);
|
||||
@ -138,18 +111,17 @@ final class RSAClientKeyExchange extends HandshakeMessage {
|
||||
}
|
||||
}
|
||||
|
||||
Exception failover = null;
|
||||
byte[] encoded = null;
|
||||
try {
|
||||
Cipher cipher = JsseJce.getCipher(JsseJce.CIPHER_RSA_PKCS1);
|
||||
// Cannot generate key here, please don't use Cipher.UNWRAP_MODE!
|
||||
cipher.init(Cipher.DECRYPT_MODE, privateKey);
|
||||
encoded = cipher.doFinal(encrypted);
|
||||
} catch (BadPaddingException bpe) {
|
||||
failover = bpe;
|
||||
encoded = null;
|
||||
} catch (IllegalBlockSizeException ibse) {
|
||||
// the message it too big to process with RSA
|
||||
cipher.init(Cipher.UNWRAP_MODE, privateKey,
|
||||
new TlsRsaPremasterSecretParameterSpec(
|
||||
maxVersion.v, currentVersion.v),
|
||||
generator);
|
||||
preMaster = (SecretKey)cipher.unwrap(encrypted,
|
||||
"TlsRsaPremasterSecret", Cipher.SECRET_KEY);
|
||||
} catch (InvalidKeyException ibk) {
|
||||
// the message is too big to process with RSA
|
||||
throw new SSLProtocolException(
|
||||
"Unable to process PreMasterSecret, may be too big");
|
||||
} catch (Exception e) {
|
||||
@ -160,124 +132,6 @@ final class RSAClientKeyExchange extends HandshakeMessage {
|
||||
}
|
||||
throw new RuntimeException("Could not generate dummy secret", e);
|
||||
}
|
||||
|
||||
// polish the premaster secret
|
||||
preMaster = polishPreMasterSecretKey(
|
||||
currentVersion, maxVersion, generator, encoded, failover);
|
||||
}
|
||||
|
||||
/**
|
||||
* To avoid vulnerabilities described by section 7.4.7.1, RFC 5246,
|
||||
* treating incorrectly formatted message blocks and/or mismatched
|
||||
* version numbers in a manner indistinguishable from correctly
|
||||
* formatted RSA blocks.
|
||||
*
|
||||
* RFC 5246 describes the approach as :
|
||||
*
|
||||
* 1. Generate a string R of 48 random bytes
|
||||
*
|
||||
* 2. Decrypt the message to recover the plaintext M
|
||||
*
|
||||
* 3. If the PKCS#1 padding is not correct, or the length of message
|
||||
* M is not exactly 48 bytes:
|
||||
* pre_master_secret = R
|
||||
* else If ClientHello.client_version <= TLS 1.0, and version
|
||||
* number check is explicitly disabled:
|
||||
* premaster secret = M
|
||||
* else If M[0..1] != ClientHello.client_version:
|
||||
* premaster secret = R
|
||||
* else:
|
||||
* premaster secret = M
|
||||
*
|
||||
* Note that #2 has completed before the call of this method.
|
||||
*/
|
||||
private SecretKey polishPreMasterSecretKey(ProtocolVersion currentVersion,
|
||||
ProtocolVersion clientHelloVersion, SecureRandom generator,
|
||||
byte[] encoded, Exception failoverException) {
|
||||
|
||||
this.protocolVersion = clientHelloVersion;
|
||||
if (generator == null) {
|
||||
generator = new SecureRandom();
|
||||
}
|
||||
byte[] random = new byte[48];
|
||||
generator.nextBytes(random);
|
||||
|
||||
if (failoverException == null && encoded != null) {
|
||||
// check the length
|
||||
if (encoded.length != 48) {
|
||||
if (debug != null && Debug.isOn("handshake")) {
|
||||
System.out.println(
|
||||
"incorrect length of premaster secret: " +
|
||||
encoded.length);
|
||||
}
|
||||
|
||||
return generatePreMasterSecret(
|
||||
clientHelloVersion, random, generator);
|
||||
}
|
||||
|
||||
if (clientHelloVersion.major != encoded[0] ||
|
||||
clientHelloVersion.minor != encoded[1]) {
|
||||
|
||||
if (clientHelloVersion.v <= ProtocolVersion.TLS10.v &&
|
||||
currentVersion.major == encoded[0] &&
|
||||
currentVersion.minor == encoded[1]) {
|
||||
/*
|
||||
* For compatibility, we maintain the behavior that the
|
||||
* version in pre_master_secret can be the negotiated
|
||||
* version for TLS v1.0 and SSL v3.0.
|
||||
*/
|
||||
this.protocolVersion = currentVersion;
|
||||
} else {
|
||||
if (debug != null && Debug.isOn("handshake")) {
|
||||
System.out.println("Mismatching Protocol Versions, " +
|
||||
"ClientHello.client_version is " +
|
||||
clientHelloVersion +
|
||||
", while PreMasterSecret.client_version is " +
|
||||
ProtocolVersion.valueOf(encoded[0], encoded[1]));
|
||||
}
|
||||
|
||||
encoded = random;
|
||||
}
|
||||
}
|
||||
|
||||
return generatePreMasterSecret(
|
||||
clientHelloVersion, encoded, generator);
|
||||
}
|
||||
|
||||
if (debug != null && Debug.isOn("handshake") &&
|
||||
failoverException != null) {
|
||||
System.out.println("Error decrypting premaster secret:");
|
||||
failoverException.printStackTrace(System.out);
|
||||
}
|
||||
|
||||
return generatePreMasterSecret(clientHelloVersion, random, generator);
|
||||
}
|
||||
|
||||
// generate a premaster secret with the specified version number
|
||||
private static SecretKey generatePreMasterSecret(
|
||||
ProtocolVersion version, byte[] encodedSecret,
|
||||
SecureRandom generator) {
|
||||
|
||||
if (debug != null && Debug.isOn("handshake")) {
|
||||
System.out.println("Generating a random fake premaster secret");
|
||||
}
|
||||
|
||||
try {
|
||||
String s = ((version.v >= ProtocolVersion.TLS12.v) ?
|
||||
"SunTls12RsaPremasterSecret" : "SunTlsRsaPremasterSecret");
|
||||
KeyGenerator kg = JsseJce.getKeyGenerator(s);
|
||||
kg.init(new TlsRsaPremasterSecretParameterSpec(
|
||||
version.major, version.minor, encodedSecret), generator);
|
||||
return kg.generateKey();
|
||||
} catch (InvalidAlgorithmParameterException |
|
||||
NoSuchAlgorithmException iae) {
|
||||
// unlikely to happen, otherwise, must be a provider exception
|
||||
if (debug != null && Debug.isOn("handshake")) {
|
||||
System.out.println("RSA premaster secret generation error:");
|
||||
iae.printStackTrace(System.out);
|
||||
}
|
||||
throw new RuntimeException("Could not generate dummy secret", iae);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2012, 2014, 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
|
||||
@ -32,6 +32,7 @@ import java.security.InvalidKeyException;
|
||||
import java.security.interfaces.ECKey;
|
||||
import java.security.interfaces.RSAKey;
|
||||
import java.security.interfaces.DSAKey;
|
||||
import java.security.SecureRandom;
|
||||
import java.security.spec.KeySpec;
|
||||
import javax.crypto.SecretKey;
|
||||
import javax.crypto.interfaces.DHKey;
|
||||
@ -156,6 +157,79 @@ public final class KeyUtil {
|
||||
providerName.startsWith("SunPKCS11"));
|
||||
}
|
||||
|
||||
/**
|
||||
* Check the format of TLS PreMasterSecret.
|
||||
* <P>
|
||||
* To avoid vulnerabilities described by section 7.4.7.1, RFC 5246,
|
||||
* treating incorrectly formatted message blocks and/or mismatched
|
||||
* version numbers in a manner indistinguishable from correctly
|
||||
* formatted RSA blocks.
|
||||
*
|
||||
* RFC 5246 describes the approach as :
|
||||
*
|
||||
* 1. Generate a string R of 48 random bytes
|
||||
*
|
||||
* 2. Decrypt the message to recover the plaintext M
|
||||
*
|
||||
* 3. If the PKCS#1 padding is not correct, or the length of message
|
||||
* M is not exactly 48 bytes:
|
||||
* pre_master_secret = R
|
||||
* else If ClientHello.client_version <= TLS 1.0, and version
|
||||
* number check is explicitly disabled:
|
||||
* premaster secret = M
|
||||
* else If M[0..1] != ClientHello.client_version:
|
||||
* premaster secret = R
|
||||
* else:
|
||||
* premaster secret = M
|
||||
*
|
||||
* Note that #2 should have completed before the call to this method.
|
||||
*
|
||||
* @param clientVersion the version of the TLS protocol by which the
|
||||
* client wishes to communicate during this session
|
||||
* @param serverVersion the negotiated version of the TLS protocol which
|
||||
* contains the lower of that suggested by the client in the client
|
||||
* hello and the highest supported by the server.
|
||||
* @param encoded the encoded key in its "RAW" encoding format
|
||||
* @param isFailover whether or not the previous decryption of the
|
||||
* encrypted PreMasterSecret message run into problem
|
||||
* @return the polished PreMasterSecret key in its "RAW" encoding format
|
||||
*/
|
||||
public static byte[] checkTlsPreMasterSecretKey(
|
||||
int clientVersion, int serverVersion, SecureRandom random,
|
||||
byte[] encoded, boolean isFailOver) {
|
||||
|
||||
if (random == null) {
|
||||
random = new SecureRandom();
|
||||
}
|
||||
byte[] replacer = new byte[48];
|
||||
random.nextBytes(replacer);
|
||||
|
||||
if (!isFailOver && (encoded != null)) {
|
||||
// check the length
|
||||
if (encoded.length != 48) {
|
||||
// private, don't need to clone the byte array.
|
||||
return replacer;
|
||||
}
|
||||
|
||||
int encodedVersion =
|
||||
((encoded[0] & 0xFF) << 8) | (encoded[1] & 0xFF);
|
||||
if (clientVersion != encodedVersion) {
|
||||
if (clientVersion > 0x0301 || // 0x0301: TLSv1
|
||||
serverVersion != encodedVersion) {
|
||||
encoded = replacer;
|
||||
} // Otherwise, For compatibility, we maintain the behavior
|
||||
// that the version in pre_master_secret can be the
|
||||
// negotiated version for TLS v1.0 and SSL v3.0.
|
||||
}
|
||||
|
||||
// private, don't need to clone the byte array.
|
||||
return encoded;
|
||||
}
|
||||
|
||||
// private, don't need to clone the byte array.
|
||||
return replacer;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether the Diffie-Hellman public key is valid or not.
|
||||
*
|
||||
|
@ -35,6 +35,8 @@ import javax.crypto.*;
|
||||
import javax.crypto.spec.*;
|
||||
|
||||
import sun.security.rsa.RSAKeyFactory;
|
||||
import sun.security.internal.spec.TlsRsaPremasterSecretParameterSpec;
|
||||
import sun.security.util.KeyUtil;
|
||||
|
||||
/**
|
||||
* RSA cipher implementation using the Microsoft Crypto API.
|
||||
@ -92,9 +94,16 @@ public final class RSACipher extends CipherSpi {
|
||||
|
||||
// the public key, if we were initialized using a public key
|
||||
private sun.security.mscapi.Key publicKey;
|
||||
|
||||
// the private key, if we were initialized using a private key
|
||||
private sun.security.mscapi.Key privateKey;
|
||||
|
||||
// cipher parameter for TLS RSA premaster secret
|
||||
private AlgorithmParameterSpec spec = null;
|
||||
|
||||
// the source of randomness
|
||||
private SecureRandom random;
|
||||
|
||||
public RSACipher() {
|
||||
paddingType = PAD_PKCS1;
|
||||
}
|
||||
@ -155,8 +164,12 @@ public final class RSACipher extends CipherSpi {
|
||||
throws InvalidKeyException, InvalidAlgorithmParameterException {
|
||||
|
||||
if (params != null) {
|
||||
throw new InvalidAlgorithmParameterException
|
||||
("Parameters not supported");
|
||||
if (!(params instanceof TlsRsaPremasterSecretParameterSpec)) {
|
||||
throw new InvalidAlgorithmParameterException(
|
||||
"Parameters not supported");
|
||||
}
|
||||
spec = params;
|
||||
this.random = random; // for TLS RSA premaster secret
|
||||
}
|
||||
init(opmode, key);
|
||||
}
|
||||
@ -356,39 +369,47 @@ public final class RSACipher extends CipherSpi {
|
||||
}
|
||||
|
||||
// see JCE spec
|
||||
protected java.security.Key engineUnwrap(byte[] wrappedKey, String algorithm,
|
||||
protected java.security.Key engineUnwrap(byte[] wrappedKey,
|
||||
String algorithm,
|
||||
int type) throws InvalidKeyException, NoSuchAlgorithmException {
|
||||
|
||||
if (wrappedKey.length > buffer.length) {
|
||||
throw new InvalidKeyException("Key is too long for unwrapping");
|
||||
}
|
||||
|
||||
boolean isTlsRsaPremasterSecret =
|
||||
algorithm.equals("TlsRsaPremasterSecret");
|
||||
Exception failover = null;
|
||||
byte[] encoded = null;
|
||||
|
||||
update(wrappedKey, 0, wrappedKey.length);
|
||||
|
||||
try {
|
||||
byte[] encoding = doFinal();
|
||||
|
||||
switch (type) {
|
||||
case Cipher.PUBLIC_KEY:
|
||||
return constructPublicKey(encoding, algorithm);
|
||||
|
||||
case Cipher.PRIVATE_KEY:
|
||||
return constructPrivateKey(encoding, algorithm);
|
||||
|
||||
case Cipher.SECRET_KEY:
|
||||
return constructSecretKey(encoding, algorithm);
|
||||
|
||||
default:
|
||||
throw new InvalidKeyException("Unknown key type " + type);
|
||||
}
|
||||
|
||||
encoded = doFinal();
|
||||
} catch (BadPaddingException e) {
|
||||
// should not occur
|
||||
throw new InvalidKeyException("Unwrapping failed", e);
|
||||
|
||||
if (isTlsRsaPremasterSecret) {
|
||||
failover = e;
|
||||
} else {
|
||||
throw new InvalidKeyException("Unwrapping failed", e);
|
||||
}
|
||||
} catch (IllegalBlockSizeException e) {
|
||||
// should not occur, handled with length check above
|
||||
throw new InvalidKeyException("Unwrapping failed", e);
|
||||
}
|
||||
|
||||
if (isTlsRsaPremasterSecret) {
|
||||
if (!(spec instanceof TlsRsaPremasterSecretParameterSpec)) {
|
||||
throw new IllegalStateException(
|
||||
"No TlsRsaPremasterSecretParameterSpec specified");
|
||||
}
|
||||
|
||||
// polish the TLS premaster secret
|
||||
encoded = KeyUtil.checkTlsPreMasterSecretKey(
|
||||
((TlsRsaPremasterSecretParameterSpec)spec).getClientVersion(),
|
||||
((TlsRsaPremasterSecretParameterSpec)spec).getServerVersion(),
|
||||
random, encoded, (failover != null));
|
||||
}
|
||||
|
||||
return constructKey(encoded, algorithm, type);
|
||||
}
|
||||
|
||||
// see JCE spec
|
||||
@ -452,6 +473,22 @@ public final class RSACipher extends CipherSpi {
|
||||
return new SecretKeySpec(encodedKey, encodedKeyAlgorithm);
|
||||
}
|
||||
|
||||
private static Key constructKey(byte[] encodedKey,
|
||||
String encodedKeyAlgorithm,
|
||||
int keyType) throws InvalidKeyException, NoSuchAlgorithmException {
|
||||
|
||||
switch (keyType) {
|
||||
case Cipher.PUBLIC_KEY:
|
||||
return constructPublicKey(encodedKey, encodedKeyAlgorithm);
|
||||
case Cipher.PRIVATE_KEY:
|
||||
return constructPrivateKey(encodedKey, encodedKeyAlgorithm);
|
||||
case Cipher.SECRET_KEY:
|
||||
return constructSecretKey(encodedKey, encodedKeyAlgorithm);
|
||||
default:
|
||||
throw new InvalidKeyException("Unknown key type " + keyType);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Encrypt/decrypt a data buffer using Microsoft Crypto API with HCRYPTKEY.
|
||||
* It expects and returns ciphertext data in big-endian form.
|
||||
|
@ -33,6 +33,7 @@ import java.security.Provider;
|
||||
|
||||
import javax.crypto.KeyGenerator;
|
||||
import javax.crypto.SecretKey;
|
||||
import java.util.Formatter;
|
||||
|
||||
import sun.security.internal.spec.TlsRsaPremasterSecretParameterSpec;
|
||||
|
||||
@ -52,27 +53,51 @@ public class TestPremaster {
|
||||
System.out.println("OK: " + e);
|
||||
}
|
||||
|
||||
test(kg, 3, 0);
|
||||
test(kg, 3, 1);
|
||||
test(kg, 3, 2);
|
||||
test(kg, 4, 0);
|
||||
int[] protocolVersions = {0x0300, 0x0301, 0x0302, 0x0400};
|
||||
for (int clientVersion : protocolVersions) {
|
||||
for (int serverVersion : protocolVersions) {
|
||||
test(kg, clientVersion, serverVersion);
|
||||
if (serverVersion >= clientVersion) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
System.out.println("Done.");
|
||||
}
|
||||
|
||||
private static void test(KeyGenerator kg, int major, int minor)
|
||||
throws Exception {
|
||||
private static void test(KeyGenerator kg,
|
||||
int clientVersion, int serverVersion) throws Exception {
|
||||
|
||||
System.out.printf(
|
||||
"Testing RSA pre-master secret key generation between " +
|
||||
"client (0x%04X) and server(0x%04X)%n",
|
||||
clientVersion, serverVersion);
|
||||
kg.init(new TlsRsaPremasterSecretParameterSpec(
|
||||
clientVersion, serverVersion));
|
||||
|
||||
kg.init(new TlsRsaPremasterSecretParameterSpec(major, minor));
|
||||
SecretKey key = kg.generateKey();
|
||||
byte[] encoded = key.getEncoded();
|
||||
if (encoded.length != 48) {
|
||||
throw new Exception("length: " + encoded.length);
|
||||
}
|
||||
if ((encoded[0] != major) || (encoded[1] != minor)) {
|
||||
throw new Exception("version mismatch: " + encoded[0] +
|
||||
"." + encoded[1]);
|
||||
}
|
||||
System.out.println("OK: " + major + "." + minor);
|
||||
if (encoded != null) { // raw key material may be not extractable
|
||||
if (encoded.length != 48) {
|
||||
throw new Exception("length: " + encoded.length);
|
||||
}
|
||||
int v = versionOf(encoded[0], encoded[1]);
|
||||
if (clientVersion != v) {
|
||||
if (serverVersion != v || clientVersion >= 0x0302) {
|
||||
throw new Exception(String.format(
|
||||
"version mismatch: (0x%04X) rather than (0x%04X) " +
|
||||
"is used in pre-master secret", v, clientVersion));
|
||||
}
|
||||
System.out.printf("Use compatible version (0x%04X)%n", v);
|
||||
}
|
||||
System.out.println("Passed, version matches!");
|
||||
} else {
|
||||
System.out.println("Raw key material is not extractable");
|
||||
}
|
||||
}
|
||||
|
||||
private static int versionOf(int major, int minor) {
|
||||
return ((major & 0xFF) << 8) | (minor & 0xFF);
|
||||
}
|
||||
}
|
||||
|
@ -472,8 +472,21 @@ public class CipherTest {
|
||||
return false;
|
||||
}
|
||||
|
||||
// No ECDH-capable certificate in key store. May restructure
|
||||
// this in the future.
|
||||
if (cipherSuite.contains("ECDHE_ECDSA") ||
|
||||
cipherSuite.contains("ECDH_ECDSA") ||
|
||||
cipherSuite.contains("ECDH_RSA")) {
|
||||
System.out.println("Skipping unsupported test for " +
|
||||
cipherSuite + " of " + protocol);
|
||||
return false;
|
||||
}
|
||||
|
||||
// skip SSLv2Hello protocol
|
||||
if (protocol.equals("SSLv2Hello")) {
|
||||
//
|
||||
// skip TLSv1.2 protocol, we have not implement "SunTls12Prf" and
|
||||
// SunTls12RsaPremasterSecret in SunPKCS11 provider
|
||||
if (protocol.equals("SSLv2Hello") || protocol.equals("TLSv1.2")) {
|
||||
System.out.println("Skipping unsupported test for " +
|
||||
cipherSuite + " of " + protocol);
|
||||
return false;
|
||||
|
@ -23,7 +23,7 @@
|
||||
|
||||
/*
|
||||
* @test
|
||||
* @bug 6313675 6323647
|
||||
* @bug 6313675 6323647 8028192
|
||||
* @summary Verify that all ciphersuites work in FIPS mode
|
||||
* @library ..
|
||||
* @author Andreas Sterbenz
|
||||
@ -47,9 +47,13 @@ public class ClientJSSEServerJSSE extends SecmodTest {
|
||||
return;
|
||||
}
|
||||
|
||||
if ("sparc".equals(System.getProperty("os.arch")) == false) {
|
||||
// we have not updated other platforms with the proper NSS libraries yet
|
||||
System.out.println("Test currently works only on solaris-sparc, skipping");
|
||||
String arch = System.getProperty("os.arch");
|
||||
if (!("sparc".equals(arch) || "sparcv9".equals(arch))) {
|
||||
// we have not updated other platforms with the proper NSS
|
||||
// libraries yet
|
||||
System.out.println(
|
||||
"Test currently works only on solaris-sparc " +
|
||||
"and solaris-sparcv9. Skipping on " + arch);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -34,6 +34,7 @@ import java.security.Provider;
|
||||
|
||||
import javax.crypto.KeyGenerator;
|
||||
import javax.crypto.SecretKey;
|
||||
import java.util.Formatter;
|
||||
|
||||
import sun.security.internal.spec.TlsRsaPremasterSecretParameterSpec;
|
||||
|
||||
@ -59,27 +60,51 @@ public class TestPremaster extends PKCS11Test {
|
||||
System.out.println("OK: " + e);
|
||||
}
|
||||
|
||||
test(kg, 3, 0);
|
||||
test(kg, 3, 1);
|
||||
test(kg, 3, 2);
|
||||
test(kg, 4, 0);
|
||||
int[] protocolVersions = {0x0300, 0x0301, 0x0302, 0x0400};
|
||||
for (int clientVersion : protocolVersions) {
|
||||
for (int serverVersion : protocolVersions) {
|
||||
test(kg, clientVersion, serverVersion);
|
||||
if (serverVersion >= clientVersion) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
System.out.println("Done.");
|
||||
}
|
||||
|
||||
private static void test(KeyGenerator kg, int major, int minor)
|
||||
throws Exception {
|
||||
private static void test(KeyGenerator kg,
|
||||
int clientVersion, int serverVersion) throws Exception {
|
||||
|
||||
kg.init(new TlsRsaPremasterSecretParameterSpec(major, minor));
|
||||
System.out.printf(
|
||||
"Testing RSA pre-master secret key generation between " +
|
||||
"client (0x%04X) and server(0x%04X)%n",
|
||||
clientVersion, serverVersion);
|
||||
kg.init(new TlsRsaPremasterSecretParameterSpec(
|
||||
clientVersion, serverVersion));
|
||||
SecretKey key = kg.generateKey();
|
||||
byte[] encoded = key.getEncoded();
|
||||
if (encoded.length != 48) {
|
||||
throw new Exception("length: " + encoded.length);
|
||||
}
|
||||
if ((encoded[0] != major) || (encoded[1] != minor)) {
|
||||
throw new Exception("version mismatch: " + encoded[0] +
|
||||
"." + encoded[1]);
|
||||
}
|
||||
System.out.println("OK: " + major + "." + minor);
|
||||
if (encoded != null) { // raw key material may be not extractable
|
||||
if (encoded.length != 48) {
|
||||
throw new Exception("length: " + encoded.length);
|
||||
}
|
||||
int v = versionOf(encoded[0], encoded[1]);
|
||||
if (clientVersion != v) {
|
||||
if (serverVersion != v || clientVersion >= 0x0302) {
|
||||
throw new Exception(String.format(
|
||||
"version mismatch: (0x%04X) rather than (0x%04X) " +
|
||||
"is used in pre-master secret", v, clientVersion));
|
||||
}
|
||||
System.out.printf("Use compatible version (0x%04X)%n", v);
|
||||
}
|
||||
System.out.println("Passed, version matches!");
|
||||
} else {
|
||||
System.out.println("Raw key material is not extractable");
|
||||
}
|
||||
}
|
||||
|
||||
private static int versionOf(int major, int minor) {
|
||||
return ((major & 0xFF) << 8) | (minor & 0xFF);
|
||||
}
|
||||
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user