1678 lines · 65.9 KB · Java
RawDownload
         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:            // get preferable peer signature algorithm for server key exchange            if (protocolVersion.v >= ProtocolVersion.TLS12.v) {                preferableSignatureAlgorithm =                    SignatureAndHashAlgorithm.getPreferableAlgorithm(                                                supportedSignAlgs, "RSA");                if (preferableSignatureAlgorithm == null) {                    return false;                }            }             // need RSA certs for authentication            if (setupPrivateKeyAndChain("RSA") == false) {                return false;            }            setupEphemeralDHKeys(suite.exportable);            break;        case K_ECDHE_RSA:            // get preferable peer signature algorithm for server key exchange            if (protocolVersion.v >= ProtocolVersion.TLS12.v) {                preferableSignatureAlgorithm =                    SignatureAndHashAlgorithm.getPreferableAlgorithm(                                                supportedSignAlgs, "RSA");                if (preferableSignatureAlgorithm == null) {                    return false;                }            }             // need RSA certs for authentication            if (setupPrivateKeyAndChain("RSA") == false) {                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) {                    return false;                }            }             // need DSS certs for authentication            if (setupPrivateKeyAndChain("DSA") == false) {                return false;            }            setupEphemeralDHKeys(suite.exportable);            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) {                    return false;                }            }             // need EC cert signed using EC            if (setupPrivateKeyAndChain("EC_EC") == false) {                return false;            }            if (setupEphemeralECDHKeys() == false) {                return false;            }            break;        case K_ECDH_RSA:            // need EC cert signed using RSA            if (setupPrivateKeyAndChain("EC_RSA") == false) {                return false;            }            setupStaticECDHKeys();            break;        case K_ECDH_ECDSA:            // need EC cert signed using EC            if (setupPrivateKeyAndChain("EC_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);            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;    }     /*     * Get some "ephemeral" RSA keys for this context. This means     * generating them if it's not already been done.     *     * Note that we currently do not implement any ciphersuites that use     * strong ephemeral RSA. (We do not support the EXPORT1024 ciphersuites     * and standard RSA ciphersuites prohibit ephemeral mode for some reason)     * This means that export is always true and 512 bit keys are generated.     */    private boolean setupEphemeralRSAKeys(boolean export) {        KeyPair kp = sslContext.getEphemeralKeyManager().                        getRSAKeyPair(export, sslContext.getSecureRandom());        if (kp == null) {            return false;        } else {            tempPublicKey = kp.getPublic();            tempPrivateKey = kp.getPrivate();            return true;        }    }     /*     * Acquire some "ephemeral" Diffie-Hellman  keys for this handshake.     * We don't reuse these, for improved forward secrecy.     */    private void setupEphemeralDHKeys(boolean export) {        /*         * Diffie-Hellman keys ... we use 768 bit private keys due         * to the "use twice as many key bits as bits you want secret"         * rule of thumb, assuming we want the same size premaster         * secret with Diffie-Hellman and RSA key exchanges.  Except         * that exportable ciphers max out at 512 bits modulus values.         */        dh = new DHCrypt((export ? 512 : 768), sslContext.getSecureRandom());    }     // Setup the ephemeral ECDH parameters.    // If we cannot continue because we do not support any of the curves that    // the client requested, return false. Otherwise (all is well), return true.    private boolean setupEphemeralECDHKeys() {        int index = -1;        if (supportedCurves != null) {            // if the client sent the supported curves extension, pick the            // first one that we support;            for (int curveId : supportedCurves.curveIds()) {                if (SupportedEllipticCurvesExtension.isSupported(curveId)) {                    index = curveId;                    break;                }            }            if (index < 0) {                // no match found, cannot use this ciphersuite                return false;            }        } else {            // pick our preference            index = SupportedEllipticCurvesExtension.DEFAULT.curveIds()[0];        }        String oid = SupportedEllipticCurvesExtension.getCurveOid(index);        ecdh = new ECDHCrypt(oid, sslContext.getSecureRandom());        return true;    }     private void setupStaticECDHKeys() {        // don't need to check whether the curve is supported, already done        // in setupPrivateKeyAndChain().        ecdh = new ECDHCrypt(privateKey, certs[0].getPublicKey());    }     /**     * Retrieve the server key and certificate for the specified algorithm     * from the KeyManager and set the instance variables.     *     * @return true if successful, false if not available or invalid     */    private boolean setupPrivateKeyAndChain(String algorithm) {        X509ExtendedKeyManager km = sslContext.getX509KeyManager();        String alias;        if (conn != null) {            alias = km.chooseServerAlias(algorithm, null, conn);        } else {            alias = km.chooseEngineServerAlias(algorithm, null, engine);        }        if (alias == null) {            return false;        }        PrivateKey tempPrivateKey = km.getPrivateKey(alias);        if (tempPrivateKey == null) {            return false;        }        X509Certificate[] tempCerts = km.getCertificateChain(alias);        if ((tempCerts == null) || (tempCerts.length == 0)) {            return false;        }        String keyAlgorithm = algorithm.split("_")[0];        PublicKey publicKey = tempCerts[0].getPublicKey();        if ((tempPrivateKey.getAlgorithm().equals(keyAlgorithm) == false)                || (publicKey.getAlgorithm().equals(keyAlgorithm) == false)) {            return false;        }        // For ECC certs, check whether we support the EC domain parameters.        // If the client sent a SupportedEllipticCurves ClientHello extension,        // check against that too.        if (keyAlgorithm.equals("EC")) {            if (publicKey instanceof ECPublicKey == false) {                return false;            }            ECParameterSpec params = ((ECPublicKey)publicKey).getParams();            int index = SupportedEllipticCurvesExtension.getCurveIndex(params);            if (SupportedEllipticCurvesExtension.isSupported(index) == false) {                return false;            }            if ((supportedCurves != null) && !supportedCurves.contains(index)) {                return false;            }        }        this.privateKey = tempPrivateKey;        this.certs = tempCerts;        return true;    }     /**     * Retrieve the Kerberos key for the specified server principal     * from the JAAS configuration file.     *     * @return true if successful, false if not available or invalid     */    private boolean setupKerberosKeys() {        if (kerberosKeys != null) {            return true;        }        try {            final AccessControlContext acc = getAccSE();            kerberosKeys = AccessController.doPrivileged(                // Eliminate dependency on KerberosKey                new PrivilegedExceptionAction<SecretKey[]>() {                public SecretKey[] run() throws Exception {                    // get kerberos key for the default principal                    return Krb5Helper.getServerKeys(acc);                        }});             // check permission to access and use the secret key of the            // Kerberized "host" service            if (kerberosKeys != null && kerberosKeys.length > 0) {                if (debug != null && Debug.isOn("handshake")) {                    for (SecretKey k: kerberosKeys) {                        System.out.println("Using Kerberos key: " +                            k);                    }                }                 String serverPrincipal =                    Krb5Helper.getServerPrincipalName(kerberosKeys[0]);                SecurityManager sm = System.getSecurityManager();                try {                   if (sm != null) {                      // Eliminate dependency on ServicePermission                      sm.checkPermission(Krb5Helper.getServicePermission(                          serverPrincipal, "accept"), acc);                   }                } catch (SecurityException se) {                   kerberosKeys = null;                   // %%% destroy keys? or will that affect Subject?                   if (debug != null && Debug.isOn("handshake"))                      System.out.println("Permission to access Kerberos"                                + " secret key denied");                   return false;                }            }            return (kerberosKeys != null);        } catch (PrivilegedActionException e) {            // Likely exception here is LoginExceptin            if (debug != null && Debug.isOn("handshake")) {                System.out.println("Attempt to obtain Kerberos key failed: "                                + e.toString());            }            return false;        }    }     /*     * For Kerberos ciphers, the premaster secret is encrypted using     * the session key. See RFC 2712.     */    private SecretKey clientKeyExchange(KerberosClientKeyExchange mesg)        throws IOException {         if (debug != null && Debug.isOn("handshake")) {            mesg.print(System.out);        }         // Record the principals involved in exchange        session.setPeerPrincipal(mesg.getPeerPrincipal());        session.setLocalPrincipal(mesg.getLocalPrincipal());         byte[] b = mesg.getUnencryptedPreMasterSecret();        return new SecretKeySpec(b, "TlsPremasterSecret");    }     /*     * Diffie Hellman key exchange is used when the server presented     * D-H parameters in its certificate (signed using RSA or DSS/DSA),     * or else the server presented no certificate but sent D-H params     * in a ServerKeyExchange message.  Use of D-H is specified by the     * cipher suite chosen.     *     * The message optionally contains the client's D-H public key (if     * it wasn't not sent in a client certificate).  As always with D-H,     * if a client and a server have each other's D-H public keys and     * they use common algorithm parameters, they have a shared key     * that's derived via the D-H calculation.  That key becomes the     * pre-master secret.     */    private SecretKey clientKeyExchange(DHClientKeyExchange mesg)            throws IOException {         if (debug != null && Debug.isOn("handshake")) {            mesg.print(System.out);        }        return dh.getAgreedSecret(mesg.getClientPublicKey());    }     private SecretKey clientKeyExchange(ECDHClientKeyExchange mesg)            throws IOException {         if (debug != null && Debug.isOn("handshake")) {            mesg.print(System.out);        }        return ecdh.getAgreedSecret(mesg.getEncodedPoint());    }     /*     * 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");            }             handshakeHash.setCertificateVerifyAlg(hashAlg);        }         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;    }      /*     * Client writes "finished" at the end of its handshake, after cipher     * spec is changed.   We verify it and then send ours.     *     * When we're resuming a session, we'll have already sent our own     * Finished message so just the verification is needed.     */    private void clientFinished(Finished mesg) throws IOException {        if (debug != null && Debug.isOn("handshake")) {            mesg.print(System.out);        }         /*         * Verify if client did send the certificate when client         * authentication was required, otherwise server should not proceed         */        if (doClientAuth == SSLEngineImpl.clauth_required) {           // get X500Principal of the end-entity certificate for X509-based           // ciphersuites, or Kerberos principal for Kerberos ciphersuites           session.getPeerPrincipal();        }         /*         * Verify if client did send clientCertificateVerify message following         * the client Certificate, otherwise server should not proceed         */        if (needClientVerify) {                fatalSE(Alerts.alert_handshake_failure,                        "client did not send certificate verify message");        }         /*         * Verify the client's message with the "before" digest of messages,         * and forget about continuing to use that digest.         */        boolean verified = mesg.verify(handshakeHash, Finished.CLIENT,            session.getMasterSecret());         if (!verified) {            fatalSE(Alerts.alert_handshake_failure,                        "client 'finished' message doesn't verify");            // NOTREACHED        }         /*         * save client verify data for secure renegotiation         */        if (secureRenegotiation) {            clientVerifyData = mesg.getVerifyData();        }         /*         * OK, it verified.  If we're doing the full handshake, add that         * "Finished" message to the hash of handshake messages, then send         * the change_cipher_spec and Finished message.         */        if (!resumingSession) {            input.digestNow();            sendChangeCipherAndFinish(true);        }         /*         * Update the session cache only after the handshake completed, else         * we're open to an attack against a partially completed handshake.         */        session.setLastAccessedTime(System.currentTimeMillis());        if (!resumingSession && session.isRejoinable()) {            ((SSLSessionContextImpl)sslContext.engineGetServerSessionContext())                .put(session);            if (debug != null && Debug.isOn("session")) {                System.out.println(

Lines 1001–1500 of 1678. Previous lines