1341 lines · 53.3 KB · Java
RawDownload
         */        sendChangeCipherAndFinish(false);    }      /*     * "Finished" is the last handshake message sent.  If we got this     * far, the MAC has been validated post-decryption.  We validate     * the two hashes here as an additional sanity check, protecting     * the handshake against various active attacks.     */    private void serverFinished(Finished mesg) throws IOException {        if (debug != null && Debug.isOn("handshake")) {            mesg.print(System.out);        }         boolean verified = mesg.verify(handshakeHash, Finished.SERVER,            session.getMasterSecret());         if (!verified) {            fatalSE(Alerts.alert_illegal_parameter,                       "server 'finished' message doesn't verify");            // NOTREACHED        }         /*         * save server verify data for secure renegotiation         */        if (secureRenegotiation) {            serverVerifyData = mesg.getVerifyData();        }         /*         * OK, it verified.  If we're doing the fast handshake, add that         * "Finished" message to the hash of handshake messages, then send         * our own change_cipher_spec and Finished message for the server         * to verify in turn.  These are the last handshake messages.         *         * In any case, update the session cache.  We're done handshaking,         * so there are no threats any more associated with partially         * completed handshakes.         */        if (resumingSession) {            input.digestNow();            sendChangeCipherAndFinish(true);        }        session.setLastAccessedTime(System.currentTimeMillis());         if (!resumingSession) {            if (session.isRejoinable()) {                ((SSLSessionContextImpl) sslContext                        .engineGetClientSessionContext())                        .put(session);                if (debug != null && Debug.isOn("session")) {                    System.out.println("%% Cached client session: " + session);                }            } else if (debug != null && Debug.isOn("session")) {                System.out.println(                    "%% Didn't cache non-resumable client session: "                    + session);            }        }    }      /*     * Send my change-cipher-spec and Finished message ... done as the     * last handshake act in either the short or long sequences.  In     * the short one, we've already seen the server's Finished; in the     * long one, we wait for it now.     */    private void sendChangeCipherAndFinish(boolean finishedTag)            throws IOException {        Finished mesg = new Finished(protocolVersion, handshakeHash,            Finished.CLIENT, session.getMasterSecret(), cipherSuite);         /*         * Send the change_cipher_spec message, then the Finished message         * which we just calculated (and protected using the keys we just         * calculated).  Server responds with its Finished message, except         * in the "fast handshake" (resume session) case.         */        sendChangeCipherSpec(mesg, finishedTag);         /*         * save client verify data for secure renegotiation         */        if (secureRenegotiation) {            clientVerifyData = mesg.getVerifyData();        }         /*         * Update state machine so server MUST send 'finished' next.         * (In "long" handshake case; in short case, we're responding         * to its message.)         */        state = HandshakeMessage.ht_finished - 1;    }      /*     * Returns a ClientHello message to kickstart renegotiations     */    HandshakeMessage getKickstartMessage() throws SSLException {        // session ID of the ClientHello message        SessionId sessionId = SSLSessionImpl.nullSession.getSessionId();         // a list of cipher suites sent by the client        CipherSuiteList cipherSuites = getActiveCipherSuites();         // set the max protocol version this client is supporting.        maxProtocolVersion = protocolVersion;         //        // Try to resume an existing session.  This might be mandatory,        // given certain API options.        //        session = ((SSLSessionContextImpl)sslContext                        .engineGetClientSessionContext())                        .get(getHostSE(), getPortSE());        if (debug != null && Debug.isOn("session")) {            if (session != null) {                System.out.println("%% Client cached "                    + session                    + (session.isRejoinable() ? "" : " (not rejoinable)"));            } else {                System.out.println("%% No cached client session");            }        }        if ((session != null) && (session.isRejoinable() == false)) {            session = null;        }         if (session != null) {            CipherSuite sessionSuite = session.getSuite();            ProtocolVersion sessionVersion = session.getProtocolVersion();            if (isNegotiable(sessionSuite) == false) {                if (debug != null && Debug.isOn("session")) {                    System.out.println("%% can't resume, unavailable cipher");                }                session = null;            }             if ((session != null) && !isNegotiable(sessionVersion)) {                if (debug != null && Debug.isOn("session")) {                    System.out.println("%% can't resume, protocol disabled");                }                session = null;            }             if (session != null) {                if (debug != null) {                    if (Debug.isOn("handshake") || Debug.isOn("session")) {                        System.out.println("%% Try resuming " + session                            + " from port " + getLocalPortSE());                    }                }                 sessionId = session.getSessionId();                maxProtocolVersion = sessionVersion;                 // Update SSL version number in underlying SSL socket and                // handshake output stream, so that the output records (at the                // record layer) have the correct version                setVersion(sessionVersion);            }             /*             * Force use of the previous session ciphersuite, and             * add the SCSV if enabled.             */            if (!enableNewSession) {                if (session == null) {                    throw new SSLHandshakeException(                        "Can't reuse existing SSL client session");                }                 Collection<CipherSuite> cipherList = new ArrayList<>(2);                cipherList.add(sessionSuite);                if (!secureRenegotiation &&                        cipherSuites.contains(CipherSuite.C_SCSV)) {                    cipherList.add(CipherSuite.C_SCSV);                }   // otherwise, renegotiation_info extension will be used                 cipherSuites = new CipherSuiteList(cipherList);            }        }         if (session == null && !enableNewSession) {            throw new SSLHandshakeException("No existing session to resume");        }         // exclude SCSV for secure renegotiation        if (secureRenegotiation && cipherSuites.contains(CipherSuite.C_SCSV)) {            Collection<CipherSuite> cipherList =                        new ArrayList<>(cipherSuites.size() - 1);            for (CipherSuite suite : cipherSuites.collection()) {                if (suite != CipherSuite.C_SCSV) {                    cipherList.add(suite);                }            }             cipherSuites = new CipherSuiteList(cipherList);        }         // make sure there is a negotiable cipher suite.        boolean negotiable = false;        for (CipherSuite suite : cipherSuites.collection()) {            if (isNegotiable(suite)) {                negotiable = true;                break;            }        }         if (!negotiable) {            throw new SSLHandshakeException("No negotiable cipher suite");        }         // Not a TLS1.2+ handshake        // For SSLv2Hello, HandshakeHash.reset() will be called, so we        // cannot call HandshakeHash.protocolDetermined() here. As it does        // not follow the spec that HandshakeHash.reset() can be only be        // called before protocolDetermined.        // if (maxProtocolVersion.v < ProtocolVersion.TLS12.v) {        //     handshakeHash.protocolDetermined(maxProtocolVersion);        // }         // create the ClientHello message        ClientHello clientHelloMessage = new ClientHello(                sslContext.getSecureRandom(), maxProtocolVersion,                sessionId, cipherSuites);         // add signature_algorithm extension        if (maxProtocolVersion.v >= ProtocolVersion.TLS12.v) {            // we will always send the signature_algorithm extension            Collection<SignatureAndHashAlgorithm> localSignAlgs =                                                getLocalSupportedSignAlgs();            if (localSignAlgs.isEmpty()) {                throw new SSLHandshakeException(                            "No supported signature algorithm");            }             clientHelloMessage.addSignatureAlgorithmsExtension(localSignAlgs);        }         // add server_name extension        if (enableSNIExtension) {            // We cannot use the hostname resolved from name services.  For            // virtual hosting, multiple hostnames may be bound to the same IP            // address, so the hostname resolved from name services is not            // reliable.            String hostname = getRawHostnameSE();             // we only allow FQDN            if (hostname != null && hostname.indexOf('.') > 0 &&                    !IPAddressUtil.isIPv4LiteralAddress(hostname) &&                    !IPAddressUtil.isIPv6LiteralAddress(hostname)) {                clientHelloMessage.addServerNameIndicationExtension(hostname);            }        }         // reset the client random cookie        clnt_random = clientHelloMessage.clnt_random;         /*         * need to set the renegotiation_info extension for:         * 1: secure renegotiation         * 2: initial handshake and no SCSV in the ClientHello         * 3: insecure renegotiation and no SCSV in the ClientHello         */        if (secureRenegotiation ||                !cipherSuites.contains(CipherSuite.C_SCSV)) {            clientHelloMessage.addRenegotiationInfoExtension(clientVerifyData);        }         return clientHelloMessage;    }     /*     * Fault detected during handshake.     */    void handshakeAlert(byte description) throws SSLProtocolException {        String message = Alerts.alertDescription(description);         if (debug != null && Debug.isOn("handshake")) {            System.out.println("SSL - handshake alert: " + message);        }        throw new SSLProtocolException("handshake alert:  " + message);    }     /*     * Unless we are using an anonymous ciphersuite, the server always     * sends a certificate message (for the CipherSuites we currently     * support). The trust manager verifies the chain for us.     */    private void serverCertificate(CertificateMsg mesg) throws IOException {        if (debug != null && Debug.isOn("handshake")) {            mesg.print(System.out);        }        X509Certificate[] peerCerts = mesg.getCertificateChain();        if (peerCerts.length == 0) {            fatalSE(Alerts.alert_bad_certificate,                "empty certificate chain");        }        // ask the trust manager to verify the chain        X509TrustManager tm = sslContext.getX509TrustManager();        try {            // find out the key exchange algorithm used            // use "RSA" for non-ephemeral "RSA_EXPORT"            String keyExchangeString;            if (keyExchange == K_RSA_EXPORT && !serverKeyExchangeReceived) {                keyExchangeString = K_RSA.name;            } else {                keyExchangeString = keyExchange.name;            }             if (tm instanceof X509ExtendedTrustManager) {                if (conn != null) {                    ((X509ExtendedTrustManager)tm).checkServerTrusted(                        peerCerts.clone(),                        keyExchangeString,                        conn);                } else {                    ((X509ExtendedTrustManager)tm).checkServerTrusted(                        peerCerts.clone(),                        keyExchangeString,                        engine);                }            } else {                // Unlikely to happen, because we have wrapped the old                // X509TrustManager with the new X509ExtendedTrustManager.                throw new CertificateException(                    "Improper X509TrustManager implementation");            }        } catch (CertificateException e) {            // This will throw an exception, so include the original error.            fatalSE(Alerts.alert_certificate_unknown, e);        }        session.setPeerCertificates(peerCerts);    }}

Lines 1001–1341 of 1341. Previous lines