/* * 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.cert.*;import java.security.interfaces.*;import java.security.spec.ECParameterSpec; import javax.crypto.SecretKey;import javax.crypto.spec.SecretKeySpec; import javax.net.ssl.*; import javax.security.auth.Subject; import sun.security.ssl.HandshakeMessage.*;import sun.security.ssl.CipherSuite.*;import sun.security.ssl.SignatureAndHashAlgorithm.*;import static sun.security.ssl.CipherSuite.*;import static sun.security.ssl.CipherSuite.KeyExchange.*; /** * ServerHandshaker does the protocol handshaking from the point * of view of a server. It is driven asychronously by handshake messages * as delivered by the parent Handshaker class, and also uses * common functionality (e.g. key generation) that is provided there. * * @author David Brownell */final class ServerHandshaker extends Handshaker { // is the server going to require the client to authenticate? private byte doClientAuth; // our authentication info private X509Certificate[] certs; private PrivateKey privateKey; private SecretKey[] kerberosKeys; // flag to check for clientCertificateVerify message private boolean needClientVerify = false; /* * For exportable ciphersuites using non-exportable key sizes, we use * ephemeral RSA keys. We could also do anonymous RSA in the same way * but there are no such ciphersuites currently defined. */ private PrivateKey tempPrivateKey; private PublicKey tempPublicKey; /* * For anonymous and ephemeral Diffie-Hellman key exchange, we use * ephemeral Diffie-Hellman keys. */ private DHCrypt dh; // Helper for ECDH based key exchanges private ECDHCrypt ecdh; // version request by the client in its ClientHello // we remember it for the RSA premaster secret version check private ProtocolVersion clientRequestedVersion; private SupportedEllipticCurvesExtension supportedCurves; // the preferable signature algorithm used by ServerKeyExchange message SignatureAndHashAlgorithm preferableSignatureAlgorithm; /* * Constructor ... use the keys found in the auth context. */ ServerHandshaker(SSLSocketImpl socket, SSLContextImpl context, ProtocolList enabledProtocols, byte clientAuth, ProtocolVersion activeProtocolVersion, boolean isInitialHandshake, boolean secureRenegotiation, byte[] clientVerifyData, byte[] serverVerifyData) { super(socket, context, enabledProtocols, (clientAuth != SSLEngineImpl.clauth_none), false, activeProtocolVersion, isInitialHandshake, secureRenegotiation, clientVerifyData, serverVerifyData); doClientAuth = clientAuth; } /* * Constructor ... use the keys found in the auth context. */ ServerHandshaker(SSLEngineImpl engine, SSLContextImpl context, ProtocolList enabledProtocols, byte clientAuth, ProtocolVersion activeProtocolVersion, boolean isInitialHandshake, boolean secureRenegotiation, byte[] clientVerifyData, byte[] serverVerifyData) { super(engine, context, enabledProtocols, (clientAuth != SSLEngineImpl.clauth_none), false, activeProtocolVersion, isInitialHandshake, secureRenegotiation, clientVerifyData, serverVerifyData); doClientAuth = clientAuth; } /* * As long as handshaking has not started, we can change * whether client authentication is required. Otherwise, * we will need to wait for the next handshake. */ void setClientAuth(byte clientAuth) { doClientAuth = clientAuth; } /* * This routine handles all the server side handshake messages, one at * a time. Given the message type (and in some cases the pending cipher * spec) it parses the type-specific message. Then it calls a function * that handles that specific message. * * It updates the state machine as each message is processed, and writes * responses as needed using the connection in the constructor. */ void processMessage(byte type, int message_len) throws IOException { // // In SSLv3 and TLS, messages follow strictly increasing // numerical order _except_ for one annoying special case. // if ((state > type) && (state != HandshakeMessage.ht_client_key_exchange && type != HandshakeMessage.ht_certificate_verify)) { throw new SSLProtocolException( "Handshake message sequence violation, state = " + state + ", type = " + type); } switch (type) { case HandshakeMessage.ht_client_hello: ClientHello ch = new ClientHello(input, message_len); /* * send it off for processing. */ this.clientHello(ch); break; case HandshakeMessage.ht_certificate: if (doClientAuth == SSLEngineImpl.clauth_none) { fatalSE(Alerts.alert_unexpected_message, "client sent unsolicited cert chain"); // NOTREACHED } this.clientCertificate(new CertificateMsg(input)); break; case HandshakeMessage.ht_client_key_exchange: SecretKey preMasterSecret; switch (keyExchange) { case K_RSA: case K_RSA_EXPORT: /* * The client's pre-master secret is decrypted using * either the server's normal private RSA key, or the * temporary one used for non-export or signing-only * certificates/keys. */ RSAClientKeyExchange pms = new RSAClientKeyExchange( protocolVersion, clientRequestedVersion, sslContext.getSecureRandom(), input, message_len, privateKey); preMasterSecret = this.clientKeyExchange(pms); break; case K_KRB5: case K_KRB5_EXPORT: preMasterSecret = this.clientKeyExchange( new KerberosClientKeyExchange(protocolVersion, clientRequestedVersion, sslContext.getSecureRandom(), input, kerberosKeys)); break; case K_DHE_RSA: case K_DHE_DSS: case K_DH_ANON: /* * The pre-master secret is derived using the normal * Diffie-Hellman calculation. Note that the main * protocol difference in these five flavors is in how * the ServerKeyExchange message was constructed! */ preMasterSecret = this.clientKeyExchange( new DHClientKeyExchange(input)); break; case K_ECDH_RSA: case K_ECDH_ECDSA: case K_ECDHE_RSA: case K_ECDHE_ECDSA: case K_ECDH_ANON: preMasterSecret = this.clientKeyExchange (new ECDHClientKeyExchange(input)); break; default: throw new SSLProtocolException ("Unrecognized key exchange: " + keyExchange); } // // All keys are calculated from the premaster secret // and the exchanged nonces in the same way. // calculateKeys(preMasterSecret, clientRequestedVersion); break; case HandshakeMessage.ht_certificate_verify: this.clientCertificateVerify(new CertificateVerify(input, localSupportedSignAlgs, protocolVersion)); break; case HandshakeMessage.ht_finished: this.clientFinished( new Finished(protocolVersion, input, cipherSuite)); break; default: throw new SSLProtocolException( "Illegal server handshake msg, " + type); } // // Move the state machine forward except for that annoying // special case. This means that clients could send extra // cert verify messages; not a problem so long as all of // them actually check out. // if (state < type && type != HandshakeMessage.ht_certificate_verify) { state = type; } } /* * ClientHello presents the server with a bunch of options, to which the * server replies with a ServerHello listing the ones which this session * will use. If needed, it also writes its Certificate plus in some cases * a ServerKeyExchange message. It may also write a CertificateRequest, * to elicit a client certificate. * * All these messages are terminated by a ServerHelloDone message. In * most cases, all this can be sent in a single Record. */ private void clientHello(ClientHello mesg) throws IOException { if (debug != null && Debug.isOn("handshake")) { mesg.print(System.out); } // Does the message include security renegotiation indication? boolean renegotiationIndicated = false; // check the TLS_EMPTY_RENEGOTIATION_INFO_SCSV CipherSuiteList cipherSuites = mesg.getCipherSuites(); if (cipherSuites.contains(CipherSuite.C_SCSV)) { renegotiationIndicated = true; if (isInitialHandshake) { secureRenegotiation = true; } else { // abort the handshake with a fatal handshake_failure alert if (secureRenegotiation) { fatalSE(Alerts.alert_handshake_failure, "The SCSV is present in a secure renegotiation"); } else { fatalSE(Alerts.alert_handshake_failure, "The SCSV is present in a insecure renegotiation"); } } } // check the "renegotiation_info" extension RenegotiationInfoExtension clientHelloRI = (RenegotiationInfoExtension) mesg.extensions.get(ExtensionType.EXT_RENEGOTIATION_INFO); if (clientHelloRI != null) { renegotiationIndicated = true; if (isInitialHandshake) { // verify the length of the "renegotiated_connection" field if (!clientHelloRI.isEmpty()) { // abort the handshake with a fatal handshake_failure alert fatalSE(Alerts.alert_handshake_failure, "The renegotiation_info field is not empty"); } secureRenegotiation = true; } else { if (!secureRenegotiation) { // unexpected RI extension for insecure renegotiation, // abort the handshake with a fatal handshake_failure alert fatalSE(Alerts.alert_handshake_failure, "The renegotiation_info is present in a insecure " + "renegotiation"); } // verify the client_verify_data value if (!Arrays.equals(clientVerifyData, clientHelloRI.getRenegotiatedConnection())) { fatalSE(Alerts.alert_handshake_failure, "Incorrect verify data in ClientHello " + "renegotiation_info message"); } } } else if (!isInitialHandshake && secureRenegotiation) { // if the connection's "secure_renegotiation" flag is set to TRUE // and the "renegotiation_info" extension is not present, abort // the handshake. fatalSE(Alerts.alert_handshake_failure, "Inconsistent secure renegotiation indication"); } // if there is no security renegotiation indication or the previous // handshake is insecure. if (!renegotiationIndicated || !secureRenegotiation) { if (isInitialHandshake) { if (!allowLegacyHelloMessages) { // abort the handshake with a fatal handshake_failure alert fatalSE(Alerts.alert_handshake_failure, "Failed to negotiate the use of secure renegotiation"); } // continue with legacy ClientHello if (debug != null && Debug.isOn("handshake")) { System.out.println("Warning: No renegotiation " + "indication in ClientHello, allow legacy ClientHello"); } } else if (!allowUnsafeRenegotiation) { // abort the handshake if (activeProtocolVersion.v >= ProtocolVersion.TLS10.v) { // response with a no_renegotiation warning, warningSE(Alerts.alert_no_renegotiation); // invalidate the handshake so that the caller can // dispose this object. invalidated = true; // If there is still unread block in the handshake // input stream, it would be truncated with the disposal // and the next handshake message will become incomplete. // // However, according to SSL/TLS specifications, no more // handshake message could immediately follow ClientHello // or HelloRequest. But in case of any improper messages, // we'd better check to ensure there is no remaining bytes // in the handshake input stream. if (input.available() > 0) { fatalSE(Alerts.alert_unexpected_message, "ClientHello followed by an unexpected " + "handshake message"); } return; } else { // For SSLv3, send the handshake_failure fatal error. // Note that SSLv3 does not define a no_renegotiation // alert like TLSv1. However we cannot ignore the message // simply, otherwise the other side was waiting for a // response that would never come. fatalSE(Alerts.alert_handshake_failure, "Renegotiation is not allowed"); } } else { // !isInitialHandshake && allowUnsafeRenegotiation // continue with unsafe renegotiation. if (debug != null && Debug.isOn("handshake")) { System.out.println( "Warning: continue with insecure renegotiation"); } } } /* * Always make sure this entire record has been digested before we * start emitting output, to ensure correct digesting order. */ input.digestNow(); /* * FIRST, construct the ServerHello using the options and priorities * from the ClientHello. Update the (pending) cipher spec as we do * so, and save the client's version to protect against rollback * attacks. * * There are a bunch of minor tasks here, and one major one: deciding * if the short or the full handshake sequence will be used. */ ServerHello m1 = new ServerHello(); clientRequestedVersion = mesg.protocolVersion; // select a proper protocol version. ProtocolVersion selectedVersion = selectProtocolVersion(clientRequestedVersion); if (selectedVersion == null || selectedVersion.v == ProtocolVersion.SSL20Hello.v) { fatalSE(Alerts.alert_handshake_failure, "Client requested protocol " + clientRequestedVersion + " not enabled or not supported"); } handshakeHash.protocolDetermined(selectedVersion); setVersion(selectedVersion); m1.protocolVersion = protocolVersion; // // random ... save client and server values for later use // in computing the master secret (from pre-master secret) // and thence the other crypto keys. // // NOTE: this use of three inputs to generating _each_ set // of ciphers slows things down, but it does increase the // security since each connection in the session can hold // its own authenticated (and strong) keys. One could make // creation of a session a rare thing... // clnt_random = mesg.clnt_random; svr_random = new RandomCookie(sslContext.getSecureRandom()); m1.svr_random = svr_random; session = null; // forget about the current session // // Here we go down either of two paths: (a) the fast one, where // the client's asked to rejoin an existing session, and the server // permits this; (b) the other one, where a new session is created. // if (mesg.sessionId.length() != 0) { // client is trying to resume a session, let's see... SSLSessionImpl previous = ((SSLSessionContextImpl)sslContext .engineGetServerSessionContext()) .get(mesg.sessionId.getId()); // // Check if we can use the fast path, resuming a session. We // can do so iff we have a valid record for that session, and // the cipher suite for that session was on the list which the // client requested, and if we're not forgetting any needed // authentication on the part of the client. // if (previous != null) { resumingSession = previous.isRejoinable(); if (resumingSession) { ProtocolVersion oldVersion = previous.getProtocolVersion(); // cannot resume session with different version if (oldVersion != protocolVersion) { resumingSession = false; } } if (resumingSession && (doClientAuth == SSLEngineImpl.clauth_required)) { try { previous.getPeerPrincipal(); } catch (SSLPeerUnverifiedException e) { resumingSession = false; } } // validate subject identity if (resumingSession) { CipherSuite suite = previous.getSuite(); if (suite.keyExchange == K_KRB5 || suite.keyExchange == K_KRB5_EXPORT) { Principal localPrincipal = previous.getLocalPrincipal(); Subject subject = null; try { subject = AccessController.doPrivileged( new PrivilegedExceptionAction<Subject>() { public Subject run() throws Exception { return Krb5Helper.getServerSubject(getAccSE()); }});Lines 1–500 of 1678. Load more
/* * 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.cert.*; import java.security.interfaces.*; import java.security.spec.ECParameterSpec; import javax.crypto.SecretKey; import javax.crypto.spec.SecretKeySpec; import javax.net.ssl.*; import javax.security.auth.Subject; import sun.security.ssl.HandshakeMessage.*; import sun.security.ssl.CipherSuite.*; import sun.security.ssl.SignatureAndHashAlgorithm.*; import static sun.security.ssl.CipherSuite.*; import static sun.security.ssl.CipherSuite.KeyExchange.*; /** * ServerHandshaker does the protocol handshaking from the point * of view of a server. It is driven asychronously by handshake messages * as delivered by the parent Handshaker class, and also uses * common functionality (e.g. key generation) that is provided there. * * @author David Brownell */ final class ServerHandshaker extends Handshaker { // is the server going to require the client to authenticate? private byte doClientAuth; // our authentication info private X509Certificate[] certs; private PrivateKey privateKey; private SecretKey[] kerberosKeys; // flag to check for clientCertificateVerify message private boolean needClientVerify = false; /* * For exportable ciphersuites using non-exportable key sizes, we use * ephemeral RSA keys. We could also do anonymous RSA in the same way * but there are no such ciphersuites currently defined. */ private PrivateKey tempPrivateKey; private PublicKey tempPublicKey; /* * For anonymous and ephemeral Diffie-Hellman key exchange, we use * ephemeral Diffie-Hellman keys. */ private DHCrypt dh; // Helper for ECDH based key exchanges private ECDHCrypt ecdh; // version request by the client in its ClientHello // we remember it for the RSA premaster secret version check private ProtocolVersion clientRequestedVersion; private SupportedEllipticCurvesExtension supportedCurves; // the preferable signature algorithm used by ServerKeyExchange message SignatureAndHashAlgorithm preferableSignatureAlgorithm; /* * Constructor ... use the keys found in the auth context. */ ServerHandshaker(SSLSocketImpl socket, SSLContextImpl context, ProtocolList enabledProtocols, byte clientAuth, ProtocolVersion activeProtocolVersion, boolean isInitialHandshake, boolean secureRenegotiation, byte[] clientVerifyData, byte[] serverVerifyData) { super(socket, context, enabledProtocols, (clientAuth != SSLEngineImpl.clauth_none), false, activeProtocolVersion, isInitialHandshake, secureRenegotiation, clientVerifyData, serverVerifyData); doClientAuth = clientAuth; } /* * Constructor ... use the keys found in the auth context. */ ServerHandshaker(SSLEngineImpl engine, SSLContextImpl context, ProtocolList enabledProtocols, byte clientAuth, ProtocolVersion activeProtocolVersion, boolean isInitialHandshake, boolean secureRenegotiation, byte[] clientVerifyData, byte[] serverVerifyData) { super(engine, context, enabledProtocols, (clientAuth != SSLEngineImpl.clauth_none), false, activeProtocolVersion, isInitialHandshake, secureRenegotiation, clientVerifyData, serverVerifyData); doClientAuth = clientAuth; } /* * As long as handshaking has not started, we can change * whether client authentication is required. Otherwise, * we will need to wait for the next handshake. */ void setClientAuth(byte clientAuth) { doClientAuth = clientAuth; } /* * This routine handles all the server side handshake messages, one at * a time. Given the message type (and in some cases the pending cipher * spec) it parses the type-specific message. Then it calls a function * that handles that specific message. * * It updates the state machine as each message is processed, and writes * responses as needed using the connection in the constructor. */ void processMessage(byte type, int message_len) throws IOException { // // In SSLv3 and TLS, messages follow strictly increasing // numerical order _except_ for one annoying special case. // if ((state > type) && (state != HandshakeMessage.ht_client_key_exchange && type != HandshakeMessage.ht_certificate_verify)) { throw new SSLProtocolException( "Handshake message sequence violation, state = " + state + ", type = " + type); } switch (type) { case HandshakeMessage.ht_client_hello: ClientHello ch = new ClientHello(input, message_len); /* * send it off for processing. */ this.clientHello(ch); break; case HandshakeMessage.ht_certificate: if (doClientAuth == SSLEngineImpl.clauth_none) { fatalSE(Alerts.alert_unexpected_message, "client sent unsolicited cert chain"); // NOTREACHED } this.clientCertificate(new CertificateMsg(input)); break; case HandshakeMessage.ht_client_key_exchange: SecretKey preMasterSecret; switch (keyExchange) { case K_RSA: case K_RSA_EXPORT: /* * The client's pre-master secret is decrypted using * either the server's normal private RSA key, or the * temporary one used for non-export or signing-only * certificates/keys. */ RSAClientKeyExchange pms = new RSAClientKeyExchange( protocolVersion, clientRequestedVersion, sslContext.getSecureRandom(), input, message_len, privateKey); preMasterSecret = this.clientKeyExchange(pms); break; case K_KRB5: case K_KRB5_EXPORT: preMasterSecret = this.clientKeyExchange( new KerberosClientKeyExchange(protocolVersion, clientRequestedVersion, sslContext.getSecureRandom(), input, kerberosKeys)); break; case K_DHE_RSA: case K_DHE_DSS: case K_DH_ANON: /* * The pre-master secret is derived using the normal * Diffie-Hellman calculation. Note that the main * protocol difference in these five flavors is in how * the ServerKeyExchange message was constructed! */ preMasterSecret = this.clientKeyExchange( new DHClientKeyExchange(input)); break; case K_ECDH_RSA: case K_ECDH_ECDSA: case K_ECDHE_RSA: case K_ECDHE_ECDSA: case K_ECDH_ANON: preMasterSecret = this.clientKeyExchange (new ECDHClientKeyExchange(input)); break; default: throw new SSLProtocolException ("Unrecognized key exchange: " + keyExchange); } // // All keys are calculated from the premaster secret // and the exchanged nonces in the same way. // calculateKeys(preMasterSecret, clientRequestedVersion); break; case HandshakeMessage.ht_certificate_verify: this.clientCertificateVerify(new CertificateVerify(input, localSupportedSignAlgs, protocolVersion)); break; case HandshakeMessage.ht_finished: this.clientFinished( new Finished(protocolVersion, input, cipherSuite)); break; default: throw new SSLProtocolException( "Illegal server handshake msg, " + type); } // // Move the state machine forward except for that annoying // special case. This means that clients could send extra // cert verify messages; not a problem so long as all of // them actually check out. // if (state < type && type != HandshakeMessage.ht_certificate_verify) { state = type; } } /* * ClientHello presents the server with a bunch of options, to which the * server replies with a ServerHello listing the ones which this session * will use. If needed, it also writes its Certificate plus in some cases * a ServerKeyExchange message. It may also write a CertificateRequest, * to elicit a client certificate. * * All these messages are terminated by a ServerHelloDone message. In * most cases, all this can be sent in a single Record. */ private void clientHello(ClientHello mesg) throws IOException { if (debug != null && Debug.isOn("handshake")) { mesg.print(System.out); } // Does the message include security renegotiation indication? boolean renegotiationIndicated = false; // check the TLS_EMPTY_RENEGOTIATION_INFO_SCSV CipherSuiteList cipherSuites = mesg.getCipherSuites(); if (cipherSuites.contains(CipherSuite.C_SCSV)) { renegotiationIndicated = true; if (isInitialHandshake) { secureRenegotiation = true; } else { // abort the handshake with a fatal handshake_failure alert if (secureRenegotiation) { fatalSE(Alerts.alert_handshake_failure, "The SCSV is present in a secure renegotiation"); } else { fatalSE(Alerts.alert_handshake_failure, "The SCSV is present in a insecure renegotiation"); } } } // check the "renegotiation_info" extension RenegotiationInfoExtension clientHelloRI = (RenegotiationInfoExtension) mesg.extensions.get(ExtensionType.EXT_RENEGOTIATION_INFO); if (clientHelloRI != null) { renegotiationIndicated = true; if (isInitialHandshake) { // verify the length of the "renegotiated_connection" field if (!clientHelloRI.isEmpty()) { // abort the handshake with a fatal handshake_failure alert fatalSE(Alerts.alert_handshake_failure, "The renegotiation_info field is not empty"); } secureRenegotiation = true; } else { if (!secureRenegotiation) { // unexpected RI extension for insecure renegotiation, // abort the handshake with a fatal handshake_failure alert fatalSE(Alerts.alert_handshake_failure, "The renegotiation_info is present in a insecure " + "renegotiation"); } // verify the client_verify_data value if (!Arrays.equals(clientVerifyData, clientHelloRI.getRenegotiatedConnection())) { fatalSE(Alerts.alert_handshake_failure, "Incorrect verify data in ClientHello " + "renegotiation_info message"); } } } else if (!isInitialHandshake && secureRenegotiation) { // if the connection's "secure_renegotiation" flag is set to TRUE // and the "renegotiation_info" extension is not present, abort // the handshake. fatalSE(Alerts.alert_handshake_failure, "Inconsistent secure renegotiation indication"); } // if there is no security renegotiation indication or the previous // handshake is insecure. if (!renegotiationIndicated || !secureRenegotiation) { if (isInitialHandshake) { if (!allowLegacyHelloMessages) { // abort the handshake with a fatal handshake_failure alert fatalSE(Alerts.alert_handshake_failure, "Failed to negotiate the use of secure renegotiation"); } // continue with legacy ClientHello if (debug != null && Debug.isOn("handshake")) { System.out.println("Warning: No renegotiation " + "indication in ClientHello, allow legacy ClientHello"); } } else if (!allowUnsafeRenegotiation) { // abort the handshake if (activeProtocolVersion.v >= ProtocolVersion.TLS10.v) { // response with a no_renegotiation warning, warningSE(Alerts.alert_no_renegotiation); // invalidate the handshake so that the caller can // dispose this object. invalidated = true; // If there is still unread block in the handshake // input stream, it would be truncated with the disposal // and the next handshake message will become incomplete. // // However, according to SSL/TLS specifications, no more // handshake message could immediately follow ClientHello // or HelloRequest. But in case of any improper messages, // we'd better check to ensure there is no remaining bytes // in the handshake input stream. if (input.available() > 0) { fatalSE(Alerts.alert_unexpected_message, "ClientHello followed by an unexpected " + "handshake message"); } return; } else { // For SSLv3, send the handshake_failure fatal error. // Note that SSLv3 does not define a no_renegotiation // alert like TLSv1. However we cannot ignore the message // simply, otherwise the other side was waiting for a // response that would never come. fatalSE(Alerts.alert_handshake_failure, "Renegotiation is not allowed"); } } else { // !isInitialHandshake && allowUnsafeRenegotiation // continue with unsafe renegotiation. if (debug != null && Debug.isOn("handshake")) { System.out.println( "Warning: continue with insecure renegotiation"); } } } /* * Always make sure this entire record has been digested before we * start emitting output, to ensure correct digesting order. */ input.digestNow(); /* * FIRST, construct the ServerHello using the options and priorities * from the ClientHello. Update the (pending) cipher spec as we do * so, and save the client's version to protect against rollback * attacks. * * There are a bunch of minor tasks here, and one major one: deciding * if the short or the full handshake sequence will be used. */ ServerHello m1 = new ServerHello(); clientRequestedVersion = mesg.protocolVersion; // select a proper protocol version. ProtocolVersion selectedVersion = selectProtocolVersion(clientRequestedVersion); if (selectedVersion == null || selectedVersion.v == ProtocolVersion.SSL20Hello.v) { fatalSE(Alerts.alert_handshake_failure, "Client requested protocol " + clientRequestedVersion + " not enabled or not supported"); } handshakeHash.protocolDetermined(selectedVersion); setVersion(selectedVersion); m1.protocolVersion = protocolVersion; // // random ... save client and server values for later use // in computing the master secret (from pre-master secret) // and thence the other crypto keys. // // NOTE: this use of three inputs to generating _each_ set // of ciphers slows things down, but it does increase the // security since each connection in the session can hold // its own authenticated (and strong) keys. One could make // creation of a session a rare thing... // clnt_random = mesg.clnt_random; svr_random = new RandomCookie(sslContext.getSecureRandom()); m1.svr_random = svr_random; session = null; // forget about the current session // // Here we go down either of two paths: (a) the fast one, where // the client's asked to rejoin an existing session, and the server // permits this; (b) the other one, where a new session is created. // if (mesg.sessionId.length() != 0) { // client is trying to resume a session, let's see... SSLSessionImpl previous = ((SSLSessionContextImpl)sslContext .engineGetServerSessionContext()) .get(mesg.sessionId.getId()); // // Check if we can use the fast path, resuming a session. We // can do so iff we have a valid record for that session, and // the cipher suite for that session was on the list which the // client requested, and if we're not forgetting any needed // authentication on the part of the client. // if (previous != null) { resumingSession = previous.isRejoinable(); if (resumingSession) { ProtocolVersion oldVersion = previous.getProtocolVersion(); // cannot resume session with different version if (oldVersion != protocolVersion) { resumingSession = false; } } if (resumingSession && (doClientAuth == SSLEngineImpl.clauth_required)) { try { previous.getPeerPrincipal(); } catch (SSLPeerUnverifiedException e) { resumingSession = false; } } // validate subject identity if (resumingSession) { CipherSuite suite = previous.getSuite(); if (suite.keyExchange == K_KRB5 || suite.keyExchange == K_KRB5_EXPORT) { Principal localPrincipal = previous.getLocalPrincipal(); Subject subject = null; try { subject = AccessController.doPrivileged( new PrivilegedExceptionAction<Subject>() { public Subject run() throws Exception { return Krb5Helper.getServerSubject(getAccSE()); }});