4873188: Support TLS 1.1

Reviewed-by: wetmore, weijun
This commit is contained in:
Xue-Lei Andrew Fan 2010-10-30 18:39:17 +08:00
parent 4dce0bd6ec
commit aab01a90d7
30 changed files with 3393 additions and 377 deletions

View file

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 1997, 2007, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 1997, 2010, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
@ -30,6 +30,7 @@ import java.net.*;
import javax.net.SocketFactory; import javax.net.SocketFactory;
import java.io.IOException; import java.io.IOException;
import java.security.*; import java.security.*;
import java.util.Locale;
import sun.security.action.GetPropertyAction; import sun.security.action.GetPropertyAction;
@ -50,7 +51,8 @@ public abstract class SSLSocketFactory extends SocketFactory
static { static {
String s = java.security.AccessController.doPrivileged( String s = java.security.AccessController.doPrivileged(
new GetPropertyAction("javax.net.debug", "")).toLowerCase(); new GetPropertyAction("javax.net.debug", "")).toLowerCase(
Locale.ENGLISH);
DEBUG = s.contains("all") || s.contains("ssl"); DEBUG = s.contains("all") || s.contains("ssl");
} }

View file

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2005, 2007, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
@ -90,8 +90,10 @@ public class TlsKeyMaterialParameterSpec implements AlgorithmParameterSpec {
throw new NullPointerException(); throw new NullPointerException();
} }
this.masterSecret = masterSecret; this.masterSecret = masterSecret;
this.majorVersion = TlsMasterSecretParameterSpec.checkVersion(majorVersion); this.majorVersion =
this.minorVersion = TlsMasterSecretParameterSpec.checkVersion(minorVersion); TlsMasterSecretParameterSpec.checkVersion(majorVersion);
this.minorVersion =
TlsMasterSecretParameterSpec.checkVersion(minorVersion);
this.clientRandom = clientRandom.clone(); this.clientRandom = clientRandom.clone();
this.serverRandom = serverRandom.clone(); this.serverRandom = serverRandom.clone();
this.cipherAlgorithm = cipherAlgorithm; this.cipherAlgorithm = cipherAlgorithm;
@ -172,20 +174,36 @@ public class TlsKeyMaterialParameterSpec implements AlgorithmParameterSpec {
} }
/** /**
* Returns the length in bytes of the expanded encryption key to be generated. * Returns the length in bytes of the expanded encryption key to be
* generated. Returns zero if the expanded encryption key is not
* supposed to be generated.
* *
* @return the length in bytes of the expanded encryption key to be generated. * @return the length in bytes of the expanded encryption key to be
* generated.
*/ */
public int getExpandedCipherKeyLength() { public int getExpandedCipherKeyLength() {
// TLS v1.1 disables the exportable weak cipher suites.
if (majorVersion >= 0x03 && minorVersion >= 0x02) {
return 0;
}
return expandedCipherKeyLength; return expandedCipherKeyLength;
} }
/** /**
* Returns the length in bytes of the initialization vector to be generated. * Returns the length in bytes of the initialization vector to be
* generated. Returns zero if the initialization vector is not
* supposed to be generated.
* *
* @return the length in bytes of the initialization vector to be generated. * @return the length in bytes of the initialization vector to be
* generated.
*/ */
public int getIvLength() { public int getIvLength() {
// TLS v1.1 or later uses an explicit IV to protect against
// the CBC attacks.
if (majorVersion >= 0x03 && minorVersion >= 0x02) {
return 0;
}
return ivLength; return ivLength;
} }

