Suite B support for DTLS 1.2
[openssl.git] / ssl / s3_clnt.c
index 3f87da58c027650d7c88fc1a7e84bd26fec25e30..018a9f590ce87eab3c24c722f0fb5f83609948ef 100644 (file)
 #include <openssl/objects.h>
 #include <openssl/evp.h>
 #include <openssl/md5.h>
+#ifdef OPENSSL_FIPS
+#include <openssl/fips.h>
+#endif
 #ifndef OPENSSL_NO_DH
 #include <openssl/dh.h>
 #endif
@@ -200,6 +203,18 @@ int ssl3_connect(SSL *s)
        s->in_handshake++;
        if (!SSL_in_init(s) || SSL_in_before(s)) SSL_clear(s); 
 
+#ifndef OPENSSL_NO_HEARTBEATS
+       /* If we're awaiting a HeartbeatResponse, pretend we
+        * already got and don't await it anymore, because
+        * Heartbeats don't make sense during handshakes anyway.
+        */
+       if (s->tlsext_hb_pending)
+               {
+               s->tlsext_hb_pending = 0;
+               s->tlsext_hb_seq++;
+               }
+#endif
+
        for (;;)
                {
                state=s->state;
@@ -207,7 +222,7 @@ int ssl3_connect(SSL *s)
                switch(s->state)
                        {
                case SSL_ST_RENEGOTIATE:
-                       s->new_session=1;
+                       s->renegotiate=1;
                        s->state=SSL_ST_CONNECT;
                        s->ctx->stats.sess_connect_renegotiate++;
                        /* break */
@@ -280,12 +295,38 @@ int ssl3_connect(SSL *s)
                        if (ret <= 0) goto end;
 
                        if (s->hit)
+                               {
                                s->state=SSL3_ST_CR_FINISHED_A;
+#ifndef OPENSSL_NO_TLSEXT
+                               if (s->tlsext_ticket_expected)
+                                       {
+                                       /* receive renewed session ticket */
+                                       s->state=SSL3_ST_CR_SESSION_TICKET_A;
+                                       }
+#endif
+                               }
                        else
-                               s->state=SSL3_ST_CR_CERT_A;
+                               {
+#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
@@ -358,6 +399,17 @@ int ssl3_connect(SSL *s)
                case SSL3_ST_CR_SRVR_DONE_B:
                        ret=ssl3_get_server_done(s);
                        if (ret <= 0) goto end;
+#ifndef OPENSSL_NO_SRP
+                       if (s->s3->tmp.new_cipher->algorithm_mkey & SSL_kSRP)
+                               {
+                               if ((ret = SRP_Calc_A_param(s))<=0)
+                                       {
+                                       SSLerr(SSL_F_SSL3_CONNECT,SSL_R_SRP_A_CALC);
+                                       ssl3_send_alert(s,SSL3_AL_FATAL,SSL_AD_INTERNAL_ERROR);
+                                       goto end;
+                                       }
+                               }
+#endif
                        if (s->s3->tmp.cert_req)
                                s->state=SSL3_ST_CW_CERT_A;
                        else
@@ -423,7 +475,15 @@ int ssl3_connect(SSL *s)
                        ret=ssl3_send_change_cipher_spec(s,
                                SSL3_ST_CW_CHANGE_A,SSL3_ST_CW_CHANGE_B);
                        if (ret <= 0) goto end;
+
+#if defined(OPENSSL_NO_TLSEXT) || defined(OPENSSL_NO_NEXTPROTONEG)
                        s->state=SSL3_ST_CW_FINISHED_A;
+#else
+                       if (s->s3->next_proto_neg_seen)
+                               s->state=SSL3_ST_CW_NEXT_PROTO_A;
+                       else
+                               s->state=SSL3_ST_CW_FINISHED_A;
+#endif
                        s->init_num=0;
 
                        s->session->cipher=s->s3->tmp.new_cipher;
@@ -451,6 +511,15 @@ int ssl3_connect(SSL *s)
 
                        break;
 
+#if !defined(OPENSSL_NO_TLSEXT) && !defined(OPENSSL_NO_NEXTPROTONEG)
+               case SSL3_ST_CW_NEXT_PROTO_A:
+               case SSL3_ST_CW_NEXT_PROTO_B:
+                       ret=ssl3_send_next_proto(s);
+                       if (ret <= 0) goto end;
+                       s->state=SSL3_ST_CW_FINISHED_A;
+                       break;
+#endif
+
                case SSL3_ST_CW_FINISHED_A:
                case SSL3_ST_CW_FINISHED_B:
                        ret=ssl3_send_finished(s,
@@ -546,6 +615,7 @@ int ssl3_connect(SSL *s)
                        /* else do it later in ssl3_write */
 
                        s->init_num=0;
+                       s->renegotiate=0;
                        s->new_session=0;
 
                        ssl_update_cache(s,SSL_SESS_CACHE_CLIENT);
@@ -624,20 +694,111 @@ 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;
 
-               /* Do the message type and length last */
-               d=p= &(buf[4]);
+               /* 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)
+                       {
+                       Time=(unsigned long)time(NULL); /* Time */
+                       l2n(Time,p);
+                       RAND_pseudo_bytes(p,sizeof(s->s3->client_random)-4);
+                                       
+                       }
 
+               /* Do the message type and length last */
+               d=p= ssl_handshake_start(s);
+
+               /* version indicates the negotiated version: for example from
+                * an SSLv2/v3 compatible client hello). The client_version
+                * field is the maximum version we permit and it is also
+                * used in RSA encrypted premaster secrets. Some servers can
+                * choke if we initially report a higher version then
+                * renegotiate to a lower one in the premaster secret. This
+                * didn't happen with TLS 1.0 as most servers supported it
+                * but it can with TLS 1.1 or later if the server only supports
+                * 1.0.
+                *
+                * Possible scenario with previous logic:
+                *      1. Client hello indicates TLS 1.2
+                *      2. Server hello says TLS 1.0
+                *      3. RSA encrypted premaster secret uses 1.2.
+                *      4. Handhaked proceeds using TLS 1.0.
+                *      5. Server sends hello request to renegotiate.
+                *      6. Client hello indicates TLS v1.0 as we now
+                *         know that is maximum server supports.
+                *      7. Server chokes on RSA encrypted premaster secret
+                *         containing version 1.0.
+                *
+                * For interoperability it should be OK to always use the
+                * maximum version we support in client hello and then rely
+                * on the checking of version to ensure the servers isn't
+                * being inconsistent: for example initially negotiating with
+                * TLS 1.0 and renegotiating with TLS 1.2. We do this by using
+                * client_version in client hello and not resetting it to
+                * the negotiated version.
+                */
+#if 0
                *(p++)=s->version>>8;
                *(p++)=s->version&0xff;
                s->client_version=s->version;
+#else
+               *(p++)=s->client_version>>8;
+               *(p++)=s->client_version&0xff;
+#endif
 
                /* Random stuff */
                memcpy(p,s->s3->client_random,SSL3_RANDOM_SIZE);
@@ -660,6 +821,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)
@@ -667,6 +841,15 @@ int ssl3_client_hello(SSL *s)
                        SSLerr(SSL_F_SSL3_CLIENT_HELLO,SSL_R_NO_CIPHERS_AVAILABLE);
                        goto err;
                        }
+#ifdef OPENSSL_MAX_TLS1_2_CIPHER_LENGTH
+                       /* Some servers hang if client hello > 256 bytes
+                        * as hack workaround chop number of supported ciphers
+                        * to keep it well below this if we use TLS v1.2
+                        */
+                       if (TLS1_get_version(s) >= TLS1_2_VERSION
+                               && i > OPENSSL_MAX_TLS1_2_CIPHER_LENGTH)
+                               i = OPENSSL_MAX_TLS1_2_CIPHER_LENGTH & ~1;
+#endif
                s2n(i,p);
                p+=i;
 
@@ -703,19 +886,13 @@ int ssl3_client_hello(SSL *s)
                        }
 #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);
        }
