Support RSASSS-PSS for TLS 1.2 JDK-8145252-TLS13-branch
authorxuelei
Mon, 25 Jun 2018 08:14:11 -0700
branchJDK-8145252-TLS13-branch
changeset 56806 32a737f51e37
parent 56805 985a8862b6bf
child 56807 b9e374d0534f
Support RSASSS-PSS for TLS 1.2
src/java.base/share/classes/sun/security/ssl/CertificateMessage.java
src/java.base/share/classes/sun/security/ssl/CertificateRequest.java
src/java.base/share/classes/sun/security/ssl/ClientKeyExchange.java
src/java.base/share/classes/sun/security/ssl/DHClientKeyExchange.java
src/java.base/share/classes/sun/security/ssl/ECDHClientKeyExchange.java
src/java.base/share/classes/sun/security/ssl/JsseJce.java
src/java.base/share/classes/sun/security/ssl/RSAClientKeyExchange.java
src/java.base/share/classes/sun/security/ssl/SSLKeyExchange.java
src/java.base/share/classes/sun/security/ssl/ServerHello.java
src/java.base/share/classes/sun/security/ssl/ServerKeyExchange.java
src/java.base/share/classes/sun/security/ssl/SignatureScheme.java
src/java.base/share/classes/sun/security/ssl/X509Authentication.java
src/java.base/share/classes/sun/security/ssl/X509KeyManagerImpl.java
test/jdk/sun/security/ssl/ClientHandshaker/LengthCheckTest.java
test/jdk/sun/security/ssl/SSLEngineImpl/CloseEngineException.java
test/jdk/sun/security/ssl/SSLEngineImpl/SSLEngineKeyLimit.java
--- a/src/java.base/share/classes/sun/security/ssl/CertificateMessage.java	Sun Jun 24 13:34:42 2018 -0700
+++ b/src/java.base/share/classes/sun/security/ssl/CertificateMessage.java	Mon Jun 25 08:14:11 2018 -0700
@@ -651,15 +651,16 @@
             PublicKey key = certs[0].getPublicKey();
             String keyAlgorithm = key.getAlgorithm();
             String authType;
-            if (keyAlgorithm.equals("RSA")) {
-                authType = "RSA";
-            } else if (keyAlgorithm.equals("DSA")) {
-                authType = "DSA";
-            } else if (keyAlgorithm.equals("EC")) {
-                authType = "EC";
-            } else {
-                // unknown public key type
-                authType = "UNKNOWN";
+            switch (keyAlgorithm) {
+                case "RSA":
+                case "DSA":
+                case "EC":
+                case "RSASSA-PSS":
+                    authType = keyAlgorithm;
+                    break;
+                default:
+                    // unknown public key type
+                    authType = "UNKNOWN";
             }
 
             try {
@@ -1035,14 +1036,14 @@
 
                     if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) {
                         SSLLogger.warning(
-                        "Unable to produce CertificateVerify for scheme: " + ss.name);
+                            "Unable to produce CertificateVerify for " +
+                            "signature scheme: " + ss.name);
                     }
                     checkedKeyTypes.add(ss.keyAlgorithm);
                     continue;
                 }
 
