PR: 2295
authorDr. Stephen Henson <steve@openssl.org>
Fri, 20 May 2011 14:56:29 +0000 (14:56 +0000)
committerDr. Stephen Henson <steve@openssl.org>
Fri, 20 May 2011 14:56:29 +0000 (14:56 +0000)
Submitted by: Alexei Khlebnikov <alexei.khlebnikov@opera.com>
Reviewed by: steve

OOM checking. Leak in OOM fix. Fall-through comment. Duplicate code
elimination.

CHANGES
ssl/s3_enc.c
ssl/s3_srvr.c
ssl/ssl3.h
ssl/ssl_locl.h
ssl/t1_lib.c

diff --git a/CHANGES b/CHANGES
index 6d25e4d..2274965 100644 (file)
--- a/CHANGES
+++ b/CHANGES
@@ -4,6 +4,9 @@
 
  Changes between 1.0.1 and 1.1.0  [xx XXX xxxx]
 
+  *) Add TLS v1.2 server support for client authentication. 
+     [Steve Henson]
+
   *) Add support for FIPS mode in ssl library: disable SSLv3, non-FIPS ciphers
      and enable MD5.
      [Steve Henson]
index 9f5574a..dc3101f 100644 (file)
@@ -569,12 +569,12 @@ void ssl3_free_digest_list(SSL *s)
        OPENSSL_free(s->s3->handshake_dgst);
        s->s3->handshake_dgst=NULL;
        }       
-               
+
 
 
 void ssl3_finish_mac(SSL *s, const unsigned char *buf, int len)
        {
-       if (s->s3->handshake_buffer) 
+       if (s->s3->handshake_buffer && !(s->s3->flags & TLS1_FLAGS_KEEP_HANDSHAKE)
                {
                BIO_write (s->s3->handshake_buffer,(void *)buf,len);
                } 
@@ -629,9 +629,12 @@ int ssl3_digest_cached_records(SSL *s)
                        s->s3->handshake_dgst[i]=NULL;
                        }
                }
-       /* Free handshake_buffer BIO */
-       BIO_free(s->s3->handshake_buffer);
-       s->s3->handshake_buffer = NULL;
+       if (!(s->s3->flags & TLS1_FLAGS_KEEP_HANDSHAKE))
+               {
+               /* Free handshake_buffer BIO */
+               BIO_free(s->s3->handshake_buffer);
+               s->s3->handshake_buffer = NULL;
+               }
 
        return 1;
        }
index 940c951..9a2be88 100644 (file)
@@ -516,6 +516,9 @@ int ssl3_accept(SSL *s)
                                skip=1;
                                s->s3->tmp.cert_request=0;
                                s->state=SSL3_ST_SW_SRVR_DONE_A;
+                               if (s->s3->handshake_buffer)
+                                       if (!ssl3_digest_cached_records(s))
+                                               return -1;
                                }
                        else
                                {
@@ -608,6 +611,24 @@ int ssl3_accept(SSL *s)
 #endif
                                s->init_num = 0;
                                }
+                       else if (s->version >= TLS1_2_VERSION)
+                               {
+                               s->state=SSL3_ST_SR_CERT_VRFY_A;
+                               s->init_num=0;
+                               if (!s->session->peer)
+                                       break;
+                               /* For TLS v1.2 freeze the handshake buffer
+                                * at this point and digest cached records.
+                                */
+                               if (!s->s3->handshake_buffer)
+                                       {
+                                       SSLerr(SSL_F_SSL3_ACCEPT,ERR_R_INTERNAL_ERROR);
+                                       return -1;
+                                       }
+                               s->s3->flags |= TLS1_FLAGS_KEEP_HANDSHAKE;
+                               if (!ssl3_digest_cached_records(s))
+                                       return -1;
+                               }
                        else
                                {
                                int offset=0;
@@ -1359,8 +1380,11 @@ int ssl3_get_client_hello(SSL *s)
                s->s3->tmp.new_cipher=s->session->cipher;
                }
 
-       if (!ssl3_digest_cached_records(s))
-               goto f_err;
+       if (s->version < TLS1_2_VERSION || !(s->verify_mode & SSL_VERIFY_PEER))
+               {
+               if (!ssl3_digest_cached_records(s))
+                       goto f_err;
+               }
        
        /* we now have the following setup. 
         * client_random
@@ -2007,6 +2031,14 @@ int ssl3_send_certificate_request(SSL *s)
                p+=n;
                n++;
 
+               if (s->version >= TLS1_2_VERSION)
+                       {
+                       nl = tls12_get_req_sig_algs(s, p + 2);
+                       s2n(nl, p);
+                       p += nl + 2;
+                       n += nl + 2;
+                       }
+
                off=n;
                p+=2;
                n+=2;
@@ -2861,6 +2893,9 @@ int ssl3_get_cert_verify(SSL *s)
        long n;
        int type=0,i,j;
        X509 *peer;
+       const EVP_MD *md = NULL;
+       EVP_MD_CTX mctx;
+       EVP_MD_CTX_init(&mctx);
 
        n=s->method->ssl_get_message(s,
                SSL3_ST_SR_CERT_VRFY_A,
@@ -2929,6 +2964,36 @@ int ssl3_get_cert_verify(SSL *s)
                } 
        else 
                {       
+               if (s->version >= TLS1_2_VERSION)
+                       {
+                       int sigalg = tls12_get_sigid(pkey);
+                       /* Should never happen */
+                       if (sigalg == -1)
+                               {
+                               SSLerr(SSL_F_SSL3_GET_CERT_VERIFY,ERR_R_INTERNAL_ERROR);
+                               al=SSL_AD_INTERNAL_ERROR;
+                               goto f_err;
+                               }
+                       /* Check key type is consistent with signature */
+                       if (sigalg != (int)p[1])
+                               {
+                               SSLerr(SSL_F_SSL3_GET_CERT_VERIFY,SSL_R_WRONG_SIGNATURE_TYPE);
+                               al=SSL_AD_DECODE_ERROR;
+                               goto f_err;
+                               }
+                       md = tls12_get_hash(p[0]);
+                       if (md == NULL)
+                               {
+                               SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE,SSL_R_UNKNOWN_DIGEST);
+                               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;
+                       }
                n2s(p,i);
                n-=2;
                if (i > n)