@@ -724,13 +901,19 @@ int ssl3_get_server_hello(SSL *s)
        {
        STACK_OF(SSL_CIPHER) *sk;
        const SSL_CIPHER *c;
+       CERT *ct = s->cert;
        unsigned char *p,*d;
-       int i,al,ok;
+       int i,al=SSL_AD_INTERNAL_ERROR,ok;
        unsigned int j;
        long n;
 #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 (s->method->version == DTLS_ANY_VERSION)
+               s->first_packet = 1;
 
        n=s->method->ssl_get_message(s,
                SSL3_ST_CR_SRVR_HELLO_A,
@@ -741,8 +924,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)
@@ -767,6 +951,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)))
                {
@@ -831,7 +1042,6 @@ int ssl3_get_server_hello(SSL *s)
                        {
                        if (!ssl_get_new_session(s,0))
                                {
-                               al=SSL_AD_INTERNAL_ERROR;
                                goto f_err;
                                }
                        }
@@ -847,6 +1057,17 @@ int ssl3_get_server_hello(SSL *s)
                SSLerr(SSL_F_SSL3_GET_SERVER_HELLO,SSL_R_UNKNOWN_CIPHER_RETURNED);
                goto f_err;
                }
+       /* 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)
+               {
+               al=SSL_AD_ILLEGAL_PARAMETER;
+               SSLerr(SSL_F_SSL3_GET_SERVER_HELLO,SSL_R_WRONG_CIPHER_RETURNED);
+               goto f_err;
+               }
        p+=ssl_put_cipher_by_char(s,NULL,NULL);
 
        sk=ssl_get_ciphers_by_id(s);
@@ -866,8 +1087,11 @@ int ssl3_get_server_hello(SSL *s)
                s->session->cipher_id = s->session->cipher->id;
        if (s->hit && (s->session->cipher_id != c->id))
                {
+/* Workaround is now obsolete */
+#if 0
                if (!(s->options &
                        SSL_OP_NETSCAPE_REUSE_CIPHER_CHANGE_BUG))
+#endif
                        {
                        al=SSL_AD_ILLEGAL_PARAMETER;
                        SSLerr(SSL_F_SSL3_GET_SERVER_HELLO,SSL_R_OLD_SESSION_CIPHER_NOT_RETURNED);
@@ -875,9 +1099,11 @@ int ssl3_get_server_hello(SSL *s)
                        }
                }
        s->s3->tmp.new_cipher=c;