-                SSLAuthentication ka =
-                        X509Authentication.nameOf(ss.keyAlgorithm);
+                SSLAuthentication ka = X509Authentication.valueOf(ss);
                 if (ka == null) {
                     if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) {
                         SSLLogger.warning(
@@ -1232,18 +1233,14 @@
             String authType;
             switch (keyAlgorithm) {
                 case "RSA":
-                    authType = "RSA";
-                    break;
                 case "DSA":
-                    authType = "DSA";
-                    break;
                 case "EC":
-                    authType = "EC";
+                case "RSASSA-PSS":
+                    authType = keyAlgorithm;
                     break;
                 default:
                     // unknown public key type
                     authType = "UNKNOWN";
-                    break;
             }
 
             try {
@@ -1296,26 +1293,10 @@
                     "Failed to parse server certificates", ce);
             }
 
-            // find out the types of client authentication used
-            /*
-            String keyAlgorithm = certs[0].getPublicKey().getAlgorithm();
-            String authType;
-            switch (keyAlgorithm) {
-                case "RSA":
-                    authType = "RSA";
-                    break;
-                case "DSA":
-                    authType = "DSA";
-                    break;
-                case "EC":
-                    authType = "EC";
-                    break;
-                default:
-                    // unknown public key type
-                    authType = "UNKNOWN";
-                    break;
-            }
-            */
+            // find out the types of server authentication used
+            //
+            // Note that the "UNKNOWN" authentication type is sufficient to
+            // check the required digitalSignature KeyUsage for TLS 1.3.
             String authType = "UNKNOWN";
 
             try {
--- a/src/java.base/share/classes/sun/security/ssl/CertificateRequest.java	Sun Jun 24 13:34:42 2018 -0700
+++ b/src/java.base/share/classes/sun/security/ssl/CertificateRequest.java	Mon Jun 25 08:14:11 2018 -0700
@@ -67,7 +67,7 @@
         // RFC 2246
         RSA_SIGN            ((byte)0x01, "rsa_sign", "RSA", true),
         DSS_SIGN            ((byte)0x02, "dss_sign", "DSA", true),
-        RSA_FIXED_DH        ((byte)0x03, "rsa__fixed_dh"),
+        RSA_FIXED_DH        ((byte)0x03, "rsa_fixed_dh"),
         DSS_FIXED_DH        ((byte)0x04, "dss_fixed_dh"),
 
         // RFC 4346
--- a/src/java.base/share/classes/sun/security/ssl/ClientKeyExchange.java	Sun Jun 24 13:34:42 2018 -0700
+++ b/src/java.base/share/classes/sun/security/ssl/ClientKeyExchange.java	Mon Jun 25 08:14:11 2018 -0700
@@ -55,8 +55,9 @@
                 HandshakeMessage message) throws IOException {
             // The producing happens in client side only.
             ClientHandshakeContext chc = (ClientHandshakeContext)context;
-            SSLKeyExchange ke =
-                SSLKeyExchange.valueOf(chc.negotiatedCipherSuite.keyExchange);
+            SSLKeyExchange ke = SSLKeyExchange.valueOf(
+                        chc.negotiatedCipherSuite.keyExchange,
+                        chc.negotiatedProtocol);
             if (ke != null) {
                 for (Map.Entry<Byte, HandshakeProducer> hp :
                         ke.getHandshakeProducers(chc)) {
@@ -90,8 +91,9 @@
             ServerHandshakeContext shc = (ServerHandshakeContext)context;
             // clean up this consumer
             shc.handshakeConsumers.remove(SSLHandshake.CLIENT_KEY_EXCHANGE.id);
-            SSLKeyExchange ke =
-                SSLKeyExchange.valueOf(shc.negotiatedCipherSuite.keyExchange);
+            SSLKeyExchange ke = SSLKeyExchange.valueOf(
+                    shc.negotiatedCipherSuite.keyExchange,
+                    shc.negotiatedProtocol);
             if (ke != null) {
                 for (Map.Entry<Byte, SSLConsumer> hc :
                         ke.getHandshakeConsumers(shc)) {
--- a/src/java.base/share/classes/sun/security/ssl/DHClientKeyExchange.java	Sun Jun 24 13:34:42 2018 -0700
+++ b/src/java.base/share/classes/sun/security/ssl/DHClientKeyExchange.java	Mon Jun 25 08:14:11 2018 -0700
@@ -197,8 +197,9 @@
             chc.handshakeOutput.flush();
 
             // update the states
-            SSLKeyExchange ke =
-                SSLKeyExchange.valueOf(chc.negotiatedCipherSuite.keyExchange);
+            SSLKeyExchange ke = SSLKeyExchange.valueOf(
+                    chc.negotiatedCipherSuite.keyExchange,
+                    chc.negotiatedProtocol);
             if (ke == null) {
                 // unlikely
                 chc.conContext.fatal(Alert.INTERNAL_ERROR,
@@ -258,7 +259,8 @@
             }
 
             SSLKeyExchange ke = SSLKeyExchange.valueOf(
-                    shc.negotiatedCipherSuite.keyExchange);
+                    shc.negotiatedCipherSuite.keyExchange,
+                    shc.negotiatedProtocol);
             if (ke == null) {
                 // unlikely
                 shc.conContext.fatal(Alert.INTERNAL_ERROR,
--- a/src/java.base/share/classes/sun/security/ssl/ECDHClientKeyExchange.java	Sun Jun 24 13:34:42 2018 -0700
+++ b/src/java.base/share/classes/sun/security/ssl/ECDHClientKeyExchange.java	Mon Jun 25 08:14:11 2018 -0700
@@ -223,8 +223,9 @@
             chc.handshakeOutput.flush();
 
             // update the states
-            SSLKeyExchange ke =
-                SSLKeyExchange.valueOf(chc.negotiatedCipherSuite.keyExchange);
+            SSLKeyExchange ke = SSLKeyExchange.valueOf(
+                    chc.negotiatedCipherSuite.keyExchange,
+                    chc.negotiatedProtocol);
             if (ke == null) {
                 // unlikely
                 chc.conContext.fatal(Alert.INTERNAL_ERROR,
@@ -300,7 +301,8 @@
             }
 
             SSLKeyExchange ke = SSLKeyExchange.valueOf(
-                    shc.negotiatedCipherSuite.keyExchange);
+                    shc.negotiatedCipherSuite.keyExchange,
+                    shc.negotiatedProtocol);
             if (ke == null) {
                 // unlikely
                 shc.conContext.fatal(Alert.INTERNAL_ERROR,
@@ -405,8 +407,9 @@
             chc.handshakeOutput.flush();
 
             // update the states
-            SSLKeyExchange ke =
-                SSLKeyExchange.valueOf(chc.negotiatedCipherSuite.keyExchange);
+            SSLKeyExchange ke = SSLKeyExchange.valueOf(
+                    chc.negotiatedCipherSuite.keyExchange,
+                    chc.negotiatedProtocol);
             if (ke == null) {
                 // unlikely
                 chc.conContext.fatal(Alert.INTERNAL_ERROR,
@@ -474,7 +477,8 @@
             }
 
             SSLKeyExchange ke = SSLKeyExchange.valueOf(
-                    shc.negotiatedCipherSuite.keyExchange);
+                    shc.negotiatedCipherSuite.keyExchange,
+                    shc.negotiatedProtocol);
             if (ke == null) {
                 // unlikely
                 shc.conContext.fatal(Alert.INTERNAL_ERROR,
--- a/src/java.base/share/classes/sun/security/ssl/JsseJce.java	Sun Jun 24 13:34:42 2018 -0700
+++ b/src/java.base/share/classes/sun/security/ssl/JsseJce.java	Mon Jun 25 08:14:11 2018 -0700
@@ -100,37 +100,45 @@
      * Can be used for encryption, decryption, signing, verifying.
      */
     static final String CIPHER_RSA_PKCS1 = "RSA/ECB/PKCS1Padding";
+
     /**
      * JCE transformation string for the stream cipher RC4.
      */
     static final String CIPHER_RC4 = "RC4";
+
     /**
      * JCE transformation string for DES in CBC mode without padding.
      */
     static final String CIPHER_DES = "DES/CBC/NoPadding";
+
     /**
      * JCE transformation string for (3-key) Triple DES in CBC mode
      * without padding.
      */
     static final String CIPHER_3DES = "DESede/CBC/NoPadding";
+
     /**
      * JCE transformation string for AES in CBC mode
      * without padding.
      */
     static final String CIPHER_AES = "AES/CBC/NoPadding";
+
     /**
      * JCE transformation string for AES in GCM mode
      * without padding.
      */
     static final String CIPHER_AES_GCM = "AES/GCM/NoPadding";
+
     /**
      * JCA identifier string for DSA, i.e. a DSA with SHA-1.
      */
     static final String SIGNATURE_DSA = "DSA";
+
     /**
      * JCA identifier string for ECDSA, i.e. a ECDSA with SHA-1.
      */
     static final String SIGNATURE_ECDSA = "SHA1withECDSA";
+
     /**
      * JCA identifier string for Raw DSA, i.e. a DSA signature without
      * hashing where the application provides the SHA-1 hash of the data.
@@ -138,17 +146,20 @@
      * for compatibility.
      */
     static final String SIGNATURE_RAWDSA = "RawDSA";
+
     /**
      * JCA identifier string for Raw ECDSA, i.e. a DSA signature without
      * hashing where the application provides the SHA-1 hash of the data.
      */
     static final String SIGNATURE_RAWECDSA = "NONEwithECDSA";
+
     /**
      * JCA identifier string for Raw RSA, i.e. a RSA PKCS#1 v1.5 signature
      * without hashing where the application provides the hash of the data.
      * Used for RSA client authentication with a 36 byte hash.
      */
     static final String SIGNATURE_RAWRSA = "NONEwithRSA";
+
     /**
      * JCA identifier string for the SSL/TLS style RSA Signature. I.e.
      * an signature using RSA with PKCS#1 v1.5 padding signing a
--- a/src/java.base/share/classes/sun/security/ssl/RSAClientKeyExchange.java	Sun Jun 24 13:34:42 2018 -0700
+++ b/src/java.base/share/classes/sun/security/ssl/RSAClientKeyExchange.java	Mon Jun 25 08:14:11 2018 -0700
@@ -201,8 +201,9 @@
             chc.handshakeOutput.flush();
 
             // update the states
-            SSLKeyExchange ke =
-                SSLKeyExchange.valueOf(chc.negotiatedCipherSuite.keyExchange);
+            SSLKeyExchange ke = SSLKeyExchange.valueOf(
+                    chc.negotiatedCipherSuite.keyExchange,
+                    chc.negotiatedProtocol);
             if (ke == null) {   // unlikely
                 chc.conContext.fatal(Alert.INTERNAL_ERROR,
                         "Not supported key exchange type");
@@ -291,8 +292,9 @@
             }
 
             // update the states
-            SSLKeyExchange ke =
-                SSLKeyExchange.valueOf(shc.negotiatedCipherSuite.keyExchange);
+            SSLKeyExchange ke = SSLKeyExchange.valueOf(
+                    shc.negotiatedCipherSuite.keyExchange,
+                    shc.negotiatedProtocol);
             if (ke == null) {   // unlikely
                 shc.conContext.fatal(Alert.INTERNAL_ERROR,
                         "Not supported key exchange type");
--- a/src/java.base/share/classes/sun/security/ssl/SSLKeyExchange.java	Sun Jun 24 13:34:42 2018 -0700
+++ b/src/java.base/share/classes/sun/security/ssl/SSLKeyExchange.java	Mon Jun 25 08:14:11 2018 -0700
@@ -193,8 +193,9 @@
 
     // SSL 3.0 - (D)TLS 1.2
     static SSLKeyExchange valueOf(
-            CipherSuite.KeyExchange keyExchange) {
-        if (keyExchange == null) {
+            CipherSuite.KeyExchange keyExchange,
+            ProtocolVersion protocolVersion) {
+        if (keyExchange == null || protocolVersion == null) {
             return null;
         }
 
@@ -208,7 +209,11 @@
             case K_DHE_DSS_EXPORT:
                 return SSLKeyExDHEDSSExport.KE;
             case K_DHE_RSA:
-                return SSLKeyExDHERSA.KE;
+                if (protocolVersion.useTLS12PlusSpec()) {   // (D)TLS 1.2
+                    return SSLKeyExDHERSAOrPSS.KE;
+                } else {    // SSL 3.0, TLS 1.0/1.1
+                    return SSLKeyExDHERSA.KE;
+                }
             case K_DHE_RSA_EXPORT:
                 return SSLKeyExDHERSAExport.KE;
             case K_DH_ANON:
@@ -222,7 +227,11 @@
             case K_ECDHE_ECDSA:
                 return SSLKeyExECDHEECDSA.KE;
             case K_ECDHE_RSA:
-                return SSLKeyExECDHERSA.KE;
+                if (protocolVersion.useTLS12PlusSpec()) {   // (D)TLS 1.2
+                    return SSLKeyExECDHERSAOrPSS.KE;
+                } else {    // SSL 3.0, TLS 1.0/1.1
+                    return SSLKeyExECDHERSA.KE;
+                }
             case K_ECDH_ANON:
                 return SSLKeyExECDHANON.KE;
         }
@@ -266,6 +275,11 @@
                 X509Authentication.RSA, T12KeyAgreement.DHE);
     }
 
+    private static class SSLKeyExDHERSAOrPSS {
+        private static SSLKeyExchange KE = new SSLKeyExchange(
+                X509Authentication.RSA_OR_PSS, T12KeyAgreement.DHE);
+    }
+
     private static class SSLKeyExDHERSAExport {
         private static SSLKeyExchange KE = new SSLKeyExchange(
                 X509Authentication.RSA, T12KeyAgreement.DHE_EXPORT);
@@ -301,6 +315,11 @@
                 X509Authentication.RSA, T12KeyAgreement.ECDHE);
     }
 
+    private static class SSLKeyExECDHERSAOrPSS {
+        private static SSLKeyExchange KE = new SSLKeyExchange(
+                X509Authentication.RSA_OR_PSS, T12KeyAgreement.ECDHE);
+    }
+
     private static class SSLKeyExECDHANON {
         private static SSLKeyExchange KE = new SSLKeyExchange(
                 null, T12KeyAgreement.ECDHE);
--- a/src/java.base/share/classes/sun/security/ssl/ServerHello.java	Sun Jun 24 13:34:42 2018 -0700
+++ b/src/java.base/share/classes/sun/security/ssl/ServerHello.java	Mon Jun 25 08:14:11 2018 -0700
@@ -415,7 +415,8 @@
                     }
                 }
 
-                SSLKeyExchange ke = SSLKeyExchange.valueOf(cs.keyExchange);
+                SSLKeyExchange ke = SSLKeyExchange.valueOf(
+                        cs.keyExchange, shc.negotiatedProtocol);
                 if (ke == null) {
                     continue;
                 }
@@ -439,7 +440,8 @@
             }
 
             for (CipherSuite cs : legacySuites) {
-                SSLKeyExchange ke = SSLKeyExchange.valueOf(cs.keyExchange);
+                SSLKeyExchange ke = SSLKeyExchange.valueOf(
+                        cs.keyExchange,  shc.negotiatedProtocol);
                 if (ke != null) {
                     SSLPossession[] hcds = ke.createPossessions(shc);
                     if ((hcds != null) && (hcds.length != 0)) {
@@ -1122,7 +1124,8 @@
                         SSLHandshake.FINISHED);
             } else {
                 SSLKeyExchange ke = SSLKeyExchange.valueOf(
-                        chc.negotiatedCipherSuite.keyExchange);
+                        chc.negotiatedCipherSuite.keyExchange,
+                        chc.negotiatedProtocol);
                 chc.handshakeKeyExchange = ke;
                 if (ke != null) {
                     for (SSLHandshake handshake :
@@ -1154,7 +1157,8 @@
             HKDF hkdf = new HKDF(hashAlg.name);
             byte[] zeros = new byte[hashAlg.hashLength];
             SecretKey earlySecret = hkdf.extract(zeros, psk, "TlsEarlySecret");
-            hc.handshakeKeyDerivation = new SSLSecretDerivation(hc, earlySecret);
+            hc.handshakeKeyDerivation =
+                    new SSLSecretDerivation(hc, earlySecret);
         } catch  (GeneralSecurityException gse) {
             throw (SSLHandshakeException) new SSLHandshakeException(
                 "Could not generate secret").initCause(gse);
--- a/src/java.base/share/classes/sun/security/ssl/ServerKeyExchange.java	Sun Jun 24 13:34:42 2018 -0700
+++ b/src/java.base/share/classes/sun/security/ssl/ServerKeyExchange.java	Mon Jun 25 08:14:11 2018 -0700
@@ -55,8 +55,9 @@
             // The producing happens in server side only.
             ServerHandshakeContext shc = (ServerHandshakeContext)context;
 
-            SSLKeyExchange ke =
-                SSLKeyExchange.valueOf(shc.negotiatedCipherSuite.keyExchange);
+            SSLKeyExchange ke = SSLKeyExchange.valueOf(
+                    shc.negotiatedCipherSuite.keyExchange,
+                    shc.negotiatedProtocol);
             if (ke != null) {
                 for (Map.Entry<Byte, HandshakeProducer> hc :
                         ke.getHandshakeProducers(shc)) {
@@ -92,8 +93,9 @@
             // clean up this consumer
             chc.handshakeConsumers.remove(SSLHandshake.SERVER_KEY_EXCHANGE.id);
 
-            SSLKeyExchange ke =
-                SSLKeyExchange.valueOf(chc.negotiatedCipherSuite.keyExchange);
+            SSLKeyExchange ke = SSLKeyExchange.valueOf(
+                    chc.negotiatedCipherSuite.keyExchange,
+                    chc.negotiatedProtocol);
             if (ke != null) {
                 for (Map.Entry<Byte, SSLConsumer> hc :
                         ke.getHandshakeConsumers(chc)) {
--- a/src/java.base/share/classes/sun/security/ssl/SignatureScheme.java	Sun Jun 24 13:34:42 2018 -0700
+++ b/src/java.base/share/classes/sun/security/ssl/SignatureScheme.java	Mon Jun 25 08:14:11 2018 -0700
@@ -76,15 +76,15 @@
     RSA_PSS_RSAE_SHA256     (0x0804, "rsa_pss_rsae_sha256",
                                     "RSASSA-PSS", "RSA",
                                     SigAlgParamSpec.RSA_PSS_SHA256, 528,
-                                    ProtocolVersion.PROTOCOLS_TO_13),
+                                    ProtocolVersion.PROTOCOLS_12_13),
     RSA_PSS_RSAE_SHA384     (0x0805, "rsa_pss_rsae_sha384",
                                     "RSASSA-PSS", "RSA",
                                     SigAlgParamSpec.RSA_PSS_SHA384, 784,
-                                    ProtocolVersion.PROTOCOLS_TO_13),
+                                    ProtocolVersion.PROTOCOLS_12_13),
     RSA_PSS_RSAE_SHA512     (0x0806, "rsa_pss_rsae_sha512",
                                     "RSASSA-PSS", "RSA",
                                     SigAlgParamSpec.RSA_PSS_SHA512, 1040,
-                                    ProtocolVersion.PROTOCOLS_TO_13),
+                                    ProtocolVersion.PROTOCOLS_12_13),
 
     // RSASSA-PSS algorithms with public key OID RSASSA-PSS
     //
@@ -93,15 +93,15 @@
     RSA_PSS_PSS_SHA256      (0x0809, "rsa_pss_pss_sha256",
                                     "RSASSA-PSS", "RSASSA-PSS",
                                     SigAlgParamSpec.RSA_PSS_SHA256, 528,
-                                    ProtocolVersion.PROTOCOLS_TO_13),
+                                    ProtocolVersion.PROTOCOLS_12_13),
     RSA_PSS_PSS_SHA384      (0x080A, "rsa_pss_pss_sha384",
                                     "RSASSA-PSS", "RSASSA-PSS",
                                     SigAlgParamSpec.RSA_PSS_SHA384, 784,
-                                    ProtocolVersion.PROTOCOLS_TO_13),
+                                    ProtocolVersion.PROTOCOLS_12_13),
     RSA_PSS_PSS_SHA512      (0x080B, "rsa_pss_pss_sha512",
                                     "RSASSA-PSS", "RSASSA-PSS",
                                     SigAlgParamSpec.RSA_PSS_SHA512, 1040,
-                                    ProtocolVersion.PROTOCOLS_TO_13),
+                                    ProtocolVersion.PROTOCOLS_12_13),
 
     // RSASSA-PKCS1-v1_5 algorithms
     RSA_PKCS1_SHA256        (0x0401, "rsa_pkcs1_sha256", "SHA256withRSA",
--- a/src/java.base/share/classes/sun/security/ssl/X509Authentication.java	Sun Jun 24 13:34:42 2018 -0700
+++ b/src/java.base/share/classes/sun/security/ssl/X509Authentication.java	Mon Jun 25 08:14:11 2018 -0700
@@ -39,10 +39,29 @@
 import sun.security.ssl.SupportedGroupsExtension.SupportedGroups;
 
 enum X509Authentication implements SSLAuthentication {
-    RSA     ("RSA",        new X509PossessionGenerator("RSA")),
-    RSA_PSS ("RSASSA-PSS", new X509PossessionGenerator("RSASSA-PSS")),
-    DSA     ("DSA",        new X509PossessionGenerator("DSA")),
-    EC      ("EC",         new X509PossessionGenerator("EC"));
+    // Require rsaEncryption public key
+    RSA         ("RSA",         new X509PossessionGenerator(
+                                    new String[]{"RSA"})),
+
+    // Require RSASSA-PSS public key
+    RSASSA_PSS  ("RSASSA-PSS",  new X509PossessionGenerator(
+                                    new String[] {"RSASSA-PSS"})),
+
+    // Require rsaEncryption or RSASSA-PSS public key
+    //
+    // Note that this is a specifical scheme for TLS 1.2. (EC)DHE_RSA cipher
+    // suites of TLS 1.2 can use either rsaEncryption or RSASSA-PSS public
+    // key for authentication and handshake.
+    RSA_OR_PSS  ("RSA_OR_PSS",  new X509PossessionGenerator(
+                                    new String[] {"RSA", "RSASSA-PSS"})),
+
+    // Require DSA public key
+    DSA         ("DSA",         new X509PossessionGenerator(
+                                    new String[] {"DSA"})),
+
+    // Require EC public key
+    EC          ("EC",          new X509PossessionGenerator(
+                                    new String[] {"EC"}));
 
     final String keyType;
     final SSLPossessionGenerator possessionGenerator;
@@ -53,9 +72,9 @@
         this.possessionGenerator = possessionGenerator;
     }
 
-    static X509Authentication nameOf(String keyType) {
+    static X509Authentication valueOf(SignatureScheme signatureScheme) {
         for (X509Authentication au: X509Authentication.values()) {
-            if (au.keyType.equals(keyType)) {
+            if (au.keyType.equals(signatureScheme.keyAlgorithm)) {
                 return au;
             }
         }
@@ -122,24 +141,38 @@
 
     private static final
             class X509PossessionGenerator implements SSLPossessionGenerator {
-        final String keyType;
+        private final String[] keyTypes;
 
-        private X509PossessionGenerator(String keyType) {
-            this.keyType = keyType;
+        private X509PossessionGenerator(String[] keyTypes) {
+            this.keyTypes = keyTypes;
         }
 
         @Override
         public SSLPossession createPossession(HandshakeContext context) {
             if (context.sslConfig.isClientMode) {
-                return createClientPossession((ClientHandshakeContext)context);
+                for (String keyType : keyTypes) {
+                    SSLPossession poss = createClientPossession(
+                            (ClientHandshakeContext)context, keyType);
+                    if (poss != null) {
+                        return poss;
+                    }
+                }
             } else {
-                return createServerPossession((ServerHandshakeContext)context);
+                for (String keyType : keyTypes) {
+                    SSLPossession poss = createServerPossession(
+                            (ServerHandshakeContext)context, keyType);
+                    if (poss != null) {
+                        return poss;
+                    }
+                }
             }
+
+            return null;
         }
 
         // Used by TLS 1.3 only.
         private SSLPossession createClientPossession(
-                ClientHandshakeContext chc) {
+                ClientHandshakeContext chc, String keyType) {
             X509ExtendedKeyManager km = chc.sslContext.getX509KeyManager();
             String clientAlias = null;
             if (chc.conContext.transport instanceof SSLSocketImpl) {
@@ -192,7 +225,7 @@
         }
 
         private SSLPossession createServerPossession(
-                ServerHandshakeContext shc) {
+                ServerHandshakeContext shc, String keyType) {
             X509ExtendedKeyManager km = shc.sslContext.getX509KeyManager();
             String serverAlias = null;
             if (shc.conContext.transport instanceof SSLSocketImpl) {
--- a/src/java.base/share/classes/sun/security/ssl/X509KeyManagerImpl.java	Sun Jun 24 13:34:42 2018 -0700
+++ b/src/java.base/share/classes/sun/security/ssl/X509KeyManagerImpl.java	Mon Jun 25 08:14:11 2018 -0700
@@ -39,7 +39,6 @@
 import java.security.cert.CertificateException;
 import java.security.cert.X509Certificate;
 import java.util.*;
-import static java.util.Locale.ENGLISH;
 import java.util.concurrent.atomic.AtomicLong;
 import javax.net.ssl.*;
 import sun.security.provider.certpath.AlgorithmChecker;
@@ -292,6 +291,7 @@
         // In TLS 1.2, the signature algorithm  has been obsoleted by the
         // supported_signature_algorithms, and the certificate type no longer
         // restricts the algorithm used to sign the certificate.
+        //
         // However, because we don't support certificate type checking other
         // than rsa_sign, dss_sign and ecdsa_sign, we don't have to check the
         // protocol version here.
@@ -323,8 +323,10 @@
                 // Check the signature algorithm of the certificate itself.
                 // Look for the "withRSA" in "SHA1withRSA", etc.
                 X509Certificate issuer = (X509Certificate)chain[0];
-                String sigAlgName = issuer.getSigAlgName().toUpperCase(ENGLISH);
-                String pattern = "WITH" + sigKeyAlgorithm.toUpperCase(ENGLISH);
+                String sigAlgName =
+                        issuer.getSigAlgName().toUpperCase(Locale.ENGLISH);
+                String pattern =
+                        "WITH" + sigKeyAlgorithm.toUpperCase(Locale.ENGLISH);
                 return sigAlgName.contains(pattern);
             }
         }
@@ -434,7 +436,7 @@
                                     null, null);
                 if (results != null) {
                     if (allResults == null) {
-                        allResults = new ArrayList<EntryStatus>();
+                        allResults = new ArrayList<>();
                     }
                     allResults.addAll(results);
                 }
@@ -539,9 +541,10 @@
             return (bit < keyUsage.length) && keyUsage[bit];
         }
 
-        // check if this certificate is appropriate for this type of use
-        // first check extensions, if they match, check expiration
-        // note: we may want to move this code into the sun.security.validator
+        // Check if this certificate is appropriate for this type of use
+        // first check extensions, if they match, check expiration.
+        //
+        // Note: we may want to move this code into the sun.security.validator
         // package
         CheckResult check(X509Certificate cert, Date date,
                 List<SNIServerName> serverNames, String idAlgorithm) {
@@ -565,20 +568,25 @@
                 boolean[] ku = cert.getKeyUsage();
                 if (ku != null) {
                     String algorithm = cert.getPublicKey().getAlgorithm();
-                    boolean kuSignature = getBit(ku, 0);
+                    boolean supportsDigitalSignature = getBit(ku, 0);
                     switch (algorithm) {
                         case "RSA":
                             // require either signature bit
                             // or if server also allow key encipherment bit
-                            if (kuSignature == false) {
+                            if (!supportsDigitalSignature) {
                                 if (this == CLIENT || getBit(ku, 2) == false) {
                                     return CheckResult.EXTENSION_MISMATCH;
                                 }
                             }
                             break;
+                        case "RSASSA-PSS":
+                            if (!supportsDigitalSignature && (this == SERVER)) {
+                                return CheckResult.EXTENSION_MISMATCH;
+                            }
+                            break;
                         case "DSA":
                             // require signature bit
-                            if (kuSignature == false) {
+                            if (!supportsDigitalSignature) {
                                 return CheckResult.EXTENSION_MISMATCH;
                             }
                             break;
@@ -590,7 +598,7 @@
                             break;
                         case "EC":
                             // require signature bit
-                            if (kuSignature == false) {
+                            if (!supportsDigitalSignature) {
                                 return CheckResult.EXTENSION_MISMATCH;
                             }
                             // For servers, also require key agreement.
@@ -811,7 +819,7 @@
                 return Collections.singletonList(status);
             } else {
                 if (results == null) {
-                    results = new ArrayList<EntryStatus>();
+                    results = new ArrayList<>();
                 }
                 results.add(status);
             }
--- a/test/jdk/sun/security/ssl/ClientHandshaker/LengthCheckTest.java	Sun Jun 24 13:34:42 2018 -0700
+++ b/test/jdk/sun/security/ssl/ClientHandshaker/LengthCheckTest.java	Mon Jun 25 08:14:11 2018 -0700
@@ -268,7 +268,7 @@
                 runDelegatedTasks(serverResult, serverEngine);
                 sTOc.flip();
                 dumpByteBuffer("SERVER-TO-CLIENT", sTOc);
-    
+
                 // We expect to see the server generate an alert here
                 serverResult = serverEngine.wrap(serverOut, sTOc);
                 log("server wrap: ", serverResult);
--- a/test/jdk/sun/security/ssl/SSLEngineImpl/CloseEngineException.java	Sun Jun 24 13:34:42 2018 -0700
+++ b/test/jdk/sun/security/ssl/SSLEngineImpl/CloseEngineException.java	Mon Jun 25 08:14:11 2018 -0700
@@ -129,7 +129,7 @@
                 log("unwrap1: " + result1);
                 log("twoToOne  = " + twoToOne);
                 log("");
- 
+
                 twoToOne.compact();
             }
             if (!isEngineClosed(ssle2)) {
--- a/test/jdk/sun/security/ssl/SSLEngineImpl/SSLEngineKeyLimit.java	Sun Jun 24 13:34:42 2018 -0700
+++ b/test/jdk/sun/security/ssl/SSLEngineImpl/SSLEngineKeyLimit.java	Mon Jun 25 08:14:11 2018 -0700
@@ -181,13 +181,15 @@
     private static void doTask(SSLEngineResult result,
             SSLEngine engine) throws Exception {
 
-        if (result.getHandshakeStatus() == SSLEngineResult.HandshakeStatus.NEED_TASK) {
+        if (result.getHandshakeStatus() ==
+                SSLEngineResult.HandshakeStatus.NEED_TASK) {
             Runnable runnable;
             while ((runnable = engine.getDelegatedTask()) != null) {
                 print("\trunning delegated task...");
                 runnable.run();
             }
-            SSLEngineResult.HandshakeStatus hsStatus = engine.getHandshakeStatus();
+            SSLEngineResult.HandshakeStatus hsStatus =
+                    engine.getHandshakeStatus();
             if (hsStatus == SSLEngineResult.HandshakeStatus.NEED_TASK) {
                 throw new Exception(
                     "handshake shouldn't need additional tasks");
@@ -247,7 +249,8 @@
                             " cap: " + getWriteBuf().capacity());
                 }
                 if (again && r.getStatus() == SSLEngineResult.Status.OK &&
-                        r.getHandshakeStatus() == SSLEngineResult.HandshakeStatus.NEED_WRAP) {
+                        r.getHandshakeStatus() ==
+                                SSLEngineResult.HandshakeStatus.NEED_WRAP) {
                     print("again");
                     again = false;
                     continue;
@@ -317,7 +320,8 @@
                     buf2.flip();
                     r = eng.wrap(buf2, getWriteBuf());
                     log("read wrap", r);
-                    if (debug) { //&& r.getStatus() != SSLEngineResult.Status.OK) {
+                    if (debug) {
+                             // && r.getStatus() != SSLEngineResult.Status.OK) {
                         print("buf2 pos: " + buf2.position() +
                                 " rem: " + buf2.remaining() +
                                 " cap: " + buf2.capacity());
@@ -326,7 +330,8 @@
                                 " cap: " + getWriteBuf().capacity());
                     }
                     if (again && r.getStatus() == SSLEngineResult.Status.OK &&
-                            r.getHandshakeStatus() == SSLEngineResult.HandshakeStatus.NEED_WRAP) {
+                            r.getHandshakeStatus() ==
+                                SSLEngineResult.HandshakeStatus.NEED_WRAP) {
                         buf2.compact();
                         again = false;
                         continue;
@@ -347,7 +352,8 @@
                         buf.clear();
                         r = eng.unwrap(getReadBuf(), buf);
                         log("read unwrap", r);
-                        if (debug && r.getStatus() != SSLEngineResult.Status.OK) {
+                        if (debug &&
+                                r.getStatus() != SSLEngineResult.Status.OK) {
                             print("buf pos " + buf.position() +
                                     " rem: " + buf.remaining() +
                                     " lim: " + buf.limit() +
@@ -360,7 +366,8 @@
                         }
 
                     if (again && r.getStatus() == SSLEngineResult.Status.OK &&
-                            r.getHandshakeStatus() == SSLEngineResult.HandshakeStatus.NEED_UNWRAP) {
+                            r.getHandshakeStatus() ==
+                                SSLEngineResult.HandshakeStatus.NEED_UNWRAP) {
                         buf.clear();
                         print("again");
                         again = false;
@@ -398,12 +405,14 @@
         KeyStore ks = KeyStore.getInstance(
                 new File(System.getProperty("javax.net.ssl.keyStore")),
                 passwd.toCharArray());
-        KeyManagerFactory kmf =
-                KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
+        KeyManagerFactory kmf = KeyManagerFactory.getInstance(
+                KeyManagerFactory.getDefaultAlgorithm());
         kmf.init(ks, passwd.toCharArray());
-        TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
+        TrustManagerFactory tmf = TrustManagerFactory.getInstance(
+                TrustManagerFactory.getDefaultAlgorithm());
         tmf.init(ks);
-        sc.init(kmf.getKeyManagers(), tmf.getTrustManagers(), new SecureRandom());
+        sc.init(kmf.getKeyManagers(),
+                tmf.getTrustManagers(), new SecureRandom());
         return sc;
     }
 
@@ -414,7 +423,7 @@
             eng.setUseClientMode(false);
             eng.setNeedClientAuth(true);
         }
-        
+
         public void run() {
             try {
                 if (serverwrite) {