From ec4a50b3c3f2f50caccfd52e939857a5d6f02fd1 Mon Sep 17 00:00:00 2001 From: "Dr. Stephen Henson" Date: Tue, 24 Jul 2012 18:11:27 +0000 Subject: [PATCH] Abort handshake if signature algorithm used not supported by peer. --- CHANGES | 6 ++++++ ssl/s3_clnt.c | 27 +++++++++------------------ ssl/s3_srvr.c | 21 +++++---------------- ssl/ssl.h | 1 + ssl/ssl_err.c | 1 + ssl/ssl_locl.h | 2 ++ ssl/t1_lib.c | 39 +++++++++++++++++++++++++++++++++++++++ 7 files changed, 63 insertions(+), 34 deletions(-) diff --git a/CHANGES b/CHANGES index fafaf6ddb3..46b23de1da 100644 --- a/CHANGES +++ b/CHANGES @@ -4,6 +4,12 @@ Changes between 1.0.1 and 1.1.0 [xx XXX xxxx] + *) If an attempt is made to use a signature algorithm not in the peer + preference list abort the handshake. If client has no suitable + signature algorithms in response to a certificate request do not + use the certificate. + [Steve Henson] + *) If server EC tmp key is not in client preference list abort handshake. [Steve Henson] diff --git a/ssl/s3_clnt.c b/ssl/s3_clnt.c index 11ffabb460..e9c1518810 100644 --- a/ssl/s3_clnt.c +++ b/ssl/s3_clnt.c @@ -1750,25 +1750,12 @@ int ssl3_get_key_exchange(SSL *s) { if (TLS1_get_version(s) >= 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); + int rv = tls12_check_peer_sigalg(&md, s, p, pkey); + if (rv == -1) goto err; - } - /* Check key type is consistent with signature */ - if (sigalg != (int)p[1]) + else if (rv == 0) { - 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; + al = SSL_AD_DECODE_ERROR; goto f_err; } #ifdef SSL_DEBUG @@ -3161,13 +3148,17 @@ err: } /* Check a certificate can be used for client authentication. Currently - * just check cert exists and if static DH client certificates can be used. + * check cert exists, if we have a suitable digest for TLS 1.2 and if + * static DH client certificates can be used. */ static int ssl3_check_client_certificate(SSL *s) { unsigned long alg_k; if (!s->cert || !s->cert->key->x509 || !s->cert->key->privatekey) return 0; + /* If no suitable signature algorithm can't use certificate */ + if (TLS1_get_version(s) >= TLS1_2_VERSION && !s->cert->key->digest) + return 0; alg_k=s->s3->tmp.new_cipher->algorithm_mkey; /* See if we can use client certificate for fixed DH */ if (alg_k & (SSL_kDHr|SSL_kDHd)) diff --git a/ssl/s3_srvr.c b/ssl/s3_srvr.c index 28f3bdd6e9..2f23f2121b 100644 --- a/ssl/s3_srvr.c +++ b/ssl/s3_srvr.c @@ -3051,26 +3051,15 @@ int ssl3_get_cert_verify(SSL *s) { if (TLS1_get_version(s) >= TLS1_2_VERSION) { - int sigalg = tls12_get_sigid(pkey); - /* Should never happen */ - if (sigalg == -1) + int rv = tls12_check_peer_sigalg(&md, s, p, pkey); + if (rv == -1) { - SSLerr(SSL_F_SSL3_GET_CERT_VERIFY,ERR_R_INTERNAL_ERROR); - al=SSL_AD_INTERNAL_ERROR; + al = SSL_AD_INTERNAL_ERROR; goto f_err; } - /* Check key type is consistent with signature */ - if (sigalg != (int)p[1]) + else if (rv == 0) { - 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_CERT_VERIFY,SSL_R_UNKNOWN_DIGEST); - al=SSL_AD_DECODE_ERROR; + al = SSL_AD_DECODE_ERROR; goto f_err; } #ifdef SSL_DEBUG diff --git a/ssl/ssl.h b/ssl/ssl.h index 09085a23b5..b8b1ba1207 100644 --- a/ssl/ssl.h +++ b/ssl/ssl.h @@ -2452,6 +2452,7 @@ void ERR_load_SSL_strings(void); #define SSL_F_SSL_USE_RSAPRIVATEKEY_FILE 206 #define SSL_F_SSL_VERIFY_CERT_CHAIN 207 #define SSL_F_SSL_WRITE 208 +#define SSL_F_TLS12_CHECK_PEER_SIGALG 333 #define SSL_F_TLS1_CERT_VERIFY_MAC 286 #define SSL_F_TLS1_CHANGE_CIPHER_STATE 209 #define SSL_F_TLS1_CHECK_SERVERHELLO_TLSEXT 274 diff --git a/ssl/ssl_err.c b/ssl/ssl_err.c index 665d74fe04..14e8488411 100644 --- a/ssl/ssl_err.c +++ b/ssl/ssl_err.c @@ -288,6 +288,7 @@ static ERR_STRING_DATA SSL_str_functs[]= {ERR_FUNC(SSL_F_SSL_USE_RSAPRIVATEKEY_FILE), "SSL_use_RSAPrivateKey_file"}, {ERR_FUNC(SSL_F_SSL_VERIFY_CERT_CHAIN), "ssl_verify_cert_chain"}, {ERR_FUNC(SSL_F_SSL_WRITE), "SSL_write"}, +{ERR_FUNC(SSL_F_TLS12_CHECK_PEER_SIGALG), "tls12_check_peer_sigalg"}, {ERR_FUNC(SSL_F_TLS1_CERT_VERIFY_MAC), "tls1_cert_verify_mac"}, {ERR_FUNC(SSL_F_TLS1_CHANGE_CIPHER_STATE), "tls1_change_cipher_state"}, {ERR_FUNC(SSL_F_TLS1_CHECK_SERVERHELLO_TLSEXT), "TLS1_CHECK_SERVERHELLO_TLSEXT"}, diff --git a/ssl/ssl_locl.h b/ssl/ssl_locl.h index 8b0ea0ee71..d8d1b7918c 100644 --- a/ssl/ssl_locl.h +++ b/ssl/ssl_locl.h @@ -1252,6 +1252,8 @@ int ssl_parse_clienthello_renegotiate_ext(SSL *s, unsigned char *d, int len, long ssl_get_algorithm2(SSL *s); int tls1_process_sigalgs(SSL *s, const unsigned char *data, int dsize); size_t tls12_get_psigalgs(SSL *s, const unsigned char **psigs); +int tls12_check_peer_sigalg(const EVP_MD **pmd, SSL *s, + const unsigned char *sig, EVP_PKEY *pkey); void ssl_set_client_disabled(SSL *s); int ssl_add_clienthello_use_srtp_ext(SSL *s, unsigned char *p, int *len, int maxlen); diff --git a/ssl/t1_lib.c b/ssl/t1_lib.c index 06db730adc..8b3c213ec6 100644 --- a/ssl/t1_lib.c +++ b/ssl/t1_lib.c @@ -680,6 +680,45 @@ size_t tls12_get_psigalgs(SSL *s, const unsigned char **psigs) return sizeof(tls12_sigalgs); } } +/* Check signature algorithm is consistent with sent supported signature + * algorithms and if so return relevant digest. + */ +int tls12_check_peer_sigalg(const EVP_MD **pmd, SSL *s, + const unsigned char *sig, EVP_PKEY *pkey) + { + const unsigned char *sent_sigs; + size_t sent_sigslen, i; + int sigalg = tls12_get_sigid(pkey); + /* Should never happen */ + if (sigalg == -1) + return -1; + /* Check key type is consistent with signature */ + if (sigalg != (int)sig[1]) + { + SSLerr(SSL_F_TLS12_CHECK_PEER_SIGALG,SSL_R_WRONG_SIGNATURE_TYPE); + return 0; + } + /* Check signature matches a type we sent */ + sent_sigslen = tls12_get_psigalgs(s, &sent_sigs); + for (i = 0; i < sent_sigslen; i+=2, sent_sigs+=2) + { + if (sig[0] == sent_sigs[0] && sig[1] == sent_sigs[1]) + break; + } + /* Allow fallback to SHA1 if not strict mode */ + if (i == sent_sigslen && (sig[0] != TLSEXT_hash_sha1 || s->cert->cert_flags & SSL_CERT_FLAG_TLS_STRICT)) + { + SSLerr(SSL_F_TLS12_CHECK_PEER_SIGALG,SSL_R_WRONG_SIGNATURE_TYPE); + return 0; + } + *pmd = tls12_get_hash(sig[0]); + if (*pmd == NULL) + { + SSLerr(SSL_F_TLS12_CHECK_PEER_SIGALG,SSL_R_UNKNOWN_DIGEST); + return 0; + } + return 1; + } /* 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