-       if (!ssl3_digest_cached_records(s))
+       /* Don't digest cached records if no sigalgs: we may need them for
+        * client authentication.
+        */
+       if (!SSL_USE_SIGALGS(s) && !ssl3_digest_cached_records(s))
                goto f_err;
-
        /* lets get the compression algorithm */
        /* COMPRESSION */
 #ifdef OPENSSL_NO_COMP
@@ -892,7 +1118,6 @@ int ssl3_get_server_hello(SSL *s)
         */
        if (s->session->compress_meth != 0)
                {
-               al=SSL_AD_INTERNAL_ERROR;
                SSLerr(SSL_F_SSL3_GET_SERVER_HELLO,SSL_R_INCONSISTENT_COMPRESSION);
                goto f_err;
                }
@@ -929,19 +1154,10 @@ int ssl3_get_server_hello(SSL *s)
 
 #ifndef OPENSSL_NO_TLSEXT
        /* TLS extensions*/
-       if (s->version >= SSL3_VERSION)
+       if (!ssl_parse_serverhello_tlsext(s,&p,d,n))
                {
-               if (!ssl_parse_serverhello_tlsext(s,&p,d,n, &al))
-                       {
-                       /* 'al' set by ssl_parse_serverhello_tlsext */
-                       SSLerr(SSL_F_SSL3_GET_SERVER_HELLO,SSL_R_PARSE_TLSEXT);
-                       goto f_err; 
-                       }
-               if (ssl_check_serverhello_tlsext(s) <= 0)
-                       {
-                       SSLerr(SSL_F_SSL3_GET_SERVER_HELLO,SSL_R_SERVERHELLO_TLSEXT);
-                               goto err;
-                       }
+               SSLerr(SSL_F_SSL3_GET_SERVER_HELLO,SSL_R_PARSE_TLSEXT);
+               goto err; 
                }
 #endif
 
@@ -950,7 +1166,7 @@ int ssl3_get_server_hello(SSL *s)
                /* wrong packet length */
                al=SSL_AD_DECODE_ERROR;
                SSLerr(SSL_F_SSL3_GET_SERVER_HELLO,SSL_R_BAD_PACKET_LENGTH);
-               goto err;
+               goto f_err;
                }
 
        return(1);
@@ -982,7 +1198,7 @@ int ssl3_get_server_certificate(SSL *s)
        if (!ok) return((int)n);
 
        if ((s->s3->tmp.message_type == SSL3_MT_SERVER_KEY_EXCHANGE) ||
-               ((s->s3->tmp.new_cipher->algorithms & SSL_aKRB5) && 
+               ((s->s3->tmp.new_cipher->algorithm_auth & SSL_aKRB5) && 
                (s->s3->tmp.message_type == SSL3_MT_SERVER_DONE)))
                {
                s->s3->tmp.reuse_message=1;
@@ -1106,6 +1322,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?
@@ -1132,8 +1357,22 @@ int ssl3_get_server_certificate(SSL *s)
        s->session->verify_result = s->verify_result;
 
        x=NULL;
-       ret=1;
+#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)
                {
 f_err:
@@ -1156,6 +1395,7 @@ int ssl3_get_key_exchange(SSL *s)
        int al,i,j,param_len,ok;
        long n,alg_k,alg_a;
        EVP_PKEY *pkey=NULL;
+       const EVP_MD *md = NULL;
 #ifndef OPENSSL_NO_RSA
        RSA *rsa=NULL;
 #endif
@@ -1279,6 +1519,86 @@ int ssl3_get_key_exchange(SSL *s)
                }
        else
 #endif /* !OPENSSL_NO_PSK */
+#ifndef OPENSSL_NO_SRP
+       if (alg_k & SSL_kSRP)
+               {
+               n2s(p,i);
+               param_len=i+2;
+               if (param_len > n)
+                       {
+                       al=SSL_AD_DECODE_ERROR;
+                       SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE,SSL_R_BAD_SRP_N_LENGTH);
+                       goto f_err;
+                       }
+               if (!(s->srp_ctx.N=BN_bin2bn(p,i,NULL)))
+                       {
+                       SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE,ERR_R_BN_LIB);
+                       goto err;
+                       }
+               p+=i;
+
+               n2s(p,i);
+               param_len+=i+2;
+               if (param_len > n)
+                       {
+                       al=SSL_AD_DECODE_ERROR;
+                       SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE,SSL_R_BAD_SRP_G_LENGTH);
+                       goto f_err;
+                       }
+               if (!(s->srp_ctx.g=BN_bin2bn(p,i,NULL)))
+                       {
+                       SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE,ERR_R_BN_LIB);
+                       goto err;
+                       }
+               p+=i;
+
+               i = (unsigned int)(p[0]);
+               p++;
+               param_len+=i+1;
+               if (param_len > n)
+                       {
+                       al=SSL_AD_DECODE_ERROR;
+                       SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE,SSL_R_BAD_SRP_S_LENGTH);
+                       goto f_err;
+                       }
+               if (!(s->srp_ctx.s=BN_bin2bn(p,i,NULL)))
+                       {
+                       SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE,ERR_R_BN_LIB);
+                       goto err;
+                       }
+               p+=i;
+
+               n2s(p,i);
+               param_len+=i+2;
+               if (param_len > n)
+                       {
+                       al=SSL_AD_DECODE_ERROR;
+                       SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE,SSL_R_BAD_SRP_B_LENGTH);
+                       goto f_err;
+                       }
+               if (!(s->srp_ctx.B=BN_bin2bn(p,i,NULL)))
+                       {
+                       SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE,ERR_R_BN_LIB);
+                       goto err;
+                       }
+               p+=i;
+               n-=param_len;
+
+/* We must check if there is a certificate */
+#ifndef OPENSSL_NO_RSA
+               if (alg_a & SSL_aRSA)
+                       pkey=X509_get_pubkey(s->session->sess_cert->peer_pkeys[SSL_PKEY_RSA_ENC].x509);
+#else
+               if (0)
+                       ;
+#endif
+#ifndef OPENSSL_NO_DSA
+               else if (alg_a & SSL_aDSS)
+                       pkey=X509_get_pubkey(s->session->sess_cert->peer_pkeys[SSL_PKEY_DSA_SIGN].x509);
+#endif
+               }
+       else
+#endif /* !OPENSSL_NO_SRP */
 #ifndef OPENSSL_NO_RSA
        if (alg_k & SSL_kRSA)
                {
@@ -1433,9 +1753,17 @@ int ssl3_get_key_exchange(SSL *s)
                 * and the ECParameters in this case is just three bytes.
                 */
                param_len=3;
-               if ((param_len > n) ||
-                   (*p != NAMED_CURVE_TYPE) || 
-                   ((curve_nid = tls1_ec_curve_id2nid(*(p + 2))) == 0)) 
+               /* Check curve is one of our prefrences, if not server has
+                * sent an invalid curve.
+                */
+               if (!tls1_check_curve(s, p, param_len))
+                       {
+                       al=SSL_AD_DECODE_ERROR;
+                       SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE,SSL_R_WRONG_CURVE);
+                       goto f_err;
+                       }
+
+               if ((curve_nid = tls1_ec_curve_id2nid(*(p + 2))) == 0) 
                        {
                        al=SSL_AD_INTERNAL_ERROR;
                        SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE,SSL_R_UNABLE_TO_FIND_ECDH_PARAMETERS);
