1238384Sjkim/**********************************************************************
2238384Sjkim *                          gost_eng.c                                *
3238384Sjkim *             Copyright (c) 2005-2006 Cryptocom LTD                  *
4238384Sjkim *         This file is distributed under the same license as OpenSSL *
5238384Sjkim *                                                                    *
6238384Sjkim *              Main file of GOST engine                              *
7238384Sjkim *       for OpenSSL                                                  *
8238384Sjkim *          Requires OpenSSL 0.9.9 for compilation                    *
9238384Sjkim **********************************************************************/
10238384Sjkim#include <string.h>
11238384Sjkim#include <openssl/crypto.h>
12238384Sjkim#include <openssl/err.h>
13238384Sjkim#include <openssl/evp.h>
14238384Sjkim#include <openssl/engine.h>
15238384Sjkim#include <openssl/obj_mac.h>
16238384Sjkim#include "e_gost_err.h"
17238384Sjkim#include "gost_lcl.h"
18238384Sjkimstatic const char *engine_gost_id = "gost";
19280297Sjkimstatic const char *engine_gost_name =
20280297Sjkim    "Reference implementation of GOST engine";
21238384Sjkim
22238384Sjkim/* Symmetric cipher and digest function registrar */
23238384Sjkim
24238384Sjkimstatic int gost_ciphers(ENGINE *e, const EVP_CIPHER **cipher,
25280297Sjkim                        const int **nids, int nid);
26238384Sjkim
27238384Sjkimstatic int gost_digests(ENGINE *e, const EVP_MD **digest,
28280297Sjkim                        const int **nids, int ind);
29238384Sjkim
30280297Sjkimstatic int gost_pkey_meths(ENGINE *e, EVP_PKEY_METHOD **pmeth,
31280297Sjkim                           const int **nids, int nid);
32238384Sjkim
33280297Sjkimstatic int gost_pkey_asn1_meths(ENGINE *e, EVP_PKEY_ASN1_METHOD **ameth,
34280297Sjkim                                const int **nids, int nid);
35238384Sjkim
36280297Sjkimstatic int gost_cipher_nids[] = { NID_id_Gost28147_89, NID_gost89_cnt, 0 };
37238384Sjkim
38238384Sjkimstatic int gost_digest_nids[] =
39280297Sjkim    { NID_id_GostR3411_94, NID_id_Gost28147_89_MAC, 0 };
40238384Sjkim
41280297Sjkimstatic int gost_pkey_meth_nids[] = { NID_id_GostR3410_94,
42280297Sjkim    NID_id_GostR3410_2001, NID_id_Gost28147_89_MAC, 0
43280297Sjkim};
44238384Sjkim
45238384Sjkimstatic EVP_PKEY_METHOD *pmeth_GostR3410_94 = NULL,
46280297Sjkim    *pmeth_GostR3410_2001 = NULL, *pmeth_Gost28147_MAC = NULL;
47238384Sjkim
48238384Sjkimstatic EVP_PKEY_ASN1_METHOD *ameth_GostR3410_94 = NULL,
49280297Sjkim    *ameth_GostR3410_2001 = NULL, *ameth_Gost28147_MAC = NULL;
50238384Sjkim
51238384Sjkimstatic int gost_engine_init(ENGINE *e)
52280297Sjkim{
53280297Sjkim    return 1;
54280297Sjkim}
55238384Sjkim
56238384Sjkimstatic int gost_engine_finish(ENGINE *e)
57280297Sjkim{
58280297Sjkim    return 1;
59280297Sjkim}
60238384Sjkim
61238384Sjkimstatic int gost_engine_destroy(ENGINE *e)
62280297Sjkim{
63280297Sjkim    gost_param_free();
64246772Sjkim
65280297Sjkim    pmeth_GostR3410_94 = NULL;
66280297Sjkim    pmeth_GostR3410_2001 = NULL;
67280297Sjkim    pmeth_Gost28147_MAC = NULL;
68280297Sjkim    ameth_GostR3410_94 = NULL;
69280297Sjkim    ameth_GostR3410_2001 = NULL;
70280297Sjkim    ameth_Gost28147_MAC = NULL;
71280297Sjkim    return 1;
72280297Sjkim}
73238384Sjkim
74280297Sjkimstatic int bind_gost(ENGINE *e, const char *id)
75280297Sjkim{
76280297Sjkim    int ret = 0;
77280297Sjkim    if (id && strcmp(id, engine_gost_id))
78280297Sjkim        return 0;
79280297Sjkim    if (ameth_GostR3410_94) {
80280297Sjkim        printf("GOST engine already loaded\n");
81280297Sjkim        goto end;
82280297Sjkim    }
83238384Sjkim
84280297Sjkim    if (!ENGINE_set_id(e, engine_gost_id)) {
85280297Sjkim        printf("ENGINE_set_id failed\n");
86280297Sjkim        goto end;
87280297Sjkim    }
88280297Sjkim    if (!ENGINE_set_name(e, engine_gost_name)) {
89280297Sjkim        printf("ENGINE_set_name failed\n");
90280297Sjkim        goto end;
91280297Sjkim    }
92280297Sjkim    if (!ENGINE_set_digests(e, gost_digests)) {
93280297Sjkim        printf("ENGINE_set_digests failed\n");
94280297Sjkim        goto end;
95280297Sjkim    }
96280297Sjkim    if (!ENGINE_set_ciphers(e, gost_ciphers)) {
97280297Sjkim        printf("ENGINE_set_ciphers failed\n");
98280297Sjkim        goto end;
99280297Sjkim    }
100280297Sjkim    if (!ENGINE_set_pkey_meths(e, gost_pkey_meths)) {
101280297Sjkim        printf("ENGINE_set_pkey_meths failed\n");
102280297Sjkim        goto end;
103280297Sjkim    }
104280297Sjkim    if (!ENGINE_set_pkey_asn1_meths(e, gost_pkey_asn1_meths)) {
105280297Sjkim        printf("ENGINE_set_pkey_asn1_meths failed\n");
106280297Sjkim        goto end;
107280297Sjkim    }
108280297Sjkim    /* Control function and commands */
109280297Sjkim    if (!ENGINE_set_cmd_defns(e, gost_cmds)) {
110280297Sjkim        fprintf(stderr, "ENGINE_set_cmd_defns failed\n");
111280297Sjkim        goto end;
112280297Sjkim    }
113280297Sjkim    if (!ENGINE_set_ctrl_function(e, gost_control_func)) {
114280297Sjkim        fprintf(stderr, "ENGINE_set_ctrl_func failed\n");
115280297Sjkim        goto end;
116280297Sjkim    }
117280297Sjkim    if (!ENGINE_set_destroy_function(e, gost_engine_destroy)
118280297Sjkim        || !ENGINE_set_init_function(e, gost_engine_init)
119280297Sjkim        || !ENGINE_set_finish_function(e, gost_engine_finish)) {
120280297Sjkim        goto end;
121280297Sjkim    }
122238384Sjkim
123280297Sjkim    if (!register_ameth_gost
124280297Sjkim        (NID_id_GostR3410_94, &ameth_GostR3410_94, "GOST94",
125280297Sjkim         "GOST R 34.10-94"))
126280297Sjkim        goto end;
127280297Sjkim    if (!register_ameth_gost
128280297Sjkim        (NID_id_GostR3410_2001, &ameth_GostR3410_2001, "GOST2001",
129280297Sjkim         "GOST R 34.10-2001"))
130280297Sjkim        goto end;
131280297Sjkim    if (!register_ameth_gost(NID_id_Gost28147_89_MAC, &ameth_Gost28147_MAC,
132280297Sjkim                             "GOST-MAC", "GOST 28147-89 MAC"))
133280297Sjkim        goto end;
134238384Sjkim
135280297Sjkim    if (!register_pmeth_gost(NID_id_GostR3410_94, &pmeth_GostR3410_94, 0))
136280297Sjkim        goto end;
137280297Sjkim    if (!register_pmeth_gost(NID_id_GostR3410_2001, &pmeth_GostR3410_2001, 0))
138280297Sjkim        goto end;
139280297Sjkim    if (!register_pmeth_gost
140280297Sjkim        (NID_id_Gost28147_89_MAC, &pmeth_Gost28147_MAC, 0))
141280297Sjkim        goto end;
142280297Sjkim    if (!ENGINE_register_ciphers(e)
143280297Sjkim        || !ENGINE_register_digests(e)
144280297Sjkim        || !ENGINE_register_pkey_meths(e)
145280297Sjkim        /* These two actually should go in LIST_ADD command */
146280297Sjkim        || !EVP_add_cipher(&cipher_gost)
147280297Sjkim        || !EVP_add_cipher(&cipher_gost_cpacnt)
148280297Sjkim        || !EVP_add_digest(&digest_gost)
149280297Sjkim        || !EVP_add_digest(&imit_gost_cpa)
150280297Sjkim        ) {
151280297Sjkim        goto end;
152280297Sjkim    }
153238384Sjkim
154280297Sjkim    ERR_load_GOST_strings();
155280297Sjkim    ret = 1;
156280297Sjkim end:
157280297Sjkim    return ret;
158280297Sjkim}
159238384Sjkim
160238384Sjkimstatic int gost_digests(ENGINE *e, const EVP_MD **digest,
161280297Sjkim                        const int **nids, int nid)
162280297Sjkim{
163280297Sjkim    int ok = 1;
164280297Sjkim    if (!digest) {
165280297Sjkim        *nids = gost_digest_nids;
166280297Sjkim        return 2;
167280297Sjkim    }
168280297Sjkim    /*
169280297Sjkim     * printf("Digest no %d requested\n",nid);
170280297Sjkim     */
171280297Sjkim    if (nid == NID_id_GostR3411_94) {
172280297Sjkim        *digest = &digest_gost;
173280297Sjkim    } else if (nid == NID_id_Gost28147_89_MAC) {
174280297Sjkim        *digest = &imit_gost_cpa;
175280297Sjkim    } else {
176280297Sjkim        ok = 0;
177280297Sjkim        *digest = NULL;
178280297Sjkim    }
179280297Sjkim    return ok;
180280297Sjkim}
181238384Sjkim
182280297Sjkimstatic int gost_ciphers(ENGINE *e, const EVP_CIPHER **cipher,
183280297Sjkim                        const int **nids, int nid)
184280297Sjkim{
185280297Sjkim    int ok = 1;
186280297Sjkim    if (!cipher) {
187280297Sjkim        *nids = gost_cipher_nids;
188280297Sjkim        return 2;               /* two ciphers are supported */
189280297Sjkim    }
190238384Sjkim
191280297Sjkim    if (nid == NID_id_Gost28147_89) {
192280297Sjkim        *cipher = &cipher_gost;
193280297Sjkim    } else if (nid == NID_gost89_cnt) {
194280297Sjkim        *cipher = &cipher_gost_cpacnt;
195280297Sjkim    } else {
196280297Sjkim        ok = 0;
197280297Sjkim        *cipher = NULL;
198280297Sjkim    }
199280297Sjkim    return ok;
200280297Sjkim}
201238384Sjkim
202280297Sjkimstatic int gost_pkey_meths(ENGINE *e, EVP_PKEY_METHOD **pmeth,
203280297Sjkim                           const int **nids, int nid)
204280297Sjkim{
205280297Sjkim    if (!pmeth) {
206280297Sjkim        *nids = gost_pkey_meth_nids;
207280297Sjkim        return 3;
208280297Sjkim    }
209238384Sjkim
210280297Sjkim    switch (nid) {
211280297Sjkim    case NID_id_GostR3410_94:
212280297Sjkim        *pmeth = pmeth_GostR3410_94;
213280297Sjkim        return 1;
214280297Sjkim    case NID_id_GostR3410_2001:
215280297Sjkim        *pmeth = pmeth_GostR3410_2001;
216280297Sjkim        return 1;
217280297Sjkim    case NID_id_Gost28147_89_MAC:
218280297Sjkim        *pmeth = pmeth_Gost28147_MAC;
219280297Sjkim        return 1;
220280297Sjkim    default:;
221280297Sjkim    }
222238384Sjkim
223280297Sjkim    *pmeth = NULL;
224280297Sjkim    return 0;
225280297Sjkim}
226280297Sjkim
227280297Sjkimstatic int gost_pkey_asn1_meths(ENGINE *e, EVP_PKEY_ASN1_METHOD **ameth,
228280297Sjkim                                const int **nids, int nid)
229280297Sjkim{
230280297Sjkim    if (!ameth) {
231280297Sjkim        *nids = gost_pkey_meth_nids;
232280297Sjkim        return 3;
233280297Sjkim    }
234280297Sjkim    switch (nid) {
235280297Sjkim    case NID_id_GostR3410_94:
236280297Sjkim        *ameth = ameth_GostR3410_94;
237280297Sjkim        return 1;
238280297Sjkim    case NID_id_GostR3410_2001:
239280297Sjkim        *ameth = ameth_GostR3410_2001;
240280297Sjkim        return 1;
241280297Sjkim    case NID_id_Gost28147_89_MAC:
242280297Sjkim        *ameth = ameth_Gost28147_MAC;
243280297Sjkim        return 1;
244280297Sjkim
245280297Sjkim    default:;
246280297Sjkim    }
247280297Sjkim
248280297Sjkim    *ameth = NULL;
249280297Sjkim    return 0;
250280297Sjkim}
251280297Sjkim
252238384Sjkim#ifdef OPENSSL_NO_DYNAMIC_ENGINE
253238384Sjkimstatic ENGINE *engine_gost(void)
254280297Sjkim{
255280297Sjkim    ENGINE *ret = ENGINE_new();
256280297Sjkim    if (!ret)
257280297Sjkim        return NULL;
258280297Sjkim    if (!bind_gost(ret, engine_gost_id)) {
259280297Sjkim        ENGINE_free(ret);
260280297Sjkim        return NULL;
261280297Sjkim    }
262280297Sjkim    return ret;
263280297Sjkim}
264280297Sjkim
265238384Sjkimvoid ENGINE_load_gost(void)
266280297Sjkim{
267280297Sjkim    ENGINE *toadd;
268280297Sjkim    if (pmeth_GostR3410_94)
269280297Sjkim        return;
270280297Sjkim    toadd = engine_gost();
271280297Sjkim    if (!toadd)
272280297Sjkim        return;
273280297Sjkim    ENGINE_add(toadd);
274280297Sjkim    ENGINE_free(toadd);
275280297Sjkim    ERR_clear_error();
276280297Sjkim}
277331638Sjkim#else
278331638SjkimIMPLEMENT_DYNAMIC_BIND_FN(bind_gost)
279331638SjkimIMPLEMENT_DYNAMIC_CHECK_FN()
280280297Sjkim#endif
281