changeset 57700:14e425e3a23c

8231780: Better TLS messaging support Reviewed-by: ascarpino, rhalade, mschoene
author jnimeh
date Mon, 28 Oct 2019 18:53:51 -0700
parents bba2f6e36c17
children d78e03ecb55f
files src/java.base/share/classes/sun/security/ssl/Alert.java src/java.base/share/classes/sun/security/ssl/CertificateMessage.java src/java.base/share/classes/sun/security/ssl/CertificateVerify.java src/java.base/share/classes/sun/security/ssl/Finished.java
diffstat 4 files changed, 83 insertions(+), 2 deletions(-) [+]
line wrap: on
line diff
--- a/src/java.base/share/classes/sun/security/ssl/Alert.java	Tue Oct 22 17:25:34 2019 -0400
+++ b/src/java.base/share/classes/sun/security/ssl/Alert.java	Mon Oct 28 18:53:51 2019 -0700
@@ -271,8 +271,14 @@
                                     ClientAuthType.CLIENT_AUTH_REQUESTED)) {
                         throw tc.fatal(Alert.HANDSHAKE_FAILURE,
                             "received handshake warning: " + alert.description);
-                    }  // Otherwise, ignore the warning
-                }   // Otherwise, ignore the warning.
+                    } else {
+                        // Otherwise ignore the warning but remove the
+                        // CertificateVerify handshake consumer so the state
+                        // machine doesn't expect it.
+                        tc.handshakeContext.handshakeConsumers.remove(
+                                SSLHandshake.CERTIFICATE_VERIFY.id);
+                    }
+                }  // Otherwise, ignore the warning
             } else {    // fatal or unknown
                 String diagnostic;
                 if (alert == null) {
--- a/src/java.base/share/classes/sun/security/ssl/CertificateMessage.java	Tue Oct 22 17:25:34 2019 -0400
+++ b/src/java.base/share/classes/sun/security/ssl/CertificateMessage.java	Mon Oct 28 18:53:51 2019 -0700
@@ -371,6 +371,10 @@
                 T12CertificateMessage certificateMessage )throws IOException {
             List<byte[]> encodedCerts = certificateMessage.encodedCertChain;
             if (encodedCerts == null || encodedCerts.isEmpty()) {
+                // For empty Certificate messages, we should not expect
+                // a CertificateVerify message to follow
+                shc.handshakeConsumers.remove(
+                        SSLHandshake.CERTIFICATE_VERIFY.id);
                 if (shc.sslConfig.clientAuthType !=
                         ClientAuthType.CLIENT_AUTH_REQUESTED) {
                     // unexpected or require client authentication
@@ -1165,6 +1169,10 @@
                 T13CertificateMessage certificateMessage )throws IOException {
             if (certificateMessage.certEntries == null ||
                     certificateMessage.certEntries.isEmpty()) {
+                // For empty Certificate messages, we should not expect
+                // a CertificateVerify message to follow
+                shc.handshakeConsumers.remove(
+                        SSLHandshake.CERTIFICATE_VERIFY.id);
                 if (shc.sslConfig.clientAuthType == CLIENT_AUTH_REQUIRED) {
                     throw shc.conContext.fatal(Alert.BAD_CERTIFICATE,
                         "Empty client certificate chain");
--- a/src/java.base/share/classes/sun/security/ssl/CertificateVerify.java	Tue Oct 22 17:25:34 2019 -0400
+++ b/src/java.base/share/classes/sun/security/ssl/CertificateVerify.java	Mon Oct 28 18:53:51 2019 -0700
@@ -287,6 +287,17 @@
                 ByteBuffer message) throws IOException {
             // The consuming happens in server side only.
             ServerHandshakeContext shc = (ServerHandshakeContext)context;
+
+            // Clean up this consumer
+            shc.handshakeConsumers.remove(SSLHandshake.CERTIFICATE_VERIFY.id);
+
+            // Ensure that the CV message follows the CKE
+            if (shc.handshakeConsumers.containsKey(
+                    SSLHandshake.CLIENT_KEY_EXCHANGE.id)) {
+                throw shc.conContext.fatal(Alert.UNEXPECTED_MESSAGE,
+                        "Unexpected CertificateVerify handshake message");
+            }
+
             S30CertificateVerifyMessage cvm =
                     new S30CertificateVerifyMessage(shc, message);
             if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) {
@@ -529,6 +540,17 @@
                 ByteBuffer message) throws IOException {
             // The consuming happens in server side only.
             ServerHandshakeContext shc = (ServerHandshakeContext)context;
+
+            // Clean up this consumer
+            shc.handshakeConsumers.remove(SSLHandshake.CERTIFICATE_VERIFY.id);
+
+            // Ensure that the CV message follows the CKE
+            if (shc.handshakeConsumers.containsKey(
+                    SSLHandshake.CLIENT_KEY_EXCHANGE.id)) {
+                throw shc.conContext.fatal(Alert.UNEXPECTED_MESSAGE,
+                        "Unexpected CertificateVerify handshake message");
+            }
+
             T10CertificateVerifyMessage cvm =
                     new T10CertificateVerifyMessage(shc, message);
             if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) {
@@ -767,6 +789,17 @@
                 ByteBuffer message) throws IOException {
             // The consuming happens in server side only.
             ServerHandshakeContext shc = (ServerHandshakeContext)context;
+
+            // Clean up this consumer
+            shc.handshakeConsumers.remove(SSLHandshake.CERTIFICATE_VERIFY.id);
+
+            // Ensure that the CV message follows the CKE
+            if (shc.handshakeConsumers.containsKey(
+                    SSLHandshake.CLIENT_KEY_EXCHANGE.id)) {
+                throw shc.conContext.fatal(Alert.UNEXPECTED_MESSAGE,
+                        "Unexpected CertificateVerify handshake message");
+            }
+
             T12CertificateVerifyMessage cvm =
                     new T12CertificateVerifyMessage(shc, message);
             if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) {
@@ -1120,6 +1153,10 @@
                 ByteBuffer message) throws IOException {
             // The producing happens in handshake context only.
             HandshakeContext hc = (HandshakeContext)context;
+
+            // Clean up this consumer
+            hc.handshakeConsumers.remove(SSLHandshake.CERTIFICATE_VERIFY.id);
+
             T13CertificateVerifyMessage cvm =
                     new T13CertificateVerifyMessage(hc, message);
             if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) {
--- a/src/java.base/share/classes/sun/security/ssl/Finished.java	Tue Oct 22 17:25:34 2019 -0400
+++ b/src/java.base/share/classes/sun/security/ssl/Finished.java	Mon Oct 28 18:53:51 2019 -0700
@@ -589,6 +589,16 @@
 
         private void onConsumeFinished(ServerHandshakeContext shc,
                 ByteBuffer message) throws IOException {
+            // Make sure that any expected CertificateVerify message
+            // has been received and processed.
+            if (!shc.isResumption) {
+                if (shc.handshakeConsumers.containsKey(
+                        SSLHandshake.CERTIFICATE_VERIFY.id)) {
+                    throw shc.conContext.fatal(Alert.UNEXPECTED_MESSAGE,
+                            "Unexpected Finished handshake message");
+                }
+            }
+
             FinishedMessage fm = new FinishedMessage(shc, message);
             if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) {
                 SSLLogger.fine(
@@ -883,6 +893,16 @@
 
         private void onConsumeFinished(ClientHandshakeContext chc,
                 ByteBuffer message) throws IOException {
+            // Make sure that any expected CertificateVerify message
+            // has been received and processed.
+            if (!chc.isResumption) {
+                if (chc.handshakeConsumers.containsKey(
+                        SSLHandshake.CERTIFICATE_VERIFY.id)) {
+                    throw chc.conContext.fatal(Alert.UNEXPECTED_MESSAGE,
+                            "Unexpected Finished handshake message");
+                }
+            }
+
             FinishedMessage fm = new FinishedMessage(chc, message);
             if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) {
                 SSLLogger.fine(
@@ -1005,6 +1025,16 @@
 
         private void onConsumeFinished(ServerHandshakeContext shc,
                 ByteBuffer message) throws IOException {
+            // Make sure that any expected CertificateVerify message
+            // has been received and processed.
+            if (!shc.isResumption) {
+                if (shc.handshakeConsumers.containsKey(
+                        SSLHandshake.CERTIFICATE_VERIFY.id)) {
+                    throw shc.conContext.fatal(Alert.UNEXPECTED_MESSAGE,
+                            "Unexpected Finished handshake message");
+                }
+            }
+
             FinishedMessage fm = new FinishedMessage(shc, message);
             if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) {
                 SSLLogger.fine(