Remove all RFC5878 code.
[openssl.git] / ssl / s3_clnt.c
index 5adbb50485b435f91b24099afbea91c321cdd8b4..9a94de00d8492a292995a90b3f0c45b1fe85e087 100644 (file)
@@ -240,6 +240,13 @@ int ssl3_connect(SSL *s)
                                ret = -1;
                                goto end;
                                }
+
+                       if (!ssl_security(s, SSL_SECOP_VERSION, 0,
+                                                       s->version, NULL))
+                               {
+                               SSLerr(SSL_F_SSL3_CONNECT, SSL_R_VERSION_TOO_LOW);
+                               return -1;
+                               }
                                
                        /* s->version=SSL3_VERSION; */
                        s->type=SSL_ST_CONNECT;
@@ -307,26 +314,10 @@ int ssl3_connect(SSL *s)
                                }
                        else
                                {
-#ifndef OPENSSL_NO_TLSEXT
-                               /* The server hello indicated that
-                                * an audit proof would follow. */
-                               if (s->s3->tlsext_authz_server_promised)
-                                       s->state=SSL3_ST_CR_SUPPLEMENTAL_DATA_A;
-                               else
-#endif
                                        s->state=SSL3_ST_CR_CERT_A;
                                }
                        s->init_num=0;
                        break;
-#ifndef OPENSSL_NO_TLSEXT
-               case SSL3_ST_CR_SUPPLEMENTAL_DATA_A:
-               case SSL3_ST_CR_SUPPLEMENTAL_DATA_B:
-                       ret = tls1_get_server_supplemental_data(s);
-                       if (ret <= 0) goto end;
-                       s->state=SSL3_ST_CR_CERT_A;
-                       s->init_num = 0;
-                       break;
-#endif
                case SSL3_ST_CR_CERT_A:
                case SSL3_ST_CR_CERT_B:
 #ifndef OPENSSL_NO_TLSEXT
@@ -527,6 +518,7 @@ int ssl3_connect(SSL *s)
                                s->method->ssl3_enc->client_finished_label,
                                s->method->ssl3_enc->client_finished_label_len);
                        if (ret <= 0) goto end;
+                       s->s3->flags |= SSL3_FLAGS_CCS_OK;
                        s->state=SSL3_ST_CW_FLUSH;
 
                        /* clear flags */
@@ -576,6 +568,7 @@ int ssl3_connect(SSL *s)
                case SSL3_ST_CR_FINISHED_A:
                case SSL3_ST_CR_FINISHED_B:
 
+                       s->s3->flags |= SSL3_FLAGS_CCS_OK;
                        ret=ssl3_get_finished(s,SSL3_ST_CR_FINISHED_A,
                                SSL3_ST_CR_FINISHED_B);
                        if (ret <= 0) goto end;
@@ -672,7 +665,8 @@ int ssl3_client_hello(SSL *s)
        unsigned char *buf;
        unsigned char *p,*d;
        int i;
-       unsigned long Time,l;
+       unsigned long l;
+       int al = 0;
 #ifndef OPENSSL_NO_COMP
        int j;
        SSL_COMP *comp;
@@ -694,16 +688,69 @@ int ssl3_client_hello(SSL *s)
                        if (!ssl_get_new_session(s,0))
                                goto err;
                        }
+               if (s->method->version == DTLS_ANY_VERSION)
+                       {
+                       /* Determine which DTLS version to use */
+                       int options = s->options;
+                       /* If DTLS 1.2 disabled correct the version number */
+                       if (options & SSL_OP_NO_DTLSv1_2)
+                               {
+                               if (tls1_suiteb(s))
+                                       {
+                                       SSLerr(SSL_F_SSL3_CLIENT_HELLO, SSL_R_ONLY_DTLS_1_2_ALLOWED_IN_SUITEB_MODE);
+                                       goto err;
+                                       }
+                               /* Disabling all versions is silly: return an
+                                * error.
+                                */
+                               if (options & SSL_OP_NO_DTLSv1)
+                                       {
+                                       SSLerr(SSL_F_SSL3_CLIENT_HELLO,SSL_R_WRONG_SSL_VERSION);
+                                       goto err;
+                                       }
+                               /* Update method so we don't use any DTLS 1.2
+                                * features.
+                                */
+                               s->method = DTLSv1_client_method();
+                               s->version = DTLS1_VERSION;
+                               }
+                       else
+                               {
+                               /* We only support one version: update method */
+                               if (options & SSL_OP_NO_DTLSv1)
+                                       s->method = DTLSv1_2_client_method();
+                               s->version = DTLS1_2_VERSION;
+                               }
+                       s->client_version = s->version;
+                       }
                /* else use the pre-loaded session */
 
                p=s->s3->client_random;
