jdk/src/share/classes/sun/security/ssl/RSAClientKeyExchange.java
changeset 23733 b9b80421cfa7
parent 22309 1990211a42e5
child 24194 45f278eb1b37
equal deleted inserted replaced
23732:44fe768edfd2 23733:b9b80421cfa7
    46  * always exactly 48 bytes.
    46  * always exactly 48 bytes.
    47  *
    47  *
    48  */
    48  */
    49 final class RSAClientKeyExchange extends HandshakeMessage {
    49 final class RSAClientKeyExchange extends HandshakeMessage {
    50 
    50 
    51     /**
       
    52      * The TLS spec says that the version in the RSA premaster secret must
       
    53      * be the maximum version supported by the client (i.e. the version it
       
    54      * requested in its client hello version). However, we (and other
       
    55      * implementations) used to send the active negotiated version. The
       
    56      * system property below allows to toggle the behavior.
       
    57      */
       
    58     private final static String PROP_NAME =
       
    59                                 "com.sun.net.ssl.rsaPreMasterSecretFix";
       
    60 
       
    61     /*
       
    62      * Default is "false" (old behavior) for compatibility reasons in
       
    63      * SSLv3/TLSv1.  Later protocols (TLSv1.1+) do not use this property.
       
    64      */
       
    65     private final static boolean rsaPreMasterSecretFix =
       
    66                                 Debug.getBooleanProperty(PROP_NAME, false);
       
    67 
       
    68     /*
    51     /*
    69      * The following field values were encrypted with the server's public
    52      * The following field values were encrypted with the server's public
    70      * key (or temp key from server key exchange msg) and are presented
    53      * key (or temp key from server key exchange msg) and are presented
    71      * here in DECRYPTED form.
    54      * here in DECRYPTED form.
    72      */
    55      */
    86         if (publicKey.getAlgorithm().equals("RSA") == false) {
    69         if (publicKey.getAlgorithm().equals("RSA") == false) {
    87             throw new SSLKeyException("Public key not of type RSA");
    70             throw new SSLKeyException("Public key not of type RSA");
    88         }
    71         }
    89         this.protocolVersion = protocolVersion;
    72         this.protocolVersion = protocolVersion;
    90 
    73 
    91         int major, minor;
       
    92 
       
    93         if (rsaPreMasterSecretFix || maxVersion.v >= ProtocolVersion.TLS11.v) {
       
    94             major = maxVersion.major;
       
    95             minor = maxVersion.minor;
       
    96         } else {
       
    97             major = protocolVersion.major;
       
    98             minor = protocolVersion.minor;
       
    99         }
       
   100 
       
   101         try {
    74         try {
   102             String s = ((protocolVersion.v >= ProtocolVersion.TLS12.v) ?
    75             String s = ((protocolVersion.v >= ProtocolVersion.TLS12.v) ?
   103                 "SunTls12RsaPremasterSecret" : "SunTlsRsaPremasterSecret");
    76                 "SunTls12RsaPremasterSecret" : "SunTlsRsaPremasterSecret");
   104             KeyGenerator kg = JsseJce.getKeyGenerator(s);
    77             KeyGenerator kg = JsseJce.getKeyGenerator(s);
   105             kg.init(new TlsRsaPremasterSecretParameterSpec(major, minor),
    78             kg.init(new TlsRsaPremasterSecretParameterSpec(
   106                     generator);
    79                     maxVersion.v, protocolVersion.v), generator);
   107             preMaster = kg.generateKey();
    80             preMaster = kg.generateKey();
   108 
    81 
   109             Cipher cipher = JsseJce.getCipher(JsseJce.CIPHER_RSA_PKCS1);
    82             Cipher cipher = JsseJce.getCipher(JsseJce.CIPHER_RSA_PKCS1);
   110             cipher.init(Cipher.WRAP_MODE, publicKey, generator);
    83             cipher.init(Cipher.WRAP_MODE, publicKey, generator);
   111             encrypted = cipher.wrap(preMaster);
    84             encrypted = cipher.wrap(preMaster);
   136                 throw new SSLProtocolException(
   109                 throw new SSLProtocolException(
   137                         "SSL: read PreMasterSecret: short read");
   110                         "SSL: read PreMasterSecret: short read");
   138             }
   111             }
   139         }
   112         }
   140 
   113 
   141         Exception failover = null;
       
   142         byte[] encoded = null;
       
   143         try {
   114         try {
   144             Cipher cipher = JsseJce.getCipher(JsseJce.CIPHER_RSA_PKCS1);
   115             Cipher cipher = JsseJce.getCipher(JsseJce.CIPHER_RSA_PKCS1);
   145             // Cannot generate key here, please don't use Cipher.UNWRAP_MODE!
   116             // Cannot generate key here, please don't use Cipher.UNWRAP_MODE!
   146             cipher.init(Cipher.DECRYPT_MODE, privateKey);
   117             cipher.init(Cipher.UNWRAP_MODE, privateKey,
   147             encoded = cipher.doFinal(encrypted);
   118                     new TlsRsaPremasterSecretParameterSpec(
   148         } catch (BadPaddingException bpe) {
   119                             maxVersion.v, currentVersion.v),
   149             failover = bpe;
   120                     generator);
   150             encoded = null;
   121             preMaster = (SecretKey)cipher.unwrap(encrypted,
   151         } catch (IllegalBlockSizeException ibse) {
   122                                 "TlsRsaPremasterSecret", Cipher.SECRET_KEY);
   152             // the message it too big to process with RSA
   123         } catch (InvalidKeyException ibk) {
       
   124             // the message is too big to process with RSA
   153             throw new SSLProtocolException(
   125             throw new SSLProtocolException(
   154                 "Unable to process PreMasterSecret, may be too big");
   126                 "Unable to process PreMasterSecret, may be too big");
   155         } catch (Exception e) {
   127         } catch (Exception e) {
   156             // unlikely to happen, otherwise, must be a provider exception
   128             // unlikely to happen, otherwise, must be a provider exception
   157             if (debug != null && Debug.isOn("handshake")) {
   129             if (debug != null && Debug.isOn("handshake")) {
   158                 System.out.println("RSA premaster secret decryption error:");
   130                 System.out.println("RSA premaster secret decryption error:");
   159                 e.printStackTrace(System.out);
   131                 e.printStackTrace(System.out);
   160             }
   132             }
   161             throw new RuntimeException("Could not generate dummy secret", e);
   133             throw new RuntimeException("Could not generate dummy secret", e);
   162         }
       
   163 
       
   164         // polish the premaster secret
       
   165         preMaster = polishPreMasterSecretKey(
       
   166                     currentVersion, maxVersion, generator, encoded, failover);
       
   167     }
       
   168 
       
   169     /**
       
   170      * To avoid vulnerabilities described by section 7.4.7.1, RFC 5246,
       
   171      * treating incorrectly formatted message blocks and/or mismatched
       
   172      * version numbers in a manner indistinguishable from correctly
       
   173      * formatted RSA blocks.
       
   174      *
       
   175      * RFC 5246 describes the approach as :
       
   176      *
       
   177      *  1. Generate a string R of 48 random bytes
       
   178      *
       
   179      *  2. Decrypt the message to recover the plaintext M
       
   180      *
       
   181      *  3. If the PKCS#1 padding is not correct, or the length of message
       
   182      *     M is not exactly 48 bytes:
       
   183      *        pre_master_secret = R
       
   184      *     else If ClientHello.client_version <= TLS 1.0, and version
       
   185      *     number check is explicitly disabled:
       
   186      *        premaster secret = M
       
   187      *     else If M[0..1] != ClientHello.client_version:
       
   188      *        premaster secret = R
       
   189      *     else:
       
   190      *        premaster secret = M
       
   191      *
       
   192      * Note that #2 has completed before the call of this method.
       
   193      */
       
   194     private SecretKey polishPreMasterSecretKey(ProtocolVersion currentVersion,
       
   195             ProtocolVersion clientHelloVersion, SecureRandom generator,
       
   196             byte[] encoded, Exception failoverException) {
       
   197 
       
   198         this.protocolVersion = clientHelloVersion;
       
   199         if (generator == null) {
       
   200             generator = new SecureRandom();
       
   201         }
       
   202         byte[] random = new byte[48];
       
   203         generator.nextBytes(random);
       
   204 
       
   205         if (failoverException == null && encoded != null) {
       
   206             // check the length
       
   207             if (encoded.length != 48) {
       
   208                 if (debug != null && Debug.isOn("handshake")) {
       
   209                     System.out.println(
       
   210                         "incorrect length of premaster secret: " +
       
   211                         encoded.length);
       
   212                 }
       
   213 
       
   214                 return generatePreMasterSecret(
       
   215                         clientHelloVersion, random, generator);
       
   216             }
       
   217 
       
   218             if (clientHelloVersion.major != encoded[0] ||
       
   219                         clientHelloVersion.minor != encoded[1]) {
       
   220 
       
   221                 if (clientHelloVersion.v <= ProtocolVersion.TLS10.v &&
       
   222                        currentVersion.major == encoded[0] &&
       
   223                        currentVersion.minor == encoded[1]) {
       
   224                     /*
       
   225                      * For compatibility, we maintain the behavior that the
       
   226                      * version in pre_master_secret can be the negotiated
       
   227                      * version for TLS v1.0 and SSL v3.0.
       
   228                      */
       
   229                     this.protocolVersion = currentVersion;
       
   230                 } else {
       
   231                     if (debug != null && Debug.isOn("handshake")) {
       
   232                         System.out.println("Mismatching Protocol Versions, " +
       
   233                             "ClientHello.client_version is " +
       
   234                             clientHelloVersion +
       
   235                             ", while PreMasterSecret.client_version is " +
       
   236                             ProtocolVersion.valueOf(encoded[0], encoded[1]));
       
   237                     }
       
   238 
       
   239                     encoded = random;
       
   240                 }
       
   241             }
       
   242 
       
   243             return generatePreMasterSecret(
       
   244                     clientHelloVersion, encoded, generator);
       
   245         }
       
   246 
       
   247         if (debug != null && Debug.isOn("handshake") &&
       
   248                         failoverException != null) {
       
   249             System.out.println("Error decrypting premaster secret:");
       
   250             failoverException.printStackTrace(System.out);
       
   251         }
       
   252 
       
   253         return generatePreMasterSecret(clientHelloVersion, random, generator);
       
   254     }
       
   255 
       
   256     // generate a premaster secret with the specified version number
       
   257     private static SecretKey generatePreMasterSecret(
       
   258             ProtocolVersion version, byte[] encodedSecret,
       
   259             SecureRandom generator) {
       
   260 
       
   261         if (debug != null && Debug.isOn("handshake")) {
       
   262             System.out.println("Generating a random fake premaster secret");
       
   263         }
       
   264 
       
   265         try {
       
   266             String s = ((version.v >= ProtocolVersion.TLS12.v) ?
       
   267                 "SunTls12RsaPremasterSecret" : "SunTlsRsaPremasterSecret");
       
   268             KeyGenerator kg = JsseJce.getKeyGenerator(s);
       
   269             kg.init(new TlsRsaPremasterSecretParameterSpec(
       
   270                     version.major, version.minor, encodedSecret), generator);
       
   271             return kg.generateKey();
       
   272         } catch (InvalidAlgorithmParameterException |
       
   273                 NoSuchAlgorithmException iae) {
       
   274             // unlikely to happen, otherwise, must be a provider exception
       
   275             if (debug != null && Debug.isOn("handshake")) {
       
   276                 System.out.println("RSA premaster secret generation error:");
       
   277                 iae.printStackTrace(System.out);
       
   278             }
       
   279             throw new RuntimeException("Could not generate dummy secret", iae);
       
   280         }
   134         }
   281     }
   135     }
   282 
   136 
   283     @Override
   137     @Override
   284     int messageType() {
   138     int messageType() {