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;