From: Dr. Stephen Henson Date: Wed, 26 Dec 2012 15:27:24 +0000 (+0000) Subject: Abort handshake if signature algorithm used not supported by peer. X-Git-Tag: OpenSSL_1_0_2-beta1~507 X-Git-Url: https://git.librecmc.org/?a=commitdiff_plain;h=25d4c9254c1ccb2f9974abd9a9fd64ddb14f7832;p=oweals%2Fopenssl.git Abort handshake if signature algorithm used not supported by peer. (backport from HEAD) --- diff --git a/CHANGES b/CHANGES index df99053807..891adc3580 100644 --- a/CHANGES +++ b/CHANGES @@ -8,6 +8,12 @@ OID NID. [Steve Henson] + *) 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 a5f3d02b4c..bf695955d1 100644 --- a/ssl/s3_clnt.c +++ b/ssl/s3_clnt.c @@ -1751,25 +1751,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]) - { - 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) + else if (rv == 0) { - 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 @@ -3162,13 +3149,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 dc20fab790..8a15af6dd1 100644 --- a/ssl/s3_srvr.c +++ b/ssl/s3_srvr.c @@ -3054,26 +3054,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 d399fbc971..3e9b7ef8ad 100644 --- a/ssl/ssl.h +++ b/ssl/ssl.h @@ -2433,6 +2433,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 d3429403df..96511be130 100644 --- a/ssl/ssl_err.c +++ b/ssl/ssl_err.c @@ -289,6 +289,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 2e02145082..e0f338dfec 100644 --- a/ssl/ssl_locl.h +++ b/ssl/ssl_locl.h @@ -1255,6 +1255,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 101cfa12a6..05df5fe491 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