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";
19280304Sjkimstatic const char *engine_gost_name =
20280304Sjkim    "Reference implementation of GOST engine";
21238384Sjkim
22238384Sjkim/* Symmetric cipher and digest function registrar */
23238384Sjkim
24238384Sjkimstatic int gost_ciphers(ENGINE *e, const EVP_CIPHER **cipher,
25280304Sjkim                        const int **nids, int nid);
26238384Sjkim
27238384Sjkimstatic int gost_digests(ENGINE *e, const EVP_MD **digest,
28280304Sjkim                        const int **nids, int ind);
29238384Sjkim
30280304Sjkimstatic int gost_pkey_meths(ENGINE *e, EVP_PKEY_METHOD **pmeth,
31280304Sjkim                           const int **nids, int nid);
32238384Sjkim
33280304Sjkimstatic int gost_pkey_asn1_meths(ENGINE *e, EVP_PKEY_ASN1_METHOD **ameth,
34280304Sjkim                                const int **nids, int nid);
35238384Sjkim
36280304Sjkimstatic int gost_cipher_nids[] = { NID_id_Gost28147_89, NID_gost89_cnt, 0 };
37238384Sjkim
38238384Sjkimstatic int gost_digest_nids[] =
39280304Sjkim    { NID_id_GostR3411_94, NID_id_Gost28147_89_MAC, 0 };
40238384Sjkim
41280304Sjkimstatic int gost_pkey_meth_nids[] = { NID_id_GostR3410_94,
42280304Sjkim    NID_id_GostR3410_2001, NID_id_Gost28147_89_MAC, 0
43280304Sjkim};
44238384Sjkim
45238384Sjkimstatic EVP_PKEY_METHOD *pmeth_GostR3410_94 = NULL,
46280304Sjkim    *pmeth_GostR3410_2001 = NULL, *pmeth_Gost28147_MAC = NULL;
47238384Sjkim
48238384Sjkimstatic EVP_PKEY_ASN1_METHOD *ameth_GostR3410_94 = NULL,
49280304Sjkim    *ameth_GostR3410_2001 = NULL, *ameth_Gost28147_MAC = NULL;
50238384Sjkim
51238384Sjkimstatic int gost_engine_init(ENGINE *e)
52280304Sjkim{
53280304Sjkim    return 1;
54280304Sjkim}
55238384Sjkim
56238384Sjkimstatic int gost_engine_finish(ENGINE *e)
57280304Sjkim{
58280304Sjkim    return 1;
59280304Sjkim}
60238384Sjkim
61238384Sjkimstatic int gost_engine_destroy(ENGINE *e)
62280304Sjkim{
63280304Sjkim    gost_param_free();
64246772Sjkim
65280304Sjkim    pmeth_GostR3410_94 = NULL;
66280304Sjkim    pmeth_GostR3410_2001 = NULL;
67280304Sjkim    pmeth_Gost28147_MAC = NULL;
68280304Sjkim    ameth_GostR3410_94 = NULL;
69280304Sjkim    ameth_GostR3410_2001 = NULL;
70280304Sjkim    ameth_Gost28147_MAC = NULL;
71280304Sjkim    return 1;
72280304Sjkim}
73238384Sjkim
74280304Sjkimstatic int bind_gost(ENGINE *e, const char *id)
75280304Sjkim{
76280304Sjkim    int ret = 0;
77280304Sjkim    if (id && strcmp(id, engine_gost_id))
78280304Sjkim        return 0;
79280304Sjkim    if (ameth_GostR3410_94) {
80280304Sjkim        printf("GOST engine already loaded\n");
81280304Sjkim        goto end;
82280304Sjkim    }
83238384Sjkim
84280304Sjkim    if (!ENGINE_set_id(e, engine_gost_id)) {
85280304Sjkim        printf("ENGINE_set_id failed\n");
86280304Sjkim        goto end;
87280304Sjkim    }
88280304Sjkim    if (!ENGINE_set_name(e, engine_gost_name)) {
89280304Sjkim        printf("ENGINE_set_name failed\n");
90280304Sjkim        goto end;
91280304Sjkim    }
92280304Sjkim    if (!ENGINE_set_digests(e, gost_digests)) {
93280304Sjkim        printf("ENGINE_set_digests failed\n");
94280304Sjkim        goto end;
95280304Sjkim    }
96280304Sjkim    if (!ENGINE_set_ciphers(e, gost_ciphers)) {
97280304Sjkim        printf("ENGINE_set_ciphers failed\n");
98280304Sjkim        goto end;
99280304Sjkim    }
100280304Sjkim    if (!ENGINE_set_pkey_meths(e, gost_pkey_meths)) {
101280304Sjkim        printf("ENGINE_set_pkey_meths failed\n");
102280304Sjkim        goto end;
103280304Sjkim    }
104280304Sjkim    if (!ENGINE_set_pkey_asn1_meths(e, gost_pkey_asn1_meths)) {
105280304Sjkim        printf("ENGINE_set_pkey_asn1_meths failed\n");
106280304Sjkim        goto end;
107280304Sjkim    }
108280304Sjkim    /* Control function and commands */
109280304Sjkim    if (!ENGINE_set_cmd_defns(e, gost_cmds)) {
110280304Sjkim        fprintf(stderr, "ENGINE_set_cmd_defns failed\n");
111280304Sjkim        goto end;
112280304Sjkim    }
113280304Sjkim    if (!ENGINE_set_ctrl_function(e, gost_control_func)) {
114280304Sjkim        fprintf(stderr, "ENGINE_set_ctrl_func failed\n");
115280304Sjkim        goto end;
116280304Sjkim    }
117280304Sjkim    if (!ENGINE_set_destroy_function(e, gost_engine_destroy)
118280304Sjkim        || !ENGINE_set_init_function(e, gost_engine_init)
119280304Sjkim        || !ENGINE_set_finish_function(e, gost_engine_finish)) {
120280304Sjkim        goto end;
121280304Sjkim    }
122238384Sjkim
123280304Sjkim    if (!register_ameth_gost
124280304Sjkim        (NID_id_GostR3410_94, &ameth_GostR3410_94, "GOST94",
125280304Sjkim         "GOST R 34.10-94"))
126280304Sjkim        goto end;
127280304Sjkim    if (!register_ameth_gost
128280304Sjkim        (NID_id_GostR3410_2001, &ameth_GostR3410_2001, "GOST2001",
129280304Sjkim         "GOST R 34.10-2001"))
130280304Sjkim        goto end;
131280304Sjkim    if (!register_ameth_gost(NID_id_Gost28147_89_MAC, &ameth_Gost28147_MAC,
132280304Sjkim                             "GOST-MAC", "GOST 28147-89 MAC"))
133280304Sjkim        goto end;
134238384Sjkim
135280304Sjkim    if (!register_pmeth_gost(NID_id_GostR3410_94, &pmeth_GostR3410_94, 0))
136280304Sjkim        goto end;
137280304Sjkim    if (!register_pmeth_gost(NID_id_GostR3410_2001, &pmeth_GostR3410_2001, 0))
138280304Sjkim        goto end;
139280304Sjkim    if (!register_pmeth_gost
140280304Sjkim        (NID_id_Gost28147_89_MAC, &pmeth_Gost28147_MAC, 0))
141280304Sjkim        goto end;
142280304Sjkim    if (!ENGINE_register_ciphers(e)
143280304Sjkim        || !ENGINE_register_digests(e)
144280304Sjkim        || !ENGINE_register_pkey_meths(e)
145280304Sjkim        /* These two actually should go in LIST_ADD command */
146280304Sjkim        || !EVP_add_cipher(&cipher_gost)
147280304Sjkim        || !EVP_add_cipher(&cipher_gost_cpacnt)
148280304Sjkim        || !EVP_add_digest(&digest_gost)
149280304Sjkim        || !EVP_add_digest(&imit_gost_cpa)
150280304Sjkim        ) {
151280304Sjkim        goto end;
152280304Sjkim    }
153238384Sjkim
154280304Sjkim    ERR_load_GOST_strings();
155280304Sjkim    ret = 1;
156280304Sjkim end:
157280304Sjkim    return ret;
158280304Sjkim}
159238384Sjkim
160238384Sjkim#ifndef OPENSSL_NO_DYNAMIC_ENGINE
161238384SjkimIMPLEMENT_DYNAMIC_BIND_FN(bind_gost)
162280304Sjkim    IMPLEMENT_DYNAMIC_CHECK_FN()
163280304Sjkim#endif                          /* ndef OPENSSL_NO_DYNAMIC_ENGINE */
164238384Sjkimstatic int gost_digests(ENGINE *e, const EVP_MD **digest,
165280304Sjkim                        const int **nids, int nid)
166280304Sjkim{
167280304Sjkim    int ok = 1;
168280304Sjkim    if (!digest) {
169280304Sjkim        *nids = gost_digest_nids;
170280304Sjkim        return 2;
171280304Sjkim    }
172280304Sjkim    /*
173280304Sjkim     * printf("Digest no %d requested\n",nid);
174280304Sjkim     */
175280304Sjkim    if (nid == NID_id_GostR3411_94) {
176280304Sjkim        *digest = &digest_gost;
177280304Sjkim    } else if (nid == NID_id_Gost28147_89_MAC) {
178280304Sjkim        *digest = &imit_gost_cpa;
179280304Sjkim    } else {
180280304Sjkim        ok = 0;
181280304Sjkim        *digest = NULL;
182280304Sjkim    }
183280304Sjkim    return ok;
184280304Sjkim}
185238384Sjkim
186280304Sjkimstatic int gost_ciphers(ENGINE *e, const EVP_CIPHER **cipher,
187280304Sjkim                        const int **nids, int nid)
188280304Sjkim{
189280304Sjkim    int ok = 1;
190280304Sjkim    if (!cipher) {
191280304Sjkim        *nids = gost_cipher_nids;
192280304Sjkim        return 2;               /* two ciphers are supported */
193280304Sjkim    }
194238384Sjkim
195280304Sjkim    if (nid == NID_id_Gost28147_89) {
196280304Sjkim        *cipher = &cipher_gost;
197280304Sjkim    } else if (nid == NID_gost89_cnt) {
198280304Sjkim        *cipher = &cipher_gost_cpacnt;
199280304Sjkim    } else {
200280304Sjkim        ok = 0;
201280304Sjkim        *cipher = NULL;
202280304Sjkim    }
203280304Sjkim    return ok;
204280304Sjkim}
205238384Sjkim
206280304Sjkimstatic int gost_pkey_meths(ENGINE *e, EVP_PKEY_METHOD **pmeth,
207280304Sjkim                           const int **nids, int nid)
208280304Sjkim{
209280304Sjkim    if (!pmeth) {
210280304Sjkim        *nids = gost_pkey_meth_nids;
211280304Sjkim        return 3;
212280304Sjkim    }
213238384Sjkim
214280304Sjkim    switch (nid) {
215280304Sjkim    case NID_id_GostR3410_94:
216280304Sjkim        *pmeth = pmeth_GostR3410_94;
217280304Sjkim        return 1;
218280304Sjkim    case NID_id_GostR3410_2001:
219280304Sjkim        *pmeth = pmeth_GostR3410_2001;
220280304Sjkim        return 1;
221280304Sjkim    case NID_id_Gost28147_89_MAC:
222280304Sjkim        *pmeth = pmeth_Gost28147_MAC;
223280304Sjkim        return 1;
224280304Sjkim    default:;
225280304Sjkim    }
226238384Sjkim
227280304Sjkim    *pmeth = NULL;
228280304Sjkim    return 0;
229280304Sjkim}
230280304Sjkim
231280304Sjkimstatic int gost_pkey_asn1_meths(ENGINE *e, EVP_PKEY_ASN1_METHOD **ameth,
232280304Sjkim                                const int **nids, int nid)
233280304Sjkim{
234280304Sjkim    if (!ameth) {
235280304Sjkim        *nids = gost_pkey_meth_nids;
236280304Sjkim        return 3;
237280304Sjkim    }
238280304Sjkim    switch (nid) {
239280304Sjkim    case NID_id_GostR3410_94:
240280304Sjkim        *ameth = ameth_GostR3410_94;
241280304Sjkim        return 1;
242280304Sjkim    case NID_id_GostR3410_2001:
243280304Sjkim        *ameth = ameth_GostR3410_2001;
244280304Sjkim        return 1;
245280304Sjkim    case NID_id_Gost28147_89_MAC:
246280304Sjkim        *ameth = ameth_Gost28147_MAC;
247280304Sjkim        return 1;
248280304Sjkim
249280304Sjkim    default:;
250280304Sjkim    }
251280304Sjkim
252280304Sjkim    *ameth = NULL;
253280304Sjkim    return 0;
254280304Sjkim}
255280304Sjkim
256238384Sjkim#ifdef OPENSSL_NO_DYNAMIC_ENGINE
257238384Sjkimstatic ENGINE *engine_gost(void)
258280304Sjkim{
259280304Sjkim    ENGINE *ret = ENGINE_new();
260280304Sjkim    if (!ret)
261280304Sjkim        return NULL;
262280304Sjkim    if (!bind_gost(ret, engine_gost_id)) {
263280304Sjkim        ENGINE_free(ret);
264280304Sjkim        return NULL;
265280304Sjkim    }
266280304Sjkim    return ret;
267280304Sjkim}
268280304Sjkim
269238384Sjkimvoid ENGINE_load_gost(void)
270280304Sjkim{
271280304Sjkim    ENGINE *toadd;
272280304Sjkim    if (pmeth_GostR3410_94)
273280304Sjkim        return;
274280304Sjkim    toadd = engine_gost();
275280304Sjkim    if (!toadd)
276280304Sjkim        return;
277280304Sjkim    ENGINE_add(toadd);
278280304Sjkim    ENGINE_free(toadd);
279280304Sjkim    ERR_clear_error();
280280304Sjkim}
281280304Sjkim#endif
282