--- old/src/java.base/share/classes/sun/security/ssl/ServerHandshaker.java 2018-05-11 15:10:27.180689700 -0700 +++ /dev/null 2018-05-11 10:42:23.849000000 -0700 @@ -1,2344 +0,0 @@ -/* - * Copyright (c) 1996, 2017, 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.util.concurrent.TimeUnit; -import java.security.*; -import java.security.cert.*; -import java.security.interfaces.*; -import java.security.spec.ECParameterSpec; -import java.math.BigInteger; -import java.util.function.BiFunction; - -import javax.crypto.SecretKey; -import javax.net.ssl.*; - -import sun.security.action.GetLongAction; -import sun.security.util.KeyUtil; -import sun.security.util.LegacyAlgorithmConstraints; -import sun.security.action.GetPropertyAction; -import sun.security.ssl.HandshakeMessage.*; -import sun.security.ssl.CipherSuite.*; -import sun.security.ssl.SignatureAndHashAlgorithm.*; -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 { - - // The default number of milliseconds the handshaker will wait for - // revocation status responses. - private static final long DEFAULT_STATUS_RESP_DELAY = 5000; - - // is the server going to require the client to authenticate? - private ClientAuthType doClientAuth; - - // our authentication info - private X509Certificate[] certs; - private PrivateKey privateKey; - - private Object serviceCreds; - - // 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; - - // client supported elliptic curves - private SupportedGroupsExtension requestedGroups; - - // the preferable signature algorithm used by ServerKeyExchange message - SignatureAndHashAlgorithm preferableSignatureAlgorithm; - - // Flag to use smart ephemeral DH key which size matches the corresponding - // authentication key - private static final boolean useSmartEphemeralDHKeys; - - // Flag to use legacy ephemeral DH key which size is 512 bits for - // exportable cipher suites, and 768 bits for others - private static final boolean useLegacyEphemeralDHKeys; - - // The customized ephemeral DH key size for non-exportable cipher suites. - private static final int customizedDHKeySize; - - // legacy algorithm constraints - private static final AlgorithmConstraints legacyAlgorithmConstraints = - new LegacyAlgorithmConstraints( - LegacyAlgorithmConstraints.PROPERTY_TLS_LEGACY_ALGS, - new SSLAlgorithmDecomposer()); - - private long statusRespTimeout; - - static { - String property = GetPropertyAction - .privilegedGetProperty("jdk.tls.ephemeralDHKeySize"); - if (property == null || property.length() == 0) { - useLegacyEphemeralDHKeys = false; - useSmartEphemeralDHKeys = false; - customizedDHKeySize = -1; - } else if ("matched".equals(property)) { - useLegacyEphemeralDHKeys = false; - useSmartEphemeralDHKeys = true; - customizedDHKeySize = -1; - } else if ("legacy".equals(property)) { - useLegacyEphemeralDHKeys = true; - useSmartEphemeralDHKeys = false; - customizedDHKeySize = -1; - } else { - useLegacyEphemeralDHKeys = false; - useSmartEphemeralDHKeys = false; - - try { - // DH parameter generation can be extremely slow, best to - // use one of the supported pre-computed DH parameters - // (see DHCrypt class). - customizedDHKeySize = Integer.parseUnsignedInt(property); - if (customizedDHKeySize < 1024 || customizedDHKeySize > 8192 || - (customizedDHKeySize & 0x3f) != 0) { - throw new IllegalArgumentException( - "Unsupported customized DH key size: " + - customizedDHKeySize + ". " + - "The key size must be multiple of 64, " + - "and can only range from 1024 to 8192 (inclusive)"); - } - } catch (NumberFormatException nfe) { - throw new IllegalArgumentException( - "Invalid system property jdk.tls.ephemeralDHKeySize"); - } - } - } - - /* - * Constructor ... use the keys found in the auth context. - */ - ServerHandshaker(SSLSocketImpl socket, SSLContextImpl context, - ProtocolList enabledProtocols, ClientAuthType clientAuth, - ProtocolVersion activeProtocolVersion, boolean isInitialHandshake, - boolean secureRenegotiation, - byte[] clientVerifyData, byte[] serverVerifyData) { - - super(socket, context, enabledProtocols, - (clientAuth != ClientAuthType.CLIENT_AUTH_NONE), false, - activeProtocolVersion, isInitialHandshake, secureRenegotiation, - clientVerifyData, serverVerifyData); - doClientAuth = clientAuth; - statusRespTimeout = AccessController.doPrivileged( - new GetLongAction("jdk.tls.stapling.responseTimeout", - DEFAULT_STATUS_RESP_DELAY)); - statusRespTimeout = statusRespTimeout >= 0 ? statusRespTimeout : - DEFAULT_STATUS_RESP_DELAY; - } - - /* - * Constructor ... use the keys found in the auth context. - */ - ServerHandshaker(SSLEngineImpl engine, SSLContextImpl context, - ProtocolList enabledProtocols, ClientAuthType clientAuth, - ProtocolVersion activeProtocolVersion, - boolean isInitialHandshake, boolean secureRenegotiation, - byte[] clientVerifyData, byte[] serverVerifyData, - boolean isDTLS) { - - super(engine, context, enabledProtocols, - (clientAuth != ClientAuthType.CLIENT_AUTH_NONE), false, - activeProtocolVersion, isInitialHandshake, secureRenegotiation, - clientVerifyData, serverVerifyData, isDTLS); - doClientAuth = clientAuth; - statusRespTimeout = AccessController.doPrivileged( - new GetLongAction("jdk.tls.stapling.responseTimeout", - DEFAULT_STATUS_RESP_DELAY)); - statusRespTimeout = statusRespTimeout >= 0 ? statusRespTimeout : - DEFAULT_STATUS_RESP_DELAY; - } - - /* - * 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(ClientAuthType 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. - */ - @Override - void processMessage(byte type, int message_len) - throws IOException { - - // check the handshake state - handshakeState.check(type); - - switch (type) { - case HandshakeMessage.ht_client_hello: - ClientHello ch = new ClientHello(input, message_len, isDTLS); - handshakeState.update(ch, resumingSession); - - /* - * send it off for processing. - */ - this.clientHello(ch); - break; - - case HandshakeMessage.ht_certificate: - if (doClientAuth == ClientAuthType.CLIENT_AUTH_NONE) { - fatalSE(Alerts.alert_unexpected_message, - "client sent unsolicited cert chain"); - // NOTREACHED - } - CertificateMsg certificateMsg = new CertificateMsg(input); - handshakeState.update(certificateMsg, resumingSession); - this.clientCertificate(certificateMsg); - 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); - handshakeState.update(pms, resumingSession); - preMasterSecret = this.clientKeyExchange(pms); - 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! - */ - DHClientKeyExchange dhcke = new DHClientKeyExchange(input); - handshakeState.update(dhcke, resumingSession); - preMasterSecret = this.clientKeyExchange(dhcke); - break; - case K_ECDH_RSA: - case K_ECDH_ECDSA: - case K_ECDHE_RSA: - case K_ECDHE_ECDSA: - case K_ECDH_ANON: - ECDHClientKeyExchange ecdhcke = - new ECDHClientKeyExchange(input); - handshakeState.update(ecdhcke, resumingSession); - preMasterSecret = this.clientKeyExchange(ecdhcke); - break; - default: - ClientKeyExchangeService p = - ClientKeyExchangeService.find(keyExchange.name); - if (p == null) { - throw new SSLProtocolException - ("Unrecognized key exchange: " + keyExchange); - } - byte[] encodedTicket = input.getBytes16(); - input.getBytes16(); - byte[] secret = input.getBytes16(); - ClientKeyExchange cke = p.createServerExchange(protocolVersion, - clientRequestedVersion, - sslContext.getSecureRandom(), - encodedTicket, - secret, - this.getAccSE(), serviceCreds); - handshakeState.update(cke, resumingSession); - preMasterSecret = this.clientKeyExchange(cke); - break; - } - - // - // 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: - CertificateVerify cvm = - new CertificateVerify(input, - getLocalSupportedSignAlgs(), protocolVersion); - handshakeState.update(cvm, resumingSession); - this.clientCertificateVerify(cvm); - - break; - - case HandshakeMessage.ht_finished: - Finished cfm = - new Finished(protocolVersion, input, cipherSuite); - handshakeState.update(cfm, resumingSession); - this.clientFinished(cfm); - - break; - - default: - throw new SSLProtocolException( - "Illegal server handshake msg, " + 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); - } - - // Reject client initiated renegotiation? - // - // If server side should reject client-initiated renegotiation, - // send an alert_handshake_failure fatal alert, not a no_renegotiation - // warning alert (no_renegotiation must be a warning: RFC 2246). - // no_renegotiation might seem more natural at first, but warnings - // are not appropriate because the sending party does not know how - // the receiving party will behave. This state must be treated as - // a fatal server condition. - // - // This will not have any impact on server initiated renegotiation. - if (rejectClientInitiatedRenego && !isInitialHandshake && - !serverHelloRequested) { - fatalSE(Alerts.alert_handshake_failure, - "Client initiated renegotiation is not allowed"); - } - - // check the server name indication if required - ServerNameExtension clientHelloSNIExt = (ServerNameExtension) - mesg.extensions.get(ExtensionType.EXT_SERVER_NAME); - if (!sniMatchers.isEmpty()) { - // we do not reject client without SNI extension - if (clientHelloSNIExt != null && - !clientHelloSNIExt.isMatched(sniMatchers)) { - fatalSE(Alerts.alert_unrecognized_name, - "Unrecognized server name indication"); - } - } - - // 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 (!MessageDigest.isEqual(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.useTLS10PlusSpec()) { - // respond 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"); - } - } - } - - // check the "max_fragment_length" extension - MaxFragmentLengthExtension maxFragLenExt = (MaxFragmentLengthExtension) - mesg.extensions.get(ExtensionType.EXT_MAX_FRAGMENT_LENGTH); - if ((maxFragLenExt != null) && (maximumPacketSize != 0)) { - // Not yet consider the impact of IV/MAC/padding. - int estimatedMaxFragSize = maximumPacketSize; - if (isDTLS) { - estimatedMaxFragSize -= DTLSRecord.headerSize; - } else { - estimatedMaxFragSize -= SSLRecord.headerSize; - } - - if (maxFragLenExt.getMaxFragLen() > estimatedMaxFragSize) { - // For better interoperability, abort the maximum fragment - // length negotiation, rather than terminate the connection - // with a fatal alert. - maxFragLenExt = null; - - // fatalSE(Alerts.alert_illegal_parameter, - // "Not an allowed max_fragment_length value"); - } - } - - // check out the "extended_master_secret" extension - if (useExtendedMasterSecret) { - ExtendedMasterSecretExtension extendedMasterSecretExtension = - (ExtendedMasterSecretExtension)mesg.extensions.get( - ExtensionType.EXT_EXTENDED_MASTER_SECRET); - if (extendedMasterSecretExtension != null) { - requestedToUseEMS = true; - } else if (mesg.protocolVersion.useTLS10PlusSpec()) { - if (!allowLegacyMasterSecret) { - // For full handshake, if the server receives a ClientHello - // without the extension, it SHOULD abort the handshake if - // it does not wish to interoperate with legacy clients. - // - // As if extended master extension is required for full - // handshake, it MUST be used in abbreviated handshake too. - fatalSE(Alerts.alert_handshake_failure, - "Extended Master Secret extension is required"); - } - } - } - - // check the ALPN extension - ALPNExtension clientHelloALPN = (ALPNExtension) - mesg.extensions.get(ExtensionType.EXT_ALPN); - - // Use the application protocol callback when provided. - // Otherwise use the local list of application protocols. - boolean hasAPCallback = - ((engine != null && appProtocolSelectorSSLEngine != null) || - (conn != null && appProtocolSelectorSSLSocket != null)); - - if (!hasAPCallback) { - if ((clientHelloALPN != null) && (localApl.length > 0)) { - - // Intersect the requested and the locally supported, - // and save for later. - String negotiatedValue = null; - List protocols = clientHelloALPN.getPeerAPs(); - - // Use server preference order - for (String ap : localApl) { - if (protocols.contains(ap)) { - negotiatedValue = ap; - break; - } - } - - if (negotiatedValue == null) { - fatalSE(Alerts.alert_no_application_protocol, - new SSLHandshakeException( - "No matching ALPN values")); - } - applicationProtocol = negotiatedValue; - - } else { - applicationProtocol = ""; - } - } // Otherwise, applicationProtocol will be set by the callback. - - 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 != mesg.protocolVersion) { - resumingSession = false; - } - } - - if (resumingSession && useExtendedMasterSecret) { - if (requestedToUseEMS && - !previous.getUseExtendedMasterSecret()) { - // For abbreviated handshake request, If the original - // session did not use the "extended_master_secret" - // extension but the new ClientHello contains the - // extension, then the server MUST NOT perform the - // abbreviated handshake. Instead, it SHOULD continue - // with a full handshake. - resumingSession = false; - } else if (!requestedToUseEMS && - previous.getUseExtendedMasterSecret()) { - // For abbreviated handshake request, if the original - // session used the "extended_master_secret" extension - // but the new ClientHello does not contain it, the - // server MUST abort the abbreviated handshake. - fatalSE(Alerts.alert_handshake_failure, - "Missing Extended Master Secret extension " + - "on session resumption"); - } else if (!requestedToUseEMS && - !previous.getUseExtendedMasterSecret()) { - // For abbreviated handshake request, if neither the - // original session nor the new ClientHello uses the - // extension, the server SHOULD abort the handshake. - if (!allowLegacyResumption) { - fatalSE(Alerts.alert_handshake_failure, - "Missing Extended Master Secret extension " + - "on session resumption"); - } else { // Otherwise, continue with a full handshake. - resumingSession = false; - } - } - } - - // cannot resume session with different server name indication - if (resumingSession) { - List oldServerNames = - previous.getRequestedServerNames(); - if (clientHelloSNIExt != null) { - if (!clientHelloSNIExt.isIdentical(oldServerNames)) { - resumingSession = false; - } - } else if (!oldServerNames.isEmpty()) { - resumingSession = false; - } - - if (!resumingSession && - debug != null && Debug.isOn("handshake")) { - System.out.println( - "The requested server name indication " + - "is not identical to the previous one"); - } - } - - if (resumingSession && - (doClientAuth == ClientAuthType.CLIENT_AUTH_REQUIRED)) { - try { - previous.getPeerPrincipal(); - } catch (SSLPeerUnverifiedException e) { - resumingSession = false; - } - } - - // validate subject identity - if (resumingSession) { - CipherSuite suite = previous.getSuite(); - ClientKeyExchangeService p = - ClientKeyExchangeService.find(suite.keyExchange.name); - if (p != null) { - Principal localPrincipal = previous.getLocalPrincipal(); - - if (p.isRelated( - false, getAccSE(), localPrincipal)) { - if (debug != null && Debug.isOn("session")) - System.out.println("Subject can" + - " provide creds for princ"); - } else { - resumingSession = false; - if (debug != null && Debug.isOn("session")) - System.out.println("Subject cannot" + - " provide creds for princ"); - } - } - } - - if (resumingSession) { - CipherSuite suite = previous.getSuite(); - // verify that the ciphersuite from the cached session - // is in the list of client requested ciphersuites and - // we have it enabled - if ((isNegotiable(suite) == false) || - (mesg.getCipherSuites().contains(suite) == false)) { - resumingSession = false; - } else { - // everything looks ok, set the ciphersuite - // this should be done last when we are sure we - // will resume - setCipherSuite(suite); - } - } - - if (resumingSession) { - session = previous; - if (debug != null && - (Debug.isOn("handshake") || Debug.isOn("session"))) { - System.out.println("%% Resuming " + session); - } - } - } - } // else client did not try to resume - - // cookie exchange - if (isDTLS && !resumingSession) { - HelloCookieManager hcMgr = sslContext.getHelloCookieManager(); - if ((mesg.cookie == null) || (mesg.cookie.length == 0) || - (!hcMgr.isValid(mesg))) { - - // - // Perform cookie exchange for DTLS handshaking if no cookie - // or the cookie is invalid in the ClientHello message. - // - HelloVerifyRequest m0 = new HelloVerifyRequest(hcMgr, mesg); - - if (debug != null && Debug.isOn("handshake")) { - m0.print(System.out); - } - - m0.write(output); - handshakeState.update(m0, resumingSession); - output.flush(); - - return; - } - } - - /* - * 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; - - // - // If client hasn't specified a session we can resume, start a - // new one and choose its cipher suite and compression options. - // Unless new session creation is disabled for this connection! - // - if (session == null) { - if (!enableNewSession) { - throw new SSLException("Client did not resume a session"); - } - - requestedGroups = (SupportedGroupsExtension) - mesg.extensions.get(ExtensionType.EXT_SUPPORTED_GROUPS); - - // We only need to handle the "signature_algorithm" extension - // for full handshakes and TLS 1.2 or later. - if (protocolVersion.useTLS12PlusSpec()) { - SignatureAlgorithmsExtension signAlgs = - (SignatureAlgorithmsExtension)mesg.extensions.get( - ExtensionType.EXT_SIGNATURE_ALGORITHMS); - if (signAlgs != null) { - Collection peerSignAlgs = - signAlgs.getSignAlgorithms(); - if (peerSignAlgs == null || peerSignAlgs.isEmpty()) { - throw new SSLHandshakeException( - "No peer supported signature algorithms"); - } - - Collection - supportedPeerSignAlgs = - SignatureAndHashAlgorithm.getSupportedAlgorithms( - algorithmConstraints, peerSignAlgs); - if (supportedPeerSignAlgs.isEmpty()) { - throw new SSLHandshakeException( - "No signature and hash algorithm in common"); - } - - setPeerSupportedSignAlgs(supportedPeerSignAlgs); - } // else, need to use peer implicit supported signature algs - } - - session = new SSLSessionImpl(protocolVersion, CipherSuite.C_NULL, - getLocalSupportedSignAlgs(), - sslContext.getSecureRandom(), - getHostAddressSE(), getPortSE(), - (requestedToUseEMS && - protocolVersion.useTLS10PlusSpec())); - - if (protocolVersion.useTLS12PlusSpec()) { - if (peerSupportedSignAlgs != null) { - session.setPeerSupportedSignatureAlgorithms( - peerSupportedSignAlgs); - } // else, we will set the implicit peer supported signature - // algorithms in chooseCipherSuite() - } - - // set the server name indication in the session - List clientHelloSNI = - Collections.emptyList(); - if (clientHelloSNIExt != null) { - clientHelloSNI = clientHelloSNIExt.getServerNames(); - } - session.setRequestedServerNames(clientHelloSNI); - - // set the handshake session - setHandshakeSessionSE(session); - - // choose cipher suite and corresponding private key - chooseCipherSuite(mesg); - - session.setSuite(cipherSuite); - session.setLocalPrivateKey(privateKey); - - // chooseCompression(mesg); - - // set the negotiated maximum fragment in the session - // - // The protocol version and cipher suite have been negotiated - // in previous processes. - if (maxFragLenExt != null) { - int maxFragLen = maxFragLenExt.getMaxFragLen(); - - // More check of the requested "max_fragment_length" extension. - if (maximumPacketSize != 0) { - int estimatedMaxFragSize = cipherSuite.calculatePacketSize( - maxFragLen, protocolVersion, isDTLS); - if (estimatedMaxFragSize > maximumPacketSize) { - // For better interoperability, abort the maximum - // fragment length negotiation, rather than terminate - // the connection with a fatal alert. - maxFragLenExt = null; - - // fatalSE(Alerts.alert_illegal_parameter, - // "Not an allowed max_fragment_length value"); - } - } - - if (maxFragLenExt != null) { - session.setNegotiatedMaxFragSize(maxFragLen); - } - } - - session.setMaximumPacketSize(maximumPacketSize); - } else { - // set the handshake session - setHandshakeSessionSE(session); - } - - if (protocolVersion.useTLS12PlusSpec()) { - handshakeHash.setFinishedAlg(cipherSuite.prfAlg.getPRFHashAlg()); - } - - m1.cipherSuite = cipherSuite; - m1.sessionId = session.getSessionId(); - m1.compression_method = session.getCompression(); - - if (secureRenegotiation) { - // For ServerHellos that are initial handshakes, then the - // "renegotiated_connection" field in "renegotiation_info" - // extension is of zero length. - // - // For ServerHellos that are renegotiating, this field contains - // the concatenation of client_verify_data and server_verify_data. - // - // Note that for initial handshakes, both the clientVerifyData - // variable and serverVerifyData variable are of zero length. - HelloExtension serverHelloRI = new RenegotiationInfoExtension( - clientVerifyData, serverVerifyData); - m1.extensions.add(serverHelloRI); - } - - if (!sniMatchers.isEmpty() && clientHelloSNIExt != null) { - // When resuming a session, the server MUST NOT include a - // server_name extension in the server hello. - if (!resumingSession) { - ServerNameExtension serverHelloSNI = new ServerNameExtension(); - m1.extensions.add(serverHelloSNI); - } - } - - if ((maxFragLenExt != null) && !resumingSession) { - // When resuming a session, the server MUST NOT include a - // max_fragment_length extension in the server hello. - // - // Otherwise, use the same value as the requested extension. - m1.extensions.add(maxFragLenExt); - } - - if (session.getUseExtendedMasterSecret()) { - m1.extensions.add(new ExtendedMasterSecretExtension()); - } - - StaplingParameters staplingParams = processStapling(mesg); - if (staplingParams != null) { - // We now can safely assert status_request[_v2] in our - // ServerHello, and know for certain that we can provide - // responses back to this client for this connection. - if (staplingParams.statusRespExt == - ExtensionType.EXT_STATUS_REQUEST) { - m1.extensions.add(new CertStatusReqExtension()); - } else if (staplingParams.statusRespExt == - ExtensionType.EXT_STATUS_REQUEST_V2) { - m1.extensions.add(new CertStatusReqListV2Extension()); - } - } - - // Prepare the ALPN response - if (clientHelloALPN != null) { - List peerAPs = clientHelloALPN.getPeerAPs(); - - // check for a callback function - if (hasAPCallback) { - if (conn != null) { - applicationProtocol = - appProtocolSelectorSSLSocket.apply(conn, peerAPs); - } else { - applicationProtocol = - appProtocolSelectorSSLEngine.apply(engine, peerAPs); - } - } - - // check for no-match and that the selected name was also proposed - // by the TLS peer - if (applicationProtocol == null || - (!applicationProtocol.isEmpty() && - !peerAPs.contains(applicationProtocol))) { - - fatalSE(Alerts.alert_no_application_protocol, - new SSLHandshakeException( - "No matching ALPN values")); - - } else if (!applicationProtocol.isEmpty()) { - m1.extensions.add(new ALPNExtension(applicationProtocol)); - } - } else { - // Nothing was negotiated, returned at end of the handshake - applicationProtocol = ""; - } - - if (debug != null && Debug.isOn("handshake")) { - m1.print(System.out); - System.out.println("Cipher suite: " + session.getSuite()); - } - m1.write(output); - handshakeState.update(m1, resumingSession); - - // - // If we are resuming a session, we finish writing handshake - // messages right now and then finish. - // - if (resumingSession) { - calculateConnectionKeys(session.getMasterSecret()); - sendChangeCipherAndFinish(false); - - // expecting the final ChangeCipherSpec and Finished messages - expectingFinishFlightSE(); - - return; - } - - - /* - * SECOND, write the server Certificate(s) if we need to. - * - * NOTE: while an "anonymous RSA" mode is explicitly allowed by - * the protocol, we can't support it since all of the SSL flavors - * defined in the protocol spec are explicitly stated to require - * using RSA certificates. - */ - if (ClientKeyExchangeService.find( - cipherSuite.keyExchange.name) != null) { - // No external key exchange provider needs a cert now. - } else if ((keyExchange != K_DH_ANON) && (keyExchange != K_ECDH_ANON)) { - if (certs == null) { - throw new RuntimeException("no certificates"); - } - - CertificateMsg m2 = new CertificateMsg(certs); - - /* - * Set local certs in the SSLSession, output - * debug info, and then actually write to the client. - */ - session.setLocalCertificates(certs); - if (debug != null && Debug.isOn("handshake")) { - m2.print(System.out); - } - m2.write(output); - handshakeState.update(m2, resumingSession); - - // XXX has some side effects with OS TCP buffering, - // leave it out for now - - // let client verify chain in the meantime... - // output.flush(); - } else { - if (certs != null) { - throw new RuntimeException("anonymous keyexchange with certs"); - } - } - - /** - * The CertificateStatus message ... only if it is needed. - * This would only be needed if we've established that this handshake - * supports status stapling and there is at least one response to - * return to the client. - */ - if (staplingParams != null) { - CertificateStatus csMsg = new CertificateStatus( - staplingParams.statReqType, certs, - staplingParams.responseMap); - if (debug != null && Debug.isOn("handshake")) { - csMsg.print(System.out); - } - csMsg.write(output); - handshakeState.update(csMsg, resumingSession); - } - - /* - * THIRD, the ServerKeyExchange message ... iff it's needed. - * - * It's usually needed unless there's an encryption-capable - * RSA cert, or a D-H cert. The notable exception is that - * exportable ciphers used with big RSA keys need to downgrade - * to use short RSA keys, even when the key/cert encrypts OK. - */ - - ServerKeyExchange m3; - switch (keyExchange) { - case K_RSA: - // no server key exchange for RSA ciphersuites - m3 = null; - break; - case K_RSA_EXPORT: - if (JsseJce.getRSAKeyLength(certs[0].getPublicKey()) > 512) { - try { - m3 = new RSA_ServerKeyExchange( - tempPublicKey, privateKey, - clnt_random, svr_random, - sslContext.getSecureRandom()); - privateKey = tempPrivateKey; - } catch (GeneralSecurityException e) { - m3 = null; // make compiler happy - throw new SSLException( - "Error generating RSA server key exchange", e); - } - } else { - // RSA_EXPORT with short key, don't need ServerKeyExchange - m3 = null; - } - break; - case K_DHE_RSA: - case K_DHE_DSS: - try { - m3 = new DH_ServerKeyExchange(dh, - privateKey, - clnt_random.random_bytes, - svr_random.random_bytes, - sslContext.getSecureRandom(), - preferableSignatureAlgorithm, - protocolVersion); - } catch (GeneralSecurityException e) { - m3 = null; // make compiler happy - throw new SSLException( - "Error generating DH server key exchange", e); - } - break; - case K_DH_ANON: - m3 = new DH_ServerKeyExchange(dh, protocolVersion); - break; - case K_ECDHE_RSA: - case K_ECDHE_ECDSA: - case K_ECDH_ANON: - try { - m3 = new ECDH_ServerKeyExchange(ecdh, - privateKey, - clnt_random.random_bytes, - svr_random.random_bytes, - sslContext.getSecureRandom(), - preferableSignatureAlgorithm, - protocolVersion); - } catch (GeneralSecurityException e) { - m3 = null; // make compiler happy - throw new SSLException( - "Error generating ECDH server key exchange", e); - } - break; - case K_ECDH_RSA: - case K_ECDH_ECDSA: - // ServerKeyExchange not used for fixed ECDH - m3 = null; - break; - default: - ClientKeyExchangeService p = - ClientKeyExchangeService.find(keyExchange.name); - if (p != null) { - // No external key exchange provider needs a cert now. - m3 = null; - break; - } - throw new RuntimeException("internal error: " + keyExchange); - } - if (m3 != null) { - if (debug != null && Debug.isOn("handshake")) { - m3.print(System.out); - } - m3.write(output); - handshakeState.update(m3, resumingSession); - } - - // - // FOURTH, the CertificateRequest message. The details of - // the message can be affected by the key exchange algorithm - // in use. For example, certs with fixed Diffie-Hellman keys - // are only useful with the DH_DSS and DH_RSA key exchange - // algorithms. - // - // Needed only if server requires client to authenticate self. - // Illegal for anonymous flavors, so we need to check that. - // - // No external key exchange provider needs a cert now. - if (doClientAuth != ClientAuthType.CLIENT_AUTH_NONE && - keyExchange != K_DH_ANON && keyExchange != K_ECDH_ANON && - ClientKeyExchangeService.find(keyExchange.name) == null) { - - CertificateRequest m4; - X509Certificate[] caCerts; - - Collection localSignAlgs = null; - if (protocolVersion.useTLS12PlusSpec()) { - // We currently use all local upported signature and hash - // algorithms. However, to minimize the computation cost - // of requested hash algorithms, we may use a restricted - // set of signature algorithms in the future. - localSignAlgs = getLocalSupportedSignAlgs(); - if (localSignAlgs.isEmpty()) { - throw new SSLHandshakeException( - "No supported signature algorithm"); - } - - Set localHashAlgs = - SignatureAndHashAlgorithm.getHashAlgorithmNames( - localSignAlgs); - if (localHashAlgs.isEmpty()) { - throw new SSLHandshakeException( - "No supported signature algorithm"); - } - } - - caCerts = sslContext.getX509TrustManager().getAcceptedIssuers(); - m4 = new CertificateRequest(caCerts, keyExchange, - localSignAlgs, protocolVersion); - - if (debug != null && Debug.isOn("handshake")) { - m4.print(System.out); - } - m4.write(output); - handshakeState.update(m4, resumingSession); - } - - /* - * FIFTH, say ServerHelloDone. - */ - ServerHelloDone m5 = new ServerHelloDone(); - - if (debug != null && Debug.isOn("handshake")) { - m5.print(System.out); - } - m5.write(output); - handshakeState.update(m5, resumingSession); - - /* - * Flush any buffered messages so the client will see them. - * Ideally, all the messages above go in a single network level - * message to the client. Without big Certificate chains, it's - * going to be the common case. - */ - output.flush(); - } - - /* - * Choose cipher suite from among those supported by client. Sets - * the cipherSuite and keyExchange variables. - */ - private void chooseCipherSuite(ClientHello mesg) throws IOException { - CipherSuiteList prefered; - CipherSuiteList proposed; - if (preferLocalCipherSuites) { - prefered = getActiveCipherSuites(); - proposed = mesg.getCipherSuites(); - } else { - prefered = mesg.getCipherSuites(); - proposed = getActiveCipherSuites(); - } - - List legacySuites = new ArrayList<>(); - for (CipherSuite suite : prefered.collection()) { - if (isNegotiable(proposed, suite) == false) { - continue; - } - - if (doClientAuth == ClientAuthType.CLIENT_AUTH_REQUIRED) { - if ((suite.keyExchange == K_DH_ANON) || - (suite.keyExchange == K_ECDH_ANON)) { - continue; - } - } - - if (!legacyAlgorithmConstraints.permits(null, suite.name, null)) { - legacySuites.add(suite); - continue; - } - - if (trySetCipherSuite(suite) == false) { - continue; - } - - if (debug != null && Debug.isOn("handshake")) { - System.out.println("Standard ciphersuite chosen: " + suite); - } - return; - } - - for (CipherSuite suite : legacySuites) { - if (trySetCipherSuite(suite)) { - if (debug != null && Debug.isOn("handshake")) { - System.out.println("Legacy ciphersuite chosen: " + suite); - } - return; - } - } - - fatalSE(Alerts.alert_handshake_failure, "no cipher suites in common"); - } - - /** - * Set the given CipherSuite, if possible. Return the result. - * The call succeeds if the CipherSuite is available and we have - * the necessary certificates to complete the handshake. We don't - * check if the CipherSuite is actually enabled. - * - * If successful, this method also generates ephemeral keys if - * required for this ciphersuite. This may take some time, so this - * method should only be called if you really want to use the - * CipherSuite. - * - * This method is called from chooseCipherSuite() in this class. - */ - boolean trySetCipherSuite(CipherSuite suite) { - /* - * If we're resuming a session we know we can - * support this key exchange algorithm and in fact - * have already cached the result of it in - * the session state. - */ - if (resumingSession) { - return true; - } - - if (suite.isNegotiable() == false) { - return false; - } - - // must not negotiate the obsoleted weak cipher suites. - if (protocolVersion.obsoletes(suite)) { - return false; - } - - // must not negotiate unsupported cipher suites. - if (!protocolVersion.supports(suite)) { - return false; - } - - KeyExchange keyExchange = suite.keyExchange; - - // null out any existing references - privateKey = null; - certs = null; - dh = null; - tempPrivateKey = null; - tempPublicKey = null; - - Collection supportedSignAlgs = null; - if (protocolVersion.useTLS12PlusSpec()) { - if (peerSupportedSignAlgs != null) { - supportedSignAlgs = peerSupportedSignAlgs; - } else { - SignatureAndHashAlgorithm algorithm = null; - - // we may optimize the performance - switch (keyExchange) { - // If the negotiated key exchange algorithm is one of - // (RSA, DHE_RSA, DH_RSA, RSA_PSK, ECDH_RSA, ECDHE_RSA), - // behave as if client had sent the value {sha1,rsa}. - case K_RSA: - case K_DHE_RSA: - case K_DH_RSA: - // case K_RSA_PSK: - case K_ECDH_RSA: - case K_ECDHE_RSA: - algorithm = SignatureAndHashAlgorithm.valueOf( - HashAlgorithm.SHA1.value, - SignatureAlgorithm.RSA.value, 0); - break; - // If the negotiated key exchange algorithm is one of - // (DHE_DSS, DH_DSS), behave as if the client had - // sent the value {sha1,dsa}. - case K_DHE_DSS: - case K_DH_DSS: - algorithm = SignatureAndHashAlgorithm.valueOf( - HashAlgorithm.SHA1.value, - SignatureAlgorithm.DSA.value, 0); - break; - // If the negotiated key exchange algorithm is one of - // (ECDH_ECDSA, ECDHE_ECDSA), behave as if the client - // had sent value {sha1,ecdsa}. - case K_ECDH_ECDSA: - case K_ECDHE_ECDSA: - algorithm = SignatureAndHashAlgorithm.valueOf( - HashAlgorithm.SHA1.value, - SignatureAlgorithm.ECDSA.value, 0); - break; - default: - // no peer supported signature algorithms - } - - if (algorithm == null) { - supportedSignAlgs = - Collections.emptySet(); - } else { - supportedSignAlgs = - new ArrayList(1); - supportedSignAlgs.add(algorithm); - - supportedSignAlgs = - SignatureAndHashAlgorithm.getSupportedAlgorithms( - algorithmConstraints, supportedSignAlgs); - - // May be no default activated signature algorithm, but - // let the following process make the final decision. - } - - // Sets the peer supported signature algorithm to use in KM - // temporarily. - session.setPeerSupportedSignatureAlgorithms(supportedSignAlgs); - } - } - - // The named group used for ECDHE and FFDHE. - NamedGroup namedGroup = null; - switch (keyExchange) { - case K_RSA: - // need RSA certs for authentication - if (setupPrivateKeyAndChain("RSA") == false) { - return false; - } - break; - case K_RSA_EXPORT: - // need RSA certs for authentication - if (setupPrivateKeyAndChain("RSA") == false) { - return false; - } - - try { - if (JsseJce.getRSAKeyLength(certs[0].getPublicKey()) > 512) { - if (!setupEphemeralRSAKeys(suite.exportable)) { - return false; - } - } - } catch (RuntimeException e) { - // could not determine keylength, ignore key - return false; - } - break; - case K_DHE_RSA: - // Is ephemeral DH cipher suite usable for the connection? - // - // [RFC 7919] If a compatible TLS server receives a Supported - // Groups extension from a client that includes any FFDHE group - // (i.e., any codepoint between 256 and 511, inclusive, even if - // unknown to the server), and if none of the client-proposed - // FFDHE groups are known and acceptable to the server, then - // the server MUST NOT select an FFDHE cipher suite. In this - // case, the server SHOULD select an acceptable non-FFDHE cipher - // suite from the client's offered list. If the extension is - // present with FFDHE groups, none of the client's offered - // groups are acceptable by the server, and none of the client's - // proposed non-FFDHE cipher suites are acceptable to the server, - // the server MUST end the connection with a fatal TLS alert - // of type insufficient_security(71). - // - // Note: For compatibility, if an application is customized to - // use legacy sizes (512 bits for exportable cipher suites and - // 768 bits for others), or the cipher suite is exportable, the - // FFDHE extension will not be used. - if ((!useLegacyEphemeralDHKeys) && (!suite.exportable) && - (requestedGroups != null) && requestedGroups.hasFFDHEGroup()) { - - namedGroup = requestedGroups.getPreferredGroup( - algorithmConstraints, NamedGroupType.NAMED_GROUP_FFDHE); - if (namedGroup == null) { - // no match found, cannot use this cipher suite. - return false; - } - } - - // need RSA certs for authentication - if (setupPrivateKeyAndChain("RSA") == false) { - return false; - } - - // get preferable peer signature algorithm for server key exchange - if (protocolVersion.useTLS12PlusSpec()) { - preferableSignatureAlgorithm = - SignatureAndHashAlgorithm.getPreferableAlgorithm( - supportedSignAlgs, "RSA", privateKey); - if (preferableSignatureAlgorithm == null) { - if ((debug != null) && Debug.isOn("handshake")) { - System.out.println( - "No signature and hash algorithm for cipher " + - suite); - } - return false; - } - } - - setupEphemeralDHKeys(namedGroup, suite.exportable, privateKey); - break; - case K_ECDHE_RSA: - // Is ECDHE cipher suite usable for the connection? - namedGroup = (requestedGroups != null) ? - requestedGroups.getPreferredGroup( - algorithmConstraints, NamedGroupType.NAMED_GROUP_ECDHE) : - SupportedGroupsExtension.getPreferredECGroup( - algorithmConstraints); - if (namedGroup == null) { - // no match found, cannot use this ciphersuite - return false; - } - - // need RSA certs for authentication - if (setupPrivateKeyAndChain("RSA") == false) { - return false; - } - - // get preferable peer signature algorithm for server key exchange - if (protocolVersion.useTLS12PlusSpec()) { - preferableSignatureAlgorithm = - SignatureAndHashAlgorithm.getPreferableAlgorithm( - supportedSignAlgs, "RSA", privateKey); - if (preferableSignatureAlgorithm == null) { - if ((debug != null) && Debug.isOn("handshake")) { - System.out.println( - "No signature and hash algorithm for cipher " + - suite); - } - return false; - } - } - - setupEphemeralECDHKeys(namedGroup); - break; - case K_DHE_DSS: - // Is ephemeral DH cipher suite usable for the connection? - // - // See comment in K_DHE_RSA case. - if ((!useLegacyEphemeralDHKeys) && (!suite.exportable) && - (requestedGroups != null) && requestedGroups.hasFFDHEGroup()) { - - namedGroup = requestedGroups.getPreferredGroup( - algorithmConstraints, NamedGroupType.NAMED_GROUP_FFDHE); - if (namedGroup == null) { - // no match found, cannot use this cipher suite. - return false; - } - } - - // get preferable peer signature algorithm for server key exchange - if (protocolVersion.useTLS12PlusSpec()) { - preferableSignatureAlgorithm = - SignatureAndHashAlgorithm.getPreferableAlgorithm( - supportedSignAlgs, "DSA"); - if (preferableSignatureAlgorithm == null) { - if ((debug != null) && Debug.isOn("handshake")) { - System.out.println( - "No signature and hash algorithm for cipher " + - suite); - } - return false; - } - } - - // need DSS certs for authentication - if (setupPrivateKeyAndChain("DSA") == false) { - return false; - } - - setupEphemeralDHKeys(namedGroup, suite.exportable, privateKey); - break; - case K_ECDHE_ECDSA: - // Is ECDHE cipher suite usable for the connection? - namedGroup = (requestedGroups != null) ? - requestedGroups.getPreferredGroup( - algorithmConstraints, NamedGroupType.NAMED_GROUP_ECDHE) : - SupportedGroupsExtension.getPreferredECGroup( - algorithmConstraints); - if (namedGroup == null) { - // no match found, cannot use this ciphersuite - return false; - } - - // get preferable peer signature algorithm for server key exchange - if (protocolVersion.useTLS12PlusSpec()) { - preferableSignatureAlgorithm = - SignatureAndHashAlgorithm.getPreferableAlgorithm( - supportedSignAlgs, "ECDSA"); - if (preferableSignatureAlgorithm == null) { - if ((debug != null) && Debug.isOn("handshake")) { - System.out.println( - "No signature and hash algorithm for cipher " + - suite); - } - return false; - } - } - - // need EC cert - if (setupPrivateKeyAndChain("EC") == false) { - return false; - } - - setupEphemeralECDHKeys(namedGroup); - break; - case K_ECDH_RSA: - // need EC cert - if (setupPrivateKeyAndChain("EC") == false) { - return false; - } - setupStaticECDHKeys(); - break; - case K_ECDH_ECDSA: - // need EC cert - if (setupPrivateKeyAndChain("EC") == false) { - return false; - } - setupStaticECDHKeys(); - break; - case K_DH_ANON: - // Is ephemeral DH cipher suite usable for the connection? - // - // See comment in K_DHE_RSA case. - if ((!useLegacyEphemeralDHKeys) && (!suite.exportable) && - (requestedGroups != null) && requestedGroups.hasFFDHEGroup()) { - namedGroup = requestedGroups.getPreferredGroup( - algorithmConstraints, NamedGroupType.NAMED_GROUP_FFDHE); - if (namedGroup == null) { - // no match found, cannot use this cipher suite. - return false; - } - } - - // no certs needed for anonymous - setupEphemeralDHKeys(namedGroup, suite.exportable, null); - break; - case K_ECDH_ANON: - // Is ECDHE cipher suite usable for the connection? - namedGroup = (requestedGroups != null) ? - requestedGroups.getPreferredGroup( - algorithmConstraints, NamedGroupType.NAMED_GROUP_ECDHE) : - SupportedGroupsExtension.getPreferredECGroup( - algorithmConstraints); - if (namedGroup == null) { - // no match found, cannot use this ciphersuite - return false; - } - - // no certs needed for anonymous - setupEphemeralECDHKeys(namedGroup); - break; - default: - ClientKeyExchangeService p = - ClientKeyExchangeService.find(keyExchange.name); - if (p == null) { - // internal error, unknown key exchange - throw new RuntimeException( - "Unrecognized cipherSuite: " + suite); - } - // need service creds - if (serviceCreds == null) { - AccessControlContext acc = getAccSE(); - serviceCreds = p.getServiceCreds(acc); - if (serviceCreds != null) { - if (debug != null && Debug.isOn("handshake")) { - System.out.println("Using serviceCreds"); - } - } - if (serviceCreds == null) { - return false; - } - } - break; - } - setCipherSuite(suite); - - // set the peer implicit supported signature algorithms - if (protocolVersion.useTLS12PlusSpec()) { - if (peerSupportedSignAlgs == null) { - setPeerSupportedSignAlgs(supportedSignAlgs); - // we had alreay update the session - } - } - return true; - } - - /* - * Get some "ephemeral" RSA keys for this context. This means - * generating them if it's not already been done. - * - * Note that we currently do not implement any ciphersuites that use - * strong ephemeral RSA. (We do not support the EXPORT1024 ciphersuites - * and standard RSA ciphersuites prohibit ephemeral mode for some reason) - * This means that export is always true and 512 bit keys are generated. - */ - private boolean setupEphemeralRSAKeys(boolean export) { - KeyPair kp = sslContext.getEphemeralKeyManager(). - getRSAKeyPair(export, sslContext.getSecureRandom()); - if (kp == null) { - return false; - } else { - tempPublicKey = kp.getPublic(); - tempPrivateKey = kp.getPrivate(); - return true; - } - } - - /* - * Acquire some "ephemeral" Diffie-Hellman keys for this handshake. - * We don't reuse these, for improved forward secrecy. - */ - private void setupEphemeralDHKeys( - NamedGroup namedGroup, boolean export, Key key) { - // Are the client and server willing to negotiate FFDHE groups? - if ((!useLegacyEphemeralDHKeys) && (!export) && (namedGroup != null)) { - dh = new DHCrypt(namedGroup, sslContext.getSecureRandom()); - - return; - } // Otherwise, the client is not compatible with FFDHE extension. - - /* - * 768 bits ephemeral DH private keys were used to be used in - * ServerKeyExchange except that exportable ciphers max out at 512 - * bits modulus values. We still adhere to this behavior in legacy - * mode (system property "jdk.tls.ephemeralDHKeySize" is defined - * as "legacy"). - * - * Old JDK (JDK 7 and previous) releases don't support DH keys bigger - * than 1024 bits. We have to consider the compatibility requirement. - * 1024 bits DH key is always used for non-exportable cipher suites - * in default mode (system property "jdk.tls.ephemeralDHKeySize" - * is not defined). - * - * However, if applications want more stronger strength, setting - * system property "jdk.tls.ephemeralDHKeySize" to "matched" - * is a workaround to use ephemeral DH key which size matches the - * corresponding authentication key. For example, if the public key - * size of an authentication certificate is 2048 bits, then the - * ephemeral DH key size should be 2048 bits accordingly unless - * the cipher suite is exportable. This key sizing scheme keeps - * the cryptographic strength consistent between authentication - * keys and key-exchange keys. - * - * Applications may also want to customize the ephemeral DH key size - * to a fixed length for non-exportable cipher suites. This can be - * approached by setting system property "jdk.tls.ephemeralDHKeySize" - * to a valid positive integer between 1024 and 8192 bits, inclusive. - * - * Note that the minimum acceptable key size is 1024 bits except - * exportable cipher suites or legacy mode. - * - * Note that per RFC 2246, the key size limit of DH is 512 bits for - * exportable cipher suites. Because of the weakness, exportable - * cipher suites are deprecated since TLS v1.1 and they are not - * enabled by default in Oracle provider. The legacy behavior is - * reserved and 512 bits DH key is always used for exportable - * cipher suites. - */ - int keySize = export ? 512 : 1024; // default mode - if (!export) { - if (useLegacyEphemeralDHKeys) { // legacy mode - keySize = 768; - } else if (useSmartEphemeralDHKeys) { // matched mode - if (key != null) { - int ks = KeyUtil.getKeySize(key); - - // DH parameter generation can be extremely slow, make - // sure to use one of the supported pre-computed DH - // parameters (see DHCrypt class). - // - // Old deployed applications may not be ready to support - // DH key sizes bigger than 2048 bits. Please DON'T use - // value other than 1024 and 2048 at present. May improve - // the underlying providers and key size limit in the - // future when the compatibility and interoperability - // impact is limited. - // - // keySize = ks <= 1024 ? 1024 : (ks >= 2048 ? 2048 : ks); - keySize = ks <= 1024 ? 1024 : 2048; - } // Otherwise, anonymous cipher suites, 1024-bit is used. - } else if (customizedDHKeySize > 0) { // customized mode - keySize = customizedDHKeySize; - } - } - - dh = new DHCrypt(keySize, sslContext.getSecureRandom()); - } - - /** - * Setup the ephemeral ECDH parameters. - */ - private void setupEphemeralECDHKeys(NamedGroup namedGroup) { - ecdh = new ECDHCrypt(namedGroup, sslContext.getSecureRandom()); - } - - private void setupStaticECDHKeys() { - // don't need to check whether the curve is supported, already done - // in setupPrivateKeyAndChain(). - ecdh = new ECDHCrypt(privateKey, certs[0].getPublicKey()); - } - - /** - * Retrieve the server key and certificate for the specified algorithm - * from the KeyManager and set the instance variables. - * - * @return true if successful, false if not available or invalid - */ - private boolean setupPrivateKeyAndChain(String algorithm) { - X509ExtendedKeyManager km = sslContext.getX509KeyManager(); - String alias; - if (conn != null) { - alias = km.chooseServerAlias(algorithm, null, conn); - } else { - alias = km.chooseEngineServerAlias(algorithm, null, engine); - } - if (alias == null) { - return false; - } - PrivateKey tempPrivateKey = km.getPrivateKey(alias); - if (tempPrivateKey == null) { - return false; - } - X509Certificate[] tempCerts = km.getCertificateChain(alias); - if ((tempCerts == null) || (tempCerts.length == 0)) { - return false; - } - String keyAlgorithm = algorithm.split("_")[0]; - PublicKey publicKey = tempCerts[0].getPublicKey(); - if ((tempPrivateKey.getAlgorithm().equals(keyAlgorithm) == false) - || (publicKey.getAlgorithm().equals(keyAlgorithm) == false)) { - return false; - } - // For ECC certs, check whether we support the EC domain parameters. - // If the client sent a SupportedEllipticCurves ClientHello extension, - // check against that too. - if (keyAlgorithm.equals("EC")) { - if (publicKey instanceof ECPublicKey == false) { - return false; - } - ECParameterSpec params = ((ECPublicKey)publicKey).getParams(); - NamedGroup namedGroup = NamedGroup.valueOf(params); - if ((namedGroup == null) || - (!SupportedGroupsExtension.supports(namedGroup)) || - ((requestedGroups != null) && - !requestedGroups.contains(namedGroup.id))) { - return false; - } - } - this.privateKey = tempPrivateKey; - this.certs = tempCerts; - return true; - } - - /* - * Returns premaster secret for external key exchange services. - */ - private SecretKey clientKeyExchange(ClientKeyExchange mesg) - throws IOException { - - if (debug != null && Debug.isOn("handshake")) { - mesg.print(System.out); - } - - // Record the principals involved in exchange - session.setPeerPrincipal(mesg.getPeerPrincipal()); - session.setLocalPrincipal(mesg.getLocalPrincipal()); - - return mesg.clientKeyExchange(); - } - - /* - * Diffie Hellman key exchange is used when the server presented - * D-H parameters in its certificate (signed using RSA or DSS/DSA), - * or else the server presented no certificate but sent D-H params - * in a ServerKeyExchange message. Use of D-H is specified by the - * cipher suite chosen. - * - * The message optionally contains the client's D-H public key (if - * it wasn't not sent in a client certificate). As always with D-H, - * if a client and a server have each other's D-H public keys and - * they use common algorithm parameters, they have a shared key - * that's derived via the D-H calculation. That key becomes the - * pre-master secret. - */ - private SecretKey clientKeyExchange(DHClientKeyExchange mesg) - throws IOException { - - if (debug != null && Debug.isOn("handshake")) { - mesg.print(System.out); - } - - BigInteger publicKeyValue = mesg.getClientPublicKey(); - - // check algorithm constraints - dh.checkConstraints(algorithmConstraints, publicKeyValue); - - return dh.getAgreedSecret(publicKeyValue, false); - } - - private SecretKey clientKeyExchange(ECDHClientKeyExchange mesg) - throws IOException { - - if (debug != null && Debug.isOn("handshake")) { - mesg.print(System.out); - } - - byte[] publicPoint = mesg.getEncodedPoint(); - - // check algorithm constraints - ecdh.checkConstraints(algorithmConstraints, publicPoint); - - return ecdh.getAgreedSecret(publicPoint); - } - - /* - * Client wrote a message to verify the certificate it sent earlier. - * - * Note that this certificate isn't involved in key exchange. Client - * authentication messages are included in the checksums used to - * validate the handshake (e.g. Finished messages). Other than that, - * the _exact_ identity of the client is less fundamental to protocol - * security than its role in selecting keys via the pre-master secret. - */ - private void clientCertificateVerify(CertificateVerify mesg) - throws IOException { - - if (debug != null && Debug.isOn("handshake")) { - mesg.print(System.out); - } - - if (protocolVersion.useTLS12PlusSpec()) { - SignatureAndHashAlgorithm signAlg = - mesg.getPreferableSignatureAlgorithm(); - if (signAlg == null) { - throw new SSLHandshakeException( - "Illegal CertificateVerify message"); - } - - String hashAlg = - SignatureAndHashAlgorithm.getHashAlgorithmName(signAlg); - if (hashAlg == null || hashAlg.length() == 0) { - throw new SSLHandshakeException( - "No supported hash algorithm"); - } - } - - try { - PublicKey publicKey = - session.getPeerCertificates()[0].getPublicKey(); - - boolean valid = mesg.verify(protocolVersion, handshakeHash, - publicKey, session.getMasterSecret()); - if (valid == false) { - fatalSE(Alerts.alert_bad_certificate, - "certificate verify message signature error"); - } - } catch (GeneralSecurityException e) { - fatalSE(Alerts.alert_bad_certificate, - "certificate verify format error", e); - } - - // reset the flag for clientCertificateVerify message - needClientVerify = false; - } - - - /* - * Client writes "finished" at the end of its handshake, after cipher - * spec is changed. We verify it and then send ours. - * - * When we're resuming a session, we'll have already sent our own - * Finished message so just the verification is needed. - */ - private void clientFinished(Finished mesg) throws IOException { - if (debug != null && Debug.isOn("handshake")) { - mesg.print(System.out); - } - - /* - * Verify if client did send the certificate when client - * authentication was required, otherwise server should not proceed - */ - if (doClientAuth == ClientAuthType.CLIENT_AUTH_REQUIRED) { - // get X500Principal of the end-entity certificate for X509-based - // ciphersuites, or Kerberos principal for Kerberos ciphersuites, etc - session.getPeerPrincipal(); - } - - /* - * Verify if client did send clientCertificateVerify message following - * the client Certificate, otherwise server should not proceed - */ - if (needClientVerify) { - fatalSE(Alerts.alert_handshake_failure, - "client did not send certificate verify message"); - } - - /* - * Verify the client's message with the "before" digest of messages, - * and forget about continuing to use that digest. - */ - boolean verified = mesg.verify(handshakeHash, Finished.CLIENT, - session.getMasterSecret()); - - if (!verified) { - fatalSE(Alerts.alert_handshake_failure, - "client 'finished' message doesn't verify"); - // NOTREACHED - } - - /* - * save client verify data for secure renegotiation - */ - if (secureRenegotiation) { - clientVerifyData = mesg.getVerifyData(); - } - - /* - * OK, it verified. If we're doing the full handshake, add that - * "Finished" message to the hash of handshake messages, then send - * the change_cipher_spec and Finished message. - */ - if (!resumingSession) { - sendChangeCipherAndFinish(true); - } else { - handshakeFinished = true; - } - - /* - * Update the session cache only after the handshake completed, else - * we're open to an attack against a partially completed handshake. - */ - session.setLastAccessedTime(System.currentTimeMillis()); - if (!resumingSession && session.isRejoinable()) { - ((SSLSessionContextImpl)sslContext.engineGetServerSessionContext()) - .put(session); - if (debug != null && Debug.isOn("session")) { - System.out.println( - "%% Cached server session: " + session); - } - } else if (!resumingSession && - debug != null && Debug.isOn("session")) { - System.out.println( - "%% Didn't cache non-resumable server session: " - + session); - } - } - - /* - * Compute finished message with the "server" digest (and then forget - * about that digest, it can't be used again). - */ - private void sendChangeCipherAndFinish(boolean finishedTag) - throws IOException { - - // Reload if this message has been reserved. - handshakeHash.reload(); - - Finished mesg = new Finished(protocolVersion, handshakeHash, - Finished.SERVER, session.getMasterSecret(), cipherSuite); - - /* - * Send the change_cipher_spec record; then our Finished handshake - * message will be the last handshake message. Flush, and now we - * are ready for application data!! - */ - sendChangeCipherSpec(mesg, finishedTag); - - /* - * save server verify data for secure renegotiation - */ - if (secureRenegotiation) { - serverVerifyData = mesg.getVerifyData(); - } - } - - - /* - * Returns a HelloRequest message to kickstart renegotiations - */ - @Override - HandshakeMessage getKickstartMessage() { - return new HelloRequest(); - } - - - /* - * Fault detected during handshake. - */ - @Override - void handshakeAlert(byte description) throws SSLProtocolException { - - String message = Alerts.alertDescription(description); - - if (debug != null && Debug.isOn("handshake")) { - System.out.println("SSL -- handshake alert: " - + message); - } - - /* - * It's ok to get a no_certificate alert from a client of which - * we *requested* authentication information. - * However, if we *required* it, then this is not acceptable. - * - * Anyone calling getPeerCertificates() on the - * session will get an SSLPeerUnverifiedException. - */ - if ((description == Alerts.alert_no_certificate) && - (doClientAuth == ClientAuthType.CLIENT_AUTH_REQUESTED)) { - return; - } - - throw new SSLProtocolException("handshake alert: " + message); - } - - /* - * RSA key exchange is normally used. The client encrypts a "pre-master - * secret" with the server's public key, from the Certificate (or else - * ServerKeyExchange) message that was sent to it by the server. That's - * decrypted using the private key before we get here. - */ - private SecretKey clientKeyExchange(RSAClientKeyExchange mesg) - throws IOException { - - if (debug != null && Debug.isOn("handshake")) { - mesg.print(System.out); - } - return mesg.preMaster; - } - - /* - * Verify the certificate sent by the client. We'll only get one if we - * sent a CertificateRequest to request client authentication. If we - * are in TLS mode, the client may send a message with no certificates - * to indicate it does not have an appropriate chain. (In SSLv3 mode, - * it would send a no certificate alert). - */ - private void clientCertificate(CertificateMsg mesg) throws IOException { - if (debug != null && Debug.isOn("handshake")) { - mesg.print(System.out); - } - - X509Certificate[] peerCerts = mesg.getCertificateChain(); - - if (peerCerts.length == 0) { - /* - * If the client authentication is only *REQUESTED* (e.g. - * not *REQUIRED*, this is an acceptable condition.) - */ - if (doClientAuth == ClientAuthType.CLIENT_AUTH_REQUESTED) { - return; - } else { - fatalSE(Alerts.alert_bad_certificate, - "null cert chain"); - } - } - - // ask the trust manager to verify the chain - X509TrustManager tm = sslContext.getX509TrustManager(); - - try { - // find out the types of client authentication used - PublicKey key = peerCerts[0].getPublicKey(); - String keyAlgorithm = key.getAlgorithm(); - String authType; - if (keyAlgorithm.equals("RSA")) { - authType = "RSA"; - } else if (keyAlgorithm.equals("DSA")) { - authType = "DSA"; - } else if (keyAlgorithm.equals("EC")) { - authType = "EC"; - } else { - // unknown public key type - authType = "UNKNOWN"; - } - - if (tm instanceof X509ExtendedTrustManager) { - if (conn != null) { - ((X509ExtendedTrustManager)tm).checkClientTrusted( - peerCerts.clone(), - authType, - conn); - } else { - ((X509ExtendedTrustManager)tm).checkClientTrusted( - peerCerts.clone(), - authType, - engine); - } - } else { - // Unlikely to happen, because we have wrapped the old - // X509TrustManager with the new X509ExtendedTrustManager. - throw new CertificateException( - "Improper X509TrustManager implementation"); - } - } catch (CertificateException e) { - // This will throw an exception, so include the original error. - fatalSE(Alerts.alert_certificate_unknown, e); - } - // set the flag for clientCertificateVerify message - needClientVerify = true; - - session.setPeerCertificates(peerCerts); - } - - private StaplingParameters processStapling(ClientHello mesg) { - StaplingParameters params = null; - ExtensionType ext = null; - StatusRequestType type = null; - StatusRequest req = null; - Map responses; - - // If this feature has not been enabled, then no more processing - // is necessary. Also we will only staple if we're doing a full - // handshake. - if (!sslContext.isStaplingEnabled(false) || resumingSession) { - return null; - } - - // Check if the client has asserted the status_request[_v2] extension(s) - CertStatusReqExtension statReqExt = (CertStatusReqExtension) - mesg.extensions.get(ExtensionType.EXT_STATUS_REQUEST); - CertStatusReqListV2Extension statReqExtV2 = - (CertStatusReqListV2Extension)mesg.extensions.get( - ExtensionType.EXT_STATUS_REQUEST_V2); - - // Determine which type of stapling we are doing and assert the - // proper extension in the server hello. - // Favor status_request_v2 over status_request and ocsp_multi - // over ocsp. - // If multiple ocsp or ocsp_multi types exist, select the first - // instance of a given type. Also since we don't support ResponderId - // selection yet, only accept a request if the ResponderId field - // is empty. - if (statReqExtV2 != null) { // RFC 6961 stapling - ext = ExtensionType.EXT_STATUS_REQUEST_V2; - List reqItems = - statReqExtV2.getRequestItems(); - int ocspIdx = -1; - int ocspMultiIdx = -1; - for (int pos = 0; (pos < reqItems.size() && - (ocspIdx == -1 || ocspMultiIdx == -1)); pos++) { - CertStatusReqItemV2 item = reqItems.get(pos); - StatusRequestType curType = item.getType(); - if (ocspIdx < 0 && curType == StatusRequestType.OCSP) { - OCSPStatusRequest ocspReq = - (OCSPStatusRequest)item.getRequest(); - if (ocspReq.getResponderIds().isEmpty()) { - ocspIdx = pos; - } - } else if (ocspMultiIdx < 0 && - curType == StatusRequestType.OCSP_MULTI) { - // If the type is OCSP, then the request - // is guaranteed to be OCSPStatusRequest - OCSPStatusRequest ocspReq = - (OCSPStatusRequest)item.getRequest(); - if (ocspReq.getResponderIds().isEmpty()) { - ocspMultiIdx = pos; - } - } - } - if (ocspMultiIdx >= 0) { - type = reqItems.get(ocspMultiIdx).getType(); - req = reqItems.get(ocspMultiIdx).getRequest(); - } else if (ocspIdx >= 0) { - type = reqItems.get(ocspIdx).getType(); - req = reqItems.get(ocspIdx).getRequest(); - } else { - if (debug != null && Debug.isOn("handshake")) { - System.out.println("Warning: No suitable request " + - "found in the status_request_v2 extension."); - } - } - } - - // Only attempt to process a status_request extension if: - // * The status_request extension is set AND - // * either the status_request_v2 extension is not present OR - // * none of the underlying OCSPStatusRequest structures is suitable - // for stapling. - // If either of the latter two bullet items is true the ext, type and - // req variables should all be null. If any are null we will try - // processing an asserted status_request. - if ((statReqExt != null) && - (ext == null || type == null || req == null)) { - ext = ExtensionType.EXT_STATUS_REQUEST; - type = statReqExt.getType(); - if (type == StatusRequestType.OCSP) { - // If the type is OCSP, then the request is guaranteed - // to be OCSPStatusRequest - OCSPStatusRequest ocspReq = - (OCSPStatusRequest)statReqExt.getRequest(); - if (ocspReq.getResponderIds().isEmpty()) { - req = ocspReq; - } else { - if (debug != null && Debug.isOn("handshake")) { - req = null; - System.out.println("Warning: No suitable request " + - "found in the status_request extension."); - } - } - } - } - - // If, after walking through the extensions we were unable to - // find a suitable StatusRequest, then stapling is disabled. - // The ext, type and req variables must have been set to continue. - if (type == null || req == null || ext == null) { - return null; - } - - // Get the OCSP responses from the StatusResponseManager - StatusResponseManager statRespMgr = - sslContext.getStatusResponseManager(); - if (statRespMgr != null) { - responses = statRespMgr.get(type, req, certs, statusRespTimeout, - TimeUnit.MILLISECONDS); - if (!responses.isEmpty()) { - // If this RFC 6066-style stapling (SSL cert only) then the - // response cannot be zero length - if (type == StatusRequestType.OCSP) { - byte[] respDER = responses.get(certs[0]); - if (respDER == null || respDER.length <= 0) { - return null; - } - } - params = new StaplingParameters(ext, type, req, responses); - } - } else { - // This should not happen, but if lazy initialization of the - // StatusResponseManager doesn't occur we should turn off stapling. - if (debug != null && Debug.isOn("handshake")) { - System.out.println("Warning: lazy initialization " + - "of the StatusResponseManager failed. " + - "Stapling has been disabled."); - } - } - - return params; - } - - /** - * Inner class used to hold stapling parameters needed by the handshaker - * when stapling is active. - */ - private class StaplingParameters { - private final ExtensionType statusRespExt; - private final StatusRequestType statReqType; - private final StatusRequest statReqData; - private final Map responseMap; - - StaplingParameters(ExtensionType ext, StatusRequestType type, - StatusRequest req, Map responses) { - statusRespExt = ext; - statReqType = type; - statReqData = req; - responseMap = responses; - } - } -} --- /dev/null 2018-05-11 10:42:23.849000000 -0700 +++ new/src/java.base/share/classes/sun/security/ssl/ServerHandshakeContext.java 2018-05-11 15:10:26.475013800 -0700 @@ -0,0 +1,83 @@ +/* + * Copyright (c) 2018, 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.IOException; +import java.security.AlgorithmConstraints; +import java.security.AccessController; +import sun.security.util.LegacyAlgorithmConstraints; +import sun.security.action.GetPropertyAction; +import sun.security.action.GetLongAction; + +class ServerHandshakeContext extends HandshakeContext { + // To prevent the TLS renegotiation issues, by setting system property + // "jdk.tls.rejectClientInitiatedRenegotiation" to true, applications in + // server side can disable all client initiated SSL renegotiations + // regardless of the support of TLS protocols. + // + // By default, allow client initiated renegotiations. + static final boolean rejectClientInitiatedRenego = + Utilities.getBooleanProperty( + "jdk.tls.rejectClientInitiatedRenegotiation", false); + + // legacy algorithm constraints + static final AlgorithmConstraints legacyAlgorithmConstraints = + new LegacyAlgorithmConstraints( + LegacyAlgorithmConstraints.PROPERTY_TLS_LEGACY_ALGS, + new SSLAlgorithmDecomposer()); + + // temporary authentication information + SSLPossession interimAuthn; + + StatusResponseManager.StaplingParameters stapleParams; + CertificateMessage.CertificateEntry currentCertEntry; + private static final long DEFAULT_STATUS_RESP_DELAY = 5000L; + final long statusRespTimeout; + + + ServerHandshakeContext(SSLContextImpl sslContext, + TransportContext conContext) throws IOException { + super(sslContext, conContext); + long respTimeOut = AccessController.doPrivileged( + new GetLongAction("jdk.tls.stapling.responseTimeout", + DEFAULT_STATUS_RESP_DELAY)); + statusRespTimeout = respTimeOut >= 0 ? respTimeOut : + DEFAULT_STATUS_RESP_DELAY; + handshakeConsumers.put( + SSLHandshake.CLIENT_HELLO.id, SSLHandshake.CLIENT_HELLO); + } + + @Override + void kickstart() throws IOException { + if (!conContext.isNegotiated || kickstartMessageDelivered) { + return; + } + + SSLHandshake.kickstart(this); + kickstartMessageDelivered = true; + } +} +