From b28fbdfa7dd72fa8ca4fde7008634ee87b067998 Mon Sep 17 00:00:00 2001 From: "Dr. Stephen Henson" Date: Wed, 26 Dec 2012 14:55:46 +0000 Subject: [PATCH] New function ssl_set_client_disabled to set masks for any ciphersuites that are disabled for this session (as opposed to always disabled by configuration). (backport from HEAD) --- CHANGES | 5 +++ ssl/s3_clnt.c | 10 +++-- ssl/s3_srvr.c | 6 ++- ssl/ssl_lib.c | 24 ++++------- ssl/ssl_locl.h | 12 ++++-- ssl/t1_lib.c | 108 +++++++++++++++++++++++++++++++++++++++++-------- 6 files changed, 124 insertions(+), 41 deletions(-) diff --git a/CHANGES b/CHANGES index a597f56ef7..9137cc8263 100644 --- a/CHANGES +++ b/CHANGES @@ -8,6 +8,11 @@ OID NID. [Steve Henson] + *) New function ssl_set_client_disabled to set a ciphersuite disabled + mask based on the current session, check mask when sending client + hello and checking the requested ciphersuite. + [Steve Henson] + *) New ctrls to retrieve and set certificate types in a certificate request message. Print out received values in s_client. If certificate types is not set with custom values set sensible values based on diff --git a/ssl/s3_clnt.c b/ssl/s3_clnt.c index 07f3102265..4c1967ea01 100644 --- a/ssl/s3_clnt.c +++ b/ssl/s3_clnt.c @@ -837,6 +837,7 @@ int ssl3_get_server_hello(SSL *s) { STACK_OF(SSL_CIPHER) *sk; const SSL_CIPHER *c; + CERT *ct = s->cert; unsigned char *p,*d; int i,al=SSL_AD_INTERNAL_ERROR,ok; unsigned int j; @@ -959,9 +960,12 @@ int ssl3_get_server_hello(SSL *s) SSLerr(SSL_F_SSL3_GET_SERVER_HELLO,SSL_R_UNKNOWN_CIPHER_RETURNED); goto f_err; } - /* TLS v1.2 only ciphersuites require v1.2 or later */ - if ((c->algorithm_ssl & SSL_TLSV1_2) && - (TLS1_get_version(s) < TLS1_2_VERSION)) + /* If it is a disabled cipher we didn't send it in client hello, + * so return an error. + */ + if (c->algorithm_ssl & ct->mask_ssl || + c->algorithm_mkey & ct->mask_k || + c->algorithm_auth & ct->mask_a) { al=SSL_AD_ILLEGAL_PARAMETER; SSLerr(SSL_F_SSL3_GET_SERVER_HELLO,SSL_R_WRONG_CIPHER_RETURNED); diff --git a/ssl/s3_srvr.c b/ssl/s3_srvr.c index f6ab29cd79..5218edf083 100644 --- a/ssl/s3_srvr.c +++ b/ssl/s3_srvr.c @@ -2077,9 +2077,11 @@ int ssl3_send_certificate_request(SSL *s) if (TLS1_get_version(s) >= TLS1_2_VERSION) { - nl = tls12_get_sig_algs(s, p + 2); + const unsigned char *psigs; + nl = tls12_get_psigalgs(s, &psigs); s2n(nl, p); - p += nl + 2; + memcpy(p, psigs, nl); + p += nl; n += nl + 2; } diff --git a/ssl/ssl_lib.c b/ssl/ssl_lib.c index 51c020dc03..fac4132be2 100644 --- a/ssl/ssl_lib.c +++ b/ssl/ssl_lib.c @@ -1409,10 +1409,10 @@ int ssl_cipher_list_to_bytes(SSL *s,STACK_OF(SSL_CIPHER) *sk,unsigned char *p, { int i,j=0; SSL_CIPHER *c; + CERT *ct = s->cert; unsigned char *q; -#ifndef OPENSSL_NO_KRB5 - int nokrb5 = !kssl_tgt_is_available(s->kssl_ctx); -#endif /* OPENSSL_NO_KRB5 */ + /* Set disabled masks for this session */ + ssl_set_client_disabled(s); if (sk == NULL) return(0); q=p; @@ -1420,21 +1420,11 @@ int ssl_cipher_list_to_bytes(SSL *s,STACK_OF(SSL_CIPHER) *sk,unsigned char *p, for (i=0; ialgorithm_ssl & SSL_TLSV1_2) && - (TLS1_get_client_version(s) < TLS1_2_VERSION)) - continue; -#ifndef OPENSSL_NO_KRB5 - if (((c->algorithm_mkey & SSL_kKRB5) || (c->algorithm_auth & SSL_aKRB5)) && - nokrb5) - continue; -#endif /* OPENSSL_NO_KRB5 */ -#ifndef OPENSSL_NO_PSK - /* with PSK there must be client callback set */ - if (((c->algorithm_mkey & SSL_kPSK) || (c->algorithm_auth & SSL_aPSK)) && - s->psk_client_callback == NULL) + /* Skip disabled ciphers */ + if (c->algorithm_ssl & ct->mask_ssl || + c->algorithm_mkey & ct->mask_k || + c->algorithm_auth & ct->mask_a) continue; -#endif /* OPENSSL_NO_PSK */ j = put_cb ? put_cb(c,p) : ssl_put_cipher_by_char(s,c,p); p+=j; } diff --git a/ssl/ssl_locl.h b/ssl/ssl_locl.h index 4b88efe57c..d26ff9863c 100644 --- a/ssl/ssl_locl.h +++ b/ssl/ssl_locl.h @@ -507,13 +507,18 @@ typedef struct cert_st * Probably it would make more sense to store * an index, not a pointer. */ - /* The following masks are for the key and auth - * algorithms that are supported by the certs below */ + /* For servers the following masks are for the key and auth + * algorithms that are supported by the certs below. + * For clients they are masks of *disabled* algorithms based + * on the current session. + */ int valid; unsigned long mask_k; unsigned long mask_a; unsigned long export_mask_k; unsigned long export_mask_a; + /* Client only */ + unsigned long mask_ssl; #ifndef OPENSSL_NO_RSA RSA *rsa_tmp; RSA *(*rsa_tmp_cb)(SSL *ssl,int is_export,int keysize); @@ -1240,7 +1245,8 @@ 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); -size_t tls12_get_sig_algs(SSL *s, unsigned char *p); +size_t tls12_get_psigalgs(SSL *s, const unsigned char **psigs); +void ssl_set_client_disabled(SSL *s); int ssl_add_clienthello_use_srtp_ext(SSL *s, unsigned char *p, int *len, int maxlen); int ssl_parse_clienthello_use_srtp_ext(SSL *s, unsigned char *d, int len,int *al); diff --git a/ssl/t1_lib.c b/ssl/t1_lib.c index 65bd8c3f44..48e99c5011 100644 --- a/ssl/t1_lib.c +++ b/ssl/t1_lib.c @@ -635,35 +635,110 @@ static unsigned char tls12_sigalgs[] = { #endif }; -size_t tls12_get_sig_algs(SSL *s, unsigned char *p) +size_t tls12_get_psigalgs(SSL *s, const unsigned char **psigs) { - const unsigned char *sigs; - size_t sigslen; /* If server use client authentication sigalgs if not NULL */ if (s->server && s->cert->client_sigalgs) { - sigs = s->cert->client_sigalgs; - sigslen = s->cert->client_sigalgslen; + *psigs = s->cert->client_sigalgs; + return s->cert->client_sigalgslen; } else if (s->cert->conf_sigalgs) { - sigs = s->cert->conf_sigalgs; - sigslen = s->cert->conf_sigalgslen; + *psigs = s->cert->conf_sigalgs; + return s->cert->conf_sigalgslen; } else { - sigs = tls12_sigalgs; - sigslen = sizeof(tls12_sigalgs); + *psigs = tls12_sigalgs; #ifdef OPENSSL_FIPS /* If FIPS mode don't include MD5 which is last */ if (FIPS_mode()) - sigslen -= 2; + return sizeof(tls12_sigalgs) - 2; + else #endif + return sizeof(tls12_sigalgs); } - - if (p) - memcpy(p, sigs, sigslen); - return sigslen; + } +/* Get a mask of disabled algorithms: an algorithm is disabled + * if it isn't supported or doesn't appear in supported signature + * algorithms. Unlike ssl_cipher_get_disabled this applies to a specific + * session and not global settings. + * + */ +void ssl_set_client_disabled(SSL *s) + { + CERT *c = s->cert; + const unsigned char *sigalgs; + size_t i, sigalgslen; + int have_rsa = 0, have_dsa = 0, have_ecdsa = 0; + c->mask_a = 0; + c->mask_k = 0; + /* If less than TLS 1.2 don't allow TLS 1.2 only ciphers */ + if (TLS1_get_version(s) < TLS1_2_VERSION) + c->mask_ssl = SSL_TLSV1_2; + else + c->mask_ssl = 0; + /* Now go through all signature algorithms seeing if we support + * any for RSA, DSA, ECDSA. Do this for all versions not just + * TLS 1.2. + */ + sigalgslen = tls12_get_psigalgs(s, &sigalgs); + for (i = 0; i < sigalgslen; i += 2, sigalgs += 2) + { + switch(sigalgs[1]) + { +#ifndef OPENSSL_NO_RSA + case TLSEXT_signature_rsa: + have_rsa = 1; + break; +#endif +#ifndef OPENSSL_NO_DSA + case TLSEXT_signature_dsa: + have_dsa = 1; + break; +#endif +#ifndef OPENSSL_NO_ECDSA + case TLSEXT_signature_ecdsa: + have_ecdsa = 1; + break; +#endif + } + } + /* Disable auth and static DH if we don't include any appropriate + * signature algorithms. + */ + if (!have_rsa) + { + c->mask_a |= SSL_aRSA; + c->mask_k |= SSL_kDHr|SSL_kECDHr; + } + if (!have_dsa) + { + c->mask_a |= SSL_aDSS; + c->mask_k |= SSL_kDHd; + } + if (!have_ecdsa) + { + c->mask_a |= SSL_aECDSA; + c->mask_k |= SSL_kECDHe; + } +#ifndef OPENSSL_NO_KRB5 + if (!kssl_tgt_is_available(s->kssl_ctx)) + { + c->mask_a |= SSL_aKRB5; + c->mask_k |= SSL_kKRB5; + } +#endif +#ifndef OPENSSL_NO_PSK + /* with PSK there must be client callback set */ + if (!s->psk_client_callback) + { + c->mask_a |= SSL_aPSK; + c->mask_k |= SSL_kPSK; + } +#endif /* OPENSSL_NO_PSK */ + c->valid = 1; } /* byte_compare is a compare function for qsort(3) that compares bytes. */ @@ -899,13 +974,14 @@ unsigned char *ssl_add_clienthello_tlsext(SSL *s, unsigned char *p, unsigned cha if (TLS1_get_client_version(s) >= TLS1_2_VERSION) { size_t salglen; - salglen = tls12_get_sig_algs(s, NULL); + const unsigned char *salg; + salglen = tls12_get_psigalgs(s, &salg); if ((size_t)(limit - ret) < salglen + 6) return NULL; s2n(TLSEXT_TYPE_signature_algorithms,ret); s2n(salglen + 2, ret); s2n(salglen, ret); - tls12_get_sig_algs(s, ret); + memcpy(ret, salg, salglen); ret += salglen; } -- 2.25.1