1386 lines · 48.9 KB · Java
RawDownload
/* * Copyright (c) 1996, 2011, 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 * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation.  Oracle designates this * particular file as subject to the "Classpath" exception as provided * by Oracle in the LICENSE file that accompanied this code. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License * version 2 for more details (a copy is included in the LICENSE file that * accompanied this code). * * You should have received a copy of the GNU General Public License version * 2 along with this work; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA * or visit www.oracle.com if you need additional information or have any * questions. */  package sun.security.ssl; import java.io.*;import java.util.*;import java.security.*;import java.security.NoSuchAlgorithmException;import java.security.AccessController;import java.security.AlgorithmConstraints;import java.security.AccessControlContext;import java.security.PrivilegedExceptionAction;import java.security.PrivilegedActionException; import javax.crypto.*;import javax.crypto.spec.*; import javax.net.ssl.*;import sun.misc.HexDumpEncoder; import sun.security.internal.spec.*;import sun.security.internal.interfaces.TlsMasterSecret; import sun.security.ssl.HandshakeMessage.*;import sun.security.ssl.CipherSuite.*; import static sun.security.ssl.CipherSuite.PRF.*; /** * Handshaker ... processes handshake records from an SSL V3.0 * data stream, handling all the details of the handshake protocol. * * Note that the real protocol work is done in two subclasses, the  base * class just provides the control flow and key generation framework. * * @author David Brownell */abstract class Handshaker {     // protocol version being established using this Handshaker    ProtocolVersion protocolVersion;     // the currently active protocol version during a renegotiation    ProtocolVersion     activeProtocolVersion;     // security parameters for secure renegotiation.    boolean             secureRenegotiation;    byte[]              clientVerifyData;    byte[]              serverVerifyData;     // Is it an initial negotiation  or a renegotiation?    boolean                     isInitialHandshake;     // List of enabled protocols    private ProtocolList        enabledProtocols;     // List of enabled CipherSuites    private CipherSuiteList     enabledCipherSuites;     // The endpoint identification protocol    String              identificationProtocol;     // The cryptographic algorithm constraints    private AlgorithmConstraints    algorithmConstraints = null;     // Local supported signature and algorithms    Collection<SignatureAndHashAlgorithm> localSupportedSignAlgs;     // Peer supported signature and algorithms    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;     /*     * List of active cipher suites     *     * 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 boolean             isClient;    private boolean             needCertVerify;     SSLSocketImpl               conn = null;    SSLEngineImpl               engine = null;     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;     // current key exchange. Never null, initially K_NULL    KeyExchange         keyExchange;     /* True if this session is being resumed (fast handshake) */    boolean             resumingSession;     /* True if it's OK to start a new SSL session */    boolean             enableNewSession;     // Temporary storage for the individual keys. Set by    // calculateConnectionKeys() and cleared once the ciphers are    // activated.    private SecretKey clntWriteKey, svrWriteKey;    private IvParameterSpec clntWriteIV, svrWriteIV;    private SecretKey clntMacSecret, svrMacSecret;     /*     * Delegated task subsystem data structures.     *     * If thrown is set, we need to propagate this back immediately     * on entry into processMessage().     *     * Data is protected by the SSLEngine.this lock.     */    private volatile boolean taskDelegated = false;    private volatile DelegatedTask delegatedTask = null;    private volatile Exception thrown = null;     // Could probably use a java.util.concurrent.atomic.AtomicReference    // here instead of using this lock.  Consider changing.    private Object thrownLock = new Object();     /* Class and subclass dynamic debugging support */    static final Debug debug = Debug.getInstance("ssl");     // By default, disable the unsafe legacy session renegotiation    static final boolean allowUnsafeRenegotiation = Debug.getBooleanProperty(                    "sun.security.ssl.allowUnsafeRenegotiation", false);     // For maximum interoperability and backward compatibility, RFC 5746    // allows server (or client) to accept ClientHello (or ServerHello)    // message without the secure renegotiation_info extension or SCSV.    //    // For maximum security, RFC 5746 also allows server (or client) to    // reject such message with a fatal "handshake_failure" alert.    //    // By default, allow such legacy hello messages.    static final boolean allowLegacyHelloMessages = Debug.getBooleanProperty(                    "sun.security.ssl.allowLegacyHelloMessages", true);     // need to dispose the object when it is invalidated    boolean invalidated;     Handshaker(SSLSocketImpl c, SSLContextImpl context,            ProtocolList enabledProtocols, boolean needCertVerify,            boolean isClient, ProtocolVersion activeProtocolVersion,            boolean isInitialHandshake, boolean secureRenegotiation,            byte[] clientVerifyData, byte[] serverVerifyData) {        this.conn = c;        init(context, enabledProtocols, needCertVerify, isClient,            activeProtocolVersion, isInitialHandshake, secureRenegotiation,            clientVerifyData, serverVerifyData);    }     Handshaker(SSLEngineImpl engine, SSLContextImpl context,            ProtocolList enabledProtocols, boolean needCertVerify,            boolean isClient, ProtocolVersion activeProtocolVersion,            boolean isInitialHandshake, boolean secureRenegotiation,            byte[] clientVerifyData, byte[] serverVerifyData) {        this.engine = engine;        init(context, enabledProtocols, needCertVerify, isClient,            activeProtocolVersion, isInitialHandshake, secureRenegotiation,            clientVerifyData, serverVerifyData);    }     private void init(SSLContextImpl context, ProtocolList enabledProtocols,            boolean needCertVerify, boolean isClient,            ProtocolVersion activeProtocolVersion,            boolean isInitialHandshake, boolean secureRenegotiation,            byte[] clientVerifyData, byte[] serverVerifyData) {         if (debug != null && Debug.isOn("handshake")) {            System.out.println(                "Allow unsafe renegotiation: " + allowUnsafeRenegotiation +                "\nAllow legacy hello messages: " + allowLegacyHelloMessages +                "\nIs initial handshake: " + isInitialHandshake +                "\nIs secure renegotiation: " + secureRenegotiation);        }         this.sslContext = context;        this.isClient = isClient;        this.needCertVerify = needCertVerify;        this.activeProtocolVersion = activeProtocolVersion;        this.isInitialHandshake = isInitialHandshake;        this.secureRenegotiation = secureRenegotiation;        this.clientVerifyData = clientVerifyData;        this.serverVerifyData = serverVerifyData;        enableNewSession = true;        invalidated = false;         setCipherSuite(CipherSuite.C_NULL);        setEnabledProtocols(enabledProtocols);         if (conn != null) {            algorithmConstraints = new SSLAlgorithmConstraints(conn, true);        } else {        // engine != null            algorithmConstraints = new SSLAlgorithmConstraints(engine, true);        }          //        // In addition to the connection state machine, controlling        // how the connection deals with the different sorts of records        // that get sent (notably handshake transitions!), there's        // also a handshaking state machine that controls message        // sequencing.        //        // It's a convenient artifact of the protocol that this can,        // with only a couple of minor exceptions, be driven by the        // type constant for the last message seen:  except for the        // client's cert verify, those constants are in a convenient        // order to drastically simplify state machine checking.        //        state = -2;  // initialized but not activated    }     /*     * Reroutes calls to the SSLSocket or SSLEngine (*SE).     *     * We could have also done it by extra classes     * and letting them override, but this seemed much     * less involved.     */    void fatalSE(byte b, String diagnostic) throws IOException {        fatalSE(b, diagnostic, null);    }     void fatalSE(byte b, Throwable cause) throws IOException {        fatalSE(b, null, cause);    }     void fatalSE(byte b, String diagnostic, Throwable cause)            throws IOException {        if (conn != null) {            conn.fatal(b, diagnostic, cause);        } else {            engine.fatal(b, diagnostic, cause);        }    }     void warningSE(byte b) {        if (conn != null) {            conn.warning(b);        } else {            engine.warning(b);        }    }     String getRawHostnameSE() {        if (conn != null) {            return conn.getRawHostname();        } else {            return engine.getPeerHost();        }    }     String getHostSE() {        if (conn != null) {            return conn.getHost();        } else {            return engine.getPeerHost();        }    }     String getHostAddressSE() {        if (conn != null) {            return conn.getInetAddress().getHostAddress();        } else {            /*             * This is for caching only, doesn't matter that's is really             * a hostname.  The main thing is that it doesn't do             * a reverse DNS lookup, potentially slowing things down.             */            return engine.getPeerHost();        }    }     boolean isLoopbackSE() {        if (conn != null) {            return conn.getInetAddress().isLoopbackAddress();        } else {            return false;        }    }     int getPortSE() {        if (conn != null) {            return conn.getPort();        } else {            return engine.getPeerPort();        }    }     int getLocalPortSE() {        if (conn != null) {            return conn.getLocalPort();        } else {            return -1;        }    }     AccessControlContext getAccSE() {        if (conn != null) {            return conn.getAcc();        } else {            return engine.getAcc();        }    }     private void setVersionSE(ProtocolVersion protocolVersion) {        if (conn != null) {            conn.setVersion(protocolVersion);        } else {            engine.setVersion(protocolVersion);        }    }     /**     * Set the active protocol version and propagate it to the SSLSocket     * and our handshake streams. Called from ClientHandshaker     * and ServerHandshaker with the negotiated protocol version.     */    void setVersion(ProtocolVersion protocolVersion) {        this.protocolVersion = protocolVersion;        setVersionSE(protocolVersion);         output.r.setVersion(protocolVersion);    }     /**     * Set the enabled protocols. Called from the constructor or     * SSLSocketImpl/SSLEngineImpl.setEnabledProtocols() (if the     * handshake is not yet in progress).     */    void setEnabledProtocols(ProtocolList enabledProtocols) {        activeCipherSuites = null;        activeProtocols = null;         this.enabledProtocols = enabledProtocols;    }     /**     * Set the enabled cipher suites. Called from     * SSLSocketImpl/SSLEngineImpl.setEnabledCipherSuites() (if the     * handshake is not yet in progress).     */    void setEnabledCipherSuites(CipherSuiteList enabledCipherSuites) {        activeCipherSuites = null;        activeProtocols = null;        this.enabledCipherSuites = enabledCipherSuites;    }     /**     * Set the algorithm constraints. Called from the constructor or     * SSLSocketImpl/SSLEngineImpl.setAlgorithmConstraints() (if the     * handshake is not yet in progress).     */    void setAlgorithmConstraints(AlgorithmConstraints algorithmConstraints) {        activeCipherSuites = null;        activeProtocols = null;         this.algorithmConstraints =            new SSLAlgorithmConstraints(algorithmConstraints);        this.localSupportedSignAlgs = null;    }     Collection<SignatureAndHashAlgorithm> getLocalSupportedSignAlgs() {        if (localSupportedSignAlgs == null) {            localSupportedSignAlgs =                SignatureAndHashAlgorithm.getSupportedAlgorithms(                                                    algorithmConstraints);        }         return localSupportedSignAlgs;    }     void setPeerSupportedSignAlgs(            Collection<SignatureAndHashAlgorithm> algorithms) {        peerSupportedSignAlgs =            new ArrayList<SignatureAndHashAlgorithm>(algorithms);    }     Collection<SignatureAndHashAlgorithm> getPeerSupportedSignAlgs() {        return peerSupportedSignAlgs;    }      /**     * Set the identification protocol. Called from the constructor or     * SSLSocketImpl/SSLEngineImpl.setIdentificationProtocol() (if the     * handshake is not yet in progress).     */    void setIdentificationProtocol(String protocol) {        this.identificationProtocol = protocol;    }     /**     * Prior to handshaking, activate the handshake and initialize the version,     * input stream and output stream.     */    void activate(ProtocolVersion helloVersion) throws IOException {        if (activeProtocols == null) {            activeProtocols = getActiveProtocols();        }         if (activeProtocols.collection().isEmpty() ||                activeProtocols.max.v == ProtocolVersion.NONE.v) {            throw new SSLHandshakeException("No appropriate protocol");        }         if (activeCipherSuites == null) {            activeCipherSuites = getActiveCipherSuites();        }         if (activeCipherSuites.collection().isEmpty()) {            throw new SSLHandshakeException("No appropriate cipher suite");        }         // temporary protocol version until the actual protocol version        // is negotiated in the Hello exchange. This affects the record        // version we sent with the ClientHello.        if (!isInitialHandshake) {            protocolVersion = activeProtocolVersion;        } else {            protocolVersion = activeProtocols.max;        }         if (helloVersion == null || helloVersion.v == ProtocolVersion.NONE.v) {            helloVersion = activeProtocols.helloVersion;        }         // We accumulate digests of the handshake messages so that        // we can read/write CertificateVerify and Finished messages,        // getting assurance against some particular active attacks.        Set<String> localSupportedHashAlgorithms =            SignatureAndHashAlgorithm.getHashAlgorithmNames(                getLocalSupportedSignAlgs());        handshakeHash = new HandshakeHash(!isClient, needCertVerify,            localSupportedHashAlgorithms);         // Generate handshake input/output stream.        input = new HandshakeInStream(handshakeHash);        if (conn != null) {            output = new HandshakeOutStream(protocolVersion, helloVersion,                                        handshakeHash, conn);            conn.getAppInputStream().r.setHandshakeHash(handshakeHash);            conn.getAppInputStream().r.setHelloVersion(helloVersion);            conn.getAppOutputStream().r.setHelloVersion(helloVersion);        } else {            output = new HandshakeOutStream(protocolVersion, helloVersion,                                        handshakeHash, engine);            engine.inputRecord.setHandshakeHash(handshakeHash);            engine.inputRecord.setHelloVersion(helloVersion);            engine.outputRecord.setHelloVersion(helloVersion);        }         // move state to activated        state = -1;    }

Lines 1–500 of 1386.