From 3653d0c224593ef55830c2fb17941aba9ea26ea8 Mon Sep 17 00:00:00 2001 From: Matt Caswell Date: Wed, 13 Mar 2019 14:49:40 +0000 Subject: [PATCH] Implement EVP_MD_fetch() Reviewed-by: Paul Dale (Merged from https://github.com/openssl/openssl/pull/8513) --- crypto/evp/digest.c | 92 +++++++++++++++++++++++++++++++ crypto/evp/evp_lib.c | 27 ++++++++- crypto/include/internal/evp_int.h | 18 ++++++ include/openssl/core_numbers.h | 22 ++++++++ include/openssl/evp.h | 4 ++ util/libcrypto.num | 2 + 6 files changed, 164 insertions(+), 1 deletion(-) diff --git a/crypto/evp/digest.c b/crypto/evp/digest.c index 86be9aec57..08b5198f04 100644 --- a/crypto/evp/digest.c +++ b/crypto/evp/digest.c @@ -13,6 +13,7 @@ #include #include #include "internal/evp_int.h" +#include "internal/provider.h" #include "evp_locl.h" /* This call frees resources associated with the context */ @@ -296,3 +297,94 @@ int EVP_MD_CTX_ctrl(EVP_MD_CTX *ctx, int cmd, int p1, void *p2) } return 0; } + +static void *evp_md_from_dispatch(int mdtype, const OSSL_DISPATCH *fns, + OSSL_PROVIDER *prov) +{ + EVP_MD *md = NULL; + + if ((md = EVP_MD_meth_new(mdtype, NID_undef)) == NULL) + return NULL; + + for (; fns->function_id != 0; fns++) { + int fncnt = 0; + + switch (fns->function_id) { + case OSSL_FUNC_DIGEST_NEWCTX: + if (md->newctx != NULL) + break; + md->newctx = OSSL_get_OP_digest_newctx(fns); + fncnt++; + break; + case OSSL_FUNC_DIGEST_INIT: + if (md->dinit != NULL) + break; + md->dinit = OSSL_get_OP_digest_init(fns); + fncnt++; + break; + case OSSL_FUNC_DIGEST_UPDDATE: + if (md->dupdate != NULL) + break; + md->dupdate = OSSL_get_OP_digest_update(fns); + fncnt++; + break; + case OSSL_FUNC_DIGEST_FINAL: + if (md->dfinal != NULL) + break; + md->dfinal = OSSL_get_OP_digest_final(fns); + fncnt++; + break; + case OSSL_FUNC_DIGEST_DIGEST: + if (md->digest != NULL) + break; + md->digest = OSSL_get_OP_digest_digest(fns); + /* We don't increment fnct for this as it is stand alone */ + break; + case OSSL_FUNC_DIGEST_CLEANCTX: + if (md->cleanctx != NULL) + break; + md->cleanctx = OSSL_get_OP_digest_cleanctx(fns); + fncnt++; + break; + case OSSL_FUNC_DIGEST_FREECTX: + if (md->freectx != NULL) + break; + md->freectx = OSSL_get_OP_digest_freectx(fns); + fncnt++; + break; + } + if ((fncnt != 0 && fncnt != 6) || (fncnt == 0 && md->digest == NULL)) { + /* + * In order to be a consistent set of functions we either need the + * whole set of init/update/final etc functions or none of them. + * The "digest" function can standalone. We at least need one way to + * generate digests. + */ + EVP_MD_meth_free(md); + return NULL; + } + } + md->prov = prov; + if (prov != NULL) + ossl_provider_upref(prov); + + return md; +} + +static int evp_md_upref(void *md) +{ + return EVP_MD_upref(md); +} + +static void evp_md_free(void *md) +{ + EVP_MD_meth_free(md); +} + +EVP_MD *EVP_MD_fetch(OPENSSL_CTX *ctx, const char *algorithm, + const char *properties) +{ + return evp_generic_fetch(ctx, OSSL_OP_DIGEST, algorithm, properties, + evp_md_from_dispatch, evp_md_upref, + evp_md_free); +} diff --git a/crypto/evp/evp_lib.c b/crypto/evp/evp_lib.c index f0ee6ab663..ed95dd5eec 100644 --- a/crypto/evp/evp_lib.c +++ b/crypto/evp/evp_lib.c @@ -12,6 +12,7 @@ #include #include #include "internal/evp_int.h" +#include "internal/provider.h" #include "evp_locl.h" int EVP_CIPHER_param_to_asn1(EVP_CIPHER_CTX *c, ASN1_TYPE *type) @@ -331,6 +332,12 @@ EVP_MD *EVP_MD_meth_new(int md_type, int pkey_type) if (md != NULL) { md->type = md_type; md->pkey_type = pkey_type; + md->lock = CRYPTO_THREAD_lock_new(); + if (md->lock == NULL) { + OPENSSL_free(md); + return NULL; + } + md->refcnt = 1; } return md; } @@ -342,9 +349,27 @@ EVP_MD *EVP_MD_meth_dup(const EVP_MD *md) memcpy(to, md, sizeof(*to)); return to; } + +int EVP_MD_upref(EVP_MD *md) +{ + int ref = 0; + + CRYPTO_UP_REF(&md->refcnt, &ref, md->lock); + return 1; +} + void EVP_MD_meth_free(EVP_MD *md) { - OPENSSL_free(md); + if (md != NULL) { + int i; + + CRYPTO_DOWN_REF(&md->refcnt, &i, md->lock); + if (i > 0) + return; + ossl_provider_free(md->prov); + CRYPTO_THREAD_lock_free(md->lock); + OPENSSL_free(md); + } } int EVP_MD_meth_set_input_blocksize(EVP_MD *md, int blocksize) { diff --git a/crypto/include/internal/evp_int.h b/crypto/include/internal/evp_int.h index f6f99edb14..ba0eedd46b 100644 --- a/crypto/include/internal/evp_int.h +++ b/crypto/include/internal/evp_int.h @@ -8,6 +8,7 @@ */ #include +#include #include "internal/refcount.h" /* @@ -172,7 +173,11 @@ extern const EVP_KDF_METHOD sshkdf_kdf_meth; extern const EVP_KDF_METHOD ss_kdf_meth; struct evp_md_st { + /* nid */ int type; + + /* Legacy structure members */ + /* TODO(3.0): Remove these */ int pkey_type; int md_size; unsigned long flags; @@ -185,6 +190,19 @@ struct evp_md_st { int ctx_size; /* how big does the ctx->md_data need to be */ /* control function */ int (*md_ctrl) (EVP_MD_CTX *ctx, int cmd, int p1, void *p2); + + /* New structure members */ + /* TODO(3.0): Remove above comment when legacy has gone */ + OSSL_PROVIDER *prov; + CRYPTO_REF_COUNT refcnt; + CRYPTO_RWLOCK *lock; + OSSL_OP_digest_newctx_fn *newctx; + OSSL_OP_digest_init_fn *dinit; + OSSL_OP_digest_update_fn *dupdate; + OSSL_OP_digest_final_fn *dfinal; + OSSL_OP_digest_digest_fn *digest; + OSSL_OP_digest_freectx_fn *freectx; + } /* EVP_MD */ ; struct evp_cipher_st { diff --git a/include/openssl/core_numbers.h b/include/openssl/core_numbers.h index 7be2a2bb75..9bce619e99 100644 --- a/include/openssl/core_numbers.h +++ b/include/openssl/core_numbers.h @@ -72,6 +72,28 @@ OSSL_CORE_MAKE_FUNC(const OSSL_ALGORITHM *,provider_query_operation, (const OSSL_PROVIDER *, int operation_id, const int *no_store)) +/* Digests */ + +# define OSSL_OP_DIGEST 1 + +# define OSSL_FUNC_DIGEST_NEWCTX 1 +# define OSSL_FUNC_DIGEST_INIT 2 +# define OSSL_FUNC_DIGEST_UPDDATE 3 +# define OSSL_FUNC_DIGEST_FINAL 4 +# define OSSL_FUNC_DIGEST_DIGEST 5 +# define OSSL_FUNC_DIGEST_FREECTX 6 + +OSSL_CORE_MAKE_FUNC(void *, OP_digest_newctx, (void)) +OSSL_CORE_MAKE_FUNC(int, OP_digest_init, (void *vctx)) +OSSL_CORE_MAKE_FUNC(int, OP_digest_update, + (void *vctx, unsigned char *in, size_t inl)) +OSSL_CORE_MAKE_FUNC(int, OP_digest_final, + (void *vctx, unsigned char *out, size_t *outl)) +OSSL_CORE_MAKE_FUNC(int, OP_digest_digest, + (unsigned char *in, size_t inl, unsigned char *out, + size_t *out_l)) +OSSL_CORE_MAKE_FUNC(void, OP_digest_cleanctx, (void *vctx)) +OSSL_CORE_MAKE_FUNC(void, OP_digest_freectx, (void *vctx)) # ifdef __cplusplus } diff --git a/include/openssl/evp.h b/include/openssl/evp.h index ca7655d5e4..db8eec12f2 100644 --- a/include/openssl/evp.h +++ b/include/openssl/evp.h @@ -77,6 +77,7 @@ extern "C" { # ifndef EVP_MD EVP_MD *EVP_MD_meth_new(int md_type, int pkey_type); EVP_MD *EVP_MD_meth_dup(const EVP_MD *md); +int EVP_MD_upref(EVP_MD *md); void EVP_MD_meth_free(EVP_MD *md); int EVP_MD_meth_set_input_blocksize(EVP_MD *md, int blocksize); @@ -561,6 +562,9 @@ __owur int EVP_DigestFinal(EVP_MD_CTX *ctx, unsigned char *md, __owur int EVP_DigestFinalXOF(EVP_MD_CTX *ctx, unsigned char *md, size_t len); +__owur EVP_MD *EVP_MD_fetch(OPENSSL_CTX *ctx, const char *algorithm, + const char *properties); + int EVP_read_pw_string(char *buf, int length, const char *prompt, int verify); int EVP_read_pw_string_min(char *buf, int minlen, int maxlen, const char *prompt, int verify); diff --git a/util/libcrypto.num b/util/libcrypto.num index bf14bbd28d..5b488d0e4d 100644 --- a/util/libcrypto.num +++ b/util/libcrypto.num @@ -4791,3 +4791,5 @@ OSSL_PARAM_set_octet_ptr 4738 3_0_0 EXIST::FUNCTION: X509_set_sm2_id 4739 3_0_0 EXIST::FUNCTION:SM2 X509_get0_sm2_id 4740 3_0_0 EXIST::FUNCTION:SM2 EVP_PKEY_get0_engine 4741 3_0_0 EXIST::FUNCTION:ENGINE +EVP_MD_upref 4742 3_0_0 EXIST::FUNCTION: +EVP_MD_fetch 4743 3_0_0 EXIST::FUNCTION: -- 2.25.1