@@ -1508,6 +1836,7 @@ int ssl3_get_key_exchange(SSL *s)
                s->session->sess_cert->peer_ecdh_tmp=ecdh;
                ecdh=NULL;
                BN_CTX_free(bn_ctx);
+               bn_ctx = NULL;
                EC_POINT_free(srvr_ecpoint);
                srvr_ecpoint = NULL;
                }
@@ -1525,6 +1854,25 @@ int ssl3_get_key_exchange(SSL *s)
        /* if it was signed, check the signature */
        if (pkey != NULL)
                {
+               if (SSL_USE_SIGALGS(s))
+                       {
+                       int rv = tls12_check_peer_sigalg(&md, s, p, pkey);
+                       if (rv == -1)
+                               goto err;
+                       else if (rv == 0)
+                               {
+                               al = SSL_AD_DECODE_ERROR;
+                               goto f_err;
+                               }
+#ifdef SSL_DEBUG
+fprintf(stderr, "USING TLSv1.2 HASH %s\n", EVP_MD_name(md));
+#endif
+                       p += 2;
+                       n -= 2;
+                       }
+               else
+                       md = EVP_sha1();
+                       
                n2s(p,i);
                n-=2;
                j=EVP_PKEY_size(pkey);
@@ -1538,7 +1886,7 @@ int ssl3_get_key_exchange(SSL *s)
                        }
 
 #ifndef OPENSSL_NO_RSA
-               if (pkey->type == EVP_PKEY_RSA)
+               if (pkey->type == EVP_PKEY_RSA && !SSL_USE_SIGALGS(s))
                        {
                        int num;
 
@@ -1546,6 +1894,8 @@ int ssl3_get_key_exchange(SSL *s)
                        q=md_buf;
                        for (num=2; num > 0; num--)
                                {
+                               EVP_MD_CTX_set_flags(&md_ctx,
+                                       EVP_MD_CTX_FLAG_NON_FIPS_ALLOW);
                                EVP_DigestInit_ex(&md_ctx,(num == 2)
                                        ?s->ctx->md5:s->ctx->sha1, NULL);
                                EVP_DigestUpdate(&md_ctx,&(s->s3->client_random[0]),SSL3_RANDOM_SIZE);
@@ -1573,29 +1923,8 @@ int ssl3_get_key_exchange(SSL *s)
                        }
                else
 #endif
-#ifndef OPENSSL_NO_DSA
-                       if (pkey->type == EVP_PKEY_DSA)
-                       {
-                       /* lets do DSS */
-                       EVP_VerifyInit_ex(&md_ctx,EVP_dss1(), NULL);
-                       EVP_VerifyUpdate(&md_ctx,&(s->s3->client_random[0]),SSL3_RANDOM_SIZE);
-                       EVP_VerifyUpdate(&md_ctx,&(s->s3->server_random[0]),SSL3_RANDOM_SIZE);
-                       EVP_VerifyUpdate(&md_ctx,param,param_len);
-                       if (EVP_VerifyFinal(&md_ctx,p,(int)n,pkey) <= 0)
-                               {
-                               /* bad signature */
-                               al=SSL_AD_DECRYPT_ERROR;
-                               SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE,SSL_R_BAD_SIGNATURE);
-                               goto f_err;
-                               }
-                       }
-               else
-#endif
-#ifndef OPENSSL_NO_ECDSA
-                       if (pkey->type == EVP_PKEY_EC)
                        {
-                       /* let's do ECDSA */
-                       EVP_VerifyInit_ex(&md_ctx,EVP_ecdsa(), NULL);
+                       EVP_VerifyInit_ex(&md_ctx, md, NULL);
                        EVP_VerifyUpdate(&md_ctx,&(s->s3->client_random[0]),SSL3_RANDOM_SIZE);
                        EVP_VerifyUpdate(&md_ctx,&(s->s3->server_random[0]),SSL3_RANDOM_SIZE);
                        EVP_VerifyUpdate(&md_ctx,param,param_len);
@@ -1607,19 +1936,16 @@ int ssl3_get_key_exchange(SSL *s)
                                goto f_err;
                                }
                        }
