jdk/src/share/classes/com/sun/crypto/provider/RSACipher.java
changeset 23733 b9b80421cfa7
parent 16909 78a1749a43e2
--- a/jdk/src/share/classes/com/sun/crypto/provider/RSACipher.java	Wed Apr 09 17:19:19 2014 +0800
+++ b/jdk/src/share/classes/com/sun/crypto/provider/RSACipher.java	Wed Apr 09 12:49:51 2014 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2003, 2014, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -39,6 +39,8 @@
 
 import sun.security.rsa.*;
 import sun.security.jca.Providers;
+import sun.security.internal.spec.TlsRsaPremasterSecretParameterSpec;
+import sun.security.util.KeyUtil;
 
 /**
  * RSA cipher implementation. Supports RSA en/decryption and signing/verifying
@@ -91,8 +93,8 @@
     // padding object
     private RSAPadding padding;
 
-    // cipher parameter for OAEP padding
-    private OAEPParameterSpec spec = null;
+    // cipher parameter for OAEP padding and TLS RSA premaster secret
+    private AlgorithmParameterSpec spec = null;
 
     // buffer for the data
     private byte[] buffer;
@@ -110,6 +112,9 @@
     // hash algorithm for OAEP
     private String oaepHashAlgorithm = "SHA-1";
 
+    // the source of randomness
+    private SecureRandom random;
+
     public RSACipher() {
         paddingType = PAD_PKCS1;
     }
@@ -175,7 +180,7 @@
 
     // see JCE spec
     protected AlgorithmParameters engineGetParameters() {
-        if (spec != null) {
+        if (spec != null && spec instanceof OAEPParameterSpec) {
             try {
                 AlgorithmParameters params =
                     AlgorithmParameters.getInstance("OAEP",
@@ -276,8 +281,13 @@
             buffer = new byte[n];
         } else if (paddingType == PAD_PKCS1) {
             if (params != null) {
-                throw new InvalidAlgorithmParameterException
-                ("Parameters not supported");
+                if (!(params instanceof TlsRsaPremasterSecretParameterSpec)) {
+                    throw new InvalidAlgorithmParameterException(
+                            "Parameters not supported");
+                }
+
+                spec = params;
+                this.random = random;   // for TLS RSA premaster secret
             }
             int blockType = (mode <= MODE_DECRYPT) ? RSAPadding.PAD_BLOCKTYPE_2
                                                    : RSAPadding.PAD_BLOCKTYPE_1;
@@ -293,19 +303,18 @@
                 throw new InvalidKeyException
                         ("OAEP cannot be used to sign or verify signatures");
             }
-            OAEPParameterSpec myParams;
             if (params != null) {
                 if (!(params instanceof OAEPParameterSpec)) {
                     throw new InvalidAlgorithmParameterException
                         ("Wrong Parameters for OAEP Padding");
                 }
-                myParams = (OAEPParameterSpec) params;
+                spec = params;
             } else {
-                myParams = new OAEPParameterSpec(oaepHashAlgorithm, "MGF1",
+                spec = new OAEPParameterSpec(oaepHashAlgorithm, "MGF1",
                     MGF1ParameterSpec.SHA1, PSource.PSpecified.DEFAULT);
             }
             padding = RSAPadding.getInstance(RSAPadding.PAD_OAEP_MGF1, n,
-                random, myParams);
+                random, (OAEPParameterSpec)spec);
             if (encrypt) {
                 int k = padding.getMaxDataSize();
                 buffer = new byte[k];
@@ -420,17 +429,40 @@
         if (wrappedKey.length > buffer.length) {
             throw new InvalidKeyException("Key is too long for unwrapping");
         }
+
+        boolean isTlsRsaPremasterSecret =
+                algorithm.equals("TlsRsaPremasterSecret");
+        Exception failover = null;
+        byte[] encoded = null;
+
         update(wrappedKey, 0, wrappedKey.length);
         try {
-            byte[] encoded = doFinal();
-            return ConstructKeys.constructKey(encoded, algorithm, type);
+            encoded = doFinal();
         } catch (BadPaddingException e) {
-            // should not occur
-            throw new InvalidKeyException("Unwrapping failed", e);
+            if (isTlsRsaPremasterSecret) {
+                failover = e;
+            } else {
+                throw new InvalidKeyException("Unwrapping failed", e);
+            }
         } catch (IllegalBlockSizeException e) {
             // should not occur, handled with length check above
             throw new InvalidKeyException("Unwrapping failed", e);
         }
+
+        if (isTlsRsaPremasterSecret) {
+            if (!(spec instanceof TlsRsaPremasterSecretParameterSpec)) {
+                throw new IllegalStateException(
+                        "No TlsRsaPremasterSecretParameterSpec specified");
+            }
+
+            // polish the TLS premaster secret
+            encoded = KeyUtil.checkTlsPreMasterSecretKey(
+                ((TlsRsaPremasterSecretParameterSpec)spec).getClientVersion(),
+                ((TlsRsaPremasterSecretParameterSpec)spec).getServerVersion(),
+                random, encoded, (failover != null));
+        }
+
+        return ConstructKeys.constructKey(encoded, algorithm, type);
     }
 
     // see JCE spec
@@ -438,5 +470,4 @@
         RSAKey rsaKey = RSAKeyFactory.toRSAKey(key);
         return rsaKey.getModulus().bitLength();
     }
-
 }