Skip to content

Commit 0d53de1

Browse files
levittebeldmit
authored andcommitted
Making a gost provider - Add the macs
We add the macs for the provider as wrappers around the EVP_MD implementations designed for ENGINEs. This is not the most elegant, but it does the job. When an algorithm has an OID, it's included in the OSSL_ALGORITHM name as an alias. This is the way to avoid having to register the OIDs in OpenSSL proper.
1 parent dd645e7 commit 0d53de1

File tree

5 files changed

+554
-25
lines changed

5 files changed

+554
-25
lines changed

CMakeLists.txt

+1
Original file line numberDiff line numberDiff line change
@@ -201,6 +201,7 @@ set(GOST_PROV_SOURCE_FILES
201201
gost_prov.c
202202
gost_prov_cipher.c
203203
gost_prov_digest.c
204+
gost_prov_mac.c
204205
)
205206

206207
set(TEST_ENVIRONMENT_COMMON

gost_lcl.h

+4
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,10 @@ void gost_param_free(void);
5353

5454
/* method registration */
5555

56+
/* Provider implementation data */
57+
extern const OSSL_ALGORITHM GOST_prov_macs[];
58+
void GOST_prov_deinit_mac_digests(void);
59+
5660
int register_ameth_gost(int nid, EVP_PKEY_ASN1_METHOD **ameth,
5761
const char *pemstr, const char *info);
5862
int register_pmeth_gost(int id, EVP_PKEY_METHOD **pmeth, int flags);

gost_prov.c

+3
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,8 @@ static const OSSL_ALGORITHM *gost_operation(void *vprovctx,
9191
return GOST_prov_ciphers;
9292
case OSSL_OP_DIGEST:
9393
return GOST_prov_digests;
94+
case OSSL_OP_MAC:
95+
return GOST_prov_macs;
9496
}
9597
return NULL;
9698
}
@@ -113,6 +115,7 @@ static void gost_teardown(void *vprovctx)
113115
{
114116
GOST_prov_deinit_ciphers();
115117
GOST_prov_deinit_digests();
118+
GOST_prov_deinit_mac_digests();
116119
provider_ctx_free(vprovctx);
117120
}
118121

gost_prov_mac.c