-               else
-#endif
-                       {
-                       SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE,ERR_R_INTERNAL_ERROR);
-                       goto err;
-                       }
                }
        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 */
@@ -1659,7 +1985,7 @@ int ssl3_get_certificate_request(SSL *s)
        {
        int ok,ret=0;
        unsigned long n,nc,l;
-       unsigned int llen,ctype_num,i;
+       unsigned int llen, ctype_num,i;
        X509_NAME *xn=NULL;
        const unsigned char *p,*q;
        unsigned char *d;
@@ -1679,6 +2005,14 @@ int ssl3_get_certificate_request(SSL *s)
        if (s->s3->tmp.message_type == SSL3_MT_SERVER_DONE)
                {
                s->s3->tmp.reuse_message=1;
+               /* If we get here we don't need any cached handshake records
+                * as we wont be doing client auth.
+                */
+               if (s->s3->handshake_buffer)
+                       {
+                       if (!ssl3_digest_cached_records(s))
+                               goto err;
+                       }
                return(1);
                }
 
@@ -1710,11 +2044,48 @@ int ssl3_get_certificate_request(SSL *s)
 
        /* get the certificate types */
        ctype_num= *(p++);
+       if (s->cert->ctypes)
+               {
+               OPENSSL_free(s->cert->ctypes);
+               s->cert->ctypes = NULL;
+               }
        if (ctype_num > SSL3_CT_NUMBER)
+               {
+               /* If we exceed static buffer copy all to cert structure */
+               s->cert->ctypes = OPENSSL_malloc(ctype_num);
+               memcpy(s->cert->ctypes, p, ctype_num);
+               s->cert->ctype_num = (size_t)ctype_num;
                ctype_num=SSL3_CT_NUMBER;
+               }
        for (i=0; i<ctype_num; i++)
                s->s3->tmp.ctype[i]= p[i];
-       p+=ctype_num;
+       p+=p[-1];
+       if (SSL_USE_SIGALGS(s))
+               {
+               n2s(p, llen);
+               /* Check we have enough room for signature algorithms and
+                * following length value.
+                */
+               if ((unsigned long)(p - d + llen + 2) > n)
+                       {
+                       ssl3_send_alert(s,SSL3_AL_FATAL,SSL_AD_DECODE_ERROR);
+                       SSLerr(SSL_F_SSL3_GET_CERTIFICATE_REQUEST,SSL_R_DATA_LENGTH_TOO_LONG);
+                       goto err;
+                       }
+               /* Clear certificate digests and validity flags */
+               for (i = 0; i < SSL_PKEY_NUM; i++)
+                       {
+                       s->cert->pkeys[i].digest = NULL;
+                       s->cert->pkeys[i].valid_flags = 0;
+                       }
+               if ((llen & 1) || !tls1_process_sigalgs(s, p, llen))
+                       {
+                       ssl3_send_alert(s,SSL3_AL_FATAL,SSL_AD_DECODE_ERROR);
+                       SSLerr(SSL_F_SSL3_GET_CERTIFICATE_REQUEST,SSL_R_SIGNATURE_ALGORITHMS_ERROR);
+                       goto err;
+                       }
+               p += llen;
+               }
 
        /* get the CA RDNs */
        n2s(p,llen);
@@ -1727,7 +2098,7 @@ fclose(out);
 }
 #endif
 