@@ -2946,6 +3011,37 @@ int ssl3_get_cert_verify(SSL *s)
                goto f_err;
                }
 
+       if (s->version >= TLS1_2_VERSION)
+               {
+               long hdatalen = 0;
+               void *hdata;
+               hdatalen = BIO_get_mem_data(s->s3->handshake_buffer, &hdata);
+               if (hdatalen <= 0)
+                       {
+                       SSLerr(SSL_F_SSL3_GET_CERT_VERIFY, ERR_R_INTERNAL_ERROR);
+                       al=SSL_AD_INTERNAL_ERROR;
+                       goto f_err;
+                       }
+#ifdef SSL_DEBUG
+               fprintf(stderr, "Using TLS 1.2 with client verify alg %s\n",
+                                                       EVP_MD_name(md));
+#endif
+               if (!EVP_VerifyInit_ex(&mctx, md, NULL)
+                       || !EVP_VerifyUpdate(&mctx, hdata, hdatalen))
+                       {
+                       SSLerr(SSL_F_SSL3_GET_CERT_VERIFY, ERR_R_EVP_LIB);
+                       al=SSL_AD_INTERNAL_ERROR;
+                       goto f_err;
+                       }
+
+               if (EVP_VerifyFinal(&mctx, p , i, pkey) <= 0)
+                       {
+                       al=SSL_AD_DECRYPT_ERROR;
+                       SSLerr(SSL_F_SSL3_GET_CERT_VERIFY,SSL_R_BAD_SIGNATURE);
+                       goto f_err;
+                       }
+               }
+       else
 #ifndef OPENSSL_NO_RSA 
        if (pkey->type == EVP_PKEY_RSA)
                {
@@ -3036,6 +3132,13 @@ f_err:
                ssl3_send_alert(s,SSL3_AL_FATAL,al);
                }
 end:
+       if (s->s3->handshake_buffer)
+               {
+               BIO_free(s->s3->handshake_buffer);
+               s->s3->handshake_buffer = NULL;
+               s->s3->flags &= ~TLS1_FLAGS_KEEP_HANDSHAKE;
+               }
+       EVP_MD_CTX_cleanup(&mctx);
        EVP_PKEY_free(pkey);
        return(ret);
        }
@@ -3148,6 +3251,12 @@ int ssl3_get_client_certificate(SSL *s)
                        al=SSL_AD_HANDSHAKE_FAILURE;
                        goto f_err;
                        }
+               /* No client certificate so digest cached records */
+               if (s->s3->handshake_buffer && !ssl3_digest_cached_records(s))
+                       {
+                       al=SSL_AD_INTERNAL_ERROR;
+                       goto f_err;
+                       }
                }
        else
                {
index ea0c854..aa9987f 100644 (file)
@@ -383,6 +383,7 @@ typedef struct ssl3_buffer_st
 #define SSL3_FLAGS_POP_BUFFER                  0x0004
 #define TLS1_FLAGS_TLS_PADDING_BUG             0x0008
 #define TLS1_FLAGS_SKIP_CERT_VERIFY            0x0010
+#define TLS1_FLAGS_KEEP_HANDSHAKE              0x0020
 
 #ifndef OPENSSL_NO_SSL_INTERN
 
index 1c17de7..ca88199 100644 (file)
@@ -1096,4 +1096,5 @@ int ssl_parse_clienthello_renegotiate_ext(SSL *s, unsigned char *d, int len,
                                          int *al);
 long ssl_get_algorithm2(SSL *s);
 int tls1_process_sigalgs(SSL *s, const unsigned char *data, int dsize);
+int tls12_get_req_sig_algs(SSL *s, unsigned char *p);
 #endif
index 928295e..414e4c2 100644 (file)
@@ -315,7 +315,12 @@ static unsigned char tls12_sigalgs[] = {
 #endif
 };
 
-
+int tls12_get_req_sig_algs(SSL *s, unsigned char *p)
+       {
+       if (p)
+               memcpy(p, tls12_sigalgs, sizeof(tls12_sigalgs));
+       return (int)sizeof(tls12_sigalgs);
+       }
 
 unsigned char *ssl_add_clienthello_tlsext(SSL *s, unsigned char *p, unsigned char *limit)
        {