From 263ff2c9d4c88f19133d21d9956d71edd7401d54 Mon Sep 17 00:00:00 2001 From: Matt Caswell Date: Fri, 1 May 2020 17:41:25 +0100 Subject: [PATCH] Check that Signature Algorithms are available before using them We should confirm that Signature Algorithms are actually available through the loaded providers before we offer or select them. Reviewed-by: Shane Lontis (Merged from https://github.com/openssl/openssl/pull/11834) --- ssl/ssl_lib.c | 6 ++ ssl/ssl_local.h | 6 ++ ssl/t1_lib.c | 149 +++++++++++++++++++++++++++++++++--------------- 3 files changed, 114 insertions(+), 47 deletions(-) diff --git a/ssl/ssl_lib.c b/ssl/ssl_lib.c index cb02129d9d..c2c2388716 100644 --- a/ssl/ssl_lib.c +++ b/ssl/ssl_lib.c @@ -3166,6 +3166,10 @@ SSL_CTX *SSL_CTX_new_with_libctx(OPENSSL_CTX *libctx, const char *propq, /* initialize cipher/digest methods table */ if (!ssl_load_ciphers(ret)) goto err2; + /* initialise sig algs */ + if (!ssl_setup_sig_algs(ret)) + goto err2; + if (!SSL_CTX_set_ciphersuites(ret, OSSL_default_ciphersuites())) goto err; @@ -3386,6 +3390,8 @@ void SSL_CTX_free(SSL_CTX *a) for (i = 0; i < SSL_MD_NUM_IDX; i++) ssl_evp_md_free(a->ssl_digest_methods[i]); + OPENSSL_free(a->sigalg_lookup_cache); + CRYPTO_THREAD_lock_free(a->lock); OPENSSL_free(a->propq); diff --git a/ssl/ssl_local.h b/ssl/ssl_local.h index 5e2379c093..d2e8e23e23 100644 --- a/ssl/ssl_local.h +++ b/ssl/ssl_local.h @@ -1157,6 +1157,9 @@ struct ssl_ctx_st { const EVP_CIPHER *ssl_cipher_methods[SSL_ENC_NUM_IDX]; const EVP_MD *ssl_digest_methods[SSL_MD_NUM_IDX]; size_t ssl_mac_secret_size[SSL_MD_NUM_IDX]; + + /* Cache of all sigalgs we know and whether they are available or not */ + struct sigalg_lookup_st *sigalg_lookup_cache; }; typedef struct cert_pkey_st CERT_PKEY; @@ -1776,6 +1779,8 @@ typedef struct sigalg_lookup_st { int sigandhash; /* Required public key curve (ECDSA only) */ int curve; + /* Whether this signature algorithm is actually available for use */ + int enabled; } SIGALG_LOOKUP; typedef struct tls_group_info_st { @@ -2432,6 +2437,7 @@ __owur STACK_OF(SSL_CIPHER) *ssl_get_ciphers_by_id(SSL *s); __owur int ssl_x509err2alert(int type); void ssl_sort_cipher_list(void); int ssl_load_ciphers(SSL_CTX *ctx); +__owur int ssl_setup_sig_algs(SSL_CTX *ctx); __owur int ssl_fill_hello_random(SSL *s, int server, unsigned char *field, size_t len, DOWNGRADE dgrd); __owur int ssl_generate_master_secret(SSL *s, unsigned char *pms, size_t pmslen, diff --git a/ssl/t1_lib.c b/ssl/t1_lib.c index 5afe53acfc..a59d992e47 100644 --- a/ssl/t1_lib.c +++ b/ssl/t1_lib.c @@ -793,97 +793,97 @@ static const SIGALG_LOOKUP sigalg_lookup_tbl[] = { #ifndef OPENSSL_NO_EC {"ecdsa_secp256r1_sha256", TLSEXT_SIGALG_ecdsa_secp256r1_sha256, NID_sha256, SSL_MD_SHA256_IDX, EVP_PKEY_EC, SSL_PKEY_ECC, - NID_ecdsa_with_SHA256, NID_X9_62_prime256v1}, + NID_ecdsa_with_SHA256, NID_X9_62_prime256v1, 1}, {"ecdsa_secp384r1_sha384", TLSEXT_SIGALG_ecdsa_secp384r1_sha384, NID_sha384, SSL_MD_SHA384_IDX, EVP_PKEY_EC, SSL_PKEY_ECC, - NID_ecdsa_with_SHA384, NID_secp384r1}, + NID_ecdsa_with_SHA384, NID_secp384r1, 1}, {"ecdsa_secp521r1_sha512", TLSEXT_SIGALG_ecdsa_secp521r1_sha512, NID_sha512, SSL_MD_SHA512_IDX, EVP_PKEY_EC, SSL_PKEY_ECC, - NID_ecdsa_with_SHA512, NID_secp521r1}, + NID_ecdsa_with_SHA512, NID_secp521r1, 1}, {"ed25519", TLSEXT_SIGALG_ed25519, NID_undef, -1, EVP_PKEY_ED25519, SSL_PKEY_ED25519, - NID_undef, NID_undef}, + NID_undef, NID_undef, 1}, {"ed448", TLSEXT_SIGALG_ed448, NID_undef, -1, EVP_PKEY_ED448, SSL_PKEY_ED448, - NID_undef, NID_undef}, + NID_undef, NID_undef, 1}, {NULL, TLSEXT_SIGALG_ecdsa_sha224, NID_sha224, SSL_MD_SHA224_IDX, EVP_PKEY_EC, SSL_PKEY_ECC, - NID_ecdsa_with_SHA224, NID_undef}, + NID_ecdsa_with_SHA224, NID_undef, 1}, {NULL, TLSEXT_SIGALG_ecdsa_sha1, NID_sha1, SSL_MD_SHA1_IDX, EVP_PKEY_EC, SSL_PKEY_ECC, - NID_ecdsa_with_SHA1, NID_undef}, + NID_ecdsa_with_SHA1, NID_undef, 1}, #endif {"rsa_pss_rsae_sha256", TLSEXT_SIGALG_rsa_pss_rsae_sha256, NID_sha256, SSL_MD_SHA256_IDX, EVP_PKEY_RSA_PSS, SSL_PKEY_RSA, - NID_undef, NID_undef}, + NID_undef, NID_undef, 1}, {"rsa_pss_rsae_sha384", TLSEXT_SIGALG_rsa_pss_rsae_sha384, NID_sha384, SSL_MD_SHA384_IDX, EVP_PKEY_RSA_PSS, SSL_PKEY_RSA, - NID_undef, NID_undef}, + NID_undef, NID_undef, 1}, {"rsa_pss_rsae_sha512", TLSEXT_SIGALG_rsa_pss_rsae_sha512, NID_sha512, SSL_MD_SHA512_IDX, EVP_PKEY_RSA_PSS, SSL_PKEY_RSA, - NID_undef, NID_undef}, + NID_undef, NID_undef, 1}, {"rsa_pss_pss_sha256", TLSEXT_SIGALG_rsa_pss_pss_sha256, NID_sha256, SSL_MD_SHA256_IDX, EVP_PKEY_RSA_PSS, SSL_PKEY_RSA_PSS_SIGN, - NID_undef, NID_undef}, + NID_undef, NID_undef, 1}, {"rsa_pss_pss_sha384", TLSEXT_SIGALG_rsa_pss_pss_sha384, NID_sha384, SSL_MD_SHA384_IDX, EVP_PKEY_RSA_PSS, SSL_PKEY_RSA_PSS_SIGN, - NID_undef, NID_undef}, + NID_undef, NID_undef, 1}, {"rsa_pss_pss_sha512", TLSEXT_SIGALG_rsa_pss_pss_sha512, NID_sha512, SSL_MD_SHA512_IDX, EVP_PKEY_RSA_PSS, SSL_PKEY_RSA_PSS_SIGN, - NID_undef, NID_undef}, + NID_undef, NID_undef, 1}, {"rsa_pkcs1_sha256", TLSEXT_SIGALG_rsa_pkcs1_sha256, NID_sha256, SSL_MD_SHA256_IDX, EVP_PKEY_RSA, SSL_PKEY_RSA, - NID_sha256WithRSAEncryption, NID_undef}, + NID_sha256WithRSAEncryption, NID_undef, 1}, {"rsa_pkcs1_sha384", TLSEXT_SIGALG_rsa_pkcs1_sha384, NID_sha384, SSL_MD_SHA384_IDX, EVP_PKEY_RSA, SSL_PKEY_RSA, - NID_sha384WithRSAEncryption, NID_undef}, + NID_sha384WithRSAEncryption, NID_undef, 1}, {"rsa_pkcs1_sha512", TLSEXT_SIGALG_rsa_pkcs1_sha512, NID_sha512, SSL_MD_SHA512_IDX, EVP_PKEY_RSA, SSL_PKEY_RSA, - NID_sha512WithRSAEncryption, NID_undef}, + NID_sha512WithRSAEncryption, NID_undef, 1}, {"rsa_pkcs1_sha224", TLSEXT_SIGALG_rsa_pkcs1_sha224, NID_sha224, SSL_MD_SHA224_IDX, EVP_PKEY_RSA, SSL_PKEY_RSA, - NID_sha224WithRSAEncryption, NID_undef}, + NID_sha224WithRSAEncryption, NID_undef, 1}, {"rsa_pkcs1_sha1", TLSEXT_SIGALG_rsa_pkcs1_sha1, NID_sha1, SSL_MD_SHA1_IDX, EVP_PKEY_RSA, SSL_PKEY_RSA, - NID_sha1WithRSAEncryption, NID_undef}, + NID_sha1WithRSAEncryption, NID_undef, 1}, #ifndef OPENSSL_NO_DSA {NULL, TLSEXT_SIGALG_dsa_sha256, NID_sha256, SSL_MD_SHA256_IDX, EVP_PKEY_DSA, SSL_PKEY_DSA_SIGN, - NID_dsa_with_SHA256, NID_undef}, + NID_dsa_with_SHA256, NID_undef, 1}, {NULL, TLSEXT_SIGALG_dsa_sha384, NID_sha384, SSL_MD_SHA384_IDX, EVP_PKEY_DSA, SSL_PKEY_DSA_SIGN, - NID_undef, NID_undef}, + NID_undef, NID_undef, 1}, {NULL, TLSEXT_SIGALG_dsa_sha512, NID_sha512, SSL_MD_SHA512_IDX, EVP_PKEY_DSA, SSL_PKEY_DSA_SIGN, - NID_undef, NID_undef}, + NID_undef, NID_undef, 1}, {NULL, TLSEXT_SIGALG_dsa_sha224, NID_sha224, SSL_MD_SHA224_IDX, EVP_PKEY_DSA, SSL_PKEY_DSA_SIGN, - NID_undef, NID_undef}, + NID_undef, NID_undef, 1}, {NULL, TLSEXT_SIGALG_dsa_sha1, NID_sha1, SSL_MD_SHA1_IDX, EVP_PKEY_DSA, SSL_PKEY_DSA_SIGN, - NID_dsaWithSHA1, NID_undef}, + NID_dsaWithSHA1, NID_undef, 1}, #endif #ifndef OPENSSL_NO_GOST {NULL, TLSEXT_SIGALG_gostr34102012_256_intrinsic, NID_id_GostR3411_2012_256, SSL_MD_GOST12_256_IDX, NID_id_GostR3410_2012_256, SSL_PKEY_GOST12_256, - NID_undef, NID_undef}, + NID_undef, NID_undef, 1}, {NULL, TLSEXT_SIGALG_gostr34102012_512_intrinsic, NID_id_GostR3411_2012_512, SSL_MD_GOST12_512_IDX, NID_id_GostR3410_2012_512, SSL_PKEY_GOST12_512, - NID_undef, NID_undef}, + NID_undef, NID_undef, 1}, {NULL, TLSEXT_SIGALG_gostr34102012_256_gostr34112012_256, NID_id_GostR3411_2012_256, SSL_MD_GOST12_256_IDX, NID_id_GostR3410_2012_256, SSL_PKEY_GOST12_256, - NID_undef, NID_undef}, + NID_undef, NID_undef, 1}, {NULL, TLSEXT_SIGALG_gostr34102012_512_gostr34112012_512, NID_id_GostR3411_2012_512, SSL_MD_GOST12_512_IDX, NID_id_GostR3410_2012_512, SSL_PKEY_GOST12_512, - NID_undef, NID_undef}, + NID_undef, NID_undef, 1}, {NULL, TLSEXT_SIGALG_gostr34102001_gostr3411, NID_id_GostR3411_94, SSL_MD_GOST94_IDX, NID_id_GostR3410_2001, SSL_PKEY_GOST01, - NID_undef, NID_undef} + NID_undef, NID_undef, 1} #endif }; /* Legacy sigalgs for TLS < 1.2 RSA TLS signatures */ @@ -891,7 +891,7 @@ static const SIGALG_LOOKUP legacy_rsa_sigalg = { "rsa_pkcs1_md5_sha1", 0, NID_md5_sha1, SSL_MD_MD5_SHA1_IDX, EVP_PKEY_RSA, SSL_PKEY_RSA, - NID_undef, NID_undef + NID_undef, NID_undef, 1 }; /* @@ -910,16 +910,72 @@ static const uint16_t tls_default_sigalg[] = { 0, /* SSL_PKEY_ED448 */ }; +int ssl_setup_sig_algs(SSL_CTX *ctx) +{ + size_t i; + const SIGALG_LOOKUP *lu; + SIGALG_LOOKUP *cache + = OPENSSL_malloc(sizeof(*lu) * OSSL_NELEM(sigalg_lookup_tbl)); + EVP_PKEY *tmpkey = EVP_PKEY_new(); + int ret = 0; + + if (cache == NULL || tmpkey == NULL) + goto err; + + ERR_set_mark(); + for (i = 0, lu = sigalg_lookup_tbl; + i < OSSL_NELEM(sigalg_lookup_tbl); lu++, i++) { + EVP_PKEY_CTX *pctx; + + cache[i] = *lu; + + /* + * Check hash is available. + * TODO(3.0): This test is not perfect. A provider could have support + * for a signature scheme, but not a particular hash. However the hash + * could be available from some other loaded provider. In that case it + * could be that the signature is available, and the hash is available + * independently - but not as a combination. We ignore this for now. + */ + if (lu->hash != NID_undef + && ctx->ssl_digest_methods[lu->hash_idx] == NULL) { + cache[i].enabled = 0; + continue; + } + + if (!EVP_PKEY_set_type(tmpkey, lu->sig)) { + cache[i].enabled = 0; + continue; + } + pctx = EVP_PKEY_CTX_new_from_pkey(ctx->libctx, tmpkey, ctx->propq); + /* If unable to create pctx we assume the sig algorithm is unavailable */ + if (pctx == NULL) + cache[i].enabled = 0; + EVP_PKEY_CTX_free(pctx); + } + ERR_pop_to_mark(); + ctx->sigalg_lookup_cache = cache; + cache = NULL; + + ret = 1; + err: + OPENSSL_free(cache); + EVP_PKEY_free(tmpkey); + return ret; +} + /* Lookup TLS signature algorithm */ -static const SIGALG_LOOKUP *tls1_lookup_sigalg(uint16_t sigalg) +static const SIGALG_LOOKUP *tls1_lookup_sigalg(const SSL *s, uint16_t sigalg) { size_t i; - const SIGALG_LOOKUP *s; + const SIGALG_LOOKUP *lu; - for (i = 0, s = sigalg_lookup_tbl; i < OSSL_NELEM(sigalg_lookup_tbl); - i++, s++) { - if (s->sigalg == sigalg) - return s; + for (i = 0, lu = s->ctx->sigalg_lookup_cache; + /* cache should have the same number of elements as sigalg_lookup_tbl */ + i < OSSL_NELEM(sigalg_lookup_tbl); + lu++, i++) { + if (lu->sigalg == sigalg) + return lu; } return NULL; } @@ -1023,7 +1079,7 @@ static const SIGALG_LOOKUP *tls1_get_legacy_sigalg(const SSL *s, int idx) if (idx < 0 || idx >= (int)OSSL_NELEM(tls_default_sigalg)) return NULL; if (SSL_USE_SIGALGS(s) || idx != SSL_PKEY_RSA) { - const SIGALG_LOOKUP *lu = tls1_lookup_sigalg(tls_default_sigalg[idx]); + const SIGALG_LOOKUP *lu = tls1_lookup_sigalg(s, tls_default_sigalg[idx]); if (!tls1_lookup_md(s->ctx, lu, NULL)) return NULL; @@ -1107,7 +1163,7 @@ int tls_check_sigalg_curve(const SSL *s, int curve) } for (i = 0; i < siglen; i++) { - const SIGALG_LOOKUP *lu = tls1_lookup_sigalg(sigs[i]); + const SIGALG_LOOKUP *lu = tls1_lookup_sigalg(s, sigs[i]); if (lu == NULL) continue; @@ -1187,7 +1243,7 @@ int tls12_check_peer_sigalg(SSL *s, uint16_t sig, EVP_PKEY *pkey) if (pkeyid == EVP_PKEY_RSA) pkeyid = EVP_PKEY_RSA_PSS; } - lu = tls1_lookup_sigalg(sig); + lu = tls1_lookup_sigalg(s, sig); /* * Check sigalgs is known. Disallow SHA1/SHA224 with TLS 1.3. Check key type * is consistent with signature: RSA keys can be used for RSA-PSS @@ -1761,8 +1817,7 @@ static int tls12_sigalg_allowed(const SSL *s, int op, const SIGALG_LOOKUP *lu) unsigned char sigalgstr[2]; int secbits; - /* See if sigalgs is recognised and if hash is enabled */ - if (!tls1_lookup_md(s->ctx, lu, NULL)) + if (lu == NULL || !lu->enabled) return 0; /* DSA is not allowed in TLS 1.3 */ if (SSL_IS_TLS13(s) && lu->sig == EVP_PKEY_DSA) @@ -1841,7 +1896,7 @@ void ssl_set_sig_mask(uint32_t *pmask_a, SSL *s, int op) */ sigalgslen = tls12_get_psigalgs(s, 1, &sigalgs); for (i = 0; i < sigalgslen; i++, sigalgs++) { - const SIGALG_LOOKUP *lu = tls1_lookup_sigalg(*sigalgs); + const SIGALG_LOOKUP *lu = tls1_lookup_sigalg(s, *sigalgs); const SSL_CERT_LOOKUP *clu; if (lu == NULL) @@ -1866,7 +1921,7 @@ int tls12_copy_sigalgs(SSL *s, WPACKET *pkt, int rv = 0; for (i = 0; i < psiglen; i++, psig++) { - const SIGALG_LOOKUP *lu = tls1_lookup_sigalg(*psig); + const SIGALG_LOOKUP *lu = tls1_lookup_sigalg(s, *psig); if (!tls12_sigalg_allowed(s, SSL_SECOP_SIGALG_SUPPORTED, lu)) continue; @@ -1895,7 +1950,7 @@ static size_t tls12_shared_sigalgs(SSL *s, const SIGALG_LOOKUP **shsig, const uint16_t *ptmp, *atmp; size_t i, j, nmatch = 0; for (i = 0, ptmp = pref; i < preflen; i++, ptmp++) { - const SIGALG_LOOKUP *lu = tls1_lookup_sigalg(*ptmp); + const SIGALG_LOOKUP *lu = tls1_lookup_sigalg(s, *ptmp); /* Skip disabled hashes or signature algorithms */ if (!tls12_sigalg_allowed(s, SSL_SECOP_SIGALG_SHARED, lu)) @@ -2056,7 +2111,7 @@ int SSL_get_sigalgs(SSL *s, int idx, *rhash = (unsigned char)((*psig >> 8) & 0xff); if (rsig != NULL) *rsig = (unsigned char)(*psig & 0xff); - lu = tls1_lookup_sigalg(*psig); + lu = tls1_lookup_sigalg(s, *psig); if (psign != NULL) *psign = lu != NULL ? lu->sig : NID_undef; if (phash != NULL) @@ -2294,7 +2349,7 @@ static int tls1_check_sig_alg(SSL *s, X509 *x, int default_nid) } for (i = 0; i < sigalgslen; i++) { sigalg = use_pc_sigalgs - ? tls1_lookup_sigalg(s->s3.tmp.peer_cert_sigalgs[i]) + ? tls1_lookup_sigalg(s, s->s3.tmp.peer_cert_sigalgs[i]) : s->shared_sigalgs[i]; if (sigalg != NULL && sig_nid == sigalg->sigandhash) return 1; @@ -2442,7 +2497,7 @@ int tls1_check_chain(SSL *s, X509 *x, EVP_PKEY *pk, STACK_OF(X509) *chain, size_t j; const uint16_t *p = c->conf_sigalgs; for (j = 0; j < c->conf_sigalgslen; j++, p++) { - const SIGALG_LOOKUP *lu = tls1_lookup_sigalg(*p); + const SIGALG_LOOKUP *lu = tls1_lookup_sigalg(s, *p); if (lu != NULL && lu->hash == NID_sha1 && lu->sig == rsign) break; @@ -2777,7 +2832,7 @@ static int check_cert_usable(SSL *s, const SIGALG_LOOKUP *sig, X509 *x, if (!X509_get_signature_info(x, &mdnid, &pknid, NULL, NULL)) return 0; for (i = 0; i < s->s3.tmp.peer_cert_sigalgslen; i++) { - lu = tls1_lookup_sigalg(s->s3.tmp.peer_cert_sigalgs[i]); + lu = tls1_lookup_sigalg(s, s->s3.tmp.peer_cert_sigalgs[i]); if (lu == NULL) continue; -- 2.34.1