-               Time=(unsigned long)time(NULL);                 /* Time */
-               l2n(Time,p);
-               if (RAND_pseudo_bytes(p,SSL3_RANDOM_SIZE-4) <= 0)
-                       goto err;
+
+               /* for DTLS if client_random is initialized, reuse it, we are
+                * required to use same upon reply to HelloVerify */
+               if (SSL_IS_DTLS(s))
+                       {
+                       size_t idx;
+                       i = 1;
+                       for (idx=0; idx < sizeof(s->s3->client_random); idx++)
+                               {
+                               if (p[idx])
+                                       {
+                                       i = 0;
+                                       break;
+                                       }
+                               }
+                       }
+               else 
+                       i = 1;
+
+               if (i)
+                       ssl_fill_hello_random(s, 0, p,
+                                             sizeof(s->s3->client_random));
 
                /* Do the message type and length last */
-               d=p= &(buf[4]);
+               d=p= ssl_handshake_start(s);
 
                /* version indicates the negotiated version: for example from
                 * an SSLv2/v3 compatible client hello). The client_version
@@ -764,6 +811,19 @@ int ssl3_client_hello(SSL *s)
                        p+=i;
                        }
                
+               /* cookie stuff for DTLS */
+               if (SSL_IS_DTLS(s))
+                       {
+                       if ( s->d1->cookie_len > sizeof(s->d1->cookie))
+                               {
+                               SSLerr(SSL_F_SSL3_CLIENT_HELLO, ERR_R_INTERNAL_ERROR);
+                               goto err;
+                               }
+                       *(p++) = s->d1->cookie_len;
+                       memcpy(p, s->d1->cookie, s->d1->cookie_len);
+                       p += s->d1->cookie_len;
+                       }
+               
                /* Ciphers supported */
                i=ssl_cipher_list_to_bytes(s,SSL_get_ciphers(s),&(p[2]),0);
                if (i == 0)
@@ -788,8 +848,7 @@ int ssl3_client_hello(SSL *s)
                *(p++)=1;
 #else
 
-               if ((s->options & SSL_OP_NO_COMPRESSION)
-                                       || !s->ctx->comp_methods)
+               if (!ssl_allow_compression(s) || !s->ctx->comp_methods)
                        j=0;
                else
                        j=sk_SSL_COMP_num(s->ctx->comp_methods);
@@ -809,26 +868,21 @@ int ssl3_client_hello(SSL *s)
                        SSLerr(SSL_F_SSL3_CLIENT_HELLO,SSL_R_CLIENTHELLO_TLSEXT);
                        goto err;
                        }
-               if ((p = ssl_add_clienthello_tlsext(s, p, buf+SSL3_RT_MAX_PLAIN_LENGTH)) == NULL)
+               if ((p = ssl_add_clienthello_tlsext(s, p, buf+SSL3_RT_MAX_PLAIN_LENGTH, &al)) == NULL)
                        {
+                       ssl3_send_alert(s,SSL3_AL_FATAL,al);
                        SSLerr(SSL_F_SSL3_CLIENT_HELLO,ERR_R_INTERNAL_ERROR);
                        goto err;
                        }
 #endif
                
-               l=(p-d);
-               d=buf;
-               *(d++)=SSL3_MT_CLIENT_HELLO;
-               l2n3(l,d);
-
+               l= p-d;
+               ssl_set_handshake_header(s, SSL3_MT_CLIENT_HELLO, l);
                s->state=SSL3_ST_CW_CLNT_HELLO_B;
-               /* number of bytes to write */
-               s->init_num=p-buf;
-               s->init_off=0;
                }
 
        /* SSL3_ST_CW_CLNT_HELLO_B */
-       return(ssl3_do_write(s,SSL3_RT_HANDSHAKE));
+       return ssl_do_write(s);
 err:
        return(-1);
        }
@@ -845,6 +899,11 @@ int ssl3_get_server_hello(SSL *s)
 #ifndef OPENSSL_NO_COMP
        SSL_COMP *comp;
 #endif
