changeset 7768:73424f010d46

8046656: Update protocol support Reviewed-by: mullan, wetmore Contributed-by: jamil.nimeh@oracle.com
author igerasim
date Mon, 01 Sep 2014 12:13:32 +0400
parents 0ca149ae5a23
children 1549349f6eb1
files src/share/classes/sun/security/ssl/Handshaker.java src/share/classes/sun/security/ssl/SSLEngineImpl.java src/share/classes/sun/security/ssl/SSLSocketImpl.java
diffstat 3 files changed, 96 insertions(+), 40 deletions(-) [+]
line wrap: on
line diff
--- a/src/share/classes/sun/security/ssl/Handshaker.java	Tue Aug 26 15:53:05 2014 +0100
+++ b/src/share/classes/sun/security/ssl/Handshaker.java	Mon Sep 01 12:13:32 2014 +0400
@@ -65,27 +65,27 @@
     ProtocolVersion protocolVersion;
 
     // the currently active protocol version during a renegotiation
-    ProtocolVersion     activeProtocolVersion;
+    ProtocolVersion activeProtocolVersion;
 
     // security parameters for secure renegotiation.
-    boolean             secureRenegotiation;
-    byte[]              clientVerifyData;
-    byte[]              serverVerifyData;
+    boolean secureRenegotiation;
+    byte[] clientVerifyData;
+    byte[] serverVerifyData;
 
     // Is it an initial negotiation  or a renegotiation?
-    boolean                     isInitialHandshake;
+    boolean isInitialHandshake;
 
     // List of enabled protocols
-    private ProtocolList        enabledProtocols;
+    private ProtocolList enabledProtocols;
 
     // List of enabled CipherSuites
-    private CipherSuiteList     enabledCipherSuites;
+    private CipherSuiteList enabledCipherSuites;
 
     // The endpoint identification protocol
-    String              identificationProtocol;
+    String identificationProtocol;
 
     // The cryptographic algorithm constraints
-    private AlgorithmConstraints    algorithmConstraints = null;
+    private AlgorithmConstraints algorithmConstraints = null;
 
     // Local supported signature and algorithms
     Collection<SignatureAndHashAlgorithm> localSupportedSignAlgs;
@@ -94,15 +94,13 @@
     Collection<SignatureAndHashAlgorithm> peerSupportedSignAlgs;
 
     /*
-
-    /*
      * List of active protocols
      *
      * Active protocols is a subset of enabled protocols, and will
      * contain only those protocols that have vaild cipher suites
      * enabled.
      */
-    private ProtocolList       activeProtocols;
+    private ProtocolList activeProtocols;
 
     /*
      * List of active cipher suites
@@ -110,33 +108,37 @@
      * Active cipher suites is a subset of enabled cipher suites, and will
      * contain only those cipher suites available for the active protocols.
      */
-    private CipherSuiteList    activeCipherSuites;
+    private CipherSuiteList activeCipherSuites;
 
-    private boolean             isClient;
-    private boolean             needCertVerify;
+    private boolean isClient;
+    private boolean needCertVerify;
 
-    SSLSocketImpl               conn = null;
-    SSLEngineImpl               engine = null;
+    SSLSocketImpl conn = null;
+    SSLEngineImpl engine = null;
 
-    HandshakeHash               handshakeHash;
-    HandshakeInStream           input;
-    HandshakeOutStream          output;
-    int                         state;
-    SSLContextImpl              sslContext;
-    RandomCookie                clnt_random, svr_random;
-    SSLSessionImpl              session;
+    HandshakeHash handshakeHash;
+    HandshakeInStream input;
+    HandshakeOutStream output;
+    int state;
+    SSLContextImpl sslContext;
+    RandomCookie clnt_random, svr_random;
+    SSLSessionImpl session;
 
     // current CipherSuite. Never null, initially SSL_NULL_WITH_NULL_NULL
-    CipherSuite         cipherSuite;
+    CipherSuite cipherSuite;
 
     // current key exchange. Never null, initially K_NULL
-    KeyExchange         keyExchange;
+    KeyExchange keyExchange;
 
-    /* True if this session is being resumed (fast handshake) */
-    boolean             resumingSession;
+    // True if this session is being resumed (fast handshake)
+    boolean resumingSession;
 
-    /* True if it's OK to start a new SSL session */
-    boolean             enableNewSession;
+    // True if it's OK to start a new SSL session
+    boolean enableNewSession;
+
+    // True if session keys have been calculated and the caller may receive
+    // and process a ChangeCipherSpec message
+    private boolean sessKeysCalculated;
 
     // Temporary storage for the individual keys. Set by
     // calculateConnectionKeys() and cleared once the ciphers are
@@ -161,7 +163,7 @@
     // here instead of using this lock.  Consider changing.
     private Object thrownLock = new Object();
 
-    /* Class and subclass dynamic debugging support */
+    // Class and subclass dynamic debugging support
     static final Debug debug = Debug.getInstance("ssl");
 
     // By default, disable the unsafe legacy session renegotiation
@@ -228,6 +230,7 @@
         this.serverVerifyData = serverVerifyData;
         enableNewSession = true;
         invalidated = false;
+        sessKeysCalculated = false;
 
         setCipherSuite(CipherSuite.C_NULL);
         setEnabledProtocols(enabledProtocols);
@@ -1140,6 +1143,10 @@
             throw new ProviderException(e);
         }
 
+        // Mark a flag that allows outside entities (like SSLSocket/SSLEngine)
+        // determine if a ChangeCipherSpec message could be processed.
+        sessKeysCalculated = true;
+
         //
         // Dump the connection keys as they're generated.
         //
@@ -1190,6 +1197,15 @@
         }
     }
 
