jdk/src/share/classes/sun/security/internal/spec/TlsRsaPremasterSecretParameterSpec.java
--- a/jdk/src/share/classes/sun/security/internal/spec/TlsRsaPremasterSecretParameterSpec.java Wed Apr 09 17:19:19 2014 +0800
+++ b/jdk/src/share/classes/sun/security/internal/spec/TlsRsaPremasterSecretParameterSpec.java Wed Apr 09 12:49:51 2014 +0000
@@ -26,11 +26,11 @@
package sun.security.internal.spec;
import java.security.spec.AlgorithmParameterSpec;
+import java.security.AccessController;
+import java.security.PrivilegedAction;
/**
- * Parameters for SSL/TLS RSA Premaster secret generation.
- * This class is used by SSL/TLS client to initialize KeyGenerators of the
- * type "TlsRsaPremasterSecret".
+ * Parameters for SSL/TLS RSA premaster secret.
*
* <p>Instances of this class are immutable.
*
@@ -43,90 +43,108 @@
public class TlsRsaPremasterSecretParameterSpec
implements AlgorithmParameterSpec {
- private final int majorVersion;
- private final int minorVersion;
- private final byte[] encodedSecret;
+ /*
+ * The TLS spec says that the version in the RSA premaster secret must
+ * be the maximum version supported by the client (i.e. the version it
+ * requested in its client hello version). However, we (and other
+ * implementations) used to send the active negotiated version. The
+ * system property below allows to toggle the behavior.
+ */
+ private final static String PROP_NAME =
+ "com.sun.net.ssl.rsaPreMasterSecretFix";
- /**
- * Constructs a new TlsRsaPremasterSecretParameterSpec.
- * <P>
- * The version numbers will be placed inside the premaster secret to
- * detect version rollbacks attacks as described in the TLS specification.
- * Note that they do not indicate the protocol version negotiated for
- * the handshake.
- *
- * @param majorVersion the major number of the protocol version
- * @param minorVersion the minor number of the protocol version
- *
- * @throws IllegalArgumentException if minorVersion or majorVersion are
- * negative or larger than 255
+ /*
+ * Default is "false" (old behavior) for compatibility reasons in
+ * SSLv3/TLSv1. Later protocols (TLSv1.1+) do not use this property.
*/
- public TlsRsaPremasterSecretParameterSpec(int majorVersion,
- int minorVersion) {
- this.majorVersion =
- TlsMasterSecretParameterSpec.checkVersion(majorVersion);
- this.minorVersion =
- TlsMasterSecretParameterSpec.checkVersion(minorVersion);
- this.encodedSecret = null;
- }
+ private final static boolean rsaPreMasterSecretFix =
+ AccessController.doPrivileged(new PrivilegedAction<Boolean>() {
+ public Boolean run() {
+ String value = System.getProperty(PROP_NAME);
+ if (value != null && value.equalsIgnoreCase("true")) {
+ return Boolean.TRUE;
+ }
+
+ return Boolean.FALSE;
+ }
+ });
+
+ private final int clientVersion;
+ private final int serverVersion;
/**
* Constructs a new TlsRsaPremasterSecretParameterSpec.
- * <P>
- * The version numbers will be placed inside the premaster secret to
- * detect version rollbacks attacks as described in the TLS specification.
- * Note that they do not indicate the protocol version negotiated for
- * the handshake.
- * <P>
- * Usually, the encoded secret key is a random number that acts as
- * dummy pre_master_secret to avoid vulnerabilities described by
- * section 7.4.7.1, RFC 5246.
*
- * @param majorVersion the major number of the protocol version
- * @param minorVersion the minor number of the protocol version
- * @param encodedSecret the encoded secret key
+ * @param clientVersion the version of the TLS protocol by which the
+ * client wishes to communicate during this session
+ * @param serverVersion the negotiated version of the TLS protocol which
+ * contains the lower of that suggested by the client in the client
+ * hello and the highest supported by the server.
*
- * @throws IllegalArgumentException if minorVersion or majorVersion are
- * negative or larger than 255, or encodedSecret is not exactly 48 bytes.
+ * @throws IllegalArgumentException if clientVersion or serverVersion are
+ * negative or larger than (2^16 - 1)
*/
- public TlsRsaPremasterSecretParameterSpec(int majorVersion,
- int minorVersion, byte[] encodedSecret) {
- this.majorVersion =
- TlsMasterSecretParameterSpec.checkVersion(majorVersion);
- this.minorVersion =
- TlsMasterSecretParameterSpec.checkVersion(minorVersion);
+ public TlsRsaPremasterSecretParameterSpec(
+ int clientVersion, int serverVersion) {
+
+ this.clientVersion = checkVersion(clientVersion);
+ this.serverVersion = checkVersion(serverVersion);
+ }
- if (encodedSecret == null || encodedSecret.length != 48) {
- throw new IllegalArgumentException(
- "Encoded secret is not exactly 48 bytes");
- }
- this.encodedSecret = encodedSecret.clone();
+ /**
+ * Returns the version of the TLS protocol by which the client wishes to
+ * communicate during this session.
+ *
+ * @return the version of the TLS protocol in ClientHello message
+ */
+ public int getClientVersion() {
+ return clientVersion;
}
/**
- * Returns the major version.
+ * Returns the negotiated version of the TLS protocol which contains the
+ * lower of that suggested by the client in the client hello and the
+ * highest supported by the server.
*
- * @return the major version.
+ * @return the negotiated version of the TLS protocol in ServerHello message
*/
- public int getMajorVersion() {
- return majorVersion;
+ public int getServerVersion() {
+ return serverVersion;
}
/**
- * Returns the minor version.
+ * Returns the major version used in RSA premaster secret.
*
- * @return the minor version.
+ * @return the major version used in RSA premaster secret.
*/
- public int getMinorVersion() {
- return minorVersion;
+ public int getMajorVersion() {
+ if (rsaPreMasterSecretFix || clientVersion >= 0x0302) {
+ // 0x0302: TLSv1.1
+ return (clientVersion >>> 8) & 0xFF;
+ }
+
+ return (serverVersion >>> 8) & 0xFF;
}
/**
- * Returns the encoded secret.
+ * Returns the minor version used in RSA premaster secret.
*
- * @return the encoded secret, may be null if no encoded secret.
+ * @return the minor version used in RSA premaster secret.
*/
- public byte[] getEncodedSecret() {
- return encodedSecret == null ? null : encodedSecret.clone();
+ public int getMinorVersion() {
+ if (rsaPreMasterSecretFix || clientVersion >= 0x0302) {
+ // 0x0302: TLSv1.1
+ return clientVersion & 0xFF;
+ }
+
+ return serverVersion & 0xFF;
+ }
+
+ private int checkVersion(int version) {
+ if ((version < 0) || (version > 0xFFFF)) {
+ throw new IllegalArgumentException(
+ "Version must be between 0 and 65,535");
+ }
+ return version;
}
}