+++ /dev/null
-/*
- * Copyright 2018-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
- */
-
-/* We need to use some engine deprecated APIs */
-#define OPENSSL_SUPPRESS_DEPRECATED
-
-#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 "crypto/evp.h"
-#include "evp_local.h"
-
-/* MAC PKEY context structure */
-
-typedef struct {
- EVP_MAC_CTX *ctx;
-
- /*
- * We know of two MAC types:
- *
- * 1. those who take a secret in raw form, i.e. raw data as a
- * ASN1_OCTET_STRING embedded in a EVP_PKEY. So far, that's
- * all of them but CMAC.
- * 2. those who take a secret with associated cipher in very generic
- * form, i.e. a complete EVP_MAC_CTX embedded in a PKEY. So far,
- * only CMAC does this.
- *
- * (one might wonder why the second form isn't used for all)
- */
-#define MAC_TYPE_RAW 1 /* HMAC like MAC type (all but CMAC so far) */
-#define MAC_TYPE_MAC 2 /* CMAC like MAC type (only CMAC known so far) */
- int type;
-
- /* The following is only used for MAC_TYPE_RAW implementations */
- struct {
- const EVP_MD *md; /* temp storage of MD */
- ASN1_OCTET_STRING ktmp; /* temp storage for key */
- } 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;
- }
-
- if (mac != NULL) {
- hctx->ctx = EVP_MAC_CTX_new(mac);
- if (hctx->ctx == NULL) {
- OPENSSL_free(hctx);
- return 0;
- }
- }
-
- if (nid == EVP_PKEY_CMAC) {
- hctx->type = MAC_TYPE_MAC;
- } else {
- hctx->type = MAC_TYPE_RAW;
- 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 int pkey_mac_copy(EVP_PKEY_CTX *dst, const EVP_PKEY_CTX *src)
-{
- MAC_PKEY_CTX *sctx, *dctx;
-
- 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;
-
- 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;
-
- 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;
- if (ASN1_STRING_get0_data(&sctx->raw_data.ktmp) != NULL &&
- !ASN1_STRING_copy(&dctx->raw_data.ktmp, &sctx->raw_data.ktmp))
- goto err;
- break;
- case MAC_TYPE_MAC:
- /* Nothing more to do */
- break;
- default:
- /* This should be dead code */
- return 0;
- }
- return 1;
- err:
- pkey_mac_cleanup(dst);
- return 0;
-}
-
-static void pkey_mac_cleanup(EVP_PKEY_CTX *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,
- hctx->raw_data.ktmp.length);
- break;
- }
- EVP_MAC_CTX_free(hctx->ctx);
- EVP_MAC_free(mac);
- OPENSSL_free(hctx);
- EVP_PKEY_CTX_set_data(ctx, NULL);
- }
-}
-
-static int pkey_mac_keygen(EVP_PKEY_CTX *ctx, EVP_PKEY *pkey)
-{
- MAC_PKEY_CTX *hctx = EVP_PKEY_CTX_get_data(ctx);
- int nid = ctx->pmeth->pkey_id;
-
- switch (hctx->type) {
- case MAC_TYPE_RAW:
- {
- ASN1_OCTET_STRING *hkey = NULL;
-
- if (!hctx->raw_data.ktmp.data)
- return 0;
- hkey = ASN1_OCTET_STRING_dup(&hctx->raw_data.ktmp);
- if (!hkey)
- return 0;
- EVP_PKEY_assign(pkey, nid, hkey);
- }
- break;
- case MAC_TYPE_MAC:
- {
- 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_up_ref(EVP_MAC_CTX_mac(hctx->ctx)))
- return 0;
- EVP_PKEY_assign(pkey, nid, cmkey);
- }
- break;
- default:
- /* This should be dead code */
- return 0;
- }
-
- return 1;
-}
-
-static int int_update(EVP_MD_CTX *ctx, const void *data, size_t count)
-{
- MAC_PKEY_CTX *hctx = EVP_PKEY_CTX_get_data(EVP_MD_CTX_pkey_ctx(ctx));
-
- if (!EVP_MAC_update(hctx->ctx, data, count))
- return 0;
- return 1;
-}
-
-static int pkey_mac_signctx_init(EVP_PKEY_CTX *ctx, EVP_MD_CTX *mctx)
-{
- MAC_PKEY_CTX *hctx = EVP_PKEY_CTX_get_data(ctx);
- ASN1_OCTET_STRING *key = NULL;
- int rv = 1;
- /*
- * For MACs with the EVP_PKEY_FLAG_SIGCTX_CUSTOM flag set and that
- * gets the key passed as an ASN.1 OCTET STRING, we set the key here,
- * as this may be only time it's set during a DigestSign.
- *
- * MACs that pass around the key in form of EVP_MAC_CTX are setting
- * the key through other mechanisms. (this is only CMAC for now)
- */
- int set_key =
- 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_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;
- }
-
- EVP_MD_CTX_set_flags(mctx, EVP_MD_CTX_FLAG_NO_INIT);
- EVP_MD_CTX_set_update_fn(mctx, int_update);
-
- /* 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,
- size_t *siglen, EVP_MD_CTX *mctx)
-{
- MAC_PKEY_CTX *hctx = EVP_PKEY_CTX_get_data(ctx);
-
- 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)
-{
- MAC_PKEY_CTX *hctx = EVP_PKEY_CTX_get_data(ctx);
-
- switch (type) {
-
- case EVP_PKEY_CTRL_CIPHER:
- switch (hctx->type) {
- case MAC_TYPE_RAW:
- return -2; /* The raw types don't support ciphers */
- case MAC_TYPE_MAC:
- {
- OSSL_PARAM params[3];
- size_t params_n = 0;
- char *ciphname = (char *)OBJ_nid2sn(EVP_CIPHER_nid(p2));
-
-#ifndef OPENSSL_NO_ENGINE
- if (ctx->engine != NULL) {
- char *engid = (char *)ENGINE_get_id(ctx->engine);
-
- params[params_n++] =
- OSSL_PARAM_construct_utf8_string("engine", engid, 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:
- /* This should be dead code */
- return 0;
- }
- break;
-
- case EVP_PKEY_CTRL_MD:
- switch (hctx->type) {
- case MAC_TYPE_RAW:
- hctx->raw_data.md = p2;
- break;
- 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 */
- return 0;
- }
- break;
-
- case EVP_PKEY_CTRL_SET_DIGEST_SIZE:
- {
- 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_{get,set}_ctx_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:
- if ((!p2 && p1 > 0) || (p1 < -1))
- return 0;
- if (!ASN1_OCTET_STRING_set(&hctx->raw_data.ktmp, p2, p1))
- return 0;
- break;
- case MAC_TYPE_MAC:
- {
- 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 */
- return 0;
- }
- break;
-
- 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;
- {
- ASN1_OCTET_STRING *key =
- (ASN1_OCTET_STRING *)ctx->pkey->pkey.ptr;
- 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
- if (ctx->engine != NULL) {
- char *engid = (char *)ENGINE_get_id(ctx->engine);
-
- params[params_n++] =
- OSSL_PARAM_construct_utf8_string("engine", engid, 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:
- return -2; /* The mac types don't support ciphers */
- default:
- /* This should be dead code */
- return 0;
- }
- break;
-
- default:
- return -2;
-
- }
- return 1;
-}
-
-static int pkey_mac_ctrl_str(EVP_PKEY_CTX *ctx,
- 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();
-
- ok = EVP_MAC_CTX_set_params(hctx->ctx, params);
- OPENSSL_free(params[0].data);
- return ok;
-}
-
-static const EVP_PKEY_METHOD cmac_pkey_meth = {
- EVP_PKEY_CMAC,
- 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 *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;
-}