-       if ((llen+ctype_num+2+1) != n)
+       if ((unsigned long)(p - d + llen) != n)
                {
                ssl3_send_alert(s,SSL3_AL_FATAL,SSL_AD_DECODE_ERROR);
                SSLerr(SSL_F_SSL3_GET_CERTIFICATE_REQUEST,SSL_R_LENGTH_MISMATCH);
@@ -1833,7 +2204,7 @@ int ssl3_get_new_session_ticket(SSL *s)
        if (n < 6)
                {
                /* need at least ticket_lifetime_hint + ticket length */
-               al = SSL3_AL_FATAL,SSL_AD_DECODE_ERROR;
+               al = SSL_AD_DECODE_ERROR;
                SSLerr(SSL_F_SSL3_GET_NEW_SESSION_TICKET,SSL_R_LENGTH_MISMATCH);
                goto f_err;
                }
@@ -1844,7 +2215,7 @@ int ssl3_get_new_session_ticket(SSL *s)
        /* ticket_lifetime_hint + ticket_length + ticket */
        if (ticklen + 6 != n)
                {
-               al = SSL3_AL_FATAL,SSL_AD_DECODE_ERROR;
+               al = SSL_AD_DECODE_ERROR;
                SSLerr(SSL_F_SSL3_GET_NEW_SESSION_TICKET,SSL_R_LENGTH_MISMATCH);
                goto f_err;
                }
@@ -1987,7 +2358,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
@@ -2008,8 +2379,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;
 
@@ -2212,44 +2582,79 @@ int ssl3_send_client_key_exchange(SSL *s)
                else if (alg_k & (SSL_kEDH|SSL_kDHr|SSL_kDHd))
                        {
                        DH *dh_srvr,*dh_clnt;
+                       SESS_CERT *scert = s->session->sess_cert;
 
-                       if (s->session->sess_cert == NULL) 
+                       if (scert == 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;
                                }
 
-                       if (s->session->sess_cert->peer_dh_tmp != NULL)
-                               dh_srvr=s->session->sess_cert->peer_dh_tmp;
+                       if (scert->peer_dh_tmp != NULL)
+                               dh_srvr=scert->peer_dh_tmp;
                        else
                                {
                                /* we get them from the cert */
-                               ssl3_send_alert(s,SSL3_AL_FATAL,SSL_AD_HANDSHAKE_FAILURE);
-                               SSLerr(SSL_F_SSL3_SEND_CLIENT_KEY_EXCHANGE,SSL_R_UNABLE_TO_FIND_DH_PARAMETERS);
-                               goto err;
+                               int idx = scert->peer_cert_type;
+                               EVP_PKEY *spkey = NULL;
+                               dh_srvr = NULL;
+                               if (idx >= 0)
+                                       spkey = X509_get_pubkey(
+                                               scert->peer_pkeys[idx].x509);
+                               if (spkey)
+                                       {
+                                       dh_srvr = EVP_PKEY_get1_DH(spkey);
+                                       EVP_PKEY_free(spkey);
+                                       }
+                               if (dh_srvr == NULL)
+                                       {
+                                       SSLerr(SSL_F_SSL3_SEND_CLIENT_KEY_EXCHANGE,
+                                           ERR_R_INTERNAL_ERROR);
+                                       goto err;
+                                       }
                                }
-                       
-                       /* generate a new random key */
-                       if ((dh_clnt=DHparams_dup(dh_srvr)) == NULL)
+                       if (s->s3->flags & TLS1_FLAGS_SKIP_CERT_VERIFY)
                                {
-                               SSLerr(SSL_F_SSL3_SEND_CLIENT_KEY_EXCHANGE,ERR_R_DH_LIB);
-                               goto err;
+                               /* Use client certificate key */
+                               EVP_PKEY *clkey = s->cert->key->privatekey;
+                               dh_clnt = NULL;
+                               if (clkey)
+                                       dh_clnt = EVP_PKEY_get1_DH(clkey);
+                               if (dh_clnt == NULL)
+                                       {
+                                       SSLerr(SSL_F_SSL3_SEND_CLIENT_KEY_EXCHANGE,
+                                           ERR_R_INTERNAL_ERROR);
+                                       goto err;
+                                       }
                                }
-                       if (!DH_generate_key(dh_clnt))
+                       else
                                {
-                               SSLerr(SSL_F_SSL3_SEND_CLIENT_KEY_EXCHANGE,ERR_R_DH_LIB);
-                               goto err;
+                               /* generate a new random key */
+                               if ((dh_clnt=DHparams_dup(dh_srvr)) == NULL)
+                                       {
+                                       SSLerr(SSL_F_SSL3_SEND_CLIENT_KEY_EXCHANGE,ERR_R_DH_LIB);
+                                       goto err;
+                                       }
+                               if (!DH_generate_key(dh_clnt))
+                                       {
+                                       SSLerr(SSL_F_SSL3_SEND_CLIENT_KEY_EXCHANGE,ERR_R_DH_LIB);
+                                       DH_free(dh_clnt);
+                                       goto err;
+                                       }
                                }
 
                        /* use the 'p' output buffer for the DH key, but
                         * make sure to clear it out afterwards */
 
                        n=DH_compute_key(p,dh_srvr->pub_key,dh_clnt);
+                       if (scert->peer_dh_tmp == NULL)
+                               DH_free(dh_srvr);
 
                        if (n <= 0)
                                {
                                SSLerr(SSL_F_SSL3_SEND_CLIENT_KEY_EXCHANGE,ERR_R_DH_LIB);
+                               DH_free(dh_clnt);
                                goto err;
                                }
 
@@ -2260,11 +2665,16 @@ int ssl3_send_client_key_exchange(SSL *s)
                        /* clean up */
                        memset(p,0,n);
 
-                       /* send off the data */
-                       n=BN_num_bytes(dh_clnt->pub_key);
-                       s2n(n,p);
-                       BN_bn2bin(dh_clnt->pub_key,p);
-                       n+=2;
+                       if (s->s3->flags & TLS1_FLAGS_SKIP_CERT_VERIFY)
+                               n = 0;
+                       else
+                               {
+                               /* send off the data */
+                               n=BN_num_bytes(dh_clnt->pub_key);
+                               s2n(n,p);
+                               BN_bn2bin(dh_clnt->pub_key,p);
+                               n+=2;
+                               }
 
                        DH_free(dh_clnt);
 
@@ -2547,6 +2957,39 @@ int ssl3_send_client_key_exchange(SSL *s)
                        EVP_PKEY_free(pub_key);
 
                        }
+#ifndef OPENSSL_NO_SRP
+               else if (alg_k & SSL_kSRP)
+                       {
+                       if (s->srp_ctx.A != NULL)
+                               {
+                               /* send off the data */
+                               n=BN_num_bytes(s->srp_ctx.A);
+                               s2n(n,p);
+                               BN_bn2bin(s->srp_ctx.A,p);
+                               n+=2;
+                               }
+                       else
+                               {
+                               SSLerr(SSL_F_SSL3_SEND_CLIENT_KEY_EXCHANGE,ERR_R_INTERNAL_ERROR);
+                               goto err;
+                               }
+                       if (s->session->srp_username != NULL)
+                               OPENSSL_free(s->session->srp_username);
+                       s->session->srp_username = BUF_strdup(s->srp_ctx.login);
+                       if (s->session->srp_username == NULL)
+                               {
+                               SSLerr(SSL_F_SSL3_SEND_CLIENT_KEY_EXCHANGE,
+                                       ERR_R_MALLOC_FAILURE);
+                               goto err;
+                               }
+
+                       if ((s->session->master_key_length = SRP_generate_client_master_secret(s,s->session->master_key))<0)
+                               {
+                               SSLerr(SSL_F_SSL3_SEND_CLIENT_KEY_EXCHANGE,ERR_R_INTERNAL_ERROR);
+                               goto err;
+                               }
+                       }
+#endif
 #ifndef OPENSSL_NO_PSK
                else if (alg_k & SSL_kPSK)
                        {
@@ -2637,18 +3080,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);
@@ -2662,27 +3100,28 @@ 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;
-#ifndef OPENSSL_NO_RSA
+       EVP_MD_CTX mctx;
        unsigned u=0;
-#endif
        unsigned long n;
        int j;
 
+       EVP_MD_CTX_init(&mctx);
+
        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)
                        {
-                       s->method->ssl3_enc->cert_verify_mac(s,
+                       if (!SSL_USE_SIGALGS(s))
+                               s->method->ssl3_enc->cert_verify_mac(s,
                                                NID_sha1,
                                                &(data[MD5_DIGEST_LENGTH]));
                        }
@@ -2690,6 +3129,41 @@ int ssl3_send_client_verify(SSL *s)
                        {
                        ERR_clear_error();
                        }
+               /* For TLS v1.2 send signature algorithm and signature
+                * using agreed digest and cached handshake records.
+                */
+               if (SSL_USE_SIGALGS(s))
+                       {
+                       long hdatalen = 0;
+                       void *hdata;
+                       const EVP_MD *md = s->cert->key->digest;
+                       hdatalen = BIO_get_mem_data(s->s3->handshake_buffer,
+                                                               &hdata);
+                       if (hdatalen <= 0 || !tls12_get_sigandhash(p, pkey, md))
+                               {
+                               SSLerr(SSL_F_SSL3_SEND_CLIENT_VERIFY,
+                                               ERR_R_INTERNAL_ERROR);
+                               goto err;
+                               }
+                       p += 2;
+#ifdef SSL_DEBUG
+                       fprintf(stderr, "Using TLS 1.2 with client alg %s\n",
+                                                       EVP_MD_name(md));
+#endif
+                       if (!EVP_SignInit_ex(&mctx, md, NULL)
+                               || !EVP_SignUpdate(&mctx, hdata, hdatalen)
+                               || !EVP_SignFinal(&mctx, p + 2, &u, pkey))
+                               {
+                               SSLerr(SSL_F_SSL3_SEND_CLIENT_VERIFY,
+                                               ERR_R_EVP_LIB);
+                               goto err;
+                               }
+                       s2n(u,p);
+                       n = u + 4;
+                       if (!ssl3_digest_cached_records(s))
+                               goto err;
+                       }
+               else
 #ifndef OPENSSL_NO_RSA
                if (pkey->type == EVP_PKEY_RSA)
                        {
@@ -2765,35 +3239,82 @@ 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);
        return(-1);
        }
 
