Add new ctrl to retrieve client certificate types, print out
[openssl.git] / ssl / s3_clnt.c
index 0633c099c62a6a98fced8fb59ba7c0d9c148d54b..812af8cb5ade1689447a1e22ae3aecfd4332444d 100644 (file)
  */
 
 #include <stdio.h>
-#include <openssl/crypto.h>
 #include "ssl_locl.h"
 #include "kssl_lcl.h"
 #include <openssl/buffer.h>
@@ -204,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;
@@ -281,29 +292,41 @@ int ssl3_connect(SSL *s)
                case SSL3_ST_CR_SRVR_HELLO_A:
                case SSL3_ST_CR_SRVR_HELLO_B:
                        ret=ssl3_get_server_hello(s);
-#ifndef OPENSSL_NO_SRP
-                       if ((ret == 0) && (s->s3->warn_alert == SSL_AD_MISSING_SRP_USERNAME))
-                               {
-                               if (!SRP_have_to_put_srp_username(s))
-                                       {
-                                       SSLerr(SSL_F_SSL3_CONNECT,SSL_R_MISSING_SRP_USERNAME);
-                                       ssl3_send_alert(s,SSL3_AL_FATAL,SSL_AD_USER_CANCELLED);
-                                       goto end;
-                                       }
-                               s->state=SSL3_ST_CW_CLNT_HELLO_A;
-                               if (!ssl_init_wbio_buffer(s,0)) { ret= -1; goto end; }
-                               break;
-                               }
-#endif
                        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
@@ -456,7 +479,7 @@ int ssl3_connect(SSL *s)
 #if defined(OPENSSL_NO_TLSEXT) || defined(OPENSSL_NO_NEXTPROTONEG)
                        s->state=SSL3_ST_CW_FINISHED_A;
 #else
-                       if (s->next_proto_negotiated)
+                       if (s->s3->next_proto_neg_seen)
                                s->state=SSL3_ST_CW_NEXT_PROTO_A;
                        else
                                s->state=SSL3_ST_CW_FINISHED_A;
@@ -682,9 +705,43 @@ int ssl3_client_hello(SSL *s)
                /* Do the message type and length last */
                d=p= &(buf[4]);
 
+               /* 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);
@@ -714,6 +771,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;
 
@@ -772,7 +838,7 @@ int ssl3_get_server_hello(SSL *s)
        STACK_OF(SSL_CIPHER) *sk;
        const SSL_CIPHER *c;
        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
@@ -878,7 +944,6 @@ int ssl3_get_server_hello(SSL *s)
                        {
                        if (!ssl_get_new_session(s,0))
                                {
-                               al=SSL_AD_INTERNAL_ERROR;
                                goto f_err;
                                }
                        }
@@ -894,6 +959,14 @@ int ssl3_get_server_hello(SSL *s)
                SSLerr(SSL_F_SSL3_GET_SERVER_HELLO,SSL_R_UNKNOWN_CIPHER_RETURNED);
                goto f_err;
                }
+       /* TLS v1.2 only ciphersuites require v1.2 or later */
+       if ((c->algorithm_ssl & SSL_TLSV1_2) && 
+               (TLS1_get_version(s) < TLS1_2_VERSION))
+               {
+               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);
@@ -928,7 +1001,7 @@ int ssl3_get_server_hello(SSL *s)
        /* Don't digest cached records if TLS v1.2: we may need them for
         * client authentication.
         */
-       if (s->version < TLS1_2_VERSION && !ssl3_digest_cached_records(s))
+       if (TLS1_get_version(s) < TLS1_2_VERSION && !ssl3_digest_cached_records(s))
                goto f_err;
        /* lets get the compression algorithm */
        /* COMPRESSION */
@@ -944,7 +1017,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;
                }
@@ -981,19 +1053,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
 
@@ -1002,7 +1065,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);
@@ -1184,8 +1247,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:
@@ -1659,7 +1736,7 @@ int ssl3_get_key_exchange(SSL *s)
        /* if it was signed, check the signature */
        if (pkey != NULL)
                {
-               if (s->version >= TLS1_2_VERSION)
+               if (TLS1_get_version(s) >= TLS1_2_VERSION)
                        {
                        int sigalg = tls12_get_sigid(pkey);
                        /* Should never happen */
@@ -1704,7 +1781,7 @@ fprintf(stderr, "USING TLSv1.2 HASH %s\n", EVP_MD_name(md));
                        }
 
 #ifndef OPENSSL_NO_RSA
-               if (pkey->type == EVP_PKEY_RSA && s->version < TLS1_2_VERSION)
+               if (pkey->type == EVP_PKEY_RSA && TLS1_get_version(s) < TLS1_2_VERSION)
                        {
                        int num;
 
@@ -1859,13 +1936,23 @@ 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;
-       /* HACK! For now just skip over signatature algorithms */
-       if (s->version >= TLS1_2_VERSION)
+       p+=p[-1];
+       if (TLS1_get_version(s) >= TLS1_2_VERSION)
                {
                n2s(p, llen);
                /* Check we have enough room for signature algorithms and
@@ -2003,7 +2090,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;
                }
@@ -2014,7 +2101,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;
                }
@@ -2382,44 +2469,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;
                                }
 
@@ -2430,11 +2552,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);
 
@@ -2886,7 +3013,7 @@ int ssl3_send_client_verify(SSL *s)
                EVP_PKEY_sign_init(pctx);
                if (EVP_PKEY_CTX_set_signature_md(pctx, EVP_sha1())>0)
                        {
-                       if (s->version < TLS1_2_VERSION)
+                       if (TLS1_get_version(s) < TLS1_2_VERSION)
                                s->method->ssl3_enc->cert_verify_mac(s,
                                                NID_sha1,
                                                &(data[MD5_DIGEST_LENGTH]));
@@ -2898,7 +3025,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 (s->version >= TLS1_2_VERSION)
+               if (TLS1_get_version(s) >= TLS1_2_VERSION)
                        {
                        long hdatalen = 0;
                        void *hdata;
@@ -3021,6 +3148,40 @@ err:
        return(-1);
        }
 
+/* Check a certificate can be used for client authentication. Currently
+ * just check cert exists and if static DH client certificates can be used.
+ */
+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;
+       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;
@@ -3030,12 +3191,17 @@ int ssl3_send_client_certificate(SSL *s)
 
        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 */
@@ -3067,6 +3233,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)
@@ -3089,7 +3257,7 @@ int ssl3_send_client_certificate(SSL *s)
                {
                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->s3->tmp.cert_req == 2)?NULL:s->cert->key);
                s->init_num=(int)l;
                s->init_off=0;
                }
@@ -3116,7 +3284,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;
@@ -3178,19 +3346,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) && (TLS1_get_version(s) < TLS1_2_VERSION) &&
+               !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) && (TLS1_get_version(s) < TLS1_2_VERSION) &&
+               !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;
@@ -3310,3 +3480,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