1 /**********************************************************************
3 * Main file of GOST engine *
5 * Copyright (c) 2005-2006 Cryptocom LTD *
6 * Copyright (c) 2020 Chikunov Vitaly <vt@altlinux.org> *
8 * This file is distributed under the same license as OpenSSL *
10 **********************************************************************/
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"
19 #include "gost-engine.h"
21 #include "gost_grasshopper_cipher.h"
23 static const char* engine_gost_id = "gost";
25 static const char* engine_gost_name =
26 "Reference implementation of GOST engine";
28 const ENGINE_CMD_DEFN gost_cmds[] = {
29 {GOST_CTRL_CRYPT_PARAMS,
31 "OID of default GOST 28147-89 parameters",
32 ENGINE_CMD_FLAG_STRING},
33 {GOST_CTRL_PBE_PARAMS,
35 "Shortname of default digest alg for PBE",
36 ENGINE_CMD_FLAG_STRING},
39 "Private key format params",
40 ENGINE_CMD_FLAG_STRING},
44 /* Symmetric cipher and digest function registrar */
46 static int gost_ciphers(ENGINE* e, const EVP_CIPHER** cipher,
47 const int** nids, int nid);
49 static int gost_digests(ENGINE* e, const EVP_MD** digest,
50 const int** nids, int nid);
52 static int gost_pkey_meths(ENGINE* e, EVP_PKEY_METHOD** pmeth,
53 const int** nids, int nid);
55 static int gost_pkey_asn1_meths(ENGINE* e, EVP_PKEY_ASN1_METHOD** ameth,
56 const int** nids, int nid);
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;
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;
74 GOST_digest *gost_digest_array[] = {
76 &Gost28147_89_MAC_digest,
77 &GostR3411_2012_256_digest,
78 &GostR3411_2012_512_digest,
79 &Gost28147_89_mac_12_digest,
81 &grasshopper_mac_digest,
82 &kuznyechik_ctracpkm_omac_digest,
85 GOST_cipher *gost_cipher_array[] = {
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,
96 &grasshopper_mgm_cipher,
99 &magma_ctr_acpkm_cipher,
100 &magma_ctr_acpkm_omac_cipher,
102 &grasshopper_ctr_acpkm_cipher,
103 &grasshopper_ctr_acpkm_omac_cipher,
104 &magma_kexp15_cipher,
105 &kuznyechik_kexp15_cipher,
108 static struct gost_meth_minfo {
110 EVP_PKEY_METHOD **pmeth;
111 EVP_PKEY_ASN1_METHOD **ameth;
114 } gost_meth_array[] = {
116 NID_id_GostR3410_2001,
117 &pmeth_GostR3410_2001,
118 &ameth_GostR3410_2001,
123 NID_id_GostR3410_2001DH,
124 &pmeth_GostR3410_2001DH,
125 &ameth_GostR3410_2001DH,
127 "GOST R 34.10-2001 DH",
130 NID_id_Gost28147_89_MAC,
131 &pmeth_Gost28147_MAC,
132 &ameth_Gost28147_MAC,
137 NID_id_GostR3410_2012_256,
138 &pmeth_GostR3410_2012_256,
139 &ameth_GostR3410_2012_256,
141 "GOST R 34.10-2012 with 256 bit key",
144 NID_id_GostR3410_2012_512,
145 &pmeth_GostR3410_2012_512,
146 &ameth_GostR3410_2012_512,
148 "GOST R 34.10-2012 with 512 bit key",
152 &pmeth_Gost28147_MAC_12,
153 &ameth_Gost28147_MAC_12,
155 "GOST 28147-89 MAC with 2012 params",
162 "GOST R 34.13-2015 Magma MAC",
166 &pmeth_grasshopper_mac,
167 &ameth_grasshopper_mac,
169 "GOST R 34.13-2015 Grasshopper MAC",
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",
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",
189 # define OSSL_NELEM(x) (sizeof(x)/sizeof((x)[0]))
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];
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)
204 int *n = known_digest_nids;
207 for (i = 0; i < OSSL_NELEM(gost_digest_array); i++)
208 *n++ = gost_digest_array[i]->nid;
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]);
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)
228 int *n = known_cipher_nids;
231 for (i = 0; i < OSSL_NELEM(gost_cipher_array); i++)
232 *n++ = gost_cipher_array[i]->nid;
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]);
245 static int gost_meth_nids(const int **nids)
247 struct gost_meth_minfo *info = gost_meth_array;
248 int *n = known_meths_nids;
251 for (; info->nid; info++)
253 return OSSL_NELEM(known_meths_nids);
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)
260 struct gost_meth_minfo *info;
263 return gost_meth_nids(nids);
265 for (info = gost_meth_array; info->nid; info++)
266 if (nid == info->nid) {
267 *pmeth = *info->pmeth;
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)
278 struct gost_meth_minfo *info;
281 return gost_meth_nids(nids);
283 for (info = gost_meth_array; info->nid; info++)
284 if (nid == info->nid) {
285 *ameth = *info->ameth;
292 static int gost_engine_init(ENGINE* e) {
296 static int gost_engine_finish(ENGINE* e) {
300 static void free_NIDs();
302 static int gost_engine_destroy(ENGINE* e) {
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]);
312 struct gost_meth_minfo *minfo = gost_meth_array;
313 for (; minfo->nid; minfo++) {
314 *minfo->pmeth = NULL;
315 *minfo->ameth = NULL;
318 free_cached_groups();
321 # ifndef BUILDING_GOST_PROVIDER
322 ERR_unload_GOST_strings();
329 * Following is the glue that populates the ENGINE structure and that
330 * binds it to OpenSSL libraries
333 static GOST_NID_JOB *missing_NIDs[] = {
338 static int create_NIDs() {
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];
344 ASN1_OBJECT_create(new_nid + i, NULL, 0, job->sn, job->ln);
346 if (!obj || OBJ_add_object(obj) == NID_undef) {
350 (*missing_NIDs[i]->callback)(new_nid + i);
355 static void free_NIDs() {
357 for (i = 0; i < OSSL_NELEM(missing_NIDs); i++) {
358 ASN1_OBJECT_free(missing_NIDs[i]->asn1);
362 # ifndef BUILDING_GOST_PROVIDER
365 int populate_gost_engine(ENGINE* e) {
370 if (!ENGINE_set_id(e, engine_gost_id)) {
371 fprintf(stderr, "ENGINE_set_id failed\n");
374 if (!ENGINE_set_name(e, engine_gost_name)) {
375 fprintf(stderr, "ENGINE_set_name failed\n");
378 if (!create_NIDs()) {
379 fprintf(stderr, "NID creation failed\n");
382 if (!ENGINE_set_digests(e, gost_digests)) {
383 fprintf(stderr, "ENGINE_set_digests failed\n");
386 if (!ENGINE_set_ciphers(e, gost_ciphers)) {
387 fprintf(stderr, "ENGINE_set_ciphers failed\n");
390 if (!ENGINE_set_pkey_meths(e, gost_pkey_meths)) {
391 fprintf(stderr, "ENGINE_set_pkey_meths failed\n");
394 if (!ENGINE_set_pkey_asn1_meths(e, gost_pkey_asn1_meths)) {
395 fprintf(stderr, "ENGINE_set_pkey_asn1_meths failed\n");
398 /* Control function and commands */
399 if (!ENGINE_set_cmd_defns(e, gost_cmds)) {
400 fprintf(stderr, "ENGINE_set_cmd_defns failed\n");
403 if (!ENGINE_set_ctrl_function(e, gost_control_func)) {
404 fprintf(stderr, "ENGINE_set_ctrl_func failed\n");
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)) {
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.
419 struct gost_meth_minfo *minfo = gost_meth_array;
420 for (; minfo->nid; minfo++) {
422 /* This skip looks temporary. */
423 if (minfo->nid == NID_id_tc26_cipher_gostr3412_2015_magma_ctracpkm_omac)
426 if (!register_ameth_gost(minfo->nid, minfo->ameth, minfo->pemstr,
429 if (!register_pmeth_gost(minfo->nid, minfo->pmeth, 0))
438 #ifndef BUILDING_GOST_PROVIDER
439 static int bind_gost_engine(ENGINE* e) {
442 if (!ENGINE_register_ciphers(e)
443 || !ENGINE_register_digests(e)
444 || !ENGINE_register_pkey_meths(e))
448 for (i = 0; i < OSSL_NELEM(gost_cipher_array); i++) {
449 if (!EVP_add_cipher(GOST_init_cipher(gost_cipher_array[i])))
453 for (i = 0; i < OSSL_NELEM(gost_digest_array); i++) {
454 if (!EVP_add_digest(GOST_init_digest(gost_digest_array[i])))
458 ENGINE_register_all_complete();
460 ERR_load_GOST_strings();
466 static int check_gost_engine(ENGINE* e, const char* id)
468 if (id != NULL && strcmp(id, engine_gost_id) != 0)
470 if (ameth_GostR3410_2001) {
471 printf("GOST engine already loaded\n");
477 static int make_gost_engine(ENGINE* e, const char* id)
479 return check_gost_engine(e, id)
480 && populate_gost_engine(e)
481 && bind_gost_engine(e);
484 #ifndef BUILDING_ENGINE_AS_LIBRARY
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.
492 IMPLEMENT_DYNAMIC_BIND_FN(make_gost_engine)
493 IMPLEMENT_DYNAMIC_CHECK_FN()
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.
502 void ENGINE_load_gost(void) {
506 if ((toadd = ENGINE_new()) != NULL
507 && (ret = make_gost_engine(toadd, engine_gost_id)) > 0)
515 /* vim: set expandtab cinoptions=\:0,l1,t0,g0,(0 sw=4 : */