+/* Check a certificate can be used for client authentication. Currently
+ * 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)
+       {
+       unsigned long alg_k;
+       if (!s->cert || !s->cert->key->x509 || !s->cert->key->privatekey)
+               return 0;
+       /* If no suitable signature algorithm can't use certificate */
+       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 */
+       if (alg_k & (SSL_kDHr|SSL_kDHd))
+               {
+               SESS_CERT *scert = s->session->sess_cert;
+               int i = scert->peer_cert_type;
+               EVP_PKEY *clkey = NULL, *spkey = NULL;
+               clkey = s->cert->key->privatekey;
+               /* If client key not DH assume it can be used */
+               if (EVP_PKEY_id(clkey) != EVP_PKEY_DH)
+                       return 1;
+               if (i >= 0)
+                       spkey = X509_get_pubkey(scert->peer_pkeys[i].x509);
+               if (spkey)
+                       {
+                       /* Compare server and client parameters */
+                       i = EVP_PKEY_cmp_parameters(clkey, spkey);
+                       EVP_PKEY_free(spkey);
+                       if (i != 1)
+                               return 0;
+                       }
+               s->s3->flags |= TLS1_FLAGS_SKIP_CERT_VERIFY;
+               }
+       return 1;
+       }
+
 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)
                {
-               if ((s->cert == NULL) ||
-                       (s->cert->key->x509 == NULL) ||
-                       (s->cert->key->privatekey == NULL))
-                       s->state=SSL3_ST_CW_CERT_B;
-               else
+               /* Let cert callback update client certificates if required */
+               if (s->cert->cert_cb
+                       && s->cert->cert_cb(s, s->cert->cert_cb_arg) <= 0)
+                       {
+                       ssl3_send_alert(s,SSL3_AL_FATAL,SSL_AD_INTERNAL_ERROR);
+                       return 0;
+                       }
+               if (ssl3_check_client_certificate(s))
                        s->state=SSL3_ST_CW_CERT_C;
+               else
+                       s->state=SSL3_ST_CW_CERT_B;
                }
 
        /* We need to get a client cert */
