0N/A/*
4589N/A * Copyright (c) 1996, 2012, Oracle and/or its affiliates. All rights reserved.
0N/A * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
0N/A *
0N/A * This code is free software; you can redistribute it and/or modify it
0N/A * under the terms of the GNU General Public License version 2 only, as
2362N/A * published by the Free Software Foundation. Oracle designates this
0N/A * particular file as subject to the "Classpath" exception as provided
2362N/A * by Oracle in the LICENSE file that accompanied this code.
0N/A *
0N/A * This code is distributed in the hope that it will be useful, but WITHOUT
0N/A * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
0N/A * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
0N/A * version 2 for more details (a copy is included in the LICENSE file that
0N/A * accompanied this code).
0N/A *
0N/A * You should have received a copy of the GNU General Public License version
0N/A * 2 along with this work; if not, write to the Free Software Foundation,
0N/A * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
0N/A *
2362N/A * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
2362N/A * or visit www.oracle.com if you need additional information or have any
2362N/A * questions.
0N/A */
0N/A
0N/A
0N/Apackage sun.security.ssl;
0N/A
0N/Aimport java.io.*;
0N/Aimport java.util.*;
0N/Aimport java.security.*;
0N/Aimport java.security.cert.*;
0N/Aimport java.security.interfaces.*;
0N/Aimport java.security.spec.ECParameterSpec;
0N/A
0N/Aimport javax.crypto.SecretKey;
0N/Aimport javax.crypto.spec.SecretKeySpec;
0N/A
0N/Aimport javax.net.ssl.*;
0N/A
0N/Aimport javax.security.auth.Subject;
0N/A
0N/Aimport sun.security.ssl.HandshakeMessage.*;
0N/Aimport sun.security.ssl.CipherSuite.*;
3002N/Aimport sun.security.ssl.SignatureAndHashAlgorithm.*;
0N/Aimport static sun.security.ssl.CipherSuite.*;
0N/Aimport static sun.security.ssl.CipherSuite.KeyExchange.*;
0N/A
0N/A/**
0N/A * ServerHandshaker does the protocol handshaking from the point
0N/A * of view of a server. It is driven asychronously by handshake messages
0N/A * as delivered by the parent Handshaker class, and also uses
0N/A * common functionality (e.g. key generation) that is provided there.
0N/A *
0N/A * @author David Brownell
0N/A */
0N/Afinal class ServerHandshaker extends Handshaker {
0N/A
0N/A // is the server going to require the client to authenticate?
0N/A private byte doClientAuth;
0N/A
0N/A // our authentication info
0N/A private X509Certificate[] certs;
0N/A private PrivateKey privateKey;
0N/A
1870N/A private SecretKey[] kerberosKeys;
0N/A
0N/A // flag to check for clientCertificateVerify message
0N/A private boolean needClientVerify = false;
0N/A
0N/A /*
0N/A * For exportable ciphersuites using non-exportable key sizes, we use
0N/A * ephemeral RSA keys. We could also do anonymous RSA in the same way
0N/A * but there are no such ciphersuites currently defined.
0N/A */
0N/A private PrivateKey tempPrivateKey;
0N/A private PublicKey tempPublicKey;
0N/A
0N/A /*
0N/A * For anonymous and ephemeral Diffie-Hellman key exchange, we use
0N/A * ephemeral Diffie-Hellman keys.
0N/A */
0N/A private DHCrypt dh;
0N/A
0N/A // Helper for ECDH based key exchanges
0N/A private ECDHCrypt ecdh;
0N/A
0N/A // version request by the client in its ClientHello
0N/A // we remember it for the RSA premaster secret version check
0N/A private ProtocolVersion clientRequestedVersion;
0N/A
0N/A private SupportedEllipticCurvesExtension supportedCurves;
0N/A
3002N/A // the preferable signature algorithm used by ServerKeyExchange message
3002N/A SignatureAndHashAlgorithm preferableSignatureAlgorithm;
3002N/A
0N/A /*
0N/A * Constructor ... use the keys found in the auth context.
0N/A */
0N/A ServerHandshaker(SSLSocketImpl socket, SSLContextImpl context,
2261N/A ProtocolList enabledProtocols, byte clientAuth,
2890N/A ProtocolVersion activeProtocolVersion, boolean isInitialHandshake,
2890N/A boolean secureRenegotiation,
2890N/A byte[] clientVerifyData, byte[] serverVerifyData) {
2261N/A
0N/A super(socket, context, enabledProtocols,
2890N/A (clientAuth != SSLEngineImpl.clauth_none), false,
2890N/A activeProtocolVersion, isInitialHandshake, secureRenegotiation,
2890N/A clientVerifyData, serverVerifyData);
0N/A doClientAuth = clientAuth;
0N/A }
0N/A
0N/A /*
0N/A * Constructor ... use the keys found in the auth context.
0N/A */
0N/A ServerHandshaker(SSLEngineImpl engine, SSLContextImpl context,
2261N/A ProtocolList enabledProtocols, byte clientAuth,
2890N/A ProtocolVersion activeProtocolVersion,
2890N/A boolean isInitialHandshake, boolean secureRenegotiation,
2890N/A byte[] clientVerifyData, byte[] serverVerifyData) {
2261N/A
0N/A super(engine, context, enabledProtocols,
2890N/A (clientAuth != SSLEngineImpl.clauth_none), false,
2890N/A activeProtocolVersion, isInitialHandshake, secureRenegotiation,
2890N/A clientVerifyData, serverVerifyData);
0N/A doClientAuth = clientAuth;
0N/A }
0N/A
0N/A /*
0N/A * As long as handshaking has not started, we can change
0N/A * whether client authentication is required. Otherwise,
0N/A * we will need to wait for the next handshake.
0N/A */
0N/A void setClientAuth(byte clientAuth) {
0N/A doClientAuth = clientAuth;
0N/A }
0N/A
0N/A /*
0N/A * This routine handles all the server side handshake messages, one at
0N/A * a time. Given the message type (and in some cases the pending cipher
0N/A * spec) it parses the type-specific message. Then it calls a function
0N/A * that handles that specific message.
0N/A *
0N/A * It updates the state machine as each message is processed, and writes
0N/A * responses as needed using the connection in the constructor.
0N/A */
0N/A void processMessage(byte type, int message_len)
0N/A throws IOException {
0N/A //
0N/A // In SSLv3 and TLS, messages follow strictly increasing
0N/A // numerical order _except_ for one annoying special case.
0N/A //
5691N/A if ((state >= type)
0N/A && (state != HandshakeMessage.ht_client_key_exchange
0N/A && type != HandshakeMessage.ht_certificate_verify)) {
0N/A throw new SSLProtocolException(
0N/A "Handshake message sequence violation, state = " + state
0N/A + ", type = " + type);
0N/A }
0N/A
0N/A switch (type) {
0N/A case HandshakeMessage.ht_client_hello:
0N/A ClientHello ch = new ClientHello(input, message_len);
0N/A /*
0N/A * send it off for processing.
0N/A */
0N/A this.clientHello(ch);
0N/A break;
0N/A
0N/A case HandshakeMessage.ht_certificate:
0N/A if (doClientAuth == SSLEngineImpl.clauth_none) {
0N/A fatalSE(Alerts.alert_unexpected_message,
0N/A "client sent unsolicited cert chain");
0N/A // NOTREACHED
0N/A }
0N/A this.clientCertificate(new CertificateMsg(input));
0N/A break;
0N/A
0N/A case HandshakeMessage.ht_client_key_exchange:
0N/A SecretKey preMasterSecret;
0N/A switch (keyExchange) {
0N/A case K_RSA:
0N/A case K_RSA_EXPORT:
0N/A /*
0N/A * The client's pre-master secret is decrypted using
0N/A * either the server's normal private RSA key, or the
0N/A * temporary one used for non-export or signing-only
0N/A * certificates/keys.
0N/A */
2998N/A RSAClientKeyExchange pms = new RSAClientKeyExchange(
2998N/A protocolVersion, clientRequestedVersion,
2998N/A sslContext.getSecureRandom(), input,
2998N/A message_len, privateKey);
0N/A preMasterSecret = this.clientKeyExchange(pms);
0N/A break;
0N/A case K_KRB5:
0N/A case K_KRB5_EXPORT:
0N/A preMasterSecret = this.clientKeyExchange(
0N/A new KerberosClientKeyExchange(protocolVersion,
0N/A clientRequestedVersion,
0N/A sslContext.getSecureRandom(),
0N/A input,
0N/A kerberosKeys));
0N/A break;
0N/A case K_DHE_RSA:
0N/A case K_DHE_DSS:
0N/A case K_DH_ANON:
0N/A /*
0N/A * The pre-master secret is derived using the normal
0N/A * Diffie-Hellman calculation. Note that the main
0N/A * protocol difference in these five flavors is in how
0N/A * the ServerKeyExchange message was constructed!
0N/A */
0N/A preMasterSecret = this.clientKeyExchange(
0N/A new DHClientKeyExchange(input));
0N/A break;
0N/A case K_ECDH_RSA:
0N/A case K_ECDH_ECDSA:
0N/A case K_ECDHE_RSA:
0N/A case K_ECDHE_ECDSA:
0N/A case K_ECDH_ANON:
0N/A preMasterSecret = this.clientKeyExchange
0N/A (new ECDHClientKeyExchange(input));
0N/A break;
0N/A default:
0N/A throw new SSLProtocolException
0N/A ("Unrecognized key exchange: " + keyExchange);
0N/A }
0N/A
0N/A //
0N/A // All keys are calculated from the premaster secret
0N/A // and the exchanged nonces in the same way.
0N/A //
0N/A calculateKeys(preMasterSecret, clientRequestedVersion);
0N/A break;
0N/A
0N/A case HandshakeMessage.ht_certificate_verify:
3002N/A this.clientCertificateVerify(new CertificateVerify(input,
3002N/A localSupportedSignAlgs, protocolVersion));
0N/A break;
0N/A
0N/A case HandshakeMessage.ht_finished:
3002N/A this.clientFinished(
3002N/A new Finished(protocolVersion, input, cipherSuite));
0N/A break;
0N/A
0N/A default:
0N/A throw new SSLProtocolException(
0N/A "Illegal server handshake msg, " + type);
0N/A }
0N/A
0N/A //
5691N/A // Move state machine forward if the message handling
5691N/A // code didn't already do so
0N/A //
5691N/A if (state < type) {
5691N/A if(type == HandshakeMessage.ht_certificate_verify) {
5691N/A state = type + 2; // an annoying special case
5691N/A } else {
5691N/A state = type;
5691N/A }
0N/A }
0N/A }
0N/A
0N/A
0N/A /*
0N/A * ClientHello presents the server with a bunch of options, to which the
0N/A * server replies with a ServerHello listing the ones which this session
0N/A * will use. If needed, it also writes its Certificate plus in some cases
0N/A * a ServerKeyExchange message. It may also write a CertificateRequest,
0N/A * to elicit a client certificate.
0N/A *
0N/A * All these messages are terminated by a ServerHelloDone message. In
0N/A * most cases, all this can be sent in a single Record.
0N/A */
0N/A private void clientHello(ClientHello mesg) throws IOException {
0N/A if (debug != null && Debug.isOn("handshake")) {
0N/A mesg.print(System.out);
0N/A }
2261N/A
2890N/A // Does the message include security renegotiation indication?
2890N/A boolean renegotiationIndicated = false;
2261N/A
2890N/A // check the TLS_EMPTY_RENEGOTIATION_INFO_SCSV
2890N/A CipherSuiteList cipherSuites = mesg.getCipherSuites();
2890N/A if (cipherSuites.contains(CipherSuite.C_SCSV)) {
2890N/A renegotiationIndicated = true;
2890N/A if (isInitialHandshake) {
2890N/A secureRenegotiation = true;
2890N/A } else {
2890N/A // abort the handshake with a fatal handshake_failure alert
2890N/A if (secureRenegotiation) {
2890N/A fatalSE(Alerts.alert_handshake_failure,
2890N/A "The SCSV is present in a secure renegotiation");
2890N/A } else {
2890N/A fatalSE(Alerts.alert_handshake_failure,
2890N/A "The SCSV is present in a insecure renegotiation");
2890N/A }
2890N/A }
2890N/A }
2261N/A
2890N/A // check the "renegotiation_info" extension
2890N/A RenegotiationInfoExtension clientHelloRI = (RenegotiationInfoExtension)
2890N/A mesg.extensions.get(ExtensionType.EXT_RENEGOTIATION_INFO);
2890N/A if (clientHelloRI != null) {
2890N/A renegotiationIndicated = true;
2890N/A if (isInitialHandshake) {
2890N/A // verify the length of the "renegotiated_connection" field
2890N/A if (!clientHelloRI.isEmpty()) {
2890N/A // abort the handshake with a fatal handshake_failure alert
2890N/A fatalSE(Alerts.alert_handshake_failure,
2890N/A "The renegotiation_info field is not empty");
2890N/A }
2261N/A
2890N/A secureRenegotiation = true;
2890N/A } else {
2890N/A if (!secureRenegotiation) {
2890N/A // unexpected RI extension for insecure renegotiation,
2890N/A // abort the handshake with a fatal handshake_failure alert
2890N/A fatalSE(Alerts.alert_handshake_failure,
2890N/A "The renegotiation_info is present in a insecure " +
2890N/A "renegotiation");
2261N/A }
2261N/A
2890N/A // verify the client_verify_data value
2890N/A if (!Arrays.equals(clientVerifyData,
2890N/A clientHelloRI.getRenegotiatedConnection())) {
2890N/A fatalSE(Alerts.alert_handshake_failure,
2890N/A "Incorrect verify data in ClientHello " +
2890N/A "renegotiation_info message");
2890N/A }
2890N/A }
2890N/A } else if (!isInitialHandshake && secureRenegotiation) {
2890N/A // if the connection's "secure_renegotiation" flag is set to TRUE
2890N/A // and the "renegotiation_info" extension is not present, abort
2890N/A // the handshake.
2890N/A fatalSE(Alerts.alert_handshake_failure,
2890N/A "Inconsistent secure renegotiation indication");
2890N/A }
2890N/A
2890N/A // if there is no security renegotiation indication or the previous
2890N/A // handshake is insecure.
2890N/A if (!renegotiationIndicated || !secureRenegotiation) {
2890N/A if (isInitialHandshake) {
2890N/A if (!allowLegacyHelloMessages) {
2890N/A // abort the handshake with a fatal handshake_failure alert
2890N/A fatalSE(Alerts.alert_handshake_failure,
2890N/A "Failed to negotiate the use of secure renegotiation");
2890N/A }
2890N/A
2890N/A // continue with legacy ClientHello
2890N/A if (debug != null && Debug.isOn("handshake")) {
2890N/A System.out.println("Warning: No renegotiation " +
2890N/A "indication in ClientHello, allow legacy ClientHello");
2890N/A }
2890N/A } else if (!allowUnsafeRenegotiation) {
2890N/A // abort the handshake
2890N/A if (activeProtocolVersion.v >= ProtocolVersion.TLS10.v) {
2890N/A // response with a no_renegotiation warning,
2890N/A warningSE(Alerts.alert_no_renegotiation);
2890N/A
2890N/A // invalidate the handshake so that the caller can
2890N/A // dispose this object.
2890N/A invalidated = true;
2890N/A
2890N/A // If there is still unread block in the handshake
2890N/A // input stream, it would be truncated with the disposal
2890N/A // and the next handshake message will become incomplete.
2890N/A //
2890N/A // However, according to SSL/TLS specifications, no more
2890N/A // handshake message could immediately follow ClientHello
2890N/A // or HelloRequest. But in case of any improper messages,
2890N/A // we'd better check to ensure there is no remaining bytes
2890N/A // in the handshake input stream.
2890N/A if (input.available() > 0) {
2890N/A fatalSE(Alerts.alert_unexpected_message,
2890N/A "ClientHello followed by an unexpected " +
2890N/A "handshake message");
2890N/A }
2890N/A
2890N/A return;
2890N/A } else {
2890N/A // For SSLv3, send the handshake_failure fatal error.
2890N/A // Note that SSLv3 does not define a no_renegotiation
2890N/A // alert like TLSv1. However we cannot ignore the message
2890N/A // simply, otherwise the other side was waiting for a
2890N/A // response that would never come.
2890N/A fatalSE(Alerts.alert_handshake_failure,
2890N/A "Renegotiation is not allowed");
2890N/A }
2890N/A } else { // !isInitialHandshake && allowUnsafeRenegotiation
2890N/A // continue with unsafe renegotiation.
2890N/A if (debug != null && Debug.isOn("handshake")) {
2890N/A System.out.println(
2890N/A "Warning: continue with insecure renegotiation");
2890N/A }
2261N/A }
2261N/A }
2261N/A
0N/A /*
0N/A * Always make sure this entire record has been digested before we
0N/A * start emitting output, to ensure correct digesting order.
0N/A */
0N/A input.digestNow();
0N/A
0N/A /*
0N/A * FIRST, construct the ServerHello using the options and priorities
0N/A * from the ClientHello. Update the (pending) cipher spec as we do
0N/A * so, and save the client's version to protect against rollback
0N/A * attacks.
0N/A *
0N/A * There are a bunch of minor tasks here, and one major one: deciding
0N/A * if the short or the full handshake sequence will be used.
0N/A */
0N/A ServerHello m1 = new ServerHello();
0N/A
0N/A clientRequestedVersion = mesg.protocolVersion;
0N/A
2998N/A // select a proper protocol version.
2998N/A ProtocolVersion selectedVersion =
2998N/A selectProtocolVersion(clientRequestedVersion);
2998N/A if (selectedVersion == null ||
2998N/A selectedVersion.v == ProtocolVersion.SSL20Hello.v) {
0N/A fatalSE(Alerts.alert_handshake_failure,
0N/A "Client requested protocol " + clientRequestedVersion +
2998N/A " not enabled or not supported");
0N/A }
3002N/A
3324N/A handshakeHash.protocolDetermined(selectedVersion);
0N/A setVersion(selectedVersion);
0N/A
0N/A m1.protocolVersion = protocolVersion;
0N/A
0N/A //
0N/A // random ... save client and server values for later use
0N/A // in computing the master secret (from pre-master secret)
0N/A // and thence the other crypto keys.
0N/A //
0N/A // NOTE: this use of three inputs to generating _each_ set
0N/A // of ciphers slows things down, but it does increase the
0N/A // security since each connection in the session can hold
0N/A // its own authenticated (and strong) keys. One could make
0N/A // creation of a session a rare thing...
0N/A //
0N/A clnt_random = mesg.clnt_random;
0N/A svr_random = new RandomCookie(sslContext.getSecureRandom());
0N/A m1.svr_random = svr_random;
0N/A
0N/A session = null; // forget about the current session
0N/A //
0N/A // Here we go down either of two paths: (a) the fast one, where
0N/A // the client's asked to rejoin an existing session, and the server
0N/A // permits this; (b) the other one, where a new session is created.
0N/A //
0N/A if (mesg.sessionId.length() != 0) {
0N/A // client is trying to resume a session, let's see...
0N/A
0N/A SSLSessionImpl previous = ((SSLSessionContextImpl)sslContext
0N/A .engineGetServerSessionContext())
0N/A .get(mesg.sessionId.getId());
0N/A //
0N/A // Check if we can use the fast path, resuming a session. We
0N/A // can do so iff we have a valid record for that session, and
0N/A // the cipher suite for that session was on the list which the
0N/A // client requested, and if we're not forgetting any needed
0N/A // authentication on the part of the client.
0N/A //
0N/A if (previous != null) {
0N/A resumingSession = previous.isRejoinable();
0N/A
0N/A if (resumingSession) {
0N/A ProtocolVersion oldVersion = previous.getProtocolVersion();
0N/A // cannot resume session with different version
0N/A if (oldVersion != protocolVersion) {
0N/A resumingSession = false;
0N/A }
0N/A }
0N/A
0N/A if (resumingSession &&
0N/A (doClientAuth == SSLEngineImpl.clauth_required)) {
0N/A try {
0N/A previous.getPeerPrincipal();
0N/A } catch (SSLPeerUnverifiedException e) {
0N/A resumingSession = false;
0N/A }
0N/A }
0N/A
0N/A // validate subject identity
0N/A if (resumingSession) {
0N/A CipherSuite suite = previous.getSuite();
0N/A if (suite.keyExchange == K_KRB5 ||
0N/A suite.keyExchange == K_KRB5_EXPORT) {
0N/A Principal localPrincipal = previous.getLocalPrincipal();
0N/A
0N/A Subject subject = null;
0N/A try {
0N/A subject = AccessController.doPrivileged(
0N/A new PrivilegedExceptionAction<Subject>() {
0N/A public Subject run() throws Exception {
1870N/A return
1870N/A Krb5Helper.getServerSubject(getAccSE());
0N/A }});
0N/A } catch (PrivilegedActionException e) {
0N/A subject = null;
0N/A if (debug != null && Debug.isOn("session")) {
0N/A System.out.println("Attempt to obtain" +
0N/A " subject failed!");
0N/A }
0N/A }
0N/A
0N/A if (subject != null) {
1870N/A // Eliminate dependency on KerberosPrincipal
1870N/A Set<Principal> principals =
1870N/A subject.getPrincipals(Principal.class);
0N/A if (!principals.contains(localPrincipal)) {
0N/A resumingSession = false;
0N/A if (debug != null && Debug.isOn("session")) {
0N/A System.out.println("Subject identity" +
0N/A " is not the same");
0N/A }
0N/A } else {
0N/A if (debug != null && Debug.isOn("session"))
0N/A System.out.println("Subject identity" +
0N/A " is same");
0N/A }
0N/A } else {
0N/A resumingSession = false;
0N/A if (debug != null && Debug.isOn("session"))
0N/A System.out.println("Kerberos credentials are" +
0N/A " not present in the current Subject;" +
0N/A " check if " +
0N/A " javax.security.auth.useSubjectAsCreds" +
0N/A " system property has been set to false");
0N/A }
0N/A }
0N/A }
0N/A
0N/A if (resumingSession) {
0N/A CipherSuite suite = previous.getSuite();
0N/A // verify that the ciphersuite from the cached session
0N/A // is in the list of client requested ciphersuites and
0N/A // we have it enabled
2890N/A if ((isNegotiable(suite) == false) ||
0N/A (mesg.getCipherSuites().contains(suite) == false)) {
0N/A resumingSession = false;
0N/A } else {
0N/A // everything looks ok, set the ciphersuite
0N/A // this should be done last when we are sure we
0N/A // will resume
0N/A setCipherSuite(suite);
0N/A }
0N/A }
0N/A
0N/A if (resumingSession) {
0N/A session = previous;
0N/A if (debug != null &&
0N/A (Debug.isOn("handshake") || Debug.isOn("session"))) {
0N/A System.out.println("%% Resuming " + session);
0N/A }
0N/A }
0N/A }
0N/A } // else client did not try to resume
0N/A
0N/A //
0N/A // If client hasn't specified a session we can resume, start a
0N/A // new one and choose its cipher suite and compression options.
0N/A // Unless new session creation is disabled for this connection!
0N/A //
0N/A if (session == null) {
0N/A if (!enableNewSession) {
0N/A throw new SSLException("Client did not resume a session");
0N/A }
3002N/A
2890N/A supportedCurves = (SupportedEllipticCurvesExtension)
2890N/A mesg.extensions.get(ExtensionType.EXT_ELLIPTIC_CURVES);
3002N/A
3002N/A // We only need to handle the "signature_algorithm" extension
3002N/A // for full handshakes and TLS 1.2 or later.
3002N/A if (protocolVersion.v >= ProtocolVersion.TLS12.v) {
3002N/A SignatureAlgorithmsExtension signAlgs =
3002N/A (SignatureAlgorithmsExtension)mesg.extensions.get(
3002N/A ExtensionType.EXT_SIGNATURE_ALGORITHMS);
3002N/A if (signAlgs != null) {
3002N/A Collection<SignatureAndHashAlgorithm> peerSignAlgs =
3002N/A signAlgs.getSignAlgorithms();
3002N/A if (peerSignAlgs == null || peerSignAlgs.isEmpty()) {
3002N/A throw new SSLHandshakeException(
3002N/A "No peer supported signature algorithms");
3002N/A }
3002N/A
3002N/A Collection<SignatureAndHashAlgorithm>
3002N/A supportedPeerSignAlgs =
3002N/A SignatureAndHashAlgorithm.getSupportedAlgorithms(
3002N/A peerSignAlgs);
3002N/A if (supportedPeerSignAlgs.isEmpty()) {
3002N/A throw new SSLHandshakeException(
3002N/A "No supported signature and hash algorithm " +
3002N/A "in common");
3002N/A }
3002N/A
3002N/A setPeerSupportedSignAlgs(supportedPeerSignAlgs);
3002N/A } // else, need to use peer implicit supported signature algs
3002N/A }
3002N/A
3002N/A session = new SSLSessionImpl(protocolVersion, CipherSuite.C_NULL,
3002N/A getLocalSupportedSignAlgs(),
3002N/A sslContext.getSecureRandom(),
3002N/A getHostAddressSE(), getPortSE());
3002N/A
3002N/A if (protocolVersion.v >= ProtocolVersion.TLS12.v) {
3002N/A if (peerSupportedSignAlgs != null) {
3002N/A session.setPeerSupportedSignatureAlgorithms(
3002N/A peerSupportedSignAlgs);
3002N/A } // else, we will set the implicit peer supported signature
3002N/A // algorithms in chooseCipherSuite()
3002N/A }
3002N/A
3002N/A // set the handshake session
3002N/A setHandshakeSessionSE(session);
3002N/A
3002N/A // choose cipher suite and corresponding private key
0N/A chooseCipherSuite(mesg);
3002N/A
3002N/A session.setSuite(cipherSuite);
0N/A session.setLocalPrivateKey(privateKey);
3002N/A
0N/A // chooseCompression(mesg);
3002N/A } else {
3002N/A // set the handshake session
3002N/A setHandshakeSessionSE(session);
3002N/A }
3002N/A
3002N/A if (protocolVersion.v >= ProtocolVersion.TLS12.v) {
3002N/A if (resumingSession) {
3002N/A handshakeHash.setCertificateVerifyAlg(null);
3002N/A }
3002N/A handshakeHash.setFinishedAlg(cipherSuite.prfAlg.getPRFHashAlg());
0N/A }
0N/A
0N/A m1.cipherSuite = cipherSuite;
0N/A m1.sessionId = session.getSessionId();
0N/A m1.compression_method = session.getCompression();
0N/A
2890N/A if (secureRenegotiation) {
2890N/A // For ServerHellos that are initial handshakes, then the
2890N/A // "renegotiated_connection" field in "renegotiation_info"
2890N/A // extension is of zero length.
2890N/A //
2890N/A // For ServerHellos that are renegotiating, this field contains
2890N/A // the concatenation of client_verify_data and server_verify_data.
2890N/A //
2890N/A // Note that for initial handshakes, both the clientVerifyData
2890N/A // variable and serverVerifyData variable are of zero length.
2890N/A HelloExtension serverHelloRI = new RenegotiationInfoExtension(
2890N/A clientVerifyData, serverVerifyData);
2890N/A m1.extensions.add(serverHelloRI);
2890N/A }
2890N/A
0N/A if (debug != null && Debug.isOn("handshake")) {
0N/A m1.print(System.out);
0N/A System.out.println("Cipher suite: " + session.getSuite());
0N/A }
0N/A m1.write(output);
0N/A
0N/A //
0N/A // If we are resuming a session, we finish writing handshake
0N/A // messages right now and then finish.
0N/A //
0N/A if (resumingSession) {
0N/A calculateConnectionKeys(session.getMasterSecret());
0N/A sendChangeCipherAndFinish(false);
0N/A return;
0N/A }
0N/A
0N/A
0N/A /*
0N/A * SECOND, write the server Certificate(s) if we need to.
0N/A *
0N/A * NOTE: while an "anonymous RSA" mode is explicitly allowed by
0N/A * the protocol, we can't support it since all of the SSL flavors
0N/A * defined in the protocol spec are explicitly stated to require
0N/A * using RSA certificates.
0N/A */
0N/A if (keyExchange == K_KRB5 || keyExchange == K_KRB5_EXPORT) {
0N/A // Server certificates are omitted for Kerberos ciphers
0N/A
0N/A } else if ((keyExchange != K_DH_ANON) && (keyExchange != K_ECDH_ANON)) {
0N/A if (certs == null) {
0N/A throw new RuntimeException("no certificates");
0N/A }
0N/A
0N/A CertificateMsg m2 = new CertificateMsg(certs);
0N/A
0N/A /*
0N/A * Set local certs in the SSLSession, output
0N/A * debug info, and then actually write to the client.
0N/A */
0N/A session.setLocalCertificates(certs);
0N/A if (debug != null && Debug.isOn("handshake")) {
0N/A m2.print(System.out);
0N/A }
0N/A m2.write(output);
0N/A
0N/A // XXX has some side effects with OS TCP buffering,
0N/A // leave it out for now
0N/A
0N/A // let client verify chain in the meantime...
0N/A // output.flush();
0N/A } else {
0N/A if (certs != null) {
0N/A throw new RuntimeException("anonymous keyexchange with certs");
0N/A }
0N/A }
0N/A
0N/A /*
0N/A * THIRD, the ServerKeyExchange message ... iff it's needed.
0N/A *
0N/A * It's usually needed unless there's an encryption-capable
0N/A * RSA cert, or a D-H cert. The notable exception is that
0N/A * exportable ciphers used with big RSA keys need to downgrade
0N/A * to use short RSA keys, even when the key/cert encrypts OK.
0N/A */
0N/A
0N/A ServerKeyExchange m3;
0N/A switch (keyExchange) {
0N/A case K_RSA:
0N/A case K_KRB5:
0N/A case K_KRB5_EXPORT:
0N/A // no server key exchange for RSA or KRB5 ciphersuites
0N/A m3 = null;
0N/A break;
0N/A case K_RSA_EXPORT:
0N/A if (JsseJce.getRSAKeyLength(certs[0].getPublicKey()) > 512) {
0N/A try {
0N/A m3 = new RSA_ServerKeyExchange(
0N/A tempPublicKey, privateKey,
0N/A clnt_random, svr_random,
0N/A sslContext.getSecureRandom());
0N/A privateKey = tempPrivateKey;
0N/A } catch (GeneralSecurityException e) {
0N/A throwSSLException
0N/A ("Error generating RSA server key exchange", e);
0N/A m3 = null; // make compiler happy
0N/A }
0N/A } else {
0N/A // RSA_EXPORT with short key, don't need ServerKeyExchange
0N/A m3 = null;
0N/A }
0N/A break;
0N/A case K_DHE_RSA:
0N/A case K_DHE_DSS:
0N/A try {
0N/A m3 = new DH_ServerKeyExchange(dh,
0N/A privateKey,
0N/A clnt_random.random_bytes,
0N/A svr_random.random_bytes,
3002N/A sslContext.getSecureRandom(),
3002N/A preferableSignatureAlgorithm,
3002N/A protocolVersion);
0N/A } catch (GeneralSecurityException e) {
0N/A throwSSLException("Error generating DH server key exchange", e);
0N/A m3 = null; // make compiler happy
0N/A }
0N/A break;
0N/A case K_DH_ANON:
3002N/A m3 = new DH_ServerKeyExchange(dh, protocolVersion);
0N/A break;
0N/A case K_ECDHE_RSA:
0N/A case K_ECDHE_ECDSA:
0N/A case K_ECDH_ANON:
0N/A try {
0N/A m3 = new ECDH_ServerKeyExchange(ecdh,
0N/A privateKey,
0N/A clnt_random.random_bytes,
0N/A svr_random.random_bytes,
3002N/A sslContext.getSecureRandom(),
3002N/A preferableSignatureAlgorithm,
3002N/A protocolVersion);
0N/A } catch (GeneralSecurityException e) {
3002N/A throwSSLException(
3002N/A "Error generating ECDH server key exchange", e);
0N/A m3 = null; // make compiler happy
0N/A }
0N/A break;
0N/A case K_ECDH_RSA:
0N/A case K_ECDH_ECDSA:
0N/A // ServerKeyExchange not used for fixed ECDH
0N/A m3 = null;
0N/A break;
0N/A default:
0N/A throw new RuntimeException("internal error: " + keyExchange);
0N/A }
0N/A if (m3 != null) {
0N/A if (debug != null && Debug.isOn("handshake")) {
0N/A m3.print(System.out);
0N/A }
0N/A m3.write(output);
0N/A }
0N/A
0N/A //
0N/A // FOURTH, the CertificateRequest message. The details of
0N/A // the message can be affected by the key exchange algorithm
0N/A // in use. For example, certs with fixed Diffie-Hellman keys
0N/A // are only useful with the DH_DSS and DH_RSA key exchange
0N/A // algorithms.
0N/A //
0N/A // Needed only if server requires client to authenticate self.
0N/A // Illegal for anonymous flavors, so we need to check that.
0N/A //
3002N/A // CertificateRequest is omitted for Kerberos ciphers
3002N/A if (doClientAuth != SSLEngineImpl.clauth_none &&
3002N/A keyExchange != K_DH_ANON && keyExchange != K_ECDH_ANON &&
3002N/A keyExchange != K_KRB5 && keyExchange != K_KRB5_EXPORT) {
0N/A
0N/A CertificateRequest m4;
0N/A X509Certificate caCerts[];
0N/A
3002N/A Collection<SignatureAndHashAlgorithm> localSignAlgs = null;
3002N/A if (protocolVersion.v >= ProtocolVersion.TLS12.v) {
3002N/A // We currently use all local upported signature and hash
3002N/A // algorithms. However, to minimize the computation cost
3002N/A // of requested hash algorithms, we may use a restricted
3002N/A // set of signature algorithms in the future.
3002N/A localSignAlgs = getLocalSupportedSignAlgs();
3002N/A if (localSignAlgs.isEmpty()) {
3002N/A throw new SSLHandshakeException(
3002N/A "No supported signature algorithm");
3002N/A }
3002N/A
3002N/A Set<String> localHashAlgs =
3002N/A SignatureAndHashAlgorithm.getHashAlgorithmNames(
3002N/A localSignAlgs);
3002N/A if (localHashAlgs.isEmpty()) {
3002N/A throw new SSLHandshakeException(
3002N/A "No supported signature algorithm");
3002N/A }
3002N/A handshakeHash.restrictCertificateVerifyAlgs(localHashAlgs);
3002N/A }
3002N/A
0N/A caCerts = sslContext.getX509TrustManager().getAcceptedIssuers();
3002N/A m4 = new CertificateRequest(caCerts, keyExchange,
3002N/A localSignAlgs, protocolVersion);
0N/A
0N/A if (debug != null && Debug.isOn("handshake")) {
0N/A m4.print(System.out);
0N/A }
0N/A m4.write(output);
3002N/A } else {
3002N/A if (protocolVersion.v >= ProtocolVersion.TLS12.v) {
3002N/A handshakeHash.setCertificateVerifyAlg(null);
3002N/A }
0N/A }
0N/A
0N/A /*
0N/A * FIFTH, say ServerHelloDone.
0N/A */
0N/A ServerHelloDone m5 = new ServerHelloDone();
0N/A
0N/A if (debug != null && Debug.isOn("handshake")) {
0N/A m5.print(System.out);
0N/A }
0N/A m5.write(output);
0N/A
0N/A /*
0N/A * Flush any buffered messages so the client will see them.
0N/A * Ideally, all the messages above go in a single network level
0N/A * message to the client. Without big Certificate chains, it's
0N/A * going to be the common case.
0N/A */
0N/A output.flush();
0N/A }
0N/A
0N/A /*
0N/A * Choose cipher suite from among those supported by client. Sets
0N/A * the cipherSuite and keyExchange variables.
0N/A */
0N/A private void chooseCipherSuite(ClientHello mesg) throws IOException {
0N/A for (CipherSuite suite : mesg.getCipherSuites().collection()) {
2890N/A if (isNegotiable(suite) == false) {
0N/A continue;
0N/A }
2890N/A
0N/A if (doClientAuth == SSLEngineImpl.clauth_required) {
2890N/A if ((suite.keyExchange == K_DH_ANON) ||
2890N/A (suite.keyExchange == K_ECDH_ANON)) {
0N/A continue;
0N/A }
0N/A }
0N/A if (trySetCipherSuite(suite) == false) {
0N/A continue;
0N/A }
0N/A return;
0N/A }
0N/A fatalSE(Alerts.alert_handshake_failure,
0N/A "no cipher suites in common");
0N/A }
0N/A
0N/A /**
0N/A * Set the given CipherSuite, if possible. Return the result.
0N/A * The call succeeds if the CipherSuite is available and we have
0N/A * the necessary certificates to complete the handshake. We don't
0N/A * check if the CipherSuite is actually enabled.
0N/A *
0N/A * If successful, this method also generates ephemeral keys if
0N/A * required for this ciphersuite. This may take some time, so this
0N/A * method should only be called if you really want to use the
0N/A * CipherSuite.
0N/A *
2998N/A * This method is called from chooseCipherSuite() in this class.
0N/A */
0N/A boolean trySetCipherSuite(CipherSuite suite) {
0N/A /*
0N/A * If we're resuming a session we know we can
0N/A * support this key exchange algorithm and in fact
0N/A * have already cached the result of it in
0N/A * the session state.
0N/A */
0N/A if (resumingSession) {
0N/A return true;
0N/A }
0N/A
2890N/A if (suite.isNegotiable() == false) {
0N/A return false;
0N/A }
0N/A
3002N/A // must not negotiate the obsoleted weak cipher suites.
2998N/A if (protocolVersion.v >= suite.obsoleted) {
2998N/A return false;
2998N/A }
2998N/A
3002N/A // must not negotiate unsupported cipher suites.
3002N/A if (protocolVersion.v < suite.supported) {
3002N/A return false;
3002N/A }
3002N/A
0N/A KeyExchange keyExchange = suite.keyExchange;
0N/A
0N/A // null out any existing references
0N/A privateKey = null;
0N/A certs = null;
0N/A dh = null;
0N/A tempPrivateKey = null;
0N/A tempPublicKey = null;
0N/A
3002N/A Collection<SignatureAndHashAlgorithm> supportedSignAlgs = null;
3002N/A if (protocolVersion.v >= ProtocolVersion.TLS12.v) {
3002N/A if (peerSupportedSignAlgs != null) {
3002N/A supportedSignAlgs = peerSupportedSignAlgs;
3002N/A } else {
3002N/A SignatureAndHashAlgorithm algorithm = null;
3002N/A
3002N/A // we may optimize the performance
3002N/A switch (keyExchange) {
3002N/A // If the negotiated key exchange algorithm is one of
3002N/A // (RSA, DHE_RSA, DH_RSA, RSA_PSK, ECDH_RSA, ECDHE_RSA),
3002N/A // behave as if client had sent the value {sha1,rsa}.
3002N/A case K_RSA:
3002N/A case K_DHE_RSA:
3002N/A case K_DH_RSA:
3002N/A // case K_RSA_PSK:
3002N/A case K_ECDH_RSA:
3002N/A case K_ECDHE_RSA:
3002N/A algorithm = SignatureAndHashAlgorithm.valueOf(
3002N/A HashAlgorithm.SHA1.value,
3002N/A SignatureAlgorithm.RSA.value, 0);
3002N/A break;
3002N/A // If the negotiated key exchange algorithm is one of
3002N/A // (DHE_DSS, DH_DSS), behave as if the client had
3002N/A // sent the value {sha1,dsa}.
3002N/A case K_DHE_DSS:
3002N/A case K_DH_DSS:
3002N/A algorithm = SignatureAndHashAlgorithm.valueOf(
3002N/A HashAlgorithm.SHA1.value,
3002N/A SignatureAlgorithm.DSA.value, 0);
3002N/A break;
3002N/A // If the negotiated key exchange algorithm is one of
3002N/A // (ECDH_ECDSA, ECDHE_ECDSA), behave as if the client
3002N/A // had sent value {sha1,ecdsa}.
3002N/A case K_ECDH_ECDSA:
3002N/A case K_ECDHE_ECDSA:
3002N/A algorithm = SignatureAndHashAlgorithm.valueOf(
3002N/A HashAlgorithm.SHA1.value,
3002N/A SignatureAlgorithm.ECDSA.value, 0);
3002N/A break;
3002N/A default:
3002N/A // no peer supported signature algorithms
3002N/A }
3002N/A
3002N/A if (algorithm == null) {
3002N/A supportedSignAlgs =
3002N/A Collections.<SignatureAndHashAlgorithm>emptySet();
3002N/A } else {
3002N/A supportedSignAlgs =
3002N/A new ArrayList<SignatureAndHashAlgorithm>(1);
3002N/A supportedSignAlgs.add(algorithm);
3002N/A }
3002N/A
3002N/A // Sets the peer supported signature algorithm to use in KM
3002N/A // temporarily.
3002N/A session.setPeerSupportedSignatureAlgorithms(supportedSignAlgs);
3002N/A }
3002N/A }
3002N/A
0N/A switch (keyExchange) {
0N/A case K_RSA:
3002N/A // need RSA certs for authentication
3002N/A if (setupPrivateKeyAndChain("RSA") == false) {
3002N/A return false;
3002N/A }
3002N/A break;
0N/A case K_RSA_EXPORT:
0N/A // need RSA certs for authentication
0N/A if (setupPrivateKeyAndChain("RSA") == false) {
0N/A return false;
0N/A }
0N/A
3002N/A try {
3002N/A if (JsseJce.getRSAKeyLength(certs[0].getPublicKey()) > 512) {
3002N/A if (!setupEphemeralRSAKeys(suite.exportable)) {
3002N/A return false;
3002N/A }
3002N/A }
3002N/A } catch (RuntimeException e) {
3002N/A // could not determine keylength, ignore key
3002N/A return false;
3002N/A }
3002N/A break;
3002N/A case K_DHE_RSA:
4589N/A // need RSA certs for authentication
4589N/A if (setupPrivateKeyAndChain("RSA") == false) {
4589N/A return false;
4589N/A }
4589N/A
3002N/A // get preferable peer signature algorithm for server key exchange
3002N/A if (protocolVersion.v >= ProtocolVersion.TLS12.v) {
3002N/A preferableSignatureAlgorithm =
3002N/A SignatureAndHashAlgorithm.getPreferableAlgorithm(
4589N/A supportedSignAlgs, "RSA", privateKey);
3002N/A if (preferableSignatureAlgorithm == null) {
0N/A return false;
0N/A }
3002N/A }
3002N/A
4589N/A setupEphemeralDHKeys(suite.exportable);
4589N/A break;
4589N/A case K_ECDHE_RSA:
3002N/A // need RSA certs for authentication
3002N/A if (setupPrivateKeyAndChain("RSA") == false) {
3002N/A return false;
3002N/A }
4589N/A
3002N/A // get preferable peer signature algorithm for server key exchange
3002N/A if (protocolVersion.v >= ProtocolVersion.TLS12.v) {
3002N/A preferableSignatureAlgorithm =
3002N/A SignatureAndHashAlgorithm.getPreferableAlgorithm(
4589N/A supportedSignAlgs, "RSA", privateKey);
3002N/A if (preferableSignatureAlgorithm == null) {
0N/A return false;
0N/A }
3002N/A }
3002N/A
3002N/A if (setupEphemeralECDHKeys() == false) {
3002N/A return false;
3002N/A }
0N/A break;
0N/A case K_DHE_DSS:
3002N/A // get preferable peer signature algorithm for server key exchange
3002N/A if (protocolVersion.v >= ProtocolVersion.TLS12.v) {
3002N/A preferableSignatureAlgorithm =
3002N/A SignatureAndHashAlgorithm.getPreferableAlgorithm(
3002N/A supportedSignAlgs, "DSA");
3002N/A if (preferableSignatureAlgorithm == null) {
3002N/A return false;
3002N/A }
3002N/A }
3002N/A
0N/A // need DSS certs for authentication
0N/A if (setupPrivateKeyAndChain("DSA") == false) {
0N/A return false;
0N/A }
0N/A setupEphemeralDHKeys(suite.exportable);
0N/A break;
0N/A case K_ECDHE_ECDSA:
3002N/A // get preferable peer signature algorithm for server key exchange
3002N/A if (protocolVersion.v >= ProtocolVersion.TLS12.v) {
3002N/A preferableSignatureAlgorithm =
3002N/A SignatureAndHashAlgorithm.getPreferableAlgorithm(
3002N/A supportedSignAlgs, "ECDSA");
3002N/A if (preferableSignatureAlgorithm == null) {
3002N/A return false;
3002N/A }
3002N/A }
3002N/A
0N/A // need EC cert signed using EC
0N/A if (setupPrivateKeyAndChain("EC_EC") == false) {
0N/A return false;
0N/A }
0N/A if (setupEphemeralECDHKeys() == false) {
0N/A return false;
0N/A }
0N/A break;
0N/A case K_ECDH_RSA:
0N/A // need EC cert signed using RSA
0N/A if (setupPrivateKeyAndChain("EC_RSA") == false) {
0N/A return false;
0N/A }
0N/A setupStaticECDHKeys();
0N/A break;
0N/A case K_ECDH_ECDSA:
0N/A // need EC cert signed using EC
0N/A if (setupPrivateKeyAndChain("EC_EC") == false) {
0N/A return false;
0N/A }
0N/A setupStaticECDHKeys();
0N/A break;
0N/A case K_KRB5:
0N/A case K_KRB5_EXPORT:
0N/A // need Kerberos Key
0N/A if (!setupKerberosKeys()) {
0N/A return false;
0N/A }
0N/A break;
0N/A case K_DH_ANON:
0N/A // no certs needed for anonymous
0N/A setupEphemeralDHKeys(suite.exportable);
0N/A break;
0N/A case K_ECDH_ANON:
0N/A // no certs needed for anonymous
0N/A if (setupEphemeralECDHKeys() == false) {
0N/A return false;
0N/A }
0N/A break;
0N/A default:
0N/A // internal error, unknown key exchange
0N/A throw new RuntimeException("Unrecognized cipherSuite: " + suite);
0N/A }
0N/A setCipherSuite(suite);
3002N/A
3002N/A // set the peer implicit supported signature algorithms
3002N/A if (protocolVersion.v >= ProtocolVersion.TLS12.v) {
3002N/A if (peerSupportedSignAlgs == null) {
3002N/A setPeerSupportedSignAlgs(supportedSignAlgs);
3002N/A // we had alreay update the session
3002N/A }
3002N/A }
0N/A return true;
0N/A }
0N/A
0N/A /*
0N/A * Get some "ephemeral" RSA keys for this context. This means
0N/A * generating them if it's not already been done.
0N/A *
0N/A * Note that we currently do not implement any ciphersuites that use
0N/A * strong ephemeral RSA. (We do not support the EXPORT1024 ciphersuites
0N/A * and standard RSA ciphersuites prohibit ephemeral mode for some reason)
0N/A * This means that export is always true and 512 bit keys are generated.
0N/A */
0N/A private boolean setupEphemeralRSAKeys(boolean export) {
0N/A KeyPair kp = sslContext.getEphemeralKeyManager().
0N/A getRSAKeyPair(export, sslContext.getSecureRandom());
0N/A if (kp == null) {
0N/A return false;
0N/A } else {
0N/A tempPublicKey = kp.getPublic();
0N/A tempPrivateKey = kp.getPrivate();
0N/A return true;
0N/A }
0N/A }
0N/A
0N/A /*
0N/A * Acquire some "ephemeral" Diffie-Hellman keys for this handshake.
0N/A * We don't reuse these, for improved forward secrecy.
0N/A */
0N/A private void setupEphemeralDHKeys(boolean export) {
0N/A /*
0N/A * Diffie-Hellman keys ... we use 768 bit private keys due
0N/A * to the "use twice as many key bits as bits you want secret"
0N/A * rule of thumb, assuming we want the same size premaster
0N/A * secret with Diffie-Hellman and RSA key exchanges. Except
0N/A * that exportable ciphers max out at 512 bits modulus values.
0N/A */
0N/A dh = new DHCrypt((export ? 512 : 768), sslContext.getSecureRandom());
0N/A }
0N/A
0N/A // Setup the ephemeral ECDH parameters.
0N/A // If we cannot continue because we do not support any of the curves that
0N/A // the client requested, return false. Otherwise (all is well), return true.
0N/A private boolean setupEphemeralECDHKeys() {
0N/A int index = -1;
0N/A if (supportedCurves != null) {
0N/A // if the client sent the supported curves extension, pick the
0N/A // first one that we support;
0N/A for (int curveId : supportedCurves.curveIds()) {
0N/A if (SupportedEllipticCurvesExtension.isSupported(curveId)) {
0N/A index = curveId;
0N/A break;
0N/A }
0N/A }
0N/A if (index < 0) {
0N/A // no match found, cannot use this ciphersuite
0N/A return false;
0N/A }
0N/A } else {
0N/A // pick our preference
0N/A index = SupportedEllipticCurvesExtension.DEFAULT.curveIds()[0];
0N/A }
0N/A String oid = SupportedEllipticCurvesExtension.getCurveOid(index);
0N/A ecdh = new ECDHCrypt(oid, sslContext.getSecureRandom());
0N/A return true;
0N/A }
0N/A
0N/A private void setupStaticECDHKeys() {
0N/A // don't need to check whether the curve is supported, already done
0N/A // in setupPrivateKeyAndChain().
0N/A ecdh = new ECDHCrypt(privateKey, certs[0].getPublicKey());
0N/A }
0N/A
0N/A /**
0N/A * Retrieve the server key and certificate for the specified algorithm
0N/A * from the KeyManager and set the instance variables.
0N/A *
0N/A * @return true if successful, false if not available or invalid
0N/A */
0N/A private boolean setupPrivateKeyAndChain(String algorithm) {
0N/A X509ExtendedKeyManager km = sslContext.getX509KeyManager();
0N/A String alias;
0N/A if (conn != null) {
0N/A alias = km.chooseServerAlias(algorithm, null, conn);
0N/A } else {
0N/A alias = km.chooseEngineServerAlias(algorithm, null, engine);
0N/A }
0N/A if (alias == null) {
0N/A return false;
0N/A }
0N/A PrivateKey tempPrivateKey = km.getPrivateKey(alias);
0N/A if (tempPrivateKey == null) {
0N/A return false;
0N/A }
0N/A X509Certificate[] tempCerts = km.getCertificateChain(alias);
0N/A if ((tempCerts == null) || (tempCerts.length == 0)) {
0N/A return false;
0N/A }
0N/A String keyAlgorithm = algorithm.split("_")[0];
0N/A PublicKey publicKey = tempCerts[0].getPublicKey();
0N/A if ((tempPrivateKey.getAlgorithm().equals(keyAlgorithm) == false)
0N/A || (publicKey.getAlgorithm().equals(keyAlgorithm) == false)) {
0N/A return false;
0N/A }
0N/A // For ECC certs, check whether we support the EC domain parameters.
0N/A // If the client sent a SupportedEllipticCurves ClientHello extension,
0N/A // check against that too.
0N/A if (keyAlgorithm.equals("EC")) {
0N/A if (publicKey instanceof ECPublicKey == false) {
0N/A return false;
0N/A }
0N/A ECParameterSpec params = ((ECPublicKey)publicKey).getParams();
0N/A int index = SupportedEllipticCurvesExtension.getCurveIndex(params);
0N/A if (SupportedEllipticCurvesExtension.isSupported(index) == false) {
0N/A return false;
0N/A }
0N/A if ((supportedCurves != null) && !supportedCurves.contains(index)) {
0N/A return false;
0N/A }
0N/A }
0N/A this.privateKey = tempPrivateKey;
0N/A this.certs = tempCerts;
0N/A return true;
0N/A }
0N/A
0N/A /**
0N/A * Retrieve the Kerberos key for the specified server principal
0N/A * from the JAAS configuration file.
0N/A *
0N/A * @return true if successful, false if not available or invalid
0N/A */
0N/A private boolean setupKerberosKeys() {
0N/A if (kerberosKeys != null) {
0N/A return true;
0N/A }
0N/A try {
0N/A final AccessControlContext acc = getAccSE();
0N/A kerberosKeys = AccessController.doPrivileged(
1870N/A // Eliminate dependency on KerberosKey
1870N/A new PrivilegedExceptionAction<SecretKey[]>() {
1870N/A public SecretKey[] run() throws Exception {
0N/A // get kerberos key for the default principal
1870N/A return Krb5Helper.getServerKeys(acc);
0N/A }});
0N/A
0N/A // check permission to access and use the secret key of the
0N/A // Kerberized "host" service
4102N/A if (kerberosKeys != null && kerberosKeys.length > 0) {
0N/A if (debug != null && Debug.isOn("handshake")) {
4102N/A for (SecretKey k: kerberosKeys) {
4102N/A System.out.println("Using Kerberos key: " +
4102N/A k);
4102N/A }
0N/A }
0N/A
0N/A String serverPrincipal =
1870N/A Krb5Helper.getServerPrincipalName(kerberosKeys[0]);
0N/A SecurityManager sm = System.getSecurityManager();
0N/A try {
0N/A if (sm != null) {
1870N/A // Eliminate dependency on ServicePermission
1870N/A sm.checkPermission(Krb5Helper.getServicePermission(
1870N/A serverPrincipal, "accept"), acc);
0N/A }
0N/A } catch (SecurityException se) {
0N/A kerberosKeys = null;
0N/A // %%% destroy keys? or will that affect Subject?
0N/A if (debug != null && Debug.isOn("handshake"))
0N/A System.out.println("Permission to access Kerberos"
0N/A + " secret key denied");
0N/A return false;
0N/A }
0N/A }
5070N/A return (kerberosKeys != null && kerberosKeys.length > 0);
0N/A } catch (PrivilegedActionException e) {
0N/A // Likely exception here is LoginExceptin
0N/A if (debug != null && Debug.isOn("handshake")) {
0N/A System.out.println("Attempt to obtain Kerberos key failed: "
0N/A + e.toString());
0N/A }
0N/A return false;
0N/A }
0N/A }
0N/A
0N/A /*
0N/A * For Kerberos ciphers, the premaster secret is encrypted using
0N/A * the session key. See RFC 2712.
0N/A */
0N/A private SecretKey clientKeyExchange(KerberosClientKeyExchange mesg)
0N/A throws IOException {
0N/A
0N/A if (debug != null && Debug.isOn("handshake")) {
0N/A mesg.print(System.out);
0N/A }
0N/A
0N/A // Record the principals involved in exchange
0N/A session.setPeerPrincipal(mesg.getPeerPrincipal());
0N/A session.setLocalPrincipal(mesg.getLocalPrincipal());
0N/A
1870N/A byte[] b = mesg.getUnencryptedPreMasterSecret();
0N/A return new SecretKeySpec(b, "TlsPremasterSecret");
0N/A }
0N/A
0N/A /*
0N/A * Diffie Hellman key exchange is used when the server presented
0N/A * D-H parameters in its certificate (signed using RSA or DSS/DSA),
0N/A * or else the server presented no certificate but sent D-H params
0N/A * in a ServerKeyExchange message. Use of D-H is specified by the
0N/A * cipher suite chosen.
0N/A *
0N/A * The message optionally contains the client's D-H public key (if
0N/A * it wasn't not sent in a client certificate). As always with D-H,
0N/A * if a client and a server have each other's D-H public keys and
0N/A * they use common algorithm parameters, they have a shared key
0N/A * that's derived via the D-H calculation. That key becomes the
0N/A * pre-master secret.
0N/A */
0N/A private SecretKey clientKeyExchange(DHClientKeyExchange mesg)
0N/A throws IOException {
0N/A
0N/A if (debug != null && Debug.isOn("handshake")) {
0N/A mesg.print(System.out);
0N/A }
5690N/A return dh.getAgreedSecret(mesg.getClientPublicKey(), false);
0N/A }
0N/A
0N/A private SecretKey clientKeyExchange(ECDHClientKeyExchange mesg)
0N/A throws IOException {
0N/A
0N/A if (debug != null && Debug.isOn("handshake")) {
0N/A mesg.print(System.out);
0N/A }
0N/A return ecdh.getAgreedSecret(mesg.getEncodedPoint());
0N/A }
0N/A
0N/A /*
0N/A * Client wrote a message to verify the certificate it sent earlier.
0N/A *
0N/A * Note that this certificate isn't involved in key exchange. Client
0N/A * authentication messages are included in the checksums used to
0N/A * validate the handshake (e.g. Finished messages). Other than that,
0N/A * the _exact_ identity of the client is less fundamental to protocol
0N/A * security than its role in selecting keys via the pre-master secret.
0N/A */
0N/A private void clientCertificateVerify(CertificateVerify mesg)
0N/A throws IOException {
0N/A
0N/A if (debug != null && Debug.isOn("handshake")) {
0N/A mesg.print(System.out);
0N/A }
0N/A
3002N/A if (protocolVersion.v >= ProtocolVersion.TLS12.v) {
3002N/A SignatureAndHashAlgorithm signAlg =
3002N/A mesg.getPreferableSignatureAlgorithm();
3002N/A if (signAlg == null) {
3002N/A throw new SSLHandshakeException(
3002N/A "Illegal CertificateVerify message");
3002N/A }
3002N/A
3002N/A String hashAlg =
3002N/A SignatureAndHashAlgorithm.getHashAlgorithmName(signAlg);
3002N/A if (hashAlg == null || hashAlg.length() == 0) {
3002N/A throw new SSLHandshakeException(
3002N/A "No supported hash algorithm");
3002N/A }
3002N/A
3002N/A handshakeHash.setCertificateVerifyAlg(hashAlg);
3002N/A }
3002N/A
0N/A try {
0N/A PublicKey publicKey =
0N/A session.getPeerCertificates()[0].getPublicKey();
0N/A
0N/A boolean valid = mesg.verify(protocolVersion, handshakeHash,
0N/A publicKey, session.getMasterSecret());
0N/A if (valid == false) {
0N/A fatalSE(Alerts.alert_bad_certificate,
0N/A "certificate verify message signature error");
0N/A }
0N/A } catch (GeneralSecurityException e) {
0N/A fatalSE(Alerts.alert_bad_certificate,
0N/A "certificate verify format error", e);
0N/A }
0N/A
0N/A // reset the flag for clientCertificateVerify message
0N/A needClientVerify = false;
0N/A }
0N/A
0N/A
0N/A /*
0N/A * Client writes "finished" at the end of its handshake, after cipher
0N/A * spec is changed. We verify it and then send ours.
0N/A *
0N/A * When we're resuming a session, we'll have already sent our own
0N/A * Finished message so just the verification is needed.
0N/A */
0N/A private void clientFinished(Finished mesg) throws IOException {
0N/A if (debug != null && Debug.isOn("handshake")) {
0N/A mesg.print(System.out);
0N/A }
0N/A
0N/A /*
0N/A * Verify if client did send the certificate when client
0N/A * authentication was required, otherwise server should not proceed
0N/A */
0N/A if (doClientAuth == SSLEngineImpl.clauth_required) {
0N/A // get X500Principal of the end-entity certificate for X509-based
0N/A // ciphersuites, or Kerberos principal for Kerberos ciphersuites
0N/A session.getPeerPrincipal();
0N/A }
0N/A
0N/A /*
0N/A * Verify if client did send clientCertificateVerify message following
0N/A * the client Certificate, otherwise server should not proceed
0N/A */
0N/A if (needClientVerify) {
0N/A fatalSE(Alerts.alert_handshake_failure,
0N/A "client did not send certificate verify message");
0N/A }
0N/A
0N/A /*
0N/A * Verify the client's message with the "before" digest of messages,
0N/A * and forget about continuing to use that digest.
0N/A */
3002N/A boolean verified = mesg.verify(handshakeHash, Finished.CLIENT,
3002N/A session.getMasterSecret());
0N/A
0N/A if (!verified) {
0N/A fatalSE(Alerts.alert_handshake_failure,
0N/A "client 'finished' message doesn't verify");
0N/A // NOTREACHED
0N/A }
0N/A
0N/A /*
2890N/A * save client verify data for secure renegotiation
2890N/A */
2890N/A if (secureRenegotiation) {
2890N/A clientVerifyData = mesg.getVerifyData();
2890N/A }
2890N/A
2890N/A /*
0N/A * OK, it verified. If we're doing the full handshake, add that
0N/A * "Finished" message to the hash of handshake messages, then send
0N/A * the change_cipher_spec and Finished message.
0N/A */
0N/A if (!resumingSession) {
0N/A input.digestNow();
0N/A sendChangeCipherAndFinish(true);
0N/A }
0N/A
0N/A /*
0N/A * Update the session cache only after the handshake completed, else
0N/A * we're open to an attack against a partially completed handshake.
0N/A */
0N/A session.setLastAccessedTime(System.currentTimeMillis());
0N/A if (!resumingSession && session.isRejoinable()) {
0N/A ((SSLSessionContextImpl)sslContext.engineGetServerSessionContext())
0N/A .put(session);
0N/A if (debug != null && Debug.isOn("session")) {
0N/A System.out.println(
0N/A "%% Cached server session: " + session);
0N/A }
0N/A } else if (!resumingSession &&
0N/A debug != null && Debug.isOn("session")) {
0N/A System.out.println(
0N/A "%% Didn't cache non-resumable server session: "
0N/A + session);
0N/A }
0N/A }
0N/A
0N/A /*
0N/A * Compute finished message with the "server" digest (and then forget
0N/A * about that digest, it can't be used again).
0N/A */
0N/A private void sendChangeCipherAndFinish(boolean finishedTag)
0N/A throws IOException {
0N/A
0N/A output.flush();
0N/A
0N/A Finished mesg = new Finished(protocolVersion, handshakeHash,
3002N/A Finished.SERVER, session.getMasterSecret(), cipherSuite);
0N/A
0N/A /*
0N/A * Send the change_cipher_spec record; then our Finished handshake
0N/A * message will be the last handshake message. Flush, and now we
0N/A * are ready for application data!!
0N/A */
0N/A sendChangeCipherSpec(mesg, finishedTag);
0N/A
0N/A /*
2890N/A * save server verify data for secure renegotiation
2890N/A */
2890N/A if (secureRenegotiation) {
2890N/A serverVerifyData = mesg.getVerifyData();
2890N/A }
2890N/A
2890N/A /*
0N/A * Update state machine so client MUST send 'finished' next
0N/A * The update should only take place if it is not in the fast
0N/A * handshake mode since the server has to wait for a finished
0N/A * message from the client.
0N/A */
0N/A if (finishedTag) {
0N/A state = HandshakeMessage.ht_finished;
0N/A }
0N/A }
0N/A
0N/A
0N/A /*
0N/A * Returns a HelloRequest message to kickstart renegotiations
0N/A */
0N/A HandshakeMessage getKickstartMessage() {
0N/A return new HelloRequest();
0N/A }
0N/A
0N/A
0N/A /*
0N/A * Fault detected during handshake.
0N/A */
0N/A void handshakeAlert(byte description) throws SSLProtocolException {
0N/A
0N/A String message = Alerts.alertDescription(description);
0N/A
0N/A if (debug != null && Debug.isOn("handshake")) {
0N/A System.out.println("SSL -- handshake alert: "
0N/A + message);
0N/A }
0N/A
0N/A /*
0N/A * It's ok to get a no_certificate alert from a client of which
0N/A * we *requested* authentication information.
0N/A * However, if we *required* it, then this is not acceptable.
0N/A *
0N/A * Anyone calling getPeerCertificates() on the
0N/A * session will get an SSLPeerUnverifiedException.
0N/A */
0N/A if ((description == Alerts.alert_no_certificate) &&
0N/A (doClientAuth == SSLEngineImpl.clauth_requested)) {
0N/A return;
0N/A }
0N/A
0N/A throw new SSLProtocolException("handshake alert: " + message);
0N/A }
0N/A
0N/A /*
0N/A * RSA key exchange is normally used. The client encrypts a "pre-master
0N/A * secret" with the server's public key, from the Certificate (or else
0N/A * ServerKeyExchange) message that was sent to it by the server. That's
0N/A * decrypted using the private key before we get here.
0N/A */
3002N/A private SecretKey clientKeyExchange(RSAClientKeyExchange mesg)
3002N/A throws IOException {
0N/A
0N/A if (debug != null && Debug.isOn("handshake")) {
0N/A mesg.print(System.out);
0N/A }
0N/A return mesg.preMaster;
0N/A }
0N/A
0N/A /*
0N/A * Verify the certificate sent by the client. We'll only get one if we
0N/A * sent a CertificateRequest to request client authentication. If we
0N/A * are in TLS mode, the client may send a message with no certificates
0N/A * to indicate it does not have an appropriate chain. (In SSLv3 mode,
0N/A * it would send a no certificate alert).
0N/A */
0N/A private void clientCertificate(CertificateMsg mesg) throws IOException {
0N/A if (debug != null && Debug.isOn("handshake")) {
0N/A mesg.print(System.out);
0N/A }
0N/A
0N/A X509Certificate[] peerCerts = mesg.getCertificateChain();
0N/A
0N/A if (peerCerts.length == 0) {
0N/A /*
0N/A * If the client authentication is only *REQUESTED* (e.g.
0N/A * not *REQUIRED*, this is an acceptable condition.)
0N/A */
0N/A if (doClientAuth == SSLEngineImpl.clauth_requested) {
3002N/A // Smart (aka stupid) to forecast that no CertificateVerify
3002N/A // message will be received.
3002N/A if (protocolVersion.v >= ProtocolVersion.TLS12.v) {
3002N/A handshakeHash.setCertificateVerifyAlg(null);
3002N/A }
0N/A return;
0N/A } else {
0N/A fatalSE(Alerts.alert_bad_certificate,
0N/A "null cert chain");
0N/A }
0N/A }
0N/A
0N/A // ask the trust manager to verify the chain
0N/A X509TrustManager tm = sslContext.getX509TrustManager();
0N/A
0N/A try {
0N/A // find out the types of client authentication used
0N/A PublicKey key = peerCerts[0].getPublicKey();
0N/A String keyAlgorithm = key.getAlgorithm();
0N/A String authType;
0N/A if (keyAlgorithm.equals("RSA")) {
0N/A authType = "RSA";
0N/A } else if (keyAlgorithm.equals("DSA")) {
0N/A authType = "DSA";
0N/A } else if (keyAlgorithm.equals("EC")) {
0N/A authType = "EC";
0N/A } else {
0N/A // unknown public key type
0N/A authType = "UNKNOWN";
0N/A }
0N/A
0N/A if (tm instanceof X509ExtendedTrustManager) {
3002N/A if (conn != null) {
3002N/A ((X509ExtendedTrustManager)tm).checkClientTrusted(
3002N/A peerCerts.clone(),
0N/A authType,
3002N/A conn);
3002N/A } else {
3002N/A ((X509ExtendedTrustManager)tm).checkClientTrusted(
3002N/A peerCerts.clone(),
3002N/A authType,
3002N/A engine);
3002N/A }
0N/A } else {
3002N/A // Unlikely to happen, because we have wrapped the old
3002N/A // X509TrustManager with the new X509ExtendedTrustManager.
3002N/A throw new CertificateException(
3002N/A "Improper X509TrustManager implementation");
0N/A }
0N/A } catch (CertificateException e) {
0N/A // This will throw an exception, so include the original error.
0N/A fatalSE(Alerts.alert_certificate_unknown, e);
0N/A }
0N/A // set the flag for clientCertificateVerify message
0N/A needClientVerify = true;
0N/A
0N/A session.setPeerCertificates(peerCerts);
0N/A }
0N/A}