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"
18static const char *engine_gost_id = "gost";
19static const char *engine_gost_name =
20    "Reference implementation of GOST engine";
21
22/* Symmetric cipher and digest function registrar */
23
24static int gost_ciphers(ENGINE *e, const EVP_CIPHER **cipher,
25                        const int **nids, int nid);
26
27static int gost_digests(ENGINE *e, const EVP_MD **digest,
28                        const int **nids, int ind);
29
30static int gost_pkey_meths(ENGINE *e, EVP_PKEY_METHOD **pmeth,
31                           const int **nids, int nid);
32
33static int gost_pkey_asn1_meths(ENGINE *e, EVP_PKEY_ASN1_METHOD **ameth,
34                                const int **nids, int nid);
35
36static int gost_cipher_nids[] = { NID_id_Gost28147_89, NID_gost89_cnt, 0 };
37
38static int gost_digest_nids[] =
39    { NID_id_GostR3411_94, NID_id_Gost28147_89_MAC, 0 };
40
41static int gost_pkey_meth_nids[] = { NID_id_GostR3410_94,
42    NID_id_GostR3410_2001, NID_id_Gost28147_89_MAC, 0
43};
44
45static EVP_PKEY_METHOD *pmeth_GostR3410_94 = NULL,
46    *pmeth_GostR3410_2001 = NULL, *pmeth_Gost28147_MAC = NULL;
47
48static EVP_PKEY_ASN1_METHOD *ameth_GostR3410_94 = NULL,
49    *ameth_GostR3410_2001 = NULL, *ameth_Gost28147_MAC = NULL;
50
51static int gost_engine_init(ENGINE *e)
52{
53    return 1;
54}
55
56static int gost_engine_finish(ENGINE *e)
57{
58    return 1;
59}
60
61static 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
74static 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
160static int gost_digests(ENGINE *e, const EVP_MD **digest,
161                        const int **nids, int nid)
162{
163    int ok = 1;
164    if (!digest) {
165        *nids = gost_digest_nids;
166        return 2;
167    }
168    /*
169     * printf("Digest no %d requested\n",nid);
170     */
171    if (nid == NID_id_GostR3411_94) {
172        *digest = &digest_gost;
173    } else if (nid == NID_id_Gost28147_89_MAC) {
174        *digest = &imit_gost_cpa;
175    } else {
176        ok = 0;
177        *digest = NULL;
178    }
179    return ok;
180}
181
182static int gost_ciphers(ENGINE *e, const EVP_CIPHER **cipher,
183                        const int **nids, int nid)
184{
185    int ok = 1;
186    if (!cipher) {
187        *nids = gost_cipher_nids;
188        return 2;               /* two ciphers are supported */
189    }
190
191    if (nid == NID_id_Gost28147_89) {
192        *cipher = &cipher_gost;
193    } else if (nid == NID_gost89_cnt) {
194        *cipher = &cipher_gost_cpacnt;
195    } else {
196        ok = 0;
197        *cipher = NULL;
198    }
199    return ok;
200}
201
202static int gost_pkey_meths(ENGINE *e, EVP_PKEY_METHOD **pmeth,
203                           const int **nids, int nid)
204{
205    if (!pmeth) {
206        *nids = gost_pkey_meth_nids;
207        return 3;
208    }
209
210    switch (nid) {
211    case NID_id_GostR3410_94:
212        *pmeth = pmeth_GostR3410_94;
213        return 1;
214    case NID_id_GostR3410_2001:
215        *pmeth = pmeth_GostR3410_2001;
216        return 1;
217    case NID_id_Gost28147_89_MAC:
218        *pmeth = pmeth_Gost28147_MAC;
219        return 1;
220    default:;
221    }
222
223    *pmeth = NULL;
224    return 0;
225}
226
227static int gost_pkey_asn1_meths(ENGINE *e, EVP_PKEY_ASN1_METHOD **ameth,
228                                const int **nids, int nid)
229{
230    if (!ameth) {
231        *nids = gost_pkey_meth_nids;
232        return 3;
233    }
234    switch (nid) {
235    case NID_id_GostR3410_94:
236        *ameth = ameth_GostR3410_94;
237        return 1;
238    case NID_id_GostR3410_2001:
239        *ameth = ameth_GostR3410_2001;
240        return 1;
241    case NID_id_Gost28147_89_MAC:
242        *ameth = ameth_Gost28147_MAC;
243        return 1;
244
245    default:;
246    }
247
248    *ameth = NULL;
249    return 0;
250}
251
252#ifdef OPENSSL_NO_DYNAMIC_ENGINE
253static ENGINE *engine_gost(void)
254{
255    ENGINE *ret = ENGINE_new();
256    if (!ret)
257        return NULL;
258    if (!bind_gost(ret, engine_gost_id)) {
259        ENGINE_free(ret);
260        return NULL;
261    }
262    return ret;
263}
264
265void ENGINE_load_gost(void)
266{
267    ENGINE *toadd;
268    if (pmeth_GostR3410_94)
269        return;
270    toadd = engine_gost();
271    if (!toadd)
272        return;
273    ENGINE_add(toadd);
274    ENGINE_free(toadd);
275    ERR_clear_error();
276}
277#else
278IMPLEMENT_DYNAMIC_BIND_FN(bind_gost)
279IMPLEMENT_DYNAMIC_CHECK_FN()
280#endif
281