View file

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2005, 2007, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
@ -67,7 +67,8 @@ public class TlsMasterSecretParameterSpec implements AlgorithmParameterSpec {
* negative or larger than 255 * negative or larger than 255
*/ */
public TlsMasterSecretParameterSpec(SecretKey premasterSecret, public TlsMasterSecretParameterSpec(SecretKey premasterSecret,
int majorVersion, int minorVersion, byte[] clientRandom, byte[] serverRandom) { int majorVersion, int minorVersion,
byte[] clientRandom, byte[] serverRandom) {
if (premasterSecret == null) { if (premasterSecret == null) {
throw new NullPointerException("premasterSecret must not be null"); throw new NullPointerException("premasterSecret must not be null");
} }
@ -80,7 +81,8 @@ public class TlsMasterSecretParameterSpec implements AlgorithmParameterSpec {
static int checkVersion(int version) { static int checkVersion(int version) {
if ((version < 0) || (version > 255)) { if ((version < 0) || (version > 255)) {
throw new IllegalArgumentException("Version must be between 0 and 255"); throw new IllegalArgumentException(
"Version must be between 0 and 255");
} }
return version; return version;
} }

View file

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 1996, 2008, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 1996, 2010, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
@ -28,6 +28,7 @@ package sun.security.ssl;
import java.io.ByteArrayInputStream; import java.io.ByteArrayInputStream;
import java.io.IOException; import java.io.IOException;
import java.util.Hashtable;
import java.security.*; import java.security.*;
import javax.crypto.*; import javax.crypto.*;
@ -50,6 +51,37 @@ import sun.misc.HexDumpEncoder;
* Individual instances are obtained by calling the static method * Individual instances are obtained by calling the static method
* newCipherBox(), which should only be invoked by BulkCipher.newCipher(). * newCipherBox(), which should only be invoked by BulkCipher.newCipher().
* *
* In RFC 2246, with bock ciphers in CBC mode, the Initialization
* Vector (IV) for the first record is generated with the other keys
* and secrets when the security parameters are set. The IV for
* subsequent records is the last ciphertext block from the previous
* record.
*
* In RFC 4346, the implicit Initialization Vector (IV) is replaced
* with an explicit IV to protect against CBC attacks. RFC 4346
* recommends two algorithms used to generated the per-record IV.
* The implementation uses the algorithm (2)(b), as described at
* section 6.2.3.2 of RFC 4346.
*
* The usage of IV in CBC block cipher can be illustrated in
* the following diagrams.
*
* (random)
* R P1 IV C1
* | | | |
* SIV---+ |-----+ |-... |----- |------
* | | | | | | | |
* +----+ | +----+ | +----+ | +----+ |
* | Ek | | + Ek + | | Dk | | | Dk | |
* +----+ | +----+ | +----+ | +----+ |
* | | | | | | | |
* |----| |----| SIV--+ |----| |-...
* | | | |
* IV C1 R P1
* (discard)
*
* CBC Encryption CBC Decryption
*
* NOTE that any ciphering involved in key exchange (e.g. with RSA) is * NOTE that any ciphering involved in key exchange (e.g. with RSA) is
* handled separately. * handled separately.
* *
@ -75,6 +107,21 @@ final class CipherBox {
*/ */
private int blockSize; private int blockSize;
/**
* secure random
*/
private SecureRandom random;
/**
* Fixed masks of various block size, as the initial decryption IVs
* for TLS 1.1 or later.
*
* For performance, we do not use random IVs. As the initial decryption
* IVs will be discarded by TLS decryption processes, so the fixed masks
* do not hurt cryptographic strength.
*/
private static Hashtable<Integer, IvParameterSpec> masks;
/** /**
* NULL cipherbox. Identity operation, no encryption. * NULL cipherbox. Identity operation, no encryption.
*/ */
@ -90,14 +137,37 @@ final class CipherBox {
* implementation could be found. * implementation could be found.
*/ */
private CipherBox(ProtocolVersion protocolVersion, BulkCipher bulkCipher, private CipherBox(ProtocolVersion protocolVersion, BulkCipher bulkCipher,
SecretKey key, IvParameterSpec iv, boolean encrypt) SecretKey key, IvParameterSpec iv, SecureRandom random,
throws NoSuchAlgorithmException { boolean encrypt) throws NoSuchAlgorithmException {
try { try {
this.protocolVersion = protocolVersion; this.protocolVersion = protocolVersion;
this.cipher = JsseJce.getCipher(bulkCipher.transformation); this.cipher = JsseJce.getCipher(bulkCipher.transformation);
int mode = encrypt ? Cipher.ENCRYPT_MODE : Cipher.DECRYPT_MODE; int mode = encrypt ? Cipher.ENCRYPT_MODE : Cipher.DECRYPT_MODE;
cipher.init(mode, key, iv);
// do not call getBlockSize until after init() if (random == null) {
random = JsseJce.getSecureRandom();
}
this.random = random;
/*
* RFC 4346 recommends two algorithms used to generated the
* per-record IV. The implementation uses the algorithm (2)(b),
* as described at section 6.2.3.2 of RFC 4346.
*
* As we don't care about the initial IV value for TLS 1.1 or
* later, so if the "iv" parameter is null, we use the default
* value generated by Cipher.init() for encryption, and a fixed
* mask for decryption.
*/
if (iv == null && bulkCipher.ivSize != 0 &&
mode == Cipher.DECRYPT_MODE &&
protocolVersion.v >= ProtocolVersion.TLS11.v) {
iv = getFixedMask(bulkCipher.ivSize);
}
cipher.init(mode, key, iv, random);
// Do not call getBlockSize until after init()
// otherwise we would disrupt JCE delayed provider selection // otherwise we would disrupt JCE delayed provider selection
blockSize = cipher.getBlockSize(); blockSize = cipher.getBlockSize();
// some providers implement getBlockSize() incorrectly // some providers implement getBlockSize() incorrectly
@ -119,18 +189,36 @@ final class CipherBox {
* Factory method to obtain a new CipherBox object. * Factory method to obtain a new CipherBox object.
*/ */
static CipherBox newCipherBox(ProtocolVersion version, BulkCipher cipher, static CipherBox newCipherBox(ProtocolVersion version, BulkCipher cipher,
SecretKey key, IvParameterSpec iv, boolean encrypt) SecretKey key, IvParameterSpec iv, SecureRandom random,
throws NoSuchAlgorithmException { boolean encrypt) throws NoSuchAlgorithmException {
if (cipher.allowed == false) { if (cipher.allowed == false) {
throw new NoSuchAlgorithmException("Unsupported cipher " + cipher); throw new NoSuchAlgorithmException("Unsupported cipher " + cipher);
} }
if (cipher == B_NULL) { if (cipher == B_NULL) {
return NULL; return NULL;
} else { } else {
return new CipherBox(version, cipher, key, iv, encrypt); return new CipherBox(version, cipher, key, iv, random, encrypt);
} }
} }
/*
* Get a fixed mask, as the initial decryption IVs for TLS 1.1 or later.
*/
private static IvParameterSpec getFixedMask(int ivSize) {
if (masks == null) {
masks = new Hashtable<Integer, IvParameterSpec>(5);
}
IvParameterSpec iv = masks.get(ivSize);
if (iv == null) {
iv = new IvParameterSpec(new byte[ivSize]);
masks.put(ivSize, iv);
}
return iv;
}
/* /*
* Encrypts a block of data, returning the size of the * Encrypts a block of data, returning the size of the
* resulting block. * resulting block.
@ -139,8 +227,26 @@ final class CipherBox {
if (cipher == null) { if (cipher == null) {
return len; return len;
} }
try { try {
if (blockSize != 0) { if (blockSize != 0) {
// TLSv1.1 needs a IV block
if (protocolVersion.v >= ProtocolVersion.TLS11.v) {
// generate a random number
byte[] prefix = new byte[blockSize];
random.nextBytes(prefix);
// move forward the plaintext
System.arraycopy(buf, offset,
buf, offset + prefix.length, len);
// prefix the plaintext
System.arraycopy(prefix, 0,
buf, offset, prefix.length);
len += prefix.length;
}
len = addPadding(buf, offset, len, blockSize); len = addPadding(buf, offset, len, blockSize);
} }
if (debug != null && Debug.isOn("plaintext")) { if (debug != null && Debug.isOn("plaintext")) {
@ -189,6 +295,34 @@ final class CipherBox {
int pos = bb.position(); int pos = bb.position();
if (blockSize != 0) { if (blockSize != 0) {
// TLSv1.1 needs a IV block
if (protocolVersion.v >= ProtocolVersion.TLS11.v) {
// generate a random number
byte[] prefix = new byte[blockSize];
random.nextBytes(prefix);
// move forward the plaintext
byte[] buf = null;
int limit = bb.limit();
if (bb.hasArray()) {
buf = bb.array();
System.arraycopy(buf, pos,
buf, pos + prefix.length, limit - pos);
bb.limit(limit + prefix.length);
} else {
buf = new byte[limit - pos];
bb.get(buf, 0, limit - pos);
bb.position(pos + prefix.length);
bb.limit(limit + prefix.length);
bb.put(buf);
}
bb.position(pos);
// prefix the plaintext
bb.put(prefix);
bb.position(pos);
}
// addPadding adjusts pos/limit // addPadding adjusts pos/limit
len = addPadding(bb, blockSize); len = addPadding(bb, blockSize);
bb.position(pos); bb.position(pos);
@ -236,11 +370,25 @@ final class CipherBox {
/* /*
* Decrypts a block of data, returning the size of the * Decrypts a block of data, returning the size of the
* resulting block if padding was required. * resulting block if padding was required.
*
* For SSLv3 and TLSv1.0, with block ciphers in CBC mode the
* Initialization Vector (IV) for the first record is generated by
* the handshake protocol, the IV for subsequent records is the
* last ciphertext block from the previous record.
*
* From TLSv1.1, the implicit IV is replaced with an explicit IV to
* protect against CBC attacks.
*
* Differentiating between bad_record_mac and decryption_failed alerts
* may permit certain attacks against CBC mode. It is preferable to
* uniformly use the bad_record_mac alert to hide the specific type of
* the error.
*/ */
int decrypt(byte[] buf, int offset, int len) throws BadPaddingException { int decrypt(byte[] buf, int offset, int len) throws BadPaddingException {
if (cipher == null) { if (cipher == null) {
return len; return len;
} }
try { try {
int newLen = cipher.update(buf, offset, len, buf, offset); int newLen = cipher.update(buf, offset, len, buf, offset);
if (newLen != len) { if (newLen != len) {
@ -263,6 +411,18 @@ final class CipherBox {
if (blockSize != 0) { if (blockSize != 0) {
newLen = removePadding(buf, offset, newLen, newLen = removePadding(buf, offset, newLen,
blockSize, protocolVersion); blockSize, protocolVersion);
if (protocolVersion.v >= ProtocolVersion.TLS11.v) {
if (newLen < blockSize) {
throw new BadPaddingException("invalid explicit IV");
}
// discards the first cipher block, the IV component.
System.arraycopy(buf, offset + blockSize,
buf, offset, newLen - blockSize);
newLen -= blockSize;
}
} }
return newLen; return newLen;
} catch (ShortBufferException e) { } catch (ShortBufferException e) {
@ -277,6 +437,8 @@ final class CipherBox {
* point to the end of the decrypted/depadded data. The initial * point to the end of the decrypted/depadded data. The initial
* limit and new limit may be different, given we may * limit and new limit may be different, given we may
* have stripped off some padding bytes. * have stripped off some padding bytes.
*
* @see decrypt(byte[], int, int)
*/ */
int decrypt(ByteBuffer bb) throws BadPaddingException { int decrypt(ByteBuffer bb) throws BadPaddingException {
@ -292,7 +454,6 @@ final class CipherBox {
* Decrypt "in-place". * Decrypt "in-place".
*/ */
int pos = bb.position(); int pos = bb.position();
ByteBuffer dup = bb.duplicate(); ByteBuffer dup = bb.duplicate();
int newLen = cipher.update(dup, bb); int newLen = cipher.update(dup, bb);
if (newLen != len) { if (newLen != len) {
@ -320,6 +481,33 @@ final class CipherBox {
if (blockSize != 0) { if (blockSize != 0) {
bb.position(pos); bb.position(pos);
newLen = removePadding(bb, blockSize, protocolVersion); newLen = removePadding(bb, blockSize, protocolVersion);
if (protocolVersion.v >= ProtocolVersion.TLS11.v) {
if (newLen < blockSize) {
throw new BadPaddingException("invalid explicit IV");
}
// discards the first cipher block, the IV component.
byte[] buf = null;
int limit = bb.limit();
if (bb.hasArray()) {
buf = bb.array();
System.arraycopy(buf, pos + blockSize,
buf, pos, limit - pos - blockSize);
bb.limit(limit - blockSize);
} else {
buf = new byte[limit - pos - blockSize];
bb.position(pos + blockSize);
bb.get(buf);
bb.position(pos);
bb.put(buf);
bb.limit(limit - blockSize);
}
// reset the position to the end of the decrypted data
limit = bb.limit();
bb.position(limit);
}
} }
return newLen; return newLen;
} catch (ShortBufferException e) { } catch (ShortBufferException e) {

View file

@ -30,6 +30,7 @@ import java.util.*;
import java.security.NoSuchAlgorithmException; import java.security.NoSuchAlgorithmException;
import java.security.InvalidKeyException; import java.security.InvalidKeyException;
import java.security.SecureRandom;
import javax.crypto.SecretKey; import javax.crypto.SecretKey;
import javax.crypto.spec.IvParameterSpec; import javax.crypto.spec.IvParameterSpec;
@ -112,8 +113,12 @@ final class CipherSuite implements Comparable {
// true iff implemented and enabled at compile time // true iff implemented and enabled at compile time
final boolean allowed; final boolean allowed;
// obsoleted since protocol version
final int obsoleted;
private CipherSuite(String name, int id, int priority, private CipherSuite(String name, int id, int priority,
KeyExchange keyExchange, BulkCipher cipher, boolean allowed) { KeyExchange keyExchange, BulkCipher cipher,
boolean allowed, int obsoleted) {
this.name = name; this.name = name;
this.id = id; this.id = id;
this.priority = priority; this.priority = priority;
@ -136,6 +141,7 @@ final class CipherSuite implements Comparable {
allowed &= keyExchange.allowed; allowed &= keyExchange.allowed;
allowed &= cipher.allowed; allowed &= cipher.allowed;
this.allowed = allowed; this.allowed = allowed;
this.obsoleted = obsoleted;
} }
private CipherSuite(String name, int id) { private CipherSuite(String name, int id) {
@ -148,6 +154,7 @@ final class CipherSuite implements Comparable {
this.cipher = null; this.cipher = null;
this.macAlg = null; this.macAlg = null;
this.exportable = false; this.exportable = false;
this.obsoleted = ProtocolVersion.LIMIT_MAX_VALUE;
} }
/** /**
@ -197,10 +204,12 @@ final class CipherSuite implements Comparable {
if (s == null) { if (s == null) {
throw new IllegalArgumentException("Name must not be null"); throw new IllegalArgumentException("Name must not be null");
} }
CipherSuite c = nameMap.get(s); CipherSuite c = nameMap.get(s);
if ((c == null) || (c.allowed == false)) { if ((c == null) || (c.allowed == false)) {
throw new IllegalArgumentException("Unsupported ciphersuite " + s); throw new IllegalArgumentException("Unsupported ciphersuite " + s);
} }
return c; return c;
} }
@ -228,9 +237,11 @@ final class CipherSuite implements Comparable {
} }
private static void add(String name, int id, int priority, private static void add(String name, int id, int priority,
KeyExchange keyExchange, BulkCipher cipher, boolean allowed) { KeyExchange keyExchange, BulkCipher cipher,
boolean allowed, int obsoleted) {
CipherSuite c = new CipherSuite(name, id, priority, keyExchange, CipherSuite c = new CipherSuite(name, id, priority, keyExchange,
cipher, allowed); cipher, allowed, obsoleted);
if (idMap.put(id, c) != null) { if (idMap.put(id, c) != null) {
throw new RuntimeException("Duplicate ciphersuite definition: " throw new RuntimeException("Duplicate ciphersuite definition: "
+ id + ", " + name); + id + ", " + name);
@ -243,6 +254,12 @@ final class CipherSuite implements Comparable {
} }
} }
private static void add(String name, int id, int priority,
KeyExchange keyExchange, BulkCipher cipher, boolean allowed) {
add(name, id, priority, keyExchange,
cipher, allowed, ProtocolVersion.LIMIT_MAX_VALUE);
}
private static void add(String name, int id) { private static void add(String name, int id) {
CipherSuite c = new CipherSuite(name, id); CipherSuite c = new CipherSuite(name, id);
if (idMap.put(id, c) != null) { if (idMap.put(id, c) != null) {
@ -380,10 +397,11 @@ final class CipherSuite implements Comparable {
* *
* @exception NoSuchAlgorithmException if anything goes wrong * @exception NoSuchAlgorithmException if anything goes wrong
*/ */
CipherBox newCipher(ProtocolVersion version, CipherBox newCipher(ProtocolVersion version, SecretKey key,
SecretKey key, IvParameterSpec iv, IvParameterSpec iv, SecureRandom random,
boolean encrypt) throws NoSuchAlgorithmException { boolean encrypt) throws NoSuchAlgorithmException {
return CipherBox.newCipherBox(version, this, key, iv, encrypt); return CipherBox.newCipherBox(version, this,
key, iv, random, encrypt);
} }
/** /**
@ -402,6 +420,7 @@ final class CipherSuite implements Comparable {
if (this == B_AES_256) { if (this == B_AES_256) {
return isAvailable(this); return isAvailable(this);
} }
// always available // always available
return true; return true;
} }
@ -421,7 +440,8 @@ final class CipherSuite implements Comparable {
(new byte[cipher.expandedKeySize], cipher.algorithm); (new byte[cipher.expandedKeySize], cipher.algorithm);
IvParameterSpec iv = IvParameterSpec iv =
new IvParameterSpec(new byte[cipher.ivSize]); new IvParameterSpec(new byte[cipher.ivSize]);
cipher.newCipher(ProtocolVersion.DEFAULT, key, iv, true); cipher.newCipher(ProtocolVersion.DEFAULT,
key, iv, null, true);
b = Boolean.TRUE; b = Boolean.TRUE;
} catch (NoSuchAlgorithmException e) { } catch (NoSuchAlgorithmException e) {
b = Boolean.FALSE; b = Boolean.FALSE;
@ -509,6 +529,239 @@ final class CipherSuite implements Comparable {
// N: ciphersuites only allowed if we are not in FIPS mode // N: ciphersuites only allowed if we are not in FIPS mode
final boolean N = (SunJSSE.isFIPS() == false); final boolean N = (SunJSSE.isFIPS() == false);
/*
* TLS Cipher Suite Registry, as of August 2010.
*
* http://www.iana.org/assignments/tls-parameters/tls-parameters.xml
*
* Range Registration Procedures Notes
* 000-191 Standards Action Refers to value of first byte
* 192-254 Specification Required Refers to value of first byte
* 255 Reserved for Private Use Refers to value of first byte
*
* Value Description Reference
* 0x00,0x00 TLS_NULL_WITH_NULL_NULL [RFC5246]
* 0x00,0x01 TLS_RSA_WITH_NULL_MD5 [RFC5246]
* 0x00,0x02 TLS_RSA_WITH_NULL_SHA [RFC5246]
* 0x00,0x03 TLS_RSA_EXPORT_WITH_RC4_40_MD5 [RFC4346]
* 0x00,0x04 TLS_RSA_WITH_RC4_128_MD5 [RFC5246]
* 0x00,0x05 TLS_RSA_WITH_RC4_128_SHA [RFC5246]
* 0x00,0x06 TLS_RSA_EXPORT_WITH_RC2_CBC_40_MD5 [RFC4346]
* 0x00,0x07 TLS_RSA_WITH_IDEA_CBC_SHA [RFC5469]
* 0x00,0x08 TLS_RSA_EXPORT_WITH_DES40_CBC_SHA [RFC4346]
* 0x00,0x09 TLS_RSA_WITH_DES_CBC_SHA [RFC5469]
* 0x00,0x0A TLS_RSA_WITH_3DES_EDE_CBC_SHA [RFC5246]
* 0x00,0x0B TLS_DH_DSS_EXPORT_WITH_DES40_CBC_SHA [RFC4346]
* 0x00,0x0C TLS_DH_DSS_WITH_DES_CBC_SHA [RFC5469]
* 0x00,0x0D TLS_DH_DSS_WITH_3DES_EDE_CBC_SHA [RFC5246]
* 0x00,0x0E TLS_DH_RSA_EXPORT_WITH_DES40_CBC_SHA [RFC4346]
* 0x00,0x0F TLS_DH_RSA_WITH_DES_CBC_SHA [RFC5469]
* 0x00,0x10 TLS_DH_RSA_WITH_3DES_EDE_CBC_SHA [RFC5246]
* 0x00,0x11 TLS_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA [RFC4346]
* 0x00,0x12 TLS_DHE_DSS_WITH_DES_CBC_SHA [RFC5469]
* 0x00,0x13 TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA [RFC5246]
* 0x00,0x14 TLS_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA [RFC4346]
* 0x00,0x15 TLS_DHE_RSA_WITH_DES_CBC_SHA [RFC5469]
* 0x00,0x16 TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA [RFC5246]
* 0x00,0x17 TLS_DH_anon_EXPORT_WITH_RC4_40_MD5 [RFC4346]
* 0x00,0x18 TLS_DH_anon_WITH_RC4_128_MD5 [RFC5246]
* 0x00,0x19 TLS_DH_anon_EXPORT_WITH_DES40_CBC_SHA [RFC4346]
* 0x00,0x1A TLS_DH_anon_WITH_DES_CBC_SHA [RFC5469]
* 0x00,0x1B TLS_DH_anon_WITH_3DES_EDE_CBC_SHA [RFC5246]
* 0x00,0x1C-1D Reserved to avoid conflicts with SSLv3 [RFC5246]
* 0x00,0x1E TLS_KRB5_WITH_DES_CBC_SHA [RFC2712]
* 0x00,0x1F TLS_KRB5_WITH_3DES_EDE_CBC_SHA [RFC2712]
* 0x00,0x20 TLS_KRB5_WITH_RC4_128_SHA [RFC2712]
* 0x00,0x21 TLS_KRB5_WITH_IDEA_CBC_SHA [RFC2712]
* 0x00,0x22 TLS_KRB5_WITH_DES_CBC_MD5 [RFC2712]
* 0x00,0x23 TLS_KRB5_WITH_3DES_EDE_CBC_MD5 [RFC2712]
* 0x00,0x24 TLS_KRB5_WITH_RC4_128_MD5 [RFC2712]
* 0x00,0x25 TLS_KRB5_WITH_IDEA_CBC_MD5 [RFC2712]
* 0x00,0x26 TLS_KRB5_EXPORT_WITH_DES_CBC_40_SHA [RFC2712]
* 0x00,0x27 TLS_KRB5_EXPORT_WITH_RC2_CBC_40_SHA [RFC2712]
* 0x00,0x28 TLS_KRB5_EXPORT_WITH_RC4_40_SHA [RFC2712]
* 0x00,0x29 TLS_KRB5_EXPORT_WITH_DES_CBC_40_MD5 [RFC2712]
* 0x00,0x2A TLS_KRB5_EXPORT_WITH_RC2_CBC_40_MD5 [RFC2712]
* 0x00,0x2B TLS_KRB5_EXPORT_WITH_RC4_40_MD5 [RFC2712]
* 0x00,0x2C TLS_PSK_WITH_NULL_SHA [RFC4785]
* 0x00,0x2D TLS_DHE_PSK_WITH_NULL_SHA [RFC4785]
* 0x00,0x2E TLS_RSA_PSK_WITH_NULL_SHA [RFC4785]
* 0x00,0x2F TLS_RSA_WITH_AES_128_CBC_SHA [RFC5246]
* 0x00,0x30 TLS_DH_DSS_WITH_AES_128_CBC_SHA [RFC5246]
* 0x00,0x31 TLS_DH_RSA_WITH_AES_128_CBC_SHA [RFC5246]
* 0x00,0x32 TLS_DHE_DSS_WITH_AES_128_CBC_SHA [RFC5246]
* 0x00,0x33 TLS_DHE_RSA_WITH_AES_128_CBC_SHA [RFC5246]
* 0x00,0x34 TLS_DH_anon_WITH_AES_128_CBC_SHA [RFC5246]
* 0x00,0x35 TLS_RSA_WITH_AES_256_CBC_SHA [RFC5246]
* 0x00,0x36 TLS_DH_DSS_WITH_AES_256_CBC_SHA [RFC5246]
* 0x00,0x37 TLS_DH_RSA_WITH_AES_256_CBC_SHA [RFC5246]
* 0x00,0x38 TLS_DHE_DSS_WITH_AES_256_CBC_SHA [RFC5246]
* 0x00,0x39 TLS_DHE_RSA_WITH_AES_256_CBC_SHA [RFC5246]
* 0x00,0x3A TLS_DH_anon_WITH_AES_256_CBC_SHA [RFC5246]
* 0x00,0x3B TLS_RSA_WITH_NULL_SHA256 [RFC5246]
* 0x00,0x3C TLS_RSA_WITH_AES_128_CBC_SHA256 [RFC5246]
* 0x00,0x3D TLS_RSA_WITH_AES_256_CBC_SHA256 [RFC5246]
* 0x00,0x3E TLS_DH_DSS_WITH_AES_128_CBC_SHA256 [RFC5246]
* 0x00,0x3F TLS_DH_RSA_WITH_AES_128_CBC_SHA256 [RFC5246]
* 0x00,0x40 TLS_DHE_DSS_WITH_AES_128_CBC_SHA256 [RFC5246]
* 0x00,0x41 TLS_RSA_WITH_CAMELLIA_128_CBC_SHA [RFC5932]
* 0x00,0x42 TLS_DH_DSS_WITH_CAMELLIA_128_CBC_SHA [RFC5932]
* 0x00,0x43 TLS_DH_RSA_WITH_CAMELLIA_128_CBC_SHA [RFC5932]
* 0x00,0x44 TLS_DHE_DSS_WITH_CAMELLIA_128_CBC_SHA [RFC5932]
* 0x00,0x45 TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA [RFC5932]
* 0x00,0x46 TLS_DH_anon_WITH_CAMELLIA_128_CBC_SHA [RFC5932]
* 0x00,0x47-4F Reserved to avoid conflicts with
* deployed implementations [Pasi_Eronen]
* 0x00,0x50-58 Reserved to avoid conflicts [Pasi Eronen]
* 0x00,0x59-5C Reserved to avoid conflicts with
* deployed implementations [Pasi_Eronen]
* 0x00,0x5D-5F Unassigned
* 0x00,0x60-66 Reserved to avoid conflicts with widely
* deployed implementations [Pasi_Eronen]
* 0x00,0x67 TLS_DHE_RSA_WITH_AES_128_CBC_SHA256 [RFC5246]
* 0x00,0x68 TLS_DH_DSS_WITH_AES_256_CBC_SHA256 [RFC5246]
* 0x00,0x69 TLS_DH_RSA_WITH_AES_256_CBC_SHA256 [RFC5246]
* 0x00,0x6A TLS_DHE_DSS_WITH_AES_256_CBC_SHA256 [RFC5246]
* 0x00,0x6B TLS_DHE_RSA_WITH_AES_256_CBC_SHA256 [RFC5246]
* 0x00,0x6C TLS_DH_anon_WITH_AES_128_CBC_SHA256 [RFC5246]
* 0x00,0x6D TLS_DH_anon_WITH_AES_256_CBC_SHA256 [RFC5246]
* 0x00,0x6E-83 Unassigned
* 0x00,0x84 TLS_RSA_WITH_CAMELLIA_256_CBC_SHA [RFC5932]
* 0x00,0x85 TLS_DH_DSS_WITH_CAMELLIA_256_CBC_SHA [RFC5932]
* 0x00,0x86 TLS_DH_RSA_WITH_CAMELLIA_256_CBC_SHA [RFC5932]
* 0x00,0x87 TLS_DHE_DSS_WITH_CAMELLIA_256_CBC_SHA [RFC5932]
* 0x00,0x88 TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA [RFC5932]
* 0x00,0x89 TLS_DH_anon_WITH_CAMELLIA_256_CBC_SHA [RFC5932]
* 0x00,0x8A TLS_PSK_WITH_RC4_128_SHA [RFC4279]
* 0x00,0x8B TLS_PSK_WITH_3DES_EDE_CBC_SHA [RFC4279]
* 0x00,0x8C TLS_PSK_WITH_AES_128_CBC_SHA [RFC4279]
* 0x00,0x8D TLS_PSK_WITH_AES_256_CBC_SHA [RFC4279]
* 0x00,0x8E TLS_DHE_PSK_WITH_RC4_128_SHA [RFC4279]
* 0x00,0x8F TLS_DHE_PSK_WITH_3DES_EDE_CBC_SHA [RFC4279]
* 0x00,0x90 TLS_DHE_PSK_WITH_AES_128_CBC_SHA [RFC4279]
* 0x00,0x91 TLS_DHE_PSK_WITH_AES_256_CBC_SHA [RFC4279]
* 0x00,0x92 TLS_RSA_PSK_WITH_RC4_128_SHA [RFC4279]
* 0x00,0x93 TLS_RSA_PSK_WITH_3DES_EDE_CBC_SHA [RFC4279]
* 0x00,0x94 TLS_RSA_PSK_WITH_AES_128_CBC_SHA [RFC4279]
* 0x00,0x95 TLS_RSA_PSK_WITH_AES_256_CBC_SHA [RFC4279]
* 0x00,0x96 TLS_RSA_WITH_SEED_CBC_SHA [RFC4162]
* 0x00,0x97 TLS_DH_DSS_WITH_SEED_CBC_SHA [RFC4162]
* 0x00,0x98 TLS_DH_RSA_WITH_SEED_CBC_SHA [RFC4162]
* 0x00,0x99 TLS_DHE_DSS_WITH_SEED_CBC_SHA [RFC4162]
* 0x00,0x9A TLS_DHE_RSA_WITH_SEED_CBC_SHA [RFC4162]
* 0x00,0x9B TLS_DH_anon_WITH_SEED_CBC_SHA [RFC4162]
* 0x00,0x9C TLS_RSA_WITH_AES_128_GCM_SHA256 [RFC5288]
* 0x00,0x9D TLS_RSA_WITH_AES_256_GCM_SHA384 [RFC5288]
* 0x00,0x9E TLS_DHE_RSA_WITH_AES_128_GCM_SHA256 [RFC5288]
* 0x00,0x9F TLS_DHE_RSA_WITH_AES_256_GCM_SHA384 [RFC5288]
* 0x00,0xA0 TLS_DH_RSA_WITH_AES_128_GCM_SHA256 [RFC5288]
* 0x00,0xA1 TLS_DH_RSA_WITH_AES_256_GCM_SHA384 [RFC5288]
* 0x00,0xA2 TLS_DHE_DSS_WITH_AES_128_GCM_SHA256 [RFC5288]
* 0x00,0xA3 TLS_DHE_DSS_WITH_AES_256_GCM_SHA384 [RFC5288]
* 0x00,0xA4 TLS_DH_DSS_WITH_AES_128_GCM_SHA256 [RFC5288]
* 0x00,0xA5 TLS_DH_DSS_WITH_AES_256_GCM_SHA384 [RFC5288]
* 0x00,0xA6 TLS_DH_anon_WITH_AES_128_GCM_SHA256 [RFC5288]
* 0x00,0xA7 TLS_DH_anon_WITH_AES_256_GCM_SHA384 [RFC5288]
* 0x00,0xA8 TLS_PSK_WITH_AES_128_GCM_SHA256 [RFC5487]
* 0x00,0xA9 TLS_PSK_WITH_AES_256_GCM_SHA384 [RFC5487]
* 0x00,0xAA TLS_DHE_PSK_WITH_AES_128_GCM_SHA256 [RFC5487]
* 0x00,0xAB TLS_DHE_PSK_WITH_AES_256_GCM_SHA384 [RFC5487]
* 0x00,0xAC TLS_RSA_PSK_WITH_AES_128_GCM_SHA256 [RFC5487]
* 0x00,0xAD TLS_RSA_PSK_WITH_AES_256_GCM_SHA384 [RFC5487]
* 0x00,0xAE TLS_PSK_WITH_AES_128_CBC_SHA256 [RFC5487]
* 0x00,0xAF TLS_PSK_WITH_AES_256_CBC_SHA384 [RFC5487]
* 0x00,0xB0 TLS_PSK_WITH_NULL_SHA256 [RFC5487]
* 0x00,0xB1 TLS_PSK_WITH_NULL_SHA384 [RFC5487]
* 0x00,0xB2 TLS_DHE_PSK_WITH_AES_128_CBC_SHA256 [RFC5487]
* 0x00,0xB3 TLS_DHE_PSK_WITH_AES_256_CBC_SHA384 [RFC5487]
* 0x00,0xB4 TLS_DHE_PSK_WITH_NULL_SHA256 [RFC5487]
* 0x00,0xB5 TLS_DHE_PSK_WITH_NULL_SHA384 [RFC5487]
* 0x00,0xB6 TLS_RSA_PSK_WITH_AES_128_CBC_SHA256 [RFC5487]
* 0x00,0xB7 TLS_RSA_PSK_WITH_AES_256_CBC_SHA384 [RFC5487]
* 0x00,0xB8 TLS_RSA_PSK_WITH_NULL_SHA256 [RFC5487]
* 0x00,0xB9 TLS_RSA_PSK_WITH_NULL_SHA384 [RFC5487]
* 0x00,0xBA TLS_RSA_WITH_CAMELLIA_128_CBC_SHA256 [RFC5932]
* 0x00,0xBB TLS_DH_DSS_WITH_CAMELLIA_128_CBC_SHA256 [RFC5932]
* 0x00,0xBC TLS_DH_RSA_WITH_CAMELLIA_128_CBC_SHA256 [RFC5932]
* 0x00,0xBD TLS_DHE_DSS_WITH_CAMELLIA_128_CBC_SHA256 [RFC5932]
* 0x00,0xBE TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA256 [RFC5932]
* 0x00,0xBF TLS_DH_anon_WITH_CAMELLIA_128_CBC_SHA256 [RFC5932]
* 0x00,0xC0 TLS_RSA_WITH_CAMELLIA_256_CBC_SHA256 [RFC5932]
* 0x00,0xC1 TLS_DH_DSS_WITH_CAMELLIA_256_CBC_SHA256 [RFC5932]
* 0x00,0xC2 TLS_DH_RSA_WITH_CAMELLIA_256_CBC_SHA256 [RFC5932]
* 0x00,0xC3 TLS_DHE_DSS_WITH_CAMELLIA_256_CBC_SHA256 [RFC5932]
* 0x00,0xC4 TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA256 [RFC5932]
* 0x00,0xC5 TLS_DH_anon_WITH_CAMELLIA_256_CBC_SHA256 [RFC5932]
* 0x00,0xC6-FE Unassigned
* 0x00,0xFF TLS_EMPTY_RENEGOTIATION_INFO_SCSV [RFC5746]
* 0x01-BF,* Unassigned
* 0xC0,0x01 TLS_ECDH_ECDSA_WITH_NULL_SHA [RFC4492]
* 0xC0,0x02 TLS_ECDH_ECDSA_WITH_RC4_128_SHA [RFC4492]
* 0xC0,0x03 TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA [RFC4492]
* 0xC0,0x04 TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA [RFC4492]
* 0xC0,0x05 TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA [RFC4492]
* 0xC0,0x06 TLS_ECDHE_ECDSA_WITH_NULL_SHA [RFC4492]
* 0xC0,0x07 TLS_ECDHE_ECDSA_WITH_RC4_128_SHA [RFC4492]
* 0xC0,0x08 TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA [RFC4492]
* 0xC0,0x09 TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA [RFC4492]
* 0xC0,0x0A TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA [RFC4492]
* 0xC0,0x0B TLS_ECDH_RSA_WITH_NULL_SHA [RFC4492]
* 0xC0,0x0C TLS_ECDH_RSA_WITH_RC4_128_SHA [RFC4492]
* 0xC0,0x0D TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA [RFC4492]
* 0xC0,0x0E TLS_ECDH_RSA_WITH_AES_128_CBC_SHA [RFC4492]
* 0xC0,0x0F TLS_ECDH_RSA_WITH_AES_256_CBC_SHA [RFC4492]
* 0xC0,0x10 TLS_ECDHE_RSA_WITH_NULL_SHA [RFC4492]
* 0xC0,0x11 TLS_ECDHE_RSA_WITH_RC4_128_SHA [RFC4492]
* 0xC0,0x12 TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA [RFC4492]
* 0xC0,0x13 TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA [RFC4492]
* 0xC0,0x14 TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA [RFC4492]
* 0xC0,0x15 TLS_ECDH_anon_WITH_NULL_SHA [RFC4492]
* 0xC0,0x16 TLS_ECDH_anon_WITH_RC4_128_SHA [RFC4492]
* 0xC0,0x17 TLS_ECDH_anon_WITH_3DES_EDE_CBC_SHA [RFC4492]
* 0xC0,0x18 TLS_ECDH_anon_WITH_AES_128_CBC_SHA [RFC4492]
* 0xC0,0x19 TLS_ECDH_anon_WITH_AES_256_CBC_SHA [RFC4492]
* 0xC0,0x1A TLS_SRP_SHA_WITH_3DES_EDE_CBC_SHA [RFC5054]
* 0xC0,0x1B TLS_SRP_SHA_RSA_WITH_3DES_EDE_CBC_SHA [RFC5054]
* 0xC0,0x1C TLS_SRP_SHA_DSS_WITH_3DES_EDE_CBC_SHA [RFC5054]
* 0xC0,0x1D TLS_SRP_SHA_WITH_AES_128_CBC_SHA [RFC5054]
* 0xC0,0x1E TLS_SRP_SHA_RSA_WITH_AES_128_CBC_SHA [RFC5054]
* 0xC0,0x1F TLS_SRP_SHA_DSS_WITH_AES_128_CBC_SHA [RFC5054]
* 0xC0,0x20 TLS_SRP_SHA_WITH_AES_256_CBC_SHA [RFC5054]
* 0xC0,0x21 TLS_SRP_SHA_RSA_WITH_AES_256_CBC_SHA [RFC5054]
* 0xC0,0x22 TLS_SRP_SHA_DSS_WITH_AES_256_CBC_SHA [RFC5054]
* 0xC0,0x23 TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256 [RFC5289]
* 0xC0,0x24 TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384 [RFC5289]
* 0xC0,0x25 TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256 [RFC5289]
* 0xC0,0x26 TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384 [RFC5289]
* 0xC0,0x27 TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256 [RFC5289]
* 0xC0,0x28 TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384 [RFC5289]
* 0xC0,0x29 TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256 [RFC5289]
* 0xC0,0x2A TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384 [RFC5289]
* 0xC0,0x2B TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256 [RFC5289]
* 0xC0,0x2C TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384 [RFC5289]
* 0xC0,0x2D TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256 [RFC5289]
* 0xC0,0x2E TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384 [RFC5289]
* 0xC0,0x2F TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 [RFC5289]
* 0xC0,0x30 TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 [RFC5289]
* 0xC0,0x31 TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256 [RFC5289]
* 0xC0,0x32 TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384 [RFC5289]
* 0xC0,0x33 TLS_ECDHE_PSK_WITH_RC4_128_SHA [RFC5489]
* 0xC0,0x34 TLS_ECDHE_PSK_WITH_3DES_EDE_CBC_SHA [RFC5489]
* 0xC0,0x35 TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA [RFC5489]
* 0xC0,0x36 TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA [RFC5489]
* 0xC0,0x37 TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA256 [RFC5489]
* 0xC0,0x38 TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA384 [RFC5489]
* 0xC0,0x39 TLS_ECDHE_PSK_WITH_NULL_SHA [RFC5489]
* 0xC0,0x3A TLS_ECDHE_PSK_WITH_NULL_SHA256 [RFC5489]
* 0xC0,0x3B TLS_ECDHE_PSK_WITH_NULL_SHA384 [RFC5489]
* 0xC0,0x3C-FF Unassigned
* 0xC1-FD,* Unassigned
* 0xFE,0x00-FD Unassigned
* 0xFE,0xFE-FF Reserved to avoid conflicts with widely
* deployed implementations [Pasi_Eronen]
* 0xFF,0x00-FF Reserved for Private Use [RFC5246]
*/
add("SSL_NULL_WITH_NULL_NULL", add("SSL_NULL_WITH_NULL_NULL",
0x0000, 1, K_NULL, B_NULL, F); 0x0000, 1, K_NULL, B_NULL, F);
@ -574,7 +827,6 @@ final class CipherSuite implements Comparable {
0x0016, --p, K_DHE_RSA, B_3DES, T); 0x0016, --p, K_DHE_RSA, B_3DES, T);
add("SSL_DHE_DSS_WITH_3DES_EDE_CBC_SHA", add("SSL_DHE_DSS_WITH_3DES_EDE_CBC_SHA",
0x0013, --p, K_DHE_DSS, B_3DES, N); 0x0013, --p, K_DHE_DSS, B_3DES, N);
add("SSL_RSA_WITH_DES_CBC_SHA", add("SSL_RSA_WITH_DES_CBC_SHA",
0x0009, --p, K_RSA, B_DES, N); 0x0009, --p, K_RSA, B_DES, N);
add("SSL_DHE_RSA_WITH_DES_CBC_SHA", add("SSL_DHE_RSA_WITH_DES_CBC_SHA",
@ -582,13 +834,17 @@ final class CipherSuite implements Comparable {
add("SSL_DHE_DSS_WITH_DES_CBC_SHA", add("SSL_DHE_DSS_WITH_DES_CBC_SHA",
0x0012, --p, K_DHE_DSS, B_DES, N); 0x0012, --p, K_DHE_DSS, B_DES, N);
add("SSL_RSA_EXPORT_WITH_RC4_40_MD5", add("SSL_RSA_EXPORT_WITH_RC4_40_MD5",
0x0003, --p, K_RSA_EXPORT, B_RC4_40, N); 0x0003, --p, K_RSA_EXPORT, B_RC4_40, N,
ProtocolVersion.TLS11.v);
add("SSL_RSA_EXPORT_WITH_DES40_CBC_SHA", add("SSL_RSA_EXPORT_WITH_DES40_CBC_SHA",
0x0008, --p, K_RSA_EXPORT, B_DES_40, N); 0x0008, --p, K_RSA_EXPORT, B_DES_40, N,
ProtocolVersion.TLS11.v);
add("SSL_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA", add("SSL_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA",
0x0014, --p, K_DHE_RSA, B_DES_40, N); 0x0014, --p, K_DHE_RSA, B_DES_40, N,
ProtocolVersion.TLS11.v);
add("SSL_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA", add("SSL_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA",
0x0011, --p, K_DHE_DSS, B_DES_40, N); 0x0011, --p, K_DHE_DSS, B_DES_40, N,
ProtocolVersion.TLS11.v);
// Renegotiation protection request Signalling Cipher Suite Value (SCSV) // Renegotiation protection request Signalling Cipher Suite Value (SCSV)
add("TLS_EMPTY_RENEGOTIATION_INFO_SCSV", add("TLS_EMPTY_RENEGOTIATION_INFO_SCSV",
@ -634,9 +890,11 @@ final class CipherSuite implements Comparable {
0xC017, --p, K_ECDH_ANON, B_3DES, T); 0xC017, --p, K_ECDH_ANON, B_3DES, T);
add("SSL_DH_anon_EXPORT_WITH_RC4_40_MD5", add("SSL_DH_anon_EXPORT_WITH_RC4_40_MD5",
0x0017, --p, K_DH_ANON, B_RC4_40, N); 0x0017, --p, K_DH_ANON, B_RC4_40, N,
ProtocolVersion.TLS11.v);
add("SSL_DH_anon_EXPORT_WITH_DES40_CBC_SHA", add("SSL_DH_anon_EXPORT_WITH_DES40_CBC_SHA",
0x0019, --p, K_DH_ANON, B_DES_40, N); 0x0019, --p, K_DH_ANON, B_DES_40, N,
ProtocolVersion.TLS11.v);
add("TLS_ECDH_anon_WITH_NULL_SHA", add("TLS_ECDH_anon_WITH_NULL_SHA",
0xC015, --p, K_ECDH_ANON, B_NULL, N); 0xC015, --p, K_ECDH_ANON, B_NULL, N);
@ -655,13 +913,28 @@ final class CipherSuite implements Comparable {
add("TLS_KRB5_WITH_DES_CBC_MD5", add("TLS_KRB5_WITH_DES_CBC_MD5",
0x0022, --p, K_KRB5, B_DES, N); 0x0022, --p, K_KRB5, B_DES, N);
add("TLS_KRB5_EXPORT_WITH_RC4_40_SHA", add("TLS_KRB5_EXPORT_WITH_RC4_40_SHA",
0x0028, --p, K_KRB5_EXPORT, B_RC4_40, N); 0x0028, --p, K_KRB5_EXPORT, B_RC4_40, N,
ProtocolVersion.TLS11.v);
add("TLS_KRB5_EXPORT_WITH_RC4_40_MD5", add("TLS_KRB5_EXPORT_WITH_RC4_40_MD5",
0x002b, --p, K_KRB5_EXPORT, B_RC4_40, N); 0x002b, --p, K_KRB5_EXPORT, B_RC4_40, N,
ProtocolVersion.TLS11.v);
add("TLS_KRB5_EXPORT_WITH_DES_CBC_40_SHA", add("TLS_KRB5_EXPORT_WITH_DES_CBC_40_SHA",
0x0026, --p, K_KRB5_EXPORT, B_DES_40, N); 0x0026, --p, K_KRB5_EXPORT, B_DES_40, N,
ProtocolVersion.TLS11.v);
add("TLS_KRB5_EXPORT_WITH_DES_CBC_40_MD5", add("TLS_KRB5_EXPORT_WITH_DES_CBC_40_MD5",
0x0029, --p, K_KRB5_EXPORT, B_DES_40, N); 0x0029, --p, K_KRB5_EXPORT, B_DES_40, N,
ProtocolVersion.TLS11.v);
/*
* Other values from the TLS Cipher Suite Registry, as of August 2010.
*
* http://www.iana.org/assignments/tls-parameters/tls-parameters.xml
*
* Range Registration Procedures Notes
* 000-191 Standards Action Refers to value of first byte
* 192-254 Specification Required Refers to value of first byte
* 255 Reserved for Private Use Refers to value of first byte
*/
// Register the names of a few additional CipherSuites. // Register the names of a few additional CipherSuites.
// Makes them show up as names instead of numbers in // Makes them show up as names instead of numbers in
@ -701,6 +974,151 @@ final class CipherSuite implements Comparable {
add("TLS_KRB5_EXPORT_WITH_RC2_CBC_40_SHA", 0x0027); add("TLS_KRB5_EXPORT_WITH_RC2_CBC_40_SHA", 0x0027);
add("TLS_KRB5_EXPORT_WITH_RC2_CBC_40_MD5", 0x002a); add("TLS_KRB5_EXPORT_WITH_RC2_CBC_40_MD5", 0x002a);
// Unsupported cipher suites from RFC 4162
add("TLS_RSA_WITH_SEED_CBC_SHA", 0x0096);
add("TLS_DH_DSS_WITH_SEED_CBC_SHA", 0x0097);
add("TLS_DH_RSA_WITH_SEED_CBC_SHA", 0x0098);
add("TLS_DHE_DSS_WITH_SEED_CBC_SHA", 0x0099);
add("TLS_DHE_RSA_WITH_SEED_CBC_SHA", 0x009a);
add("TLS_DH_anon_WITH_SEED_CBC_SHA", 0x009b);
// Unsupported cipher suites from RFC 4279
add("TLS_PSK_WITH_RC4_128_SHA", 0x008a);
add("TLS_PSK_WITH_3DES_EDE_CBC_SHA", 0x008b);
add("TLS_PSK_WITH_AES_128_CBC_SHA", 0x008c);
add("TLS_PSK_WITH_AES_256_CBC_SHA", 0x008d);
add("TLS_DHE_PSK_WITH_RC4_128_SHA", 0x008e);
add("TLS_DHE_PSK_WITH_3DES_EDE_CBC_SHA", 0x008f);
add("TLS_DHE_PSK_WITH_AES_128_CBC_SHA", 0x0090);
add("TLS_DHE_PSK_WITH_AES_256_CBC_SHA", 0x0091);
add("TLS_RSA_PSK_WITH_RC4_128_SHA", 0x0092);
add("TLS_RSA_PSK_WITH_3DES_EDE_CBC_SHA", 0x0093);
add("TLS_RSA_PSK_WITH_AES_128_CBC_SHA", 0x0094);
add("TLS_RSA_PSK_WITH_AES_256_CBC_SHA", 0x0095);
// Unsupported cipher suites from RFC 4785
add("TLS_PSK_WITH_NULL_SHA", 0x002c);
add("TLS_DHE_PSK_WITH_NULL_SHA", 0x002d);
add("TLS_RSA_PSK_WITH_NULL_SHA", 0x002e);
// Unsupported cipher suites from RFC 5246
add("TLS_DH_DSS_WITH_AES_128_CBC_SHA", 0x0030);
add("TLS_DH_RSA_WITH_AES_128_CBC_SHA", 0x0031);
add("TLS_DH_DSS_WITH_AES_256_CBC_SHA", 0x0036);
add("TLS_DH_RSA_WITH_AES_256_CBC_SHA", 0x0037);
add("TLS_RSA_WITH_NULL_SHA256", 0x003b);
add("TLS_RSA_WITH_AES_128_CBC_SHA256", 0x003c);
add("TLS_RSA_WITH_AES_256_CBC_SHA256", 0x003d);
add("TLS_DH_DSS_WITH_AES_128_CBC_SHA256", 0x003e);
add("TLS_DH_RSA_WITH_AES_128_CBC_SHA256", 0x003f);
add("TLS_DHE_DSS_WITH_AES_128_CBC_SHA256", 0x0040);
add("TLS_DHE_RSA_WITH_AES_128_CBC_SHA256", 0x0067);
add("TLS_DH_DSS_WITH_AES_256_CBC_SHA256", 0x0068);
add("TLS_DH_RSA_WITH_AES_256_CBC_SHA256", 0x0069);
add("TLS_DHE_DSS_WITH_AES_256_CBC_SHA256", 0x006a);
add("TLS_DHE_RSA_WITH_AES_256_CBC_SHA256", 0x006b);
add("TLS_DH_anon_WITH_AES_128_CBC_SHA256", 0x006c);
add("TLS_DH_anon_WITH_AES_256_CBC_SHA256", 0x006d);
// Unsupported cipher suites from RFC 5288
add("TLS_RSA_WITH_AES_128_GCM_SHA256", 0x009c);
add("TLS_RSA_WITH_AES_256_GCM_SHA384", 0x009d);
add("TLS_DHE_RSA_WITH_AES_128_GCM_SHA256", 0x009e);
add("TLS_DHE_RSA_WITH_AES_256_GCM_SHA384", 0x009f);
add("TLS_DH_RSA_WITH_AES_128_GCM_SHA256", 0x00a0);
add("TLS_DH_RSA_WITH_AES_256_GCM_SHA384", 0x00a1);
add("TLS_DHE_DSS_WITH_AES_128_GCM_SHA256", 0x00a2);
add("TLS_DHE_DSS_WITH_AES_256_GCM_SHA384", 0x00a3);
add("TLS_DH_DSS_WITH_AES_128_GCM_SHA256", 0x00a4);
add("TLS_DH_DSS_WITH_AES_256_GCM_SHA384", 0x00a5);
add("TLS_DH_anon_WITH_AES_128_GCM_SHA256", 0x00a6);
add("TLS_DH_anon_WITH_AES_256_GCM_SHA384", 0x00a7);
// Unsupported cipher suites from RFC 5487
add("TLS_PSK_WITH_AES_128_GCM_SHA256", 0x00a8);
add("TLS_PSK_WITH_AES_256_GCM_SHA384", 0x00a9);
add("TLS_DHE_PSK_WITH_AES_128_GCM_SHA256", 0x00aa);
add("TLS_DHE_PSK_WITH_AES_256_GCM_SHA384", 0x00ab);
add("TLS_RSA_PSK_WITH_AES_128_GCM_SHA256", 0x00ac);
add("TLS_RSA_PSK_WITH_AES_256_GCM_SHA384", 0x00ad);
add("TLS_PSK_WITH_AES_128_CBC_SHA256", 0x00ae);
add("TLS_PSK_WITH_AES_256_CBC_SHA384", 0x00af);
add("TLS_PSK_WITH_NULL_SHA256", 0x00b0);
add("TLS_PSK_WITH_NULL_SHA384", 0x00b1);
add("TLS_DHE_PSK_WITH_AES_128_CBC_SHA256", 0x00b2);
add("TLS_DHE_PSK_WITH_AES_256_CBC_SHA384", 0x00b3);
add("TLS_DHE_PSK_WITH_NULL_SHA256", 0x00b4);
add("TLS_DHE_PSK_WITH_NULL_SHA384", 0x00b5);
add("TLS_RSA_PSK_WITH_AES_128_CBC_SHA256", 0x00b6);
add("TLS_RSA_PSK_WITH_AES_256_CBC_SHA384", 0x00b7);
add("TLS_RSA_PSK_WITH_NULL_SHA256", 0x00b8);
add("TLS_RSA_PSK_WITH_NULL_SHA384", 0x00b9);
// Unsupported cipher suites from RFC 5932
add("TLS_RSA_WITH_CAMELLIA_128_CBC_SHA", 0x0041);
add("TLS_DH_DSS_WITH_CAMELLIA_128_CBC_SHA", 0x0042);
add("TLS_DH_RSA_WITH_CAMELLIA_128_CBC_SHA", 0x0043);
add("TLS_DHE_DSS_WITH_CAMELLIA_128_CBC_SHA", 0x0044);
add("TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA", 0x0045);
add("TLS_DH_anon_WITH_CAMELLIA_128_CBC_SHA", 0x0046);
add("TLS_RSA_WITH_CAMELLIA_256_CBC_SHA", 0x0084);
add("TLS_DH_DSS_WITH_CAMELLIA_256_CBC_SHA", 0x0085);
add("TLS_DH_RSA_WITH_CAMELLIA_256_CBC_SHA", 0x0086);
add("TLS_DHE_DSS_WITH_CAMELLIA_256_CBC_SHA", 0x0087);
add("TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA", 0x0088);
add("TLS_DH_anon_WITH_CAMELLIA_256_CBC_SHA", 0x0089);
add("TLS_RSA_WITH_CAMELLIA_128_CBC_SHA256", 0x00ba);
add("TLS_DH_DSS_WITH_CAMELLIA_128_CBC_SHA256", 0x00bb);
add("TLS_DH_RSA_WITH_CAMELLIA_128_CBC_SHA256", 0x00bc);
add("TLS_DHE_DSS_WITH_CAMELLIA_128_CBC_SHA256", 0x00bd);
add("TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA256", 0x00be);
add("TLS_DH_anon_WITH_CAMELLIA_128_CBC_SHA256", 0x00bf);
add("TLS_RSA_WITH_CAMELLIA_256_CBC_SHA256", 0x00c0);
add("TLS_DH_DSS_WITH_CAMELLIA_256_CBC_SHA256", 0x00c1);
add("TLS_DH_RSA_WITH_CAMELLIA_256_CBC_SHA256", 0x00c2);
add("TLS_DHE_DSS_WITH_CAMELLIA_256_CBC_SHA256", 0x00c3);
add("TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA256", 0x00c4);
add("TLS_DH_anon_WITH_CAMELLIA_256_CBC_SHA256", 0x00c5);
// Unsupported cipher suites from RFC 5054
add("TLS_SRP_SHA_WITH_3DES_EDE_CBC_SHA", 0xc01a);
add("TLS_SRP_SHA_RSA_WITH_3DES_EDE_CBC_SHA", 0xc01b);
add("TLS_SRP_SHA_DSS_WITH_3DES_EDE_CBC_SHA", 0xc01c);
add("TLS_SRP_SHA_WITH_AES_128_CBC_SHA", 0xc01d);
add("TLS_SRP_SHA_RSA_WITH_AES_128_CBC_SHA", 0xc01e);
add("TLS_SRP_SHA_DSS_WITH_AES_128_CBC_SHA", 0xc01f);
add("TLS_SRP_SHA_WITH_AES_256_CBC_SHA", 0xc020);
add("TLS_SRP_SHA_RSA_WITH_AES_256_CBC_SHA", 0xc021);
add("TLS_SRP_SHA_DSS_WITH_AES_256_CBC_SHA", 0xc022);
// Unsupported cipher suites from RFC 5289
add("TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256", 0xc023);
add("TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384", 0xc024);
add("TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256", 0xc025);
add("TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384", 0xc026);
add("TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256", 0xc027);
add("TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384", 0xc028);
add("TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256", 0xc029);
add("TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384", 0xc02a);
add("TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256", 0xc02b);
add("TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384", 0xc02c);
add("TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256", 0xc02d);
add("TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384", 0xc02e);
add("TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256", 0xc02f);
add("TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384", 0xc030);
add("TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256", 0xc031);
add("TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384", 0xc032);
// Unsupported cipher suites from RFC 5489
add("TLS_ECDHE_PSK_WITH_RC4_128_SHA", 0xc033);
add("TLS_ECDHE_PSK_WITH_3DES_EDE_CBC_SHA", 0xc034);
add("TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA", 0xc035);
add("TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA", 0xc036);
add("TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA256", 0xc037);
add("TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA384", 0xc038);
add("TLS_ECDHE_PSK_WITH_NULL_SHA", 0xc039);
add("TLS_ECDHE_PSK_WITH_NULL_SHA256", 0xc03a);
add("TLS_ECDHE_PSK_WITH_NULL_SHA384", 0xc03b);
} }
// ciphersuite SSL_NULL_WITH_NULL_NULL // ciphersuite SSL_NULL_WITH_NULL_NULL

View file

@ -345,9 +345,10 @@ final class ClientHandshaker extends Handshaker {
// check if the server selected protocol version is OK for us // check if the server selected protocol version is OK for us
ProtocolVersion mesgVersion = mesg.protocolVersion; ProtocolVersion mesgVersion = mesg.protocolVersion;
if (enabledProtocols.contains(mesgVersion) == false) { if (!isNegotiable(mesgVersion)) {
throw new SSLHandshakeException throw new SSLHandshakeException(
("Server chose unsupported or disabled protocol: " + mesgVersion); "Server chose unsupported or disabled protocol: " +
mesgVersion);
} }
// Set protocolVersion and propagate to SSLSocket and the // Set protocolVersion and propagate to SSLSocket and the
@ -1022,7 +1023,7 @@ final class ClientHandshaker extends Handshaker {
SessionId sessionId = SSLSessionImpl.nullSession.getSessionId(); SessionId sessionId = SSLSessionImpl.nullSession.getSessionId();
// a list of cipher suites sent by the client // a list of cipher suites sent by the client
CipherSuiteList cipherSuites = enabledCipherSuites; CipherSuiteList cipherSuites = getActiveCipherSuites();
// set the max protocol version this client is supporting. // set the max protocol version this client is supporting.
maxProtocolVersion = protocolVersion; maxProtocolVersion = protocolVersion;
@ -1057,8 +1058,7 @@ final class ClientHandshaker extends Handshaker {
session = null; session = null;
} }
if ((session != null) && if ((session != null) && !isNegotiable(sessionVersion)) {
(enabledProtocols.contains(sessionVersion) == false)) {
if (debug != null && Debug.isOn("session")) { if (debug != null && Debug.isOn("session")) {
System.out.println("%% can't resume, protocol disabled"); System.out.println("%% can't resume, protocol disabled");
} }
@ -1088,7 +1088,7 @@ final class ClientHandshaker extends Handshaker {
*/ */
if (!enableNewSession) { if (!enableNewSession) {
if (session == null) { if (session == null) {
throw new SSLException( throw new SSLHandshakeException(
"Can't reuse existing SSL client session"); "Can't reuse existing SSL client session");
} }
@ -1105,7 +1105,7 @@ final class ClientHandshaker extends Handshaker {
} }
if (session == null && !enableNewSession) { if (session == null && !enableNewSession) {
throw new SSLException("No existing session to resume"); throw new SSLHandshakeException("No existing session to resume");
} }
// exclude SCSV for secure renegotiation // exclude SCSV for secure renegotiation
@ -1131,7 +1131,7 @@ final class ClientHandshaker extends Handshaker {
} }
if (!negotiable) { if (!negotiable) {
throw new SSLException("No negotiable cipher suite"); throw new SSLHandshakeException("No negotiable cipher suite");
} }
// create the ClientHello message // create the ClientHello message

View file

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 1999, 2009, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
@ -27,6 +27,7 @@ package sun.security.ssl;
import java.io.PrintStream; import java.io.PrintStream;
import java.security.AccessController; import java.security.AccessController;
import java.util.Locale;
import sun.security.action.GetPropertyAction; import sun.security.action.GetPropertyAction;
@ -44,7 +45,7 @@ public class Debug {
static { static {
args = java.security.AccessController.doPrivileged( args = java.security.AccessController.doPrivileged(
new GetPropertyAction("javax.net.debug", "")); new GetPropertyAction("javax.net.debug", ""));
args = args.toLowerCase(); args = args.toLowerCase(Locale.ENGLISH);
if (args.equals("help")) { if (args.equals("help")) {
Help(); Help();
} }
@ -114,7 +115,7 @@ public class Debug {
return false; return false;
} else { } else {
int n = 0; int n = 0;
option = option.toLowerCase(); option = option.toLowerCase(Locale.ENGLISH);
if (args.indexOf("all") != -1) { if (args.indexOf("all") != -1) {
return true; return true;

View file

@ -1167,10 +1167,15 @@ class CertificateRequest extends HandshakeMessage
s.println(); s.println();
s.println("Cert Authorities:"); s.println("Cert Authorities:");
for (int i = 0; i < authorities.length; i++) if (authorities.length == 0) {
s.println("<Empty>");
} else {
for (int i = 0; i < authorities.length; i++) {
authorities[i].print(s); authorities[i].print(s);
} }
} }
}
}
} }

View file

@ -71,11 +71,31 @@ abstract class Handshaker {
byte[] clientVerifyData; byte[] clientVerifyData;
byte[] serverVerifyData; byte[] serverVerifyData;
// is it an initial negotiation or a renegotiation? // Is it an initial negotiation or a renegotiation?
boolean isInitialHandshake; boolean isInitialHandshake;
// list of enabled protocols // List of enabled protocols
ProtocolList enabledProtocols; private ProtocolList enabledProtocols;
// List of enabled CipherSuites
private CipherSuiteList enabledCipherSuites;
/*
* List of active protocols
*
* Active protocols is a subset of enabled protocols, and will
* contain only those protocols that have vaild cipher suites
* enabled.
*/
private ProtocolList activeProtocols;
/*
* List of active cipher suites
*
* Active cipher suites is a subset of enabled cipher suites, and will
* contain only those cipher suites available for the active protocols.
*/
private CipherSuiteList activeCipherSuites;
private boolean isClient; private boolean isClient;
@ -94,9 +114,6 @@ abstract class Handshaker {
// in reset state after use. // in reset state after use.
private MessageDigest md5Tmp, shaTmp; private MessageDigest md5Tmp, shaTmp;
// list of enabled CipherSuites
CipherSuiteList enabledCipherSuites;
// current CipherSuite. Never null, initially SSL_NULL_WITH_NULL_NULL // current CipherSuite. Never null, initially SSL_NULL_WITH_NULL_NULL
CipherSuite cipherSuite; CipherSuite cipherSuite;
@ -233,7 +250,7 @@ abstract class Handshaker {
// client's cert verify, those constants are in a convenient // client's cert verify, those constants are in a convenient
// order to drastically simplify state machine checking. // order to drastically simplify state machine checking.
// //
state = -1; state = -2; // initialized but not activated
} }
/* /*
@ -345,26 +362,69 @@ abstract class Handshaker {
void setVersion(ProtocolVersion protocolVersion) { void setVersion(ProtocolVersion protocolVersion) {
this.protocolVersion = protocolVersion; this.protocolVersion = protocolVersion;
setVersionSE(protocolVersion); setVersionSE(protocolVersion);
output.r.setVersion(protocolVersion); output.r.setVersion(protocolVersion);
} }
/** /**
* Set the enabled protocols. Called from the constructor or * Set the enabled protocols. Called from the constructor or
* SSLSocketImpl.setEnabledProtocols() (if the handshake is not yet * SSLSocketImpl/SSLEngineImpl.setEnabledProtocols() (if the
* in progress). * handshake is not yet in progress).
*/ */
void setEnabledProtocols(ProtocolList enabledProtocols) { void setEnabledProtocols(ProtocolList enabledProtocols) {
activeCipherSuites = null;
activeProtocols = null;
this.enabledProtocols = enabledProtocols; this.enabledProtocols = enabledProtocols;
}
/**
* Set the enabled cipher suites. Called from
* SSLSocketImpl/SSLEngineImpl.setEnabledCipherSuites() (if the
* handshake is not yet in progress).
*/
void setEnabledCipherSuites(CipherSuiteList enabledCipherSuites) {
activeCipherSuites = null;
activeProtocols = null;
this.enabledCipherSuites = enabledCipherSuites;
}
/**
* Prior to handshaking, activate the handshake and initialize the version,
* input stream and output stream.
*/
void activate(ProtocolVersion helloVersion) throws IOException {
if (activeProtocols == null) {
activeProtocols = getActiveProtocols();
}
if (activeProtocols.collection().isEmpty() ||
activeProtocols.max.v == ProtocolVersion.NONE.v) {
throw new SSLHandshakeException("No appropriate protocol");
}
if (activeCipherSuites == null) {
activeCipherSuites = getActiveCipherSuites();
}
if (activeCipherSuites.collection().isEmpty()) {
throw new SSLHandshakeException("No appropriate cipher suite");
}
// temporary protocol version until the actual protocol version // temporary protocol version until the actual protocol version
// is negotiated in the Hello exchange. This affects the record // is negotiated in the Hello exchange. This affects the record
// version we sent with the ClientHello. Using max() as the record // version we sent with the ClientHello.
// version is not really correct but some implementations fail to if (!isInitialHandshake) {
// correctly negotiate TLS otherwise. protocolVersion = activeProtocolVersion;
protocolVersion = enabledProtocols.max; } else {
protocolVersion = activeProtocols.max;
}
ProtocolVersion helloVersion = enabledProtocols.helloVersion; if (helloVersion == null || helloVersion.v == ProtocolVersion.NONE.v) {
helloVersion = activeProtocols.helloVersion;
}
input = new HandshakeInStream(handshakeHash); input = new HandshakeInStream(handshakeHash);
@ -372,12 +432,16 @@ abstract class Handshaker {
output = new HandshakeOutStream(protocolVersion, helloVersion, output = new HandshakeOutStream(protocolVersion, helloVersion,
handshakeHash, conn); handshakeHash, conn);
conn.getAppInputStream().r.setHelloVersion(helloVersion); conn.getAppInputStream().r.setHelloVersion(helloVersion);
conn.getAppOutputStream().r.setHelloVersion(helloVersion);
} else { } else {
output = new HandshakeOutStream(protocolVersion, helloVersion, output = new HandshakeOutStream(protocolVersion, helloVersion,
handshakeHash, engine); handshakeHash, engine);
engine.inputRecord.setHelloVersion(helloVersion);
engine.outputRecord.setHelloVersion(helloVersion); engine.outputRecord.setHelloVersion(helloVersion);
} }
// move state to activated
state = -1;
} }
/** /**
@ -392,20 +456,127 @@ abstract class Handshaker {
/** /**
* Check if the given ciphersuite is enabled and available. * Check if the given ciphersuite is enabled and available.
* (Enabled ciphersuites are always available unless the status has
* changed due to change in JCE providers since it was enabled).
* Does not check if the required server certificates are available. * Does not check if the required server certificates are available.
*/ */
boolean isNegotiable(CipherSuite s) { boolean isNegotiable(CipherSuite s) {
return enabledCipherSuites.contains(s) && s.isNegotiable(); if (activeCipherSuites == null) {
activeCipherSuites = getActiveCipherSuites();
}
return activeCipherSuites.contains(s) && s.isNegotiable();
} }
/** /**
* As long as handshaking has not started, we can * Check if the given protocol version is enabled and available.
*/
boolean isNegotiable(ProtocolVersion protocolVersion) {
if (activeProtocols == null) {
activeProtocols = getActiveProtocols();
}
return activeProtocols.contains(protocolVersion);
}
/**
* Select a protocol version from the list. Called from
* ServerHandshaker to negotiate protocol version.
*
* Return the lower of the protocol version suggested in the
* clien hello and the highest supported by the server.
*/
ProtocolVersion selectProtocolVersion(ProtocolVersion protocolVersion) {
if (activeProtocols == null) {
activeProtocols = getActiveProtocols();
}
return activeProtocols.selectProtocolVersion(protocolVersion);
}
/**
* Get the active cipher suites.
*
* In TLS 1.1, many weak or vulnerable cipher suites were obsoleted,
* such as TLS_RSA_EXPORT_WITH_RC4_40_MD5. The implementation MUST NOT
* negotiate these cipher suites in TLS 1.1 or later mode.
*
* Therefore, when the active protocols only include TLS 1.1 or later,
* the client cannot request to negotiate those obsoleted cipher
* suites, that's, the obsoleted suites should not be included in the
* client hello. So we need to create a subset of the enabled cipher
* suites, the active cipher suites, which does not contain obsoleted
* cipher suites of the minimum active protocol.
*
* Return empty list instead of null if no active cipher suites.
*/
CipherSuiteList getActiveCipherSuites() {
if (activeCipherSuites == null) {
if (activeProtocols == null) {
activeProtocols = getActiveProtocols();
}
ArrayList<CipherSuite> suites = new ArrayList<CipherSuite>();
if (!(activeProtocols.collection().isEmpty()) &&
activeProtocols.min.v != ProtocolVersion.NONE.v) {
for (CipherSuite suite : enabledCipherSuites.collection()) {
if (suite.obsoleted > activeProtocols.min.v) {
suites.add(suite);
} else if (debug != null && Debug.isOn("handshake")) {
System.out.println(
"Ignoring obsoleted cipher suite: " + suite);
}
}
}
activeCipherSuites = new CipherSuiteList(suites);
}
return activeCipherSuites;
}
/*
* Get the active protocol versions.
*
* In TLS 1.1, many weak or vulnerable cipher suites were obsoleted,
* such as TLS_RSA_EXPORT_WITH_RC4_40_MD5. The implementation MUST NOT
* negotiate these cipher suites in TLS 1.1 or later mode.
*
* For example, if "TLS_RSA_EXPORT_WITH_RC4_40_MD5" is the
* only enabled cipher suite, the client cannot request TLS 1.1 or
* later, even though TLS 1.1 or later is enabled. We need to create a
* subset of the enabled protocols, called the active protocols, which
* contains protocols appropriate to the list of enabled Ciphersuites.
*
* Return empty list instead of null if no active protocol versions.
*/
ProtocolList getActiveProtocols() {
if (activeProtocols == null) {
ArrayList<ProtocolVersion> protocols =
new ArrayList<ProtocolVersion>(3);
for (ProtocolVersion protocol : enabledProtocols.collection()) {
boolean found = false;
for (CipherSuite suite : enabledCipherSuites.collection()) {
if (suite.isAvailable() && suite.obsoleted > protocol.v) {
protocols.add(protocol);
found = true;
break;
}
}
if (!found && (debug != null) && Debug.isOn("handshake")) {
System.out.println(
"No available cipher suite for " + protocol);
}
}
activeProtocols = new ProtocolList(protocols);
}
return activeProtocols;
}
/**
* As long as handshaking has not activated, we can
* change whether session creations are allowed. * change whether session creations are allowed.
* *
* Callers should do their own checking if handshaking * Callers should do their own checking if handshaking
* has started. * has activated.
*/ */
void setEnableSessionCreation(boolean newSessions) { void setEnableSessionCreation(boolean newSessions) {
enableNewSession = newSessions; enableNewSession = newSessions;
@ -419,12 +590,12 @@ abstract class Handshaker {
CipherBox box; CipherBox box;
if (isClient) { if (isClient) {
box = cipher.newCipher(protocolVersion, svrWriteKey, svrWriteIV, box = cipher.newCipher(protocolVersion, svrWriteKey, svrWriteIV,
false); sslContext.getSecureRandom(), false);
svrWriteKey = null; svrWriteKey = null;
svrWriteIV = null; svrWriteIV = null;
} else { } else {
box = cipher.newCipher(protocolVersion, clntWriteKey, clntWriteIV, box = cipher.newCipher(protocolVersion, clntWriteKey, clntWriteIV,
false); sslContext.getSecureRandom(), false);
clntWriteKey = null; clntWriteKey = null;
clntWriteIV = null; clntWriteIV = null;
} }
@ -439,12 +610,12 @@ abstract class Handshaker {
CipherBox box; CipherBox box;
if (isClient) { if (isClient) {
box = cipher.newCipher(protocolVersion, clntWriteKey, clntWriteIV, box = cipher.newCipher(protocolVersion, clntWriteKey, clntWriteIV,
true); sslContext.getSecureRandom(), true);
clntWriteKey = null; clntWriteKey = null;
clntWriteIV = null; clntWriteIV = null;
} else { } else {
box = cipher.newCipher(protocolVersion, svrWriteKey, svrWriteIV, box = cipher.newCipher(protocolVersion, svrWriteKey, svrWriteIV,
true); sslContext.getSecureRandom(), true);
svrWriteKey = null; svrWriteKey = null;
svrWriteIV = null; svrWriteIV = null;
} }
@ -613,14 +784,21 @@ abstract class Handshaker {
} }
/**
* Returns true iff the handshaker has been activated.
*
* In activated state, the handshaker may not send any messages out.
*/
boolean activated() {
return state >= -1;
}
/** /**
* Returns true iff the handshaker has sent any messages. * Returns true iff the handshaker has sent any messages.
* Server kickstarting is not as neat as it should be; we
* need to create a new handshaker, this method lets us
* know if we should.
*/ */
boolean started() { boolean started() {
return state >= 0; return state >= 0; // 0: HandshakeMessage.ht_hello_request
// 1: HandshakeMessage.ht_hello_request
} }
@ -633,6 +811,7 @@ abstract class Handshaker {
if (state >= 0) { if (state >= 0) {
return; return;
} }
HandshakeMessage m = getKickstartMessage(); HandshakeMessage m = getKickstartMessage();
if (debug != null && Debug.isOn("handshake")) { if (debug != null && Debug.isOn("handshake")) {
@ -746,6 +925,7 @@ abstract class Handshaker {
*/ */
private SecretKey calculateMasterSecret(SecretKey preMasterSecret, private SecretKey calculateMasterSecret(SecretKey preMasterSecret,
ProtocolVersion requestedVersion) { ProtocolVersion requestedVersion) {
TlsMasterSecretParameterSpec spec = new TlsMasterSecretParameterSpec TlsMasterSecretParameterSpec spec = new TlsMasterSecretParameterSpec
(preMasterSecret, protocolVersion.major, protocolVersion.minor, (preMasterSecret, protocolVersion.major, protocolVersion.minor,
clnt_random.random_bytes, svr_random.random_bytes); clnt_random.random_bytes, svr_random.random_bytes);
@ -773,22 +953,37 @@ abstract class Handshaker {
if (!preMasterSecret.getAlgorithm().equals("TlsRsaPremasterSecret")) { if (!preMasterSecret.getAlgorithm().equals("TlsRsaPremasterSecret")) {
throw new ProviderException(e); throw new ProviderException(e);
} }
if (debug != null && Debug.isOn("handshake")) { if (debug != null && Debug.isOn("handshake")) {
System.out.println("RSA master secret generation error:"); System.out.println("RSA master secret generation error:");
e.printStackTrace(System.out); e.printStackTrace(System.out);
System.out.println("Generating new random premaster secret"); System.out.println("Generating new random premaster secret");
} }
preMasterSecret = RSAClientKeyExchange.generateDummySecret(protocolVersion);
if (requestedVersion != null) {
preMasterSecret =
RSAClientKeyExchange.generateDummySecret(requestedVersion);
} else {
preMasterSecret =
RSAClientKeyExchange.generateDummySecret(protocolVersion);
}
// recursive call with new premaster secret // recursive call with new premaster secret
return calculateMasterSecret(preMasterSecret, null); return calculateMasterSecret(preMasterSecret, null);
} }
// if no version check requested (client side handshake), // if no version check requested (client side handshake), or version
// or version information is not available (not an RSA premaster secret), // information is not available (not an RSA premaster secret),
// return master secret immediately. // return master secret immediately.
if ((requestedVersion == null) || !(masterSecret instanceof TlsMasterSecret)) { if ((requestedVersion == null) ||
!(masterSecret instanceof TlsMasterSecret)) {
return masterSecret; return masterSecret;
} }
// we have checked the ClientKeyExchange message when reading TLS
// record, the following check is necessary to ensure that
// JCE provider does not ignore the checking, or the previous
// checking process bypassed the premaster secret version checking.
TlsMasterSecret tlsKey = (TlsMasterSecret)masterSecret; TlsMasterSecret tlsKey = (TlsMasterSecret)masterSecret;
int major = tlsKey.getMajorVersion(); int major = tlsKey.getMajorVersion();
int minor = tlsKey.getMinorVersion(); int minor = tlsKey.getMinorVersion();
@ -800,13 +995,21 @@ abstract class Handshaker {
// the specification says that it must be the maximum version supported // the specification says that it must be the maximum version supported
// by the client from its ClientHello message. However, many // by the client from its ClientHello message. However, many
// implementations send the negotiated version, so accept both // implementations send the negotiated version, so accept both
// NOTE that we may be comparing two unsupported version numbers in // for SSL v3.0 and TLS v1.0.
// the second case, which is why we cannot use object reference // NOTE that we may be comparing two unsupported version numbers, which
// equality in this special case // is why we cannot use object reference equality in this special case.
ProtocolVersion premasterVersion = ProtocolVersion.valueOf(major, minor); ProtocolVersion premasterVersion =
boolean versionMismatch = (premasterVersion != protocolVersion) && ProtocolVersion.valueOf(major, minor);
(premasterVersion.v != requestedVersion.v); boolean versionMismatch = (premasterVersion.v != requestedVersion.v);
/*
* we never checked the client_version in server side
* for TLS v1.0 and SSL v3.0. For compatibility, we
* maintain this behavior.
*/
if (versionMismatch && requestedVersion.v <= ProtocolVersion.TLS10.v) {
versionMismatch = (premasterVersion.v != protocolVersion.v);
}
if (versionMismatch == false) { if (versionMismatch == false) {
// check passed, return key // check passed, return key
@ -823,7 +1026,9 @@ abstract class Handshaker {
+ premasterVersion); + premasterVersion);
System.out.println("Generating new random premaster secret"); System.out.println("Generating new random premaster secret");
} }
preMasterSecret = RSAClientKeyExchange.generateDummySecret(protocolVersion); preMasterSecret =
RSAClientKeyExchange.generateDummySecret(requestedVersion);
// recursive call with new premaster secret // recursive call with new premaster secret
return calculateMasterSecret(preMasterSecret, null); return calculateMasterSecret(preMasterSecret, null);
} }
@ -849,8 +1054,6 @@ abstract class Handshaker {
int hashSize = cipherSuite.macAlg.size; int hashSize = cipherSuite.macAlg.size;
boolean is_exportable = cipherSuite.exportable; boolean is_exportable = cipherSuite.exportable;
BulkCipher cipher = cipherSuite.cipher; BulkCipher cipher = cipherSuite.cipher;
int keySize = cipher.keySize;
int ivSize = cipher.ivSize;
int expandedKeySize = is_exportable ? cipher.expandedKeySize : 0; int expandedKeySize = is_exportable ? cipher.expandedKeySize : 0;
TlsKeyMaterialParameterSpec spec = new TlsKeyMaterialParameterSpec TlsKeyMaterialParameterSpec spec = new TlsKeyMaterialParameterSpec
@ -867,6 +1070,8 @@ abstract class Handshaker {
clntWriteKey = keySpec.getClientCipherKey(); clntWriteKey = keySpec.getClientCipherKey();
svrWriteKey = keySpec.getServerCipherKey(); svrWriteKey = keySpec.getServerCipherKey();
// Return null if IVs are not supposed to be generated.
// e.g. TLS 1.1+.
clntWriteIV = keySpec.getClientIv(); clntWriteIV = keySpec.getClientIv();
svrWriteIV = keySpec.getServerIv(); svrWriteIV = keySpec.getServerIv();
@ -913,9 +1118,14 @@ abstract class Handshaker {
printHex(dump, clntWriteIV.getIV()); printHex(dump, clntWriteIV.getIV());
System.out.println("Server write IV:"); System.out.println("Server write IV:");
printHex(dump, svrWriteIV.getIV()); printHex(dump, svrWriteIV.getIV());
} else {
if (protocolVersion.v >= ProtocolVersion.TLS11.v) {
System.out.println(
"... no IV derived for this protocol");
} else { } else {
System.out.println("... no IV used for this cipher"); System.out.println("... no IV used for this cipher");
} }
}
System.out.flush(); System.out.flush();
} }
} }

View file

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2003, 2009, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
@ -69,6 +69,7 @@ public class KerberosClientKeyExchange extends HandshakeMessage {
} }
public KerberosClientKeyExchange() { public KerberosClientKeyExchange() {
// empty
} }
public KerberosClientKeyExchange(String serverName, boolean isLoopback, public KerberosClientKeyExchange(String serverName, boolean isLoopback,
@ -93,14 +94,17 @@ public class KerberosClientKeyExchange extends HandshakeMessage {
} }
} }
@Override
int messageType() { int messageType() {
return ht_client_key_exchange; return ht_client_key_exchange;
} }
@Override
public int messageLength() { public int messageLength() {
return impl.messageLength(); return impl.messageLength();
} }
@Override
public void send(HandshakeOutStream s) throws IOException { public void send(HandshakeOutStream s) throws IOException {
impl.send(s); impl.send(s);
} }

View file

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 1996, 2007, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 1996, 2010, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
@ -155,6 +155,42 @@ final class MAC {
return compute(type, bb, null, 0, bb.remaining()); return compute(type, bb, null, 0, bb.remaining());
} }
/**
* Check whether the sequence number is close to wrap
*
* Sequence numbers are of type uint64 and may not exceed 2^64-1.
* Sequence numbers do not wrap. When the sequence number is near
* to wrap, we need to close the connection immediately.
*/
final boolean seqNumOverflow() {
/*
* Conservatively, we don't allow more records to be generated
* when there are only 2^8 sequence numbers left.
*/
return (block != null && mac != null &&
block[0] == 0xFF && block[1] == 0xFF &&
block[2] == 0xFF && block[3] == 0xFF &&
block[4] == 0xFF && block[5] == 0xFF &&
block[6] == 0xFF);
}
/*
* Check whether to renew the sequence number
*
* Sequence numbers are of type uint64 and may not exceed 2^64-1.
* Sequence numbers do not wrap. If a TLS
* implementation would need to wrap a sequence number, it must
* renegotiate instead.
*/
final boolean seqNumIsHuge() {
/*
* Conservatively, we should ask for renegotiation when there are
* only 2^48 sequence numbers left.
*/
return (block != null && mac != null &&
block[0] == 0xFF && block[1] == 0xFF);
}
// increment the sequence number in the block array // increment the sequence number in the block array
// it is a 64-bit number stored in big-endian format // it is a 64-bit number stored in big-endian format
private void incrementSequenceNumber() { private void incrementSequenceNumber() {

View file

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2002, 2008, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2002, 2010, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
@ -38,8 +38,12 @@ import java.util.*;
final class ProtocolList { final class ProtocolList {
private static final ProtocolList SUPPORTED; private static final ProtocolList SUPPORTED;
private static final ProtocolList CLIENT_DEFAULT;
private static final ProtocolList SERVER_DEFAULT;
// the sorted protocol version list
private final ArrayList<ProtocolVersion> protocols;
private final Collection<ProtocolVersion> protocols;
private String[] protocolNames; private String[] protocolNames;
// the minimum and maximum ProtocolVersions in this list // the minimum and maximum ProtocolVersions in this list
@ -49,30 +53,45 @@ final class ProtocolList {
final ProtocolVersion helloVersion; final ProtocolVersion helloVersion;
ProtocolList(String[] names) { ProtocolList(String[] names) {
this(convert(names));
}
ProtocolList(ArrayList<ProtocolVersion> versions) {
this.protocols = versions;
if ((protocols.size() == 1) &&
protocols.contains(ProtocolVersion.SSL20Hello)) {
throw new IllegalArgumentException("SSLv2Hello cannot be " +
"enabled unless at least one other supported version " +
"is also enabled.");
}
if (protocols.size() != 0) {
Collections.sort(protocols);
min = protocols.get(0);
max = protocols.get(protocols.size() - 1);
helloVersion = protocols.get(0);
} else {
min = ProtocolVersion.NONE;
max = ProtocolVersion.NONE;
helloVersion = ProtocolVersion.NONE;
}
}
private static ArrayList<ProtocolVersion> convert(String[] names) {
if (names == null) { if (names == null) {
throw new IllegalArgumentException("Protocols may not be null"); throw new IllegalArgumentException("Protocols may not be null");
} }
protocols = new ArrayList<ProtocolVersion>(3);
ArrayList<ProtocolVersion> versions = new ArrayList<ProtocolVersion>(3);
for (int i = 0; i < names.length; i++ ) { for (int i = 0; i < names.length; i++ ) {
ProtocolVersion version = ProtocolVersion.valueOf(names[i]); ProtocolVersion version = ProtocolVersion.valueOf(names[i]);
if (protocols.contains(version) == false) { if (versions.contains(version) == false) {
protocols.add(version); versions.add(version);
} }
} }
if ((protocols.size() == 1)
&& protocols.contains(ProtocolVersion.SSL20Hello)) { return versions;
throw new IllegalArgumentException("SSLv2Hello" +
"cannot be enabled unless TLSv1 or SSLv3 is also enabled");
}
min = contains(ProtocolVersion.SSL30) ? ProtocolVersion.SSL30
: ProtocolVersion.TLS10;
max = contains(ProtocolVersion.TLS10) ? ProtocolVersion.TLS10
: ProtocolVersion.SSL30;
if (protocols.contains(ProtocolVersion.SSL20Hello)) {
helloVersion = ProtocolVersion.SSL20Hello;
} else {
helloVersion = min;
}
} }
/** /**
@ -87,6 +106,37 @@ final class ProtocolList {
return protocols.contains(protocolVersion); return protocols.contains(protocolVersion);
} }
/**
* Return a reference to the internal Collection of CipherSuites.
* The Collection MUST NOT be modified.
*/
Collection<ProtocolVersion> collection() {
return protocols;
}
/**
* Select a protocol version from the list.
*
* Return the lower of the protocol version of that suggested by
* the <code>protocolVersion</code> and the highest version of this
* protocol list, or null if no protocol version is available.
*
* The method is used by TLS server to negotiated the protocol
* version between client suggested protocol version in the
* client hello and protocol versions supported by the server.
*/
ProtocolVersion selectProtocolVersion(ProtocolVersion protocolVersion) {
ProtocolVersion selectedVersion = null;
for (ProtocolVersion pv : protocols) {
if (pv.v > protocolVersion.v) {
break; // Safe to break here as this.protocols is sorted
}
selectedVersion = pv;
}
return selectedVersion;
}
/** /**
* Return an array with the names of the ProtocolVersions in this list. * Return an array with the names of the ProtocolVersions in this list.
*/ */
@ -106,11 +156,18 @@ final class ProtocolList {
} }
/** /**
* Return the list of default enabled protocols. Currently, this * Return the list of default enabled protocols.
* is identical to the supported protocols.
*/ */
static ProtocolList getDefault() { static ProtocolList getDefault(boolean isServer) {
return SUPPORTED; return isServer ? SERVER_DEFAULT : CLIENT_DEFAULT;
}
/**
* Return whether a protocol list is the original default enabled
* protocols. See: SSLSocket/SSLEngine.setEnabledProtocols()
*/
static boolean isDefaultProtocolList(ProtocolList protocols) {
return protocols == CLIENT_DEFAULT || protocols == SERVER_DEFAULT;
} }
/** /**
@ -123,6 +180,12 @@ final class ProtocolList {
static { static {
if (SunJSSE.isFIPS()) { if (SunJSSE.isFIPS()) {
SUPPORTED = new ProtocolList(new String[] { SUPPORTED = new ProtocolList(new String[] {
ProtocolVersion.TLS10.name,
ProtocolVersion.TLS11.name
});
SERVER_DEFAULT = SUPPORTED;
CLIENT_DEFAULT = new ProtocolList(new String[] {
ProtocolVersion.TLS10.name ProtocolVersion.TLS10.name
}); });
} else { } else {
@ -130,6 +193,13 @@ final class ProtocolList {
ProtocolVersion.SSL20Hello.name, ProtocolVersion.SSL20Hello.name,
ProtocolVersion.SSL30.name, ProtocolVersion.SSL30.name,
ProtocolVersion.TLS10.name, ProtocolVersion.TLS10.name,
ProtocolVersion.TLS11.name
});
SERVER_DEFAULT = SUPPORTED;
CLIENT_DEFAULT = new ProtocolList(new String[] {
ProtocolVersion.SSL30.name,
ProtocolVersion.TLS10.name
}); });
} }
} }

View file

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2002, 2009, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2002, 2010, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
@ -45,9 +45,12 @@ package sun.security.ssl;
* @author Andreas Sterbenz * @author Andreas Sterbenz
* @since 1.4.1 * @since 1.4.1
*/ */
public final class ProtocolVersion { public final class ProtocolVersion implements Comparable<ProtocolVersion> {
// dummy protocol version value for invalid SSLSession // The limit of maximum protocol version
final static int LIMIT_MAX_VALUE = 0xFFFF;
// Dummy protocol version value for invalid SSLSession
final static ProtocolVersion NONE = new ProtocolVersion(-1, "NONE"); final static ProtocolVersion NONE = new ProtocolVersion(-1, "NONE");
// If enabled, send/ accept SSLv2 hello messages // If enabled, send/ accept SSLv2 hello messages
@ -61,22 +64,24 @@ public final class ProtocolVersion {
final static ProtocolVersion TLS10 = new ProtocolVersion(0x0301, "TLSv1"); final static ProtocolVersion TLS10 = new ProtocolVersion(0x0301, "TLSv1");
// TLS 1.1 // TLS 1.1
// not supported yet, but added for better readability of the debug trace
final static ProtocolVersion TLS11 = new ProtocolVersion(0x0302, "TLSv1.1"); final static ProtocolVersion TLS11 = new ProtocolVersion(0x0302, "TLSv1.1");
// TLS 1.2
final static ProtocolVersion TLS12 = new ProtocolVersion(0x0303, "TLSv1.2");
private static final boolean FIPS = SunJSSE.isFIPS(); private static final boolean FIPS = SunJSSE.isFIPS();
// minimum version we implement (SSL 3.0) // minimum version we implement (SSL 3.0)
final static ProtocolVersion MIN = FIPS ? TLS10 : SSL30; final static ProtocolVersion MIN = FIPS ? TLS10 : SSL30;
// maximum version we implement (TLS 1.0) // maximum version we implement (TLS 1.1)
final static ProtocolVersion MAX = TLS10; final static ProtocolVersion MAX = TLS11;
// ProtocolVersion to use by default (TLS 1.0) // ProtocolVersion to use by default (TLS 1.0)
final static ProtocolVersion DEFAULT = TLS10; final static ProtocolVersion DEFAULT = TLS10;
// Default version for hello messages (SSLv2Hello) // Default version for hello messages (SSLv2Hello)
final static ProtocolVersion DEFAULT_HELLO = FIPS ? TLS10 : SSL20Hello; final static ProtocolVersion DEFAULT_HELLO = FIPS ? TLS10 : SSL30;
// version in 16 bit MSB format as it appears in records and // version in 16 bit MSB format as it appears in records and
// messages, i.e. 0x0301 for TLS 1.0 // messages, i.e. 0x0301 for TLS 1.0
@ -104,6 +109,8 @@ public final class ProtocolVersion {
return TLS10; return TLS10;
} else if (v == TLS11.v) { } else if (v == TLS11.v) {
return TLS11; return TLS11;
} else if (v == TLS12.v) {
return TLS12;
} else if (v == SSL20Hello.v) { } else if (v == SSL20Hello.v) {
return SSL20Hello; return SSL20Hello;
} else { } else {
@ -134,18 +141,20 @@ public final class ProtocolVersion {
if (name == null) { if (name == null) {
throw new IllegalArgumentException("Protocol cannot be null"); throw new IllegalArgumentException("Protocol cannot be null");
} }
if (FIPS) {
if (name.equals(TLS10.name)) { if (FIPS && (name.equals(SSL30.name) || name.equals(SSL20Hello.name))) {
return TLS10;
} else {
throw new IllegalArgumentException throw new IllegalArgumentException
("Only TLS 1.0 allowed in FIPS mode"); ("Only TLS 1.0 or later allowed in FIPS mode");
}
} }
if (name.equals(SSL30.name)) { if (name.equals(SSL30.name)) {
return SSL30; return SSL30;
} else if (name.equals(TLS10.name)) { } else if (name.equals(TLS10.name)) {
return TLS10; return TLS10;
} else if (name.equals(TLS11.name)) {
return TLS11;
} else if (name.equals(TLS12.name)) {
return TLS12;
} else if (name.equals(SSL20Hello.name)) { } else if (name.equals(SSL20Hello.name)) {
return SSL20Hello; return SSL20Hello;
} else { } else {
@ -157,4 +166,10 @@ public final class ProtocolVersion {
return name; return name;
} }
/**
* Compares this object with the specified object for order.
*/
public int compareTo(ProtocolVersion protocolVersion) {
return this.v - protocolVersion.v;
}
} }

View file

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 1996, 2007, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 1996, 2010, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
@ -55,20 +55,17 @@ final class RSAClientKeyExchange extends HandshakeMessage {
* requested in its client hello version). However, we (and other * requested in its client hello version). However, we (and other
* implementations) used to send the active negotiated version. The * implementations) used to send the active negotiated version. The
* system property below allows to toggle the behavior. * system property below allows to toggle the behavior.
*
* Default is "false" (old behavior) for compatibility reasons. This
* will be changed in the future.
*/ */
private final static String PROP_NAME = private final static String PROP_NAME =
"com.sun.net.ssl.rsaPreMasterSecretFix"; "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 = private final static boolean rsaPreMasterSecretFix =
Debug.getBooleanProperty(PROP_NAME, false); Debug.getBooleanProperty(PROP_NAME, false);
int messageType() {
return ht_client_key_exchange;
}
/* /*
* The following field values were encrypted with the server's public * The following field values were encrypted with the server's public
* key (or temp key from server key exchange msg) and are presented * key (or temp key from server key exchange msg) and are presented
@ -78,14 +75,14 @@ final class RSAClientKeyExchange extends HandshakeMessage {
SecretKey preMaster; SecretKey preMaster;
private byte[] encrypted; // same size as public modulus private byte[] encrypted; // same size as public modulus
/* /*
* Client randomly creates a pre-master secret and encrypts it * Client randomly creates a pre-master secret and encrypts it
* using the server's RSA public key; only the server can decrypt * using the server's RSA public key; only the server can decrypt
* it, using its RSA private key. Result is the same size as the * it, using its RSA private key. Result is the same size as the
* server's public key, and uses PKCS #1 block format 02. * server's public key, and uses PKCS #1 block format 02.
*/ */
RSAClientKeyExchange(ProtocolVersion protocolVersion, ProtocolVersion maxVersion, RSAClientKeyExchange(ProtocolVersion protocolVersion,
ProtocolVersion maxVersion,
SecureRandom generator, PublicKey publicKey) throws IOException { SecureRandom generator, PublicKey publicKey) throws IOException {
if (publicKey.getAlgorithm().equals("RSA") == false) { if (publicKey.getAlgorithm().equals("RSA") == false) {
throw new SSLKeyException("Public key not of type RSA"); throw new SSLKeyException("Public key not of type RSA");
@ -94,7 +91,7 @@ final class RSAClientKeyExchange extends HandshakeMessage {
int major, minor; int major, minor;
if (rsaPreMasterSecretFix) { if (rsaPreMasterSecretFix || maxVersion.v >= ProtocolVersion.TLS11.v) {
major = maxVersion.major; major = maxVersion.major;
minor = maxVersion.minor; minor = maxVersion.minor;
} else { } else {
@ -103,7 +100,8 @@ final class RSAClientKeyExchange extends HandshakeMessage {
} }
try { try {
KeyGenerator kg = JsseJce.getKeyGenerator("SunTlsRsaPremasterSecret"); KeyGenerator kg =
JsseJce.getKeyGenerator("SunTlsRsaPremasterSecret");
kg.init(new TlsRsaPremasterSecretParameterSpec(major, minor)); kg.init(new TlsRsaPremasterSecretParameterSpec(major, minor));
preMaster = kg.generateKey(); preMaster = kg.generateKey();
@ -120,14 +118,15 @@ final class RSAClientKeyExchange extends HandshakeMessage {
* Server gets the PKCS #1 (block format 02) data, decrypts * Server gets the PKCS #1 (block format 02) data, decrypts
* it with its private key. * it with its private key.
*/ */
RSAClientKeyExchange(ProtocolVersion currentVersion, HandshakeInStream input, RSAClientKeyExchange(ProtocolVersion currentVersion,
ProtocolVersion maxVersion,
SecureRandom generator, HandshakeInStream input,
int messageSize, PrivateKey privateKey) throws IOException { int messageSize, PrivateKey privateKey) throws IOException {
if (privateKey.getAlgorithm().equals("RSA") == false) { if (privateKey.getAlgorithm().equals("RSA") == false) {
throw new SSLKeyException("Private key not of type RSA"); throw new SSLKeyException("Private key not of type RSA");
} }
this.protocolVersion = currentVersion;
if (currentVersion.v >= ProtocolVersion.TLS10.v) { if (currentVersion.v >= ProtocolVersion.TLS10.v) {
encrypted = input.getBytes16(); encrypted = input.getBytes16();
} else { } else {
@ -143,24 +142,101 @@ final class RSAClientKeyExchange extends HandshakeMessage {
cipher.init(Cipher.UNWRAP_MODE, privateKey); cipher.init(Cipher.UNWRAP_MODE, privateKey);
preMaster = (SecretKey)cipher.unwrap(encrypted, preMaster = (SecretKey)cipher.unwrap(encrypted,
"TlsRsaPremasterSecret", Cipher.SECRET_KEY); "TlsRsaPremasterSecret", Cipher.SECRET_KEY);
// polish the premaster secret
preMaster = polishPreMasterSecretKey(currentVersion, maxVersion,
generator, preMaster, null);
} catch (Exception e) { } catch (Exception e) {
/* // polish the premaster secret
* Bogus decrypted ClientKeyExchange? If so, conjure a preMaster =
* a random preMaster secret that will fail later during polishPreMasterSecretKey(currentVersion, maxVersion,
* Finished message processing. This is a countermeasure against generator, null, e);
* the "interactive RSA PKCS#1 encryption envelop attack" reported }
* in June 1998. Preserving the executation path will }
* mitigate timing attacks and force consistent error handling
* that will prevent an attacking client from differentiating /**
* different kinds of decrypted ClientKeyExchange bogosities. * 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 46 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 = ClientHello.client_version || R
* else If ClientHello.client_version <= TLS 1.0, and version
* number check is explicitly disabled:
* pre_master_secret = M
* else:
* pre_master_secret = ClientHello.client_version || M[2..47]
*/ */
private SecretKey polishPreMasterSecretKey(ProtocolVersion currentVersion,
ProtocolVersion clientHelloVersion, SecureRandom generator,
SecretKey secretKey, Exception failoverException) {
this.protocolVersion = clientHelloVersion;
if (failoverException == null && secretKey != null) {
// check the length
byte[] encoded = secretKey.getEncoded();
if (encoded == null) { // unable to get the encoded key
if (debug != null && Debug.isOn("handshake")) { if (debug != null && Debug.isOn("handshake")) {
System.out.println(
"unable to get the plaintext of the premaster secret");
}
// We are not always able to get the encoded key of the
// premaster secret. Pass the cheking to master secret
// calculation.
return secretKey;
} else if (encoded.length == 48) {
// check the version
if (clientHelloVersion.major == encoded[0] &&
clientHelloVersion.minor == encoded[1]) {
return secretKey;
} else if (clientHelloVersion.v <= ProtocolVersion.TLS10.v) {
/*
* we never checked the client_version in server side
* for TLS v1.0 and SSL v3.0. For compatibility, we
* maintain this behavior.
*/
if (currentVersion.major == encoded[0] &&
currentVersion.minor == encoded[1]) {
this.protocolVersion = currentVersion;
return secretKey;
}
}
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]));
}
} else {
if (debug != null && Debug.isOn("handshake")) {
System.out.println(
"incorrect length of premaster secret: " +
encoded.length);
}
}
}
if (debug != null && Debug.isOn("handshake")) {
if (failoverException != null) {
System.out.println("Error decrypting premaster secret:"); System.out.println("Error decrypting premaster secret:");
e.printStackTrace(System.out); failoverException.printStackTrace(System.out);
}
System.out.println("Generating random secret"); System.out.println("Generating random secret");
} }
preMaster = generateDummySecret(currentVersion);
} return generateDummySecret(clientHelloVersion);
} }
// generate a premaster secret with the specified version number // generate a premaster secret with the specified version number
@ -176,6 +252,12 @@ final class RSAClientKeyExchange extends HandshakeMessage {
} }
} }
@Override
int messageType() {
return ht_client_key_exchange;
}
@Override
int messageLength() { int messageLength() {
if (protocolVersion.v >= ProtocolVersion.TLS10.v) { if (protocolVersion.v >= ProtocolVersion.TLS10.v) {
return encrypted.length + 2; return encrypted.length + 2;
@ -184,6 +266,7 @@ final class RSAClientKeyExchange extends HandshakeMessage {
} }
} }
@Override
void send(HandshakeOutStream s) throws IOException { void send(HandshakeOutStream s) throws IOException {
if (protocolVersion.v >= ProtocolVersion.TLS10.v) { if (protocolVersion.v >= ProtocolVersion.TLS10.v) {
s.putBytes16(encrypted); s.putBytes16(encrypted);
@ -192,7 +275,9 @@ final class RSAClientKeyExchange extends HandshakeMessage {
} }
} }
@Override
void print(PrintStream s) throws IOException { void print(PrintStream s) throws IOException {
s.println("*** ClientKeyExchange, RSA PreMasterSecret, " + protocolVersion); s.println("*** ClientKeyExchange, RSA PreMasterSecret, " +
protocolVersion);
} }
} }

View file

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 1996, 2007, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 1996, 2010, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
@ -52,6 +52,7 @@ interface Record {
static final int trailerSize = 20; // SHA1 hash size static final int trailerSize = 20; // SHA1 hash size
static final int maxDataSize = 16384; // 2^14 bytes of data static final int maxDataSize = 16384; // 2^14 bytes of data
static final int maxPadding = 256; // block cipher padding static final int maxPadding = 256; // block cipher padding
static final int maxIVLength = 256; // block length
/* /*
* SSL has a maximum record size. It's header, (compressed) data, * SSL has a maximum record size. It's header, (compressed) data,
@ -61,6 +62,7 @@ interface Record {
*/ */
static final int maxRecordSize = static final int maxRecordSize =
headerSize // header headerSize // header
+ maxIVLength // iv
+ maxDataSize // data + maxDataSize // data
+ maxPadding // padding + maxPadding // padding
+ trailerSize; // MAC + trailerSize; // MAC
@ -85,6 +87,10 @@ interface Record {
* Allocate a smaller array. * Allocate a smaller array.
*/ */
static final int maxAlertRecordSize = static final int maxAlertRecordSize =
headerSize + 2 + maxPadding + trailerSize; headerSize // header
+ maxIVLength // iv
+ 2 // alert
+ maxPadding // padding
+ trailerSize; // MAC
} }

View file

@ -240,12 +240,14 @@ final public class SSLEngineImpl extends SSLEngine {
* session is changed. * session is changed.
*/ */
private byte doClientAuth; private byte doClientAuth;
private CipherSuiteList enabledCipherSuites;
private boolean enableSessionCreation = true; private boolean enableSessionCreation = true;
EngineInputRecord inputRecord; EngineInputRecord inputRecord;
EngineOutputRecord outputRecord; EngineOutputRecord outputRecord;
private AccessControlContext acc; private AccessControlContext acc;
// The cipher suites enabled for use on this connection.
private CipherSuiteList enabledCipherSuites;
// hostname identification algorithm, the hostname identification is // hostname identification algorithm, the hostname identification is
// disabled by default. // disabled by default.
private String identificationAlg = null; private String identificationAlg = null;
@ -255,11 +257,11 @@ final public class SSLEngineImpl extends SSLEngine {
private boolean roleIsServer; private boolean roleIsServer;
/* /*
* The protocols we support are SSL Version 3.0) and * The protocol versions enabled for use on this connection.
* TLS (version 3.1). *
* In addition we support a pseudo protocol called * Note: we support a pseudo protocol called SSLv2Hello which when
* SSLv2Hello which when set will result in an SSL v2 Hello * set will result in an SSL v2 Hello being sent with SSL (version 3.0)
* being sent with SSLv3 or TLSv1 version info. * or TLS (version 3.1, 3.2, etc.) version info.
*/ */
private ProtocolList enabledProtocols; private ProtocolList enabledProtocols;
@ -368,7 +370,7 @@ final public class SSLEngineImpl extends SSLEngine {
serverVerifyData = new byte[0]; serverVerifyData = new byte[0];
enabledCipherSuites = CipherSuiteList.getDefault(); enabledCipherSuites = CipherSuiteList.getDefault();
enabledProtocols = ProtocolList.getDefault(); enabledProtocols = ProtocolList.getDefault(roleIsServer);
wrapLock = new Object(); wrapLock = new Object();
unwrapLock = new Object(); unwrapLock = new Object();
@ -405,8 +407,8 @@ final public class SSLEngineImpl extends SSLEngine {
* . if the engine is already closed, throw an Exception (internal error) * . if the engine is already closed, throw an Exception (internal error)
* *
* . otherwise (cs_START or cs_DATA), create the appropriate handshaker * . otherwise (cs_START or cs_DATA), create the appropriate handshaker
* object, initialize it, and advance the connection state (to * object and advance the connection state (to cs_HANDSHAKE or
* cs_HANDSHAKE or cs_RENEGOTIATE, respectively). * cs_RENEGOTIATE, respectively).
* *
* This method is called right after a new engine is created, when * This method is called right after a new engine is created, when
* starting renegotiation, or when changing client/server mode of the * starting renegotiation, or when changing client/server mode of the
@ -454,12 +456,8 @@ final public class SSLEngineImpl extends SSLEngine {
protocolVersion, connectionState == cs_HANDSHAKE, protocolVersion, connectionState == cs_HANDSHAKE,
secureRenegotiation, clientVerifyData, serverVerifyData); secureRenegotiation, clientVerifyData, serverVerifyData);
} }
handshaker.enabledCipherSuites = enabledCipherSuites; handshaker.setEnabledCipherSuites(enabledCipherSuites);
handshaker.setEnableSessionCreation(enableSessionCreation); handshaker.setEnableSessionCreation(enableSessionCreation);
if (connectionState == cs_RENEGOTIATE) {
// don't use SSLv2Hello when renegotiating
handshaker.output.r.setHelloVersion(protocolVersion);
}
} }
/* /*
@ -686,7 +684,15 @@ final public class SSLEngineImpl extends SSLEngine {
// to its HandshakeOutStream, which calls back into // to its HandshakeOutStream, which calls back into
// SSLSocketImpl.writeRecord() to send it. // SSLSocketImpl.writeRecord() to send it.
// //
if (!handshaker.started()) { if (!handshaker.activated()) {
// prior to handshaking, activate the handshake
if (connectionState == cs_RENEGOTIATE) {
// don't use SSLv2Hello when renegotiating
handshaker.activate(protocolVersion);
} else {
handshaker.activate(null);
}
if (handshaker instanceof ClientHandshaker) { if (handshaker instanceof ClientHandshaker) {
// send client hello // send client hello
handshaker.kickstart(); handshaker.kickstart();
@ -696,6 +702,7 @@ final public class SSLEngineImpl extends SSLEngine {
} else { } else {
// we want to renegotiate, send hello request // we want to renegotiate, send hello request
handshaker.kickstart(); handshaker.kickstart();
// hello request is not included in the handshake // hello request is not included in the handshake
// hashes, reset them // hashes, reset them
handshaker.handshakeHash.reset(); handshaker.handshakeHash.reset();
@ -982,6 +989,15 @@ final public class SSLEngineImpl extends SSLEngine {
* in it. * in it.
*/ */
initHandshaker(); initHandshaker();
if (!handshaker.activated()) {
// prior to handshaking, activate the handshake
if (connectionState == cs_RENEGOTIATE) {
// don't use SSLv2Hello when renegotiating
handshaker.activate(protocolVersion);
} else {
handshaker.activate(null);
}
}
/* /*
* process the handshake record ... may contain just * process the handshake record ... may contain just
@ -1081,6 +1097,26 @@ final public class SSLEngineImpl extends SSLEngine {
} }
break; break;
} // switch } // switch
/*
* We only need to check the sequence number state for
* non-handshaking record.
*
* Note that in order to maintain the handshake status
* properly, we check the sequence number after the last
* record reading process. As we request renegotiation
* or close the connection for wrapped sequence number
* when there is enough sequence number space left to
* handle a few more records, so the sequence number
* of the last record cannot be wrapped.
*/
if (connectionState < cs_ERROR && !isInboundDone() &&
(hsStatus == HandshakeStatus.NOT_HANDSHAKING)) {
if (checkSequenceNumber(readMAC,
inputRecord.contentType())) {
hsStatus = getHSStatus(null);
}
}
} // synchronized (this) } // synchronized (this)
} }
@ -1229,7 +1265,29 @@ final public class SSLEngineImpl extends SSLEngine {
EngineArgs ea) throws IOException { EngineArgs ea) throws IOException {
// eventually compress as well. // eventually compress as well.
return writer.writeRecord(eor, ea, writeMAC, writeCipher); HandshakeStatus hsStatus =
writer.writeRecord(eor, ea, writeMAC, writeCipher);
/*
* We only need to check the sequence number state for
* non-handshaking record.
*
* Note that in order to maintain the handshake status
* properly, we check the sequence number after the last
* record writing process. As we request renegotiation
* or close the connection for wrapped sequence number
* when there is enough sequence number space left to
* handle a few more records, so the sequence number
* of the last record cannot be wrapped.
*/
if (connectionState < cs_ERROR && !isOutboundDone() &&
(hsStatus == HandshakeStatus.NOT_HANDSHAKING)) {
if (checkSequenceNumber(writeMAC, eor.contentType())) {
hsStatus = getHSStatus(null);
}
}
return hsStatus;
} }
/* /*
@ -1238,12 +1296,88 @@ final public class SSLEngineImpl extends SSLEngine {
void writeRecord(EngineOutputRecord eor) throws IOException { void writeRecord(EngineOutputRecord eor) throws IOException {
// eventually compress as well. // eventually compress as well.
writer.writeRecord(eor, writeMAC, writeCipher); writer.writeRecord(eor, writeMAC, writeCipher);
/*
* Check the sequence number state
*
* Note that in order to maintain the connection I/O
* properly, we check the sequence number after the last
* record writing process. As we request renegotiation
* or close the connection for wrapped sequence number
* when there is enough sequence number space left to
* handle a few more records, so the sequence number
* of the last record cannot be wrapped.
*/
if ((connectionState < cs_ERROR) && !isOutboundDone()) {
checkSequenceNumber(writeMAC, eor.contentType());
}
} }
// //
// Close code // Close code
// //
/**
* Check the sequence number state
*
* RFC 4346 states that, "Sequence numbers are of type uint64 and
* may not exceed 2^64-1. Sequence numbers do not wrap. If a TLS
* implementation would need to wrap a sequence number, it must
* renegotiate instead."
*
* Return true if the handshake status may be changed.
*/
private boolean checkSequenceNumber(MAC mac, byte type)
throws IOException {
/*
* Don't bother to check the sequence number for error or
* closed connections, or NULL MAC
*/
if (connectionState >= cs_ERROR || mac == MAC.NULL) {
return false;
}
/*
* Conservatively, close the connection immediately when the
* sequence number is close to overflow
*/
if (mac.seqNumOverflow()) {
/*
* TLS protocols do not define a error alert for sequence
* number overflow. We use handshake_failure error alert
* for handshaking and bad_record_mac for other records.
*/
if (debug != null && Debug.isOn("ssl")) {
System.out.println(threadName() +
", sequence number extremely close to overflow " +
"(2^64-1 packets). Closing connection.");
}
fatal(Alerts.alert_handshake_failure, "sequence number overflow");
return true; // make the compiler happy
}
/*
* Ask for renegotiation when need to renew sequence number.
*
* Don't bother to kickstart the renegotiation when the local is
* asking for it.
*/
if ((type != Record.ct_handshake) && mac.seqNumIsHuge()) {
if (debug != null && Debug.isOn("ssl")) {
System.out.println(threadName() + ", request renegotiation " +
"to avoid sequence number overflow");
}
beginHandshake();
return true;
}
return false;
}
/** /**
* Signals that no more outbound application data will be sent * Signals that no more outbound application data will be sent
* on this <code>SSLEngine</code>. * on this <code>SSLEngine</code>.
@ -1594,10 +1728,18 @@ final public class SSLEngineImpl extends SSLEngine {
* Emit alerts. Caller must have synchronized with "this". * Emit alerts. Caller must have synchronized with "this".
*/ */
private void sendAlert(byte level, byte description) { private void sendAlert(byte level, byte description) {
// the connectionState cannot be cs_START
if (connectionState >= cs_CLOSED) { if (connectionState >= cs_CLOSED) {
return; return;
} }
// For initial handshaking, don't send alert message to peer if
// handshaker has not started.
if (connectionState == cs_HANDSHAKE &&
(handshaker == null || !handshaker.started())) {
return;
}
EngineOutputRecord r = new EngineOutputRecord(Record.ct_alert, this); EngineOutputRecord r = new EngineOutputRecord(Record.ct_alert, this);
r.setVersion(protocolVersion); r.setVersion(protocolVersion);
@ -1647,7 +1789,7 @@ final public class SSLEngineImpl extends SSLEngine {
synchronized public void setEnableSessionCreation(boolean flag) { synchronized public void setEnableSessionCreation(boolean flag) {
enableSessionCreation = flag; enableSessionCreation = flag;
if ((handshaker != null) && !handshaker.started()) { if ((handshaker != null) && !handshaker.activated()) {
handshaker.setEnableSessionCreation(enableSessionCreation); handshaker.setEnableSessionCreation(enableSessionCreation);
} }
} }
@ -1675,7 +1817,7 @@ final public class SSLEngineImpl extends SSLEngine {
if ((handshaker != null) && if ((handshaker != null) &&
(handshaker instanceof ServerHandshaker) && (handshaker instanceof ServerHandshaker) &&
!handshaker.started()) { !handshaker.activated()) {
((ServerHandshaker) handshaker).setClientAuth(doClientAuth); ((ServerHandshaker) handshaker).setClientAuth(doClientAuth);
} }
} }
@ -1698,7 +1840,7 @@ final public class SSLEngineImpl extends SSLEngine {
if ((handshaker != null) && if ((handshaker != null) &&
(handshaker instanceof ServerHandshaker) && (handshaker instanceof ServerHandshaker) &&
!handshaker.started()) { !handshaker.activated()) {
((ServerHandshaker) handshaker).setClientAuth(doClientAuth); ((ServerHandshaker) handshaker).setClientAuth(doClientAuth);
} }
} }
@ -1717,6 +1859,16 @@ final public class SSLEngineImpl extends SSLEngine {
switch (connectionState) { switch (connectionState) {
case cs_START: case cs_START:
/*
* If we need to change the engine mode and the enabled
* protocols haven't specifically been set by the user,
* change them to the corresponding default ones.
*/
if (roleIsServer != (!flag) &&
ProtocolList.isDefaultProtocolList(enabledProtocols)) {
enabledProtocols = ProtocolList.getDefault(!flag);
}
roleIsServer = !flag; roleIsServer = !flag;
serverModeSet = true; serverModeSet = true;
break; break;
@ -1730,7 +1882,17 @@ final public class SSLEngineImpl extends SSLEngine {
* have the streams. * have the streams.
*/ */
assert(handshaker != null); assert(handshaker != null);
if (!handshaker.started()) { if (!handshaker.activated()) {
/*
* If we need to change the engine mode and the enabled
* protocols haven't specifically been set by the user,
* change them to the corresponding default ones.
*/
if (roleIsServer != (!flag) &&
ProtocolList.isDefaultProtocolList(enabledProtocols)) {
enabledProtocols = ProtocolList.getDefault(!flag);
}
roleIsServer = !flag; roleIsServer = !flag;
connectionState = cs_START; connectionState = cs_START;
initHandshaker(); initHandshaker();
@ -1786,8 +1948,8 @@ final public class SSLEngineImpl extends SSLEngine {
*/ */
synchronized public void setEnabledCipherSuites(String[] suites) { synchronized public void setEnabledCipherSuites(String[] suites) {
enabledCipherSuites = new CipherSuiteList(suites); enabledCipherSuites = new CipherSuiteList(suites);
if ((handshaker != null) && !handshaker.started()) { if ((handshaker != null) && !handshaker.activated()) {
handshaker.enabledCipherSuites = enabledCipherSuites; handshaker.setEnabledCipherSuites(enabledCipherSuites);
} }
} }
@ -1826,7 +1988,7 @@ final public class SSLEngineImpl extends SSLEngine {
*/ */
synchronized public void setEnabledProtocols(String[] protocols) { synchronized public void setEnabledProtocols(String[] protocols) {
enabledProtocols = new ProtocolList(protocols); enabledProtocols = new ProtocolList(protocols);
if ((handshaker != null) && !handshaker.started()) { if ((handshaker != null) && !handshaker.activated()) {
handshaker.setEnabledProtocols(enabledProtocols); handshaker.setEnabledProtocols(enabledProtocols);
} }
} }

View file

@ -145,7 +145,7 @@ class SSLServerSocketImpl extends SSLServerSocket
} }
sslContext = context; sslContext = context;
enabledCipherSuites = CipherSuiteList.getDefault(); enabledCipherSuites = CipherSuiteList.getDefault();
enabledProtocols = ProtocolList.getDefault(); enabledProtocols = ProtocolList.getDefault(true);
} }
/** /**
@ -238,6 +238,16 @@ class SSLServerSocketImpl extends SSLServerSocket
* rejoining the already-negotiated SSL connection. * rejoining the already-negotiated SSL connection.
*/ */
public void setUseClientMode(boolean flag) { public void setUseClientMode(boolean flag) {
/*
* If we need to change the socket mode and the enabled
* protocols haven't specifically been set by the user,
* change them to the corresponding default ones.
*/
if (useServerMode != (!flag) &&
ProtocolList.isDefaultProtocolList(enabledProtocols)) {
enabledProtocols = ProtocolList.getDefault(!flag);
}
useServerMode = !flag; useServerMode = !flag;
} }
@ -262,15 +272,12 @@ class SSLServerSocketImpl extends SSLServerSocket
return enableSessionCreation; return enableSessionCreation;
} }
/** /**
* Accept a new SSL connection. This server identifies itself with * Accept a new SSL connection. This server identifies itself with
* information provided in the authentication context which was * information provided in the authentication context which was
* presented during construction. * presented during construction.
*/ */
public Socket accept() throws IOException { public Socket accept() throws IOException {
checkEnabledSuites();
SSLSocketImpl s = new SSLSocketImpl(sslContext, useServerMode, SSLSocketImpl s = new SSLSocketImpl(sslContext, useServerMode,
enabledCipherSuites, doClientAuth, enableSessionCreation, enabledCipherSuites, doClientAuth, enableSessionCreation,
enabledProtocols); enabledProtocols);
@ -280,56 +287,6 @@ class SSLServerSocketImpl extends SSLServerSocket
return s; return s;
} }
/*
* This is a sometimes helpful diagnostic check that is performed
* once for each ServerSocket to verify that the initial set of
* enabled suites are capable of supporting a successful handshake.
*/
private void checkEnabledSuites() throws IOException {
//
// We want to report an error if no cipher suites were actually
// enabled, since this is an error users are known to make. Then
// they get vastly confused by having clients report an error!
//
synchronized (this) {
if (checkedEnabled) {
return;
}
if (useServerMode == false) {
return;
}
SSLSocketImpl tmp = new SSLSocketImpl(sslContext, useServerMode,
enabledCipherSuites, doClientAuth,
enableSessionCreation, enabledProtocols);
try {
ServerHandshaker handshaker = tmp.getServerHandshaker();
for (Iterator<CipherSuite> t = enabledCipherSuites.iterator();
t.hasNext();) {
CipherSuite suite = t.next();
if (handshaker.trySetCipherSuite(suite)) {
checkedEnabled = true;
return;
}
}
} finally {
tmp.closeSocket();
}
//
// diagnostic text here is currently appropriate
// since it's only certificate unavailability that can
// cause such problems ... but that might change someday.
//
throw new SSLException("No available certificate or key corresponds"
+ " to the SSL cipher suites which are enabled.");
}
}
/** /**
* Provides a brief description of this SSL socket. * Provides a brief description of this SSL socket.
*/ */

View file

@ -194,12 +194,14 @@ final public class SSLSocketImpl extends BaseSSLSocketImpl {
*/ */
private byte doClientAuth; private byte doClientAuth;
private boolean roleIsServer; private boolean roleIsServer;
private CipherSuiteList enabledCipherSuites;
private boolean enableSessionCreation = true; private boolean enableSessionCreation = true;
private String host; private String host;
private boolean autoClose = true; private boolean autoClose = true;
private AccessControlContext acc; private AccessControlContext acc;
// The cipher suites enabled for use on this connection.
private CipherSuiteList enabledCipherSuites;
// hostname identification algorithm, the hostname identification is // hostname identification algorithm, the hostname identification is
// disabled by default. // disabled by default.
private String identificationAlg = null; private String identificationAlg = null;
@ -341,11 +343,11 @@ final public class SSLSocketImpl extends BaseSSLSocketImpl {
private AppOutputStream output; private AppOutputStream output;
/* /*
* The protocols we support are SSL Version 3.0) and * The protocol versions enabled for use on this connection.
* TLS (version 3.1). *
* In addition we support a pseudo protocol called * Note: we support a pseudo protocol called SSLv2Hello which when
* SSLv2Hello which when set will result in an SSL v2 Hello * set will result in an SSL v2 Hello being sent with SSL (version 3.0)
* being sent with SSLv3 or TLSv1 version info. * or TLS (version 3.1, 3.2, etc.) version info.
*/ */
private ProtocolList enabledProtocols; private ProtocolList enabledProtocols;
@ -541,7 +543,7 @@ final public class SSLSocketImpl extends BaseSSLSocketImpl {
serverVerifyData = new byte[0]; serverVerifyData = new byte[0];
enabledCipherSuites = CipherSuiteList.getDefault(); enabledCipherSuites = CipherSuiteList.getDefault();
enabledProtocols = ProtocolList.getDefault(); enabledProtocols = ProtocolList.getDefault(roleIsServer);
inrec = null; inrec = null;
// save the acc // save the acc
@ -764,6 +766,21 @@ final public class SSLSocketImpl extends BaseSSLSocketImpl {
r.addMAC(writeMAC); r.addMAC(writeMAC);
r.encrypt(writeCipher); r.encrypt(writeCipher);
r.write(sockOutput); r.write(sockOutput);
/*
* Check the sequence number state
*
* Note that in order to maintain the connection I/O
* properly, we check the sequence number after the last
* record writing process. As we request renegotiation
* or close the connection for wrapped sequence number
* when there is enough sequence number space left to
* handle a few more records, so the sequence number
* of the last record cannot be wrapped.
*/
if (connectionState < cs_ERROR) {
checkSequenceNumber(writeMAC, r.contentType());
}
} }
@ -883,6 +900,7 @@ final public class SSLSocketImpl extends BaseSSLSocketImpl {
} }
} }
// if (!r.decompress(c)) // if (!r.decompress(c))
// fatal(Alerts.alert_decompression_failure, // fatal(Alerts.alert_decompression_failure,
// "decompression failure"); // "decompression failure");
@ -905,6 +923,15 @@ final public class SSLSocketImpl extends BaseSSLSocketImpl {
* in it. * in it.
*/ */
initHandshaker(); initHandshaker();
if (!handshaker.activated()) {
// prior to handshaking, activate the handshake
if (connectionState == cs_RENEGOTIATE) {
// don't use SSLv2Hello when renegotiating
handshaker.activate(protocolVersion);
} else {
handshaker.activate(null);
}
}
/* /*
* process the handshake record ... may contain just * process the handshake record ... may contain just
@ -949,9 +976,8 @@ final public class SSLSocketImpl extends BaseSSLSocketImpl {
if (needAppData || connectionState != cs_DATA) { if (needAppData || connectionState != cs_DATA) {
continue; continue;
} else {
return;
} }
break;
case Record.ct_application_data: case Record.ct_application_data:
// Pass this right back up to the application. // Pass this right back up to the application.
@ -971,7 +997,7 @@ final public class SSLSocketImpl extends BaseSSLSocketImpl {
} }
r.setAppDataValid(true); r.setAppDataValid(true);
return; break;
case Record.ct_alert: case Record.ct_alert:
recvAlert(r); recvAlert(r);
@ -1010,6 +1036,23 @@ final public class SSLSocketImpl extends BaseSSLSocketImpl {
} }
continue; continue;
} // switch } // switch
/*
* Check the sequence number state
*
* Note that in order to maintain the connection I/O
* properly, we check the sequence number after the last
* record reading process. As we request renegotiation
* or close the connection for wrapped sequence number
* when there is enough sequence number space left to
* handle a few more records, so the sequence number
* of the last record cannot be wrapped.
*/
if (connectionState < cs_ERROR) {
checkSequenceNumber(readMAC, r.contentType());
}
return;
} // synchronized (this) } // synchronized (this)
} }
@ -1021,6 +1064,61 @@ final public class SSLSocketImpl extends BaseSSLSocketImpl {
} // synchronized (readLock) } // synchronized (readLock)
} }
/**
* Check the sequence number state
*
* RFC 4346 states that, "Sequence numbers are of type uint64 and
* may not exceed 2^64-1. Sequence numbers do not wrap. If a TLS
* implementation would need to wrap a sequence number, it must
* renegotiate instead."
*/
private void checkSequenceNumber(MAC mac, byte type)
throws IOException {
/*
* Don't bother to check the sequence number for error or
* closed connections, or NULL MAC.
*/
if (connectionState >= cs_ERROR || mac == MAC.NULL) {
return;
}
/*
* Conservatively, close the connection immediately when the
* sequence number is close to overflow
*/
if (mac.seqNumOverflow()) {
/*
* TLS protocols do not define a error alert for sequence
* number overflow. We use handshake_failure error alert
* for handshaking and bad_record_mac for other records.
*/
if (debug != null && Debug.isOn("ssl")) {
System.out.println(threadName() +
", sequence number extremely close to overflow " +
"(2^64-1 packets). Closing connection.");
}
fatal(Alerts.alert_handshake_failure, "sequence number overflow");
}
/*
* Ask for renegotiation when need to renew sequence number.
*
* Don't bother to kickstart the renegotiation when the local is
* asking for it.
*/
if ((type != Record.ct_handshake) && mac.seqNumIsHuge()) {
if (debug != null && Debug.isOn("ssl")) {
System.out.println(threadName() + ", request renegotiation " +
"to avoid sequence number overflow");
}
startHandshake();
}
}
// //
// HANDSHAKE RELATED CODE // HANDSHAKE RELATED CODE
// //
@ -1033,28 +1131,10 @@ final public class SSLSocketImpl extends BaseSSLSocketImpl {
} }
/** /**
* Initialize and get the server handshaker. Used by SSLServerSocketImpl * Return the AppOutputStream. For use by Handshaker only.
* for the ciphersuite availability test *only*.
*/ */
ServerHandshaker getServerHandshaker() throws SSLException { AppOutputStream getAppOutputStream() {
initHandshaker(); return output;
// The connection state would have been set to cs_HANDSHAKE during the
// handshaking initializing, however the caller may not have the
// the low level connection's established, which is not consistent with
// the HANDSHAKE state. As if it is unconnected, we need to reset the
// connection state to cs_START.
if (!isConnected()) {
connectionState = cs_START;
}
// Make sure that we get a ServerHandshaker.
// This should never happen.
if (!(handshaker instanceof ServerHandshaker)) {
throw new SSLProtocolException("unexpected handshaker instance");
}
return (ServerHandshaker)handshaker;
} }
/** /**
@ -1066,8 +1146,8 @@ final public class SSLSocketImpl extends BaseSSLSocketImpl {
* . if the socket is already closed, throw an Exception (internal error) * . if the socket is already closed, throw an Exception (internal error)
* *
* . otherwise (cs_START or cs_DATA), create the appropriate handshaker * . otherwise (cs_START or cs_DATA), create the appropriate handshaker
* object, initialize it, and advance the connection state (to * object, and advance the connection state (to cs_HANDSHAKE or
* cs_HANDSHAKE or cs_RENEGOTIATE, respectively). * cs_RENEGOTIATE, respectively).
* *
* This method is called right after a new socket is created, when * This method is called right after a new socket is created, when
* starting renegotiation, or when changing client/ server mode of the * starting renegotiation, or when changing client/ server mode of the
@ -1115,12 +1195,8 @@ final public class SSLSocketImpl extends BaseSSLSocketImpl {
protocolVersion, connectionState == cs_HANDSHAKE, protocolVersion, connectionState == cs_HANDSHAKE,
secureRenegotiation, clientVerifyData, serverVerifyData); secureRenegotiation, clientVerifyData, serverVerifyData);
} }
handshaker.enabledCipherSuites = enabledCipherSuites; handshaker.setEnabledCipherSuites(enabledCipherSuites);
handshaker.setEnableSessionCreation(enableSessionCreation); handshaker.setEnableSessionCreation(enableSessionCreation);
if (connectionState == cs_RENEGOTIATE) {
// don't use SSLv2Hello when renegotiating
handshaker.output.r.setHelloVersion(protocolVersion);
}
} }
/** /**
@ -1135,6 +1211,8 @@ final public class SSLSocketImpl extends BaseSSLSocketImpl {
// one thread performs the handshake // one thread performs the handshake
synchronized (handshakeLock) { synchronized (handshakeLock) {
if (getConnectionState() == cs_HANDSHAKE) { if (getConnectionState() == cs_HANDSHAKE) {
kickstartHandshake();
/* /*
* All initial handshaking goes through this * All initial handshaking goes through this
* InputRecord until we have a valid SSL connection. * InputRecord until we have a valid SSL connection.
@ -1157,7 +1235,6 @@ final public class SSLSocketImpl extends BaseSSLSocketImpl {
inrec.enableFormatChecks(); inrec.enableFormatChecks();
} }
kickstartHandshake();
readRecord(inrec, false); readRecord(inrec, false);
inrec = null; inrec = null;
} }
@ -1211,6 +1288,7 @@ final public class SSLSocketImpl extends BaseSSLSocketImpl {
* on servers when renegotiating). * on servers when renegotiating).
*/ */
private synchronized void kickstartHandshake() throws IOException { private synchronized void kickstartHandshake() throws IOException {
switch (connectionState) { switch (connectionState) {
case cs_HANDSHAKE: case cs_HANDSHAKE:
@ -1257,7 +1335,15 @@ final public class SSLSocketImpl extends BaseSSLSocketImpl {
// to its HandshakeOutStream, which calls back into // to its HandshakeOutStream, which calls back into
// SSLSocketImpl.writeRecord() to send it. // SSLSocketImpl.writeRecord() to send it.
// //
if (!handshaker.started()) { if (!handshaker.activated()) {
// prior to handshaking, activate the handshake
if (connectionState == cs_RENEGOTIATE) {
// don't use SSLv2Hello when renegotiating
handshaker.activate(protocolVersion);
} else {
handshaker.activate(null);
}
if (handshaker instanceof ClientHandshaker) { if (handshaker instanceof ClientHandshaker) {
// send client hello // send client hello
handshaker.kickstart(); handshaker.kickstart();
@ -1752,10 +1838,18 @@ final public class SSLSocketImpl extends BaseSSLSocketImpl {
* Emit alerts. Caller must have synchronized with "this". * Emit alerts. Caller must have synchronized with "this".
*/ */
private void sendAlert(byte level, byte description) { private void sendAlert(byte level, byte description) {
// the connectionState cannot be cs_START
if (connectionState >= cs_SENT_CLOSE) { if (connectionState >= cs_SENT_CLOSE) {
return; return;
} }
// For initial handshaking, don't send alert message to peer if
// handshaker has not started.
if (connectionState == cs_HANDSHAKE &&
(handshaker == null || !handshaker.started())) {
return;
}
OutputRecord r = new OutputRecord(Record.ct_alert); OutputRecord r = new OutputRecord(Record.ct_alert);
r.setVersion(protocolVersion); r.setVersion(protocolVersion);
@ -1962,7 +2056,7 @@ final public class SSLSocketImpl extends BaseSSLSocketImpl {
synchronized public void setEnableSessionCreation(boolean flag) { synchronized public void setEnableSessionCreation(boolean flag) {
enableSessionCreation = flag; enableSessionCreation = flag;
if ((handshaker != null) && !handshaker.started()) { if ((handshaker != null) && !handshaker.activated()) {
handshaker.setEnableSessionCreation(enableSessionCreation); handshaker.setEnableSessionCreation(enableSessionCreation);
} }
} }
@ -1990,7 +2084,7 @@ final public class SSLSocketImpl extends BaseSSLSocketImpl {
if ((handshaker != null) && if ((handshaker != null) &&
(handshaker instanceof ServerHandshaker) && (handshaker instanceof ServerHandshaker) &&
!handshaker.started()) { !handshaker.activated()) {
((ServerHandshaker) handshaker).setClientAuth(doClientAuth); ((ServerHandshaker) handshaker).setClientAuth(doClientAuth);
} }
} }
@ -2013,7 +2107,7 @@ final public class SSLSocketImpl extends BaseSSLSocketImpl {
if ((handshaker != null) && if ((handshaker != null) &&
(handshaker instanceof ServerHandshaker) && (handshaker instanceof ServerHandshaker) &&
!handshaker.started()) { !handshaker.activated()) {
((ServerHandshaker) handshaker).setClientAuth(doClientAuth); ((ServerHandshaker) handshaker).setClientAuth(doClientAuth);
} }
} }
@ -2032,6 +2126,15 @@ final public class SSLSocketImpl extends BaseSSLSocketImpl {
switch (connectionState) { switch (connectionState) {
case cs_START: case cs_START:
/*
* If we need to change the socket mode and the enabled
* protocols haven't specifically been set by the user,
* change them to the corresponding default ones.
*/
if (roleIsServer != (!flag) &&
ProtocolList.isDefaultProtocolList(enabledProtocols)) {
enabledProtocols = ProtocolList.getDefault(!flag);
}
roleIsServer = !flag; roleIsServer = !flag;
break; break;
@ -2044,7 +2147,16 @@ final public class SSLSocketImpl extends BaseSSLSocketImpl {
* have the streams. * have the streams.
*/ */
assert(handshaker != null); assert(handshaker != null);
if (!handshaker.started()) { if (!handshaker.activated()) {
/*
* If we need to change the socket mode and the enabled
* protocols haven't specifically been set by the user,
* change them to the corresponding default ones.
*/
if (roleIsServer != (!flag) &&
ProtocolList.isDefaultProtocolList(enabledProtocols)) {
enabledProtocols = ProtocolList.getDefault(!flag);
}
roleIsServer = !flag; roleIsServer = !flag;
connectionState = cs_START; connectionState = cs_START;
initHandshaker(); initHandshaker();
@ -2095,8 +2207,8 @@ final public class SSLSocketImpl extends BaseSSLSocketImpl {
*/ */
synchronized public void setEnabledCipherSuites(String[] suites) { synchronized public void setEnabledCipherSuites(String[] suites) {
enabledCipherSuites = new CipherSuiteList(suites); enabledCipherSuites = new CipherSuiteList(suites);
if ((handshaker != null) && !handshaker.started()) { if ((handshaker != null) && !handshaker.activated()) {
handshaker.enabledCipherSuites = enabledCipherSuites; handshaker.setEnabledCipherSuites(enabledCipherSuites);
} }
} }
@ -2135,7 +2247,7 @@ final public class SSLSocketImpl extends BaseSSLSocketImpl {
*/ */
synchronized public void setEnabledProtocols(String[] protocols) { synchronized public void setEnabledProtocols(String[] protocols) {
enabledProtocols = new ProtocolList(protocols); enabledProtocols = new ProtocolList(protocols);
if ((handshaker != null) && !handshaker.started()) { if ((handshaker != null) && !handshaker.activated()) {
handshaker.setEnabledProtocols(enabledProtocols); handshaker.setEnabledProtocols(enabledProtocols);
} }
} }

View file

@ -185,8 +185,10 @@ final class ServerHandshaker extends Handshaker {
* temporary one used for non-export or signing-only * temporary one used for non-export or signing-only
* certificates/keys. * certificates/keys.
*/ */
RSAClientKeyExchange pms = new RSAClientKeyExchange RSAClientKeyExchange pms = new RSAClientKeyExchange(
(protocolVersion, input, message_len, privateKey); protocolVersion, clientRequestedVersion,
sslContext.getSecureRandom(), input,
message_len, privateKey);
preMasterSecret = this.clientKeyExchange(pms); preMasterSecret = this.clientKeyExchange(pms);
break; break;
case K_KRB5: case K_KRB5:
@ -408,21 +410,15 @@ final class ServerHandshaker extends Handshaker {
clientRequestedVersion = mesg.protocolVersion; clientRequestedVersion = mesg.protocolVersion;
// check if clientVersion is recent enough for us // select a proper protocol version.
if (clientRequestedVersion.v < enabledProtocols.min.v) { ProtocolVersion selectedVersion =
selectProtocolVersion(clientRequestedVersion);
if (selectedVersion == null ||
selectedVersion.v == ProtocolVersion.SSL20Hello.v) {
fatalSE(Alerts.alert_handshake_failure, fatalSE(Alerts.alert_handshake_failure,
"Client requested protocol " + clientRequestedVersion + "Client requested protocol " + clientRequestedVersion +
" not enabled or not supported"); " not enabled or not supported");
} }
// now we know we have an acceptable version
// use the lower of our max and the client requested version
ProtocolVersion selectedVersion;
if (clientRequestedVersion.v <= enabledProtocols.max.v) {
selectedVersion = clientRequestedVersion;
} else {
selectedVersion = enabledProtocols.max;
}
setVersion(selectedVersion); setVersion(selectedVersion);
m1.protocolVersion = protocolVersion; m1.protocolVersion = protocolVersion;
@ -813,8 +809,7 @@ final class ServerHandshaker extends Handshaker {
* method should only be called if you really want to use the * method should only be called if you really want to use the
* CipherSuite. * CipherSuite.
* *
* This method is called from chooseCipherSuite() in this class * This method is called from chooseCipherSuite() in this class.
* and SSLServerSocketImpl.checkEnabledSuites() (as a sanity check).
*/ */
boolean trySetCipherSuite(CipherSuite suite) { boolean trySetCipherSuite(CipherSuite suite) {
/* /*
@ -831,6 +826,11 @@ final class ServerHandshaker extends Handshaker {
return false; return false;
} }
// TLSv1.1 must not negotiate the exportable weak cipher suites.
if (protocolVersion.v >= suite.obsoleted) {
return false;
}
KeyExchange keyExchange = suite.keyExchange; KeyExchange keyExchange = suite.keyExchange;
// null out any existing references // null out any existing references

View file

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 1999, 2007, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
@ -38,7 +38,7 @@ import java.security.*;
* *
* SunJSSE now supports an experimental FIPS compliant mode when used with an * SunJSSE now supports an experimental FIPS compliant mode when used with an
* appropriate FIPS certified crypto provider. In FIPS mode, we: * appropriate FIPS certified crypto provider. In FIPS mode, we:
* . allow only TLS 1.0 * . allow only TLS 1.0 or later
* . allow only FIPS approved ciphersuites * . allow only FIPS approved ciphersuites
* . perform all crypto in the FIPS crypto provider * . perform all crypto in the FIPS crypto provider
* *
@ -211,6 +211,8 @@ public abstract class SunJSSE extends java.security.Provider {
"sun.security.ssl.SSLContextImpl"); "sun.security.ssl.SSLContextImpl");
put("SSLContext.TLSv1", put("SSLContext.TLSv1",
"sun.security.ssl.SSLContextImpl"); "sun.security.ssl.SSLContextImpl");
put("SSLContext.TLSv1.1",
"sun.security.ssl.SSLContextImpl");
put("SSLContext.Default", put("SSLContext.Default",
"sun.security.ssl.DefaultSSLContextImpl"); "sun.security.ssl.DefaultSSLContextImpl");

View file

@ -244,7 +244,7 @@ public final class KerberosClientKeyExchangeImpl
clientVersion, rand, input, sessionKey); clientVersion, rand, input, sessionKey);
} else { } else {
// Generate bogus premaster secret // Generate bogus premaster secret
preMaster = new KerberosPreMasterSecret(protocolVersion, rand); preMaster = new KerberosPreMasterSecret(clientVersion, rand);
} }
} }

View file

@ -176,13 +176,21 @@ final class KerberosPreMasterSecret {
// check if the premaster secret version is ok // check if the premaster secret version is ok
// the specification says that it must be the maximum version supported // the specification says that it must be the maximum version supported
// by the client from its ClientHello message. However, many // by the client from its ClientHello message. However, many
// implementations send the negotiated version, so accept both // old implementations send the negotiated version, so accept both
// for SSL v3.0 and TLS v1.0.
// NOTE that we may be comparing two unsupported version numbers in // NOTE that we may be comparing two unsupported version numbers in
// the second case, which is why we cannot use object references // the second case, which is why we cannot use object references
// equality in this special case // equality in this special case
boolean versionMismatch = (protocolVersion != currentVersion) && boolean versionMismatch = (protocolVersion.v != clientVersion.v);
(protocolVersion.v != clientVersion.v);
/*
* we never checked the client_version in server side
* for TLS v1.0 and SSL v3.0. For compatibility, we
* maintain this behavior.
*/
if (versionMismatch && (clientVersion.v <= 0x0301)) {
versionMismatch = (protocolVersion.v != currentVersion.v);
}
/* /*
* Bogus decrypted ClientKeyExchange? If so, conjure a * Bogus decrypted ClientKeyExchange? If so, conjure a
@ -203,8 +211,14 @@ final class KerberosPreMasterSecret {
Debug.println(System.out, "Invalid secret", preMaster); Debug.println(System.out, "Invalid secret", preMaster);
} }
} }
preMaster = generatePreMaster(generator, currentVersion);
protocolVersion = currentVersion; /*
* Randomize the preMaster secret with the
* ClientHello.client_version, as will produce invalid master
* secret to prevent the attacks.
*/
preMaster = generatePreMaster(generator, clientVersion);
protocolVersion = clientVersion;
} }
} }

View file

@ -119,6 +119,13 @@ public class CipherTest {
return false; return false;
} }
// ignore exportable cipher suite for TLSv1.1
if (protocol.equals("TLSv1.1")) {
if(cipherSuite.indexOf("_EXPORT_") != -1) {
return false;
}
}
return true; return true;
} }
@ -149,18 +156,14 @@ public class CipherTest {
cipherSuites.length * protocols.length * clientAuths.length); cipherSuites.length * protocols.length * clientAuths.length);
for (int i = 0; i < cipherSuites.length; i++) { for (int i = 0; i < cipherSuites.length; i++) {
String cipherSuite = cipherSuites[i]; String cipherSuite = cipherSuites[i];
if (peerFactory.isSupported(cipherSuite) == false) {
continue;
}
// skip kerberos cipher suites
if (cipherSuite.startsWith("TLS_KRB5")) {
continue;
}
for (int j = 0; j < protocols.length; j++) { for (int j = 0; j < protocols.length; j++) {
String protocol = protocols[j]; String protocol = protocols[j];
if (protocol.equals("SSLv2Hello")) {
if (!peerFactory.isSupported(cipherSuite, protocol)) {
continue; continue;
} }
for (int k = 0; k < clientAuths.length; k++) { for (int k = 0; k < clientAuths.length; k++) {
String clientAuth = clientAuths[k]; String clientAuth = clientAuths[k];
if ((clientAuth != null) && if ((clientAuth != null) &&
@ -293,11 +296,12 @@ public class CipherTest {
return ks; return ks;
} }
public static void main(PeerFactory peerFactory, KeyStore keyStore, String[] args) public static void main(PeerFactory peerFactory, KeyStore keyStore,
throws Exception { String[] args) throws Exception {
long time = System.currentTimeMillis(); long time = System.currentTimeMillis();
String relPath; String relPath;
if ((args.length > 0) && args[0].equals("sh")) { if ((args != null) && (args.length > 0) && args[0].equals("sh")) {
relPath = pathToStoresSH; relPath = pathToStoresSH;
} else { } else {
relPath = pathToStores; relPath = pathToStores;
@ -345,7 +349,30 @@ public class CipherTest {
abstract Server newServer(CipherTest cipherTest) throws Exception; abstract Server newServer(CipherTest cipherTest) throws Exception;
boolean isSupported(String cipherSuite) { boolean isSupported(String cipherSuite, String protocol) {
// skip kerberos cipher suites
if (cipherSuite.startsWith("TLS_KRB5")) {
System.out.println("Skipping unsupported test for " +
cipherSuite + " of " + protocol);
return false;
}
// skip SSLv2Hello protocol
if (protocol.equals("SSLv2Hello")) {
System.out.println("Skipping unsupported test for " +
cipherSuite + " of " + protocol);
return false;
}
// ignore exportable cipher suite for TLSv1.1
if (protocol.equals("TLSv1.1")) {
if (cipherSuite.indexOf("_EXPORT_WITH") != -1) {
System.out.println("Skipping obsoleted test for " +
cipherSuite + " of " + protocol);
return false;
}
}
return true; return true;
} }
} }

View file

@ -119,6 +119,13 @@ public class CipherTest {
return false; return false;
} }
// ignore exportable cipher suite for TLSv1.1
if (protocol.equals("TLSv1.1")) {
if(cipherSuite.indexOf("_EXPORT_") != -1) {
return false;
}
}
return true; return true;
} }
@ -148,18 +155,14 @@ public class CipherTest {
cipherSuites.length * protocols.length * clientAuths.length); cipherSuites.length * protocols.length * clientAuths.length);
for (int i = 0; i < cipherSuites.length; i++) { for (int i = 0; i < cipherSuites.length; i++) {
String cipherSuite = cipherSuites[i]; String cipherSuite = cipherSuites[i];
if (peerFactory.isSupported(cipherSuite) == false) {
continue;
}
// skip kerberos cipher suites
if (cipherSuite.startsWith("TLS_KRB5")) {
continue;
}
for (int j = 0; j < protocols.length; j++) { for (int j = 0; j < protocols.length; j++) {
String protocol = protocols[j]; String protocol = protocols[j];
if (protocol.equals("SSLv2Hello")) {
if (!peerFactory.isSupported(cipherSuite, protocol)) {
continue; continue;
} }
for (int k = 0; k < clientAuths.length; k++) { for (int k = 0; k < clientAuths.length; k++) {
String clientAuth = clientAuths[k]; String clientAuth = clientAuths[k];
if ((clientAuth != null) && if ((clientAuth != null) &&
@ -275,7 +278,6 @@ public class CipherTest {
// for some reason, ${test.src} has a different value when the // for some reason, ${test.src} has a different value when the
// test is called from the script and when it is called directly... // test is called from the script and when it is called directly...
// static String pathToStores = "../../etc";
static String pathToStores = "."; static String pathToStores = ".";
static String pathToStoresSH = "."; static String pathToStoresSH = ".";
static String keyStoreFile = "keystore"; static String keyStoreFile = "keystore";
@ -336,7 +338,30 @@ public class CipherTest {
abstract Server newServer(CipherTest cipherTest) throws Exception; abstract Server newServer(CipherTest cipherTest) throws Exception;
boolean isSupported(String cipherSuite) { boolean isSupported(String cipherSuite, String protocol) {
// skip kerberos cipher suites
if (cipherSuite.startsWith("TLS_KRB5")) {
System.out.println("Skipping unsupported test for " +
cipherSuite + " of " + protocol);
return false;
}
// skip SSLv2Hello protocol
if (protocol.equals("SSLv2Hello")) {
System.out.println("Skipping unsupported test for " +
cipherSuite + " of " + protocol);
return false;
}
// ignore exportable cipher suite for TLSv1.1
if (protocol.equals("TLSv1.1")) {
if (cipherSuite.indexOf("_EXPORT_WITH") != -1) {
System.out.println("Skipping obsoleted test for " +
cipherSuite + " of " + protocol);
return false;
}
}
return true; return true;
} }
} }

View file

@ -0,0 +1,371 @@
/*
* Copyright (c) 2010, 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.
*/
/*
* @test
* @bug 4873188
* @summary Support TLS 1.1
* @run main/othervm -Djavax.net.debug=all EmptyCertificateAuthorities
*
* @author Xuelei Fan
*/
import java.io.*;
import java.net.*;
import java.security.*;
import java.security.cert.*;
import javax.net.ssl.*;
public class EmptyCertificateAuthorities {
/*
* =============================================================
* Set the various variables needed for the tests, then
* specify what tests to run on each side.
*/
/*
* Should we run the client or server in a separate thread?
* Both sides can throw exceptions, but do you have a preference
* as to which side should be the main thread.
*/
static boolean separateServerThread = false;
/*
* Where do we find the keystores?
*/
static String pathToStores = "/../../../../etc";
static String keyStoreFile = "keystore";
static String trustStoreFile = "truststore";
static String passwd = "passphrase";
/*
* Is the server ready to serve?
*/
volatile static boolean serverReady = false;
/*
* Turn on SSL debugging?
*/
static boolean debug = false;
/*
* If the client or server is doing some kind of object creation
* that the other side depends on, and that thread prematurely
* exits, you may experience a hang. The test harness will
* terminate all hung threads after its timeout has expired,
* currently 3 minutes by default, but you might try to be
* smart about it....
*/
/*
* Define the server side of the test.
*
* If the server prematurely exits, serverReady will be set to true
* to avoid infinite hangs.
*/
void doServerSide() throws Exception {
SSLServerSocketFactory sslssf = getSSLServerSF();
SSLServerSocket sslServerSocket =
(SSLServerSocket) sslssf.createServerSocket(serverPort);
// require client authentication.
sslServerSocket.setNeedClientAuth(true);
serverPort = sslServerSocket.getLocalPort();
/*
* Signal Client, we're ready for his connect.
*/
serverReady = true;
SSLSocket sslSocket = (SSLSocket) sslServerSocket.accept();
InputStream sslIS = sslSocket.getInputStream();
OutputStream sslOS = sslSocket.getOutputStream();
sslIS.read();
sslOS.write('A');
sslOS.flush();
sslSocket.close();
}
/*
* Define the client side of the test.
*
* If the server prematurely exits, serverReady will be set to true
* to avoid infinite hangs.
*/
void doClientSide() throws Exception {
/*
* Wait for server to get started.
*/
while (!serverReady) {
Thread.sleep(50);
}
SSLSocketFactory sslsf =
(SSLSocketFactory) SSLSocketFactory.getDefault();
SSLSocket sslSocket = (SSLSocket)
sslsf.createSocket("localhost", serverPort);
// enable TLSv1.1 only
sslSocket.setEnabledProtocols(new String[] {"TLSv1.1"});
InputStream sslIS = sslSocket.getInputStream();
OutputStream sslOS = sslSocket.getOutputStream();
sslOS.write('B');
sslOS.flush();
sslIS.read();
sslSocket.close();
}
private SSLServerSocketFactory getSSLServerSF() throws Exception {
char [] password =
System.getProperty("javax.net.ssl.keyStorePassword").toCharArray();
String keyFilename = System.getProperty("javax.net.ssl.keyStore");
KeyStore ks = KeyStore.getInstance("JKS");
ks.load(new FileInputStream(keyFilename), password);
KeyManagerFactory kmf = KeyManagerFactory.getInstance("NewSunX509");
kmf.init(ks, password);
KeyManager[] kms = kmf.getKeyManagers();
TrustManager[] tms = new MyX509TM[] {new MyX509TM()};
SSLContext ctx = SSLContext.getInstance("TLS");
ctx.init(kms, tms, null);
return ctx.getServerSocketFactory();
}
static class MyX509TM implements X509TrustManager {
X509TrustManager tm;
public void checkClientTrusted(X509Certificate[] chain,
String authType) throws CertificateException {
if (tm == null) {
initialize();
}
tm.checkClientTrusted(chain, authType);
}
public void checkServerTrusted(X509Certificate[] chain,
String authType) throws CertificateException {
if (tm == null) {
initialize();
}
tm.checkServerTrusted(chain, authType);
}
public X509Certificate[] getAcceptedIssuers() {
// always return empty array
return new X509Certificate[0];
}
private void initialize() throws CertificateException {
String passwd =
System.getProperty("javax.net.ssl.trustStorePassword");
char [] password = passwd.toCharArray();
String trustFilename =
System.getProperty("javax.net.ssl.trustStore");
try {
KeyStore ks = KeyStore.getInstance("JKS");
ks.load(new FileInputStream(trustFilename), password);
TrustManagerFactory tmf =
TrustManagerFactory.getInstance("PKIX");
tmf.init(ks);
tm = (X509TrustManager)tmf.getTrustManagers()[0];
} catch (Exception e) {
throw new CertificateException("Unable to initialize TM");
}
}
}
/*
* =============================================================
* The remainder is just support stuff
*/
// use any free port by default
volatile int serverPort = 0;
volatile Exception serverException = null;
volatile Exception clientException = null;
public static void main(String[] args) throws Exception {
String keyFilename =
System.getProperty("test.src", ".") + "/" + pathToStores +
"/" + keyStoreFile;
String trustFilename =
System.getProperty("test.src", ".") + "/" + pathToStores +
"/" + trustStoreFile;
System.setProperty("javax.net.ssl.keyStore", keyFilename);
System.setProperty("javax.net.ssl.keyStorePassword", passwd);
System.setProperty("javax.net.ssl.trustStore", trustFilename);
System.setProperty("javax.net.ssl.trustStorePassword", passwd);
if (debug)
System.setProperty("javax.net.debug", "all");
/*
* Start the tests.
*/
new EmptyCertificateAuthorities();
}
Thread clientThread = null;
Thread serverThread = null;
/*
* Primary constructor, used to drive remainder of the test.
*
* Fork off the other side, then do your work.
*/
EmptyCertificateAuthorities() throws Exception {
try {
if (separateServerThread) {
startServer(true);
startClient(false);
} else {
startClient(true);
startServer(false);
}
} catch (Exception e) {
// swallow for now. Show later
}
/*
* Wait for other side to close down.
*/
if (separateServerThread) {
serverThread.join();
} else {
clientThread.join();
}
/*
* When we get here, the test is pretty much over.
* Which side threw the error?
*/
Exception local;
Exception remote;
String whichRemote;
if (separateServerThread) {
remote = serverException;
local = clientException;
whichRemote = "server";
} else {
remote = clientException;
local = serverException;
whichRemote = "client";
}
/*
* If both failed, return the curthread's exception, but also
* print the remote side Exception
*/
if ((local != null) && (remote != null)) {
System.out.println(whichRemote + " also threw:");
remote.printStackTrace();
System.out.println();
throw local;
}
if (remote != null) {
throw remote;
}
if (local != null) {
throw local;
}
}
void startServer(boolean newThread) throws Exception {
if (newThread) {
serverThread = new Thread() {
public void run() {
try {
doServerSide();
} catch (Exception e) {
/*
* Our server thread just died.
*
* Release the client, if not active already...
*/
System.err.println("Server died...");
serverReady = true;
serverException = e;
}
}
};
serverThread.start();
} else {
try {
doServerSide();
} catch (Exception e) {
serverException = e;
} finally {
serverReady = true;
}
}
}
void startClient(boolean newThread) throws Exception {
if (newThread) {
clientThread = new Thread() {
public void run() {
try {
doClientSide();
} catch (Exception e) {
/*
* Our client thread just died.
*/
System.err.println("Client died...");
clientException = e;
}
}
};
clientThread.start();
} else {
try {
doClientSide();
} catch (Exception e) {
clientException = e;
}
}
}
}

View file

@ -0,0 +1,327 @@
/*
* Copyright (c) 2010, 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.
*/
/*
* @test
* @bug 4873188
* @summary Support TLS 1.1
* @run main/othervm -Djavax.net.debug=all ExportableBlockCipher
*
* @author Xuelei Fan
*/
import java.io.*;
import java.net.*;
import javax.net.ssl.*;
public class ExportableBlockCipher {
/*
* =============================================================
* Set the various variables needed for the tests, then
* specify what tests to run on each side.
*/
/*
* Should we run the client or server in a separate thread?
* Both sides can throw exceptions, but do you have a preference
* as to which side should be the main thread.
*/
static boolean separateServerThread = false;
/*
* Where do we find the keystores?
*/
static String pathToStores = "/../../../../etc";
static String keyStoreFile = "keystore";
static String trustStoreFile = "truststore";
static String passwd = "passphrase";
/*
* Is the server ready to serve?
*/
volatile static boolean serverReady = false;
/*
* Turn on SSL debugging?
*/
static boolean debug = false;
/*
* If the client or server is doing some kind of object creation
* that the other side depends on, and that thread prematurely
* exits, you may experience a hang. The test harness will
* terminate all hung threads after its timeout has expired,
* currently 3 minutes by default, but you might try to be
* smart about it....
*/
/*
* Define the server side of the test.
*
* If the server prematurely exits, serverReady will be set to true
* to avoid infinite hangs.
*/
void doServerSide() throws Exception {
SSLServerSocketFactory sslssf =
(SSLServerSocketFactory) SSLServerSocketFactory.getDefault();
SSLServerSocket sslServerSocket =
(SSLServerSocket) sslssf.createServerSocket(serverPort);
serverPort = sslServerSocket.getLocalPort();
/*
* Signal Client, we're ready for his connect.
*/
serverReady = true;
SSLSocket sslSocket = (SSLSocket) sslServerSocket.accept();
InputStream sslIS = sslSocket.getInputStream();
OutputStream sslOS = sslSocket.getOutputStream();
boolean interrupted = false;
try {
sslIS.read();
sslOS.write('A');
sslOS.flush();
} catch (SSLException ssle) {
// get the expected exception
interrupted = true;
} finally {
sslSocket.close();
}
if (!interrupted) {
throw new SSLHandshakeException(
"A weak cipher suite is negotiated, " +
"TLSv1.1 must not negotiate the exportable cipher suites.");
}
}
/*
* Define the client side of the test.
*
* If the server prematurely exits, serverReady will be set to true
* to avoid infinite hangs.
*/
void doClientSide() throws Exception {
/*
* Wait for server to get started.
*/
while (!serverReady) {
Thread.sleep(50);
}
SSLSocketFactory sslsf =
(SSLSocketFactory) SSLSocketFactory.getDefault();
SSLSocket sslSocket = (SSLSocket)
sslsf.createSocket("localhost", serverPort);
// enable TLSv1.1 only
sslSocket.setEnabledProtocols(new String[] {"TLSv1.1"});
// enable a exportable block cipher
sslSocket.setEnabledCipherSuites(
new String[] {"SSL_RSA_EXPORT_WITH_DES40_CBC_SHA"});
InputStream sslIS = sslSocket.getInputStream();
OutputStream sslOS = sslSocket.getOutputStream();
boolean interrupted = false;
try {
sslOS.write('B');
sslOS.flush();
sslIS.read();
} catch (SSLException ssle) {
// get the expected exception
interrupted = true;
} finally {
sslSocket.close();
}
if (!interrupted) {
throw new SSLHandshakeException(
"A weak cipher suite is negotiated, " +
"TLSv1.1 must not negotiate the exportable cipher suites.");
}
}
/*
* =============================================================
* The remainder is just support stuff
*/
// use any free port by default
volatile int serverPort = 0;
volatile Exception serverException = null;
volatile Exception clientException = null;
public static void main(String[] args) throws Exception {
String keyFilename =
System.getProperty("test.src", ".") + "/" + pathToStores +
"/" + keyStoreFile;
String trustFilename =
System.getProperty("test.src", ".") + "/" + pathToStores +
"/" + trustStoreFile;
System.setProperty("javax.net.ssl.keyStore", keyFilename);
System.setProperty("javax.net.ssl.keyStorePassword", passwd);
System.setProperty("javax.net.ssl.trustStore", trustFilename);
System.setProperty("javax.net.ssl.trustStorePassword", passwd);
if (debug)
System.setProperty("javax.net.debug", "all");
/*
* Start the tests.
*/
new ExportableBlockCipher();
}
Thread clientThread = null;
Thread serverThread = null;
/*
* Primary constructor, used to drive remainder of the test.
*
* Fork off the other side, then do your work.
*/
ExportableBlockCipher() throws Exception {
try {
if (separateServerThread) {
startServer(true);
startClient(false);
} else {
startClient(true);
startServer(false);
}
} catch (Exception e) {
// swallow for now. Show later
}
/*
* Wait for other side to close down.
*/
if (separateServerThread) {
serverThread.join();
} else {
clientThread.join();
}
/*
* When we get here, the test is pretty much over.
* Which side threw the error?
*/
Exception local;
Exception remote;
String whichRemote;
if (separateServerThread) {
remote = serverException;
local = clientException;
whichRemote = "server";
} else {
remote = clientException;
local = serverException;
whichRemote = "client";
}
/*
* If both failed, return the curthread's exception, but also
* print the remote side Exception
*/
if ((local != null) && (remote != null)) {
System.out.println(whichRemote + " also threw:");
remote.printStackTrace();
System.out.println();
throw local;
}
if (remote != null) {
throw remote;
}
if (local != null) {
throw local;
}
}
void startServer(boolean newThread) throws Exception {
if (newThread) {
serverThread = new Thread() {
public void run() {
try {
doServerSide();
} catch (Exception e) {
/*
* Our server thread just died.
*
* Release the client, if not active already...
*/
System.err.println("Server died...");
serverReady = true;
serverException = e;
}
}
};
serverThread.start();
} else {
try {
doServerSide();
} catch (Exception e) {
serverException = e;
} finally {
serverReady = true;
}
}
}
void startClient(boolean newThread) throws Exception {
if (newThread) {
clientThread = new Thread() {
public void run() {
try {
doClientSide();
} catch (Exception e) {
/*
* Our client thread just died.
*/
System.err.println("Client died...");
clientException = e;
}
}
};
clientThread.start();
} else {
try {
doClientSide();
} catch (Exception e) {
clientException = e;
}
}
}
}

View file

@ -0,0 +1,327 @@
/*
* Copyright (c) 2010, 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.
*/
/*
* @test
* @bug 4873188
* @summary Support TLS 1.1
* @run main/othervm -Djavax.net.debug=all ExportableStreamCipher
*
* @author Xuelei Fan
*/
import java.io.*;
import java.net.*;
import javax.net.ssl.*;
public class ExportableStreamCipher {
/*
* =============================================================
* Set the various variables needed for the tests, then
* specify what tests to run on each side.
*/
/*
* Should we run the client or server in a separate thread?
* Both sides can throw exceptions, but do you have a preference
* as to which side should be the main thread.
*/
static boolean separateServerThread = false;
/*
* Where do we find the keystores?
*/
static String pathToStores = "/../../../../etc";
static String keyStoreFile = "keystore";
static String trustStoreFile = "truststore";
static String passwd = "passphrase";
/*
* Is the server ready to serve?
*/
volatile static boolean serverReady = false;
/*
* Turn on SSL debugging?
*/
static boolean debug = false;
/*
* If the client or server is doing some kind of object creation
* that the other side depends on, and that thread prematurely
* exits, you may experience a hang. The test harness will
* terminate all hung threads after its timeout has expired,
* currently 3 minutes by default, but you might try to be
* smart about it....
*/
/*
* Define the server side of the test.
*
* If the server prematurely exits, serverReady will be set to true
* to avoid infinite hangs.
*/
void doServerSide() throws Exception {
SSLServerSocketFactory sslssf =
(SSLServerSocketFactory) SSLServerSocketFactory.getDefault();
SSLServerSocket sslServerSocket =
(SSLServerSocket) sslssf.createServerSocket(serverPort);
serverPort = sslServerSocket.getLocalPort();
/*
* Signal Client, we're ready for his connect.
*/
serverReady = true;
SSLSocket sslSocket = (SSLSocket) sslServerSocket.accept();
InputStream sslIS = sslSocket.getInputStream();
OutputStream sslOS = sslSocket.getOutputStream();
boolean interrupted = false;
try {
sslIS.read();
sslOS.write('A');
sslOS.flush();
} catch (SSLException ssle) {
// get the expected exception
interrupted = true;
} finally {
sslSocket.close();
}
if (!interrupted) {
throw new SSLHandshakeException(
"A weak cipher suite is negotiated, " +
"TLSv1.1 must not negotiate the exportable cipher suites.");
}
}
/*
* Define the client side of the test.
*
* If the server prematurely exits, serverReady will be set to true
* to avoid infinite hangs.
*/
void doClientSide() throws Exception {
/*
* Wait for server to get started.
*/
while (!serverReady) {
Thread.sleep(50);
}
SSLSocketFactory sslsf =
(SSLSocketFactory) SSLSocketFactory.getDefault();
SSLSocket sslSocket = (SSLSocket)
sslsf.createSocket("localhost", serverPort);
// enable TLSv1.1 only
sslSocket.setEnabledProtocols(new String[] {"TLSv1.1"});
// enable a exportable stream cipher
sslSocket.setEnabledCipherSuites(
new String[] {"SSL_RSA_EXPORT_WITH_RC4_40_MD5"});
InputStream sslIS = sslSocket.getInputStream();
OutputStream sslOS = sslSocket.getOutputStream();
boolean interrupted = false;
try {
sslOS.write('B');
sslOS.flush();
sslIS.read();
} catch (SSLException ssle) {
// get the expected exception
interrupted = true;
} finally {
sslSocket.close();
}
if (!interrupted) {
throw new SSLHandshakeException(
"A weak cipher suite is negotiated, " +
"TLSv1.1 must not negotiate the exportable cipher suites.");
}
}
/*
* =============================================================
* The remainder is just support stuff
*/
// use any free port by default
volatile int serverPort = 0;
volatile Exception serverException = null;
volatile Exception clientException = null;
public static void main(String[] args) throws Exception {
String keyFilename =
System.getProperty("test.src", ".") + "/" + pathToStores +
"/" + keyStoreFile;
String trustFilename =
System.getProperty("test.src", ".") + "/" + pathToStores +
"/" + trustStoreFile;
System.setProperty("javax.net.ssl.keyStore", keyFilename);
System.setProperty("javax.net.ssl.keyStorePassword", passwd);
System.setProperty("javax.net.ssl.trustStore", trustFilename);
System.setProperty("javax.net.ssl.trustStorePassword", passwd);
if (debug)
System.setProperty("javax.net.debug", "all");
/*
* Start the tests.
*/
new ExportableStreamCipher();
}
Thread clientThread = null;
Thread serverThread = null;
/*
* Primary constructor, used to drive remainder of the test.
*
* Fork off the other side, then do your work.
*/
ExportableStreamCipher() throws Exception {
try {
if (separateServerThread) {
startServer(true);
startClient(false);
} else {
startClient(true);
startServer(false);
}
} catch (Exception e) {
// swallow for now. Show later
}
/*
* Wait for other side to close down.
*/
if (separateServerThread) {
serverThread.join();
} else {
clientThread.join();
}
/*
* When we get here, the test is pretty much over.
* Which side threw the error?
*/
Exception local;
Exception remote;
String whichRemote;
if (separateServerThread) {
remote = serverException;
local = clientException;
whichRemote = "server";
} else {
remote = clientException;
local = serverException;
whichRemote = "client";
}
/*
* If both failed, return the curthread's exception, but also
* print the remote side Exception
*/
if ((local != null) && (remote != null)) {
System.out.println(whichRemote + " also threw:");
remote.printStackTrace();
System.out.println();
throw local;
}
if (remote != null) {
throw remote;
}
if (local != null) {
throw local;
}
}
void startServer(boolean newThread) throws Exception {
if (newThread) {
serverThread = new Thread() {
public void run() {
try {
doServerSide();
} catch (Exception e) {
/*
* Our server thread just died.
*
* Release the client, if not active already...
*/
System.err.println("Server died...");
serverReady = true;
serverException = e;
}
}
};
serverThread.start();
} else {
try {
doServerSide();
} catch (Exception e) {
serverException = e;
} finally {
serverReady = true;
}
}
}
void startClient(boolean newThread) throws Exception {
if (newThread) {
clientThread = new Thread() {
public void run() {
try {
doClientSide();
} catch (Exception e) {
/*
* Our client thread just died.
*/
System.err.println("Client died...");
clientException = e;
}
}
};
clientThread.start();
} else {
try {
doClientSide();
} catch (Exception e) {
clientException = e;
}
}
}
}

View file

@ -0,0 +1,303 @@
/*
* Copyright (c) 2010, 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.
*/
/*
* @test
* @bug 4873188
* @summary Support TLS 1.1
* @run main/othervm -Djavax.net.debug=all GenericBlockCipher
*
* @author Xuelei Fan
*/
import java.io.*;
import java.net.*;
import javax.net.ssl.*;
public class GenericBlockCipher {
/*
* =============================================================
* Set the various variables needed for the tests, then
* specify what tests to run on each side.
*/
/*
* Should we run the client or server in a separate thread?
* Both sides can throw exceptions, but do you have a preference
* as to which side should be the main thread.
*/
static boolean separateServerThread = false;
/*
* Where do we find the keystores?
*/
static String pathToStores = "/../../../../etc";
static String keyStoreFile = "keystore";
static String trustStoreFile = "truststore";
static String passwd = "passphrase";
/*
* Is the server ready to serve?
*/
volatile static boolean serverReady = false;
/*
* Turn on SSL debugging?
*/
static boolean debug = false;
/*
* If the client or server is doing some kind of object creation
* that the other side depends on, and that thread prematurely
* exits, you may experience a hang. The test harness will
* terminate all hung threads after its timeout has expired,
* currently 3 minutes by default, but you might try to be
* smart about it....
*/
/*
* Define the server side of the test.
*
* If the server prematurely exits, serverReady will be set to true
* to avoid infinite hangs.
*/
void doServerSide() throws Exception {
SSLServerSocketFactory sslssf =
(SSLServerSocketFactory) SSLServerSocketFactory.getDefault();
SSLServerSocket sslServerSocket =
(SSLServerSocket) sslssf.createServerSocket(serverPort);
serverPort = sslServerSocket.getLocalPort();
/*
* Signal Client, we're ready for his connect.
*/
serverReady = true;
SSLSocket sslSocket = (SSLSocket) sslServerSocket.accept();
InputStream sslIS = sslSocket.getInputStream();
OutputStream sslOS = sslSocket.getOutputStream();
sslIS.read();
sslOS.write('A');
sslOS.flush();
sslSocket.close();
}
/*
* Define the client side of the test.
*
* If the server prematurely exits, serverReady will be set to true
* to avoid infinite hangs.
*/
void doClientSide() throws Exception {
/*
* Wait for server to get started.
*/
while (!serverReady) {
Thread.sleep(50);
}
SSLSocketFactory sslsf =
(SSLSocketFactory) SSLSocketFactory.getDefault();
SSLSocket sslSocket = (SSLSocket)
sslsf.createSocket("localhost", serverPort);
// enable TLSv1.1 only
sslSocket.setEnabledProtocols(new String[] {"TLSv1.1"});
// enable a block cipher
sslSocket.setEnabledCipherSuites(
new String[] {"TLS_RSA_WITH_AES_128_CBC_SHA"});
InputStream sslIS = sslSocket.getInputStream();
OutputStream sslOS = sslSocket.getOutputStream();
sslOS.write('B');
sslOS.flush();
sslIS.read();
sslSocket.close();
}
/*
* =============================================================
* The remainder is just support stuff
*/
// use any free port by default
volatile int serverPort = 0;
volatile Exception serverException = null;
volatile Exception clientException = null;
public static void main(String[] args) throws Exception {
String keyFilename =
System.getProperty("test.src", ".") + "/" + pathToStores +
"/" + keyStoreFile;
String trustFilename =
System.getProperty("test.src", ".") + "/" + pathToStores +
"/" + trustStoreFile;
System.setProperty("javax.net.ssl.keyStore", keyFilename);
System.setProperty("javax.net.ssl.keyStorePassword", passwd);
System.setProperty("javax.net.ssl.trustStore", trustFilename);
System.setProperty("javax.net.ssl.trustStorePassword", passwd);
if (debug)
System.setProperty("javax.net.debug", "all");
/*
* Start the tests.
*/
new GenericBlockCipher();
}
Thread clientThread = null;
Thread serverThread = null;
/*
* Primary constructor, used to drive remainder of the test.
*
* Fork off the other side, then do your work.
*/
GenericBlockCipher() throws Exception {
try {
if (separateServerThread) {
startServer(true);
startClient(false);
} else {
startClient(true);
startServer(false);
}
} catch (Exception e) {
// swallow for now. Show later
}
/*
* Wait for other side to close down.
*/
if (separateServerThread) {
serverThread.join();
} else {
clientThread.join();
}
/*
* When we get here, the test is pretty much over.
* Which side threw the error?
*/
Exception local;
Exception remote;
String whichRemote;
if (separateServerThread) {
remote = serverException;
local = clientException;
whichRemote = "server";
} else {
remote = clientException;
local = serverException;
whichRemote = "client";
}
/*
* If both failed, return the curthread's exception, but also
* print the remote side Exception
*/
if ((local != null) && (remote != null)) {
System.out.println(whichRemote + " also threw:");
remote.printStackTrace();
System.out.println();
throw local;
}
if (remote != null) {
throw remote;
}
if (local != null) {
throw local;
}
}
void startServer(boolean newThread) throws Exception {
if (newThread) {
serverThread = new Thread() {
public void run() {
try {
doServerSide();
} catch (Exception e) {
/*
* Our server thread just died.
*
* Release the client, if not active already...
*/
System.err.println("Server died...");
serverReady = true;
serverException = e;
}
}
};
serverThread.start();
} else {
try {
doServerSide();
} catch (Exception e) {
serverException = e;
} finally {
serverReady = true;
}
}
}
void startClient(boolean newThread) throws Exception {
if (newThread) {
clientThread = new Thread() {
public void run() {
try {
doClientSide();
} catch (Exception e) {
/*
* Our client thread just died.
*/
System.err.println("Client died...");
clientException = e;
}
}
};
clientThread.start();
} else {
try {
doClientSide();
} catch (Exception e) {
clientException = e;
}
}
}
}

View file

@ -0,0 +1,303 @@
/*
* Copyright (c) 2010, 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.
*/
/*
* @test
* @bug 4873188
* @summary Support TLS 1.1
* @run main/othervm -Djavax.net.debug=all GenericStreamCipher
*
* @author Xuelei Fan
*/
import java.io.*;
import java.net.*;
import javax.net.ssl.*;
public class GenericStreamCipher {
/*
* =============================================================
* Set the various variables needed for the tests, then
* specify what tests to run on each side.
*/
/*
* Should we run the client or server in a separate thread?
* Both sides can throw exceptions, but do you have a preference
* as to which side should be the main thread.
*/
static boolean separateServerThread = false;
/*
* Where do we find the keystores?
*/
static String pathToStores = "/../../../../etc";
static String keyStoreFile = "keystore";
static String trustStoreFile = "truststore";
static String passwd = "passphrase";
/*
* Is the server ready to serve?
*/
volatile static boolean serverReady = false;
/*
* Turn on SSL debugging?
*/
static boolean debug = false;
/*
* If the client or server is doing some kind of object creation
* that the other side depends on, and that thread prematurely
* exits, you may experience a hang. The test harness will
* terminate all hung threads after its timeout has expired,
* currently 3 minutes by default, but you might try to be
* smart about it....
*/
/*
* Define the server side of the test.
*
* If the server prematurely exits, serverReady will be set to true
* to avoid infinite hangs.
*/
void doServerSide() throws Exception {
SSLServerSocketFactory sslssf =
(SSLServerSocketFactory) SSLServerSocketFactory.getDefault();
SSLServerSocket sslServerSocket =
(SSLServerSocket) sslssf.createServerSocket(serverPort);
serverPort = sslServerSocket.getLocalPort();
/*
* Signal Client, we're ready for his connect.
*/
serverReady = true;
SSLSocket sslSocket = (SSLSocket) sslServerSocket.accept();
InputStream sslIS = sslSocket.getInputStream();
OutputStream sslOS = sslSocket.getOutputStream();
sslIS.read();
sslOS.write('A');
sslOS.flush();
sslSocket.close();
}
/*
* Define the client side of the test.
*
* If the server prematurely exits, serverReady will be set to true
* to avoid infinite hangs.
*/
void doClientSide() throws Exception {
/*
* Wait for server to get started.
*/
while (!serverReady) {
Thread.sleep(50);
}
SSLSocketFactory sslsf =
(SSLSocketFactory) SSLSocketFactory.getDefault();
SSLSocket sslSocket = (SSLSocket)
sslsf.createSocket("localhost", serverPort);
// enable TLSv1.1 only
sslSocket.setEnabledProtocols(new String[] {"TLSv1.1"});
// enable a stream cipher
sslSocket.setEnabledCipherSuites(
new String[] {"SSL_RSA_WITH_RC4_128_MD5"});
InputStream sslIS = sslSocket.getInputStream();
OutputStream sslOS = sslSocket.getOutputStream();
sslOS.write('B');
sslOS.flush();
sslIS.read();
sslSocket.close();
}
/*
* =============================================================
* The remainder is just support stuff
*/
// use any free port by default
volatile int serverPort = 0;
volatile Exception serverException = null;
volatile Exception clientException = null;
public static void main(String[] args) throws Exception {
String keyFilename =
System.getProperty("test.src", ".") + "/" + pathToStores +
"/" + keyStoreFile;
String trustFilename =
System.getProperty("test.src", ".") + "/" + pathToStores +
"/" + trustStoreFile;
System.setProperty("javax.net.ssl.keyStore", keyFilename);
System.setProperty("javax.net.ssl.keyStorePassword", passwd);
System.setProperty("javax.net.ssl.trustStore", trustFilename);
System.setProperty("javax.net.ssl.trustStorePassword", passwd);
if (debug)
System.setProperty("javax.net.debug", "all");
/*
* Start the tests.
*/
new GenericStreamCipher();
}
Thread clientThread = null;
Thread serverThread = null;
/*
* Primary constructor, used to drive remainder of the test.
*
* Fork off the other side, then do your work.
*/
GenericStreamCipher() throws Exception {
try {
if (separateServerThread) {
startServer(true);
startClient(false);
} else {
startClient(true);
startServer(false);
}
} catch (Exception e) {
// swallow for now. Show later
}
/*
* Wait for other side to close down.
*/
if (separateServerThread) {
serverThread.join();
} else {
clientThread.join();
}
/*
* When we get here, the test is pretty much over.
* Which side threw the error?
*/
Exception local;
Exception remote;
String whichRemote;
if (separateServerThread) {
remote = serverException;
local = clientException;
whichRemote = "server";
} else {
remote = clientException;
local = serverException;
whichRemote = "client";
}
/*
* If both failed, return the curthread's exception, but also
* print the remote side Exception
*/
if ((local != null) && (remote != null)) {
System.out.println(whichRemote + " also threw:");
remote.printStackTrace();
System.out.println();
throw local;
}
if (remote != null) {
throw remote;
}
if (local != null) {
throw local;
}
}
void startServer(boolean newThread) throws Exception {
if (newThread) {
serverThread = new Thread() {
public void run() {
try {
doServerSide();
} catch (Exception e) {
/*
* Our server thread just died.
*
* Release the client, if not active already...
*/
System.err.println("Server died...");
serverReady = true;
serverException = e;
}
}
};
serverThread.start();
} else {
try {
doServerSide();
} catch (Exception e) {
serverException = e;
} finally {
serverReady = true;
}
}
}
void startClient(boolean newThread) throws Exception {
if (newThread) {
clientThread = new Thread() {
public void run() {
try {
doClientSide();
} catch (Exception e) {
/*
* Our client thread just died.
*/
System.err.println("Client died...");
clientException = e;
}
}
};
clientThread.start();
} else {
try {
doClientSide();
} catch (Exception e) {
clientException = e;
}
}
}
}

View file

@ -120,6 +120,13 @@ public class CipherTest {
return false; return false;
} }
// ignore exportable cipher suite for TLSv1.1
if (protocol.equals("TLSv1.1")) {
if(cipherSuite.indexOf("_EXPORT_") != -1) {
return false;
}
}
return true; return true;
} }
@ -149,18 +156,14 @@ public class CipherTest {
cipherSuites.length * protocols.length * clientAuths.length); cipherSuites.length * protocols.length * clientAuths.length);
for (int i = 0; i < cipherSuites.length; i++) { for (int i = 0; i < cipherSuites.length; i++) {
String cipherSuite = cipherSuites[i]; String cipherSuite = cipherSuites[i];
if (peerFactory.isSupported(cipherSuite) == false) {
continue;
}
// skip kerberos cipher suites
if (cipherSuite.startsWith("TLS_KRB5")) {
continue;
}
for (int j = 0; j < protocols.length; j++) { for (int j = 0; j < protocols.length; j++) {
String protocol = protocols[j]; String protocol = protocols[j];
if (protocol.equals("SSLv2Hello")) {
if (!peerFactory.isSupported(cipherSuite, protocol)) {
continue; continue;
} }
for (int k = 0; k < clientAuths.length; k++) { for (int k = 0; k < clientAuths.length; k++) {
String clientAuth = clientAuths[k]; String clientAuth = clientAuths[k];
if ((clientAuth != null) && if ((clientAuth != null) &&
@ -297,7 +300,7 @@ public class CipherTest {
throws Exception { throws Exception {
long time = System.currentTimeMillis(); long time = System.currentTimeMillis();
String relPath; String relPath;
if ((args.length > 0) && args[0].equals("sh")) { if ((args != null) && (args.length > 0) && args[0].equals("sh")) {
relPath = pathToStoresSH; relPath = pathToStoresSH;
} else { } else {
relPath = pathToStores; relPath = pathToStores;
@ -336,7 +339,30 @@ public class CipherTest {
abstract Server newServer(CipherTest cipherTest) throws Exception; abstract Server newServer(CipherTest cipherTest) throws Exception;
boolean isSupported(String cipherSuite) { boolean isSupported(String cipherSuite, String protocol) {
// skip kerberos cipher suites
if (cipherSuite.startsWith("TLS_KRB5")) {
System.out.println("Skipping unsupported test for " +
cipherSuite + " of " + protocol);
return false;
}
// skip SSLv2Hello protocol
if (protocol.equals("SSLv2Hello")) {
System.out.println("Skipping unsupported test for " +
cipherSuite + " of " + protocol);
return false;
}
// ignore exportable cipher suite for TLSv1.1
if (protocol.equals("TLSv1.1")) {
if (cipherSuite.indexOf("_EXPORT_WITH") != -1) {
System.out.println("Skipping obsoleted test for " +
cipherSuite + " of " + protocol);
return false;
}
}
return true; return true;
} }
} }