The branch master has been updated via 0d52ede71685e4176999cc5e52000dcb540747fc (commit) via b38425393c76ff31560d6b0bdb0b097e7d93ffc4 (commit) via 3cd69b7458f1dfa274d4d8fe1a46a35d91e9008c (commit) via d01d375264e73f49a416409e2f8febe88ad39c8a (commit) via 5f603a280ca71b7136861b9bc408f37fd1c4e0d7 (commit) via 263ff2c9d4c88f19133d21d9956d71edd7401d54 (commit) from eca471391378139f76a7d1229b6a5a1dcc4b5603 (commit)
- Log ----------------------------------------------------------------- commit 0d52ede71685e4176999cc5e52000dcb540747fc Author: Matt Caswell <m...@openssl.org> Date: Wed May 13 14:45:36 2020 +0100 Fix error path in int create_ssl_ctx_pair() If we hit the error path and create_ssl_ctx_pair has been passed a pre-created SSL_CTX then we could end up with a double free. Reviewed-by: Shane Lontis <shane.lon...@oracle.com> (Merged from https://github.com/openssl/openssl/pull/11834) commit b38425393c76ff31560d6b0bdb0b097e7d93ffc4 Author: Matt Caswell <m...@openssl.org> Date: Fri May 8 16:43:14 2020 +0100 Implement a test for sigalgs not being present If sigalgs are not present we should not offer or accept them. We should test that we handle this correctly. Reviewed-by: Shane Lontis <shane.lon...@oracle.com> (Merged from https://github.com/openssl/openssl/pull/11834) commit 3cd69b7458f1dfa274d4d8fe1a46a35d91e9008c Author: Matt Caswell <m...@openssl.org> Date: Mon May 4 16:26:07 2020 +0100 Implement a Filtering Provider The filtering provider can be used to place a filter in front of the default provider. Initially to filter out certain algorithms from being available for test purposes. Reviewed-by: Shane Lontis <shane.lon...@oracle.com> (Merged from https://github.com/openssl/openssl/pull/11834) commit d01d375264e73f49a416409e2f8febe88ad39c8a Author: Matt Caswell <m...@openssl.org> Date: Fri May 8 16:44:02 2020 +0100 Implement OSSL_PROVIDER_get0_provider_ctx() Implement a function which enables us to get hold of the provider ctx for a loaded provider. Reviewed-by: Shane Lontis <shane.lon...@oracle.com> (Merged from https://github.com/openssl/openssl/pull/11834) commit 5f603a280ca71b7136861b9bc408f37fd1c4e0d7 Author: Matt Caswell <m...@openssl.org> Date: Mon May 4 15:28:15 2020 +0100 Enable applications to directly call a provider's query operation This is useful to get hold of the low-level dispatch tables. This could be used to create a new provider based on an existing one. Reviewed-by: Shane Lontis <shane.lon...@oracle.com> (Merged from https://github.com/openssl/openssl/pull/11834) commit 263ff2c9d4c88f19133d21d9956d71edd7401d54 Author: Matt Caswell <m...@openssl.org> Date: Fri May 1 17:41:25 2020 +0100 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 <shane.lon...@oracle.com> (Merged from https://github.com/openssl/openssl/pull/11834) ----------------------------------------------------------------------- Summary of changes: crypto/provider.c | 13 +++ crypto/provider_core.c | 8 ++ doc/man3/OSSL_PROVIDER.pod | 23 +++++ include/internal/provider.h | 1 + include/openssl/provider.h | 5 ++ ssl/ssl_lib.c | 6 ++ ssl/ssl_local.h | 6 ++ ssl/t1_lib.c | 149 ++++++++++++++++++++++----------- test/build.info | 2 +- test/filterprov.c | 199 ++++++++++++++++++++++++++++++++++++++++++++ test/sslapitest.c | 160 +++++++++++++++++++++++++++++++++-- test/ssltestlib.c | 6 +- util/libcrypto.num | 2 + 13 files changed, 525 insertions(+), 55 deletions(-) create mode 100644 test/filterprov.c diff --git a/crypto/provider.c b/crypto/provider.c index 13438cefe3..02002a5f95 100644 --- a/crypto/provider.c +++ b/crypto/provider.c @@ -57,6 +57,19 @@ int OSSL_PROVIDER_get_params(const OSSL_PROVIDER *prov, OSSL_PARAM params[]) return ossl_provider_get_params(prov, params); } + +const OSSL_ALGORITHM *OSSL_PROVIDER_query_operation(const OSSL_PROVIDER *prov, + int operation_id, + int *no_cache) +{ + return ossl_provider_query_operation(prov, operation_id, no_cache); +} + +void *OSSL_PROVIDER_get0_provider_ctx(const OSSL_PROVIDER *prov) +{ + return ossl_provider_prov_ctx(prov); +} + int OSSL_PROVIDER_add_builtin(OPENSSL_CTX *libctx, const char *name, OSSL_provider_init_fn *init_fn) { diff --git a/crypto/provider_core.c b/crypto/provider_core.c index 8b868fdb6b..f7af51a297 100644 --- a/crypto/provider_core.c +++ b/crypto/provider_core.c @@ -787,6 +787,14 @@ const char *ossl_provider_module_path(const OSSL_PROVIDER *prov) #endif } +void *ossl_provider_prov_ctx(const OSSL_PROVIDER *prov) +{ + if (prov != NULL) + return prov->provctx; + + return NULL; +} + OPENSSL_CTX *ossl_provider_library_context(const OSSL_PROVIDER *prov) { /* TODO(3.0) just: return prov->libctx; */ diff --git a/doc/man3/OSSL_PROVIDER.pod b/doc/man3/OSSL_PROVIDER.pod index 93d6e1421c..d6f0af53c9 100644 --- a/doc/man3/OSSL_PROVIDER.pod +++ b/doc/man3/OSSL_PROVIDER.pod @@ -6,6 +6,7 @@ OSSL_PROVIDER_set_default_search_path, OSSL_PROVIDER, OSSL_PROVIDER_load, OSSL_PROVIDER_unload, OSSL_PROVIDER_available, OSSL_PROVIDER_do_all, OSSL_PROVIDER_gettable_params, OSSL_PROVIDER_get_params, +OSSL_PROVIDER_query_operation, OSSL_PROVIDER_get0_provider_ctx, OSSL_PROVIDER_add_builtin, OSSL_PROVIDER_name - provider routines =head1 SYNOPSIS @@ -27,6 +28,11 @@ OSSL_PROVIDER_add_builtin, OSSL_PROVIDER_name - provider routines const OSSL_PARAM *OSSL_PROVIDER_gettable_params(OSSL_PROVIDER *prov); int OSSL_PROVIDER_get_params(OSSL_PROVIDER *prov, OSSL_PARAM params[]); + const OSSL_ALGORITHM *OSSL_PROVIDER_query_operation(const OSSL_PROVIDER *prov, + int operation_id, + int *no_cache); + void *OSSL_PROVIDER_get0_provider_ctx(const OSSL_PROVIDER *prov); + int OSSL_PROVIDER_add_builtin(OPENSSL_CTX *libctx, const char *name, ossl_provider_init_fn *init_fn); @@ -82,6 +88,20 @@ The caller must prepare the B<OSSL_PARAM> array before calling this function, and the variables acting as buffers for this parameter array should be filled with data when it returns successfully. +OSSL_PROVIDER_query_operation() calls the provider's I<query_operation> +function (see L<provider(7)>), if the provider has one. It returns an +array of I<OSSL_ALGORITHM> for the given I<operation_id> terminated by an all +NULL OSSL_ALGORITHM entry. This is considered a low-level function that most +applications should not need to call. + +OSSL_PROVIDER_get0_provider_ctx() returns the provider context for the given +provider. The provider context is an opaque handle set by the provider itself +and is passed back to the provider by libcrypto in various function calls. + +If it is permissible to cache references to this array then I<*no_store> is set +to 0 or 1 otherwise. If the array is not cacheable then it is assumed to +have a short lifetime. + OSSL_PROVIDER_name() returns the name of the given provider. =head1 RETURN VALUES @@ -101,6 +121,9 @@ of constant B<OSSL_PARAM>, or NULL if none is provided. OSSL_PROVIDER_get_params() returns 1 on success, or 0 on error. +OSSL_PROVIDER_query_operation() returns an array of OSSL_ALGORITHM or NULL on +error. + =head1 EXAMPLES This demonstrates how to load the provider module "foo" and ask for diff --git a/include/internal/provider.h b/include/internal/provider.h index 135b660f49..d7c0926a0b 100644 --- a/include/internal/provider.h +++ b/include/internal/provider.h @@ -64,6 +64,7 @@ const char *ossl_provider_name(const OSSL_PROVIDER *prov); const DSO *ossl_provider_dso(const OSSL_PROVIDER *prov); const char *ossl_provider_module_name(const OSSL_PROVIDER *prov); const char *ossl_provider_module_path(const OSSL_PROVIDER *prov); +void *ossl_provider_prov_ctx(const OSSL_PROVIDER *prov); OPENSSL_CTX *ossl_provider_library_context(const OSSL_PROVIDER *prov); /* Thin wrappers around calls to the provider */ diff --git a/include/openssl/provider.h b/include/openssl/provider.h index 6ce68b16e7..e9a1408675 100644 --- a/include/openssl/provider.h +++ b/include/openssl/provider.h @@ -30,6 +30,11 @@ int OSSL_PROVIDER_do_all(OPENSSL_CTX *ctx, const OSSL_PARAM *OSSL_PROVIDER_gettable_params(const OSSL_PROVIDER *prov); int OSSL_PROVIDER_get_params(const OSSL_PROVIDER *prov, OSSL_PARAM params[]); +const OSSL_ALGORITHM *OSSL_PROVIDER_query_operation(const OSSL_PROVIDER *prov, + int operation_id, + int *no_cache); +void *OSSL_PROVIDER_get0_provider_ctx(const OSSL_PROVIDER *prov); + /* Add a built in providers */ int OSSL_PROVIDER_add_builtin(OPENSSL_CTX *, const char *name, OSSL_provider_init_fn *init_fn); 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; diff --git a/test/build.info b/test/build.info index 3255a836de..868b8ebefa 100644 --- a/test/build.info +++ b/test/build.info @@ -290,7 +290,7 @@ IF[{- !$disabled{tests} -}] INCLUDE[param_build_test]=../include ../apps/include DEPEND[param_build_test]=../libcrypto.a libtestutil.a - SOURCE[sslapitest]=sslapitest.c ssltestlib.c + SOURCE[sslapitest]=sslapitest.c ssltestlib.c filterprov.c INCLUDE[sslapitest]=../include ../apps/include .. DEPEND[sslapitest]=../libcrypto ../libssl libtestutil.a diff --git a/test/filterprov.c b/test/filterprov.c new file mode 100644 index 0000000000..9fe6690e50 --- /dev/null +++ b/test/filterprov.c @@ -0,0 +1,199 @@ +/* + * Copyright 2020 The OpenSSL Project Authors. All Rights Reserved. + * + * Licensed under the Apache License 2.0 (the "License"). You may not use + * this file except in compliance with the License. You can obtain a copy + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ + +/* + * A filtering provider for test purposes. We pass all calls through to the + * default provider except where we want other behaviour for a test. + */ + +#include <string.h> +#include <openssl/core.h> +#include <openssl/core_numbers.h> +#include <openssl/provider.h> +#include <openssl/crypto.h> + +OSSL_provider_init_fn filter_provider_init; + +int filter_provider_set_filter(int operation, const char *name); + +#define MAX_FILTERS 10 +#define MAX_ALG_FILTERS 5 + +struct filter_prov_globals_st { + OPENSSL_CTX *libctx; + OSSL_PROVIDER *deflt; + struct { + int operation; + OSSL_ALGORITHM alg[MAX_ALG_FILTERS + 1]; + } dispatch[MAX_FILTERS]; + int num_dispatch; +}; + +static struct filter_prov_globals_st ourglobals; + +static struct filter_prov_globals_st *get_globals(void) +{ + /* + * Ideally we'd like to store this in the OPENSSL_CTX so that we can have + * more than one instance of the filter provider at a time. But for now we + * just make it simple. + */ + return &ourglobals; +} + +static OSSL_provider_gettable_params_fn filter_gettable_params; +static OSSL_provider_get_params_fn filter_get_params; +static OSSL_provider_query_operation_fn filter_query; +static OSSL_provider_teardown_fn filter_teardown; + +static const OSSL_PARAM *filter_gettable_params(void *provctx) +{ + struct filter_prov_globals_st *globs = get_globals(); + + return OSSL_PROVIDER_gettable_params(globs->deflt); +} + +static int filter_get_params(void *provctx, OSSL_PARAM params[]) +{ + struct filter_prov_globals_st *globs = get_globals(); + + return OSSL_PROVIDER_get_params(globs->deflt, params); +} + +static const OSSL_ALGORITHM *filter_query(void *provctx, + int operation_id, + int *no_cache) +{ + struct filter_prov_globals_st *globs = get_globals(); + int i; + + for (i = 0; i < globs->num_dispatch; i++) { + if (globs->dispatch[i].operation == operation_id) { + *no_cache = 0; + return globs->dispatch[i].alg; + } + } + + /* No filter set, so pass it down to the chained provider */ + return OSSL_PROVIDER_query_operation(globs->deflt, operation_id, no_cache); +} + +static void filter_teardown(void *provctx) +{ + struct filter_prov_globals_st *globs = get_globals(); + + OSSL_PROVIDER_unload(globs->deflt); + OPENSSL_CTX_free(globs->libctx); +} + +/* Functions we provide to the core */ +static const OSSL_DISPATCH filter_dispatch_table[] = { + { OSSL_FUNC_PROVIDER_GETTABLE_PARAMS, (void (*)(void))filter_gettable_params }, + { OSSL_FUNC_PROVIDER_GET_PARAMS, (void (*)(void))filter_get_params }, + { OSSL_FUNC_PROVIDER_QUERY_OPERATION, (void (*)(void))filter_query }, + { OSSL_FUNC_PROVIDER_TEARDOWN, (void (*)(void))filter_teardown }, + { 0, NULL } +}; + +int filter_provider_init(const OSSL_CORE_HANDLE *handle, + const OSSL_DISPATCH *in, + const OSSL_DISPATCH **out, + void **provctx) +{ + memset(&ourglobals, 0, sizeof(ourglobals)); + ourglobals.libctx = OPENSSL_CTX_new(); + if (ourglobals.libctx == NULL) + goto err; + + ourglobals.deflt = OSSL_PROVIDER_load(ourglobals.libctx, "default"); + if (ourglobals.deflt == NULL) + goto err; + + *provctx = OSSL_PROVIDER_get0_provider_ctx(ourglobals.deflt); + *out = filter_dispatch_table; + return 1; + + err: + OSSL_PROVIDER_unload(ourglobals.deflt); + OPENSSL_CTX_free(ourglobals.libctx); + return 0; +} + +/* + * Set a filter for the given operation id. The filter string is a colon + * separated list of algorithms that will be made available by this provider. + * Anything not in the filter will be suppressed. If a filter is not set for + * a given operation id then all algorithms are made available. + */ +int filter_provider_set_filter(int operation, const char *filterstr) +{ + int no_cache = 0; + int algnum = 0, last = 0, ret = 0; + struct filter_prov_globals_st *globs = get_globals(); + size_t namelen; + char *filterstrtmp = OPENSSL_strdup(filterstr); + char *name, *sep; + const OSSL_ALGORITHM *provalgs = OSSL_PROVIDER_query_operation(globs->deflt, + operation, + &no_cache); + const OSSL_ALGORITHM *algs; + + if (filterstrtmp == NULL) + goto err; + + /* We don't support no_cache */ + if (no_cache) + goto err; + + /* Nothing to filter */ + if (provalgs == NULL) + goto err; + + if (globs->num_dispatch >= MAX_FILTERS) + goto err; + + for (name = filterstrtmp; !last; name = sep + 1) { + sep = strstr(name, ":"); + if (sep != NULL) + *sep = '\0'; + else + last = 1; + namelen = strlen(name); + + for (algs = provalgs; algs->algorithm_names != NULL; algs++) { + const char *found = strstr(algs->algorithm_names, name); + + if (found == NULL) + continue; + if (found[namelen] != '\0' && found[namelen] != ':') + continue; + if (found != algs->algorithm_names && found[-1] != ':') + continue; + + /* We found a match */ + if (algnum >= MAX_ALG_FILTERS) + goto err; + + globs->dispatch[globs->num_dispatch].alg[algnum++] = *algs; + break; + } + if (algs->algorithm_names == NULL) { + /* No match found */ + goto err; + } + } + + globs->dispatch[globs->num_dispatch].operation = operation; + globs->num_dispatch++; + + ret = 1; + err: + OPENSSL_free(filterstrtmp); + return ret; +} diff --git a/test/sslapitest.c b/test/sslapitest.c index 423da560ae..8847ba38ce 100644 --- a/test/sslapitest.c +++ b/test/sslapitest.c @@ -28,6 +28,7 @@ #include <openssl/aes.h> #include <openssl/rand.h> #include <openssl/core_names.h> +#include <openssl/core_numbers.h> #include <openssl/provider.h> #include "ssltestlib.h" @@ -37,6 +38,10 @@ #include "internal/ktls.h" #include "../ssl/ssl_local.h" +/* Defined in filterprov.c */ +OSSL_provider_init_fn filter_provider_init; +int filter_provider_set_filter(int operation, const char *name); + DEFINE_STACK_OF(OCSP_RESPID) DEFINE_STACK_OF(X509) DEFINE_STACK_OF(X509_NAME) @@ -65,6 +70,8 @@ static SSL_SESSION *create_a_psk(SSL *ssl); static char *certsdir = NULL; static char *cert = NULL; static char *privkey = NULL; +static char *cert2 = NULL; +static char *privkey2 = NULL; static char *srpvfile = NULL; static char *tmpfilename = NULL; @@ -7664,6 +7671,131 @@ static int test_servername(int tst) return testresult; } +#ifndef OPENSSL_NO_EC +/* + * Test that if signature algorithms are not available, then we do not offer or + * accept them. + * Test 0: Two RSA sig algs available: both RSA sig algs shared + * Test 1: The client only has SHA2-256: only SHA2-256 algorithms shared + * Test 2: The server only has SHA2-256: only SHA2-256 algorithms shared + * Test 3: An RSA and an ECDSA sig alg available: both sig algs shared + * Test 4: The client only has an ECDSA sig alg: only ECDSA algorithms shared + * Test 5: The server only has an ECDSA sig alg: only ECDSA algorithms shared + */ +static int test_sigalgs_available(int idx) +{ + SSL_CTX *cctx = NULL, *sctx = NULL; + SSL *clientssl = NULL, *serverssl = NULL; + int testresult = 0; + OPENSSL_CTX *tmpctx = OPENSSL_CTX_new(); + OPENSSL_CTX *clientctx = libctx, *serverctx = libctx; + OSSL_PROVIDER *filterprov = NULL; + int sig, hash; + + if (!TEST_ptr(tmpctx)) + goto end; + + if (idx != 0 && idx != 3) { + if (!TEST_true(OSSL_PROVIDER_add_builtin(tmpctx, "filter", + filter_provider_init))) + goto end; + + filterprov = OSSL_PROVIDER_load(tmpctx, "filter"); + if (!TEST_ptr(filterprov)) + goto end; + + if (idx < 3) { + /* + * Only enable SHA2-256 so rsa_pss_rsae_sha384 should not be offered + * or accepted for the peer that uses this libctx. Note that libssl + * *requires* SHA2-256 to be available so we cannot disable that. We + * also need SHA1 for our certificate. + */ + if (!TEST_true(filter_provider_set_filter(OSSL_OP_DIGEST, + "SHA2-256:SHA1"))) + goto end; + } else { + if (!TEST_true(filter_provider_set_filter(OSSL_OP_SIGNATURE, + "ECDSA")) + || !TEST_true(filter_provider_set_filter(OSSL_OP_KEYMGMT, + "EC:X25519:X448"))) + goto end; + } + + if (idx == 1 || idx == 4) + clientctx = tmpctx; + else + serverctx = tmpctx; + } + + cctx = SSL_CTX_new_with_libctx(clientctx, NULL, TLS_client_method()); + sctx = SSL_CTX_new_with_libctx(serverctx, NULL, TLS_server_method()); + + if (!TEST_true(create_ssl_ctx_pair(libctx, TLS_server_method(), + TLS_client_method(), + TLS1_VERSION, + 0, + &sctx, &cctx, cert, privkey))) + goto end; + + if (idx < 3) { + if (!SSL_CTX_set1_sigalgs_list(cctx, + "rsa_pss_rsae_sha384" + ":rsa_pss_rsae_sha256") + || !SSL_CTX_set1_sigalgs_list(sctx, + "rsa_pss_rsae_sha384" + ":rsa_pss_rsae_sha256")) + goto end; + } else { + if (!SSL_CTX_set1_sigalgs_list(cctx, "rsa_pss_rsae_sha256:ECDSA+SHA256") + || !SSL_CTX_set1_sigalgs_list(sctx, + "rsa_pss_rsae_sha256:ECDSA+SHA256")) + goto end; + } + + if (!TEST_int_eq(SSL_CTX_use_certificate_file(sctx, cert2, + SSL_FILETYPE_PEM), 1) + || !TEST_int_eq(SSL_CTX_use_PrivateKey_file(sctx, + privkey2, + SSL_FILETYPE_PEM), 1) + || !TEST_int_eq(SSL_CTX_check_private_key(sctx), 1)) + goto end; + + if (!TEST_true(create_ssl_objects(sctx, cctx, &serverssl, &clientssl, + NULL, NULL))) + goto end; + + if (!TEST_true(create_ssl_connection(serverssl, clientssl, SSL_ERROR_NONE))) + goto end; + + /* For tests 0 and 3 we expect 2 shared sigalgs, otherwise exactly 1 */ + if (!TEST_int_eq(SSL_get_shared_sigalgs(serverssl, 0, &sig, &hash, NULL, + NULL, NULL), + (idx == 0 || idx == 3) ? 2 : 1)) + goto end; + + if (!TEST_int_eq(hash, idx == 0 ? NID_sha384 : NID_sha256)) + goto end; + + if (!TEST_int_eq(sig, (idx == 4 || idx == 5) ? EVP_PKEY_EC + : NID_rsassaPss)) + goto end; + + testresult = 1; + + end: + SSL_free(serverssl); + SSL_free(clientssl); + SSL_CTX_free(sctx); + SSL_CTX_free(cctx); + OSSL_PROVIDER_unload(filterprov); + OPENSSL_CTX_free(tmpctx); + + return testresult; +} +#endif /* OPENSSL_NO_EC */ + + OPT_TEST_DECLARE_USAGE("certfile privkeyfile srpvfile tmpfile provider config\n") int setup_tests(void) @@ -7730,13 +7862,19 @@ int setup_tests(void) cert = test_mk_file_path(certsdir, "servercert.pem"); if (cert == NULL) - return 0; + goto err; privkey = test_mk_file_path(certsdir, "serverkey.pem"); - if (privkey == NULL) { - OPENSSL_free(cert); - return 0; - } + if (privkey == NULL) + goto err; + + cert2 = test_mk_file_path(certsdir, "server-ecdsa-cert.pem"); + if (cert2 == NULL) + goto err; + + privkey2 = test_mk_file_path(certsdir, "server-ecdsa-key.pem"); + if (privkey2 == NULL) + goto err; #if !defined(OPENSSL_NO_TLS1_2) && !defined(OPENSSL_NO_KTLS) \ && !defined(OPENSSL_NO_SOCK) @@ -7859,13 +7997,25 @@ int setup_tests(void) ADD_ALL_TESTS(test_multiblock_write, OSSL_NELEM(multiblock_cipherlist_data)); #endif ADD_ALL_TESTS(test_servername, 10); +#ifndef OPENSSL_NO_EC + ADD_ALL_TESTS(test_sigalgs_available, 6); +#endif return 1; + + err: + OPENSSL_free(cert); + OPENSSL_free(privkey); + OPENSSL_free(cert2); + OPENSSL_free(privkey2); + return 0; } void cleanup_tests(void) { OPENSSL_free(cert); OPENSSL_free(privkey); + OPENSSL_free(cert2); + OPENSSL_free(privkey2); bio_s_mempacket_test_free(); bio_s_always_retry_free(); OSSL_PROVIDER_unload(defctxnull); diff --git a/test/ssltestlib.c b/test/ssltestlib.c index ce0e776110..96c1a7f2de 100644 --- a/test/ssltestlib.c +++ b/test/ssltestlib.c @@ -741,8 +741,10 @@ const SSL_METHOD *cm, return 1; err: - SSL_CTX_free(serverctx); - SSL_CTX_free(clientctx); + if (*sctx == NULL) + SSL_CTX_free(serverctx); + if (cctx != NULL && *cctx == NULL) + SSL_CTX_free(clientctx); return 0; } diff --git a/util/libcrypto.num b/util/libcrypto.num index fd0509172f..a34d467099 100644 --- a/util/libcrypto.num +++ b/util/libcrypto.num @@ -5097,3 +5097,5 @@ EC_GROUP_get_field_type ? 3_0_0 EXIST::FUNCTION:EC X509_PUBKEY_eq ? 3_0_0 EXIST::FUNCTION: EVP_PKEY_eq ? 3_0_0 EXIST::FUNCTION: EVP_PKEY_parameters_eq ? 3_0_0 EXIST::FUNCTION: +OSSL_PROVIDER_query_operation ? 3_0_0 EXIST::FUNCTION: +OSSL_PROVIDER_get0_provider_ctx ? 3_0_0 EXIST::FUNCTION: