361 lines
12 KiB
C
361 lines
12 KiB
C
/**********************************************************************
|
|
* gost_prov_mac.c - Initialize all macs *
|
|
* *
|
|
* Copyright (c) 2021 Richard Levitte <richard@levitte.org> *
|
|
* This file is distributed under the same license as OpenSSL *
|
|
* *
|
|
* OpenSSL provider interface to GOST mac functions *
|
|
* Requires OpenSSL 3.0 for compilation *
|
|
**********************************************************************/
|
|
|
|
#include <openssl/core.h>
|
|
#include <openssl/core_dispatch.h>
|
|
#include "gost_prov.h"
|
|
#include "gost_lcl.h"
|
|
|
|
/*
|
|
* Forward declarations of all generic OSSL_DISPATCH functions, to make sure
|
|
* they are correctly defined further down. For the algorithm specific ones
|
|
* MAKE_FUNCTIONS() does it for us.
|
|
*/
|
|
|
|
static OSSL_FUNC_mac_dupctx_fn mac_dupctx;
|
|
static OSSL_FUNC_mac_freectx_fn mac_freectx;
|
|
static OSSL_FUNC_mac_init_fn mac_init;
|
|
static OSSL_FUNC_mac_update_fn mac_update;
|
|
static OSSL_FUNC_mac_final_fn mac_final;
|
|
static OSSL_FUNC_mac_get_ctx_params_fn mac_get_ctx_params;
|
|
static OSSL_FUNC_mac_set_ctx_params_fn mac_set_ctx_params;
|
|
|
|
struct gost_prov_mac_desc_st {
|
|
/*
|
|
* In the GOST engine, the MAC implementation bases itself heavily on
|
|
* digests with the same name. We can re-use that part.
|
|
*/
|
|
GOST_digest *digest_desc;
|
|
size_t initial_mac_size;
|
|
};
|
|
typedef struct gost_prov_mac_desc_st GOST_DESC;
|
|
|
|
struct gost_prov_mac_ctx_st {
|
|
/* Provider context */
|
|
PROV_CTX *provctx;
|
|
const GOST_DESC *descriptor;
|
|
|
|
/* Output MAC size */
|
|
size_t mac_size;
|
|
/* XOF mode, where applicable */
|
|
int xof_mode;
|
|
|
|
/*
|
|
* Since existing functionality is mainly designed as EVP_MDs for
|
|
* ENGINEs, the functions in this file are accomodated and are simply
|
|
* wrappers that use a local EVP_MD and EVP_MD_CTX.
|
|
* Future development should take a more direct approach and have the
|
|
* appropriate digest functions and digest data directly in this context.
|
|
*/
|
|
|
|
/* The EVP_MD created from |descriptor| */
|
|
EVP_MD *digest;
|
|
/* The context for the EVP_MD functions */
|
|
EVP_MD_CTX *dctx;
|
|
};
|
|
typedef struct gost_prov_mac_ctx_st GOST_CTX;
|
|
|
|
static void mac_freectx(void *vgctx)
|
|
{
|
|
GOST_CTX *gctx = vgctx;
|
|
|
|
/*
|
|
* We don't free gctx->digest here.
|
|
* That will be done by the provider teardown, via
|
|
* GOST_prov_deinit_digests() (defined at the bottom of this file).
|
|
*/
|
|
EVP_MD_CTX_free(gctx->dctx);
|
|
OPENSSL_free(gctx);
|
|
}
|
|
|
|
static GOST_CTX *mac_newctx(void *provctx, const GOST_DESC *descriptor)
|
|
{
|
|
GOST_CTX *gctx = NULL;
|
|
|
|
if ((gctx = OPENSSL_zalloc(sizeof(*gctx))) != NULL) {
|
|
gctx->provctx = provctx;
|
|
gctx->descriptor = descriptor;
|
|
gctx->mac_size = descriptor->initial_mac_size;
|
|
gctx->digest = GOST_init_digest(descriptor->digest_desc);
|
|
gctx->dctx = EVP_MD_CTX_new();
|
|
|
|
if (gctx->digest == NULL
|
|
|| gctx->dctx == NULL
|
|
|| EVP_DigestInit_ex(gctx->dctx, gctx->digest,
|
|
gctx->provctx->e) <= 0) {
|
|
mac_freectx(gctx);
|
|
gctx = NULL;
|
|
}
|
|
}
|
|
return gctx;
|
|
}
|
|
|
|
static void *mac_dupctx(void *vsrc)
|
|
{
|
|
GOST_CTX *src = vsrc;
|
|
GOST_CTX *dst =
|
|
mac_newctx(src->provctx, src->descriptor);
|
|
|
|
if (dst != NULL)
|
|
EVP_MD_CTX_copy(dst->dctx, src->dctx);
|
|
return dst;
|
|
}
|
|
|
|
static int mac_init(void *mctx, const unsigned char *key,
|
|
size_t keylen, const OSSL_PARAM params[])
|
|
{
|
|
GOST_CTX *gctx = mctx;
|
|
|
|
return mac_set_ctx_params(gctx, params)
|
|
&& (key == NULL
|
|
|| EVP_MD_CTX_ctrl(gctx->dctx, EVP_MD_CTRL_SET_KEY,
|
|
(int)keylen, (void *)key) > 0);
|
|
}
|
|
|
|
static int mac_update(void *mctx, const unsigned char *in, size_t inl)
|
|
{
|
|
GOST_CTX *gctx = mctx;
|
|
|
|
return EVP_DigestUpdate(gctx->dctx, in, inl) > 0;
|
|
}
|
|
|
|
static int mac_final(void *mctx, unsigned char *out, size_t *outl,
|
|
size_t outsize)
|
|
{
|
|
GOST_CTX *gctx = mctx;
|
|
unsigned int tmpoutl;
|
|
int ret = 0;
|
|
|
|
/* This is strange code... but it duplicates pkey_gost_mac_signctx() */
|
|
|
|
if (outl == NULL)
|
|
return 0;
|
|
|
|
/* for platforms where sizeof(int) != * sizeof(size_t) */
|
|
tmpoutl = *outl;
|
|
|
|
if (out != NULL) {
|
|
/* We ignore the error for GOST MDs that don't support setting
|
|
the size */
|
|
EVP_MD_CTX_ctrl(gctx->dctx, EVP_MD_CTRL_XOF_LEN, gctx->mac_size, NULL);
|
|
ret = EVP_DigestFinal_ex(gctx->dctx, out, &tmpoutl);
|
|
}
|
|
if (outl != NULL)
|
|
*outl = (size_t)gctx->mac_size;
|
|
return ret;
|
|
}
|
|
|
|
static const OSSL_PARAM *mac_gettable_params(void *provctx,
|
|
const GOST_DESC * descriptor)
|
|
{
|
|
static const OSSL_PARAM params[] = {
|
|
OSSL_PARAM_size_t("size", NULL),
|
|
OSSL_PARAM_size_t("keylen", NULL),
|
|
OSSL_PARAM_END
|
|
};
|
|
|
|
return params;
|
|
}
|
|
|
|
static const OSSL_PARAM *mac_gettable_ctx_params(void *mctx, void *provctx)
|
|
{
|
|
static const OSSL_PARAM params[] = {
|
|
OSSL_PARAM_size_t("size", NULL),
|
|
OSSL_PARAM_size_t("keylen", NULL),
|
|
OSSL_PARAM_END
|
|
};
|
|
|
|
return params;
|
|
}
|
|
|
|
static const OSSL_PARAM *mac_settable_ctx_params(void *mctx, void *provctx)
|
|
{
|
|
static const OSSL_PARAM params[] = {
|
|
OSSL_PARAM_size_t("size", NULL),
|
|
OSSL_PARAM_octet_string("key", NULL, 0),
|
|
OSSL_PARAM_END
|
|
};
|
|
|
|
return params;
|
|
}
|
|
|
|
static int mac_get_params(const GOST_DESC * descriptor, OSSL_PARAM params[])
|
|
{
|
|
OSSL_PARAM *p = NULL;
|
|
|
|
if (((p = OSSL_PARAM_locate(params, "size")) != NULL
|
|
&& !OSSL_PARAM_set_size_t(p, descriptor->initial_mac_size))
|
|
|| ((p = OSSL_PARAM_locate(params, "keylen")) != NULL
|
|
&& !OSSL_PARAM_set_size_t(p, 32)))
|
|
return 0;
|
|
return 1;
|
|
}
|
|
|
|
static int mac_get_ctx_params(void *mctx, OSSL_PARAM params[])
|
|
{
|
|
GOST_CTX *gctx = mctx;
|
|
OSSL_PARAM *p = NULL;
|
|
|
|
if ((p = OSSL_PARAM_locate(params, "size")) != NULL
|
|
&& !OSSL_PARAM_set_size_t(p, gctx->mac_size))
|
|
return 0;
|
|
|
|
if ((p = OSSL_PARAM_locate(params, "keylen")) != NULL) {
|
|
unsigned int len = 0;
|
|
|
|
if (EVP_MD_CTX_ctrl(gctx->dctx, EVP_MD_CTRL_KEY_LEN, 0, &len) <= 0
|
|
|| !OSSL_PARAM_set_size_t(p, len))
|
|
return 0;
|
|
}
|
|
|
|
if ((p = OSSL_PARAM_locate(params, "xof")) != NULL
|
|
&& (!(EVP_MD_flags(EVP_MD_CTX_md(gctx->dctx)) & EVP_MD_FLAG_XOF)
|
|
|| !OSSL_PARAM_set_int(p, gctx->xof_mode)))
|
|
return 0;
|
|
|
|
return 1;
|
|
}
|
|
|
|
static int mac_set_ctx_params(void *mctx, const OSSL_PARAM params[])
|
|
{
|
|
GOST_CTX *gctx = mctx;
|
|
const OSSL_PARAM *p = NULL;
|
|
|
|
if ((p = OSSL_PARAM_locate_const(params, "size")) != NULL
|
|
&& !OSSL_PARAM_get_size_t(p, &gctx->mac_size))
|
|
return 0;
|
|
if ((p = OSSL_PARAM_locate_const(params, "key")) != NULL) {
|
|
const unsigned char *key = NULL;
|
|
size_t keylen = 0;
|
|
int ret;
|
|
|
|
if (!OSSL_PARAM_get_octet_string_ptr(p, (const void **)&key, &keylen))
|
|
return 0;
|
|
|
|
ret = EVP_MD_CTX_ctrl(gctx->dctx, EVP_MD_CTRL_SET_KEY,
|
|
(int)keylen, (void *)key);
|
|
if (ret <= 0 && ret != -2)
|
|
return 0;
|
|
}
|
|
if ((p = OSSL_PARAM_locate_const(params, "xof")) != NULL
|
|
&& (!(EVP_MD_flags(EVP_MD_CTX_md(gctx->dctx)) & EVP_MD_FLAG_XOF)
|
|
|| !OSSL_PARAM_get_int(p, &gctx->xof_mode)))
|
|
return 0;
|
|
if ((p = OSSL_PARAM_locate_const(params, "key-mesh")) != NULL) {
|
|
size_t key_mesh = 0;
|
|
int i_cipher_key_mesh = 0, *p_cipher_key_mesh = NULL;
|
|
|
|
if (!OSSL_PARAM_get_size_t(p, &key_mesh))
|
|
return 0;
|
|
|
|
if ((p = OSSL_PARAM_locate_const(params, "cipher-key-mesh")) != NULL) {
|
|
size_t cipher_key_mesh = 0;
|
|
|
|
if (!OSSL_PARAM_get_size_t(p, &cipher_key_mesh)) {
|
|
return 0;
|
|
} else {
|
|
i_cipher_key_mesh = (int)cipher_key_mesh;
|
|
p_cipher_key_mesh = &i_cipher_key_mesh;
|
|
}
|
|
}
|
|
|
|
if (EVP_MD_CTX_ctrl(gctx->dctx, EVP_CTRL_KEY_MESH,
|
|
key_mesh, p_cipher_key_mesh) <= 0)
|
|
return 0;
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
/*
|
|
* Macros to map the MAC algorithms to their respective GOST_digest
|
|
* implementation where necessary. Not needed for magma and grasshopper, as
|
|
* they already have fitting names.
|
|
*/
|
|
#define id_Gost28147_89_MAC_digest Gost28147_89_MAC_digest
|
|
#define gost_mac_12_digest Gost28147_89_mac_12_digest
|
|
#define id_tc26_cipher_gostr3412_2015_kuznyechik_ctracpkm_omac_digest \
|
|
kuznyechik_ctracpkm_omac_digest
|
|
|
|
typedef void (*fptr_t)(void);
|
|
#define MAKE_FUNCTIONS(name, macsize) \
|
|
const GOST_DESC name##_desc = { \
|
|
&name##_digest, \
|
|
macsize, \
|
|
}; \
|
|
static OSSL_FUNC_mac_newctx_fn name##_newctx; \
|
|
static void *name##_newctx(void *provctx) \
|
|
{ \
|
|
return mac_newctx(provctx, &name##_desc); \
|
|
} \
|
|
static OSSL_FUNC_mac_gettable_params_fn name##_gettable_params; \
|
|
static const OSSL_PARAM *name##_gettable_params(void *provctx) \
|
|
{ \
|
|
return mac_gettable_params(provctx, &name##_desc); \
|
|
} \
|
|
static OSSL_FUNC_mac_get_params_fn name##_get_params; \
|
|
static int name##_get_params(OSSL_PARAM *params) \
|
|
{ \
|
|
return mac_get_params(&name##_desc, params); \
|
|
} \
|
|
static const OSSL_DISPATCH name##_functions[] = { \
|
|
{ OSSL_FUNC_MAC_GETTABLE_PARAMS, \
|
|
(fptr_t)name##_gettable_params }, \
|
|
{ OSSL_FUNC_MAC_GET_PARAMS, (fptr_t)name##_get_params }, \
|
|
{ OSSL_FUNC_MAC_NEWCTX, (fptr_t)name##_newctx }, \
|
|
{ OSSL_FUNC_MAC_DUPCTX, (fptr_t)mac_dupctx }, \
|
|
{ OSSL_FUNC_MAC_FREECTX, (fptr_t)mac_freectx }, \
|
|
{ OSSL_FUNC_MAC_INIT, (fptr_t)mac_init }, \
|
|
{ OSSL_FUNC_MAC_UPDATE, (fptr_t)mac_update }, \
|
|
{ OSSL_FUNC_MAC_FINAL, (fptr_t)mac_final }, \
|
|
{ OSSL_FUNC_MAC_GETTABLE_CTX_PARAMS, \
|
|
(fptr_t)mac_gettable_ctx_params }, \
|
|
{ OSSL_FUNC_MAC_GET_CTX_PARAMS, (fptr_t)mac_get_ctx_params }, \
|
|
{ OSSL_FUNC_MAC_SETTABLE_CTX_PARAMS, \
|
|
(fptr_t)mac_settable_ctx_params }, \
|
|
{ OSSL_FUNC_MAC_SET_CTX_PARAMS, (fptr_t)mac_set_ctx_params }, \
|
|
}
|
|
|
|
/*
|
|
* The name used here is the same as the NID name. Some of the names are
|
|
* horribly long, but that can't be helped...
|
|
*/
|
|
MAKE_FUNCTIONS(id_Gost28147_89_MAC, 4);
|
|
MAKE_FUNCTIONS(gost_mac_12, 4);
|
|
MAKE_FUNCTIONS(magma_mac, 8);
|
|
MAKE_FUNCTIONS(grasshopper_mac, 16);
|
|
MAKE_FUNCTIONS(id_tc26_cipher_gostr3412_2015_kuznyechik_ctracpkm_omac, 16);
|
|
|
|
/* The OSSL_ALGORITHM for the provider's operation query function */
|
|
const OSSL_ALGORITHM GOST_prov_macs[] = {
|
|
{ SN_id_Gost28147_89_MAC ":1.2.643.2.2.22", NULL,
|
|
id_Gost28147_89_MAC_functions, "GOST 28147-89 MAC" },
|
|
{ SN_gost_mac_12, NULL, gost_mac_12_functions },
|
|
{ SN_magma_mac, NULL, magma_mac_functions },
|
|
{ SN_grasshopper_mac, NULL, grasshopper_mac_functions },
|
|
{ SN_id_tc26_cipher_gostr3412_2015_kuznyechik_ctracpkm_omac
|
|
":1.2.643.7.1.1.5.2.2", NULL,
|
|
id_tc26_cipher_gostr3412_2015_kuznyechik_ctracpkm_omac_functions },
|
|
{ NULL , NULL, NULL }
|
|
};
|
|
|
|
void GOST_prov_deinit_mac_digests(void) {
|
|
static GOST_digest *list[] = {
|
|
&Gost28147_89_MAC_digest,
|
|
&Gost28147_89_mac_12_digest,
|
|
&magma_mac_digest,
|
|
&grasshopper_mac_digest,
|
|
&kuznyechik_ctracpkm_omac_digest
|
|
};
|
|
size_t i;
|
|
#define elems(l) (sizeof(l) / sizeof(l[0]))
|
|
|
|
for (i = 0; i < elems(list); i++)
|
|
GOST_deinit_digest(list[i]);
|
|
}
|