+       /* Hello verify request and/or server hello version may not
+        * match so set first packet if we're negotiating version.
+        */
+       if (SSL_IS_DTLS(s))
+               s->first_packet = 1;
 
        n=s->method->ssl_get_message(s,
                SSL3_ST_CR_SRVR_HELLO_A,
@@ -855,8 +914,9 @@ int ssl3_get_server_hello(SSL *s)
 
        if (!ok) return((int)n);
 
-       if ( SSL_version(s) == DTLS1_VERSION || SSL_version(s) == DTLS1_BAD_VER)
+       if (SSL_IS_DTLS(s))
                {
+               s->first_packet = 0;
                if ( s->s3->tmp.message_type == DTLS1_MT_HELLO_VERIFY_REQUEST)
                        {
                        if ( s->d1->send_cookie == 0)
@@ -881,6 +941,33 @@ int ssl3_get_server_hello(SSL *s)
                }
 
        d=p=(unsigned char *)s->init_msg;
+       if (s->method->version == DTLS_ANY_VERSION)
+               {
+               /* Work out correct protocol version to use */
+               int hversion = (p[0] << 8)|p[1];
+               int options = s->options;
+               if (hversion == DTLS1_2_VERSION
+                       && !(options & SSL_OP_NO_DTLSv1_2))
+                       s->method = DTLSv1_2_client_method();
+               else if (tls1_suiteb(s))
+                       {
+                       SSLerr(SSL_F_SSL3_GET_SERVER_HELLO, SSL_R_ONLY_DTLS_1_2_ALLOWED_IN_SUITEB_MODE);
+                       s->version = hversion;
+                       al = SSL_AD_PROTOCOL_VERSION;
+                       goto f_err;
+                       }
+               else if (hversion == DTLS1_VERSION
+                       && !(options & SSL_OP_NO_DTLSv1))
+                       s->method = DTLSv1_client_method();
+               else
+                       {
+                       SSLerr(SSL_F_SSL3_GET_SERVER_HELLO,SSL_R_WRONG_SSL_VERSION);
+                       s->version = hversion;
+                       al = SSL_AD_PROTOCOL_VERSION;
+                       goto f_err;
+                       }
+               s->version = s->client_version = s->method->version;
+               }
 
        if ((p[0] != (s->version>>8)) || (p[1] != (s->version&0xff)))
                {
@@ -919,6 +1006,7 @@ int ssl3_get_server_hello(SSL *s)
                        {
                        s->session->cipher = pref_cipher ?
                                pref_cipher : ssl_get_cipher_by_char(s, p+j);
+                       s->s3->flags |= SSL3_FLAGS_CCS_OK;
                        }
                }
 #endif /* OPENSSL_NO_TLSEXT */
@@ -934,6 +1022,7 @@ int ssl3_get_server_hello(SSL *s)
                SSLerr(SSL_F_SSL3_GET_SERVER_HELLO,SSL_R_ATTEMPT_TO_REUSE_SESSION_IN_DIFFERENT_CONTEXT);
                goto f_err;
                }
+           s->s3->flags |= SSL3_FLAGS_CCS_OK;
            s->hit=1;
            }
        else    /* a miss or crap from the other end */
@@ -960,12 +1049,15 @@ int ssl3_get_server_hello(SSL *s)
                SSLerr(SSL_F_SSL3_GET_SERVER_HELLO,SSL_R_UNKNOWN_CIPHER_RETURNED);
                goto f_err;
                }
+       /* Set version disabled mask now we know version */
+       if (!SSL_USE_TLS1_2_CIPHERS(s))
+               ct->mask_ssl = SSL_TLSV1_2;
+       else
+               ct->mask_ssl = 0;
        /* If it is a disabled cipher we didn't send it in client hello,
         * so return an error.
         */
-       if (c->algorithm_ssl & ct->mask_ssl ||
-               c->algorithm_mkey & ct->mask_k ||
-               c->algorithm_auth & ct->mask_a)
+       if (ssl_cipher_disabled(s, c, SSL_SECOP_CIPHER_CHECK))
                {
                al=SSL_AD_ILLEGAL_PARAMETER;
                SSLerr(SSL_F_SSL3_GET_SERVER_HELLO,SSL_R_WRONG_CIPHER_RETURNED);
@@ -1002,10 +1094,10 @@ int ssl3_get_server_hello(SSL *s)
                        }
                }
        s->s3->tmp.new_cipher=c;
-       /* Don't digest cached records if TLS v1.2: we may need them for
+       /* Don't digest cached records if no sigalgs: we may need them for
         * client authentication.
         */
-       if (TLS1_get_version(s) < TLS1_2_VERSION && !ssl3_digest_cached_records(s))
+       if (!SSL_USE_SIGALGS(s) && !ssl3_digest_cached_records(s))
                goto f_err;
        /* lets get the compression algorithm */
        /* COMPRESSION */
@@ -1034,7 +1126,7 @@ int ssl3_get_server_hello(SSL *s)
                }
        if (j == 0)
                comp=NULL;
-       else if (s->options & SSL_OP_NO_COMPRESSION)
+       else if (!ssl_allow_compression(s))
                {
                al=SSL_AD_ILLEGAL_PARAMETER;
                SSLerr(SSL_F_SSL3_GET_SERVER_HELLO,SSL_R_COMPRESSION_DISABLED);
@@ -1176,6 +1268,12 @@ int ssl3_get_server_certificate(SSL *s)
                goto f_err; 
                }
        ERR_clear_error(); /* but we keep s->verify_result */
