From a2f9200fba20ae7c25531c2f2ce6f80610f257e2 Mon Sep 17 00:00:00 2001 From: "Dr. Stephen Henson" Date: Mon, 9 May 2011 15:44:01 +0000 Subject: [PATCH] Initial TLS v1.2 client support. Include a default supported signature algorithms extension (including everything we support). Swicth to new signature format where needed and relax ECC restrictions. Not TLS v1.2 client certifcate support yet but client will handle case where a certificate is requested and we don't have one. --- CHANGES | 6 ++ apps/s_client.c | 15 +++++ ssl/s3_clnt.c | 81 +++++++++++++++----------- ssl/s3_srvr.c | 4 ++ ssl/ssl.h | 2 + ssl/ssl_err.c | 2 + ssl/ssl_lib.c | 7 ++- ssl/ssl_locl.h | 9 ++- ssl/t1_enc.c | 11 ++++ ssl/t1_lib.c | 149 ++++++++++++++++++++++++++++++++++-------------- 10 files changed, 206 insertions(+), 80 deletions(-) diff --git a/CHANGES b/CHANGES index a955b3fd98..1ee3a478d3 100644 --- a/CHANGES +++ b/CHANGES @@ -4,6 +4,12 @@ Changes between 1.0.1 and 1.1.0 [xx XXX xxxx] + *) Initial TLS v1.2 client support. Add a default signature algorithms + extension including all the algorithms we support. Parse new signature + format in client key exchange. Relax some ECC signing restrictions for + TLS v1.2 as indicated in RFC5246. + [Steve Henson] + *) Add server support for TLS v1.2 signature algorithms extension. Switch to new signature format when needed using client digest preference. All server ciphersuites should now work correctly in TLS v1.2. No client diff --git a/apps/s_client.c b/apps/s_client.c index faf7f39c1d..2b8b1455eb 100644 --- a/apps/s_client.c +++ b/apps/s_client.c @@ -1103,6 +1103,9 @@ bad: SSL_CTX_set_psk_client_callback(ctx, psk_client_cb); } #endif + /* HACK while TLS v1.2 is disabled by default */ + if (!(off & SSL_OP_NO_TLSv1_2)) + SSL_CTX_clear_options(ctx, SSL_OP_NO_TLSv1_2); if (bugs) SSL_CTX_set_options(ctx,SSL_OP_ALL|off); else @@ -2011,6 +2014,18 @@ static void print_stuff(BIO *bio, SSL *s, int full) } #endif +#ifdef SSL_DEBUG + { + /* Print out local port of connection: useful for debugging */ + int sock; + struct sockaddr_in ladd; + socklen_t ladd_size = sizeof(ladd); + sock = SSL_get_fd(s); + getsockname(sock, (struct sockaddr *)&ladd, &ladd_size); + BIO_printf(bio_c_out, "LOCAL PORT is %u\n", ntohs(ladd.sin_port)); + } +#endif + SSL_SESSION_print(bio,SSL_get_session(s)); BIO_printf(bio,"---\n"); if (peer != NULL) diff --git a/ssl/s3_clnt.c b/ssl/s3_clnt.c index f96ec4f984..0541de95b9 100644 --- a/ssl/s3_clnt.c +++ b/ssl/s3_clnt.c @@ -1203,6 +1203,7 @@ int ssl3_get_key_exchange(SSL *s) int al,i,j,param_len,ok; long n,alg_k,alg_a; EVP_PKEY *pkey=NULL; + const EVP_MD *md = NULL; #ifndef OPENSSL_NO_RSA RSA *rsa=NULL; #endif @@ -1653,6 +1654,38 @@ int ssl3_get_key_exchange(SSL *s) /* if it was signed, check the signature */ if (pkey != NULL) { + if (s->version >= TLS1_2_VERSION) + { + int sigalg = tls12_get_sigid(pkey); + /* Should never happen */ + if (sigalg == -1) + { + SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE,ERR_R_INTERNAL_ERROR); + goto err; + } + /* Check key type is consistent with signature */ + if (sigalg != (int)p[1]) + { + SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE,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; + } + else + md = EVP_sha1(); + n2s(p,i); n-=2; j=EVP_PKEY_size(pkey); @@ -1666,7 +1699,7 @@ int ssl3_get_key_exchange(SSL *s) } #ifndef OPENSSL_NO_RSA - if (pkey->type == EVP_PKEY_RSA) + if (pkey->type == EVP_PKEY_RSA && s->version < TLS1_2_VERSION) { int num; @@ -1701,29 +1734,8 @@ int ssl3_get_key_exchange(SSL *s) } else #endif -#ifndef OPENSSL_NO_DSA - if (pkey->type == EVP_PKEY_DSA) - { - /* lets do DSS */ - EVP_VerifyInit_ex(&md_ctx,EVP_dss1(), NULL); - EVP_VerifyUpdate(&md_ctx,&(s->s3->client_random[0]),SSL3_RANDOM_SIZE); - EVP_VerifyUpdate(&md_ctx,&(s->s3->server_random[0]),SSL3_RANDOM_SIZE); - EVP_VerifyUpdate(&md_ctx,param,param_len); - if (EVP_VerifyFinal(&md_ctx,p,(int)n,pkey) <= 0) - { - /* bad signature */ - al=SSL_AD_DECRYPT_ERROR; - SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE,SSL_R_BAD_SIGNATURE); - goto f_err; - } - } - else -#endif -#ifndef OPENSSL_NO_ECDSA - if (pkey->type == EVP_PKEY_EC) { - /* let's do ECDSA */ - EVP_VerifyInit_ex(&md_ctx,EVP_ecdsa(), NULL); + EVP_VerifyInit_ex(&md_ctx, md, NULL); EVP_VerifyUpdate(&md_ctx,&(s->s3->client_random[0]),SSL3_RANDOM_SIZE); EVP_VerifyUpdate(&md_ctx,&(s->s3->server_random[0]),SSL3_RANDOM_SIZE); EVP_VerifyUpdate(&md_ctx,param,param_len); @@ -1735,12 +1747,6 @@ int ssl3_get_key_exchange(SSL *s) goto f_err; } } - else -#endif - { - SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE,ERR_R_INTERNAL_ERROR); - goto err; - } } else { @@ -1787,7 +1793,7 @@ int ssl3_get_certificate_request(SSL *s) { int ok,ret=0; unsigned long n,nc,l; - unsigned int llen,ctype_num,i; + unsigned int llen,sigalglen, ctype_num,i; X509_NAME *xn=NULL; const unsigned char *p,*q; unsigned char *d; @@ -1843,6 +1849,17 @@ int ssl3_get_certificate_request(SSL *s) for (i=0; is3->tmp.ctype[i]= p[i]; p+=ctype_num; + /* HACK! For now just skip over signatature algorithms */ + if (s->version >= TLS1_2_VERSION) + { + n2s(p, sigalglen); + p += sigalglen; + sigalglen += 2; + } + else + sigalglen = 0; + + /* get the CA RDNs */ n2s(p,llen); @@ -1855,7 +1872,7 @@ fclose(out); } #endif - if ((llen+ctype_num+2+1) != n) + if ((llen+ctype_num+sigalglen+2+1) != n) { ssl3_send_alert(s,SSL3_AL_FATAL,SSL_AD_DECODE_ERROR); SSLerr(SSL_F_SSL3_GET_CERTIFICATE_REQUEST,SSL_R_LENGTH_MISMATCH); @@ -3059,7 +3076,7 @@ int ssl3_check_cert_and_algorithm(SSL *s) if (idx == SSL_PKEY_ECC) { if (ssl_check_srvr_ecc_cert_and_alg(sc->peer_pkeys[idx].x509, - s->s3->tmp.new_cipher) == 0) + s) == 0) { /* check failed */ SSLerr(SSL_F_SSL3_CHECK_CERT_AND_ALGORITHM,SSL_R_BAD_ECC_CERT); goto f_err; diff --git a/ssl/s3_srvr.c b/ssl/s3_srvr.c index 4eec497bef..0f203ec6b1 100644 --- a/ssl/s3_srvr.c +++ b/ssl/s3_srvr.c @@ -1932,6 +1932,10 @@ int ssl3_send_server_key_exchange(SSL *s) } p+=2; } +#ifdef SSL_DEBUG + fprintf(stderr, "Using hash %s\n", + EVP_MD_name(md)); +#endif EVP_SignInit_ex(&md_ctx, md, NULL); EVP_SignUpdate(&md_ctx,&(s->s3->client_random[0]),SSL3_RANDOM_SIZE); EVP_SignUpdate(&md_ctx,&(s->s3->server_random[0]),SSL3_RANDOM_SIZE); diff --git a/ssl/ssl.h b/ssl/ssl.h index c487407607..755dd853dc 100644 --- a/ssl/ssl.h +++ b/ssl/ssl.h @@ -2500,6 +2500,7 @@ void ERR_load_SSL_strings(void); #define SSL_R_UNKNOWN_CERTIFICATE_TYPE 247 #define SSL_R_UNKNOWN_CIPHER_RETURNED 248 #define SSL_R_UNKNOWN_CIPHER_TYPE 249 +#define SSL_R_UNKNOWN_DIGEST 357 #define SSL_R_UNKNOWN_KEY_EXCHANGE_TYPE 250 #define SSL_R_UNKNOWN_PKEY_TYPE 251 #define SSL_R_UNKNOWN_PROTOCOL 252 @@ -2520,6 +2521,7 @@ void ERR_load_SSL_strings(void); #define SSL_R_WRONG_NUMBER_OF_KEY_BITS 263 #define SSL_R_WRONG_SIGNATURE_LENGTH 264 #define SSL_R_WRONG_SIGNATURE_SIZE 265 +#define SSL_R_WRONG_SIGNATURE_TYPE 358 #define SSL_R_WRONG_SSL_VERSION 266 #define SSL_R_WRONG_VERSION_NUMBER 267 #define SSL_R_X509_LIB 268 diff --git a/ssl/ssl_err.c b/ssl/ssl_err.c index af52856a68..76c8e1e33e 100644 --- a/ssl/ssl_err.c +++ b/ssl/ssl_err.c @@ -543,6 +543,7 @@ static ERR_STRING_DATA SSL_str_reasons[]= {ERR_REASON(SSL_R_UNKNOWN_CERTIFICATE_TYPE),"unknown certificate type"}, {ERR_REASON(SSL_R_UNKNOWN_CIPHER_RETURNED),"unknown cipher returned"}, {ERR_REASON(SSL_R_UNKNOWN_CIPHER_TYPE) ,"unknown cipher type"}, +{ERR_REASON(SSL_R_UNKNOWN_DIGEST) ,"unknown digest"}, {ERR_REASON(SSL_R_UNKNOWN_KEY_EXCHANGE_TYPE),"unknown key exchange type"}, {ERR_REASON(SSL_R_UNKNOWN_PKEY_TYPE) ,"unknown pkey type"}, {ERR_REASON(SSL_R_UNKNOWN_PROTOCOL) ,"unknown protocol"}, @@ -563,6 +564,7 @@ static ERR_STRING_DATA SSL_str_reasons[]= {ERR_REASON(SSL_R_WRONG_NUMBER_OF_KEY_BITS),"wrong number of key bits"}, {ERR_REASON(SSL_R_WRONG_SIGNATURE_LENGTH),"wrong signature length"}, {ERR_REASON(SSL_R_WRONG_SIGNATURE_SIZE) ,"wrong signature size"}, +{ERR_REASON(SSL_R_WRONG_SIGNATURE_TYPE) ,"wrong signature type"}, {ERR_REASON(SSL_R_WRONG_SSL_VERSION) ,"wrong ssl version"}, {ERR_REASON(SSL_R_WRONG_VERSION_NUMBER) ,"wrong version number"}, {ERR_REASON(SSL_R_X509_LIB) ,"x509 lib"}, diff --git a/ssl/ssl_lib.c b/ssl/ssl_lib.c index 114ad476a8..3f60ab1612 100644 --- a/ssl/ssl_lib.c +++ b/ssl/ssl_lib.c @@ -2185,12 +2185,13 @@ void ssl_set_cert_masks(CERT *c, const SSL_CIPHER *cipher) #ifndef OPENSSL_NO_EC -int ssl_check_srvr_ecc_cert_and_alg(X509 *x, const SSL_CIPHER *cs) +int ssl_check_srvr_ecc_cert_and_alg(X509 *x, SSL *s) { unsigned long alg_k, alg_a; EVP_PKEY *pkey = NULL; int keysize = 0; int signature_nid = 0; + const SSL_CIPHER *cs = s->s3->tmp.new_cipher; alg_k = cs->algorithm_mkey; alg_a = cs->algorithm_auth; @@ -2217,7 +2218,7 @@ int ssl_check_srvr_ecc_cert_and_alg(X509 *x, const SSL_CIPHER *cs) SSLerr(SSL_F_SSL_CHECK_SRVR_ECC_CERT_AND_ALG, SSL_R_ECC_CERT_NOT_FOR_KEY_AGREEMENT); return 0; } - if (alg_k & SSL_kECDHe) + if ((alg_k & SSL_kECDHe) && s->version < TLS1_2_VERSION) { /* signature alg must be ECDSA */ if (signature_nid != NID_ecdsa_with_SHA1) @@ -2226,7 +2227,7 @@ int ssl_check_srvr_ecc_cert_and_alg(X509 *x, const SSL_CIPHER *cs) return 0; } } - if (alg_k & SSL_kECDHr) + if ((alg_k & SSL_kECDHr) && s->version < TLS1_2_VERSION) { /* signature alg must be RSA */ diff --git a/ssl/ssl_locl.h b/ssl/ssl_locl.h index 3225d6517a..78958d4506 100644 --- a/ssl/ssl_locl.h +++ b/ssl/ssl_locl.h @@ -1050,7 +1050,7 @@ int ssl3_alert_code(int code); int ssl_ok(SSL *s); #ifndef OPENSSL_NO_ECDH -int ssl_check_srvr_ecc_cert_and_alg(X509 *x, const SSL_CIPHER *cs); +int ssl_check_srvr_ecc_cert_and_alg(X509 *x, SSL *s); #endif SSL_COMP *ssl3_comp_find(STACK_OF(SSL_COMP) *sk, int n); @@ -1077,6 +1077,12 @@ int ssl_check_serverhello_tlsext(SSL *s); #endif int tls1_process_ticket(SSL *s, unsigned char *session_id, int len, const unsigned char *limit, SSL_SESSION **ret); + +int tls12_get_sigandhash(unsigned char *p, const EVP_PKEY *pk, + const EVP_MD *md); +int tls12_get_sigid(const EVP_PKEY *pk); +const EVP_MD *tls12_get_hash(unsigned char hash_alg); + #endif EVP_MD_CTX* ssl_replace_hash(EVP_MD_CTX **hash,const EVP_MD *md) ; void ssl_clear_hash_ctx(EVP_MD_CTX **hash); @@ -1090,4 +1096,3 @@ int ssl_parse_clienthello_renegotiate_ext(SSL *s, unsigned char *d, int len, int *al); long ssl_get_algorithm2(SSL *s); #endif -int tls12_get_sigandhash(unsigned char *p, EVP_PKEY *pk, const EVP_MD *md); diff --git a/ssl/t1_enc.c b/ssl/t1_enc.c index 95a5b35c42..c60bccd2c0 100644 --- a/ssl/t1_enc.c +++ b/ssl/t1_enc.c @@ -1008,6 +1008,7 @@ int tls1_generate_master_secret(SSL *s, unsigned char *out, unsigned char *p, const void *co = NULL, *so = NULL; int col = 0, sol = 0; + #ifdef KSSL_DEBUG printf ("tls1_generate_master_secret(%p,%p, %p, %d)\n", s,out, p,len); #endif /* KSSL_DEBUG */ @@ -1032,6 +1033,16 @@ int tls1_generate_master_secret(SSL *s, unsigned char *out, unsigned char *p, so, sol, p,len, s->session->master_key,buff,sizeof buff); +#ifdef SSL_DEBUG + fprintf(stderr, "Premaster Secret:\n"); + BIO_dump_fp(stderr, (char *)p, len); + fprintf(stderr, "Client Random:\n"); + BIO_dump_fp(stderr, (char *)s->s3->client_random, SSL3_RANDOM_SIZE); + fprintf(stderr, "Server Random:\n"); + BIO_dump_fp(stderr, (char *)s->s3->server_random, SSL3_RANDOM_SIZE); + fprintf(stderr, "Master Secret:\n"); + BIO_dump_fp(stderr, (char *)s->session->master_key, SSL3_MASTER_SECRET_SIZE); +#endif #ifdef KSSL_DEBUG printf ("tls1_generate_master_secret() complete\n"); diff --git a/ssl/t1_lib.c b/ssl/t1_lib.c index 67a3f86adc..ca4b2db493 100644 --- a/ssl/t1_lib.c +++ b/ssl/t1_lib.c @@ -451,6 +451,62 @@ unsigned char *ssl_add_clienthello_tlsext(SSL *s, unsigned char *p, unsigned cha } skip_ext: + if (s->version >= TLS1_2_VERSION) + { + /* List of supported signature algorithms and hashes. + * Should make this customisable at some point, for + * now include everything we support. + */ + static unsigned char sigalgs[] = { +#ifndef OPENSSL_NO_RSA +# ifndef OPENSSL_NO_SHA512 + TLSEXT_hash_sha512, TLSEXT_signature_rsa, + TLSEXT_hash_sha384, TLSEXT_signature_rsa, +# endif +# ifndef OPENSSL_NO_SHA256 + TLSEXT_hash_sha256, TLSEXT_signature_rsa, + TLSEXT_hash_sha224, TLSEXT_signature_rsa, +# endif +# ifndef OPENSSL_NO_SHA + TLSEXT_hash_sha1, TLSEXT_signature_rsa, +# endif +#endif +#ifndef OPENSSL_NO_ECDSA +# ifndef OPENSSL_NO_SHA512 + TLSEXT_hash_sha512, TLSEXT_signature_ecdsa, + TLSEXT_hash_sha384, TLSEXT_signature_ecdsa, +# endif +# ifndef OPENSSL_NO_SHA256 + TLSEXT_hash_sha256, TLSEXT_signature_ecdsa, + TLSEXT_hash_sha224, TLSEXT_signature_ecdsa, +# endif +# ifndef OPENSSL_NO_SHA + TLSEXT_hash_sha1, TLSEXT_signature_ecdsa, +# endif +#endif +#ifndef OPENSSL_NO_DSA +# ifndef OPENSSL_NO_SHA512 + TLSEXT_hash_sha512, TLSEXT_signature_dsa, + TLSEXT_hash_sha384, TLSEXT_signature_dsa, +# endif +# ifndef OPENSSL_NO_SHA256 + TLSEXT_hash_sha256, TLSEXT_signature_dsa, + TLSEXT_hash_sha224, TLSEXT_signature_dsa, +# endif +# ifndef OPENSSL_NO_SHA + TLSEXT_hash_sha1, TLSEXT_signature_dsa +# endif +#endif + }; + if ((size_t)(limit - ret) < sizeof(sigalgs) + 6) + return NULL; + s2n(TLSEXT_TYPE_signature_algorithms,ret); + s2n(sizeof(sigalgs) + 2, ret); + s2n(sizeof(sigalgs), ret); + memcpy(ret, sigalgs, sizeof(sigalgs)); + ret += sizeof(sigalgs); + } + #ifdef TLSEXT_TYPE_opaque_prf_input if (s->s3->client_opaque_prf_input != NULL && s->version != DTLS1_VERSION) @@ -1976,15 +2032,15 @@ static int tls12_find_nid(int id, tls12_lookup *table, size_t tlen) return -1; } #endif -int tls12_get_sigandhash(unsigned char *p, EVP_PKEY *pk, const EVP_MD *md) + +int tls12_get_sigandhash(unsigned char *p, const EVP_PKEY *pk, const EVP_MD *md) { int sig_id, md_id; md_id = tls12_find_id(EVP_MD_type(md), tls12_md, sizeof(tls12_md)/sizeof(tls12_lookup)); if (md_id == -1) return 0; - sig_id = tls12_find_id(pk->type, tls12_sig, - sizeof(tls12_sig)/sizeof(tls12_lookup)); + sig_id = tls12_get_sigid(pk); if (sig_id == -1) return 0; p[0] = (unsigned char)md_id; @@ -1992,9 +2048,47 @@ int tls12_get_sigandhash(unsigned char *p, EVP_PKEY *pk, const EVP_MD *md) return 1; } +int tls12_get_sigid(const EVP_PKEY *pk) + { + return tls12_find_id(pk->type, tls12_sig, + sizeof(tls12_sig)/sizeof(tls12_lookup)); + } + +const EVP_MD *tls12_get_hash(unsigned char hash_alg) + { + switch(hash_alg) + { +#ifndef OPENSSL_NO_MD5 + case TLSEXT_hash_md5: + return EVP_md5(); +#endif +#ifndef OPENSSL_NO_SHA + case TLSEXT_hash_sha1: + return EVP_sha1(); +#endif +#ifndef OPENSSL_NO_SHA256 + case TLSEXT_hash_sha224: + return EVP_sha224(); + + case TLSEXT_hash_sha256: + return EVP_sha256(); +#endif +#ifndef OPENSSL_NO_SHA512 + case TLSEXT_hash_sha384: + return EVP_sha384(); + + case TLSEXT_hash_sha512: + return EVP_sha512(); +#endif + default: + return NULL; + + } + } + /* Set preferred digest for each key type */ -int tls1_process_sigalgs(SSL *s, const unsigned char *data, int dsize) +static int tls1_process_sigalgs(SSL *s, const unsigned char *data, int dsize) { int i, idx; const EVP_MD *md; @@ -2033,48 +2127,17 @@ int tls1_process_sigalgs(SSL *s, const unsigned char *data, int dsize) continue; } - if (c->pkeys[idx].digest) - continue; - - switch(hash_alg) + if (c->pkeys[idx].digest == NULL) { -#ifndef OPENSSL_NO_MD5 - case TLSEXT_hash_md5: - md = EVP_md5(); - break; -#endif -#ifndef OPENSSL_NO_SHA - case TLSEXT_hash_sha1: - md = EVP_sha1(); - break; -#endif -#ifndef OPENSSL_NO_SHA256 - case TLSEXT_hash_sha224: - md = EVP_sha224(); - break; - - case TLSEXT_hash_sha256: - md = EVP_sha256(); - break; -#endif -#ifndef OPENSSL_NO_SHA512 - case TLSEXT_hash_sha384: - md = EVP_sha384(); - break; - - case TLSEXT_hash_sha512: - md = EVP_sha512(); - break; -#endif - default: - continue; - + md = tls12_get_hash(hash_alg); + if (md) + { + c->pkeys[idx].digest = md; + if (idx == SSL_PKEY_RSA_SIGN) + c->pkeys[SSL_PKEY_RSA_ENC].digest = md; + } } - c->pkeys[idx].digest = md; - if (idx == SSL_PKEY_RSA_SIGN) - c->pkeys[SSL_PKEY_RSA_ENC].digest = md; - } /* Set any remaining keys to default values. NOTE: if alg is not -- 2.34.1