private void serverHello(ServerHello mesg) throws IOException {
        serverKeyExchangeReceived = false;
        if (debug != null && Debug.isOn("handshake")) {
            mesg.print(System.out);
        }

        // check if the server selected protocol version is OK for us
        ProtocolVersion mesgVersion = mesg.protocolVersion;
        if (!isNegotiable(mesgVersion)) {
            throw new SSLHandshakeException(
                "Server chose " + mesgVersion +
                ", but that protocol version is not enabled or not supported " +
                "by the client.");
        }

        handshakeHash.protocolDetermined(mesgVersion);

        // Set protocolVersion and propagate to SSLSocket and the
        // Handshake streams
        setVersion(mesgVersion);

        // check the "renegotiation_info" extension
        RenegotiationInfoExtension serverHelloRI = (RenegotiationInfoExtension)
                    mesg.extensions.get(ExtensionType.EXT_RENEGOTIATION_INFO);
        if (serverHelloRI != null) {
            if (isInitialHandshake) {
                // verify the length of the "renegotiated_connection" field
                if (!serverHelloRI.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 {
                // For a legacy renegotiation, the client MUST verify that
                // it does not contain the "renegotiation_info" extension.
                if (!secureRenegotiation) {
                    fatalSE(Alerts.alert_handshake_failure,
                        "Unexpected renegotiation indication extension");
                }

                // verify the client_verify_data and server_verify_data values
                byte[] verifyData =
                    new byte[clientVerifyData.length + serverVerifyData.length];
                System.arraycopy(clientVerifyData, 0, verifyData,
                        0, clientVerifyData.length);
                System.arraycopy(serverVerifyData, 0, verifyData,
                        clientVerifyData.length, serverVerifyData.length);
                if (!Arrays.equals(verifyData,
                                serverHelloRI.getRenegotiatedConnection())) {
                    fatalSE(Alerts.alert_handshake_failure,
                        "Incorrect verify data in ServerHello " +
                        "renegotiation_info message");
                }
            }
        } else {
            // no renegotiation indication extension
            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");
                }

                secureRenegotiation = false;
                if (debug != null && Debug.isOn("handshake")) {
                    System.out.println("Warning: No renegotiation " +
                                    "indication extension in ServerHello");
                }
            } else {
                // For a secure renegotiation, the client must abort the
                // handshake if no "renegotiation_info" extension is present.
                if (secureRenegotiation) {
                    fatalSE(Alerts.alert_handshake_failure,
                        "No renegotiation indication extension");
                }

                // we have already allowed unsafe renegotation before request
                // the renegotiation.
            }
        }

        //
        // Save server nonce, we always use it to compute connection
        // keys and it's also used to create the master secret if we're
        // creating a new session (i.e. in the full handshake).
        //
        svr_random = mesg.svr_random;

        if (isNegotiable(mesg.cipherSuite) == false) {
            fatalSE(Alerts.alert_illegal_parameter,
                "Server selected improper ciphersuite " + mesg.cipherSuite);
        }

        setCipherSuite(mesg.cipherSuite);
        if (protocolVersion.v >= ProtocolVersion.TLS12.v) {
            handshakeHash.setFinishedAlg(cipherSuite.prfAlg.getPRFHashAlg());
        }

        if (mesg.compression_method != 0) {
            fatalSE(Alerts.alert_illegal_parameter,
                "compression type not supported, "
                + mesg.compression_method);
            // NOTREACHED
        }

        // so far so good, let's look at the session
        if (session != null) {
            // we tried to resume, let's see what the server decided
            if (session.getSessionId().equals(mesg.sessionId)) {
                // server resumed the session, let's make sure everything
                // checks out

                // Verify that the session ciphers are unchanged.
                CipherSuite sessionSuite = session.getSuite();
                if (cipherSuite != sessionSuite) {
                    throw new SSLProtocolException
                        ("Server returned wrong cipher suite for session");
                }

                // verify protocol version match
                ProtocolVersion sessionVersion = session.getProtocolVersion();
                if (protocolVersion != sessionVersion) {
                    throw new SSLProtocolException
                        ("Server resumed session with wrong protocol version");
                }

                // validate subject identity
                if (sessionSuite.keyExchange == K_KRB5 ||
                    sessionSuite.keyExchange == K_KRB5_EXPORT) {
                    Principal localPrincipal = session.getLocalPrincipal();

                    Subject subject = null;
                    try {
                        subject = AccessController.doPrivileged(
                            new PrivilegedExceptionAction<Subject>() {
                            public Subject run() throws Exception {
                                return Krb5Helper.getClientSubject(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
                        Set<Principal> principals =
                            subject.getPrincipals(Principal.class);
                        if (!principals.contains(localPrincipal)) {
                            throw new SSLProtocolException("Server resumed" +
                                " session with wrong subject identity");
                        } else {
                            if (debug != null && Debug.isOn("session"))
                                System.out.println("Subject identity is same");
                        }
                    } else {
                        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");
                        throw new SSLProtocolException
                            ("Server resumed session with no subject");
                    }
                }

                // looks fine; resume it, and update the state machine.
                resumingSession = true;
                state = HandshakeMessage.ht_finished - 1;
                calculateConnectionKeys(session.getMasterSecret());
                if (debug != null && Debug.isOn("session")) {
                    System.out.println("%% Server resumed " + session);
                }
            } else {
                // we wanted to resume, but the server refused
                session = null;
                if (!enableNewSession) {
                    throw new SSLException("New session creation is disabled");
                }
            }
        }

        if (resumingSession && session != null) {
            if (protocolVersion.v >= ProtocolVersion.TLS12.v) {
                handshakeHash.setCertificateVerifyAlg(null);
            }

            setHandshakeSessionSE(session);
            // Reserve the handshake state if this is a session-resumption
            // abbreviated initial handshake.
            if (isInitialHandshake) {
                session.setAsSessionResumption(true);
                // NPN_CHANGES_BEGIN
                npnReceived(mesg);
                // NPN_CHANGES_END
            }
            return;
        }

        // check extensions
        for (HelloExtension ext : mesg.extensions.list()) {
            ExtensionType type = ext.type;
            if ((type != ExtensionType.EXT_ELLIPTIC_CURVES)
                    && (type != ExtensionType.EXT_EC_POINT_FORMATS)
                    && (type != ExtensionType.EXT_SERVER_NAME)
                    // NPN_CHANGES_BEGIN
                    && (type != ExtensionType.EXT_NEXT_PROTOCOL_NEGOTIATION)
                    // NPN_CHANGES_END
                    && (type != ExtensionType.EXT_RENEGOTIATION_INFO)) {
                fatalSE(Alerts.alert_unsupported_extension,
                    "Server sent an unsupported extension: " + type);
            }
        }

        // Create a new session, we need to do the full handshake
        session = new SSLSessionImpl(protocolVersion, cipherSuite,
                            getLocalSupportedSignAlgs(),
                            mesg.sessionId, getHostSE(), getPortSE());
        setHandshakeSessionSE(session);
        if (debug != null && Debug.isOn("handshake")) {
            System.out.println("** " + cipherSuite);
        }

        // NPN_CHANGES_BEGIN
        if (isInitialHandshake)
            npnReceived(mesg);
        // NPN_CHANGES_END
    }
private void serverHello ( ServerHello mesg ) throws IOException { serverKeyExchangeReceived = false ; if ( debug != null && Debug . isOn ( "handshake" ) ) { mesg . print ( System . out ) ; } ProtocolVersion mesgVersion = mesg . protocolVersion ; if ( ! isNegotiable ( mesgVersion ) ) { throw new SSLHandshakeException ( "Server chose " + mesgVersion + ", but that protocol version is not enabled or not supported " + "by the client." ) ; } handshakeHash . protocolDetermined ( mesgVersion ) ; setVersion ( mesgVersion ) ; RenegotiationInfoExtension serverHelloRI = ( RenegotiationInfoExtension ) mesg . extensions . get ( ExtensionType . EXT_RENEGOTIATION_INFO ) ; if ( serverHelloRI != null ) { if ( isInitialHandshake ) { if ( ! serverHelloRI . isEmpty ( ) ) { fatalSE ( Alerts . alert_handshake_failure , "The renegotiation_info field is not empty" ) ; } secureRenegotiation = true ; } else { if ( ! secureRenegotiation ) { fatalSE ( Alerts . alert_handshake_failure , "Unexpected renegotiation indication extension" ) ; } byte [ ] verifyData = new byte [ clientVerifyData . length + serverVerifyData . length ] ; System . arraycopy ( clientVerifyData , 0 , verifyData , 0 , clientVerifyData . length ) ; System . arraycopy ( serverVerifyData , 0 , verifyData , clientVerifyData . length , serverVerifyData . length ) ; if ( ! Arrays . equals ( verifyData , serverHelloRI . getRenegotiatedConnection ( ) ) ) { fatalSE ( Alerts . alert_handshake_failure , "Incorrect verify data in ServerHello " + "renegotiation_info message" ) ; } } } else { if ( isInitialHandshake ) { if ( ! allowLegacyHelloMessages ) { fatalSE ( Alerts . alert_handshake_failure , "Failed to negotiate the use of secure renegotiation" ) ; } secureRenegotiation = false ; if ( debug != null && Debug . isOn ( "handshake" ) ) { System . out . println ( "Warning: No renegotiation " + "indication extension in ServerHello" ) ; } } else { if ( secureRenegotiation ) { fatalSE ( Alerts . alert_handshake_failure , "No renegotiation indication extension" ) ; } } } svr_random = mesg . svr_random ; if ( isNegotiable ( mesg . cipherSuite ) == false ) { fatalSE ( Alerts . alert_illegal_parameter , "Server selected improper ciphersuite " + mesg . cipherSuite ) ; } setCipherSuite ( mesg . cipherSuite ) ; if ( protocolVersion . v >= ProtocolVersion . TLS12 . v ) { handshakeHash . setFinishedAlg ( cipherSuite . prfAlg . getPRFHashAlg ( ) ) ; } if ( mesg . compression_method != 0 ) { fatalSE ( Alerts . alert_illegal_parameter , "compression type not supported, " + mesg . compression_method ) ; } if ( session != null ) { if ( session . getSessionId ( ) . equals ( mesg . sessionId ) ) { CipherSuite sessionSuite = session . getSuite ( ) ; if ( cipherSuite != sessionSuite ) { throw new SSLProtocolException ( "Server returned wrong cipher suite for session" ) ; } ProtocolVersion sessionVersion = session . getProtocolVersion ( ) ; if ( protocolVersion != sessionVersion ) { throw new SSLProtocolException ( "Server resumed session with wrong protocol version" ) ; } if ( sessionSuite . keyExchange == K_KRB5 || sessionSuite . keyExchange == K_KRB5_EXPORT ) { Principal localPrincipal = session . getLocalPrincipal ( ) ; Subject subject = null ; try { subject = AccessController . doPrivileged ( new PrivilegedExceptionAction < Subject > ( ) { public Subject run ( ) throws Exception { return Krb5Helper . getClientSubject ( getAccSE ( ) ) ; } } ) ; } catch ( PrivilegedActionException e ) { subject = null ; if ( debug != null && Debug . isOn ( "session" ) ) { System . out . println ( "Attempt to obtain" + " subject failed!" ) ; } } if ( subject != null ) { Set < Principal > principals = subject . getPrincipals ( Principal . class ) ; if ( ! principals . contains ( localPrincipal ) ) { throw new SSLProtocolException ( "Server resumed" + " session with wrong subject identity" ) ; } else { if ( debug != null && Debug . isOn ( "session" ) ) System . out . println ( "Subject identity is same" ) ; } } else { 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" ) ; throw new SSLProtocolException ( "Server resumed session with no subject" ) ; } } resumingSession = true ; state = HandshakeMessage . ht_finished - 1 ; calculateConnectionKeys ( session . getMasterSecret ( ) ) ; if ( debug != null && Debug . isOn ( "session" ) ) { System . out . println ( "%% Server resumed " + session ) ; } } else { session = null ; if ( ! enableNewSession ) { throw new SSLException ( "New session creation is disabled" ) ; } } } if ( resumingSession && session != null ) { if ( protocolVersion . v >= ProtocolVersion . TLS12 . v ) { handshakeHash . setCertificateVerifyAlg ( null ) ; } setHandshakeSessionSE ( session ) ; if ( isInitialHandshake ) { session . setAsSessionResumption ( true ) ; npnReceived ( mesg ) ; } return ; } for ( HelloExtension ext : mesg . extensions . list ( ) ) { ExtensionType type = ext . type ; if ( ( type != ExtensionType . EXT_ELLIPTIC_CURVES ) && ( type != ExtensionType . EXT_EC_POINT_FORMATS ) && ( type != ExtensionType . EXT_SERVER_NAME ) && ( type != ExtensionType . EXT_NEXT_PROTOCOL_NEGOTIATION ) && ( type != ExtensionType . EXT_RENEGOTIATION_INFO ) ) { fatalSE ( Alerts . alert_unsupported_extension , "Server sent an unsupported extension: " + type ) ; } } session = new SSLSessionImpl ( protocolVersion , cipherSuite , getLocalSupportedSignAlgs ( ) , mesg . sessionId , getHostSE ( ) , getPortSE ( ) ) ; setHandshakeSessionSE ( session ) ; if ( debug != null && Debug . isOn ( "handshake" ) ) { System . out . println ( "** " + cipherSuite ) ; } if ( isInitialHandshake ) npnReceived ( mesg ) ; }
/*
Server chooses session parameters given options created by the
client -- basically, cipher options, session id, and someday a
set of compression options.

There are two branches of the state machine, decided by the
details of this message.  One is the "fast" handshake, where we
can resume the pre-existing session we asked resume.  The other
is a more expensive "full" handshake, with key exchange and
probably authentication getting done.