+       if (i > 1)
+               {
+               SSLerr(SSL_F_SSL3_GET_SERVER_CERTIFICATE, i);
+               al = SSL_AD_HANDSHAKE_FAILURE;
+               goto f_err;
+               }
 
        sc=ssl_sess_cert_new();
        if (sc == NULL) goto err;
@@ -1225,6 +1323,15 @@ int ssl3_get_server_certificate(SSL *s)
 
        if (need_cert)
                {
+               int exp_idx = ssl_cipher_get_cert_index(s->s3->tmp.new_cipher);
+               if (exp_idx >= 0 && i != exp_idx)
+                       {
+                       x=NULL;
+                       al=SSL_AD_ILLEGAL_PARAMETER;
+                       SSLerr(SSL_F_SSL3_GET_SERVER_CERTIFICATE,
+                               SSL_R_WRONG_CERTIFICATE_TYPE);
+                       goto f_err;
+                       }
                sc->peer_cert_type=i;
                CRYPTO_add(&x->references,1,CRYPTO_LOCK_X509);
                /* Why would the following ever happen?
@@ -1251,21 +1358,6 @@ int ssl3_get_server_certificate(SSL *s)
        s->session->verify_result = s->verify_result;
 
        x=NULL;
-#ifndef OPENSSL_NO_TLSEXT
-       /* Check the audit proof. */
-       if (s->ctx->tlsext_authz_server_audit_proof_cb)
-               {
-               ret = s->ctx->tlsext_authz_server_audit_proof_cb(s,
-                       s->ctx->tlsext_authz_server_audit_proof_cb_arg);
-               if (ret <= 0)
-                       {
-                       al = SSL_AD_BAD_CERTIFICATE;
-                       SSLerr(SSL_F_SSL3_GET_SERVER_CERTIFICATE,SSL_R_INVALID_AUDIT_PROOF);
-                       goto f_err;
-                       }
-               }
-
-#endif
        ret=1;
        if (0)
                {
@@ -1548,7 +1640,7 @@ int ssl3_get_key_exchange(SSL *s)
                ;
 #endif
 #ifndef OPENSSL_NO_DH
-       else if (alg_k & SSL_kEDH)
+       else if (alg_k & SSL_kDHE)
                {
                if ((dh=DH_new()) == NULL)
                        {
@@ -1601,6 +1693,14 @@ int ssl3_get_key_exchange(SSL *s)
                p+=i;
                n-=param_len;
 
+               if (!ssl_security(s, SSL_SECOP_TMP_DH,
+                                               DH_security_bits(dh), 0, dh))
+                       {
+                       al=SSL_AD_HANDSHAKE_FAILURE;
+                       SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE,SSL_R_DH_KEY_TOO_SMALL);
+                       goto f_err;
+                       }
+
 #ifndef OPENSSL_NO_RSA
                if (alg_a & SSL_aRSA)
                        pkey=X509_get_pubkey(s->session->sess_cert->peer_pkeys[SSL_PKEY_RSA_ENC].x509);
@@ -1626,7 +1726,7 @@ int ssl3_get_key_exchange(SSL *s)
 #endif /* !OPENSSL_NO_DH */
 
 #ifndef OPENSSL_NO_ECDH
-       else if (alg_k & SSL_kEECDH)
+       else if (alg_k & SSL_kECDHE)
                {
                EC_GROUP *ngroup;
                const EC_GROUP *group;
@@ -1647,7 +1747,7 @@ int ssl3_get_key_exchange(SSL *s)
                 * and the ECParameters in this case is just three bytes.
                 */
                param_len=3;
-               /* Check curve is one of our prefrences, if not server has
+               /* Check curve is one of our preferences, if not server has
                 * sent an invalid curve.
                 */
                if (!tls1_check_curve(s, p, param_len))
@@ -1748,7 +1848,7 @@ int ssl3_get_key_exchange(SSL *s)
        /* if it was signed, check the signature */
        if (pkey != NULL)
                {
-               if (TLS1_get_version(s) >= TLS1_2_VERSION)
+               if (SSL_USE_SIGALGS(s))
                        {
                        int rv = tls12_check_peer_sigalg(&md, s, p, pkey);
                        if (rv == -1)
@@ -1780,7 +1880,7 @@ fprintf(stderr, "USING TLSv1.2 HASH %s\n", EVP_MD_name(md));
                        }
 
 #ifndef OPENSSL_NO_RSA
-               if (pkey->type == EVP_PKEY_RSA && TLS1_get_version(s) < TLS1_2_VERSION)
+               if (pkey->type == EVP_PKEY_RSA && !SSL_USE_SIGALGS(s))
                        {
                        int num;
 
@@ -1833,10 +1933,13 @@ fprintf(stderr, "USING TLSv1.2 HASH %s\n", EVP_MD_name(md));
                }
        else
                {
+               /* aNULL or kPSK do not need public keys */
                if (!(alg_a & SSL_aNULL) && !(alg_k & SSL_kPSK))
-                       /* aNULL or kPSK do not need public keys */
                        {
-                       SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE,ERR_R_INTERNAL_ERROR);
+                       /* Might be wrong key type, check it */
+                       if (ssl3_check_cert_and_algorithm(s))
+                               /* Otherwise this shouldn't happen */
+                               SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE,ERR_R_INTERNAL_ERROR);
                        goto err;
                        }
                /* still data left over */
@@ -1951,7 +2054,7 @@ int ssl3_get_certificate_request(SSL *s)
        for (i=0; i<ctype_num; i++)
                s->s3->tmp.ctype[i]= p[i];
        p+=p[-1];
-       if (TLS1_get_version(s) >= TLS1_2_VERSION)
+       if (SSL_USE_SIGALGS(s))
                {
                n2s(p, llen);
                /* Check we have enough room for signature algorithms and
@@ -2249,7 +2352,7 @@ int ssl3_get_server_done(SSL *s)
 
 int ssl3_send_client_key_exchange(SSL *s)
        {
-       unsigned char *p,*d;
+       unsigned char *p;
        int n;
        unsigned long alg_k;
 #ifndef OPENSSL_NO_RSA
@@ -2270,8 +2373,7 @@ int ssl3_send_client_key_exchange(SSL *s)
 
        if (s->state == SSL3_ST_CW_KEY_EXCH_A)
                {
-               d=(unsigned char *)s->init_buf->data;
-               p= &(d[4]);
+               p = ssl_handshake_start(s);
 
                alg_k=s->s3->tmp.new_cipher->algorithm_mkey;
 
@@ -2471,7 +2573,7 @@ int ssl3_send_client_key_exchange(SSL *s)
                        }
 #endif
 #ifndef OPENSSL_NO_DH
-               else if (alg_k & (SSL_kEDH|SSL_kDHr|SSL_kDHd))
+               else if (alg_k & (SSL_kDHE|SSL_kDHr|SSL_kDHd))
                        {
                        DH *dh_srvr,*dh_clnt;
                        SESS_CERT *scert = s->session->sess_cert;
@@ -2575,13 +2677,20 @@ int ssl3_send_client_key_exchange(SSL *s)
 #endif
 
 #ifndef OPENSSL_NO_ECDH 
-               else if (alg_k & (SSL_kEECDH|SSL_kECDHr|SSL_kECDHe))
+               else if (alg_k & (SSL_kECDHE|SSL_kECDHr|SSL_kECDHe))
                        {
                        const EC_GROUP *srvr_group = NULL;
                        EC_KEY *tkey;
                        int ecdh_clnt_cert = 0;
                        int field_size = 0;
 
+                       if (s->session->sess_cert == NULL) 
+                               {
+                               ssl3_send_alert(s,SSL3_AL_FATAL,SSL_AD_UNEXPECTED_MESSAGE);
+                               SSLerr(SSL_F_SSL3_SEND_CLIENT_KEY_EXCHANGE,SSL_R_UNEXPECTED_MESSAGE);
+                               goto err;
+                               }
+
                        /* Did we send out the client's
                         * ECDH share for use in premaster
                         * computation as part of client certificate?
@@ -2972,18 +3081,13 @@ int ssl3_send_client_key_exchange(SSL *s)
                            ERR_R_INTERNAL_ERROR);
                        goto err;
                        }
-               
-               *(d++)=SSL3_MT_CLIENT_KEY_EXCHANGE;
-               l2n3(n,d);
 
+               ssl_set_handshake_header(s, SSL3_MT_CLIENT_KEY_EXCHANGE, n);
                s->state=SSL3_ST_CW_KEY_EXCH_B;
-               /* number of bytes to write */
-               s->init_num=n+4;
-               s->init_off=0;
                }
 
        /* SSL3_ST_CW_KEY_EXCH_B */
-       return(ssl3_do_write(s,SSL3_RT_HANDSHAKE));
+       return ssl_do_write(s);
 err:
 #ifndef OPENSSL_NO_ECDH
        BN_CTX_free(bn_ctx);
@@ -2997,7 +3101,7 @@ err:
 
 int ssl3_send_client_verify(SSL *s)
        {
-       unsigned char *p,*d;
+       unsigned char *p;
        unsigned char data[MD5_DIGEST_LENGTH+SHA_DIGEST_LENGTH];
        EVP_PKEY *pkey;
        EVP_PKEY_CTX *pctx=NULL;
@@ -3010,15 +3114,14 @@ int ssl3_send_client_verify(SSL *s)
 
        if (s->state == SSL3_ST_CW_CERT_VRFY_A)
                {
-               d=(unsigned char *)s->init_buf->data;
-               p= &(d[4]);
+               p= ssl_handshake_start(s);
                pkey=s->cert->key->privatekey;
 /* Create context from key and test if sha1 is allowed as digest */
                pctx = EVP_PKEY_CTX_new(pkey,NULL);
                EVP_PKEY_sign_init(pctx);
                if (EVP_PKEY_CTX_set_signature_md(pctx, EVP_sha1())>0)
                        {
-                       if (TLS1_get_version(s) < TLS1_2_VERSION)
+                       if (!SSL_USE_SIGALGS(s))
                                s->method->ssl3_enc->cert_verify_mac(s,
                                                NID_sha1,
                                                &(data[MD5_DIGEST_LENGTH]));
@@ -3030,7 +3133,7 @@ int ssl3_send_client_verify(SSL *s)
                /* For TLS v1.2 send signature algorithm and signature
                 * using agreed digest and cached handshake records.
                 */
-               if (TLS1_get_version(s) >= TLS1_2_VERSION)
+               if (SSL_USE_SIGALGS(s))
                        {
                        long hdatalen = 0;
                        void *hdata;
@@ -3137,16 +3240,12 @@ int ssl3_send_client_verify(SSL *s)
                        SSLerr(SSL_F_SSL3_SEND_CLIENT_VERIFY,ERR_R_INTERNAL_ERROR);
                        goto err;
                }
-               *(d++)=SSL3_MT_CERTIFICATE_VERIFY;
-               l2n3(n,d);
-
+               ssl_set_handshake_header(s, SSL3_MT_CERTIFICATE_VERIFY, n);
                s->state=SSL3_ST_CW_CERT_VRFY_B;
-               s->init_num=(int)n+4;
-               s->init_off=0;
                }
        EVP_MD_CTX_cleanup(&mctx);
        EVP_PKEY_CTX_free(pctx);
-       return(ssl3_do_write(s,SSL3_RT_HANDSHAKE));
+       return ssl_do_write(s);
 err:
        EVP_MD_CTX_cleanup(&mctx);
        EVP_PKEY_CTX_free(pctx);
@@ -3154,8 +3253,9 @@ err:
        }
 
 /* Check a certificate can be used for client authentication. Currently
- * check cert exists, if we have a suitable digest for TLS 1.2  and if
- * static DH client certificates can be used.
+ * check cert exists, if we have a suitable digest for TLS 1.2 if
+ * static DH client certificates can be used and optionally checks
+ * suitability for Suite B.
  */
 static int ssl3_check_client_certificate(SSL *s)
        {
@@ -3163,7 +3263,13 @@ static int ssl3_check_client_certificate(SSL *s)
        if (!s->cert || !s->cert->key->x509 || !s->cert->key->privatekey)
                return 0;
        /* If no suitable signature algorithm can't use certificate */
-       if (TLS1_get_version(s) >= TLS1_2_VERSION && !s->cert->key->digest)
+       if (SSL_USE_SIGALGS(s) && !s->cert->key->digest)
+               return 0;
+       /* If strict mode check suitability of chain before using it.
+        * This also adjusts suite B digest if necessary.
+        */
+       if (s->cert->cert_flags & SSL_CERT_FLAGS_CHECK_TLS_STRICT &&
+               !tls1_check_chain(s, NULL, NULL, NULL, -2))
                return 0;
        alg_k=s->s3->tmp.new_cipher->algorithm_mkey;
        /* See if we can use client certificate for fixed DH */
@@ -3196,16 +3302,24 @@ int ssl3_send_client_certificate(SSL *s)
        X509 *x509=NULL;
        EVP_PKEY *pkey=NULL;
        int i;
-       unsigned long l;
 
        if (s->state == SSL3_ST_CW_CERT_A)
                {
                /* Let cert callback update client certificates if required */
-               if (s->cert->cert_cb
-                       && s->cert->cert_cb(s, s->cert->cert_cb_arg) <= 0)
+               if (s->cert->cert_cb)
                        {
-                       ssl3_send_alert(s,SSL3_AL_FATAL,SSL_AD_INTERNAL_ERROR);
-                       return 0;
+                       i = s->cert->cert_cb(s, s->cert->cert_cb_arg);
+                       if (i < 0)
+                               {
+                               s->rwstate=SSL_X509_LOOKUP;
+                               return -1;
+                               }
+                       if (i == 0)
+                               {
+                               ssl3_send_alert(s,SSL3_AL_FATAL,SSL_AD_INTERNAL_ERROR);
+                               return 0;
+                               }
+                       s->rwstate=SSL_NOTHING;
                        }
                if (ssl3_check_client_certificate(s))
                        s->state=SSL3_ST_CW_CERT_C;
@@ -3265,13 +3379,16 @@ int ssl3_send_client_certificate(SSL *s)
        if (s->state == SSL3_ST_CW_CERT_C)
                {
                s->state=SSL3_ST_CW_CERT_D;
-               l=ssl3_output_cert_chain(s,
-                       (s->s3->tmp.cert_req == 2)?NULL:s->cert->key);
-               s->init_num=(int)l;
-               s->init_off=0;
+               if (!ssl3_output_cert_chain(s,
+                       (s->s3->tmp.cert_req == 2)?NULL:s->cert->key))
+                       {
+                       SSLerr(SSL_F_SSL3_SEND_CLIENT_CERTIFICATE, ERR_R_INTERNAL_ERROR);
+                       ssl3_send_alert(s,SSL3_AL_FATAL,SSL_AD_INTERNAL_ERROR);
+                       return 0;
+                       }
                }
        /* SSL3_ST_CW_CERT_D */
-       return(ssl3_do_write(s,SSL3_RT_HANDSHAKE));
+       return ssl_do_write(s);
        }
 
 #define has_bits(i,m)  (((i)&(m)) == (m))
@@ -3327,6 +3444,16 @@ int ssl3_check_cert_and_algorithm(SSL *s)
                        return 1;
                        }
                }
+       else if (alg_a & SSL_aECDSA)
+               {
+               SSLerr(SSL_F_SSL3_CHECK_CERT_AND_ALGORITHM,SSL_R_MISSING_ECDSA_SIGNING_CERT);
+               goto f_err;
+               }
+       else if (alg_k & (SSL_kECDHr|SSL_kECDHe))
+               {
+               SSLerr(SSL_F_SSL3_CHECK_CERT_AND_ALGORITHM,SSL_R_MISSING_ECDH_CERT);
+               goto f_err;
+               }
 #endif
        pkey=X509_get_pubkey(sc->peer_pkeys[idx].x509);
        i=X509_certificate_type(sc->peer_pkeys[idx].x509,pkey);
@@ -3355,20 +3482,20 @@ int ssl3_check_cert_and_algorithm(SSL *s)
                }
 #endif
 #ifndef OPENSSL_NO_DH
-       if ((alg_k & SSL_kEDH) && 
+       if ((alg_k & SSL_kDHE) && 
                !(has_bits(i,EVP_PK_DH|EVP_PKT_EXCH) || (dh != NULL)))
                {
                SSLerr(SSL_F_SSL3_CHECK_CERT_AND_ALGORITHM,SSL_R_MISSING_DH_KEY);
                goto f_err;
                }
-       else if ((alg_k & SSL_kDHr) && (TLS1_get_version(s) < TLS1_2_VERSION) &&
+       else if ((alg_k & SSL_kDHr) && !SSL_USE_SIGALGS(s) &&
                !has_bits(i,EVP_PK_DH|EVP_PKS_RSA))
                {
                SSLerr(SSL_F_SSL3_CHECK_CERT_AND_ALGORITHM,SSL_R_MISSING_DH_RSA_CERT);
                goto f_err;
                }
 #ifndef OPENSSL_NO_DSA
-       else if ((alg_k & SSL_kDHd) && (TLS1_get_version(s) < TLS1_2_VERSION) &&
+       else if ((alg_k & SSL_kDHd) && !SSL_USE_SIGALGS(s) &&
                !has_bits(i,EVP_PK_DH|EVP_PKS_DSA))
                {
                SSLerr(SSL_F_SSL3_CHECK_CERT_AND_ALGORITHM,SSL_R_MISSING_DH_DSA_CERT);
@@ -3392,7 +3519,7 @@ int ssl3_check_cert_and_algorithm(SSL *s)
                else
 #endif
 #ifndef OPENSSL_NO_DH
-                       if (alg_k & (SSL_kEDH|SSL_kDHr|SSL_kDHd))
+                       if (alg_k & (SSL_kDHE|SSL_kDHr|SSL_kDHd))
                            {
                            if (dh == NULL
                                || DH_size(dh)*8 > SSL_C_EXPORT_PKEYLENGTH(s->s3->tmp.new_cipher))
@@ -3451,6 +3578,7 @@ int ssl3_check_finished(SSL *s)
        {
        int ok;
        long n;
+
        /* If we have no ticket it cannot be a resumed session. */
        if (!s->session->tlsext_tick)
                return 1;
@@ -3464,6 +3592,7 @@ int ssl3_check_finished(SSL *s)
                &ok);
        if (!ok) return((int)n);
        s->s3->tmp.reuse_message = 1;
+
        if ((s->s3->tmp.message_type == SSL3_MT_FINISHED)
                || (s->s3->tmp.message_type == SSL3_MT_NEWSESSION_TICKET))
                return 2;
@@ -3489,106 +3618,3 @@ int ssl_do_client_cert_cb(SSL *s, X509 **px509, EVP_PKEY **ppkey)
                i = s->ctx->client_cert_cb(s,px509,ppkey);
        return i;
        }
-
-#ifndef OPENSSL_NO_TLSEXT
-int tls1_get_server_supplemental_data(SSL *s)
-       {
-       int al;
-       int ok;
-       unsigned long supp_data_len, authz_data_len;
-       long n;
-       unsigned short supp_data_type, authz_data_type, proof_len;
-       const unsigned char *p;
-       unsigned char *new_proof;
-
-       n=s->method->ssl_get_message(s,
-               SSL3_ST_CR_SUPPLEMENTAL_DATA_A,
-               SSL3_ST_CR_SUPPLEMENTAL_DATA_B,
-               SSL3_MT_SUPPLEMENTAL_DATA,
-               /* use default limit */
-               TLSEXT_MAXLEN_supplemental_data,
-               &ok);
-
-       if (!ok) return((int)n);
-
-       p = (unsigned char *)s->init_msg;
-
-       /* The message cannot be empty */
-       if (n < 3)
-               {
-               al = SSL_AD_DECODE_ERROR;
-               SSLerr(SSL_F_TLS1_GET_SERVER_SUPPLEMENTAL_DATA,SSL_R_LENGTH_MISMATCH);
-               goto f_err;
-               }
-       /* Length of supplemental data */
-       n2l3(p,supp_data_len);
-       n -= 3;
-       /* We must have at least one supplemental data entry
-        * with type (1 byte) and length (2 bytes). */
-       if (supp_data_len != (unsigned long) n || n < 4)
-               {
-               al = SSL_AD_DECODE_ERROR;
-               SSLerr(SSL_F_TLS1_GET_SERVER_SUPPLEMENTAL_DATA,SSL_R_LENGTH_MISMATCH);
-               goto f_err;
-               }
-       /* Supplemental data type: must be authz_data */
-       n2s(p,supp_data_type);
-       n -= 2;
-       if (supp_data_type != TLSEXT_SUPPLEMENTALDATATYPE_authz_data)
-               {
-               al = SSL_AD_UNEXPECTED_MESSAGE;
-               SSLerr(SSL_F_TLS1_GET_SERVER_SUPPLEMENTAL_DATA,SSL_R_UNKNOWN_SUPPLEMENTAL_DATA_TYPE);
-               goto f_err;
-               }
-       /* Authz data length */
-       n2s(p, authz_data_len);
-       n -= 2;
-       if (authz_data_len != (unsigned long) n || n < 1)
-               {
-               al = SSL_AD_DECODE_ERROR;
-               SSLerr(SSL_F_TLS1_GET_SERVER_SUPPLEMENTAL_DATA,SSL_R_LENGTH_MISMATCH);
-               goto f_err;
-               }
-       /* Authz data type: must be audit_proof */
-       authz_data_type = *(p++);
-       n -= 1;
-       if (authz_data_type != TLSEXT_AUTHZDATAFORMAT_audit_proof)
-               {
-               al=SSL_AD_UNEXPECTED_MESSAGE;
-               SSLerr(SSL_F_TLS1_GET_SERVER_SUPPLEMENTAL_DATA,SSL_R_UNKNOWN_AUTHZ_DATA_TYPE);
-               goto f_err;
-               }
-       /* We have a proof: read its length */
-       if (n < 2)
-               {
-               al = SSL_AD_DECODE_ERROR;
-               SSLerr(SSL_F_TLS1_GET_SERVER_SUPPLEMENTAL_DATA,SSL_R_LENGTH_MISMATCH);
-               goto f_err;
-               }
-       n2s(p, proof_len);
-       n -= 2;
-       if (proof_len != (unsigned long) n)
-               {
-               al = SSL_AD_DECODE_ERROR;
-               SSLerr(SSL_F_TLS1_GET_SERVER_SUPPLEMENTAL_DATA,SSL_R_LENGTH_MISMATCH);
-               goto f_err;
-               }
-       /* Store the proof */
-       new_proof = OPENSSL_realloc(s->session->audit_proof,
-                                   proof_len);
-       if (new_proof == NULL)
-               {
-               SSLerr(SSL_F_TLS1_GET_SERVER_SUPPLEMENTAL_DATA,ERR_R_MALLOC_FAILURE);
-               return 0;
-               }
-       s->session->audit_proof_length = proof_len;
-       s->session->audit_proof = new_proof;
-       memcpy(s->session->audit_proof, p, proof_len);
-
-       /* Got the proof, but can't verify it yet. */
-       return 1;
-f_err:
-       ssl3_send_alert(s,SSL3_AL_FATAL,al);
-       return -1;
-       }
-#endif