0N/A/*
5408N/A * Copyright (c) 1996, 2012, Oracle and/or its affiliates. All rights reserved.
0N/A * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
0N/A *
0N/A * This code is free software; you can redistribute it and/or modify it
0N/A * under the terms of the GNU General Public License version 2 only, as
2362N/A * published by the Free Software Foundation. Oracle designates this
0N/A * particular file as subject to the "Classpath" exception as provided
2362N/A * by Oracle in the LICENSE file that accompanied this code.
0N/A *
0N/A * This code is distributed in the hope that it will be useful, but WITHOUT
0N/A * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
0N/A * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
0N/A * version 2 for more details (a copy is included in the LICENSE file that
0N/A * accompanied this code).
0N/A *
0N/A * You should have received a copy of the GNU General Public License version
0N/A * 2 along with this work; if not, write to the Free Software Foundation,
0N/A * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
0N/A *
2362N/A * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
2362N/A * or visit www.oracle.com if you need additional information or have any
2362N/A * questions.
0N/A */
0N/A
0N/A
0N/Apackage sun.security.ssl;
0N/A
0N/Aimport java.io.*;
0N/Aimport java.util.*;
0N/Aimport java.security.*;
0N/Aimport java.security.NoSuchAlgorithmException;
0N/Aimport java.security.AccessController;
3002N/Aimport java.security.AlgorithmConstraints;
0N/Aimport java.security.AccessControlContext;
0N/Aimport java.security.PrivilegedExceptionAction;
0N/Aimport java.security.PrivilegedActionException;
0N/A
0N/Aimport javax.crypto.*;
0N/Aimport javax.crypto.spec.*;
0N/A
0N/Aimport javax.net.ssl.*;
0N/Aimport sun.misc.HexDumpEncoder;
0N/A
0N/Aimport sun.security.internal.spec.*;
0N/Aimport sun.security.internal.interfaces.TlsMasterSecret;
0N/A
0N/Aimport sun.security.ssl.HandshakeMessage.*;
0N/Aimport sun.security.ssl.CipherSuite.*;
0N/A
3002N/Aimport static sun.security.ssl.CipherSuite.PRF.*;
3002N/A
0N/A/**
0N/A * Handshaker ... processes handshake records from an SSL V3.0
0N/A * data stream, handling all the details of the handshake protocol.
0N/A *
0N/A * Note that the real protocol work is done in two subclasses, the base
0N/A * class just provides the control flow and key generation framework.
0N/A *
0N/A * @author David Brownell
0N/A */
0N/Aabstract class Handshaker {
0N/A
2261N/A // protocol version being established using this Handshaker
0N/A ProtocolVersion protocolVersion;
0N/A
2261N/A // the currently active protocol version during a renegotiation
2261N/A ProtocolVersion activeProtocolVersion;
2261N/A
2890N/A // security parameters for secure renegotiation.
2890N/A boolean secureRenegotiation;
2890N/A byte[] clientVerifyData;
2890N/A byte[] serverVerifyData;
2890N/A
2998N/A // Is it an initial negotiation or a renegotiation?
2890N/A boolean isInitialHandshake;
2890N/A
2998N/A // List of enabled protocols
2998N/A private ProtocolList enabledProtocols;
2998N/A
2998N/A // List of enabled CipherSuites
2998N/A private CipherSuiteList enabledCipherSuites;
2998N/A
3002N/A // The endpoint identification protocol
3002N/A String identificationProtocol;
3002N/A
3002N/A // The cryptographic algorithm constraints
3002N/A private AlgorithmConstraints algorithmConstraints = null;
3002N/A
3002N/A // Local supported signature and algorithms
3002N/A Collection<SignatureAndHashAlgorithm> localSupportedSignAlgs;
3002N/A
3002N/A // Peer supported signature and algorithms
3002N/A Collection<SignatureAndHashAlgorithm> peerSupportedSignAlgs;
3002N/A
3002N/A /*
3002N/A
2998N/A /*
2998N/A * List of active protocols
2998N/A *
2998N/A * Active protocols is a subset of enabled protocols, and will
2998N/A * contain only those protocols that have vaild cipher suites
2998N/A * enabled.
2998N/A */
2998N/A private ProtocolList activeProtocols;
2998N/A
2998N/A /*
2998N/A * List of active cipher suites
2998N/A *
2998N/A * Active cipher suites is a subset of enabled cipher suites, and will
2998N/A * contain only those cipher suites available for the active protocols.
2998N/A */
2998N/A private CipherSuiteList activeCipherSuites;
0N/A
0N/A private boolean isClient;
3002N/A private boolean needCertVerify;
0N/A
0N/A SSLSocketImpl conn = null;
0N/A SSLEngineImpl engine = null;
0N/A
0N/A HandshakeHash handshakeHash;
0N/A HandshakeInStream input;
0N/A HandshakeOutStream output;
0N/A int state;
0N/A SSLContextImpl sslContext;
0N/A RandomCookie clnt_random, svr_random;
0N/A SSLSessionImpl session;
0N/A
0N/A // current CipherSuite. Never null, initially SSL_NULL_WITH_NULL_NULL
0N/A CipherSuite cipherSuite;
0N/A
0N/A // current key exchange. Never null, initially K_NULL
0N/A KeyExchange keyExchange;
0N/A
0N/A /* True if this session is being resumed (fast handshake) */
0N/A boolean resumingSession;
0N/A
0N/A /* True if it's OK to start a new SSL session */
0N/A boolean enableNewSession;
0N/A
0N/A // Temporary storage for the individual keys. Set by
0N/A // calculateConnectionKeys() and cleared once the ciphers are
0N/A // activated.
0N/A private SecretKey clntWriteKey, svrWriteKey;
0N/A private IvParameterSpec clntWriteIV, svrWriteIV;
0N/A private SecretKey clntMacSecret, svrMacSecret;
0N/A
0N/A /*
0N/A * Delegated task subsystem data structures.
0N/A *
0N/A * If thrown is set, we need to propagate this back immediately
0N/A * on entry into processMessage().
0N/A *
0N/A * Data is protected by the SSLEngine.this lock.
0N/A */
0N/A private volatile boolean taskDelegated = false;
0N/A private volatile DelegatedTask delegatedTask = null;
0N/A private volatile Exception thrown = null;
0N/A
0N/A // Could probably use a java.util.concurrent.atomic.AtomicReference
0N/A // here instead of using this lock. Consider changing.
0N/A private Object thrownLock = new Object();
0N/A
0N/A /* Class and subclass dynamic debugging support */
0N/A static final Debug debug = Debug.getInstance("ssl");
0N/A
2261N/A // By default, disable the unsafe legacy session renegotiation
2890N/A static final boolean allowUnsafeRenegotiation = Debug.getBooleanProperty(
2261N/A "sun.security.ssl.allowUnsafeRenegotiation", false);
2261N/A
2890N/A // For maximum interoperability and backward compatibility, RFC 5746
2890N/A // allows server (or client) to accept ClientHello (or ServerHello)
2890N/A // message without the secure renegotiation_info extension or SCSV.
2890N/A //
2890N/A // For maximum security, RFC 5746 also allows server (or client) to
2890N/A // reject such message with a fatal "handshake_failure" alert.
2890N/A //
2890N/A // By default, allow such legacy hello messages.
2890N/A static final boolean allowLegacyHelloMessages = Debug.getBooleanProperty(
2890N/A "sun.security.ssl.allowLegacyHelloMessages", true);
2890N/A
2261N/A // need to dispose the object when it is invalidated
2261N/A boolean invalidated;
2261N/A
0N/A Handshaker(SSLSocketImpl c, SSLContextImpl context,
0N/A ProtocolList enabledProtocols, boolean needCertVerify,
2890N/A boolean isClient, ProtocolVersion activeProtocolVersion,
2890N/A boolean isInitialHandshake, boolean secureRenegotiation,
2890N/A byte[] clientVerifyData, byte[] serverVerifyData) {
0N/A this.conn = c;
2890N/A init(context, enabledProtocols, needCertVerify, isClient,
2890N/A activeProtocolVersion, isInitialHandshake, secureRenegotiation,
2890N/A clientVerifyData, serverVerifyData);
0N/A }
0N/A
0N/A Handshaker(SSLEngineImpl engine, SSLContextImpl context,
0N/A ProtocolList enabledProtocols, boolean needCertVerify,
2890N/A boolean isClient, ProtocolVersion activeProtocolVersion,
2890N/A boolean isInitialHandshake, boolean secureRenegotiation,
2890N/A byte[] clientVerifyData, byte[] serverVerifyData) {
0N/A this.engine = engine;
2890N/A init(context, enabledProtocols, needCertVerify, isClient,
2890N/A activeProtocolVersion, isInitialHandshake, secureRenegotiation,
2890N/A clientVerifyData, serverVerifyData);
0N/A }
0N/A
0N/A private void init(SSLContextImpl context, ProtocolList enabledProtocols,
2890N/A boolean needCertVerify, boolean isClient,
2890N/A ProtocolVersion activeProtocolVersion,
2890N/A boolean isInitialHandshake, boolean secureRenegotiation,
2890N/A byte[] clientVerifyData, byte[] serverVerifyData) {
2890N/A
2890N/A if (debug != null && Debug.isOn("handshake")) {
2890N/A System.out.println(
2890N/A "Allow unsafe renegotiation: " + allowUnsafeRenegotiation +
2890N/A "\nAllow legacy hello messages: " + allowLegacyHelloMessages +
2890N/A "\nIs initial handshake: " + isInitialHandshake +
2890N/A "\nIs secure renegotiation: " + secureRenegotiation);
2890N/A }
0N/A
0N/A this.sslContext = context;
0N/A this.isClient = isClient;
3002N/A this.needCertVerify = needCertVerify;
2890N/A this.activeProtocolVersion = activeProtocolVersion;
2890N/A this.isInitialHandshake = isInitialHandshake;
2890N/A this.secureRenegotiation = secureRenegotiation;
2890N/A this.clientVerifyData = clientVerifyData;
2890N/A this.serverVerifyData = serverVerifyData;
0N/A enableNewSession = true;
2261N/A invalidated = false;
0N/A
0N/A setCipherSuite(CipherSuite.C_NULL);
0N/A setEnabledProtocols(enabledProtocols);
0N/A
0N/A if (conn != null) {
3002N/A algorithmConstraints = new SSLAlgorithmConstraints(conn, true);
0N/A } else { // engine != null
3002N/A algorithmConstraints = new SSLAlgorithmConstraints(engine, true);
0N/A }
0N/A
0N/A
0N/A //
0N/A // In addition to the connection state machine, controlling
0N/A // how the connection deals with the different sorts of records
0N/A // that get sent (notably handshake transitions!), there's
0N/A // also a handshaking state machine that controls message
0N/A // sequencing.
0N/A //
0N/A // It's a convenient artifact of the protocol that this can,
0N/A // with only a couple of minor exceptions, be driven by the
0N/A // type constant for the last message seen: except for the
0N/A // client's cert verify, those constants are in a convenient
0N/A // order to drastically simplify state machine checking.
0N/A //
2998N/A state = -2; // initialized but not activated
0N/A }
0N/A
0N/A /*
0N/A * Reroutes calls to the SSLSocket or SSLEngine (*SE).
0N/A *
0N/A * We could have also done it by extra classes
0N/A * and letting them override, but this seemed much
0N/A * less involved.
0N/A */
0N/A void fatalSE(byte b, String diagnostic) throws IOException {
0N/A fatalSE(b, diagnostic, null);
0N/A }
0N/A
0N/A void fatalSE(byte b, Throwable cause) throws IOException {
0N/A fatalSE(b, null, cause);
0N/A }
0N/A
0N/A void fatalSE(byte b, String diagnostic, Throwable cause)
0N/A throws IOException {
0N/A if (conn != null) {
0N/A conn.fatal(b, diagnostic, cause);
0N/A } else {
0N/A engine.fatal(b, diagnostic, cause);
0N/A }
0N/A }
0N/A
0N/A void warningSE(byte b) {
0N/A if (conn != null) {
0N/A conn.warning(b);
0N/A } else {
0N/A engine.warning(b);
0N/A }
0N/A }
0N/A
3002N/A String getRawHostnameSE() {
3002N/A if (conn != null) {
3002N/A return conn.getRawHostname();
3002N/A } else {
3002N/A return engine.getPeerHost();
3002N/A }
3002N/A }
3002N/A
0N/A String getHostSE() {
0N/A if (conn != null) {
0N/A return conn.getHost();
0N/A } else {
0N/A return engine.getPeerHost();
0N/A }
0N/A }
0N/A
0N/A String getHostAddressSE() {
0N/A if (conn != null) {
0N/A return conn.getInetAddress().getHostAddress();
0N/A } else {
0N/A /*
0N/A * This is for caching only, doesn't matter that's is really
0N/A * a hostname. The main thing is that it doesn't do
0N/A * a reverse DNS lookup, potentially slowing things down.
0N/A */
0N/A return engine.getPeerHost();
0N/A }
0N/A }
0N/A
0N/A boolean isLoopbackSE() {
0N/A if (conn != null) {
0N/A return conn.getInetAddress().isLoopbackAddress();
0N/A } else {
0N/A return false;
0N/A }
0N/A }
0N/A
0N/A int getPortSE() {
0N/A if (conn != null) {
0N/A return conn.getPort();
0N/A } else {
0N/A return engine.getPeerPort();
0N/A }
0N/A }
0N/A
0N/A int getLocalPortSE() {
0N/A if (conn != null) {
0N/A return conn.getLocalPort();
0N/A } else {
0N/A return -1;
0N/A }
0N/A }
0N/A
0N/A AccessControlContext getAccSE() {
0N/A if (conn != null) {
0N/A return conn.getAcc();
0N/A } else {
0N/A return engine.getAcc();
0N/A }
0N/A }
0N/A
0N/A private void setVersionSE(ProtocolVersion protocolVersion) {
0N/A if (conn != null) {
0N/A conn.setVersion(protocolVersion);
0N/A } else {
0N/A engine.setVersion(protocolVersion);
0N/A }
0N/A }
0N/A
0N/A /**
0N/A * Set the active protocol version and propagate it to the SSLSocket
0N/A * and our handshake streams. Called from ClientHandshaker
0N/A * and ServerHandshaker with the negotiated protocol version.
0N/A */
0N/A void setVersion(ProtocolVersion protocolVersion) {
0N/A this.protocolVersion = protocolVersion;
0N/A setVersionSE(protocolVersion);
2998N/A
0N/A output.r.setVersion(protocolVersion);
0N/A }
0N/A
0N/A /**
0N/A * Set the enabled protocols. Called from the constructor or
2998N/A * SSLSocketImpl/SSLEngineImpl.setEnabledProtocols() (if the
2998N/A * handshake is not yet in progress).
0N/A */
0N/A void setEnabledProtocols(ProtocolList enabledProtocols) {
2998N/A activeCipherSuites = null;
2998N/A activeProtocols = null;
2998N/A
0N/A this.enabledProtocols = enabledProtocols;
2998N/A }
2998N/A
2998N/A /**
2998N/A * Set the enabled cipher suites. Called from
2998N/A * SSLSocketImpl/SSLEngineImpl.setEnabledCipherSuites() (if the
2998N/A * handshake is not yet in progress).
2998N/A */
2998N/A void setEnabledCipherSuites(CipherSuiteList enabledCipherSuites) {
2998N/A activeCipherSuites = null;
2998N/A activeProtocols = null;
2998N/A this.enabledCipherSuites = enabledCipherSuites;
2998N/A }
2998N/A
3002N/A /**
3002N/A * Set the algorithm constraints. Called from the constructor or
3002N/A * SSLSocketImpl/SSLEngineImpl.setAlgorithmConstraints() (if the
3002N/A * handshake is not yet in progress).
3002N/A */
3002N/A void setAlgorithmConstraints(AlgorithmConstraints algorithmConstraints) {
3002N/A activeCipherSuites = null;
3002N/A activeProtocols = null;
3002N/A
3002N/A this.algorithmConstraints =
3002N/A new SSLAlgorithmConstraints(algorithmConstraints);
3002N/A this.localSupportedSignAlgs = null;
3002N/A }
3002N/A
3002N/A Collection<SignatureAndHashAlgorithm> getLocalSupportedSignAlgs() {
3002N/A if (localSupportedSignAlgs == null) {
3002N/A localSupportedSignAlgs =
3002N/A SignatureAndHashAlgorithm.getSupportedAlgorithms(
3002N/A algorithmConstraints);
3002N/A }
3002N/A
3002N/A return localSupportedSignAlgs;
3002N/A }
3002N/A
3002N/A void setPeerSupportedSignAlgs(
3002N/A Collection<SignatureAndHashAlgorithm> algorithms) {
3002N/A peerSupportedSignAlgs =
3002N/A new ArrayList<SignatureAndHashAlgorithm>(algorithms);
3002N/A }
3002N/A
3002N/A Collection<SignatureAndHashAlgorithm> getPeerSupportedSignAlgs() {
3002N/A return peerSupportedSignAlgs;
3002N/A }
3002N/A
3002N/A
3002N/A /**
3002N/A * Set the identification protocol. Called from the constructor or
3002N/A * SSLSocketImpl/SSLEngineImpl.setIdentificationProtocol() (if the
3002N/A * handshake is not yet in progress).
3002N/A */
3002N/A void setIdentificationProtocol(String protocol) {
3002N/A this.identificationProtocol = protocol;
3002N/A }
2998N/A
2998N/A /**
2998N/A * Prior to handshaking, activate the handshake and initialize the version,
2998N/A * input stream and output stream.
2998N/A */
2998N/A void activate(ProtocolVersion helloVersion) throws IOException {
2998N/A if (activeProtocols == null) {
2998N/A activeProtocols = getActiveProtocols();
2998N/A }
2998N/A
2998N/A if (activeProtocols.collection().isEmpty() ||
2998N/A activeProtocols.max.v == ProtocolVersion.NONE.v) {
2998N/A throw new SSLHandshakeException("No appropriate protocol");
2998N/A }
2998N/A
2998N/A if (activeCipherSuites == null) {
2998N/A activeCipherSuites = getActiveCipherSuites();
2998N/A }
2998N/A
2998N/A if (activeCipherSuites.collection().isEmpty()) {
2998N/A throw new SSLHandshakeException("No appropriate cipher suite");
2998N/A }
0N/A
0N/A // temporary protocol version until the actual protocol version
0N/A // is negotiated in the Hello exchange. This affects the record
2998N/A // version we sent with the ClientHello.
2998N/A if (!isInitialHandshake) {
2998N/A protocolVersion = activeProtocolVersion;
2998N/A } else {
2998N/A protocolVersion = activeProtocols.max;
2998N/A }
0N/A
2998N/A if (helloVersion == null || helloVersion.v == ProtocolVersion.NONE.v) {
2998N/A helloVersion = activeProtocols.helloVersion;
2998N/A }
0N/A
3002N/A // We accumulate digests of the handshake messages so that
3002N/A // we can read/write CertificateVerify and Finished messages,
3002N/A // getting assurance against some particular active attacks.
3002N/A Set<String> localSupportedHashAlgorithms =
3002N/A SignatureAndHashAlgorithm.getHashAlgorithmNames(
3002N/A getLocalSupportedSignAlgs());
3002N/A handshakeHash = new HandshakeHash(!isClient, needCertVerify,
3002N/A localSupportedHashAlgorithms);
3002N/A
3002N/A // Generate handshake input/output stream.
0N/A input = new HandshakeInStream(handshakeHash);
0N/A if (conn != null) {
0N/A output = new HandshakeOutStream(protocolVersion, helloVersion,
0N/A handshakeHash, conn);
3002N/A conn.getAppInputStream().r.setHandshakeHash(handshakeHash);
0N/A conn.getAppInputStream().r.setHelloVersion(helloVersion);
2998N/A conn.getAppOutputStream().r.setHelloVersion(helloVersion);
0N/A } else {
0N/A output = new HandshakeOutStream(protocolVersion, helloVersion,
0N/A handshakeHash, engine);
3002N/A engine.inputRecord.setHandshakeHash(handshakeHash);
2998N/A engine.inputRecord.setHelloVersion(helloVersion);
0N/A engine.outputRecord.setHelloVersion(helloVersion);
0N/A }
0N/A
2998N/A // move state to activated
2998N/A state = -1;
0N/A }
0N/A
0N/A /**
0N/A * Set cipherSuite and keyExchange to the given CipherSuite.
0N/A * Does not perform any verification that this is a valid selection,
0N/A * this must be done before calling this method.
0N/A */
0N/A void setCipherSuite(CipherSuite s) {
0N/A this.cipherSuite = s;
0N/A this.keyExchange = s.keyExchange;
0N/A }
0N/A
0N/A /**
0N/A * Check if the given ciphersuite is enabled and available.
0N/A * Does not check if the required server certificates are available.
0N/A */
2890N/A boolean isNegotiable(CipherSuite s) {
2998N/A if (activeCipherSuites == null) {
2998N/A activeCipherSuites = getActiveCipherSuites();
2998N/A }
2998N/A
2998N/A return activeCipherSuites.contains(s) && s.isNegotiable();
2998N/A }
2998N/A
2998N/A /**
2998N/A * Check if the given protocol version is enabled and available.
2998N/A */
2998N/A boolean isNegotiable(ProtocolVersion protocolVersion) {
2998N/A if (activeProtocols == null) {
2998N/A activeProtocols = getActiveProtocols();
2998N/A }
2998N/A
2998N/A return activeProtocols.contains(protocolVersion);
2998N/A }
2998N/A
2998N/A /**
2998N/A * Select a protocol version from the list. Called from
2998N/A * ServerHandshaker to negotiate protocol version.
2998N/A *
2998N/A * Return the lower of the protocol version suggested in the
2998N/A * clien hello and the highest supported by the server.
2998N/A */
2998N/A ProtocolVersion selectProtocolVersion(ProtocolVersion protocolVersion) {
2998N/A if (activeProtocols == null) {
2998N/A activeProtocols = getActiveProtocols();
2998N/A }
2998N/A
2998N/A return activeProtocols.selectProtocolVersion(protocolVersion);
0N/A }
0N/A
0N/A /**
2998N/A * Get the active cipher suites.
2998N/A *
2998N/A * In TLS 1.1, many weak or vulnerable cipher suites were obsoleted,
2998N/A * such as TLS_RSA_EXPORT_WITH_RC4_40_MD5. The implementation MUST NOT
2998N/A * negotiate these cipher suites in TLS 1.1 or later mode.
2998N/A *
2998N/A * Therefore, when the active protocols only include TLS 1.1 or later,
2998N/A * the client cannot request to negotiate those obsoleted cipher
3002N/A * suites. That is, the obsoleted suites should not be included in the
2998N/A * client hello. So we need to create a subset of the enabled cipher
2998N/A * suites, the active cipher suites, which does not contain obsoleted
2998N/A * cipher suites of the minimum active protocol.
2998N/A *
2998N/A * Return empty list instead of null if no active cipher suites.
2998N/A */
2998N/A CipherSuiteList getActiveCipherSuites() {
2998N/A if (activeCipherSuites == null) {
2998N/A if (activeProtocols == null) {
2998N/A activeProtocols = getActiveProtocols();
2998N/A }
2998N/A
3401N/A ArrayList<CipherSuite> suites = new ArrayList<>();
2998N/A if (!(activeProtocols.collection().isEmpty()) &&
2998N/A activeProtocols.min.v != ProtocolVersion.NONE.v) {
2998N/A for (CipherSuite suite : enabledCipherSuites.collection()) {
3002N/A if (suite.obsoleted > activeProtocols.min.v &&
3002N/A suite.supported <= activeProtocols.max.v) {
3002N/A if (algorithmConstraints.permits(
3002N/A EnumSet.of(CryptoPrimitive.KEY_AGREEMENT),
3002N/A suite.name, null)) {
3002N/A suites.add(suite);
3002N/A }
3002N/A } else if (debug != null && Debug.isOn("verbose")) {
3002N/A if (suite.obsoleted <= activeProtocols.min.v) {
3002N/A System.out.println(
3002N/A "Ignoring obsoleted cipher suite: " + suite);
3002N/A } else {
3002N/A System.out.println(
3002N/A "Ignoring unsupported cipher suite: " + suite);
3002N/A }
2998N/A }
2998N/A }
2998N/A }
2998N/A activeCipherSuites = new CipherSuiteList(suites);
2998N/A }
2998N/A
2998N/A return activeCipherSuites;
2998N/A }
2998N/A
2998N/A /*
2998N/A * Get the active protocol versions.
2998N/A *
2998N/A * In TLS 1.1, many weak or vulnerable cipher suites were obsoleted,
2998N/A * such as TLS_RSA_EXPORT_WITH_RC4_40_MD5. The implementation MUST NOT
2998N/A * negotiate these cipher suites in TLS 1.1 or later mode.
2998N/A *
2998N/A * For example, if "TLS_RSA_EXPORT_WITH_RC4_40_MD5" is the
2998N/A * only enabled cipher suite, the client cannot request TLS 1.1 or
2998N/A * later, even though TLS 1.1 or later is enabled. We need to create a
2998N/A * subset of the enabled protocols, called the active protocols, which
2998N/A * contains protocols appropriate to the list of enabled Ciphersuites.
2998N/A *
2998N/A * Return empty list instead of null if no active protocol versions.
2998N/A */
2998N/A ProtocolList getActiveProtocols() {
2998N/A if (activeProtocols == null) {
3401N/A ArrayList<ProtocolVersion> protocols = new ArrayList<>(4);
2998N/A for (ProtocolVersion protocol : enabledProtocols.collection()) {
2998N/A boolean found = false;
2998N/A for (CipherSuite suite : enabledCipherSuites.collection()) {
3002N/A if (suite.isAvailable() && suite.obsoleted > protocol.v &&
3002N/A suite.supported <= protocol.v) {
3002N/A if (algorithmConstraints.permits(
3002N/A EnumSet.of(CryptoPrimitive.KEY_AGREEMENT),
3002N/A suite.name, null)) {
3002N/A protocols.add(protocol);
3002N/A found = true;
3002N/A break;
3002N/A } else if (debug != null && Debug.isOn("verbose")) {
3002N/A System.out.println(
3002N/A "Ignoring disabled cipher suite: " + suite +
3002N/A " for " + protocol);
3002N/A }
3002N/A } else if (debug != null && Debug.isOn("verbose")) {
3002N/A System.out.println(
3002N/A "Ignoring unsupported cipher suite: " + suite +
3002N/A " for " + protocol);
2998N/A }
2998N/A }
2998N/A if (!found && (debug != null) && Debug.isOn("handshake")) {
2998N/A System.out.println(
2998N/A "No available cipher suite for " + protocol);
2998N/A }
2998N/A }
2998N/A activeProtocols = new ProtocolList(protocols);
2998N/A }
2998N/A
2998N/A return activeProtocols;
2998N/A }
2998N/A
2998N/A /**
2998N/A * As long as handshaking has not activated, we can
0N/A * change whether session creations are allowed.
0N/A *
0N/A * Callers should do their own checking if handshaking
2998N/A * has activated.
0N/A */
0N/A void setEnableSessionCreation(boolean newSessions) {
0N/A enableNewSession = newSessions;
0N/A }
0N/A
0N/A /**
0N/A * Create a new read cipher and return it to caller.
0N/A */
0N/A CipherBox newReadCipher() throws NoSuchAlgorithmException {
0N/A BulkCipher cipher = cipherSuite.cipher;
0N/A CipherBox box;
0N/A if (isClient) {
0N/A box = cipher.newCipher(protocolVersion, svrWriteKey, svrWriteIV,
2998N/A sslContext.getSecureRandom(), false);
0N/A svrWriteKey = null;
0N/A svrWriteIV = null;
0N/A } else {
0N/A box = cipher.newCipher(protocolVersion, clntWriteKey, clntWriteIV,
2998N/A sslContext.getSecureRandom(), false);
0N/A clntWriteKey = null;
0N/A clntWriteIV = null;
0N/A }
0N/A return box;
0N/A }
0N/A
0N/A /**
0N/A * Create a new write cipher and return it to caller.
0N/A */
0N/A CipherBox newWriteCipher() throws NoSuchAlgorithmException {
0N/A BulkCipher cipher = cipherSuite.cipher;
0N/A CipherBox box;
0N/A if (isClient) {
0N/A box = cipher.newCipher(protocolVersion, clntWriteKey, clntWriteIV,
2998N/A sslContext.getSecureRandom(), true);
0N/A clntWriteKey = null;
0N/A clntWriteIV = null;
0N/A } else {
0N/A box = cipher.newCipher(protocolVersion, svrWriteKey, svrWriteIV,
2998N/A sslContext.getSecureRandom(), true);
0N/A svrWriteKey = null;
0N/A svrWriteIV = null;
0N/A }
0N/A return box;
0N/A }
0N/A
0N/A /**
0N/A * Create a new read MAC and return it to caller.
0N/A */
0N/A MAC newReadMAC() throws NoSuchAlgorithmException, InvalidKeyException {
0N/A MacAlg macAlg = cipherSuite.macAlg;
0N/A MAC mac;
0N/A if (isClient) {
0N/A mac = macAlg.newMac(protocolVersion, svrMacSecret);
0N/A svrMacSecret = null;
0N/A } else {
0N/A mac = macAlg.newMac(protocolVersion, clntMacSecret);
0N/A clntMacSecret = null;
0N/A }
0N/A return mac;
0N/A }
0N/A
0N/A /**
0N/A * Create a new write MAC and return it to caller.
0N/A */
0N/A MAC newWriteMAC() throws NoSuchAlgorithmException, InvalidKeyException {
0N/A MacAlg macAlg = cipherSuite.macAlg;
0N/A MAC mac;
0N/A if (isClient) {
0N/A mac = macAlg.newMac(protocolVersion, clntMacSecret);
0N/A clntMacSecret = null;
0N/A } else {
0N/A mac = macAlg.newMac(protocolVersion, svrMacSecret);
0N/A svrMacSecret = null;
0N/A }
0N/A return mac;
0N/A }
0N/A
0N/A /*
0N/A * Returns true iff the handshake sequence is done, so that
0N/A * this freshly created session can become the current one.
0N/A */
0N/A boolean isDone() {
0N/A return state == HandshakeMessage.ht_finished;
0N/A }
0N/A
0N/A
0N/A /*
0N/A * Returns the session which was created through this
0N/A * handshake sequence ... should be called after isDone()
0N/A * returns true.
0N/A */
0N/A SSLSessionImpl getSession() {
0N/A return session;
0N/A }
0N/A
0N/A /*
3002N/A * Set the handshake session
3002N/A */
3002N/A void setHandshakeSessionSE(SSLSessionImpl handshakeSession) {
3002N/A if (conn != null) {
3002N/A conn.setHandshakeSession(handshakeSession);
3002N/A } else {
3002N/A engine.setHandshakeSession(handshakeSession);
3002N/A }
3002N/A }
3002N/A
3002N/A /*
2890N/A * Returns true if renegotiation is in use for this connection.
2890N/A */
2890N/A boolean isSecureRenegotiation() {
2890N/A return secureRenegotiation;
2890N/A }
2890N/A
2890N/A /*
2890N/A * Returns the verify_data from the Finished message sent by the client.
2890N/A */
2890N/A byte[] getClientVerifyData() {
2890N/A return clientVerifyData;
2890N/A }
2890N/A
2890N/A /*
2890N/A * Returns the verify_data from the Finished message sent by the server.
2890N/A */
2890N/A byte[] getServerVerifyData() {
2890N/A return serverVerifyData;
2890N/A }
2890N/A
2890N/A /*
0N/A * This routine is fed SSL handshake records when they become available,
0N/A * and processes messages found therein.
0N/A */
0N/A void process_record(InputRecord r, boolean expectingFinished)
0N/A throws IOException {
0N/A
0N/A checkThrown();
0N/A
0N/A /*
0N/A * Store the incoming handshake data, then see if we can
0N/A * now process any completed handshake messages
0N/A */
0N/A input.incomingRecord(r);
0N/A
0N/A /*
0N/A * We don't need to create a separate delegatable task
0N/A * for finished messages.
0N/A */
0N/A if ((conn != null) || expectingFinished) {
0N/A processLoop();
0N/A } else {
0N/A delegateTask(new PrivilegedExceptionAction<Void>() {
0N/A public Void run() throws Exception {
0N/A processLoop();
0N/A return null;
0N/A }
0N/A });
0N/A }
0N/A }
0N/A
0N/A /*
0N/A * On input, we hash messages one at a time since servers may need
0N/A * to access an intermediate hash to validate a CertificateVerify
0N/A * message.
0N/A *
0N/A * Note that many handshake messages can come in one record (and often
0N/A * do, to reduce network resource utilization), and one message can also
0N/A * require multiple records (e.g. very large Certificate messages).
0N/A */
0N/A void processLoop() throws IOException {
0N/A
2261N/A // need to read off 4 bytes at least to get the handshake
2261N/A // message type and length.
2261N/A while (input.available() >= 4) {
0N/A byte messageType;
0N/A int messageLen;
0N/A
0N/A /*
0N/A * See if we can read the handshake message header, and
0N/A * then the entire handshake message. If not, wait till
0N/A * we can read and process an entire message.
0N/A */
0N/A input.mark(4);
0N/A
0N/A messageType = (byte)input.getInt8();
0N/A messageLen = input.getInt24();
0N/A
0N/A if (input.available() < messageLen) {
0N/A input.reset();
0N/A return;
0N/A }
0N/A
0N/A /*
0N/A * Process the messsage. We require
0N/A * that processMessage() consumes the entire message. In
0N/A * lieu of explicit error checks (how?!) we assume that the
0N/A * data will look like garbage on encoding/processing errors,
0N/A * and that other protocol code will detect such errors.
0N/A *
0N/A * Note that digesting is normally deferred till after the
0N/A * message has been processed, though to process at least the
0N/A * client's Finished message (i.e. send the server's) we need
0N/A * to acccelerate that digesting.
0N/A *
0N/A * Also, note that hello request messages are never hashed;
0N/A * that includes the hello request header, too.
0N/A */
0N/A if (messageType == HandshakeMessage.ht_hello_request) {
0N/A input.reset();
0N/A processMessage(messageType, messageLen);
0N/A input.ignore(4 + messageLen);
0N/A } else {
0N/A input.mark(messageLen);
0N/A processMessage(messageType, messageLen);
0N/A input.digestNow();
0N/A }
0N/A }
0N/A }
0N/A
0N/A
0N/A /**
2998N/A * Returns true iff the handshaker has been activated.
2998N/A *
2998N/A * In activated state, the handshaker may not send any messages out.
2998N/A */
2998N/A boolean activated() {
2998N/A return state >= -1;
2998N/A }
2998N/A
2998N/A /**
0N/A * Returns true iff the handshaker has sent any messages.
0N/A */
0N/A boolean started() {
2998N/A return state >= 0; // 0: HandshakeMessage.ht_hello_request
3002N/A // 1: HandshakeMessage.ht_client_hello
0N/A }
0N/A
0N/A
0N/A /*
0N/A * Used to kickstart the negotiation ... either writing a
0N/A * ClientHello or a HelloRequest as appropriate, whichever
0N/A * the subclass returns. NOP if handshaking's already started.
0N/A */
0N/A void kickstart() throws IOException {
0N/A if (state >= 0) {
0N/A return;
0N/A }
2998N/A
0N/A HandshakeMessage m = getKickstartMessage();
0N/A
0N/A if (debug != null && Debug.isOn("handshake")) {
0N/A m.print(System.out);
0N/A }
0N/A m.write(output);
0N/A output.flush();
0N/A
0N/A state = m.messageType();
0N/A }
0N/A
0N/A /**
0N/A * Both client and server modes can start handshaking; but the
0N/A * message they send to do so is different.
0N/A */
0N/A abstract HandshakeMessage getKickstartMessage() throws SSLException;
0N/A
0N/A /*
0N/A * Client and Server side protocols are each driven though this
0N/A * call, which processes a single message and drives the appropriate
0N/A * side of the protocol state machine (depending on the subclass).
0N/A */
0N/A abstract void processMessage(byte messageType, int messageLen)
0N/A throws IOException;
0N/A
0N/A /*
0N/A * Most alerts in the protocol relate to handshaking problems.
0N/A * Alerts are detected as the connection reads data.
0N/A */
0N/A abstract void handshakeAlert(byte description) throws SSLProtocolException;
0N/A
0N/A /*
0N/A * Sends a change cipher spec message and updates the write side
0N/A * cipher state so that future messages use the just-negotiated spec.
0N/A */
0N/A void sendChangeCipherSpec(Finished mesg, boolean lastMessage)
0N/A throws IOException {
0N/A
0N/A output.flush(); // i.e. handshake data
0N/A
0N/A /*
0N/A * The write cipher state is protected by the connection write lock
0N/A * so we must grab it while making the change. We also
0N/A * make sure no writes occur between sending the ChangeCipherSpec
0N/A * message, installing the new cipher state, and sending the
0N/A * Finished message.
0N/A *
0N/A * We already hold SSLEngine/SSLSocket "this" by virtue
0N/A * of this being called from the readRecord code.
0N/A */
0N/A OutputRecord r;
0N/A if (conn != null) {
0N/A r = new OutputRecord(Record.ct_change_cipher_spec);
0N/A } else {
0N/A r = new EngineOutputRecord(Record.ct_change_cipher_spec, engine);
0N/A }
0N/A
0N/A r.setVersion(protocolVersion);
0N/A r.write(1); // single byte of data
0N/A
0N/A if (conn != null) {
77N/A conn.writeLock.lock();
77N/A try {
0N/A conn.writeRecord(r);
0N/A conn.changeWriteCiphers();
0N/A if (debug != null && Debug.isOn("handshake")) {
0N/A mesg.print(System.out);
0N/A }
0N/A mesg.write(output);
0N/A output.flush();
77N/A } finally {
77N/A conn.writeLock.unlock();
0N/A }
0N/A } else {
0N/A synchronized (engine.writeLock) {
0N/A engine.writeRecord((EngineOutputRecord)r);
0N/A engine.changeWriteCiphers();
0N/A if (debug != null && Debug.isOn("handshake")) {
0N/A mesg.print(System.out);
0N/A }
0N/A mesg.write(output);
0N/A
0N/A if (lastMessage) {
0N/A output.setFinishedMsg();
0N/A }
0N/A output.flush();
0N/A }
0N/A }
0N/A }
0N/A
0N/A /*
0N/A * Single access point to key calculation logic. Given the
0N/A * pre-master secret and the nonces from client and server,
0N/A * produce all the keying material to be used.
0N/A */
0N/A void calculateKeys(SecretKey preMasterSecret, ProtocolVersion version) {
0N/A SecretKey master = calculateMasterSecret(preMasterSecret, version);
0N/A session.setMasterSecret(master);
0N/A calculateConnectionKeys(master);
0N/A }
0N/A
0N/A
0N/A /*
0N/A * Calculate the master secret from its various components. This is
0N/A * used for key exchange by all cipher suites.
0N/A *
0N/A * The master secret is the catenation of three MD5 hashes, each
0N/A * consisting of the pre-master secret and a SHA1 hash. Those three
0N/A * SHA1 hashes are of (different) constant strings, the pre-master
0N/A * secret, and the nonces provided by the client and the server.
0N/A */
0N/A private SecretKey calculateMasterSecret(SecretKey preMasterSecret,
0N/A ProtocolVersion requestedVersion) {
2998N/A
0N/A if (debug != null && Debug.isOn("keygen")) {
0N/A HexDumpEncoder dump = new HexDumpEncoder();
0N/A
0N/A System.out.println("SESSION KEYGEN:");
0N/A
0N/A System.out.println("PreMaster Secret:");
0N/A printHex(dump, preMasterSecret.getEncoded());
0N/A
0N/A // Nonces are dumped with connection keygen, no
0N/A // benefit to doing it twice
0N/A }
0N/A
3002N/A // What algs/params do we need to use?
3002N/A String masterAlg;
3002N/A PRF prf;
3002N/A
3002N/A if (protocolVersion.v >= ProtocolVersion.TLS12.v) {
3002N/A masterAlg = "SunTls12MasterSecret";
3002N/A prf = cipherSuite.prfAlg;
3002N/A } else {
3002N/A masterAlg = "SunTlsMasterSecret";
3002N/A prf = P_NONE;
3002N/A }
3002N/A
3002N/A String prfHashAlg = prf.getPRFHashAlg();
3002N/A int prfHashLength = prf.getPRFHashLength();
3002N/A int prfBlockSize = prf.getPRFBlockSize();
3002N/A
3002N/A TlsMasterSecretParameterSpec spec = new TlsMasterSecretParameterSpec(
3002N/A preMasterSecret, protocolVersion.major, protocolVersion.minor,
3002N/A clnt_random.random_bytes, svr_random.random_bytes,
3002N/A prfHashAlg, prfHashLength, prfBlockSize);
3002N/A
0N/A SecretKey masterSecret;
0N/A try {
3002N/A KeyGenerator kg = JsseJce.getKeyGenerator(masterAlg);
0N/A kg.init(spec);
0N/A masterSecret = kg.generateKey();
0N/A } catch (GeneralSecurityException e) {
0N/A // For RSA premaster secrets, do not signal a protocol error
0N/A // due to the Bleichenbacher attack. See comments further down.
3002N/A if (!preMasterSecret.getAlgorithm().equals(
3002N/A "TlsRsaPremasterSecret")) {
0N/A throw new ProviderException(e);
0N/A }
2998N/A
0N/A if (debug != null && Debug.isOn("handshake")) {
0N/A System.out.println("RSA master secret generation error:");
0N/A e.printStackTrace(System.out);
0N/A }
2998N/A
2998N/A if (requestedVersion != null) {
2998N/A preMasterSecret =
2998N/A RSAClientKeyExchange.generateDummySecret(requestedVersion);
2998N/A } else {
2998N/A preMasterSecret =
2998N/A RSAClientKeyExchange.generateDummySecret(protocolVersion);
2998N/A }
2998N/A
0N/A // recursive call with new premaster secret
0N/A return calculateMasterSecret(preMasterSecret, null);
0N/A }
0N/A
2998N/A // if no version check requested (client side handshake), or version
2998N/A // information is not available (not an RSA premaster secret),
0N/A // return master secret immediately.
2998N/A if ((requestedVersion == null) ||
2998N/A !(masterSecret instanceof TlsMasterSecret)) {
0N/A return masterSecret;
0N/A }
2998N/A
2998N/A // we have checked the ClientKeyExchange message when reading TLS
2998N/A // record, the following check is necessary to ensure that
2998N/A // JCE provider does not ignore the checking, or the previous
2998N/A // checking process bypassed the premaster secret version checking.
0N/A TlsMasterSecret tlsKey = (TlsMasterSecret)masterSecret;
0N/A int major = tlsKey.getMajorVersion();
0N/A int minor = tlsKey.getMinorVersion();
0N/A if ((major < 0) || (minor < 0)) {
0N/A return masterSecret;
0N/A }
0N/A
0N/A // check if the premaster secret version is ok
0N/A // the specification says that it must be the maximum version supported
0N/A // by the client from its ClientHello message. However, many
0N/A // implementations send the negotiated version, so accept both
2998N/A // for SSL v3.0 and TLS v1.0.
2998N/A // NOTE that we may be comparing two unsupported version numbers, which
2998N/A // is why we cannot use object reference equality in this special case.
2998N/A ProtocolVersion premasterVersion =
2998N/A ProtocolVersion.valueOf(major, minor);
2998N/A boolean versionMismatch = (premasterVersion.v != requestedVersion.v);
0N/A
2998N/A /*
2998N/A * we never checked the client_version in server side
2998N/A * for TLS v1.0 and SSL v3.0. For compatibility, we
2998N/A * maintain this behavior.
2998N/A */
2998N/A if (versionMismatch && requestedVersion.v <= ProtocolVersion.TLS10.v) {
2998N/A versionMismatch = (premasterVersion.v != protocolVersion.v);
2998N/A }
0N/A
0N/A if (versionMismatch == false) {
0N/A // check passed, return key
0N/A return masterSecret;
0N/A }
0N/A
0N/A // Due to the Bleichenbacher attack, do not signal a protocol error.
0N/A // Generate a random premaster secret and continue with the handshake,
0N/A // which will fail when verifying the finished messages.
0N/A // For more information, see comments in PreMasterSecret.
0N/A if (debug != null && Debug.isOn("handshake")) {
0N/A System.out.println("RSA PreMasterSecret version error: expected"
0N/A + protocolVersion + " or " + requestedVersion + ", decrypted: "
0N/A + premasterVersion);
0N/A }
2998N/A preMasterSecret =
2998N/A RSAClientKeyExchange.generateDummySecret(requestedVersion);
2998N/A
0N/A // recursive call with new premaster secret
0N/A return calculateMasterSecret(preMasterSecret, null);
0N/A }
0N/A
0N/A /*
0N/A * Calculate the keys needed for this connection, once the session's
0N/A * master secret has been calculated. Uses the master key and nonces;
0N/A * the amount of keying material generated is a function of the cipher
0N/A * suite that's been negotiated.
0N/A *
0N/A * This gets called both on the "full handshake" (where we exchanged
0N/A * a premaster secret and started a new session) as well as on the
0N/A * "fast handshake" (where we just resumed a pre-existing session).
0N/A */
0N/A void calculateConnectionKeys(SecretKey masterKey) {
0N/A /*
0N/A * For both the read and write sides of the protocol, we use the
0N/A * master to generate MAC secrets and cipher keying material. Block
0N/A * ciphers need initialization vectors, which we also generate.
0N/A *
0N/A * First we figure out how much keying material is needed.
0N/A */
0N/A int hashSize = cipherSuite.macAlg.size;
0N/A boolean is_exportable = cipherSuite.exportable;
0N/A BulkCipher cipher = cipherSuite.cipher;
0N/A int expandedKeySize = is_exportable ? cipher.expandedKeySize : 0;
0N/A
3002N/A // Which algs/params do we need to use?
3002N/A String keyMaterialAlg;
3002N/A PRF prf;
3002N/A
3002N/A if (protocolVersion.v >= ProtocolVersion.TLS12.v) {
3002N/A keyMaterialAlg = "SunTls12KeyMaterial";
3002N/A prf = cipherSuite.prfAlg;
3002N/A } else {
3002N/A keyMaterialAlg = "SunTlsKeyMaterial";
3002N/A prf = P_NONE;
3002N/A }
3002N/A
3002N/A String prfHashAlg = prf.getPRFHashAlg();
3002N/A int prfHashLength = prf.getPRFHashLength();
3002N/A int prfBlockSize = prf.getPRFBlockSize();
3002N/A
3002N/A TlsKeyMaterialParameterSpec spec = new TlsKeyMaterialParameterSpec(
3002N/A masterKey, protocolVersion.major, protocolVersion.minor,
0N/A clnt_random.random_bytes, svr_random.random_bytes,
0N/A cipher.algorithm, cipher.keySize, expandedKeySize,
3002N/A cipher.ivSize, hashSize,
3002N/A prfHashAlg, prfHashLength, prfBlockSize);
0N/A
0N/A try {
3002N/A KeyGenerator kg = JsseJce.getKeyGenerator(keyMaterialAlg);
0N/A kg.init(spec);
0N/A TlsKeyMaterialSpec keySpec = (TlsKeyMaterialSpec)kg.generateKey();
0N/A
0N/A clntWriteKey = keySpec.getClientCipherKey();
0N/A svrWriteKey = keySpec.getServerCipherKey();
0N/A
2998N/A // Return null if IVs are not supposed to be generated.
2998N/A // e.g. TLS 1.1+.
0N/A clntWriteIV = keySpec.getClientIv();
0N/A svrWriteIV = keySpec.getServerIv();
0N/A
0N/A clntMacSecret = keySpec.getClientMacKey();
0N/A svrMacSecret = keySpec.getServerMacKey();
0N/A } catch (GeneralSecurityException e) {
0N/A throw new ProviderException(e);
0N/A }
0N/A
0N/A //
0N/A // Dump the connection keys as they're generated.
0N/A //
0N/A if (debug != null && Debug.isOn("keygen")) {
0N/A synchronized (System.out) {
0N/A HexDumpEncoder dump = new HexDumpEncoder();
0N/A
0N/A System.out.println("CONNECTION KEYGEN:");
0N/A
0N/A // Inputs:
0N/A System.out.println("Client Nonce:");
0N/A printHex(dump, clnt_random.random_bytes);
0N/A System.out.println("Server Nonce:");
0N/A printHex(dump, svr_random.random_bytes);
0N/A System.out.println("Master Secret:");
0N/A printHex(dump, masterKey.getEncoded());
0N/A
0N/A // Outputs:
0N/A System.out.println("Client MAC write Secret:");
0N/A printHex(dump, clntMacSecret.getEncoded());
0N/A System.out.println("Server MAC write Secret:");
0N/A printHex(dump, svrMacSecret.getEncoded());
0N/A
0N/A if (clntWriteKey != null) {
0N/A System.out.println("Client write key:");
0N/A printHex(dump, clntWriteKey.getEncoded());
0N/A System.out.println("Server write key:");
0N/A printHex(dump, svrWriteKey.getEncoded());
0N/A } else {
0N/A System.out.println("... no encryption keys used");
0N/A }
0N/A
0N/A if (clntWriteIV != null) {
0N/A System.out.println("Client write IV:");
0N/A printHex(dump, clntWriteIV.getIV());
0N/A System.out.println("Server write IV:");
0N/A printHex(dump, svrWriteIV.getIV());
0N/A } else {
2998N/A if (protocolVersion.v >= ProtocolVersion.TLS11.v) {
2998N/A System.out.println(
2998N/A "... no IV derived for this protocol");
2998N/A } else {
2998N/A System.out.println("... no IV used for this cipher");
2998N/A }
0N/A }
0N/A System.out.flush();
0N/A }
0N/A }
0N/A }
0N/A
0N/A private static void printHex(HexDumpEncoder dump, byte[] bytes) {
0N/A if (bytes == null) {
0N/A System.out.println("(key bytes not available)");
0N/A } else {
0N/A try {
0N/A dump.encodeBuffer(bytes, System.out);
0N/A } catch (IOException e) {
0N/A // just for debugging, ignore this
0N/A }
0N/A }
0N/A }
0N/A
0N/A /**
0N/A * Throw an SSLException with the specified message and cause.
0N/A * Shorthand until a new SSLException constructor is added.
0N/A * This method never returns.
0N/A */
0N/A static void throwSSLException(String msg, Throwable cause)
0N/A throws SSLException {
0N/A SSLException e = new SSLException(msg);
0N/A e.initCause(cause);
0N/A throw e;
0N/A }
0N/A
0N/A
0N/A /*
0N/A * Implement a simple task delegator.
0N/A *
0N/A * We are currently implementing this as a single delegator, may
0N/A * try for parallel tasks later. Client Authentication could
0N/A * benefit from this, where ClientKeyExchange/CertificateVerify
0N/A * could be carried out in parallel.
0N/A */
0N/A class DelegatedTask<E> implements Runnable {
0N/A
0N/A private PrivilegedExceptionAction<E> pea;
0N/A
0N/A DelegatedTask(PrivilegedExceptionAction<E> pea) {
0N/A this.pea = pea;
0N/A }
0N/A
0N/A public void run() {
0N/A synchronized (engine) {
0N/A try {
0N/A AccessController.doPrivileged(pea, engine.getAcc());
0N/A } catch (PrivilegedActionException pae) {
0N/A thrown = pae.getException();
0N/A } catch (RuntimeException rte) {
0N/A thrown = rte;
0N/A }
0N/A delegatedTask = null;
0N/A taskDelegated = false;
0N/A }
0N/A }
0N/A }
0N/A
0N/A private <T> void delegateTask(PrivilegedExceptionAction<T> pea) {
0N/A delegatedTask = new DelegatedTask<T>(pea);
0N/A taskDelegated = false;
0N/A thrown = null;
0N/A }
0N/A
0N/A DelegatedTask getTask() {
0N/A if (!taskDelegated) {
0N/A taskDelegated = true;
0N/A return delegatedTask;
0N/A } else {
0N/A return null;
0N/A }
0N/A }
0N/A
0N/A /*
0N/A * See if there are any tasks which need to be delegated
0N/A *
0N/A * Locked by SSLEngine.this.
0N/A */
0N/A boolean taskOutstanding() {
0N/A return (delegatedTask != null);
0N/A }
0N/A
0N/A /*
0N/A * The previous caller failed for some reason, report back the
0N/A * Exception. We won't worry about Error's.
0N/A *
0N/A * Locked by SSLEngine.this.
0N/A */
0N/A void checkThrown() throws SSLException {
0N/A synchronized (thrownLock) {
0N/A if (thrown != null) {
0N/A
0N/A String msg = thrown.getMessage();
0N/A
0N/A if (msg == null) {
0N/A msg = "Delegated task threw Exception/Error";
0N/A }
0N/A
0N/A /*
0N/A * See what the underlying type of exception is. We should
0N/A * throw the same thing. Chain thrown to the new exception.
0N/A */
0N/A Exception e = thrown;
0N/A thrown = null;
0N/A
0N/A if (e instanceof RuntimeException) {
0N/A throw (RuntimeException)
0N/A new RuntimeException(msg).initCause(e);
0N/A } else if (e instanceof SSLHandshakeException) {
0N/A throw (SSLHandshakeException)
0N/A new SSLHandshakeException(msg).initCause(e);
0N/A } else if (e instanceof SSLKeyException) {
0N/A throw (SSLKeyException)
0N/A new SSLKeyException(msg).initCause(e);
0N/A } else if (e instanceof SSLPeerUnverifiedException) {
0N/A throw (SSLPeerUnverifiedException)
0N/A new SSLPeerUnverifiedException(msg).initCause(e);
0N/A } else if (e instanceof SSLProtocolException) {
0N/A throw (SSLProtocolException)
0N/A new SSLProtocolException(msg).initCause(e);
0N/A } else {
0N/A /*
0N/A * If it's SSLException or any other Exception,
0N/A * we'll wrap it in an SSLException.
0N/A */
0N/A throw (SSLException)
0N/A new SSLException(msg).initCause(e);
0N/A }
0N/A }
0N/A }
0N/A }
0N/A}