X-Git-Url: https://git.openssl.org/?p=openssl.git;a=blobdiff_plain;f=crypto%2Fevp%2Fpkey_mac.c;h=56231e3938fdcaa4e5c6a0bf26bae9cbaf961877;hp=ecf70bb6c156049ec53af31fed0ea015bbfc0f73;hb=4dcff55c75f911ea190b57b94d9540f80a961a4f;hpb=e74a435f58441c6f1f6b4558c762e17d0ab67b7f diff --git a/crypto/evp/pkey_mac.c b/crypto/evp/pkey_mac.c index ecf70bb6c1..56231e3938 100644 --- a/crypto/evp/pkey_mac.c +++ b/crypto/evp/pkey_mac.c @@ -1,15 +1,20 @@ /* - * Copyright 2018 The OpenSSL Project Authors. All Rights Reserved. + * Copyright 2018-2020 The OpenSSL Project Authors. All Rights Reserved. * - * Licensed under the OpenSSL license (the "License"). You may not use + * 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 */ +#include #include #include -#include "internal/evp_int.h" +#include +#include +#include +#include "crypto/evp.h" +#include "evp_local.h" /* MAC PKEY context structure */ @@ -39,21 +44,38 @@ 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; + + ERR_set_mark(); + mac = EVP_MAC_fetch(ctx->libctx, OBJ_nid2sn(nid), ctx->propquery); + ERR_pop_to_mark(); + + /* + * mac == NULL may actually be ok in some situations. In an + * EVP_PKEY_new_mac_key() call a temporary EVP_PKEY_CTX is created with + * default libctx. We don't actually need the underlying MAC to be present + * to successfully set the key in that case. The resulting EVP_PKEY could + * then be used in some other libctx where the MAC *is* present + */ 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); - if (hctx->ctx == NULL) { - OPENSSL_free(hctx); - return 0; + if (mac != NULL) { + hctx->ctx = EVP_MAC_CTX_new(mac); + if (hctx->ctx == NULL) { + OPENSSL_free(hctx); + return 0; + } } if (nid == EVP_PKEY_CMAC) { @@ -63,27 +85,54 @@ 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, EVP_PKEY_CTX *src) +static int pkey_mac_copy(EVP_PKEY_CTX *dst, const EVP_PKEY_CTX *src) { MAC_PKEY_CTX *sctx, *dctx; - if (!pkey_mac_init(dst)) + sctx = EVP_PKEY_CTX_get_data(src); + + if (sctx->ctx == NULL) { + /* This actually means the fetch failed during the init call */ + EVPerr(0, EVP_R_FETCH_FAILED); + return 0; + } + + if (sctx->ctx->data == NULL) return 0; - sctx = EVP_PKEY_CTX_get_data(src); - dctx = EVP_PKEY_CTX_get_data(dst); + dctx = OPENSSL_zalloc(sizeof(*dctx)); + if (dctx == NULL) { + EVPerr(EVP_F_PKEY_MAC_COPY, ERR_R_MALLOC_FAILURE); + return 0; + } + + EVP_PKEY_CTX_set_data(dst, dctx); + dst->keygen_info_count = 0; - if (!EVP_MAC_CTX_copy(dctx->ctx, sctx->ctx)) + dctx->ctx = EVP_MAC_CTX_dup(sctx->ctx); + 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) { case MAC_TYPE_RAW: dctx->raw_data.md = sctx->raw_data.md; @@ -100,15 +149,22 @@ static int pkey_mac_copy(EVP_PKEY_CTX *dst, EVP_PKEY_CTX *src) } return 1; err: - pkey_mac_cleanup (dst); + pkey_mac_cleanup(dst); return 0; } 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 = hctx->ctx != NULL ? EVP_MAC_CTX_mac(hctx->ctx) : NULL; + switch (hctx->type) { case MAC_TYPE_RAW: OPENSSL_clear_free(hctx->raw_data.ktmp.data, @@ -116,6 +172,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); } @@ -141,14 +198,19 @@ static int pkey_mac_keygen(EVP_PKEY_CTX *ctx, EVP_PKEY *pkey) break; case MAC_TYPE_MAC: { - EVP_MAC_CTX *cmkey = EVP_MAC_CTX_new_id(nid); + EVP_MAC_CTX *cmkey; + if (hctx->ctx == NULL) { + /* This actually means the fetch failed during the init call */ + EVPerr(0, EVP_R_FETCH_FAILED); + return 0; + } + + cmkey = EVP_MAC_CTX_dup(hctx->ctx); if (cmkey == NULL) return 0; - if (!EVP_MAC_CTX_copy(cmkey, hctx->ctx)) { - EVP_MAC_CTX_free(cmkey); + if (!EVP_MAC_up_ref(EVP_MAC_CTX_mac(hctx->ctx))) return 0; - } EVP_PKEY_assign(pkey, nid, cmkey); } break; @@ -186,26 +248,41 @@ static int pkey_mac_signctx_init(EVP_PKEY_CTX *ctx, EVP_MD_CTX *mctx) hctx->type == MAC_TYPE_RAW && (ctx->pmeth->flags & EVP_PKEY_FLAG_SIGCTX_CUSTOM) != 0; + if (hctx->ctx == NULL) { + /* This actually means the fetch failed during the init call */ + EVPerr(0, EVP_R_FETCH_FAILED); + return 0; + } + if (set_key) { - if (EVP_PKEY_id(EVP_PKEY_CTX_get0_pkey(ctx)) - != EVP_MAC_nid(EVP_MAC_CTX_mac(hctx->ctx))) + if (!EVP_MAC_is_a(EVP_MAC_CTX_mac(hctx->ctx), + OBJ_nid2sn(EVP_PKEY_id(EVP_PKEY_CTX_get0_pkey(ctx))))) 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, @@ -213,7 +290,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) @@ -228,14 +305,31 @@ 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)); +#ifndef OPENSSL_NO_ENGINE + char *engineid = (char *)ENGINE_get_id(ctx->engine); + + params[params_n++] = + OSSL_PARAM_construct_utf8_string("engine", engineid, 0); +#endif + params[params_n++] = + OSSL_PARAM_construct_utf8_string(OSSL_MAC_PARAM_CIPHER, + ciphname, 0); + params[params_n] = OSSL_PARAM_construct_end(); + + if (hctx->ctx == NULL) { + /* + * This actually means the fetch failed during the init call + */ + EVPerr(0, EVP_R_FETCH_FAILED); + return 0; + } + + if (!EVP_MAC_CTX_set_params(hctx->ctx, params) + || !EVP_MAC_init(hctx->ctx)) + return 0; } break; default: @@ -249,13 +343,17 @@ static int pkey_mac_ctrl(EVP_PKEY_CTX *ctx, int type, int p1, void *p2) case MAC_TYPE_RAW: hctx->raw_data.md = p2; break; - case MAC_TYPE_MAC: - if (ctx->pkey != NULL - && !EVP_MAC_CTX_copy(hctx->ctx, - (EVP_MAC_CTX *)ctx->pkey->pkey.ptr)) - return 0; - if (!EVP_MAC_init(hctx->ctx)) - return 0; + case MAC_TYPE_MAC: { + EVP_MAC_CTX *new_mac_ctx; + + if (ctx->pkey == NULL) + return 0; + new_mac_ctx = EVP_MAC_CTX_dup(ctx->pkey->pkey.ptr); + if (new_mac_ctx == NULL) + return 0; + EVP_MAC_CTX_free(hctx->ctx); + hctx->ctx = new_mac_ctx; + } break; default: /* This should be dead code */ @@ -264,8 +362,48 @@ 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_SIZE, &size); + + if (hctx->ctx == NULL) { + /* + * This actually means the fetch failed during the init call + */ + EVPerr(0, EVP_R_FETCH_FAILED); + return 0; + } + + if (!EVP_MAC_CTX_set_params(hctx->ctx, params)) + return 0; + + params[0] = + OSSL_PARAM_construct_size_t(OSSL_MAC_PARAM_SIZE, &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: @@ -275,8 +413,25 @@ 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)) - 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(); + + if (hctx->ctx == NULL) { + /* + * This actually means the fetch failed during the init call + */ + EVPerr(0, EVP_R_FETCH_FAILED); + return 0; + } + + return EVP_MAC_CTX_set_params(hctx->ctx, params); + } break; default: /* This should be dead code */ @@ -287,21 +442,39 @@ static int pkey_mac_ctrl(EVP_PKEY_CTX *ctx, int type, int p1, void *p2) case EVP_PKEY_CTRL_DIGESTINIT: switch (hctx->type) { case MAC_TYPE_RAW: + if (hctx->ctx == NULL) { + /* This actually means the fetch failed during the init call */ + EVPerr(0, EVP_R_FETCH_FAILED); + return 0; + } + /* Ensure that we have attached the implementation */ 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 = + (char *)OBJ_nid2sn(EVP_MD_nid(hctx->raw_data.md)); +#ifndef OPENSSL_NO_ENGINE + char *engineid = ctx->engine == NULL + ? NULL : (char *)ENGINE_get_id(ctx->engine); + + if (engineid != NULL) + params[params_n++] = + OSSL_PARAM_construct_utf8_string("engine", engineid, 0); +#endif + params[params_n++] = + OSSL_PARAM_construct_utf8_string(OSSL_MAC_PARAM_DIGEST, + mdname, 0); + params[params_n++] = + OSSL_PARAM_construct_octet_string(OSSL_MAC_PARAM_KEY, + key->data, key->length); + params[params_n] = OSSL_PARAM_construct_end(); + + return EVP_MAC_CTX_set_params(hctx->ctx, params); } break; case MAC_TYPE_MAC: @@ -320,14 +493,50 @@ static int pkey_mac_ctrl(EVP_PKEY_CTX *ctx, int type, int p1, void *p2) } static int pkey_mac_ctrl_str(EVP_PKEY_CTX *ctx, - const char *type, const char *value) + const char *type, const char *value) { MAC_PKEY_CTX *hctx = EVP_PKEY_CTX_get_data(ctx); + const EVP_MAC *mac; + OSSL_PARAM params[2]; + int ok = 0; + + if (hctx == NULL) { + EVPerr(0, EVP_R_NULL_MAC_PKEY_CTX); + return 0; + } + if (hctx->ctx == NULL) { + /* This actually means the fetch failed during the init call */ + EVPerr(0, EVP_R_FETCH_FAILED); + return 0; + } + mac = EVP_MAC_CTX_mac(hctx->ctx); + + /* + * Translation of some control names that are equivalent to a single + * parameter name. + * + * "md" and "digest" are the same thing, we use the single "digest" + * + * "digestsize" was a setting control in siphash, but naming wise, + * it's really the same as "size". + */ + if (strcmp(type, "md") == 0) + type = OSSL_MAC_PARAM_DIGEST; + else if (strcmp(type, "digestsize") == 0) + type = OSSL_MAC_PARAM_SIZE; + + if (!OSSL_PARAM_allocate_from_text(¶ms[0], + EVP_MAC_settable_ctx_params(mac), + type, value, strlen(value) + 1, NULL)) + return 0; + params[1] = OSSL_PARAM_construct_end(); - return EVP_MAC_ctrl_str(hctx->ctx, type, value); + ok = EVP_MAC_CTX_set_params(hctx->ctx, params); + OPENSSL_free(params[0].data); + return ok; } -const EVP_PKEY_METHOD cmac_pkey_meth = { +static const EVP_PKEY_METHOD cmac_pkey_meth = { EVP_PKEY_CMAC, EVP_PKEY_FLAG_SIGCTX_CUSTOM, pkey_mac_init, @@ -359,3 +568,122 @@ const EVP_PKEY_METHOD cmac_pkey_meth = { pkey_mac_ctrl, pkey_mac_ctrl_str }; + +const EVP_PKEY_METHOD *cmac_pkey_method(void) +{ + return &cmac_pkey_meth; +} + +static const EVP_PKEY_METHOD hmac_pkey_meth = { + EVP_PKEY_HMAC, + 0, + pkey_mac_init, + pkey_mac_copy, + pkey_mac_cleanup, + + 0, 0, + + 0, + pkey_mac_keygen, + + 0, 0, + + 0, 0, + + 0, 0, + + pkey_mac_signctx_init, + pkey_mac_signctx, + + 0, 0, + + 0, 0, + + 0, 0, + + 0, 0, + + pkey_mac_ctrl, + pkey_mac_ctrl_str +}; + +const EVP_PKEY_METHOD *hmac_pkey_method(void) +{ + return &hmac_pkey_meth; +} + +static const EVP_PKEY_METHOD siphash_pkey_meth = { + EVP_PKEY_SIPHASH, + EVP_PKEY_FLAG_SIGCTX_CUSTOM, + pkey_mac_init, + pkey_mac_copy, + pkey_mac_cleanup, + + 0, 0, + + 0, + pkey_mac_keygen, + + 0, 0, + + 0, 0, + + 0, 0, + + pkey_mac_signctx_init, + pkey_mac_signctx, + + 0, 0, + + 0, 0, + + 0, 0, + + 0, 0, + + pkey_mac_ctrl, + pkey_mac_ctrl_str +}; + +const EVP_PKEY_METHOD *siphash_pkey_method(void) +{ + return &siphash_pkey_meth; +} + +static const EVP_PKEY_METHOD poly1305_pkey_meth = { + EVP_PKEY_POLY1305, + EVP_PKEY_FLAG_SIGCTX_CUSTOM, + pkey_mac_init, + pkey_mac_copy, + pkey_mac_cleanup, + + 0, 0, + + 0, + pkey_mac_keygen, + + 0, 0, + + 0, 0, + + 0, 0, + + pkey_mac_signctx_init, + pkey_mac_signctx, + + 0, 0, + + 0, 0, + + 0, 0, + + 0, 0, + + pkey_mac_ctrl, + pkey_mac_ctrl_str +}; + +const EVP_PKEY_METHOD *poly1305_pkey_method(void) +{ + return &poly1305_pkey_meth; +}