1341 lines · 53.3 KB · Java
RawDownload
                    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);            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)                    && (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);        }    }     /*     * Server's own key was either a signing-only key, or was too     * large for export rules ... this message holds an ephemeral     * RSA key to use for key exchange.     */    private void serverKeyExchange(RSA_ServerKeyExchange mesg)            throws IOException, GeneralSecurityException {        if (debug != null && Debug.isOn("handshake")) {            mesg.print(System.out);        }        if (!mesg.verify(serverKey, clnt_random, svr_random)) {            fatalSE(Alerts.alert_handshake_failure,                "server key exchange invalid");            // NOTREACHED        }        ephemeralServerKey = mesg.getPublicKey();    }      /*     * Diffie-Hellman key exchange.  We save the server public key and     * our own D-H algorithm object so we can defer key calculations     * until after we've sent the client key exchange message (which     * gives client and server some useful parallelism).     */    private void serverKeyExchange(DH_ServerKeyExchange mesg)            throws IOException {        if (debug != null && Debug.isOn("handshake")) {            mesg.print(System.out);        }        dh = new DHCrypt(mesg.getModulus(), mesg.getBase(),                                            sslContext.getSecureRandom());        serverDH = mesg.getServerPublicKey();    }     private void serverKeyExchange(ECDH_ServerKeyExchange mesg)            throws IOException {        if (debug != null && Debug.isOn("handshake")) {            mesg.print(System.out);        }        ECPublicKey key = mesg.getPublicKey();        ecdh = new ECDHCrypt(key.getParams(), sslContext.getSecureRandom());        ephemeralServerKey = key;    }     /*     * The server's "Hello Done" message is the client's sign that     * it's time to do all the hard work.     */    private void serverHelloDone(ServerHelloDone mesg) throws IOException {        if (debug != null && Debug.isOn("handshake")) {            mesg.print(System.out);        }        /*         * Always make sure the input has been digested before we         * start emitting data, to ensure the hashes are correctly         * computed for the Finished and CertificateVerify messages         * which we send (here).         */        input.digestNow();         /*         * FIRST ... if requested, send an appropriate Certificate chain         * to authenticate the client, and remember the associated private         * key to sign the CertificateVerify message.         */        PrivateKey signingKey = null;         if (certRequest != null) {            X509ExtendedKeyManager km = sslContext.getX509KeyManager();             ArrayList<String> keytypesTmp = new ArrayList<>(4);             for (int i = 0; i < certRequest.types.length; i++) {                String typeName;                 switch (certRequest.types[i]) {                case CertificateRequest.cct_rsa_sign:                    typeName = "RSA";                    break;                 case CertificateRequest.cct_dss_sign:                    typeName = "DSA";                    break;                 case CertificateRequest.cct_ecdsa_sign:                    // ignore if we do not have EC crypto available                    typeName = JsseJce.isEcAvailable() ? "EC" : null;                    break;                 // Fixed DH/ECDH client authentication not supported                case CertificateRequest.cct_rsa_fixed_dh:                case CertificateRequest.cct_dss_fixed_dh:                case CertificateRequest.cct_rsa_fixed_ecdh:                case CertificateRequest.cct_ecdsa_fixed_ecdh:                // Any other values (currently not used in TLS)                case CertificateRequest.cct_rsa_ephemeral_dh:                case CertificateRequest.cct_dss_ephemeral_dh:                default:                    typeName = null;                    break;                }                 if ((typeName != null) && (!keytypesTmp.contains(typeName))) {                    keytypesTmp.add(typeName);                }            }             String alias = null;            int keytypesTmpSize = keytypesTmp.size();            if (keytypesTmpSize != 0) {                String keytypes[] =                        keytypesTmp.toArray(new String[keytypesTmpSize]);                 if (conn != null) {                    alias = km.chooseClientAlias(keytypes,                        certRequest.getAuthorities(), conn);                } else {                    alias = km.chooseEngineClientAlias(keytypes,                        certRequest.getAuthorities(), engine);                }            }             CertificateMsg m1 = null;            if (alias != null) {                X509Certificate[] certs = km.getCertificateChain(alias);                if ((certs != null) && (certs.length != 0)) {                    PublicKey publicKey = certs[0].getPublicKey();                    // for EC, make sure we use a supported named curve                    if (publicKey instanceof ECPublicKey) {                        ECParameterSpec params =                            ((ECPublicKey)publicKey).getParams();                        int index =                            SupportedEllipticCurvesExtension.getCurveIndex(                                params);                        if (!SupportedEllipticCurvesExtension.isSupported(                                index)) {                            publicKey = null;                        }                    }                    if (publicKey != null) {                        m1 = new CertificateMsg(certs);                        signingKey = km.getPrivateKey(alias);                        session.setLocalPrivateKey(signingKey);                        session.setLocalCertificates(certs);                    }                }            }            if (m1 == null) {                //                // No appropriate cert was found ... report this to the                // server.  For SSLv3, send the no_certificate alert;                // TLS uses an empty cert chain instead.                //                if (protocolVersion.v >= ProtocolVersion.TLS10.v) {                    m1 = new CertificateMsg(new X509Certificate [0]);                } else {                    warningSE(Alerts.alert_no_certificate);                }            }             //            // At last ... send any client certificate chain.            //            if (m1 != null) {                if (debug != null && Debug.isOn("handshake")) {                    m1.print(System.out);                }                m1.write(output);            }        }         /*         * SECOND ... send the client key exchange message.  The         * procedure used is a function of the cipher suite selected;         * one is always needed.         */        HandshakeMessage m2;         switch (keyExchange) {         case K_RSA:        case K_RSA_EXPORT:            if (serverKey == null) {                throw new SSLProtocolException                        ("Server did not send certificate message");            }             if (!(serverKey instanceof RSAPublicKey)) {                throw new SSLProtocolException                        ("Server certificate does not include an RSA key");            }             /*             * For RSA key exchange, we randomly generate a new             * pre-master secret and encrypt it with the server's             * public key.  Then we save that pre-master secret             * so that we can calculate the keying data later;             * it's a performance speedup not to do that until             * the client's waiting for the server response, but             * more of a speedup for the D-H case.             *             * If the RSA_EXPORT scheme is active, when the public             * key in the server certificate is less than or equal             * to 512 bits in length, use the cert's public key,             * otherwise, the ephemeral one.             */            PublicKey key;            if (keyExchange == K_RSA) {                key = serverKey;            } else {    // K_RSA_EXPORT                if (JsseJce.getRSAKeyLength(serverKey) <= 512) {                    // extraneous ephemeralServerKey check done                    // above in processMessage()                    key = serverKey;                } else {                    if (ephemeralServerKey == null) {                        throw new SSLProtocolException("Server did not send" +                            " a RSA_EXPORT Server Key Exchange message");                    }                    key = ephemeralServerKey;                }            }             m2 = new RSAClientKeyExchange(protocolVersion, maxProtocolVersion,                                sslContext.getSecureRandom(), key);            break;        case K_DH_RSA:        case K_DH_DSS:            /*             * For DH Key exchange, we only need to make sure the server             * knows our public key, so we calculate the same pre-master             * secret.             *             * For certs that had DH keys in them, we send an empty             * handshake message (no key) ... we flag this case by             * passing a null "dhPublic" value.             *             * Otherwise we send ephemeral DH keys, unsigned.             */            // if (useDH_RSA || useDH_DSS)            m2 = new DHClientKeyExchange();            break;        case K_DHE_RSA:        case K_DHE_DSS:        case K_DH_ANON:            if (dh == null) {                throw new SSLProtocolException                    ("Server did not send a DH Server Key Exchange message");            }            m2 = new DHClientKeyExchange(dh.getPublicKey());            break;        case K_ECDHE_RSA:        case K_ECDHE_ECDSA:        case K_ECDH_ANON:            if (ecdh == null) {                throw new SSLProtocolException                    ("Server did not send a ECDH Server Key Exchange message");            }            m2 = new ECDHClientKeyExchange(ecdh.getPublicKey());            break;        case K_ECDH_RSA:        case K_ECDH_ECDSA:            if (serverKey == null) {                throw new SSLProtocolException                        ("Server did not send certificate message");            }            if (serverKey instanceof ECPublicKey == false) {                throw new SSLProtocolException                        ("Server certificate does not include an EC key");            }            ECParameterSpec params = ((ECPublicKey)serverKey).getParams();            ecdh = new ECDHCrypt(params, sslContext.getSecureRandom());            m2 = new ECDHClientKeyExchange(ecdh.getPublicKey());            break;        case K_KRB5:        case K_KRB5_EXPORT:            String hostname = getHostSE();            if (hostname == null) {                throw new IOException("Hostname is required" +                                " to use Kerberos cipher suites");            }            KerberosClientKeyExchange kerberosMsg =                new KerberosClientKeyExchange(                    hostname, isLoopbackSE(), getAccSE(), protocolVersion,                sslContext.getSecureRandom());            // Record the principals involved in exchange            session.setPeerPrincipal(kerberosMsg.getPeerPrincipal());            session.setLocalPrincipal(kerberosMsg.getLocalPrincipal());            m2 = kerberosMsg;            break;        default:            // somethings very wrong            throw new RuntimeException                                ("Unsupported key exchange: " + keyExchange);        }        if (debug != null && Debug.isOn("handshake")) {            m2.print(System.out);        }        m2.write(output);          /*         * THIRD, send a "change_cipher_spec" record followed by the         * "Finished" message.  We flush the messages we've queued up, to         * get concurrency between client and server.  The concurrency is         * useful as we calculate the master secret, which is needed both         * to compute the "Finished" message, and to compute the keys used         * to protect all records following the change_cipher_spec.         */         output.doHashes();        output.flush();         /*         * We deferred calculating the master secret and this connection's         * keying data; we do it now.  Deferring this calculation is good         * from a performance point of view, since it lets us do it during         * some time that network delays and the server's own calculations         * would otherwise cause to be "dead" in the critical path.         */        SecretKey preMasterSecret;        switch (keyExchange) {        case K_RSA:        case K_RSA_EXPORT:            preMasterSecret = ((RSAClientKeyExchange)m2).preMaster;            break;        case K_KRB5:        case K_KRB5_EXPORT:            byte[] secretBytes =                ((KerberosClientKeyExchange)m2).getUnencryptedPreMasterSecret();            preMasterSecret = new SecretKeySpec(secretBytes,                "TlsPremasterSecret");            break;        case K_DHE_RSA:        case K_DHE_DSS:        case K_DH_ANON:            preMasterSecret = dh.getAgreedSecret(serverDH);            break;        case K_ECDHE_RSA:        case K_ECDHE_ECDSA:        case K_ECDH_ANON:            preMasterSecret = ecdh.getAgreedSecret(ephemeralServerKey);            break;        case K_ECDH_RSA:        case K_ECDH_ECDSA:            preMasterSecret = ecdh.getAgreedSecret(serverKey);            break;        default:            throw new IOException("Internal error: unknown key exchange "                + keyExchange);        }         calculateKeys(preMasterSecret, null);         /*         * FOURTH, if we sent a Certificate, we need to send a signed         * CertificateVerify (unless the key in the client's certificate         * was a Diffie-Hellman key).).         *         * This uses a hash of the previous handshake messages ... either         * a nonfinal one (if the particular implementation supports it)         * or else using the third element in the arrays of hashes being         * computed.         */        if (signingKey != null) {            CertificateVerify m3;            try {                SignatureAndHashAlgorithm preferableSignatureAlgorithm = null;                if (protocolVersion.v >= ProtocolVersion.TLS12.v) {                    preferableSignatureAlgorithm =                        SignatureAndHashAlgorithm.getPreferableAlgorithm(                            peerSupportedSignAlgs, signingKey.getAlgorithm());                     if (preferableSignatureAlgorithm == null) {                        throw new SSLHandshakeException(                            "No supported signature algorithm");                    }                     String hashAlg =                        SignatureAndHashAlgorithm.getHashAlgorithmName(                                preferableSignatureAlgorithm);                    if (hashAlg == null || hashAlg.length() == 0) {                        throw new SSLHandshakeException(                                "No supported hash algorithm");                    }                     handshakeHash.setCertificateVerifyAlg(hashAlg);                }                 m3 = new CertificateVerify(protocolVersion, handshakeHash,                    signingKey, session.getMasterSecret(),                    sslContext.getSecureRandom(),                    preferableSignatureAlgorithm);            } catch (GeneralSecurityException e) {                fatalSE(Alerts.alert_handshake_failure,                    "Error signing certificate verify", e);                // NOTREACHED, make compiler happy                m3 = null;            }            if (debug != null && Debug.isOn("handshake")) {                m3.print(System.out);            }            m3.write(output);            output.doHashes();        } else {            if (protocolVersion.v >= ProtocolVersion.TLS12.v) {                handshakeHash.setCertificateVerifyAlg(null);            }        }         /*         * OK, that's that!

Lines 501–1000 of 1341. Previous lines