+361
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,361 @@
1+
/**********************************************************************
2+
* gost_prov_mac.c - Initialize all macs *
3+
* *
4+
* Copyright (c) 2021 Richard Levitte <[email protected]> *
5+
* This file is distributed under the same license as OpenSSL *
6+
* *
7+
* OpenSSL provider interface to GOST mac functions *
8+
* Requires OpenSSL 3.0 for compilation *
9+
**********************************************************************/
10+
11+
#include <openssl/core.h>
12+
#include <openssl/core_dispatch.h>
13+
#include "gost_prov.h"
14+
#include "gost_lcl.h"
15+
16+
/*
17+
* Forward declarations of all generic OSSL_DISPATCH functions, to make sure
18+
* they are correctly defined further down. For the algorithm specific ones
19+
* MAKE_FUNCTIONS() does it for us.
20+
*/
21+
22+
static OSSL_FUNC_mac_dupctx_fn mac_dupctx;
23+
static OSSL_FUNC_mac_freectx_fn mac_freectx;
24+
static OSSL_FUNC_mac_init_fn mac_init;
25+
static OSSL_FUNC_mac_update_fn mac_update;
26+
static OSSL_FUNC_mac_final_fn mac_final;
27+
static OSSL_FUNC_mac_get_ctx_params_fn mac_get_ctx_params;
28+
static OSSL_FUNC_mac_set_ctx_params_fn mac_set_ctx_params;
29+
30+
struct gost_prov_mac_desc_st {
31+
/*
32+
* In the GOST engine, the MAC implementation bases itself heavily on
33+
* digests with the same name. We can re-use that part.
34+
*/
35+
GOST_digest *digest_desc;
36+
size_t initial_mac_size;
37+
};
38+
typedef struct gost_prov_mac_desc_st GOST_DESC;
39+
40+
struct gost_prov_mac_ctx_st {
41+
/* Provider context */
42+
PROV_CTX *provctx;
43+
const GOST_DESC *descriptor;
44+
45+
/* Output MAC size */
46+
size_t mac_size;
47+
/* XOF mode, where applicable */
48+
int xof_mode;
49+
50+
/*
51+
* Since existing functionality is mainly designed as EVP_MDs for
52+
* ENGINEs, the functions in this file are accomodated and are simply
53+
* wrappers that use a local EVP_MD and EVP_MD_CTX.
54+
* Future development should take a more direct approach and have the
55+
* appropriate digest functions and digest data directly in this context.
56+
*/
57+
58+
/* The EVP_MD created from |descriptor| */
59+
EVP_MD *digest;
60+
/* The context for the EVP_MD functions */
61+
EVP_MD_CTX *dctx;
62+
};
63+
typedef struct gost_prov_mac_ctx_st GOST_CTX;
64+
65+
static void mac_freectx(void *vgctx)
66+
{
67+
GOST_CTX *gctx = vgctx;
68+
69+
/*
70+
* We don't free gctx->digest here.
71+
* That will be done by the provider teardown, via
72+
* GOST_prov_deinit_digests() (defined at the bottom of this file).
73+
*/
74+
EVP_MD_CTX_free(gctx->dctx);
75+
OPENSSL_free(gctx);
76+
}
77+
78+
static GOST_CTX *mac_newctx(void *provctx, const GOST_DESC *descriptor)
79+
{
80+
GOST_CTX *gctx = NULL;
81+
82+
if ((gctx = OPENSSL_zalloc(sizeof(*gctx))) != NULL) {
83+
gctx->provctx = provctx;
84+
gctx->descriptor = descriptor;
85+
gctx->mac_size = descriptor->initial_mac_size;
86+
gctx->digest = GOST_init_digest(descriptor->digest_desc);
87+
gctx->dctx = EVP_MD_CTX_new();
88+
89+
if (gctx->digest == NULL
90+
|| gctx->dctx == NULL
91+
|| EVP_DigestInit_ex(gctx->dctx, gctx->digest,
92+
gctx->provctx->e) <= 0) {
93+
mac_freectx(gctx);
94+
gctx = NULL;
95+
}
96+
}
97+
return gctx;
98+
}
99+
100+
static void *mac_dupctx(void *vsrc)
101+
{
102+
GOST_CTX *src = vsrc;
103+
GOST_CTX *dst =
104+
mac_newctx(src->provctx, src->descriptor);
105+
106+
if (dst != NULL)
107+
EVP_MD_CTX_copy(dst->dctx, src->dctx);
108+
return dst;
109+
}
110+
111+
static int mac_init(void *mctx, const unsigned char *key,
112+
size_t keylen, const OSSL_PARAM params[])
113+
{
114+
GOST_CTX *gctx = mctx;
115+
116+
return mac_set_ctx_params(gctx, params)
117+
&& (key == NULL
118+
|| EVP_MD_CTX_ctrl(gctx->dctx, EVP_MD_CTRL_SET_KEY,
119+
(int)keylen, (void *)key) > 0);
120+
}
121+
122+
static int mac_update(void *mctx, const unsigned char *in, size_t inl)
123+
{
124+
GOST_CTX *gctx = mctx;
125+
126+
return EVP_DigestUpdate(gctx->dctx, in, inl) > 0;
127+
}
128+
129+
static int mac_final(void *mctx, unsigned char *out, size_t *outl,
130+
size_t outsize)
131+
{
132+
GOST_CTX *gctx = mctx;
133+
unsigned int tmpoutl;
134+
int ret = 0;
135+
136+
/* This is strange code... but it duplicates pkey_gost_mac_signctx() */
137+
138+
if (outl == NULL)
139+
return 0;
140+
141+
/* for platforms where sizeof(int) != * sizeof(size_t) */
142+
tmpoutl = *outl;
143+
144+
if (out != NULL) {
145+
/* We ignore the error for GOST MDs that don't support setting
146+
the size */
147+
EVP_MD_CTX_ctrl(gctx->dctx, EVP_MD_CTRL_XOF_LEN, gctx->mac_size, NULL);
148+
ret = EVP_DigestFinal_ex(gctx->dctx, out, &tmpoutl);
149+
}
150+
if (outl != NULL)
151+
*outl = (size_t)gctx->mac_size;
152+
return ret;
153+
}
154+
155+
static const OSSL_PARAM *mac_gettable_params(void *provctx,
156+
const GOST_DESC * descriptor)
157+
{
158+
static const OSSL_PARAM params[] = {
159+
OSSL_PARAM_size_t("size", NULL),
160+
OSSL_PARAM_size_t("keylen", NULL),
161+
OSSL_PARAM_END
162+
};
163+
164+
return params;
165+
}
166+
167+
static const OSSL_PARAM *mac_gettable_ctx_params(void *mctx, void *provctx)
168+
{
169+
static const OSSL_PARAM params[] = {
170+
OSSL_PARAM_size_t("size", NULL),
171+
OSSL_PARAM_size_t("keylen", NULL),
172+
OSSL_PARAM_END
173+
};
174+
175+
return params;
176+
}
177+
178+
static const OSSL_PARAM *mac_settable_ctx_params(void *mctx, void *provctx)
179+
{
180+
static const OSSL_PARAM params[] = {
181+
OSSL_PARAM_size_t("size", NULL),
182+
OSSL_PARAM_octet_string("key", NULL, 0),
183+
OSSL_PARAM_END
184+
};
185+
186+
return params;
187+
}
188+
189+
static int mac_get_params(const GOST_DESC * descriptor, OSSL_PARAM params[])
190+
{
191+
OSSL_PARAM *p = NULL;
192+
193+
if (((p = OSSL_PARAM_locate(params, "size")) != NULL
194+
&& !OSSL_PARAM_set_size_t(p, descriptor->initial_mac_size))
195+
|| ((p = OSSL_PARAM_locate(params, "keylen")) != NULL
196+
&& !OSSL_PARAM_set_size_t(p, 32)))
197+
return 0;
198+
return 1;
199+
}
200+
201+
static int mac_get_ctx_params(void *mctx, OSSL_PARAM params[])
202+
{
203+
GOST_CTX *gctx = mctx;
204+
OSSL_PARAM *p = NULL;
205+
206+
if ((p = OSSL_PARAM_locate(params, "size")) != NULL
207+
&& !OSSL_PARAM_set_size_t(p, gctx->mac_size))
208+
return 0;
209+
210+
if ((p = OSSL_PARAM_locate(params, "keylen")) != NULL) {
211+
unsigned int len = 0;
212+
213+
if (EVP_MD_CTX_ctrl(gctx->dctx, EVP_MD_CTRL_KEY_LEN, 0, &len) <= 0
214+
|| !OSSL_PARAM_set_size_t(p, len))
215+
return 0;
216+
}
217+
218+
if ((p = OSSL_PARAM_locate(params, "xof")) != NULL
219+
&& (!(EVP_MD_flags(EVP_MD_CTX_md(gctx->dctx)) & EVP_MD_FLAG_XOF)
220+
|| !OSSL_PARAM_set_int(p, gctx->xof_mode)))
221+
return 0;
222+
223+
return 1;
224+
}
225+
226+
static int mac_set_ctx_params(void *mctx, const OSSL_PARAM params[])
227+
{
228+
GOST_CTX *gctx = mctx;
229+
const OSSL_PARAM *p = NULL;
230+
231+
if ((p = OSSL_PARAM_locate_const(params, "size")) != NULL
232+
&& !OSSL_PARAM_get_size_t(p, &gctx->mac_size))
233+
return 0;
234+
if ((p = OSSL_PARAM_locate_const(params, "key")) != NULL) {
235+
const unsigned char *key = NULL;
236+
size_t keylen = 0;
237+
int ret;
238+
239+
if (!OSSL_PARAM_get_octet_string_ptr(p, (const void **)&key, &keylen))
240+
return 0;
241+
242+
ret = EVP_MD_CTX_ctrl(gctx->dctx, EVP_MD_CTRL_SET_KEY,
243+
(int)keylen, (void *)key);
244+
if (ret <= 0 && ret != -2)
245+
return 0;
246+
}
247+
if ((p = OSSL_PARAM_locate_const(params, "xof")) != NULL
248+
&& (!(EVP_MD_flags(EVP_MD_CTX_md(gctx->dctx)) & EVP_MD_FLAG_XOF)
249+
|| !OSSL_PARAM_get_int(p, &gctx->xof_mode)))
250+
return 0;
251+
if ((p = OSSL_PARAM_locate_const(params, "key-mesh")) != NULL) {
252+
size_t key_mesh = 0;
253+
int i_cipher_key_mesh = 0, *p_cipher_key_mesh = NULL;
254+
255+
if (!OSSL_PARAM_get_size_t(p, &key_mesh))
256+
return 0;
257+
258+
if ((p = OSSL_PARAM_locate_const(params, "cipher-key-mesh")) != NULL) {
259+
size_t cipher_key_mesh = 0;
260+
261+
if (!OSSL_PARAM_get_size_t(p, &cipher_key_mesh)) {
262+
return 0;
263+
} else {
264+
i_cipher_key_mesh = (int)cipher_key_mesh;
265+
p_cipher_key_mesh = &i_cipher_key_mesh;
266+
}
267+
}
268+
269+
if (EVP_MD_CTX_ctrl(gctx->dctx, EVP_CTRL_KEY_MESH,
270+
key_mesh, p_cipher_key_mesh) <= 0)
271+
return 0;
272+
}
273+
return 1;
274+
}
275+
276+
/*
277+
* Macros to map the MAC algorithms to their respective GOST_digest
278+
* implementation where necessary. Not needed for magma and grasshopper, as
279+
* they already have fitting names.
280+
*/
281+
#define id_Gost28147_89_MAC_digest Gost28147_89_MAC_digest
282+
#define gost_mac_12_digest Gost28147_89_mac_12_digest
283+
#define id_tc26_cipher_gostr3412_2015_kuznyechik_ctracpkm_omac_digest \
284+
kuznyechik_ctracpkm_omac_digest
285+
286+
typedef void (*fptr_t)(void);
287+
#define MAKE_FUNCTIONS(name, macsize) \
288+
const GOST_DESC name##_desc = { \
289+
&name##_digest, \
290+
macsize, \
291+
}; \
292+
static OSSL_FUNC_mac_newctx_fn name##_newctx; \
293+
static void *name##_newctx(void *provctx) \
294+
{ \
295+
return mac_newctx(provctx, &name##_desc); \
296+
} \
297+
static OSSL_FUNC_mac_gettable_params_fn name##_gettable_params; \
298+
static const OSSL_PARAM *name##_gettable_params(void *provctx) \
299+
{ \
300+
return mac_gettable_params(provctx, &name##_desc); \
301+
} \
302+
static OSSL_FUNC_mac_get_params_fn name##_get_params; \
303+
static int name##_get_params(OSSL_PARAM *params) \
304+
{ \
305+
return mac_get_params(&name##_desc, params); \
306+
} \
307+
static const OSSL_DISPATCH name##_functions[] = { \
308+
{ OSSL_FUNC_MAC_GETTABLE_PARAMS, \
309+
(fptr_t)name##_gettable_params }, \
310+
{ OSSL_FUNC_MAC_GET_PARAMS, (fptr_t)name##_get_params }, \
311+
{ OSSL_FUNC_MAC_NEWCTX, (fptr_t)name##_newctx }, \
312+
{ OSSL_FUNC_MAC_DUPCTX, (fptr_t)mac_dupctx }, \
313+
{ OSSL_FUNC_MAC_FREECTX, (fptr_t)mac_freectx }, \
314+
{ OSSL_FUNC_MAC_INIT, (fptr_t)mac_init }, \
315+
{ OSSL_FUNC_MAC_UPDATE, (fptr_t)mac_update }, \
316+
{ OSSL_FUNC_MAC_FINAL, (fptr_t)mac_final }, \
317+
{ OSSL_FUNC_MAC_GETTABLE_CTX_PARAMS, \
318+
(fptr_t)mac_gettable_ctx_params }, \
319+
{ OSSL_FUNC_MAC_GET_CTX_PARAMS, (fptr_t)mac_get_ctx_params }, \
320+
{ OSSL_FUNC_MAC_SETTABLE_CTX_PARAMS, \
321+
(fptr_t)mac_settable_ctx_params }, \
322+
{ OSSL_FUNC_MAC_SET_CTX_PARAMS, (fptr_t)mac_set_ctx_params }, \
323+
}
324+
325+
/*
326+
* The name used here is the same as the NID name. Some of the names are
327+
* horribly long, but that can't be helped...
328+
*/
329+
MAKE_FUNCTIONS(id_Gost28147_89_MAC, 4);
330+
MAKE_FUNCTIONS(gost_mac_12, 4);
331+
MAKE_FUNCTIONS(magma_mac, 8);
332+
MAKE_FUNCTIONS(grasshopper_mac, 16);
333+
MAKE_FUNCTIONS(id_tc26_cipher_gostr3412_2015_kuznyechik_ctracpkm_omac, 16);
334+
335+
/* The OSSL_ALGORITHM for the provider's operation query function */
336+
const OSSL_ALGORITHM GOST_prov_macs[] = {
337+
{ SN_id_Gost28147_89_MAC ":1.2.643.2.2.22", NULL,
338+
id_Gost28147_89_MAC_functions, "GOST 28147-89 MAC" },
339+
{ SN_gost_mac_12, NULL, gost_mac_12_functions },
340+
{ SN_magma_mac, NULL, magma_mac_functions },
341+
{ SN_grasshopper_mac, NULL, grasshopper_mac_functions },
342+
{ SN_id_tc26_cipher_gostr3412_2015_kuznyechik_ctracpkm_omac
343+
":1.2.643.7.1.1.5.2.2", NULL,
344+
id_tc26_cipher_gostr3412_2015_kuznyechik_ctracpkm_omac_functions },
345+
{ NULL , NULL, NULL }
346+
};
347+
348+
void GOST_prov_deinit_mac_digests(void) {
349+
static GOST_digest *list[] = {
350+
&Gost28147_89_MAC_digest,
351+
&Gost28147_89_mac_12_digest,
352+
&magma_mac_digest,
353+
&grasshopper_mac_digest,
354+
&kuznyechik_ctracpkm_omac_digest
355+
};
356+
size_t i;
357+
#define elems(l) (sizeof(l) / sizeof(l[0]))
358+
359+
for (i = 0; i < elems(list); i++)
360+
GOST_deinit_digest(list[i]);
361+
}

0 commit comments

Comments
 (0)