+    /**
+     * Return whether or not the Handshaker has derived session keys for
+     * this handshake.  This is used for determining readiness to process
+     * an incoming ChangeCipherSpec message.
+     */
+    boolean sessionKeysCalculated() {
+        return sessKeysCalculated;
+    }
+
     private static void printHex(HexDumpEncoder dump, byte[] bytes) {
         if (bytes == null) {
             System.out.println("(key bytes not available)");
--- a/src/share/classes/sun/security/ssl/SSLEngineImpl.java	Tue Aug 26 15:53:05 2014 +0100
+++ b/src/share/classes/sun/security/ssl/SSLEngineImpl.java	Mon Sep 01 12:13:32 2014 +0400
@@ -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
@@ -215,6 +215,11 @@
     static final byte           clauth_required = 2;
 
     /*
+     * Flag indicating that the engine has received a ChangeCipherSpec message.
+     */
+    private boolean             receivedCCS;
+
+    /*
      * Flag indicating if the next record we receive MUST be a Finished
      * message. Temporarily set during the handshake to ensure that
      * a change cipher spec message is followed by a finished message.
@@ -363,6 +368,7 @@
          */
         roleIsServer = true;
         connectionState = cs_START;
+        receivedCCS = false;
 
         /*
          * default read and write side cipher and MAC support
@@ -1006,6 +1012,7 @@
 
                     if (handshaker.invalidated) {
                         handshaker = null;
+                        receivedCCS = false;
                         // if state is cs_RENEGOTIATE, revert it to cs_DATA
                         if (connectionState == cs_RENEGOTIATE) {
                             connectionState = cs_DATA;
@@ -1024,6 +1031,7 @@
                         }
                         handshaker = null;
                         connectionState = cs_DATA;
+                        receivedCCS = false;
 
                         // No handshakeListeners here.  That's a
                         // SSLSocket thing.
@@ -1063,13 +1071,25 @@
                 case Record.ct_change_cipher_spec:
                     if ((connectionState != cs_HANDSHAKE
                                 && connectionState != cs_RENEGOTIATE)
-                            || inputRecord.available() != 1
+                            || !handshaker.sessionKeysCalculated()
+                            || receivedCCS) {
+                        // For the CCS message arriving in the wrong state
+                        fatal(Alerts.alert_unexpected_message,
+                                "illegal change cipher spec msg, conn state = "
+                                + connectionState + ", handshake state = "
+                                + handshaker.state);
+                    } else if (inputRecord.available() != 1
                             || inputRecord.read() != 1) {
+                        // For structural/content issues with the CCS
                         fatal(Alerts.alert_unexpected_message,
-                            "illegal change cipher spec msg, state = "
-                            + connectionState);
+                                "Malformed change cipher spec msg");
                     }
 
+                    // Once we've received CCS, update the flag.
+                    // If the remote endpoint sends it again in this handshake
+                    // we won't process it.
+                    receivedCCS = true;
+
                     //
                     // The first message after a change_cipher_spec
                     // record MUST be a "Finished" handshake record,
--- a/src/share/classes/sun/security/ssl/SSLSocketImpl.java	Tue Aug 26 15:53:05 2014 +0100
+++ b/src/share/classes/sun/security/ssl/SSLSocketImpl.java	Mon Sep 01 12:13:32 2014 +0400
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1996, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1996, 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
@@ -175,6 +175,12 @@
     private volatile int        connectionState;
 
     /*
+     * Flag indicating that the engine's handshaker has done the necessary
+     * steps so the engine may process a ChangeCipherSpec message.
+     */
+    private boolean             receivedCCS;
+
+    /*
      * Flag indicating if the next record we receive MUST be a Finished
      * message. Temporarily set during the handshake to ensure that
      * a change cipher spec message is followed by a finished message.
@@ -557,6 +563,7 @@
          */
         roleIsServer = isServer;
         connectionState = cs_START;
+        receivedCCS = false;
 
         /*
          * default read and write side cipher and MAC support
@@ -1018,6 +1025,7 @@
 
                     if (handshaker.invalidated) {
                         handshaker = null;
+                        receivedCCS = false;
                         // if state is cs_RENEGOTIATE, revert it to cs_DATA
                         if (connectionState == cs_RENEGOTIATE) {
                             connectionState = cs_DATA;
@@ -1033,6 +1041,7 @@
                         handshakeSession = null;
                         handshaker = null;
                         connectionState = cs_DATA;
+                        receivedCCS = false;
 
                         //
                         // Tell folk about handshake completion, but do
@@ -1080,13 +1089,24 @@
                 case Record.ct_change_cipher_spec:
                     if ((connectionState != cs_HANDSHAKE
                                 && connectionState != cs_RENEGOTIATE)
-                            || r.available() != 1
-                            || r.read() != 1) {
+                            || !handshaker.sessionKeysCalculated()
+                            || receivedCCS) {
+                        // For the CCS message arriving in the wrong state
                         fatal(Alerts.alert_unexpected_message,
-                            "illegal change cipher spec msg, state = "
-                            + connectionState);
+                                "illegal change cipher spec msg, conn state = "
+                                + connectionState + ", handshake state = "
+                                + handshaker.state);
+                    } else if (r.available() != 1 || r.read() != 1) {
+                        // For structural/content issues with the CCS
+                        fatal(Alerts.alert_unexpected_message,
+                                "Malformed change cipher spec msg");
                     }
 
+                    // Once we've received CCS, update the flag.
+                    // If the remote endpoint sends it again in this handshake
+                    // we won't process it.
+                    receivedCCS = true;
+
                     //
                     // The first message after a change_cipher_spec
                     // record MUST be a "Finished" handshake record,