Search in sources :

Example 1 with SignatureAndHashAlgorithm

use of sun.security.ssl.SignatureAndHashAlgorithm in project jdk8u_jdk by JetBrains.

the class ServerHandshaker method clientHello.

/*
     * 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);
    }
    // This will not have any impact on server initiated renegotiation.
    if (rejectClientInitiatedRenego && !isInitialHandshake && state != HandshakeMessage.ht_hello_request) {
        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");
    }
    // handshake is insecure.
    if (!renegotiationIndicated || !secureRenegotiation) {
        if (isInitialHandshake) {
            if (!allowLegacyHelloMessages) {
                // abort the handshake with a fatal handshake_failure alert
                fatalSE(Alerts.alert_handshake_failure, "Failed to negotiate the use of secure renegotiation");
            }
            // continue with legacy ClientHello
            if (debug != null && Debug.isOn("handshake")) {
                System.out.println("Warning: No renegotiation " + "indication in ClientHello, allow legacy ClientHello");
            }
        } else if (!allowUnsafeRenegotiation) {
            // abort the handshake
            if (activeProtocolVersion.v >= ProtocolVersion.TLS10.v) {
                // respond with a no_renegotiation warning
                warningSE(Alerts.alert_no_renegotiation);
                // invalidate the handshake so that the caller can
                // dispose this object.
                invalidated = true;
                // 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 {
            // continue with unsafe renegotiation.
            if (debug != null && Debug.isOn("handshake")) {
                System.out.println("Warning: continue with insecure renegotiation");
            }
        }
    }
    /*
         * Always make sure this entire record has been digested before we
         * start emitting output, to ensure correct digesting order.
         */
    input.digestNow();
    /*
         * FIRST, construct the ServerHello using the options and priorities
         * from the ClientHello.  Update the (pending) cipher spec as we do
         * so, and save the client's version to protect against rollback
         * attacks.
         *
         * There are a bunch of minor tasks here, and one major one: deciding
         * if the short or the full handshake sequence will be used.
         */
    ServerHello m1 = new ServerHello();
    clientRequestedVersion = mesg.protocolVersion;
    // select a proper protocol version.
    ProtocolVersion selectedVersion = selectProtocolVersion(clientRequestedVersion);
    if (selectedVersion == null || selectedVersion.v == ProtocolVersion.SSL20Hello.v) {
        fatalSE(Alerts.alert_handshake_failure, "Client requested protocol " + clientRequestedVersion + " not enabled or not supported");
    }
    handshakeHash.protocolDetermined(selectedVersion);
    setVersion(selectedVersion);
    m1.protocolVersion = protocolVersion;
    //
    // random ... save client and server values for later use
    // in computing the master secret (from pre-master secret)
    // and thence the other crypto keys.
    //
    // NOTE:  this use of three inputs to generating _each_ set
    // of ciphers slows things down, but it does increase the
    // security since each connection in the session can hold
    // its own authenticated (and strong) keys.  One could make
    // creation of a session a rare thing...
    //
    clnt_random = mesg.clnt_random;
    svr_random = new RandomCookie(sslContext.getSecureRandom());
    m1.svr_random = svr_random;
    // forget about the current session
    session = null;
    //
    if (mesg.sessionId.length() != 0) {
        // client is trying to resume a session, let's see...
        SSLSessionImpl previous = ((SSLSessionContextImpl) sslContext.engineGetServerSessionContext()).get(mesg.sessionId.getId());
        //
        if (previous != null) {
            resumingSession = previous.isRejoinable();
            if (resumingSession) {
                ProtocolVersion oldVersion = previous.getProtocolVersion();
                // cannot resume session with different version
                if (oldVersion != protocolVersion) {
                    resumingSession = false;
                }
            }
            // cannot resume session with different server name indication
            if (resumingSession) {
                List<SNIServerName> 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 == SSLEngineImpl.clauth_required)) {
                try {
                    previous.getPeerPrincipal();
                } catch (SSLPeerUnverifiedException e) {
                    resumingSession = false;
                }
            }
            // validate subject identity
            if (resumingSession) {
                CipherSuite suite = previous.getSuite();
                if (suite.keyExchange == K_KRB5 || suite.keyExchange == K_KRB5_EXPORT) {
                    Principal localPrincipal = previous.getLocalPrincipal();
                    Subject subject = null;
                    try {
                        subject = AccessController.doPrivileged(new PrivilegedExceptionAction<Subject>() {

                            @Override
                            public Subject run() throws Exception {
                                return Krb5Helper.getServerSubject(getAccSE());
                            }
                        });
                    } catch (PrivilegedActionException e) {
                        subject = null;
                        if (debug != null && Debug.isOn("session")) {
                            System.out.println("Attempt to obtain" + " subject failed!");
                        }
                    }
                    if (subject != null) {
                        // Eliminate dependency on KerberosPrincipal
                        if (Krb5Helper.isRelated(subject, 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");
                        }
                    } else {
                        resumingSession = false;
                        if (debug != null && Debug.isOn("session"))
                            System.out.println("Kerberos credentials are" + " not present in the current Subject;" + " check if " + " javax.security.auth.useSubjectAsCreds" + " system property has been set to false");
                    }
                }
            }
            if (resumingSession) {
                CipherSuite suite = previous.getSuite();
                // 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);
                }
            }
        }
    }
    //
    if (session == null) {
        if (!enableNewSession) {
            throw new SSLException("Client did not resume a session");
        }
        requestedCurves = (SupportedEllipticCurvesExtension) mesg.extensions.get(ExtensionType.EXT_ELLIPTIC_CURVES);
        // for full handshakes and TLS 1.2 or later.
        if (protocolVersion.v >= ProtocolVersion.TLS12.v) {
            SignatureAlgorithmsExtension signAlgs = (SignatureAlgorithmsExtension) mesg.extensions.get(ExtensionType.EXT_SIGNATURE_ALGORITHMS);
            if (signAlgs != null) {
                Collection<SignatureAndHashAlgorithm> peerSignAlgs = signAlgs.getSignAlgorithms();
                if (peerSignAlgs == null || peerSignAlgs.isEmpty()) {
                    throw new SSLHandshakeException("No peer supported signature algorithms");
                }
                Collection<SignatureAndHashAlgorithm> 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());
        if (protocolVersion.v >= ProtocolVersion.TLS12.v) {
            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<SNIServerName> clientHelloSNI = Collections.<SNIServerName>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);
    } else {
        // set the handshake session
        setHandshakeSessionSE(session);
    }
    if (protocolVersion.v >= ProtocolVersion.TLS12.v) {
        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) {
        // server_name extension in the server hello.
        if (!resumingSession) {
            ServerNameExtension serverHelloSNI = new ServerNameExtension();
            m1.extensions.add(serverHelloSNI);
        }
    }
    if (debug != null && Debug.isOn("handshake")) {
        m1.print(System.out);
        System.out.println("Cipher suite:  " + session.getSuite());
    }
    m1.write(output);
    //
    if (resumingSession) {
        calculateConnectionKeys(session.getMasterSecret());
        sendChangeCipherAndFinish(false);
        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 (keyExchange == K_KRB5 || keyExchange == K_KRB5_EXPORT) {
    // Server certificates are omitted for Kerberos ciphers
    } 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);
    // 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");
        }
    }
    /*
         * 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:
        case K_KRB5:
        case K_KRB5_EXPORT:
            // no server key exchange for RSA or KRB5 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) {
                    throwSSLException("Error generating RSA server key exchange", e);
                    // make compiler happy
                    m3 = null;
                }
            } 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) {
                throwSSLException("Error generating DH server key exchange", e);
                // make compiler happy
                m3 = null;
            }
            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) {
                throwSSLException("Error generating ECDH server key exchange", e);
                // make compiler happy
                m3 = null;
            }
            break;
        case K_ECDH_RSA:
        case K_ECDH_ECDSA:
            // ServerKeyExchange not used for fixed ECDH
            m3 = null;
            break;
        default:
            throw new RuntimeException("internal error: " + keyExchange);
    }
    if (m3 != null) {
        if (debug != null && Debug.isOn("handshake")) {
            m3.print(System.out);
        }
        m3.write(output);
    }
    // CertificateRequest is omitted for Kerberos ciphers
    if (doClientAuth != SSLEngineImpl.clauth_none && keyExchange != K_DH_ANON && keyExchange != K_ECDH_ANON && keyExchange != K_KRB5 && keyExchange != K_KRB5_EXPORT) {
        CertificateRequest m4;
        X509Certificate[] caCerts;
        Collection<SignatureAndHashAlgorithm> localSignAlgs = null;
        if (protocolVersion.v >= ProtocolVersion.TLS12.v) {
            // 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<String> 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);
    }
    /*
         * FIFTH, say ServerHelloDone.
         */
    ServerHelloDone m5 = new ServerHelloDone();
    if (debug != null && Debug.isOn("handshake")) {
        m5.print(System.out);
    }
    m5.write(output);
    /*
         * 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();
}
Also used : CipherSuite(sun.security.ssl.CipherSuite) SignatureAndHashAlgorithm(sun.security.ssl.SignatureAndHashAlgorithm) Subject(javax.security.auth.Subject)

Example 2 with SignatureAndHashAlgorithm

use of sun.security.ssl.SignatureAndHashAlgorithm in project jdk8u_jdk by JetBrains.

the class ServerHandshaker method clientCertificateVerify.

/*
     * 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.v >= ProtocolVersion.TLS12.v) {
        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;
}
Also used : SignatureAndHashAlgorithm(sun.security.ssl.SignatureAndHashAlgorithm)

Example 3 with SignatureAndHashAlgorithm

use of sun.security.ssl.SignatureAndHashAlgorithm in project jdk8u_jdk by JetBrains.

the class ServerHandshaker method trySetCipherSuite.

/**
     * 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.v >= suite.obsoleted) {
        return false;
    }
    // must not negotiate unsupported cipher suites.
    if (protocolVersion.v < suite.supported) {
        return false;
    }
    KeyExchange keyExchange = suite.keyExchange;
    // null out any existing references
    privateKey = null;
    certs = null;
    dh = null;
    tempPrivateKey = null;
    tempPublicKey = null;
    Collection<SignatureAndHashAlgorithm> supportedSignAlgs = null;
    if (protocolVersion.v >= ProtocolVersion.TLS12.v) {
        if (peerSupportedSignAlgs != null) {
            supportedSignAlgs = peerSupportedSignAlgs;
        } else {
            SignatureAndHashAlgorithm algorithm = null;
            // we may optimize the performance
            switch(keyExchange) {
                // 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;
                // sent the value {sha1,dsa}.
                case K_DHE_DSS:
                case K_DH_DSS:
                    algorithm = SignatureAndHashAlgorithm.valueOf(HashAlgorithm.SHA1.value, SignatureAlgorithm.DSA.value, 0);
                    break;
                // 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:
            }
            if (algorithm == null) {
                supportedSignAlgs = Collections.<SignatureAndHashAlgorithm>emptySet();
            } else {
                supportedSignAlgs = new ArrayList<SignatureAndHashAlgorithm>(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);
        }
    }
    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:
            // need RSA certs for authentication
            if (setupPrivateKeyAndChain("RSA") == false) {
                return false;
            }
            // get preferable peer signature algorithm for server key exchange
            if (protocolVersion.v >= ProtocolVersion.TLS12.v) {
                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(suite.exportable, privateKey);
            break;
        case K_ECDHE_RSA:
            // need RSA certs for authentication
            if (setupPrivateKeyAndChain("RSA") == false) {
                return false;
            }
            // get preferable peer signature algorithm for server key exchange
            if (protocolVersion.v >= ProtocolVersion.TLS12.v) {
                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;
                }
            }
            if (setupEphemeralECDHKeys() == false) {
                return false;
            }
            break;
        case K_DHE_DSS:
            // get preferable peer signature algorithm for server key exchange
            if (protocolVersion.v >= ProtocolVersion.TLS12.v) {
                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(suite.exportable, privateKey);
            break;
        case K_ECDHE_ECDSA:
            // get preferable peer signature algorithm for server key exchange
            if (protocolVersion.v >= ProtocolVersion.TLS12.v) {
                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;
            }
            if (setupEphemeralECDHKeys() == false) {
                return false;
            }
            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_KRB5:
        case K_KRB5_EXPORT:
            // need Kerberos Key
            if (!setupKerberosKeys()) {
                return false;
            }
            break;
        case K_DH_ANON:
            // no certs needed for anonymous
            setupEphemeralDHKeys(suite.exportable, null);
            break;
        case K_ECDH_ANON:
            // no certs needed for anonymous
            if (setupEphemeralECDHKeys() == false) {
                return false;
            }
            break;
        default:
            // internal error, unknown key exchange
            throw new RuntimeException("Unrecognized cipherSuite: " + suite);
    }
    setCipherSuite(suite);
    // set the peer implicit supported signature algorithms
    if (protocolVersion.v >= ProtocolVersion.TLS12.v) {
        if (peerSupportedSignAlgs == null) {
            setPeerSupportedSignAlgs(supportedSignAlgs);
        // we had alreay update the session
        }
    }
    return true;
}
Also used : KeyExchange(sun.security.ssl.CipherSuite.KeyExchange) SignatureAndHashAlgorithm(sun.security.ssl.SignatureAndHashAlgorithm)

Example 4 with SignatureAndHashAlgorithm

use of sun.security.ssl.SignatureAndHashAlgorithm in project Bytecoder by mirkosertic.

the class ServerHandshaker method clientCertificateVerify.

/*
     * 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;
}
Also used : SignatureAndHashAlgorithm(sun.security.ssl.SignatureAndHashAlgorithm)

Example 5 with SignatureAndHashAlgorithm

use of sun.security.ssl.SignatureAndHashAlgorithm in project Bytecoder by mirkosertic.

the class ServerHandshaker method clientHello.

/*
     * 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);
    }
    // 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");
    }
    // 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;
                // 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 {
            // 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 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<String> 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.
    // forget about the current session
    session = null;
    // 
    if (mesg.sessionId.length() != 0) {
        // client is trying to resume a session, let's see...
        SSLSessionImpl previous = ((SSLSessionContextImpl) sslContext.engineGetServerSessionContext()).get(mesg.sessionId.getId());
        // 
        if (previous != null) {
            resumingSession = previous.isRejoinable();
            if (resumingSession) {
                ProtocolVersion oldVersion = previous.getProtocolVersion();
                // cannot resume session with different version
                if (oldVersion != protocolVersion) {
                    resumingSession = false;
                }
            }
            // cannot resume session with different server name indication
            if (resumingSession) {
                List<SNIServerName> 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();
                // 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);
                }
            }
        }
    }
    // 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 (session == null) {
        if (!enableNewSession) {
            throw new SSLException("Client did not resume a session");
        }
        requestedGroups = (SupportedGroupsExtension) mesg.extensions.get(ExtensionType.EXT_SUPPORTED_GROUPS);
        // 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<SignatureAndHashAlgorithm> peerSignAlgs = signAlgs.getSignAlgorithms();
                if (peerSignAlgs == null || peerSignAlgs.isEmpty()) {
                    throw new SSLHandshakeException("No peer supported signature algorithms");
                }
                Collection<SignatureAndHashAlgorithm> 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());
        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<SNIServerName> clientHelloSNI = Collections.<SNIServerName>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);
        // 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) {
        // 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);
    }
    StaplingParameters staplingParams = processStapling(mesg);
    if (staplingParams != null) {
        // 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<String> peerAPs = clientHelloALPN.getPeerAPs();
        // check for a callback function
        if (hasAPCallback) {
            if (conn != null) {
                applicationProtocol = appProtocolSelectorSSLSocket.apply(conn, peerAPs);
            } else {
                applicationProtocol = appProtocolSelectorSSLEngine.apply(engine, peerAPs);
            }
        }
        // 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 (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) {
                    // make compiler happy
                    m3 = null;
                    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) {
                // make compiler happy
                m3 = null;
                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) {
                // make compiler happy
                m3 = null;
                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);
    }
    // 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<SignatureAndHashAlgorithm> 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<String> 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();
}
Also used : CipherSuite(sun.security.ssl.CipherSuite) SignatureAndHashAlgorithm(sun.security.ssl.SignatureAndHashAlgorithm)

Aggregations

SignatureAndHashAlgorithm (sun.security.ssl.SignatureAndHashAlgorithm)6 CipherSuite (sun.security.ssl.CipherSuite)2 KeyExchange (sun.security.ssl.CipherSuite.KeyExchange)2 Subject (javax.security.auth.Subject)1