@@ -2825,6 +3346,8 @@ int ssl3_send_client_certificate(SSL *s)
 
                if (x509 != NULL) X509_free(x509);
                if (pkey != NULL) EVP_PKEY_free(pkey);
+               if (i && !ssl3_check_client_certificate(s))
+                       i = 0;
                if (i == 0)
                        {
                        if (s->version == SSL3_VERSION)
@@ -2846,13 +3369,11 @@ 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->x509);
-               s->init_num=(int)l;
-               s->init_off=0;
+               ssl3_output_cert_chain(s,
+                       (s->s3->tmp.cert_req == 2)?NULL:s->cert->key);
                }
        /* 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))
@@ -2874,7 +3395,7 @@ int ssl3_check_cert_and_algorithm(SSL *s)
        alg_a=s->s3->tmp.new_cipher->algorithm_auth;
 
        /* we don't have a certificate */
-       if ((alg_a & (SSL_aDH|SSL_aNULL|SSL_aKRB5)) || (alg_k & SSL_kPSK))
+       if ((alg_a & (SSL_aNULL|SSL_aKRB5)) || (alg_k & SSL_kPSK))
                return(1);
 
        sc=s->session->sess_cert;
@@ -2898,7 +3419,7 @@ int ssl3_check_cert_and_algorithm(SSL *s)
        if (idx == SSL_PKEY_ECC)
                {
                if (ssl_check_srvr_ecc_cert_and_alg(sc->peer_pkeys[idx].x509,
-                   s->s3->tmp.new_cipher) == 0) 
+                                                               s) == 0) 
                        { /* check failed */
                        SSLerr(SSL_F_SSL3_CHECK_CERT_AND_ALGORITHM,SSL_R_BAD_ECC_CERT);
                        goto f_err;
@@ -2908,6 +3429,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);
@@ -2936,19 +3467,21 @@ int ssl3_check_cert_and_algorithm(SSL *s)
                }
 #endif
 #ifndef OPENSSL_NO_DH
-       if ((alg_k & SSL_kEDH) &&
+       if ((alg_k & SSL_kEDH) && 
                !(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) && !has_bits(i,EVP_PK_DH|EVP_PKS_RSA))
+       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) && !has_bits(i,EVP_PK_DH|EVP_PKS_DSA))
+       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);
                goto f_err;
@@ -3000,6 +3533,32 @@ err:
  */
 
 #ifndef OPENSSL_NO_TLSEXT
+# ifndef OPENSSL_NO_NEXTPROTONEG
+int ssl3_send_next_proto(SSL *s)
+       {
+       unsigned int len, padding_len;
+       unsigned char *d;
+
+       if (s->state == SSL3_ST_CW_NEXT_PROTO_A)
+               {
+               len = s->next_proto_negotiated_len;
+               padding_len = 32 - ((len + 2) % 32);
+               d = (unsigned char *)s->init_buf->data;
+               d[4] = len;
+               memcpy(d + 5, s->next_proto_negotiated, len);
+               d[5 + len] = padding_len;
+               memset(d + 6 + len, 0, padding_len);
+               *(d++)=SSL3_MT_NEXT_PROTO;
+               l2n3(2 + len + padding_len, d);
+               s->state = SSL3_ST_CW_NEXT_PROTO_B;
+               s->init_num = 4 + 2 + len + padding_len;
+               s->init_off = 0;
+               }
+
+       return ssl3_do_write(s, SSL3_RT_HANDSHAKE);
+       }
+# endif
+
 int ssl3_check_finished(SSL *s)
        {
        int ok;
@@ -3042,3 +3601,106 @@ 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