]> www.wagner.pp.ru Git - openssl-gost/engine.git/blob - gost_eng.c
tcl_tests: ca.try: Ignore openssl crl exit status for 'corrupted CRL' test
[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 #include "gost-engine.h"
20
21 #include "gost_grasshopper_cipher.h"
22
23 static const char* engine_gost_id = "gost";
24
25 static const char* engine_gost_name =
26         "Reference implementation of GOST engine";
27
28 const ENGINE_CMD_DEFN gost_cmds[] = {
29     {GOST_CTRL_CRYPT_PARAMS,
30      "CRYPT_PARAMS",
31      "OID of default GOST 28147-89 parameters",
32      ENGINE_CMD_FLAG_STRING},
33     {GOST_CTRL_PBE_PARAMS,
34      "PBE_PARAMS",
35      "Shortname of default digest alg for PBE",
36      ENGINE_CMD_FLAG_STRING},
37     {GOST_CTRL_PK_FORMAT,
38      "GOST_PK_FORMAT",
39      "Private key format params",
40      ENGINE_CMD_FLAG_STRING},
41     {0, NULL, NULL, 0}
42 };
43
44 /* Symmetric cipher and digest function registrar */
45
46 static int gost_ciphers(ENGINE* e, const EVP_CIPHER** cipher,
47                         const int** nids, int nid);
48
49 static int gost_digests(ENGINE* e, const EVP_MD** digest,
50                         const int** nids, int nid);
51
52 static int gost_pkey_meths(ENGINE* e, EVP_PKEY_METHOD** pmeth,
53                            const int** nids, int nid);
54
55 static int gost_pkey_asn1_meths(ENGINE* e, EVP_PKEY_ASN1_METHOD** ameth,
56                                 const int** nids, int nid);
57
58 static EVP_PKEY_METHOD* pmeth_GostR3410_2001 = NULL,
59         * pmeth_GostR3410_2001DH = NULL,
60         * pmeth_GostR3410_2012_256 = NULL,
61         * pmeth_GostR3410_2012_512 = NULL,
62         * pmeth_Gost28147_MAC = NULL, * pmeth_Gost28147_MAC_12 = NULL,
63         * pmeth_magma_mac = NULL,  * pmeth_grasshopper_mac = NULL,
64         * pmeth_magma_mac_acpkm = NULL,  * pmeth_grasshopper_mac_acpkm = NULL;
65
66 static EVP_PKEY_ASN1_METHOD* ameth_GostR3410_2001 = NULL,
67         * ameth_GostR3410_2001DH = NULL,
68         * ameth_GostR3410_2012_256 = NULL,
69         * ameth_GostR3410_2012_512 = NULL,
70         * ameth_Gost28147_MAC = NULL, * ameth_Gost28147_MAC_12 = NULL,
71         * ameth_magma_mac = NULL,  * ameth_grasshopper_mac = NULL,
72         * ameth_magma_mac_acpkm = NULL,  * ameth_grasshopper_mac_acpkm = NULL;
73
74 GOST_digest *gost_digest_array[] = {
75     &GostR3411_94_digest,
76     &Gost28147_89_MAC_digest,
77     &GostR3411_2012_256_digest,
78     &GostR3411_2012_512_digest,
79     &Gost28147_89_mac_12_digest,
80     &magma_mac_digest,
81     &grasshopper_mac_digest,
82     &kuznyechik_ctracpkm_omac_digest,
83 };
84
85 GOST_cipher *gost_cipher_array[] = {
86     &Gost28147_89_cipher,
87     &Gost28147_89_cnt_cipher,
88     &Gost28147_89_cnt_12_cipher,
89     &Gost28147_89_cbc_cipher,
90     &grasshopper_ecb_cipher,
91     &grasshopper_cbc_cipher,
92     &grasshopper_cfb_cipher,
93     &grasshopper_ofb_cipher,
94     &grasshopper_ctr_cipher,
95     &magma_ecb_cipher,
96     &grasshopper_mgm_cipher,
97     &magma_cbc_cipher,
98     &magma_ctr_cipher,
99     &magma_ctr_acpkm_cipher,
100     &magma_ctr_acpkm_omac_cipher,
101     &magma_mgm_cipher,
102     &grasshopper_ctr_acpkm_cipher,
103     &grasshopper_ctr_acpkm_omac_cipher,
104     &magma_kexp15_cipher,
105     &kuznyechik_kexp15_cipher,
106 };
107
108 static struct gost_meth_minfo {
109     int nid;
110     EVP_PKEY_METHOD **pmeth;
111     EVP_PKEY_ASN1_METHOD **ameth;
112     const char *pemstr;
113     const char *info;
114 } gost_meth_array[] = {
115     {
116         NID_id_GostR3410_2001,
117         &pmeth_GostR3410_2001,
118         &ameth_GostR3410_2001,
119         "GOST2001",
120         "GOST R 34.10-2001",
121     },
122     {
123         NID_id_GostR3410_2001DH,
124         &pmeth_GostR3410_2001DH,
125         &ameth_GostR3410_2001DH,
126         "GOST2001 DH",
127         "GOST R 34.10-2001 DH",
128     },
129     {
130         NID_id_Gost28147_89_MAC,
131         &pmeth_Gost28147_MAC,
132         &ameth_Gost28147_MAC,
133         "GOST-MAC",
134         "GOST 28147-89 MAC",
135     },
136     {
137         NID_id_GostR3410_2012_256,
138         &pmeth_GostR3410_2012_256,
139         &ameth_GostR3410_2012_256,
140         "GOST2012_256",
141         "GOST R 34.10-2012 with 256 bit key",
142     },
143     {
144         NID_id_GostR3410_2012_512,
145         &pmeth_GostR3410_2012_512,
146         &ameth_GostR3410_2012_512,
147         "GOST2012_512",
148         "GOST R 34.10-2012 with 512 bit key",
149     },
150     {
151         NID_gost_mac_12,
152         &pmeth_Gost28147_MAC_12,
153         &ameth_Gost28147_MAC_12,
154         "GOST-MAC-12",
155         "GOST 28147-89 MAC with 2012 params",
156     },
157     {
158         NID_magma_mac,
159         &pmeth_magma_mac,
160         &ameth_magma_mac,
161         "MAGMA-MAC",
162         "GOST R 34.13-2015 Magma MAC",
163     },
164     {
165         NID_grasshopper_mac,
166         &pmeth_grasshopper_mac,
167         &ameth_grasshopper_mac,
168         "KUZNYECHIK-MAC",
169         "GOST R 34.13-2015 Grasshopper MAC",
170     },
171     {
172         NID_id_tc26_cipher_gostr3412_2015_magma_ctracpkm_omac,
173         &pmeth_magma_mac_acpkm,
174         &ameth_magma_mac_acpkm,
175         "ID-TC26-CIPHER-GOSTR3412-2015-MAGMA-CTRACPKM-OMAC",
176         "GOST R 34.13-2015 Magma MAC ACPKM",
177     },
178     {
179         NID_id_tc26_cipher_gostr3412_2015_kuznyechik_ctracpkm_omac,
180         &pmeth_grasshopper_mac_acpkm,
181         &ameth_grasshopper_mac_acpkm,
182         "ID-TC26-CIPHER-GOSTR3412-2015-KUZNYECHIK-CTRACPKM-OMAC",
183         "GOST R 34.13-2015 Grasshopper MAC ACPKM",
184     },
185     { 0 },
186 };
187
188 #ifndef OSSL_NELEM
189 # define OSSL_NELEM(x) (sizeof(x)/sizeof((x)[0]))
190 #endif
191
192 static int known_digest_nids[OSSL_NELEM(gost_digest_array)];
193 static int known_cipher_nids[OSSL_NELEM(gost_cipher_array)];
194 /* `- 1' because of terminating zero element */
195 static int known_meths_nids[OSSL_NELEM(gost_meth_array) - 1];
196
197 /* ENGINE_DIGESTS_PTR callback installed by ENGINE_set_digests */
198 static int gost_digests(ENGINE *e, const EVP_MD **digest,
199                         const int **nids, int nid)
200 {
201     int i;
202
203     if (!digest) {
204         int *n = known_digest_nids;
205
206         *nids = n;
207         for (i = 0; i < OSSL_NELEM(gost_digest_array); i++)
208             *n++ = gost_digest_array[i]->nid;
209         return i;
210     }
211
212     for (i = 0; i < OSSL_NELEM(gost_digest_array); i++)
213         if (nid == gost_digest_array[i]->nid) {
214             *digest = GOST_init_digest(gost_digest_array[i]);
215             return 1;
216         }
217     *digest = NULL;
218     return 0;
219 }
220
221 /* ENGINE_CIPHERS_PTR callback installed by ENGINE_set_ciphers */
222 static int gost_ciphers(ENGINE *e, const EVP_CIPHER **cipher,
223                         const int **nids, int nid)
224 {
225     int i;
226
227     if (!cipher) {
228         int *n = known_cipher_nids;
229
230         *nids = n;
231         for (i = 0; i < OSSL_NELEM(gost_cipher_array); i++)
232             *n++ = gost_cipher_array[i]->nid;
233         return i;
234     }
235
236     for (i = 0; i < OSSL_NELEM(gost_cipher_array); i++)
237         if (nid == gost_cipher_array[i]->nid) {
238             *cipher = GOST_init_cipher(gost_cipher_array[i]);
239             return 1;
240         }
241     *cipher = NULL;
242     return 0;
243 }
244
245 static int gost_meth_nids(const int **nids)
246 {
247     struct gost_meth_minfo *info = gost_meth_array;
248     int *n = known_meths_nids;
249
250     *nids = n;
251     for (; info->nid; info++)
252         *n++ = info->nid;
253     return OSSL_NELEM(known_meths_nids);
254 }
255
256 /* ENGINE_PKEY_METHS_PTR installed by ENGINE_set_pkey_meths */
257 static int gost_pkey_meths(ENGINE *e, EVP_PKEY_METHOD **pmeth,
258                            const int **nids, int nid)
259 {
260     struct gost_meth_minfo *info;
261
262     if (!pmeth)
263         return gost_meth_nids(nids);
264
265     for (info = gost_meth_array; info->nid; info++)
266         if (nid == info->nid) {
267             *pmeth = *info->pmeth;
268             return 1;
269         }
270     *pmeth = NULL;
271     return 0;
272 }
273
274 /* ENGINE_PKEY_ASN1_METHS_PTR installed by ENGINE_set_pkey_asn1_meths */
275 static int gost_pkey_asn1_meths(ENGINE *e, EVP_PKEY_ASN1_METHOD **ameth,
276                                 const int **nids, int nid)
277 {
278     struct gost_meth_minfo *info;
279
280     if (!ameth)
281         return gost_meth_nids(nids);
282
283     for (info = gost_meth_array; info->nid; info++)
284         if (nid == info->nid) {
285             *ameth = *info->ameth;
286             return 1;
287         }
288     *ameth = NULL;
289     return 0;
290 }
291
292 static int gost_engine_init(ENGINE* e) {
293     return 1;
294 }
295
296 static int gost_engine_finish(ENGINE* e) {
297     return 1;
298 }
299
300 static void free_NIDs();
301
302 static int gost_engine_destroy(ENGINE* e) {
303     int i;
304
305     for (i = 0; i < OSSL_NELEM(gost_digest_array); i++)
306         GOST_deinit_digest(gost_digest_array[i]);
307     for (i = 0; i < OSSL_NELEM(gost_cipher_array); i++)
308         GOST_deinit_cipher(gost_cipher_array[i]);
309
310     gost_param_free();
311
312     struct gost_meth_minfo *minfo = gost_meth_array;
313     for (; minfo->nid; minfo++) {
314         *minfo->pmeth = NULL;
315         *minfo->ameth = NULL;
316     }
317
318     free_cached_groups();
319     free_NIDs();
320
321 # ifndef BUILDING_GOST_PROVIDER
322     ERR_unload_GOST_strings();
323 # endif
324
325     return 1;
326 }
327
328 /*
329  * Following is the glue that populates the ENGINE structure and that
330  * binds it to OpenSSL libraries
331  */
332
333 static GOST_NID_JOB *missing_NIDs[] = {
334     &kuznyechik_mgm_NID,
335     &magma_mgm_NID,
336 };
337
338 static int create_NIDs() {
339     int i;
340     int new_nid = OBJ_new_nid(OSSL_NELEM(missing_NIDs));
341     for (i = 0; i < OSSL_NELEM(missing_NIDs); i++) {
342         GOST_NID_JOB *job = missing_NIDs[i];
343         ASN1_OBJECT *obj =
344             ASN1_OBJECT_create(new_nid + i, NULL, 0, job->sn, job->ln);
345         job->asn1 = obj;
346         if (!obj || OBJ_add_object(obj) == NID_undef) {
347             OPENSSL_free(obj);
348             return 0;
349         }
350         (*missing_NIDs[i]->callback)(new_nid + i);
351     }
352     return 1;
353 }
354
355 static void free_NIDs() {
356     int i;
357     for (i = 0; i < OSSL_NELEM(missing_NIDs); i++) {
358         ASN1_OBJECT_free(missing_NIDs[i]->asn1);
359     }
360 }
361
362 # ifndef BUILDING_GOST_PROVIDER
363 static
364 # endif
365 int populate_gost_engine(ENGINE* e) {
366     int ret = 0;
367
368     if (e == NULL)
369         goto end;
370     if (!ENGINE_set_id(e, engine_gost_id)) {
371         fprintf(stderr, "ENGINE_set_id failed\n");
372         goto end;
373     }
374     if (!ENGINE_set_name(e, engine_gost_name)) {
375         fprintf(stderr, "ENGINE_set_name failed\n");
376         goto end;
377     }
378     if (!create_NIDs()) {
379         fprintf(stderr, "NID creation failed\n");
380         goto end;
381     }
382     if (!ENGINE_set_digests(e, gost_digests)) {
383         fprintf(stderr, "ENGINE_set_digests failed\n");
384         goto end;
385     }
386     if (!ENGINE_set_ciphers(e, gost_ciphers)) {
387         fprintf(stderr, "ENGINE_set_ciphers failed\n");
388         goto end;
389     }
390     if (!ENGINE_set_pkey_meths(e, gost_pkey_meths)) {
391         fprintf(stderr, "ENGINE_set_pkey_meths failed\n");
392         goto end;
393     }
394     if (!ENGINE_set_pkey_asn1_meths(e, gost_pkey_asn1_meths)) {
395         fprintf(stderr, "ENGINE_set_pkey_asn1_meths failed\n");
396         goto end;
397     }
398     /* Control function and commands */
399     if (!ENGINE_set_cmd_defns(e, gost_cmds)) {
400         fprintf(stderr, "ENGINE_set_cmd_defns failed\n");
401         goto end;
402     }
403     if (!ENGINE_set_ctrl_function(e, gost_control_func)) {
404         fprintf(stderr, "ENGINE_set_ctrl_func failed\n");
405         goto end;
406     }
407     if (!ENGINE_set_destroy_function(e, gost_engine_destroy)
408         || !ENGINE_set_init_function(e, gost_engine_init)
409         || !ENGINE_set_finish_function(e, gost_engine_finish)) {
410         goto end;
411     }
412
413     /*
414      * "register" in "register_ameth_gost" and "register_pmeth_gost" is
415      * not registering in an ENGINE sense, where things are hooked into
416      * OpenSSL's library.  "register_ameth_gost" and "register_pmeth_gost"
417      * merely allocate and populate the method structures of this engine.
418      */
419     struct gost_meth_minfo *minfo = gost_meth_array;
420     for (; minfo->nid; minfo++) {
421
422         /* This skip looks temporary. */
423         if (minfo->nid == NID_id_tc26_cipher_gostr3412_2015_magma_ctracpkm_omac)
424             continue;
425
426         if (!register_ameth_gost(minfo->nid, minfo->ameth, minfo->pemstr,
427                 minfo->info))
428             goto end;
429         if (!register_pmeth_gost(minfo->nid, minfo->pmeth, 0))
430             goto end;
431     }
432
433     ret = 1;
434   end:
435     return ret;
436 }
437
438 #ifndef BUILDING_GOST_PROVIDER
439 static int bind_gost_engine(ENGINE* e) {
440     int ret = 0;
441
442     if (!ENGINE_register_ciphers(e)
443         || !ENGINE_register_digests(e)
444         || !ENGINE_register_pkey_meths(e))
445         goto end;
446
447     int i;
448     for (i = 0; i < OSSL_NELEM(gost_cipher_array); i++) {
449         if (!EVP_add_cipher(GOST_init_cipher(gost_cipher_array[i])))
450             goto end;
451     }
452
453     for (i = 0; i < OSSL_NELEM(gost_digest_array); i++) {
454         if (!EVP_add_digest(GOST_init_digest(gost_digest_array[i])))
455             goto end;
456     }
457
458     ENGINE_register_all_complete();
459
460     ERR_load_GOST_strings();
461     ret = 1;
462   end:
463     return ret;
464 }
465
466 static int check_gost_engine(ENGINE* e, const char* id)
467 {
468     if (id != NULL && strcmp(id, engine_gost_id) != 0)
469         return 0;
470     if (ameth_GostR3410_2001) {
471         printf("GOST engine already loaded\n");
472         return 0;
473     }
474     return 1;
475 }
476
477 static int make_gost_engine(ENGINE* e, const char* id)
478 {
479     return check_gost_engine(e, id)
480         && populate_gost_engine(e)
481         && bind_gost_engine(e);
482 }
483
484 #ifndef BUILDING_ENGINE_AS_LIBRARY
485
486 /*
487  * When building gost-engine as a dynamically loadable module, these two
488  * lines do everything that's needed, and OpenSSL's libcrypto will be able
489  * to call its entry points, v_check and bind_engine.
490  */
491
492 IMPLEMENT_DYNAMIC_BIND_FN(make_gost_engine)
493 IMPLEMENT_DYNAMIC_CHECK_FN()
494
495 #else
496
497 /*
498  * When building gost-engine as a shared library, the application that uses
499  * it must manually call ENGINE_load_gost() for it to bind itself into the
500  * libcrypto libraries.
501  */
502 void ENGINE_load_gost(void) {
503     ENGINE* toadd;
504     int ret = 0;
505
506     if ((toadd = ENGINE_new()) != NULL
507         && (ret = make_gost_engine(toadd, engine_gost_id)) > 0)
508         ENGINE_add(toadd);
509     ENGINE_free(toadd);
510     if (ret > 0)
511         ERR_clear_error();
512 }
513 #endif
514 #endif
515 /* vim: set expandtab cinoptions=\:0,l1,t0,g0,(0 sw=4 : */