From b81fde02aa9c09b41ca83c59f885140d85cb9002 Mon Sep 17 00:00:00 2001 From: "Dr. Stephen Henson" Date: Fri, 20 May 2011 14:58:45 +0000 Subject: [PATCH] Add server client certificate support for TLS v1.2 . This is more complex than client side as we need to keep the handshake record cache frozen when it contains all the records need to process the certificate verify message. (backport from HEAD). --- CHANGES | 3 ++ ssl/s3_enc.c | 13 +++--- ssl/s3_srvr.c | 113 ++++++++++++++++++++++++++++++++++++++++++++++++- ssl/ssl3.h | 1 + ssl/ssl_locl.h | 1 + ssl/t1_lib.c | 8 ++++ 6 files changed, 132 insertions(+), 7 deletions(-) diff --git a/CHANGES b/CHANGES index 9f37b80aa5..656b6a2f8f 100644 --- a/CHANGES +++ b/CHANGES @@ -4,6 +4,9 @@ Changes between 1.0.0d and 1.0.1 [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] diff --git a/ssl/s3_enc.c b/ssl/s3_enc.c index 9f5574a01e..dc3101ff14 100644 --- a/ssl/s3_enc.c +++ b/ssl/s3_enc.c @@ -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; } diff --git a/ssl/s3_srvr.c b/ssl/s3_srvr.c index 9dc2a38750..861b0f3e3c 100644 --- a/ssl/s3_srvr.c +++ b/ssl/s3_srvr.c @@ -513,6 +513,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 { @@ -598,6 +601,24 @@ int ssl3_accept(SSL *s) s->state=SSL3_ST_SR_FINISHED_A; 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; @@ -1316,8 +1337,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 @@ -1963,6 +1987,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; @@ -2817,6 +2849,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, @@ -2885,6 +2920,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) @@ -2902,6 +2967,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) { @@ -2992,6 +3088,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); } @@ -3104,6 +3207,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 { diff --git a/ssl/ssl3.h b/ssl/ssl3.h index 45fef15fb6..38c5cc29a6 100644 --- a/ssl/ssl3.h +++ b/ssl/ssl3.h @@ -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 diff --git a/ssl/ssl_locl.h b/ssl/ssl_locl.h index 9847e5eb51..65a3639a44 100644 --- a/ssl/ssl_locl.h +++ b/ssl/ssl_locl.h @@ -1092,4 +1092,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 diff --git a/ssl/t1_lib.c b/ssl/t1_lib.c index bf721929d7..494f42d4e7 100644 --- a/ssl/t1_lib.c +++ b/ssl/t1_lib.c @@ -270,6 +270,14 @@ int tls1_ec_nid2curve_id(int nid) #endif /* OPENSSL_NO_EC */ #ifndef OPENSSL_NO_TLSEXT + +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) { int extdatalen=0; -- 2.25.1