1 /**********************************************************************
2  *                          gost_eng.c                                *
3  *             Copyright (c) 2005-2006 Cryptocom LTD                  *
4  *         This file is distributed under the same license as OpenSSL *
5  *                                                                    *
6  *              Main file of GOST engine                              *
7  *       for OpenSSL                                                  *
8  *          Requires OpenSSL 0.9.9 for compilation                    *
9  **********************************************************************/
10 #include <string.h>
11 #include <openssl/crypto.h>
12 #include <openssl/err.h>
13 #include <openssl/evp.h>
14 #include <openssl/engine.h>
15 #include <openssl/obj_mac.h>
16 #include "e_gost_err.h"
17 #include "gost_lcl.h"
18 static const char *engine_gost_id = "gost";
19 static const char *engine_gost_name =
20     "Reference implementation of GOST engine";
21 
22 /* Symmetric cipher and digest function registrar */
23 
24 static int gost_ciphers(ENGINE *e, const EVP_CIPHER **cipher,
25                         const int **nids, int nid);
26 
27 static int gost_digests(ENGINE *e, const EVP_MD **digest,
28                         const int **nids, int ind);
29 
30 static int gost_pkey_meths(ENGINE *e, EVP_PKEY_METHOD **pmeth,
31                            const int **nids, int nid);
32 
33 static int gost_pkey_asn1_meths(ENGINE *e, EVP_PKEY_ASN1_METHOD **ameth,
34                                 const int **nids, int nid);
35 
36 static int gost_cipher_nids[] = { NID_id_Gost28147_89, NID_gost89_cnt, 0 };
37 
38 static int gost_digest_nids[] =
39     { NID_id_GostR3411_94, NID_id_Gost28147_89_MAC, 0 };
40 
41 static int gost_pkey_meth_nids[] = { NID_id_GostR3410_94,
42     NID_id_GostR3410_2001, NID_id_Gost28147_89_MAC, 0
43 };
44 
45 static EVP_PKEY_METHOD *pmeth_GostR3410_94 = NULL,
46     *pmeth_GostR3410_2001 = NULL, *pmeth_Gost28147_MAC = NULL;
47 
48 static EVP_PKEY_ASN1_METHOD *ameth_GostR3410_94 = NULL,
49     *ameth_GostR3410_2001 = NULL, *ameth_Gost28147_MAC = NULL;
50 
gost_engine_init(ENGINE * e)51 static int gost_engine_init(ENGINE *e)
52 {
53     return 1;
54 }
55 
gost_engine_finish(ENGINE * e)56 static int gost_engine_finish(ENGINE *e)
57 {
58     return 1;
59 }
60 
gost_engine_destroy(ENGINE * e)61 static int gost_engine_destroy(ENGINE *e)
62 {
63     gost_param_free();
64 
65     pmeth_GostR3410_94 = NULL;
66     pmeth_GostR3410_2001 = NULL;
67     pmeth_Gost28147_MAC = NULL;
68     ameth_GostR3410_94 = NULL;
69     ameth_GostR3410_2001 = NULL;
70     ameth_Gost28147_MAC = NULL;
71     return 1;
72 }
73 
bind_gost(ENGINE * e,const char * id)74 static int bind_gost(ENGINE *e, const char *id)
75 {
76     int ret = 0;
77     if (id && strcmp(id, engine_gost_id))
78         return 0;
79     if (ameth_GostR3410_94) {
80         printf("GOST engine already loaded\n");
81         goto end;
82     }
83 
84     if (!ENGINE_set_id(e, engine_gost_id)) {
85         printf("ENGINE_set_id failed\n");
86         goto end;
87     }
88     if (!ENGINE_set_name(e, engine_gost_name)) {
89         printf("ENGINE_set_name failed\n");
90         goto end;
91     }
92     if (!ENGINE_set_digests(e, gost_digests)) {
93         printf("ENGINE_set_digests failed\n");
94         goto end;
95     }
96     if (!ENGINE_set_ciphers(e, gost_ciphers)) {
97         printf("ENGINE_set_ciphers failed\n");
98         goto end;
99     }
100     if (!ENGINE_set_pkey_meths(e, gost_pkey_meths)) {
101         printf("ENGINE_set_pkey_meths failed\n");
102         goto end;
103     }
104     if (!ENGINE_set_pkey_asn1_meths(e, gost_pkey_asn1_meths)) {
105         printf("ENGINE_set_pkey_asn1_meths failed\n");
106         goto end;
107     }
108     /* Control function and commands */
109     if (!ENGINE_set_cmd_defns(e, gost_cmds)) {
110         fprintf(stderr, "ENGINE_set_cmd_defns failed\n");
111         goto end;
112     }
113     if (!ENGINE_set_ctrl_function(e, gost_control_func)) {
114         fprintf(stderr, "ENGINE_set_ctrl_func failed\n");
115         goto end;
116     }
117     if (!ENGINE_set_destroy_function(e, gost_engine_destroy)
118         || !ENGINE_set_init_function(e, gost_engine_init)
119         || !ENGINE_set_finish_function(e, gost_engine_finish)) {
120         goto end;
121     }
122 
123     if (!register_ameth_gost
124         (NID_id_GostR3410_94, &ameth_GostR3410_94, "GOST94",
125          "GOST R 34.10-94"))
126         goto end;
127     if (!register_ameth_gost
128         (NID_id_GostR3410_2001, &ameth_GostR3410_2001, "GOST2001",
129          "GOST R 34.10-2001"))
130         goto end;
131     if (!register_ameth_gost(NID_id_Gost28147_89_MAC, &ameth_Gost28147_MAC,
132                              "GOST-MAC", "GOST 28147-89 MAC"))
133         goto end;
134 
135     if (!register_pmeth_gost(NID_id_GostR3410_94, &pmeth_GostR3410_94, 0))
136         goto end;
137     if (!register_pmeth_gost(NID_id_GostR3410_2001, &pmeth_GostR3410_2001, 0))
138         goto end;
139     if (!register_pmeth_gost
140         (NID_id_Gost28147_89_MAC, &pmeth_Gost28147_MAC, 0))
141         goto end;
142     if (!ENGINE_register_ciphers(e)
143         || !ENGINE_register_digests(e)
144         || !ENGINE_register_pkey_meths(e)
145         /* These two actually should go in LIST_ADD command */
146         || !EVP_add_cipher(&cipher_gost)
147         || !EVP_add_cipher(&cipher_gost_cpacnt)
148         || !EVP_add_digest(&digest_gost)
149         || !EVP_add_digest(&imit_gost_cpa)
150         ) {
151         goto end;
152     }
153 
154     ERR_load_GOST_strings();
155     ret = 1;
156  end:
157     return ret;
158 }
159 
160 #ifndef OPENSSL_NO_DYNAMIC_ENGINE
161 IMPLEMENT_DYNAMIC_BIND_FN(bind_gost)
IMPLEMENT_DYNAMIC_CHECK_FN()162     IMPLEMENT_DYNAMIC_CHECK_FN()
163 #endif                          /* ndef OPENSSL_NO_DYNAMIC_ENGINE */
164 static int gost_digests(ENGINE *e, const EVP_MD **digest,
165                         const int **nids, int nid)
166 {
167     int ok = 1;
168     if (!digest) {
169         *nids = gost_digest_nids;
170         return 2;
171     }
172     /*
173      * printf("Digest no %d requested\n",nid);
174      */
175     if (nid == NID_id_GostR3411_94) {
176         *digest = &digest_gost;
177     } else if (nid == NID_id_Gost28147_89_MAC) {
178         *digest = &imit_gost_cpa;
179     } else {
180         ok = 0;
181         *digest = NULL;
182     }
183     return ok;
184 }
185 
gost_ciphers(ENGINE * e,const EVP_CIPHER ** cipher,const int ** nids,int nid)186 static int gost_ciphers(ENGINE *e, const EVP_CIPHER **cipher,
187                         const int **nids, int nid)
188 {
189     int ok = 1;
190     if (!cipher) {
191         *nids = gost_cipher_nids;
192         return 2;               /* two ciphers are supported */
193     }
194 
195     if (nid == NID_id_Gost28147_89) {
196         *cipher = &cipher_gost;
197     } else if (nid == NID_gost89_cnt) {
198         *cipher = &cipher_gost_cpacnt;
199     } else {
200         ok = 0;
201         *cipher = NULL;
202     }
203     return ok;
204 }
205 
gost_pkey_meths(ENGINE * e,EVP_PKEY_METHOD ** pmeth,const int ** nids,int nid)206 static int gost_pkey_meths(ENGINE *e, EVP_PKEY_METHOD **pmeth,
207                            const int **nids, int nid)
208 {
209     if (!pmeth) {
210         *nids = gost_pkey_meth_nids;
211         return 3;
212     }
213 
214     switch (nid) {
215     case NID_id_GostR3410_94:
216         *pmeth = pmeth_GostR3410_94;
217         return 1;
218     case NID_id_GostR3410_2001:
219         *pmeth = pmeth_GostR3410_2001;
220         return 1;
221     case NID_id_Gost28147_89_MAC:
222         *pmeth = pmeth_Gost28147_MAC;
223         return 1;
224     default:;
225     }
226 
227     *pmeth = NULL;
228     return 0;
229 }
230 
gost_pkey_asn1_meths(ENGINE * e,EVP_PKEY_ASN1_METHOD ** ameth,const int ** nids,int nid)231 static int gost_pkey_asn1_meths(ENGINE *e, EVP_PKEY_ASN1_METHOD **ameth,
232                                 const int **nids, int nid)
233 {
234     if (!ameth) {
235         *nids = gost_pkey_meth_nids;
236         return 3;
237     }
238     switch (nid) {
239     case NID_id_GostR3410_94:
240         *ameth = ameth_GostR3410_94;
241         return 1;
242     case NID_id_GostR3410_2001:
243         *ameth = ameth_GostR3410_2001;
244         return 1;
245     case NID_id_Gost28147_89_MAC:
246         *ameth = ameth_Gost28147_MAC;
247         return 1;
248 
249     default:;
250     }
251 
252     *ameth = NULL;
253     return 0;
254 }
255 
256 #ifdef OPENSSL_NO_DYNAMIC_ENGINE
engine_gost(void)257 static ENGINE *engine_gost(void)
258 {
259     ENGINE *ret = ENGINE_new();
260     if (!ret)
261         return NULL;
262     if (!bind_gost(ret, engine_gost_id)) {
263         ENGINE_free(ret);
264         return NULL;
265     }
266     return ret;
267 }
268 
ENGINE_load_gost(void)269 void ENGINE_load_gost(void)
270 {
271     ENGINE *toadd;
272     if (pmeth_GostR3410_94)
273         return;
274     toadd = engine_gost();
275     if (!toadd)
276         return;
277     ENGINE_add(toadd);
278     ENGINE_free(toadd);
279     ERR_clear_error();
280 }
281 #endif
282