]> www.wagner.pp.ru Git - openssl-gost/engine.git/blob - gost_eng.c
gost_eng: Rework (simplify) cipher registration
[openssl-gost/engine.git] / gost_eng.c
1 /**********************************************************************
2  *                          gost_eng.c                                *
3  *              Main file of GOST engine                              *
4  *                                                                    *
5  *             Copyright (c) 2005-2006 Cryptocom LTD                  *
6  *             Copyright (c) 2020 Chikunov Vitaly <vt@altlinux.org>   *
7  *                                                                    *
8  *       This file is distributed under the same license as OpenSSL   *
9  *                                                                    *
10  **********************************************************************/
11 #include <string.h>
12 #include <openssl/crypto.h>
13 #include <openssl/err.h>
14 #include <openssl/evp.h>
15 #include <openssl/engine.h>
16 #include <openssl/obj_mac.h>
17 #include "e_gost_err.h"
18 #include "gost_lcl.h"
19
20 #include "gost_grasshopper_cipher.h"
21
22 static const char* engine_gost_id = "gost";
23
24 static const char* engine_gost_name =
25         "Reference implementation of GOST engine";
26
27 /* Symmetric cipher and digest function registrar */
28
29 static int gost_ciphers(ENGINE* e, const EVP_CIPHER** cipher,
30                         const int** nids, int nid);
31
32 static int gost_digests(ENGINE* e, const EVP_MD** digest,
33                         const int** nids, int nid);
34
35 static int gost_pkey_meths(ENGINE* e, EVP_PKEY_METHOD** pmeth,
36                            const int** nids, int nid);
37
38 static int gost_pkey_asn1_meths(ENGINE* e, EVP_PKEY_ASN1_METHOD** ameth,
39                                 const int** nids, int nid);
40
41 static EVP_PKEY_METHOD* pmeth_GostR3410_2001 = NULL,
42         * pmeth_GostR3410_2012_256 = NULL,
43         * pmeth_GostR3410_2012_512 = NULL,
44         * pmeth_Gost28147_MAC = NULL, * pmeth_Gost28147_MAC_12 = NULL,
45         * pmeth_magma_mac = NULL,  * pmeth_grasshopper_mac = NULL,
46         * pmeth_magma_mac_acpkm = NULL,  * pmeth_grasshopper_mac_acpkm = NULL;
47
48 static EVP_PKEY_ASN1_METHOD* ameth_GostR3410_2001 = NULL,
49         * ameth_GostR3410_2012_256 = NULL,
50         * ameth_GostR3410_2012_512 = NULL,
51         * ameth_Gost28147_MAC = NULL, * ameth_Gost28147_MAC_12 = NULL,
52         * ameth_magma_mac = NULL,  * ameth_grasshopper_mac = NULL,
53         * ameth_magma_mac_acpkm = NULL,  * ameth_grasshopper_mac_acpkm = NULL;
54
55 static struct gost_digest_minfo {
56     int nid;
57     EVP_MD *(*digest)(void);
58     void (*destroy)(void);
59     const char *sn;
60     const char *alias;
61 } gost_digest_array[] = {
62     {
63         NID_id_GostR3411_94,
64         digest_gost,
65         digest_gost_destroy,
66     },
67     {
68         NID_id_Gost28147_89_MAC,
69         imit_gost_cpa,
70         imit_gost_cpa_destroy,
71     },
72     {
73         NID_id_GostR3411_2012_256,
74         digest_gost2012_256,
75         digest_gost2012_256_destroy,
76         SN_id_GostR3411_2012_256,
77         "streebog256",
78     },
79     {
80         NID_id_GostR3411_2012_512,
81         digest_gost2012_512,
82         digest_gost2012_512_destroy,
83         SN_id_GostR3411_2012_512,
84         "streebog512",
85     },
86     {
87         NID_gost_mac_12,
88         imit_gost_cp_12,
89         imit_gost_cp_12_destroy,
90     },
91     {
92         NID_magma_mac,
93         magma_omac,
94         magma_omac_destroy,
95     },
96     {
97         NID_grasshopper_mac,
98         grasshopper_omac,
99         grasshopper_omac_destroy,
100     },
101     {
102         NID_id_tc26_cipher_gostr3412_2015_kuznyechik_ctracpkm_omac,
103         grasshopper_omac_acpkm,
104         grasshopper_omac_acpkm_destroy,
105     },
106     { 0 },
107 };
108
109 GOST_cipher *gost_cipher_array[] = {
110     &Gost28147_89_cipher,
111     &Gost28147_89_cnt_cipher,
112     &Gost28147_89_cnt_12_cipher,
113     &Gost28147_89_cbc_cipher,
114     &grasshopper_ecb_cipher,
115     &grasshopper_cbc_cipher,
116     &grasshopper_cfb_cipher,
117     &grasshopper_ofb_cipher,
118     &grasshopper_ctr_cipher,
119     &magma_cbc_cipher,
120     &magma_ctr_cipher,
121     &magma_ctr_acpkm_cipher,
122     &magma_ctr_acpkm_omac_cipher,
123     &grasshopper_ctr_acpkm_cipher,
124     &grasshopper_ctr_acpkm_omac_cipher,
125     &magma_kexp15_cipher,
126     &kuznyechik_kexp15_cipher,
127 };
128
129 static struct gost_meth_minfo {
130     int nid;
131     EVP_PKEY_METHOD **pmeth;
132     EVP_PKEY_ASN1_METHOD **ameth;
133     const char *pemstr;
134     const char *info;
135 } gost_meth_array[] = {
136     {
137         NID_id_GostR3410_2001,
138         &pmeth_GostR3410_2001,
139         &ameth_GostR3410_2001,
140         "GOST2001",
141         "GOST R 34.10-2001",
142     },
143     {
144         NID_id_Gost28147_89_MAC,
145         &pmeth_Gost28147_MAC,
146         &ameth_Gost28147_MAC,
147         "GOST-MAC",
148         "GOST 28147-89 MAC",
149     },
150     {
151         NID_id_GostR3410_2012_256,
152         &pmeth_GostR3410_2012_256,
153         &ameth_GostR3410_2012_256,
154         "GOST2012_256",
155         "GOST R 34.10-2012 with 256 bit key",
156     },
157     {
158         NID_id_GostR3410_2012_512,
159         &pmeth_GostR3410_2012_512,
160         &ameth_GostR3410_2012_512,
161         "GOST2012_512",
162         "GOST R 34.10-2012 with 512 bit key",
163     },
164     {
165         NID_gost_mac_12,
166         &pmeth_Gost28147_MAC_12,
167         &ameth_Gost28147_MAC_12,
168         "GOST-MAC-12",
169         "GOST 28147-89 MAC with 2012 params",
170     },
171     {
172         NID_magma_mac,
173         &pmeth_magma_mac,
174         &ameth_magma_mac,
175         "MAGMA-MAC",
176         "GOST R 34.13-2015 Magma MAC",
177     },
178     {
179         NID_grasshopper_mac,
180         &pmeth_grasshopper_mac,
181         &ameth_grasshopper_mac,
182         "KUZNYECHIK-MAC",
183         "GOST R 34.13-2015 Grasshopper MAC",
184     },
185     {
186         NID_id_tc26_cipher_gostr3412_2015_magma_ctracpkm_omac,
187         &pmeth_magma_mac_acpkm,
188         &ameth_magma_mac_acpkm,
189         "ID-TC26-CIPHER-GOSTR3412-2015-MAGMA-CTRACPKM-OMAC",
190         "GOST R 34.13-2015 Magma MAC ACPKM",
191     },
192     {
193         NID_id_tc26_cipher_gostr3412_2015_kuznyechik_ctracpkm_omac,
194         &pmeth_grasshopper_mac_acpkm,
195         &ameth_grasshopper_mac_acpkm,
196         "ID-TC26-CIPHER-GOSTR3412-2015-KUZNYECHIK-CTRACPKM-OMAC",
197         "GOST R 34.13-2015 Grasshopper MAC ACPKM",
198     },
199     { 0 },
200 };
201
202 #ifndef OSSL_NELEM
203 # define OSSL_NELEM(x) (sizeof(x)/sizeof((x)[0]))
204 #endif
205
206 /* `- 1' because of terminating zero element */
207 static int known_digest_nids[OSSL_NELEM(gost_digest_array) - 1];
208 static int known_cipher_nids[OSSL_NELEM(gost_cipher_array)];
209 static int known_meths_nids[OSSL_NELEM(gost_meth_array) - 1];
210
211 static int gost_engine_init(ENGINE* e) {
212     return 1;
213 }
214
215 static int gost_engine_finish(ENGINE* e) {
216     return 1;
217 }
218
219 static int gost_engine_destroy(ENGINE* e) {
220     struct gost_digest_minfo *dinfo = gost_digest_array;
221     for (; dinfo->nid; dinfo++) {
222         if (dinfo->alias)
223             EVP_delete_digest_alias(dinfo->alias);
224         dinfo->destroy();
225     }
226
227     int i;
228     for (i = 0; i < OSSL_NELEM(gost_cipher_array); i++)
229         GOST_deinit_cipher(gost_cipher_array[i]);
230
231     gost_param_free();
232
233     struct gost_meth_minfo *minfo = gost_meth_array;
234     for (; minfo->nid; minfo++) {
235         *minfo->pmeth = NULL;
236         *minfo->ameth = NULL;
237     }
238
239     ERR_unload_GOST_strings();
240
241     return 1;
242 }
243
244 static int bind_gost(ENGINE* e, const char* id) {
245     int ret = 0;
246     if (id != NULL && strcmp(id, engine_gost_id) != 0)
247         return 0;
248     if (ameth_GostR3410_2001) {
249         printf("GOST engine already loaded\n");
250         goto end;
251     }
252     if (!ENGINE_set_id(e, engine_gost_id)) {
253         printf("ENGINE_set_id failed\n");
254         goto end;
255     }
256     if (!ENGINE_set_name(e, engine_gost_name)) {
257         printf("ENGINE_set_name failed\n");
258         goto end;
259     }
260     if (!ENGINE_set_digests(e, gost_digests)) {
261         printf("ENGINE_set_digests failed\n");
262         goto end;
263     }
264     if (!ENGINE_set_ciphers(e, gost_ciphers)) {
265         printf("ENGINE_set_ciphers failed\n");
266         goto end;
267     }
268     if (!ENGINE_set_pkey_meths(e, gost_pkey_meths)) {
269         printf("ENGINE_set_pkey_meths failed\n");
270         goto end;
271     }
272     if (!ENGINE_set_pkey_asn1_meths(e, gost_pkey_asn1_meths)) {
273         printf("ENGINE_set_pkey_asn1_meths failed\n");
274         goto end;
275     }
276     /* Control function and commands */
277     if (!ENGINE_set_cmd_defns(e, gost_cmds)) {
278         fprintf(stderr, "ENGINE_set_cmd_defns failed\n");
279         goto end;
280     }
281     if (!ENGINE_set_ctrl_function(e, gost_control_func)) {
282         fprintf(stderr, "ENGINE_set_ctrl_func failed\n");
283         goto end;
284     }
285     if (!ENGINE_set_destroy_function(e, gost_engine_destroy)
286         || !ENGINE_set_init_function(e, gost_engine_init)
287         || !ENGINE_set_finish_function(e, gost_engine_finish)) {
288         goto end;
289     }
290
291     struct gost_meth_minfo *minfo = gost_meth_array;
292     for (; minfo->nid; minfo++) {
293
294         /* This skip looks temporary. */
295         if (minfo->nid == NID_id_tc26_cipher_gostr3412_2015_magma_ctracpkm_omac)
296             continue;
297
298         if (!register_ameth_gost(minfo->nid, minfo->ameth, minfo->pemstr,
299                 minfo->info))
300             goto end;
301         if (!register_pmeth_gost(minfo->nid, minfo->pmeth, 0))
302             goto end;
303     }
304
305     if (!ENGINE_register_ciphers(e)
306         || !ENGINE_register_digests(e)
307         || !ENGINE_register_pkey_meths(e))
308         goto end;
309
310     int i;
311     for (i = 0; i < OSSL_NELEM(gost_cipher_array); i++) {
312         if (!EVP_add_cipher(GOST_init_cipher(gost_cipher_array[i])))
313             goto end;
314     }
315
316     struct gost_digest_minfo *dinfo = gost_digest_array;
317     for (; dinfo->nid; dinfo++) {
318         if (!EVP_add_digest(dinfo->digest()))
319             goto end;
320         if (dinfo->alias &&
321             !EVP_add_digest_alias(dinfo->sn, dinfo->alias))
322             goto end;
323     }
324
325     ENGINE_register_all_complete();
326
327     ERR_load_GOST_strings();
328     ret = 1;
329     end:
330     return ret;
331 }
332
333 #ifndef OPENSSL_NO_DYNAMIC_ENGINE
334 IMPLEMENT_DYNAMIC_BIND_FN(bind_gost)
335     IMPLEMENT_DYNAMIC_CHECK_FN()
336 #endif                          /* ndef OPENSSL_NO_DYNAMIC_ENGINE */
337
338 /* ENGINE_DIGESTS_PTR callback installed by ENGINE_set_digests */
339 static int gost_digests(ENGINE *e, const EVP_MD **digest,
340                         const int **nids, int nid)
341 {
342     struct gost_digest_minfo *info = gost_digest_array;
343
344     if (!digest) {
345         int *n = known_digest_nids;
346
347         *nids = n;
348         for (; info->nid; info++)
349             *n++ = info->nid;
350         return OSSL_NELEM(known_digest_nids);
351     }
352
353     for (; info->nid; info++)
354         if (nid == info->nid) {
355             *digest = info->digest();
356             return 1;
357         }
358     *digest = NULL;
359     return 0;
360 }
361
362 /* ENGINE_CIPHERS_PTR callback installed by ENGINE_set_ciphers */
363 static int gost_ciphers(ENGINE *e, const EVP_CIPHER **cipher,
364                         const int **nids, int nid)
365 {
366     int i;
367
368     if (!cipher) {
369         int *n = known_cipher_nids;
370
371         *nids = n;
372         for (i = 0; i < OSSL_NELEM(gost_cipher_array); i++)
373             *n++ = gost_cipher_array[i]->nid;
374         return i;
375     }
376
377     for (i = 0; i < OSSL_NELEM(gost_cipher_array); i++)
378         if (nid == gost_cipher_array[i]->nid) {
379             *cipher = GOST_init_cipher(gost_cipher_array[i]);
380             return 1;
381         }
382     *cipher = NULL;
383     return 0;
384 }
385
386 static int gost_meth_nids(const int **nids)
387 {
388     struct gost_meth_minfo *info = gost_meth_array;
389     int *n = known_meths_nids;
390
391     *nids = n;
392     for (; info->nid; info++)
393         *n++ = info->nid;
394     return OSSL_NELEM(known_meths_nids);
395 }
396
397 /* ENGINE_PKEY_METHS_PTR installed by ENGINE_set_pkey_meths */
398 static int gost_pkey_meths(ENGINE *e, EVP_PKEY_METHOD **pmeth,
399                            const int **nids, int nid)
400 {
401     struct gost_meth_minfo *info;
402
403     if (!pmeth)
404         return gost_meth_nids(nids);
405
406     for (info = gost_meth_array; info->nid; info++)
407         if (nid == info->nid) {
408             *pmeth = *info->pmeth;
409             return 1;
410         }
411     *pmeth = NULL;
412     return 0;
413 }
414
415 /* ENGINE_PKEY_ASN1_METHS_PTR installed by ENGINE_set_pkey_asn1_meths */
416 static int gost_pkey_asn1_meths(ENGINE *e, EVP_PKEY_ASN1_METHOD **ameth,
417                                 const int **nids, int nid)
418 {
419     struct gost_meth_minfo *info;
420
421     if (!ameth)
422         return gost_meth_nids(nids);
423
424     for (info = gost_meth_array; info->nid; info++)
425         if (nid == info->nid) {
426             *ameth = *info->ameth;
427             return 1;
428         }
429     *ameth = NULL;
430     return 0;
431 }
432
433 #ifdef OPENSSL_NO_DYNAMIC_ENGINE
434
435 static ENGINE* engine_gost(void) {
436     ENGINE* ret = ENGINE_new();
437     if (!ret)
438         return NULL;
439     if (!bind_gost(ret, engine_gost_id)) {
440         ENGINE_free(ret);
441         return NULL;
442     }
443     return ret;
444 }
445
446 void ENGINE_load_gost(void) {
447     ENGINE* toadd;
448     if (pmeth_GostR3410_2001)
449         return;
450     toadd = engine_gost();
451     if (!toadd)
452         return;
453     ENGINE_add(toadd);
454     ENGINE_free(toadd);
455     ERR_clear_error();
456 }
457
458 #endif
459 /* vim: set expandtab cinoptions=\:0,l1,t0,g0,(0 sw=4 : */