Upstream version 10.39.225.0
[platform/framework/web/crosswalk.git] / src / third_party / boringssl / src / ssl / s3_srvr.c
index 7221fb0..0e9c7d5 100644 (file)
 
 #define NETSCAPE_HANG_BUG
 
+#include <assert.h>
 #include <stdio.h>
 #include <string.h>
 
@@ -258,8 +259,6 @@ int ssl3_accept(SSL *s)
                                }
 
                        s->init_num=0;
-                       s->s3->flags &= ~SSL3_FLAGS_SGC_RESTART_DONE;
-                       s->s3->flags &= ~TLS1_FLAGS_SKIP_CERT_VERIFY;
 
                        if (s->state != SSL_ST_RENEGOTIATE)
                                {
@@ -353,7 +352,7 @@ int ssl3_accept(SSL *s)
                                {
                                ret=ssl3_send_server_certificate(s);
                                if (ret <= 0) goto end;
-                               if (s->tlsext_status_expected)
+                               if (s->s3->tmp.certificate_status_expected)
                                        s->state=SSL3_ST_SW_CERT_STATUS_A;
                                else
                                        s->state=SSL3_ST_SW_KEY_EXCH_A;
@@ -471,21 +470,13 @@ int ssl3_accept(SSL *s)
 
                case SSL3_ST_SR_CERT_A:
                case SSL3_ST_SR_CERT_B:
-                       /* Check for second client hello (MS SGC) */
-                       ret = ssl3_check_client_hello(s);
-                       if (ret <= 0)
-                               goto end;
-                       if (ret == 2)
-                               s->state = SSL3_ST_SR_CLNT_HELLO_C;
-                       else {
-                               if (s->s3->tmp.cert_request)
-                                       {
-                                       ret=ssl3_get_client_certificate(s);
-                                       if (ret <= 0) goto end;
-                                       }
-                               s->init_num=0;
-                               s->state=SSL3_ST_SR_KEY_EXCH_A;
-                       }
+                       if (s->s3->tmp.cert_request)
+                               {
+                               ret=ssl3_get_client_certificate(s);
+                               if (ret <= 0) goto end;
+                               }
+                       s->init_num=0;
+                       s->state=SSL3_ST_SR_KEY_EXCH_A;
                        break;
 
                case SSL3_ST_SR_KEY_EXCH_A:
@@ -493,65 +484,8 @@ int ssl3_accept(SSL *s)
                        ret=ssl3_get_client_key_exchange(s);
                        if (ret <= 0)
                                goto end;
-                       if (ret == 2)
-                               {
-                               /* For the ECDH ciphersuites when
-                                * the client sends its ECDH pub key in
-                                * a certificate, the CertificateVerify
-                                * message is not sent.
-                                */
-                               s->init_num = 0;
-                               s->state = SSL3_ST_SR_CHANGE;
-                               }
-                       else if (SSL_USE_SIGALGS(s))
-                               {
-                               s->state=SSL3_ST_SR_CERT_VRFY_A;
-                               s->init_num=0;
-                               if (!s->session->peer)
-                                       break;
-                               /* For sigalgs freeze the handshake buffer
-                                * at this point and digest cached records.
-                                */
-                               if (!s->s3->handshake_buffer)
-                                       {
-                                       OPENSSL_PUT_ERROR(SSL, ssl3_accept, ERR_R_INTERNAL_ERROR);
-                                       return -1;
-                                       }
-                               s->s3->flags |= TLS1_FLAGS_KEEP_HANDSHAKE;
-                               if (!ssl3_digest_cached_records(s))
-                                       return -1;
-                               }
-                       else
-                               {
-                               int offset=0;
-                               int dgst_num;
-
-                               s->state=SSL3_ST_SR_CERT_VRFY_A;
-                               s->init_num=0;
-
-                               /* We need to get hashes here so if there is
-                                * a client cert, it can be verified
-                                * FIXME - digest processing for CertificateVerify
-                                * should be generalized. But it is next step
-                                */
-                               if (s->s3->handshake_buffer)
-                                       if (!ssl3_digest_cached_records(s))
-                                               return -1;
-                               for (dgst_num=0; dgst_num<SSL_MAX_DIGEST;dgst_num++)    
-                                       if (s->s3->handshake_dgst[dgst_num]) 
-                                               {
-                                               int dgst_size;
-
-                                               s->method->ssl3_enc->cert_verify_mac(s,EVP_MD_CTX_type(s->s3->handshake_dgst[dgst_num]),&(s->s3->tmp.cert_verify_md[offset]));
-                                               dgst_size=EVP_MD_CTX_size(s->s3->handshake_dgst[dgst_num]);
-                                               if (dgst_size < 0)
-                                                       {
-                                                       ret = -1;
-                                                       goto end;
-                                                       }
-                                               offset+=dgst_size;
-                                               }               
-                               }
+                       s->state=SSL3_ST_SR_CERT_VRFY_A;
+                       s->init_num=0;
                        break;
 
                case SSL3_ST_SR_CERT_VRFY_A:
@@ -566,9 +500,7 @@ int ssl3_accept(SSL *s)
                case SSL3_ST_SR_CHANGE: {
                        char next_proto_neg = 0;
                        char channel_id = 0;
-# if !defined(OPENSSL_NO_NEXTPROTONEG)
                        next_proto_neg = s->s3->next_proto_neg_seen;
-# endif
                        channel_id = s->s3->tlsext_channel_id_valid;
 
                        /* At this point, the next message must be entirely
@@ -587,7 +519,6 @@ int ssl3_accept(SSL *s)
                        break;
                }
 
-#if !defined(OPENSSL_NO_NEXTPROTONEG)
                case SSL3_ST_SR_NEXT_PROTO_A:
                case SSL3_ST_SR_NEXT_PROTO_B:
                        ret=ssl3_get_next_proto(s);
@@ -598,7 +529,6 @@ int ssl3_accept(SSL *s)
                        else
                                s->state=SSL3_ST_SR_FINISHED_A;
                        break;
-#endif
 
                case SSL3_ST_SR_CHANNEL_ID_A:
                case SSL3_ST_SR_CHANNEL_ID_B:
@@ -633,12 +563,14 @@ int ssl3_accept(SSL *s)
 
                case SSL3_ST_SW_SESSION_TICKET_A:
                case SSL3_ST_SW_SESSION_TICKET_B:
-                       ret=ssl3_send_newsession_ticket(s);
+                       ret=ssl3_send_new_session_ticket(s);
                        if (ret <= 0) goto end;
                        s->state=SSL3_ST_SW_CHANGE_A;
                        s->init_num=0;
                        break;
 
+#if 0
+               // TODO(davidben): Implement OCSP stapling on the server.
                case SSL3_ST_SW_CERT_STATUS_A:
                case SSL3_ST_SW_CERT_STATUS_B:
                        ret=ssl3_send_cert_status(s);
@@ -646,6 +578,7 @@ int ssl3_accept(SSL *s)
                        s->state=SSL3_ST_SW_KEY_EXCH_A;
                        s->init_num=0;
                        break;
+#endif
 
                case SSL3_ST_SW_CHANGE_A:
                case SSL3_ST_SW_CHANGE_B:
@@ -771,57 +704,11 @@ int ssl3_send_hello_request(SSL *s)
        return ssl_do_write(s);
        }
 
-int ssl3_check_client_hello(SSL *s)
-       {
-       int ok;
-       long n;
-
-       /* this function is called when we really expect a Certificate message,
-        * so permit appropriate message length */
-       n=s->method->ssl_get_message(s,
-               SSL3_ST_SR_CERT_A,
-               SSL3_ST_SR_CERT_B,
-               -1,
-               s->max_cert_list,
-               &ok);
-       if (!ok) return((int)n);
-       s->s3->tmp.reuse_message = 1;
-       if (s->s3->tmp.message_type == SSL3_MT_CLIENT_HELLO)
-               {
-               /* We only allow the client to restart the handshake once per
-                * negotiation. */
-               if (s->s3->flags & SSL3_FLAGS_SGC_RESTART_DONE)
-                       {
-                       OPENSSL_PUT_ERROR(SSL, ssl3_check_client_hello, SSL_R_MULTIPLE_SGC_RESTARTS);
-                       return -1;
-                       }
-               /* Throw away what we have done so far in the current handshake,
-                * which will now be aborted. (A full SSL_clear would be too much.) */
-#ifndef OPENSSL_NO_DH
-               if (s->s3->tmp.dh != NULL)
-                       {
-                       DH_free(s->s3->tmp.dh);
-                       s->s3->tmp.dh = NULL;
-                       }
-#endif
-#ifndef OPENSSL_NO_ECDH
-               if (s->s3->tmp.ecdh != NULL)
-                       {
-                       EC_KEY_free(s->s3->tmp.ecdh);
-                       s->s3->tmp.ecdh = NULL;
-                       }
-#endif
-               s->s3->flags |= SSL3_FLAGS_SGC_RESTART_DONE;
-               return 2;
-               }
-       return 1;
-}
-
 int ssl3_get_client_hello(SSL *s)
        {
        int i,ok,al=SSL_AD_INTERNAL_ERROR,ret= -1;
        long n;
-       SSL_CIPHER *c;
+       const SSL_CIPHER *c;
        STACK_OF(SSL_CIPHER) *ciphers=NULL;
        struct ssl_early_callback_ctx early_ctx;
        CBS client_hello;
@@ -843,6 +730,7 @@ int ssl3_get_client_hello(SSL *s)
                        SSL3_ST_SR_CLNT_HELLO_B,
                        SSL3_MT_CLIENT_HELLO,
                        SSL3_RT_MAX_PLAIN_LENGTH,
+                       SSL_GET_MESSAGE_HASH_MESSAGE,
                        &ok);
 
                if (!ok) return((int)n);
@@ -1010,8 +898,7 @@ int ssl3_get_client_hello(SSL *s)
                        if (s->ctx->app_verify_cookie_cb != NULL)
                                {
                                if (s->ctx->app_verify_cookie_cb(s,
-                                               (unsigned char*)CBS_data(&cookie),
-                                               CBS_len(&cookie)) == 0)
+                                               CBS_data(&cookie), CBS_len(&cookie)) == 0)
                                        {
                                        al=SSL_AD_HANDSHAKE_FAILURE;
                                        OPENSSL_PUT_ERROR(SSL, ssl3_get_client_hello, SSL_R_COOKIE_MISMATCH);
@@ -1040,13 +927,6 @@ int ssl3_get_client_hello(SSL *s)
                                s->version = DTLS1_2_VERSION;
                                s->method = DTLSv1_2_server_method();
                                }
-                       else if (tls1_suiteb(s))
-                               {
-                               OPENSSL_PUT_ERROR(SSL, ssl3_get_client_hello, SSL_R_ONLY_DTLS_1_2_ALLOWED_IN_SUITEB_MODE);
-                               s->version = s->client_version;
-                               al = SSL_AD_PROTOCOL_VERSION;
-                               goto f_err;
-                               }
                        else if (s->client_version <= DTLS1_VERSION &&
                                !(s->options & SSL_OP_NO_DTLSv1))
                                {
@@ -1160,7 +1040,7 @@ int ssl3_get_client_hello(SSL *s)
 
        if (!s->hit && s->version >= TLS1_VERSION && s->tls_session_secret_cb)
                {
-               SSL_CIPHER *pref_cipher=NULL;
+               const SSL_CIPHER *pref_cipher=NULL;
 
                s->session->master_key_length=sizeof(s->session->master_key);
                if(s->tls_session_secret_cb(s, s->session->master_key, &s->session->master_key_length,
@@ -1260,16 +1140,6 @@ int ssl3_get_client_hello(SSL *s)
         * s->tmp.new_cipher    - the new cipher to use.
         */
 
-       /* Handles TLS extensions that we couldn't check earlier */
-       if (s->version >= SSL3_VERSION)
-               {
-               if (ssl_check_clienthello_tlsext_late(s) <= 0)
-                       {
-                       OPENSSL_PUT_ERROR(SSL, ssl3_get_client_hello, SSL_R_CLIENTHELLO_TLSEXT);
-                       goto err;
-                       }
-               }
-
        if (ret < 0) ret=-ret;
        if (0)
                {
@@ -1399,16 +1269,12 @@ int ssl3_send_server_key_exchange(SSL *s)
        int j,num;
        unsigned char md_buf[MD5_DIGEST_LENGTH+SHA_DIGEST_LENGTH];
        unsigned int u;
-#ifndef OPENSSL_NO_DH
        DH *dh=NULL,*dhp;
-#endif
-#ifndef OPENSSL_NO_ECDH
        EC_KEY *ecdh=NULL, *ecdhp;
        unsigned char *encodedPoint = NULL;
        int encodedlen = 0;
        int curve_id = 0;
        BN_CTX *bn_ctx = NULL; 
-#endif
        const char* psk_identity_hint = NULL;
        size_t psk_identity_hint_len = 0;
        EVP_PKEY *pkey;
@@ -1445,7 +1311,6 @@ int ssl3_send_server_key_exchange(SSL *s)
                                psk_identity_hint_len = 0;
                        n+=2+psk_identity_hint_len;
                        }
-#ifndef OPENSSL_NO_DH
                if (alg_k & SSL_kEDH)
                        {
                        dhp=cert->dh_tmp;
@@ -1497,8 +1362,6 @@ int ssl3_send_server_key_exchange(SSL *s)
                        r[2]=dh->pub_key;
                        }
                else
-#endif
-#ifndef OPENSSL_NO_ECDH
                if (alg_k & SSL_kEECDH)
                        {
                        const EC_GROUP *group;
@@ -1623,7 +1486,6 @@ int ssl3_send_server_key_exchange(SSL *s)
                        r[3]=NULL;
                        }
                else
-#endif /* !OPENSSL_NO_ECDH */
                if (!(alg_k & SSL_kPSK))
                        {
                        al=SSL_AD_HANDSHAKE_FAILURE;
@@ -1680,7 +1542,6 @@ int ssl3_send_server_key_exchange(SSL *s)
                                }
                        }
 
-#ifndef OPENSSL_NO_ECDH
                if (alg_k & SSL_kEECDH)
                        {
                        /* XXX: For now, we only support named (not generic) curves.
@@ -1704,7 +1565,6 @@ int ssl3_send_server_key_exchange(SSL *s)
                        encodedPoint = NULL;
                        p += encodedlen;
                        }
-#endif /* OPENSSL_NO_ECDH */
 
                /* not anonymous */
                if (pkey != NULL)
@@ -1717,8 +1577,8 @@ int ssl3_send_server_key_exchange(SSL *s)
                                j=0;
                                for (num=2; num > 0; num--)
                                        {
-                                       EVP_DigestInit_ex(&md_ctx,(num == 2)
-                                               ?s->ctx->md5:s->ctx->sha1, NULL);
+                                       EVP_DigestInit_ex(&md_ctx,
+                                               (num == 2) ? EVP_md5() : EVP_sha1(), NULL);
                                        EVP_DigestUpdate(&md_ctx,&(s->s3->client_random[0]),SSL3_RANDOM_SIZE);
                                        EVP_DigestUpdate(&md_ctx,&(s->s3->server_random[0]),SSL3_RANDOM_SIZE);
                                        EVP_DigestUpdate(&md_ctx,d,n);
@@ -1788,10 +1648,8 @@ int ssl3_send_server_key_exchange(SSL *s)
 f_err:
        ssl3_send_alert(s,SSL3_AL_FATAL,al);
 err:
-#ifndef OPENSSL_NO_ECDH
        if (encodedPoint != NULL) OPENSSL_free(encodedPoint);
        BN_CTX_free(bn_ctx);
-#endif
        EVP_MD_CTX_cleanup(&md_ctx);
        return(-1);
        }
@@ -1893,29 +1751,25 @@ int ssl3_get_client_key_exchange(SSL *s)
        unsigned long alg_a;
        uint8_t *premaster_secret = NULL;
        size_t premaster_secret_len = 0;
-       int skip_certificate_verify = 0;
        RSA *rsa=NULL;
        uint8_t *decrypt_buf = NULL;
        EVP_PKEY *pkey=NULL;
-#ifndef OPENSSL_NO_DH
        BIGNUM *pub=NULL;
-       DH *dh_srvr, *dh_clnt = NULL;
-#endif
+       DH *dh_srvr;
 
-#ifndef OPENSSL_NO_ECDH
        EC_KEY *srvr_ecdh = NULL;
        EVP_PKEY *clnt_pub_pkey = NULL;
        EC_POINT *clnt_ecpoint = NULL;
        BN_CTX *bn_ctx = NULL;
        unsigned int psk_len = 0;
        unsigned char psk[PSK_MAX_PSK_LEN];
-#endif
 
        n=s->method->ssl_get_message(s,
                SSL3_ST_SR_KEY_EXCH_A,
                SSL3_ST_SR_KEY_EXCH_B,
                SSL3_MT_CLIENT_KEY_EXCHANGE,
                2048, /* ??? */
+               SSL_GET_MESSAGE_HASH_MESSAGE,
                &ok);
 
        if (!ok) return((int)n);
@@ -1980,8 +1834,7 @@ int ssl3_get_client_key_exchange(SSL *s)
                }
 
        /* Depending on the key exchange method, compute |premaster_secret| and
-        * |premaster_secret_len|. Also, for DH and ECDH, set
-        * |skip_certificate_verify| as appropriate. */
+        * |premaster_secret_len|. */
        if (alg_k & SSL_kRSA)
                {
                CBS encrypted_premaster_secret;
@@ -2001,12 +1854,7 @@ int ssl3_get_client_key_exchange(SSL *s)
                        }
                rsa=pkey->pkey.rsa;
 
-               /* TLS and [incidentally] DTLS{0xFEFF}
-                *
-                * TODO(davidben): Should this (and
-                * ssl3_send_client_key_exchange) include DTLS1_BAD_VER?
-                * Alternatively, get rid of DTLS1_BAD_VER?
-                */
+               /* TLS and [incidentally] DTLS{0xFEFF} */
                if (s->version > SSL3_VERSION)
                        {
                        CBS copy = client_key_exchange;
@@ -2111,36 +1959,6 @@ int ssl3_get_client_key_exchange(SSL *s)
                version_good = premaster_secret[0] ^ (s->client_version>>8);
                version_good |= premaster_secret[1] ^ (s->client_version&0xff);
 
-               /* The premaster secret must contain the same version number as
-                * the ClientHello to detect version rollback attacks
-                * (strangely, the protocol does not offer such protection for
-                * DH ciphersuites). However, buggy clients exist that send the
-                * negotiated protocol version instead if the server does not
-                * support the requested protocol version. If
-                * SSL_OP_TLS_ROLLBACK_BUG is set, tolerate such clients. */
-               if (s->options & SSL_OP_TLS_ROLLBACK_BUG)
-                       {
-                       unsigned char workaround_mask = version_good;
-                       unsigned char workaround;
-
-                       /* workaround_mask will be 0xff if version_good is
-                        * non-zero (i.e. the version match failed). Otherwise
-                        * it'll be 0x00. */
-                       workaround_mask |= workaround_mask >> 4;
-                       workaround_mask |= workaround_mask >> 2;
-                       workaround_mask |= workaround_mask >> 1;
-                       workaround_mask = ~((workaround_mask & 1) - 1);
-
-                       workaround = premaster_secret[0] ^ (s->version>>8);
-                       workaround |= premaster_secret[1] ^ (s->version&0xff);
-
-                       /* If workaround_mask is 0xff (i.e. there was a version
-                        * mismatch) then we copy the value of workaround over
-                        * version_good. */
-                       version_good = (workaround & workaround_mask) |
-                                      (version_good & ~workaround_mask);
-                       }
-
                /* If any bits in version_good are set then they'll poision
                 * decrypt_good_mask and cause rand_premaster_secret to be
                 * used. */
@@ -2173,15 +1991,13 @@ int ssl3_get_client_key_exchange(SSL *s)
 
                premaster_secret_len = sizeof(rand_premaster_secret);
                }
-#ifndef OPENSSL_NO_DH
-       else if (alg_k & (SSL_kEDH|SSL_kDHr|SSL_kDHd))
+       else if (alg_k & SSL_kEDH)
                {
                CBS dh_Yc;
-               int idx = -1;
                int dh_len;
-               EVP_PKEY *skey = NULL;
 
                if (!CBS_get_u16_length_prefixed(&client_key_exchange, &dh_Yc) ||
+                       CBS_len(&dh_Yc) == 0 ||
                        CBS_len(&client_key_exchange) != 0)
                        {
                        OPENSSL_PUT_ERROR(SSL, ssl3_get_client_key_exchange, SSL_R_DH_PUBLIC_VALUE_LENGTH_IS_WRONG);
@@ -2189,59 +2005,15 @@ int ssl3_get_client_key_exchange(SSL *s)
                        goto f_err;
                        }
 
-               if (alg_k & SSL_kDHr)
-                       idx = SSL_PKEY_DH_RSA;
-               else if (alg_k & SSL_kDHd)
-                       idx = SSL_PKEY_DH_DSA;
-               if (idx >= 0)
-                       {
-                       skey = s->cert->pkeys[idx].privatekey;
-                       if ((skey == NULL) ||
-                               (skey->type != EVP_PKEY_DH) ||
-                               (skey->pkey.dh == NULL))
-                               {
-                               al=SSL_AD_HANDSHAKE_FAILURE;
-                               OPENSSL_PUT_ERROR(SSL, ssl3_get_client_key_exchange, SSL_R_MISSING_RSA_CERTIFICATE);
-                               goto f_err;
-                               }
-                       dh_srvr = skey->pkey.dh;
-                       }
-               else if (s->s3->tmp.dh == NULL)
+               if (s->s3->tmp.dh == NULL)
                        {
                        al=SSL_AD_HANDSHAKE_FAILURE;
                        OPENSSL_PUT_ERROR(SSL, ssl3_get_client_key_exchange, SSL_R_MISSING_TMP_DH_KEY);
                        goto f_err;
                        }
-               else
-                       dh_srvr=s->s3->tmp.dh;
+                dh_srvr=s->s3->tmp.dh;
 
-               if (CBS_len(&dh_Yc) == 0)
-                       {
-                       /* Get pubkey from the client certificate. This is the
-                        * 'implicit' case of ClientDiffieHellman.
-                        *
-                        * TODO(davidben): Either lose this code or fix a bug
-                        * (or get the spec changed): if there is a fixed_dh
-                        * client certificate, per spec, the 'implicit' mode
-                        * MUST be used. This logic will still accept 'explicit'
-                        * mode. */
-                       EVP_PKEY *clkey=X509_get_pubkey(s->session->peer);
-                       if (clkey)
-                               {
-                               if (EVP_PKEY_cmp_parameters(clkey, skey) == 1)
-                                       dh_clnt = EVP_PKEY_get1_DH(clkey);
-                               }
-                       if (dh_clnt == NULL)
-                               {
-                               al=SSL_AD_HANDSHAKE_FAILURE;
-                               OPENSSL_PUT_ERROR(SSL, ssl3_get_client_key_exchange, SSL_R_MISSING_TMP_DH_KEY);
-                               goto f_err;
-                               }
-                       EVP_PKEY_free(clkey);
-                       pub = dh_clnt->pub_key;
-                       }
-               else
-                       pub = BN_bin2bn(CBS_data(&dh_Yc), CBS_len(&dh_Yc), NULL);
+               pub = BN_bin2bn(CBS_data(&dh_Yc), CBS_len(&dh_Yc), NULL);
                if (pub == NULL)
                        {
                        OPENSSL_PUT_ERROR(SSL, ssl3_get_client_key_exchange, SSL_R_BN_LIB);
@@ -2266,25 +2038,19 @@ int ssl3_get_client_key_exchange(SSL *s)
 
                DH_free(s->s3->tmp.dh);
                s->s3->tmp.dh=NULL;
-               if (dh_clnt)
-                       DH_free(dh_clnt);
-               else
-                       BN_clear_free(pub);
+               BN_clear_free(pub);
                pub=NULL;
 
                premaster_secret_len = dh_len;
-               if (dh_clnt)
-                       skip_certificate_verify = 1;
                }
-#endif
 
-#ifndef OPENSSL_NO_ECDH
-       else if (alg_k & (SSL_kEECDH|SSL_kECDHr|SSL_kECDHe))
+       else if (alg_k & SSL_kEECDH)
                {
                int field_size = 0, ecdh_len;
                const EC_KEY   *tkey;
                const EC_GROUP *group;
                const BIGNUM *priv_key;
+               CBS ecdh_Yc;
 
                /* initialize structures for server's ECDH key pair */
                if ((srvr_ecdh = EC_KEY_new()) == NULL) 
@@ -2293,19 +2059,9 @@ int ssl3_get_client_key_exchange(SSL *s)
                        goto err;
                        }
 
-               /* Let's get server private key and group information */
-               if (alg_k & (SSL_kECDHr|SSL_kECDHe))
-                       { 
-                       /* use the certificate */
-                       tkey = s->cert->pkeys[SSL_PKEY_ECC].privatekey->pkey.ec;
-                       }
-               else
-                       {
-                       /* use the ephermeral values we saved when
-                        * generating the ServerKeyExchange msg.
-                        */
-                       tkey = s->s3->tmp.ecdh;
-                       }
+                /* Use the ephermeral values we saved when generating the
+                 * ServerKeyExchange msg. */
+                tkey = s->s3->tmp.ecdh;
 
                group    = EC_KEY_get0_group(tkey);
                priv_key = EC_KEY_get0_private_key(tkey);
@@ -2324,72 +2080,28 @@ int ssl3_get_client_key_exchange(SSL *s)
                        goto err;
                        }
 
-               if (CBS_len(&client_key_exchange) == 0)
+               /* Get client's public key from encoded point
+                * in the ClientKeyExchange message.
+                */
+               if (!CBS_get_u8_length_prefixed(&client_key_exchange, &ecdh_Yc) ||
+                       CBS_len(&client_key_exchange) != 0)
                        {
-                       /* Client Publickey was in Client Certificate */
-
-                        if (alg_k & SSL_kEECDH)
-                                {
-                                al=SSL_AD_HANDSHAKE_FAILURE;
-                                OPENSSL_PUT_ERROR(SSL, ssl3_get_client_key_exchange, SSL_R_MISSING_TMP_ECDH_KEY);
-                                goto f_err;
-                                }
-                       if (((clnt_pub_pkey=X509_get_pubkey(s->session->peer))
-                           == NULL) || 
-                           (clnt_pub_pkey->type != EVP_PKEY_EC))
-                               {
-                               /* XXX: For now, we do not support client
-                                * authentication using ECDH certificates
-                                * so this branch (n == 0L) of the code is
-                                * never executed. When that support is
-                                * added, we ought to ensure the key 
-                                * received in the certificate is 
-                                * authorized for key agreement.
-                                * ECDH_compute_key implicitly checks that
-                                * the two ECDH shares are for the same
-                                * group.
-                                */
-                               al=SSL_AD_HANDSHAKE_FAILURE;
-                               OPENSSL_PUT_ERROR(SSL, ssl3_get_client_key_exchange, SSL_R_UNABLE_TO_DECODE_ECDH_CERTS);
-                               goto f_err;
-                               }
-
-                       if (EC_POINT_copy(clnt_ecpoint,
-                           EC_KEY_get0_public_key(clnt_pub_pkey->pkey.ec)) == 0)
-                               {
-                               OPENSSL_PUT_ERROR(SSL, ssl3_get_client_key_exchange, ERR_R_EC_LIB);
-                               goto err;
-                               }
-                       /* Skip certificate verify processing */
-                       skip_certificate_verify = 1;
+                       al = SSL_AD_DECODE_ERROR;
+                       OPENSSL_PUT_ERROR(SSL, ssl3_get_client_key_exchange, SSL_R_DECODE_ERROR);
+                       goto f_err;
                        }
-               else
-                       {
-                       CBS ecdh_Yc;
-
-                       /* Get client's public key from encoded point
-                        * in the ClientKeyExchange message.
-                        */
-                       if (!CBS_get_u8_length_prefixed(&client_key_exchange, &ecdh_Yc) ||
-                               CBS_len(&client_key_exchange) != 0)
-                               {
-                               al = SSL_AD_DECODE_ERROR;
-                               OPENSSL_PUT_ERROR(SSL, ssl3_get_client_key_exchange, SSL_R_DECODE_ERROR);
-                               goto f_err;
-                               }
 
-                       if ((bn_ctx = BN_CTX_new()) == NULL)
-                               {
-                               OPENSSL_PUT_ERROR(SSL, ssl3_get_client_key_exchange, ERR_R_MALLOC_FAILURE);
-                               goto err;
-                               }
+               if ((bn_ctx = BN_CTX_new()) == NULL)
+                       {
+                       OPENSSL_PUT_ERROR(SSL, ssl3_get_client_key_exchange, ERR_R_MALLOC_FAILURE);
+                       goto err;
+                       }
 
-                       if (!EC_POINT_oct2point(group, clnt_ecpoint,
-                                       CBS_data(&ecdh_Yc), CBS_len(&ecdh_Yc), bn_ctx))
-                               {
-                               OPENSSL_PUT_ERROR(SSL, ssl3_get_client_key_exchange, ERR_R_EC_LIB);
-                               goto err;
-                               }
+               if (!EC_POINT_oct2point(group, clnt_ecpoint,
+                               CBS_data(&ecdh_Yc), CBS_len(&ecdh_Yc), bn_ctx))
+                       {
+                       OPENSSL_PUT_ERROR(SSL, ssl3_get_client_key_exchange, ERR_R_EC_LIB);
+                       goto err;
                        }
 
                /* Allocate a buffer for both the secret and the PSK. */
@@ -2426,7 +2138,6 @@ int ssl3_get_client_key_exchange(SSL *s)
 
                premaster_secret_len = ecdh_len;
                }
-#endif
        else if (alg_k & SSL_kPSK)
                {
                /* For plain PSK, other_secret is a block of 0s with the same
@@ -2484,7 +2195,7 @@ int ssl3_get_client_key_exchange(SSL *s)
 
        OPENSSL_cleanse(premaster_secret, premaster_secret_len);
        OPENSSL_free(premaster_secret);
-       return skip_certificate_verify ? 2 : 1;
+       return 1;
 f_err:
        ssl3_send_alert(s,SSL3_AL_FATAL,al);
 err:
@@ -2496,41 +2207,34 @@ err:
                }
        if (decrypt_buf)
                OPENSSL_free(decrypt_buf);
-#ifndef OPENSSL_NO_ECDH
        EVP_PKEY_free(clnt_pub_pkey);
        EC_POINT_free(clnt_ecpoint);
        if (srvr_ecdh != NULL) 
                EC_KEY_free(srvr_ecdh);
        BN_CTX_free(bn_ctx);
-#endif
        return(-1);
        }
 
 int ssl3_get_cert_verify(SSL *s)
        {
-       EVP_PKEY *pkey=NULL;
        int al,ok,ret=0;
        long n;
        CBS certificate_verify, signature;
-       int type = 0;
        X509 *peer = s->session->peer;
+       EVP_PKEY *pkey = NULL;
        const EVP_MD *md = NULL;
-       EVP_MD_CTX mctx;
-
-       EVP_MD_CTX_init(&mctx);
+       uint8_t digest[EVP_MAX_MD_SIZE];
+       size_t digest_length;
+       EVP_PKEY_CTX *pctx = NULL;
 
-       /* Determine if a CertificateVerify message is expected at all. It is
-        * important that this be determined before ssl_get_message is called,
-        * so as not to process the ChangeCipherSpec message early. */
-       if (peer != NULL)
-               {
-               pkey = X509_get_pubkey(peer);
-               type = X509_certificate_type(peer,pkey);
-               }
-       if (!(type & EVP_PKT_SIGN))
+       /* Only RSA and ECDSA client certificates are supported, so a
+        * CertificateVerify is required if and only if there's a
+        * client certificate. */
+       if (peer == NULL)
                {
-               ret = 1;
-               goto done_with_buffer;
+               if (s->s3->handshake_buffer && !ssl3_digest_cached_records(s))
+                       return -1;
+               return 1;
                }
 
        n=s->method->ssl_get_message(s,
@@ -2538,26 +2242,42 @@ int ssl3_get_cert_verify(SSL *s)
                SSL3_ST_SR_CERT_VRFY_B,
                SSL3_MT_CERTIFICATE_VERIFY,
                SSL3_RT_MAX_PLAIN_LENGTH,
+               SSL_GET_MESSAGE_DONT_HASH_MESSAGE,
                &ok);
 
        if (!ok)
+               return (int)n;
+
+       /* Filter out unsupported certificate types. */
+       pkey = X509_get_pubkey(peer);
+       if (!(X509_certificate_type(peer, pkey) & EVP_PKT_SIGN) ||
+               (pkey->type != EVP_PKEY_RSA && pkey->type != EVP_PKEY_EC))
                {
-               ret = (int)n;
-               goto done;
+               al = SSL_AD_UNSUPPORTED_CERTIFICATE;
+               OPENSSL_PUT_ERROR(SSL, ssl3_get_cert_verify, SSL_R_PEER_ERROR_UNSUPPORTED_CERTIFICATE_TYPE);
+               goto f_err;
                }
 
        CBS_init(&certificate_verify, s->init_msg, n);
 
-       /* We now have a signature that we need to verify. */
-       /* TODO(davidben): This should share code with
-        * ssl3_get_server_key_exchange. */
-
+       /* Determine the digest type if needbe. */
        if (SSL_USE_SIGALGS(s))
                {
                if (!tls12_check_peer_sigalg(&md, &al, s, &certificate_verify, pkey))
                        goto f_err;
                }
 
+       /* Compute the digest. */
+       if (!ssl3_cert_verify_hash(s, digest, &digest_length, &md, pkey))
+               goto err;
+
+       /* The handshake buffer is no longer necessary, and we may hash the
+        * current message.*/
+       if (s->s3->handshake_buffer && !ssl3_digest_cached_records(s))
+               goto err;
+       ssl3_hash_current_message(s);
+
+       /* Parse and verify the signature. */
        if (!CBS_get_u16_length_prefixed(&certificate_verify, &signature) ||
                CBS_len(&certificate_verify) != 0)
                {
@@ -2566,104 +2286,27 @@ int ssl3_get_cert_verify(SSL *s)
                goto f_err;
                }
 
-       if (SSL_USE_SIGALGS(s))
-               {
-               size_t hdatalen;
-               const uint8_t *hdata;
-               if (!BIO_mem_contents(s->s3->handshake_buffer, &hdata, &hdatalen))
-                       {
-                       OPENSSL_PUT_ERROR(SSL, ssl3_get_cert_verify, ERR_R_INTERNAL_ERROR);
-                       al=SSL_AD_INTERNAL_ERROR;
-                       goto f_err;
-                       }
-               if (!EVP_VerifyInit_ex(&mctx, md, NULL)
-                       || !EVP_VerifyUpdate(&mctx, hdata, hdatalen))
-                       {
-                       OPENSSL_PUT_ERROR(SSL, ssl3_get_cert_verify, ERR_R_EVP_LIB);
-                       al=SSL_AD_INTERNAL_ERROR;
-                       goto f_err;
-                       }
-
-               if (EVP_VerifyFinal(&mctx,
-                               CBS_data(&signature), CBS_len(&signature),
-                               pkey) <= 0)
-                       {
-                       al=SSL_AD_DECRYPT_ERROR;
-                       OPENSSL_PUT_ERROR(SSL, ssl3_get_cert_verify, SSL_R_BAD_SIGNATURE);
-                       goto f_err;
-                       }
-               }
-       else
-       if (pkey->type == EVP_PKEY_RSA)
-               {
-               if (!RSA_verify(NID_md5_sha1, s->s3->tmp.cert_verify_md,
-                               MD5_DIGEST_LENGTH+SHA_DIGEST_LENGTH,
-                               CBS_data(&signature), CBS_len(&signature),
-                               pkey->pkey.rsa))
-                       {
-                       al = SSL_AD_DECRYPT_ERROR;
-                       OPENSSL_PUT_ERROR(SSL, ssl3_get_cert_verify, SSL_R_BAD_RSA_SIGNATURE);
-                       goto f_err;
-                       }
-               }
-       else
-#ifndef OPENSSL_NO_DSA
-               if (pkey->type == EVP_PKEY_DSA)
-               {
-               if (DSA_verify(pkey->save_type,
-                               &(s->s3->tmp.cert_verify_md[MD5_DIGEST_LENGTH]),
-                               SHA_DIGEST_LENGTH,
-                               CBS_data(&signature), CBS_len(&signature),
-                               pkey->pkey.dsa) <= 0)
-                       {
-                       /* bad signature */
-                       al = SSL_AD_DECRYPT_ERROR;
-                       OPENSSL_PUT_ERROR(SSL, ssl3_get_cert_verify, SSL_R_BAD_DSA_SIGNATURE);
-                       goto f_err;
-                       }
-               }
-       else
-#endif
-#ifndef OPENSSL_NO_ECDSA
-               if (pkey->type == EVP_PKEY_EC)
-               {
-               if (!ECDSA_verify(pkey->save_type,
-                               &(s->s3->tmp.cert_verify_md[MD5_DIGEST_LENGTH]),
-                               SHA_DIGEST_LENGTH,
-                               CBS_data(&signature), CBS_len(&signature),
-                               pkey->pkey.ec))
-                       {
-                       /* bad signature */
-                       al = SSL_AD_DECRYPT_ERROR;
-                       OPENSSL_PUT_ERROR(SSL, ssl3_get_cert_verify, SSL_R_BAD_ECDSA_SIGNATURE);
-                       goto f_err;
-                       }
-               }
-       else
-#endif
+       pctx = EVP_PKEY_CTX_new(pkey, NULL);
+       if (pctx == NULL)
+               goto err;
+       if (!EVP_PKEY_verify_init(pctx) ||
+               !EVP_PKEY_CTX_set_signature_md(pctx, md) ||
+               !EVP_PKEY_verify(pctx, CBS_data(&signature), CBS_len(&signature),
+                       digest, digest_length))
                {
-               OPENSSL_PUT_ERROR(SSL, ssl3_get_cert_verify, ERR_R_INTERNAL_ERROR);
-               al=SSL_AD_UNSUPPORTED_CERTIFICATE;
+               al = SSL_AD_DECRYPT_ERROR;
+               OPENSSL_PUT_ERROR(SSL, ssl3_get_cert_verify, SSL_R_BAD_SIGNATURE);
                goto f_err;
                }
 
-
-       ret=1;
+       ret = 1;
        if (0)
                {
 f_err:
                ssl3_send_alert(s,SSL3_AL_FATAL,al);
                }
-done_with_buffer:
-       /* There is no more need for the handshake buffer. */
-       if (s->s3->handshake_buffer)
-               {
-               BIO_free(s->s3->handshake_buffer);
-               s->s3->handshake_buffer = NULL;
-               s->s3->flags &= ~TLS1_FLAGS_KEEP_HANDSHAKE;
-               }
-done:
-       EVP_MD_CTX_cleanup(&mctx);
+err:
+       EVP_PKEY_CTX_free(pctx);
        EVP_PKEY_free(pkey);
        return(ret);
        }
@@ -2683,6 +2326,7 @@ int ssl3_get_client_certificate(SSL *s)
                SSL3_ST_SR_CERT_B,
                -1,
                s->max_cert_list,
+               SSL_GET_MESSAGE_HASH_MESSAGE,
                &ok);
 
        if (!ok) return((int)n);
@@ -2873,7 +2517,7 @@ int ssl3_send_server_certificate(SSL *s)
        }
 
 /* send a new session ticket (not necessarily for a new session) */
-int ssl3_send_newsession_ticket(SSL *s)
+int ssl3_send_new_session_ticket(SSL *s)
        {
        if (s->state == SSL3_ST_SW_SESSION_TICKET_A)
                {
@@ -3000,6 +2644,7 @@ int ssl3_send_newsession_ticket(SSL *s)
        return ssl_do_write(s);
        }
 
+#if 0
 int ssl3_send_cert_status(SSL *s)
        {
        if (s->state == SSL3_ST_SW_CERT_STATUS_A)
@@ -3034,8 +2679,8 @@ int ssl3_send_cert_status(SSL *s)
        /* SSL3_ST_SW_CERT_STATUS_B */
        return(ssl3_do_write(s,SSL3_RT_HANDSHAKE));
        }
+#endif
 
-# ifndef OPENSSL_NO_NEXTPROTONEG
 /* ssl3_get_next_proto reads a Next Protocol Negotiation handshake message. It
  * sets the next_proto member in s if found */
 int ssl3_get_next_proto(SSL *s)
@@ -3057,6 +2702,7 @@ int ssl3_get_next_proto(SSL *s)
                SSL3_ST_SR_NEXT_PROTO_B,
                SSL3_MT_NEXT_PROTO,
                514,  /* See the payload format below */
+               SSL_GET_MESSAGE_HASH_MESSAGE,
                &ok);
 
        if (!ok)
@@ -3093,13 +2739,15 @@ int ssl3_get_next_proto(SSL *s)
 
        return 1;
        }
-# endif
 
 /* ssl3_get_channel_id reads and verifies a ClientID handshake message. */
 int ssl3_get_channel_id(SSL *s)
        {
        int ret = -1, ok;
        long n;
+       EVP_MD_CTX md_ctx;
+       uint8_t channel_id_hash[SHA256_DIGEST_LENGTH];
+       unsigned int channel_id_hash_len;
        const uint8_t *p;
        uint16_t extension_type, expected_extension_type;
        EC_GROUP* p256 = NULL;
@@ -3109,33 +2757,32 @@ int ssl3_get_channel_id(SSL *s)
        BIGNUM x, y;
        CBS encrypted_extensions, extension;
 
-       if (s->state == SSL3_ST_SR_CHANNEL_ID_A && s->init_num == 0)
-               {
-               /* The first time that we're called we take the current
-                * handshake hash and store it. */
-               EVP_MD_CTX md_ctx;
-               unsigned int len;
-
-               EVP_MD_CTX_init(&md_ctx);
-               EVP_DigestInit_ex(&md_ctx, EVP_sha256(), NULL);
-               if (!tls1_channel_id_hash(&md_ctx, s))
-                       return -1;
-               len = sizeof(s->s3->tlsext_channel_id);
-               EVP_DigestFinal(&md_ctx, s->s3->tlsext_channel_id, &len);
-               EVP_MD_CTX_cleanup(&md_ctx);
-               }
-
        n = s->method->ssl_get_message(s,
                SSL3_ST_SR_CHANNEL_ID_A,
                SSL3_ST_SR_CHANNEL_ID_B,
                SSL3_MT_ENCRYPTED_EXTENSIONS,
                2 + 2 + TLSEXT_CHANNEL_ID_SIZE,
+               SSL_GET_MESSAGE_DONT_HASH_MESSAGE,
                &ok);
 
        if (!ok)
                return((int)n);
 
-       ssl3_finish_mac(s, (unsigned char*)s->init_buf->data, s->init_num + 4);
+       /* Before incorporating the EncryptedExtensions message to the
+        * handshake hash, compute the hash that should have been signed. */
+       channel_id_hash_len = sizeof(channel_id_hash);
+       EVP_MD_CTX_init(&md_ctx);
+       if (!EVP_DigestInit_ex(&md_ctx, EVP_sha256(), NULL) ||
+               !tls1_channel_id_hash(&md_ctx, s) ||
+               !EVP_DigestFinal(&md_ctx, channel_id_hash, &channel_id_hash_len))
+               {
+               EVP_MD_CTX_cleanup(&md_ctx);
+               return -1;
+               }
+       EVP_MD_CTX_cleanup(&md_ctx);
+       assert(channel_id_hash_len == SHA256_DIGEST_LENGTH);
+
+       ssl3_hash_current_message(s);
 
        /* s->state doesn't reflect whether ChangeCipherSpec has been received
         * in this handshake, but s->s3->change_cipher_spec does (will be reset
@@ -3208,17 +2855,12 @@ int ssl3_get_channel_id(SSL *s)
 
        /* We stored the handshake hash in |tlsext_channel_id| the first time
         * that we were called. */
-       switch (ECDSA_do_verify(s->s3->tlsext_channel_id, SHA256_DIGEST_LENGTH, &sig, key)) {
-       case 1:
-               break;
-       case 0:
+       if (!ECDSA_do_verify(channel_id_hash, channel_id_hash_len, &sig, key))
+               {
                OPENSSL_PUT_ERROR(SSL, ssl3_get_channel_id, SSL_R_CHANNEL_ID_SIGNATURE_INVALID);
                s->s3->tlsext_channel_id_valid = 0;
                goto err;
-       default:
-               s->s3->tlsext_channel_id_valid = 0;
-               goto err;
-       }
+               }
 
        memcpy(s->s3->tlsext_channel_id, p, 64);
        ret = 1;