diff options
author | Richard Levitte <levitte@openssl.org> | 2019-05-07 12:39:58 +0200 |
---|---|---|
committer | Richard Levitte <levitte@openssl.org> | 2019-08-15 22:12:25 +0200 |
commit | e74bd29053a543ab4908ae8545b46f2e38c98bab (patch) | |
tree | ee0d540bd5f8319549c1ab0d4b356f8b166d021e | |
parent | 3ded2288a45d2cc3a27a1b08d29499cbcec52c0e (diff) |
Prepare EVP_MAC infrastructure for moving all MACs to providers
Quite a few adaptations are needed, most prominently the added code
to allow provider based MACs.
As part of this, all the old information functions are gone, except
for EVP_MAC_name(). Some of them will reappear later, for example
EVP_MAC_do_all() in some form.
MACs by EVP_PKEY was particularly difficult to deal with, as they
need to allocate and deallocate EVP_MAC_CTXs "under the hood", and
thereby implicitly fetch the corresponding EVP_MAC. This means that
EVP_MACs can't be constant in a EVP_MAC_CTX, as their reference count
may need to be incremented and decremented as part of the allocation
or deallocation of the EVP_MAC_CTX. It may be that other provider
based EVP operation types may need to be handled in a similar manner.
Reviewed-by: Matt Caswell <matt@openssl.org>
Reviewed-by: Shane Lontis <shane.lontis@oracle.com>
(Merged from https://github.com/openssl/openssl/pull/8877)
-rw-r--r-- | apps/list.c | 4 | ||||
-rw-r--r-- | crypto/cmac/cm_ameth.c | 3 | ||||
-rw-r--r-- | crypto/evp/build.info | 2 | ||||
-rw-r--r-- | crypto/evp/evp_locl.h | 2 | ||||
-rw-r--r-- | crypto/evp/mac_lib.c | 162 | ||||
-rw-r--r-- | crypto/evp/mac_meth.c | 195 | ||||
-rw-r--r-- | crypto/evp/p_lib.c | 32 | ||||
-rw-r--r-- | crypto/evp/pkey_mac.c | 186 | ||||
-rw-r--r-- | crypto/include/internal/evp_int.h | 40 | ||||
-rw-r--r-- | crypto/provider_core.c | 7 | ||||
-rw-r--r-- | doc/internal/man3/ossl_provider_new.pod | 9 | ||||
-rw-r--r-- | doc/man3/EVP_MAC.pod | 309 | ||||
-rw-r--r-- | doc/man7/provider-mac.pod | 255 | ||||
-rw-r--r-- | include/internal/provider.h | 1 | ||||
-rw-r--r-- | include/openssl/core_names.h | 20 | ||||
-rw-r--r-- | include/openssl/core_numbers.h | 36 | ||||
-rw-r--r-- | include/openssl/crypto.h | 4 | ||||
-rw-r--r-- | include/openssl/evp.h | 60 | ||||
-rw-r--r-- | ssl/ssl_init.c | 3 | ||||
-rw-r--r-- | util/libcrypto.num | 30 |
20 files changed, 982 insertions, 378 deletions
diff --git a/apps/list.c b/apps/list.c index c22a2c6267..555ce7e815 100644 --- a/apps/list.c +++ b/apps/list.c @@ -229,6 +229,7 @@ static void list_digests(void) sk_EVP_MD_pop_free(digests, EVP_MD_meth_free); } +#if 0 /* Temporarly disabled */ static void list_mac_fn(const EVP_MAC *m, const char *from, const char *to, void *arg) { @@ -242,6 +243,7 @@ static void list_mac_fn(const EVP_MAC *m, BIO_printf(arg, "%s => %s\n", from, to); } } +#endif static void list_missing_help(void) { @@ -704,8 +706,10 @@ opthelp: list_type(FT_md, one); if (todo.digest_algorithms) list_digests(); +#if 0 /* Temporarly disabled */ if (todo.mac_algorithms) EVP_MAC_do_all_sorted(list_mac_fn, bio_out); +#endif if (todo.cipher_commands) list_type(FT_cipher, one); if (todo.cipher_algorithms) diff --git a/crypto/cmac/cm_ameth.c b/crypto/cmac/cm_ameth.c index ed513b113f..b1ee0d3d2f 100644 --- a/crypto/cmac/cm_ameth.c +++ b/crypto/cmac/cm_ameth.c @@ -25,7 +25,10 @@ static int cmac_size(const EVP_PKEY *pkey) static void cmac_key_free(EVP_PKEY *pkey) { EVP_MAC_CTX *cmctx = EVP_PKEY_get0(pkey); + EVP_MAC *mac = cmctx == NULL ? NULL : EVP_MAC_CTX_mac(cmctx); + EVP_MAC_CTX_free(cmctx); + EVP_MAC_free(mac); } const EVP_PKEY_ASN1_METHOD cmac_asn1_meth = { diff --git a/crypto/evp/build.info b/crypto/evp/build.info index c650c28882..eb675f3f97 100644 --- a/crypto/evp/build.info +++ b/crypto/evp/build.info @@ -16,7 +16,7 @@ SOURCE[../../libcrypto]=$COMMON\ e_old.c pmeth_lib.c pmeth_fn.c pmeth_gn.c m_sigver.c \ e_aes_cbc_hmac_sha1.c e_aes_cbc_hmac_sha256.c e_rc4_hmac_md5.c \ e_chacha20_poly1305.c \ - mac_lib.c c_allm.c pkey_mac.c exchange.c + mac_lib.c mac_meth.c c_allm.c pkey_mac.c exchange.c SOURCE[../../providers/fips]=$COMMON INCLUDE[e_aes.o]=.. ../modes diff --git a/crypto/evp/evp_locl.h b/crypto/evp/evp_locl.h index 59072e368b..3fd73212a4 100644 --- a/crypto/evp/evp_locl.h +++ b/crypto/evp/evp_locl.h @@ -56,7 +56,7 @@ struct evp_cipher_ctx_st { } /* EVP_CIPHER_CTX */ ; struct evp_mac_ctx_st { - const EVP_MAC *meth; /* Method structure */ + EVP_MAC *meth; /* Method structure */ void *data; /* Individual method data */ } /* EVP_MAC_CTX */; diff --git a/crypto/evp/mac_lib.c b/crypto/evp/mac_lib.c index ee4a68f459..7b07b55e3d 100644 --- a/crypto/evp/mac_lib.c +++ b/crypto/evp/mac_lib.c @@ -11,26 +11,24 @@ #include <stdarg.h> #include <openssl/evp.h> #include <openssl/err.h> +#include <openssl/core.h> +#include <openssl/core_names.h> #include <openssl/ossl_typ.h> #include "internal/nelem.h" #include "internal/evp_int.h" +#include "internal/provider.h" #include "evp_locl.h" -EVP_MAC_CTX *EVP_MAC_CTX_new_id(int id) -{ - const EVP_MAC *mac = EVP_get_macbynid(id); - - if (mac == NULL) - return NULL; - return EVP_MAC_CTX_new(mac); -} - -EVP_MAC_CTX *EVP_MAC_CTX_new(const EVP_MAC *mac) +EVP_MAC_CTX *EVP_MAC_CTX_new(EVP_MAC *mac) { EVP_MAC_CTX *ctx = OPENSSL_zalloc(sizeof(EVP_MAC_CTX)); - if (ctx == NULL || (ctx->data = mac->new()) == NULL) { + if (ctx == NULL + || (ctx->data = mac->newctx(ossl_provider_ctx(mac->prov))) == NULL + || !EVP_MAC_up_ref(mac)) { EVPerr(EVP_F_EVP_MAC_CTX_NEW, ERR_R_MALLOC_FAILURE); + if (ctx != NULL) + mac->freectx(ctx->data); OPENSSL_free(ctx); ctx = NULL; } else { @@ -41,9 +39,11 @@ EVP_MAC_CTX *EVP_MAC_CTX_new(const EVP_MAC *mac) void EVP_MAC_CTX_free(EVP_MAC_CTX *ctx) { - if (ctx != NULL && ctx->data != NULL) { - ctx->meth->free(ctx->data); + if (ctx != NULL) { + ctx->meth->freectx(ctx->data); ctx->data = NULL; + /* refcnt-- */ + EVP_MAC_free(ctx->meth); } OPENSSL_free(ctx); } @@ -62,8 +62,13 @@ EVP_MAC_CTX *EVP_MAC_CTX_dup(const EVP_MAC_CTX *src) } *dst = *src; + if (!EVP_MAC_up_ref(dst->meth)) { + EVPerr(EVP_F_EVP_MAC_CTX_DUP, ERR_R_MALLOC_FAILURE); + OPENSSL_free(dst); + return NULL; + } - dst->data = src->meth->dup(src->data); + dst->data = src->meth->dupctx(src->data); if (dst->data == NULL) { EVP_MAC_CTX_free(dst); return NULL; @@ -72,16 +77,31 @@ EVP_MAC_CTX *EVP_MAC_CTX_dup(const EVP_MAC_CTX *src) return dst; } -const EVP_MAC *EVP_MAC_CTX_mac(EVP_MAC_CTX *ctx) +EVP_MAC *EVP_MAC_CTX_mac(EVP_MAC_CTX *ctx) { return ctx->meth; } size_t EVP_MAC_size(EVP_MAC_CTX *ctx) { - if (ctx->data != NULL) - return ctx->meth->size(ctx->data); - /* If the MAC hasn't been initialized yet, we return zero */ + size_t sz = 0; + + if (ctx->data != NULL) { + OSSL_PARAM params[2] = { OSSL_PARAM_END, OSSL_PARAM_END }; + + params[0] = OSSL_PARAM_construct_size_t(OSSL_MAC_PARAM_OUTLEN, &sz); + if (ctx->meth->ctx_get_params != NULL) { + if (ctx->meth->ctx_get_params(ctx->data, params)) + return sz; + } else if (ctx->meth->get_params != NULL) { + if (ctx->meth->get_params(params)) + return sz; + } + } + /* + * If the MAC hasn't been initialized yet, or there is no size to get, + * we return zero + */ return 0; } @@ -97,101 +117,43 @@ int EVP_MAC_update(EVP_MAC_CTX *ctx, const unsigned char *data, size_t datalen) return ctx->meth->update(ctx->data, data, datalen); } -int EVP_MAC_final(EVP_MAC_CTX *ctx, unsigned char *out, size_t *poutlen) +int EVP_MAC_final(EVP_MAC_CTX *ctx, + unsigned char *out, size_t *outl, size_t outsize) { - int l = ctx->meth->size(ctx->data); + int l = EVP_MAC_size(ctx); if (l < 0) return 0; - if (poutlen != NULL) - *poutlen = l; + if (outl != NULL) + *outl = l; if (out == NULL) return 1; - return ctx->meth->final(ctx->data, out); -} - -int EVP_MAC_ctrl(EVP_MAC_CTX *ctx, int cmd, ...) -{ - int ok = -1; - va_list args; - - va_start(args, cmd); - ok = EVP_MAC_vctrl(ctx, cmd, args); - va_end(args); - - if (ok == -2) - EVPerr(EVP_F_EVP_MAC_CTRL, EVP_R_COMMAND_NOT_SUPPORTED); - - return ok; -} - -int EVP_MAC_vctrl(EVP_MAC_CTX *ctx, int cmd, va_list args) -{ - int ok = 1; - - if (ctx == NULL || ctx->meth == NULL) - return -2; - - switch (cmd) { -#if 0 - case ...: - /* code */ - ok = 1; - break; -#endif - default: - if (ctx->meth->ctrl != NULL) - ok = ctx->meth->ctrl(ctx->data, cmd, args); - else - ok = -2; - break; - } - - return ok; -} - -int EVP_MAC_ctrl_str(EVP_MAC_CTX *ctx, const char *type, const char *value) -{ - int ok = 1; - - if (ctx == NULL || ctx->meth == NULL || ctx->meth->ctrl_str == NULL) { - EVPerr(EVP_F_EVP_MAC_CTRL_STR, EVP_R_COMMAND_NOT_SUPPORTED); - return -2; - } - - ok = ctx->meth->ctrl_str(ctx->data, type, value); - - if (ok == -2) - EVPerr(EVP_F_EVP_MAC_CTRL_STR, EVP_R_COMMAND_NOT_SUPPORTED); - return ok; + return ctx->meth->final(ctx->data, out, outl, outsize); } -int EVP_MAC_str2ctrl(EVP_MAC_CTX *ctx, int cmd, const char *value) +/* + * The {get,set}_params functions return 1 if there is no corresponding + * function in the implementation. This is the same as if there was one, + * but it didn't recognise any of the given params, i.e. nothing in the + * bag of parameters was useful. + */ +int EVP_MAC_get_params(EVP_MAC *mac, OSSL_PARAM params[]) { - size_t len; - - len = strlen(value); - if (len > INT_MAX) - return -1; - return EVP_MAC_ctrl(ctx, cmd, value, len); + if (mac->get_params != NULL) + return mac->get_params(params); + return 1; } -int EVP_MAC_hex2ctrl(EVP_MAC_CTX *ctx, int cmd, const char *hex) +int EVP_MAC_CTX_get_params(EVP_MAC_CTX *ctx, OSSL_PARAM params[]) { - unsigned char *bin; - long binlen; - int rv = -1; - - bin = OPENSSL_hexstr2buf(hex, &binlen); - if (bin == NULL) - return 0; - if (binlen <= INT_MAX) - rv = EVP_MAC_ctrl(ctx, cmd, bin, (size_t)binlen); - OPENSSL_free(bin); - return rv; + if (ctx->meth->ctx_get_params != NULL) + return ctx->meth->ctx_get_params(ctx->data, params); + return 1; } -int EVP_MAC_nid(const EVP_MAC *mac) +int EVP_MAC_CTX_set_params(EVP_MAC_CTX *ctx, const OSSL_PARAM params[]) { - return mac->type; + if (ctx->meth->ctx_set_params != NULL) + return ctx->meth->ctx_set_params(ctx->data, params); + return 1; } diff --git a/crypto/evp/mac_meth.c b/crypto/evp/mac_meth.c new file mode 100644 index 0000000000..983b2dbd2e --- /dev/null +++ b/crypto/evp/mac_meth.c @@ -0,0 +1,195 @@ +#include <openssl/evp.h> +#include <openssl/err.h> +#include <openssl/core.h> +#include <openssl/core_numbers.h> +#include "internal/evp_int.h" +#include "internal/provider.h" +#include "evp_locl.h" + +static int evp_mac_up_ref(void *vmac) +{ + EVP_MAC *mac = vmac; + int ref = 0; + + CRYPTO_UP_REF(&mac->refcnt, &ref, mac->lock); + return 1; +} + +static void evp_mac_free(void *vmac) +{ + EVP_MAC *mac = vmac; + int ref = 0; + + if (mac == NULL) + return; + + CRYPTO_DOWN_REF(&mac->refcnt, &ref, mac->lock); + if (ref > 0) + return; + ossl_provider_free(mac->prov); + OPENSSL_free(mac->name); + CRYPTO_THREAD_lock_free(mac->lock); + OPENSSL_free(mac); +} + +static void *evp_mac_new(void) +{ + EVP_MAC *mac = NULL; + + if ((mac = OPENSSL_zalloc(sizeof(*mac))) == NULL + || (mac->lock = CRYPTO_THREAD_lock_new()) == NULL) { + evp_mac_free(mac); + return NULL; + } + + mac->refcnt = 1; + + return mac; +} + +static void *evp_mac_from_dispatch(const char *name, const OSSL_DISPATCH *fns, + OSSL_PROVIDER *prov) +{ + EVP_MAC *mac = NULL; + int fnmaccnt = 0, fnctxcnt = 0; + + if ((mac = evp_mac_new()) == NULL + || (mac->name = OPENSSL_strdup(name)) == NULL) { + EVP_MAC_free(mac); + EVPerr(0, ERR_R_MALLOC_FAILURE); + return NULL; + } + + for (; fns->function_id != 0; fns++) { + switch (fns->function_id) { + case OSSL_FUNC_MAC_NEWCTX: + if (mac->newctx != NULL) + break; + mac->newctx = OSSL_get_OP_mac_newctx(fns); + fnctxcnt++; + break; + case OSSL_FUNC_MAC_DUPCTX: + if (mac->dupctx != NULL) + break; + mac->dupctx = OSSL_get_OP_mac_dupctx(fns); + break; + case OSSL_FUNC_MAC_FREECTX: + if (mac->freectx != NULL) + break; + mac->freectx = OSSL_get_OP_mac_freectx(fns); + fnctxcnt++; + break; + case OSSL_FUNC_MAC_INIT: + if (mac->init != NULL) + break; + mac->init = OSSL_get_OP_mac_init(fns); + fnmaccnt++; + break; + case OSSL_FUNC_MAC_UPDATE: + if (mac->update != NULL) + break; + mac->update = OSSL_get_OP_mac_update(fns); + fnmaccnt++; + break; + case OSSL_FUNC_MAC_FINAL: + if (mac->final != NULL) + break; + mac->final = OSSL_get_OP_mac_final(fns); + fnmaccnt++; + break; + case OSSL_FUNC_MAC_GETTABLE_PARAMS: + if (mac->gettable_params != NULL) + break; + mac->gettable_params = + OSSL_get_OP_mac_gettable_params(fns); + break; + case OSSL_FUNC_MAC_GETTABLE_CTX_PARAMS: + if (mac->gettable_ctx_params != NULL) + break; + mac->gettable_ctx_params = + OSSL_get_OP_mac_gettable_ctx_params(fns); + break; + case OSSL_FUNC_MAC_SETTABLE_CTX_PARAMS: + if (mac->settable_ctx_params != NULL) + break; + mac->settable_ctx_params = + OSSL_get_OP_mac_settable_ctx_params(fns); + break; + case OSSL_FUNC_MAC_GET_PARAMS: + if (mac->get_params != NULL) + break; + mac->get_params = OSSL_get_OP_mac_get_params(fns); + break; + case OSSL_FUNC_MAC_CTX_GET_PARAMS: + if (mac->ctx_get_params != NULL) + break; + mac->ctx_get_params = OSSL_get_OP_mac_ctx_get_params(fns); + break; + case OSSL_FUNC_MAC_CTX_SET_PARAMS: + if (mac->ctx_set_params != NULL) + break; + mac->ctx_set_params = OSSL_get_OP_mac_ctx_set_params(fns); + break; + } + } + if (fnmaccnt != 3 + || fnctxcnt != 2) { + /* + * In order to be a consistent set of functions we must have at least + * a complete set of "mac" functions, and a complete set of context + * management functions, as well as the size function. + */ + evp_mac_free(mac); + ERR_raise(ERR_LIB_EVP, EVP_R_INVALID_PROVIDER_FUNCTIONS); + return NULL; + } + mac->prov = prov; + if (prov != NULL) + ossl_provider_up_ref(prov); + + return mac; +} + +EVP_MAC *EVP_MAC_fetch(OPENSSL_CTX *libctx, const char *algorithm, + const char *properties) +{ + return evp_generic_fetch(libctx, OSSL_OP_MAC, algorithm, properties, + evp_mac_from_dispatch, evp_mac_up_ref, + evp_mac_free); +} + +int EVP_MAC_up_ref(EVP_MAC *mac) +{ + return evp_mac_up_ref(mac); +} + +void EVP_MAC_free(EVP_MAC *mac) +{ + evp_mac_free(mac); +} + +const char *EVP_MAC_name(const EVP_MAC *mac) +{ + return mac->name; +} + +const OSSL_PARAM *EVP_MAC_gettable_params(const EVP_MAC *mac) +{ + if (mac->gettable_params == NULL) + return NULL; + return mac->gettable_params(); +} + +const OSSL_PARAM *EVP_MAC_CTX_gettable_params(const EVP_MAC *mac) +{ + if (mac->gettable_ctx_params == NULL) + return NULL; + return mac->gettable_ctx_params(); +} + +const OSSL_PARAM *EVP_MAC_CTX_settable_params(const EVP_MAC *mac) +{ + if (mac->settable_ctx_params == NULL) + return NULL; + return mac->settable_ctx_params(); +} diff --git a/crypto/evp/p_lib.c b/crypto/evp/p_lib.c index 653693e1dc..90e13f4854 100644 --- a/crypto/evp/p_lib.c +++ b/crypto/evp/p_lib.c @@ -20,9 +20,12 @@ #include <openssl/dh.h> #include <openssl/cmac.h> #include <openssl/engine.h> +#include <openssl/params.h> +#include <openssl/core_names.h> #include "internal/asn1_int.h" #include "internal/evp_int.h" +#include "internal/provider.h" static void EVP_PKEY_free_it(EVP_PKEY *x); @@ -318,8 +321,16 @@ EVP_PKEY *EVP_PKEY_new_CMAC_key(ENGINE *e, const unsigned char *priv, size_t len, const EVP_CIPHER *cipher) { #ifndef OPENSSL_NO_CMAC + const char *engine_name = e != NULL ? ENGINE_get_name(e) : NULL; + const char *cipher_name = EVP_CIPHER_name(cipher); + const OSSL_PROVIDER *prov = EVP_CIPHER_provider(cipher); + OPENSSL_CTX *libctx = + prov == NULL ? NULL : ossl_provider_library_context(prov); EVP_PKEY *ret = EVP_PKEY_new(); - EVP_MAC_CTX *cmctx = EVP_MAC_CTX_new_id(EVP_MAC_CMAC); + EVP_MAC *cmac = EVP_MAC_fetch(libctx, "CMAC", NULL); + EVP_MAC_CTX *cmctx = cmac != NULL ? EVP_MAC_CTX_new(cmac) : NULL; + OSSL_PARAM params[4]; + size_t paramsn = 0; if (ret == NULL || cmctx == NULL @@ -328,9 +339,21 @@ EVP_PKEY *EVP_PKEY_new_CMAC_key(ENGINE *e, const unsigned char *priv, goto err; } - if (EVP_MAC_ctrl(cmctx, EVP_MAC_CTRL_SET_ENGINE, e) <= 0 - || EVP_MAC_ctrl(cmctx, EVP_MAC_CTRL_SET_CIPHER, cipher) <= 0 - || EVP_MAC_ctrl(cmctx, EVP_MAC_CTRL_SET_KEY, priv, len) <= 0) { + if (engine_name != NULL) + params[paramsn++] = + OSSL_PARAM_construct_utf8_string(OSSL_MAC_PARAM_ENGINE, + (char *)engine_name, + strlen(engine_name) + 1); + params[paramsn++] = + OSSL_PARAM_construct_utf8_string(OSSL_MAC_PARAM_ALGORITHM, + (char *)cipher_name, + strlen(cipher_name) + 1); + params[paramsn++] = + OSSL_PARAM_construct_octet_string(OSSL_MAC_PARAM_KEY, + (char *)priv, len); + params[paramsn] = OSSL_PARAM_construct_end(); + + if (!EVP_MAC_CTX_set_params(cmctx, params)) { EVPerr(EVP_F_EVP_PKEY_NEW_CMAC_KEY, EVP_R_KEY_SETUP_FAILED); goto err; } @@ -341,6 +364,7 @@ EVP_PKEY *EVP_PKEY_new_CMAC_key(ENGINE *e, const unsigned char *priv, err: EVP_PKEY_free(ret); EVP_MAC_CTX_free(cmctx); + EVP_MAC_free(cmac); return NULL; #else EVPerr(EVP_F_EVP_PKEY_NEW_CMAC_KEY, diff --git a/crypto/evp/pkey_mac.c b/crypto/evp/pkey_mac.c index fafe3c96f2..07421183ea 100644 --- a/crypto/evp/pkey_mac.c +++ b/crypto/evp/pkey_mac.c @@ -7,8 +7,12 @@ * https://www.openssl.org/source/license.html */ +#include <string.h> #include <openssl/err.h> #include <openssl/evp.h> +#include <openssl/engine.h> +#include <openssl/params.h> +#include <openssl/core_names.h> #include "internal/evp_int.h" #include "evp_locl.h" @@ -40,18 +44,21 @@ typedef struct { } raw_data; } MAC_PKEY_CTX; +static void pkey_mac_cleanup(EVP_PKEY_CTX *ctx); + static int pkey_mac_init(EVP_PKEY_CTX *ctx) { MAC_PKEY_CTX *hctx; + /* We're being smart and using the same base NIDs for PKEY and for MAC */ int nid = ctx->pmeth->pkey_id; + EVP_MAC *mac = EVP_MAC_fetch(NULL, OBJ_nid2sn(nid), NULL); if ((hctx = OPENSSL_zalloc(sizeof(*hctx))) == NULL) { EVPerr(EVP_F_PKEY_MAC_INIT, ERR_R_MALLOC_FAILURE); return 0; } - /* We're being smart and using the same base NIDs for PKEY and for MAC */ - hctx->ctx = EVP_MAC_CTX_new_id(nid); + hctx->ctx = EVP_MAC_CTX_new(mac); if (hctx->ctx == NULL) { OPENSSL_free(hctx); return 0; @@ -64,14 +71,13 @@ static int pkey_mac_init(EVP_PKEY_CTX *ctx) hctx->raw_data.ktmp.type = V_ASN1_OCTET_STRING; } + pkey_mac_cleanup(ctx); EVP_PKEY_CTX_set_data(ctx, hctx); ctx->keygen_info_count = 0; return 1; } -static void pkey_mac_cleanup(EVP_PKEY_CTX *ctx); - static int pkey_mac_copy(EVP_PKEY_CTX *dst, const EVP_PKEY_CTX *src) { MAC_PKEY_CTX *sctx, *dctx; @@ -93,6 +99,17 @@ static int pkey_mac_copy(EVP_PKEY_CTX *dst, const EVP_PKEY_CTX *src) if (dctx->ctx == NULL) goto err; + /* + * Normally, nothing special would be done with the MAC method. In + * this particular case, though, the MAC method was fetched internally + * by pkey_mac_init() above or by EVP_PKEY_new_CMAC_key() and passed + * via the EVP_MAC_CTX, so it is effectively like every new EVP_MAC_CTX + * fetches the MAC method anew in this case. Therefore, its reference + * count must be adjusted here. + */ + if (!EVP_MAC_up_ref(EVP_MAC_CTX_mac(dctx->ctx))) + goto err; + dctx->type = sctx->type; switch (dctx->type) { @@ -117,9 +134,16 @@ static int pkey_mac_copy(EVP_PKEY_CTX *dst, const EVP_PKEY_CTX *src) static void pkey_mac_cleanup(EVP_PKEY_CTX *ctx) { - MAC_PKEY_CTX *hctx = EVP_PKEY_CTX_get_data(ctx); + /* + * For the exact same reasons the MAC reference count is incremented + * in pkey_mac_copy() above, it must be explicitly freed here. + */ + + MAC_PKEY_CTX *hctx = ctx == NULL ? NULL : EVP_PKEY_CTX_get_data(ctx); if (hctx != NULL) { + EVP_MAC *mac = EVP_MAC_CTX_mac(hctx->ctx); + switch (hctx->type) { case MAC_TYPE_RAW: OPENSSL_clear_free(hctx->raw_data.ktmp.data, @@ -127,6 +151,7 @@ static void pkey_mac_cleanup(EVP_PKEY_CTX *ctx) break; } EVP_MAC_CTX_free(hctx->ctx); + EVP_MAC_free(mac); OPENSSL_free(hctx); EVP_PKEY_CTX_set_data(ctx, NULL); } @@ -156,6 +181,8 @@ static int pkey_mac_keygen(EVP_PKEY_CTX *ctx, EVP_PKEY *pkey) if (cmkey == NULL) return 0; + if (!EVP_MAC_up_ref(EVP_MAC_CTX_mac(hctx->ctx))) + return 0; EVP_PKEY_assign(pkey, nid, cmkey); } break; @@ -194,25 +221,34 @@ static int pkey_mac_signctx_init(EVP_PKEY_CTX *ctx, EVP_MD_CTX *mctx) && (ctx->pmeth->flags & EVP_PKEY_FLAG_SIGCTX_CUSTOM) != 0; if (set_key) { - if (EVP_PKEY_id(EVP_PKEY_CTX_get0_pkey(ctx)) - != EVP_MAC_nid(EVP_MAC_CTX_mac(hctx->ctx))) + if (strcmp(OBJ_nid2sn(EVP_PKEY_id(EVP_PKEY_CTX_get0_pkey(ctx))), + EVP_MAC_name(EVP_MAC_CTX_mac(hctx->ctx))) != 0) return 0; key = EVP_PKEY_get0(EVP_PKEY_CTX_get0_pkey(ctx)); if (key == NULL) return 0; } - /* Some MACs don't support this control... that's fine */ - EVP_MAC_ctrl(hctx->ctx, EVP_MAC_CTRL_SET_FLAGS, - EVP_MD_CTX_test_flags(mctx, ~EVP_MD_CTX_FLAG_NO_INIT)); - EVP_MD_CTX_set_flags(mctx, EVP_MD_CTX_FLAG_NO_INIT); EVP_MD_CTX_set_update_fn(mctx, int_update); - if (set_key) - rv = EVP_MAC_ctrl(hctx->ctx, EVP_MAC_CTRL_SET_KEY, key->data, - key->length); - return rv > 0; + /* Some MACs don't support this control... that's fine */ + { + OSSL_PARAM params[3]; + size_t params_n = 0; + int flags = EVP_MD_CTX_test_flags(mctx, ~EVP_MD_CTX_FLAG_NO_INIT); + + /* TODO(3.0) "flags" isn't quite right, i.e. a quick hack for now */ + params[params_n++] = + OSSL_PARAM_construct_int(OSSL_MAC_PARAM_FLAGS, &flags); + if (set_key) + params[params_n++] = + OSSL_PARAM_construct_octet_string(OSSL_MAC_PARAM_KEY, + key->data, key->length); + params[params_n++] = OSSL_PARAM_construct_end(); + rv = EVP_MAC_CTX_set_params(hctx->ctx, params); + } + return rv; } static int pkey_mac_signctx(EVP_PKEY_CTX *ctx, unsigned char *sig, @@ -220,7 +256,7 @@ static int pkey_mac_signctx(EVP_PKEY_CTX *ctx, unsigned char *sig, { MAC_PKEY_CTX *hctx = EVP_PKEY_CTX_get_data(ctx); - return EVP_MAC_final(hctx->ctx, sig, siglen); + return EVP_MAC_final(hctx->ctx, sig, siglen, EVP_MAC_size(hctx->ctx)); } static int pkey_mac_ctrl(EVP_PKEY_CTX *ctx, int type, int p1, void *p2) @@ -235,14 +271,24 @@ static int pkey_mac_ctrl(EVP_PKEY_CTX *ctx, int type, int p1, void *p2) return -2; /* The raw types don't support ciphers */ case MAC_TYPE_MAC: { - int rv; - - if ((rv = EVP_MAC_ctrl(hctx->ctx, EVP_MAC_CTRL_SET_ENGINE, - ctx->engine)) <= 0 - || (rv = EVP_MAC_ctrl(hctx->ctx, EVP_MAC_CTRL_SET_CIPHER, - p2)) <= 0 - || !(rv = EVP_MAC_init(hctx->ctx))) - return rv; + OSSL_PARAM params[3]; + size_t params_n = 0; + char *ciphname = (char *)OBJ_nid2sn(EVP_CIPHER_nid(p2)); + char *engineid = (char *)ENGINE_get_id(ctx->engine); + + params[params_n++] = + OSSL_PARAM_construct_utf8_string(OSSL_MAC_PARAM_ENGINE, + engineid, + strlen(engineid) + 1); + params[params_n++] = + OSSL_PARAM_construct_utf8_string(OSSL_MAC_PARAM_ALGORITHM, + ciphname, + strlen(ciphname) + 1); + params[params_n] = OSSL_PARAM_construct_end(); + + if (!EVP_MAC_CTX_set_params(hctx->ctx, params) + || !EVP_MAC_init(hctx->ctx)) + return 0; } break; default: @@ -276,8 +322,40 @@ static int pkey_mac_ctrl(EVP_PKEY_CTX *ctx, int type, int p1, void *p2) break; case EVP_PKEY_CTRL_SET_DIGEST_SIZE: - return EVP_MAC_ctrl(hctx->ctx, EVP_MAC_CTRL_SET_SIZE, (size_t)p1); + { + OSSL_PARAM params[2] = { OSSL_PARAM_END, OSSL_PARAM_END }; + size_t size = (size_t)p1; + size_t verify = 0; + + /* + * We verify that the length is actually set by getting back + * the same parameter and checking that it matches what we + * tried to set. + * TODO(3.0) when we have a more direct mechanism to check if + * a parameter was used, we must refactor this to use that. + */ + + params[0] = + OSSL_PARAM_construct_size_t(OSSL_MAC_PARAM_OUTLEN, &size); + + if (!EVP_MAC_CTX_set_params(hctx->ctx, params)) + return 0; + params[0] = + OSSL_PARAM_construct_size_t(OSSL_MAC_PARAM_OUTLEN, &verify); + + if (!EVP_MAC_CTX_get_params(hctx->ctx, params)) + return 0; + + /* + * Since EVP_MAC_CTX_{get,set}_params() returned successfully, + * we can only assume that the size was ignored, i.e. this + * control is unsupported. + */ + if (verify != size) + return -2; + } + break; case EVP_PKEY_CTRL_SET_MAC_KEY: switch (hctx->type) { case MAC_TYPE_RAW: @@ -287,8 +365,17 @@ static int pkey_mac_ctrl(EVP_PKEY_CTX *ctx, int type, int p1, void *p2) return 0; break; case MAC_TYPE_MAC: - if (EVP_MAC_ctrl(hctx->ctx, EVP_MAC_CTRL_SET_KEY, p2, p1) <= 0) - return 0; + { + OSSL_PARAM params[2]; + size_t params_n = 0; + + params[params_n++] = + OSSL_PARAM_construct_octet_string(OSSL_MAC_PARAM_KEY, + p2, p1); + params[params_n] = OSSL_PARAM_construct_end(); + + return EVP_MAC_CTX_set_params(hctx->ctx, params); + } break; default: /* This should be dead code */ @@ -303,17 +390,32 @@ static int pkey_mac_ctrl(EVP_PKEY_CTX *ctx, int type, int p1, void *p2) if (!EVP_MAC_init(hctx->ctx)) return 0; { - int rv; ASN1_OCTET_STRING *key = (ASN1_OCTET_STRING *)ctx->pkey->pkey.ptr; - - if ((rv = EVP_MAC_ctrl(hctx->ctx, EVP_MAC_CTRL_SET_ENGINE, - ctx->engine)) <= 0 - || (rv = EVP_MAC_ctrl(hctx->ctx, EVP_MAC_CTRL_SET_MD, - hctx->raw_data.md)) <= 0 - || (rv = EVP_MAC_ctrl(hctx->ctx, EVP_MAC_CTRL_SET_KEY, - key->data, key->length)) <= 0) - return rv; + OSSL_PARAM params[4]; + size_t params_n = 0; + char *mdname = |