Add new ctrl to retrieve client certificate types, print out
[openssl.git] / ssl / s3_clnt.c
index 7a8b7f27d07dceaf96ab75016e87ea3c67b9ac88..812af8cb5ade1689447a1e22ae3aecfd4332444d 100644 (file)
  */
 
 #include <stdio.h>
-#include <openssl/crypto.h>
 #include "ssl_locl.h"
 #include "kssl_lcl.h"
 #include <openssl/buffer.h>
@@ -307,10 +306,27 @@ int ssl3_connect(SSL *s)
 #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
@@ -689,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);
@@ -721,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;
 
@@ -779,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
@@ -885,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;
                                }
                        }
@@ -959,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;
                }
@@ -996,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
 
@@ -1199,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:
@@ -1874,11 +1936,22 @@ 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 (TLS1_get_version(s) >= TLS1_2_VERSION)
                {
                n2s(p, llen);
@@ -3118,6 +3191,13 @@ int ssl3_send_client_certificate(SSL *s)
 
        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)
+                       {
+                       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
@@ -3177,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;
                }
@@ -3400,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