]> www.wagner.pp.ru Git - openssl-gost/engine.git/blob - gost_pmeth.c
Initial commit providing GOST 2012 algorithms.
[openssl-gost/engine.git] / gost_pmeth.c
1 /**********************************************************************
2  *                          gost_pmeth.c                              *
3  *             Copyright (c) 2005-2013 Cryptocom LTD                  *
4  *         This file is distributed under the same license as OpenSSL *
5  *                                                                    *
6  *   Implementation of RFC 4357 (GOST R 34.10) Publick key method     *
7  *       for OpenSSL                                                  *
8  *          Requires OpenSSL 1.0.0+ for compilation                   *
9  **********************************************************************/
10 #include <openssl/evp.h>
11 #include <openssl/objects.h>
12 #include <openssl/ec.h>
13 #include <openssl/x509v3.h>     /* For string_to_hex */
14 #include <stdlib.h>
15 #include <string.h>
16 #include <ctype.h>
17 #include "gost_params.h"
18 #include "gost_lcl.h"
19 #include "e_gost_err.h"
20
21 /* -----init, cleanup, copy - uniform for all algs  --------------*/
22 /* Allocates new gost_pmeth_data structure and assigns it as data */
23 static int pkey_gost_init(EVP_PKEY_CTX *ctx)
24 {
25     struct gost_pmeth_data *data;
26     EVP_PKEY *pkey = EVP_PKEY_CTX_get0_pkey(ctx);
27     data = OPENSSL_malloc(sizeof(struct gost_pmeth_data));
28     if (!data)
29         return 0;
30     memset(data, 0, sizeof(struct gost_pmeth_data));
31     if (pkey && EVP_PKEY_get0(pkey)) {
32         switch (EVP_PKEY_base_id(pkey)) {
33         case NID_id_GostR3410_94:
34             data->sign_param_nid = gost94_nid_by_params(EVP_PKEY_get0(pkey));
35             break;
36         case NID_id_GostR3410_2001:
37         case NID_id_GostR3410_2012_256:
38         case NID_id_GostR3410_2012_512:
39             {
40                 const EC_GROUP *group =
41                     EC_KEY_get0_group(EVP_PKEY_get0((EVP_PKEY *)pkey));
42                 if (group != NULL) {
43                     data->sign_param_nid = EC_GROUP_get_curve_name(group);
44                     break;
45                 }
46                 /* else */
47             }
48         default:
49             OPENSSL_free(data);
50             return 0;
51         }
52     }
53     EVP_PKEY_CTX_set_data(ctx, data);
54     return 1;
55 }
56
57 /* Copies contents of gost_pmeth_data structure */
58 static int pkey_gost_copy(EVP_PKEY_CTX *dst, EVP_PKEY_CTX *src)
59 {
60     struct gost_pmeth_data *dst_data, *src_data;
61     if (!pkey_gost_init(dst)) {
62         return 0;
63     }
64     src_data = EVP_PKEY_CTX_get_data(src);
65     dst_data = EVP_PKEY_CTX_get_data(dst);
66     if (!src_data || !dst_data)
67         return 0;
68
69     *dst_data = *src_data;
70     if (src_data->shared_ukm) {
71         dst_data->shared_ukm = NULL;
72     }
73     return 1;
74 }
75
76 /* Frees up gost_pmeth_data structure */
77 static void pkey_gost_cleanup(EVP_PKEY_CTX *ctx)
78 {
79     struct gost_pmeth_data *data = EVP_PKEY_CTX_get_data(ctx);
80     if (!data)
81         return;
82     if (data->shared_ukm)
83         OPENSSL_free(data->shared_ukm);
84     OPENSSL_free(data);
85 }
86
87 /* --------------------- control functions  ------------------------------*/
88 static int pkey_gost_ctrl(EVP_PKEY_CTX *ctx, int type, int p1, void *p2)
89 {
90     struct gost_pmeth_data *pctx =
91         (struct gost_pmeth_data *)EVP_PKEY_CTX_get_data(ctx);
92     if (pctx == NULL)
93         return 0;
94
95     switch (type) {
96     case EVP_PKEY_CTRL_MD:
97         {
98             EVP_PKEY *key = EVP_PKEY_CTX_get0_pkey(ctx);
99             int pkey_nid = (key == NULL) ? NID_undef : EVP_PKEY_base_id(key);
100
101             OPENSSL_assert(p2 != NULL);
102
103             switch (EVP_MD_type((const EVP_MD *)p2)) {
104             case NID_id_GostR3411_94:
105                 if (pkey_nid == NID_id_GostR3410_2001
106                     || pkey_nid == NID_id_GostR3410_94) {
107                     pctx->md = (EVP_MD *)p2;
108                     return 1;
109                 }
110                 break;
111
112             case NID_id_GostR3411_2012_256:
113                 if (pkey_nid == NID_id_GostR3410_2012_256) {
114                     pctx->md = (EVP_MD *)p2;
115                     return 1;
116                 }
117                 break;
118
119             case NID_id_GostR3411_2012_512:
120                 if (pkey_nid == NID_id_GostR3410_2012_512) {
121                     pctx->md = (EVP_MD *)p2;
122                     return 1;
123                 }
124                 break;
125             }
126
127             GOSTerr(GOST_F_PKEY_GOST_CTRL, GOST_R_INVALID_DIGEST_TYPE);
128             return 0;
129         }
130
131     case EVP_PKEY_CTRL_GET_MD:
132         *(const EVP_MD **)p2 = pctx->md;
133         return 1;
134
135     case EVP_PKEY_CTRL_PKCS7_ENCRYPT:
136     case EVP_PKEY_CTRL_PKCS7_DECRYPT:
137     case EVP_PKEY_CTRL_PKCS7_SIGN:
138     case EVP_PKEY_CTRL_DIGESTINIT:
139 #ifndef OPENSSL_NO_CMS
140     case EVP_PKEY_CTRL_CMS_ENCRYPT:
141     case EVP_PKEY_CTRL_CMS_DECRYPT:
142     case EVP_PKEY_CTRL_CMS_SIGN:
143 #endif
144         return 1;
145
146     case EVP_PKEY_CTRL_GOST_PARAMSET:
147         pctx->sign_param_nid = (int)p1;
148         return 1;
149     case EVP_PKEY_CTRL_SET_IV:
150         OPENSSL_assert(p2 != NULL);
151         pctx->shared_ukm = OPENSSL_malloc((int)p1);
152         if (!pctx->shared_ukm)
153             return 0;
154         memcpy(pctx->shared_ukm, p2, (int)p1);
155         return 1;
156     case EVP_PKEY_CTRL_PEER_KEY:
157         if (p1 == 0 || p1 == 1) /* call from EVP_PKEY_derive_set_peer */
158             return 1;
159         if (p1 == 2)            /* TLS: peer key used? */
160             return pctx->peer_key_used;
161         if (p1 == 3)            /* TLS: peer key used! */
162             return (pctx->peer_key_used = 1);
163         break;
164     }
165
166     GOSTerr(GOST_F_PKEY_GOST_CTRL, GOST_R_CTRL_CALL_FAILED);
167     return -2;
168 }
169
170 static int pkey_gost94_ctrl_str(EVP_PKEY_CTX *ctx,
171                                 const char *type, const char *value)
172 {
173     int param_nid = 0;
174     if (!strcmp(type, param_ctrl_string)) {
175         if (!value) {
176             return 0;
177         }
178         if (strlen(value) == 1) {
179             switch (toupper((unsigned char)value[0])) {
180             case 'A':
181                 param_nid = NID_id_GostR3410_94_CryptoPro_A_ParamSet;
182                 break;
183             case 'B':
184                 param_nid = NID_id_GostR3410_94_CryptoPro_B_ParamSet;
185                 break;
186             case 'C':
187                 param_nid = NID_id_GostR3410_94_CryptoPro_C_ParamSet;
188                 break;
189             case 'D':
190                 param_nid = NID_id_GostR3410_94_CryptoPro_D_ParamSet;
191                 break;
192             default:
193                 return 0;
194             }
195         } else if ((strlen(value) == 2)
196                    && (toupper((unsigned char)value[0]) == 'X')) {
197             switch (toupper((unsigned char)value[1])) {
198             case 'A':
199                 param_nid = NID_id_GostR3410_94_CryptoPro_XchA_ParamSet;
200                 break;
201             case 'B':
202                 param_nid = NID_id_GostR3410_94_CryptoPro_XchB_ParamSet;
203                 break;
204             case 'C':
205                 param_nid = NID_id_GostR3410_94_CryptoPro_XchC_ParamSet;
206                 break;
207             default:
208                 return 0;
209             }
210         } else {
211             R3410_params *p = R3410_paramset;
212             param_nid = OBJ_txt2nid(value);
213             if (param_nid == NID_undef) {
214                 return 0;
215             }
216             for (; p->nid != NID_undef; p++) {
217                 if (p->nid == param_nid)
218                     break;
219             }
220             if (p->nid == NID_undef) {
221                 GOSTerr(GOST_F_PKEY_GOST94_CTRL_STR, GOST_R_INVALID_PARAMSET);
222                 return 0;
223             }
224         }
225
226         return pkey_gost_ctrl(ctx, EVP_PKEY_CTRL_GOST_PARAMSET,
227                               param_nid, NULL);
228     }
229     return -2;
230 }
231
232 static int pkey_gost_ec_ctrl_str_256(EVP_PKEY_CTX *ctx,
233                                      const char *type, const char *value)
234 {
235     int param_nid = 0;
236     if (!strcmp(type, param_ctrl_string)) {
237         if (!value) {
238             return 0;
239         }
240         if (strlen(value) == 1) {
241             switch (toupper((unsigned char)value[0])) {
242             case 'A':
243                 param_nid = NID_id_GostR3410_2001_CryptoPro_A_ParamSet;
244                 break;
245             case 'B':
246                 param_nid = NID_id_GostR3410_2001_CryptoPro_B_ParamSet;
247                 break;
248             case 'C':
249                 param_nid = NID_id_GostR3410_2001_CryptoPro_C_ParamSet;
250                 break;
251             case '0':
252                 param_nid = NID_id_GostR3410_2001_TestParamSet;
253                 break;
254             default:
255                 return 0;
256             }
257         } else if ((strlen(value) == 2)
258                    && (toupper((unsigned char)value[0]) == 'X')) {
259             switch (toupper((unsigned char)value[1])) {
260             case 'A':
261                 param_nid = NID_id_GostR3410_2001_CryptoPro_XchA_ParamSet;
262                 break;
263             case 'B':
264                 param_nid = NID_id_GostR3410_2001_CryptoPro_XchB_ParamSet;
265                 break;
266             default:
267                 return 0;
268             }
269         } else {
270             R3410_ec_params *p = R3410_2001_paramset;
271             param_nid = OBJ_txt2nid(value);
272             if (param_nid == NID_undef) {
273                 return 0;
274             }
275             for (; p->nid != NID_undef; p++) {
276                 if (p->nid == param_nid)
277                     break;
278             }
279             if (p->nid == NID_undef) {
280                 GOSTerr(GOST_F_PKEY_GOST_EC_CTRL_STR_256,
281                         GOST_R_INVALID_PARAMSET);
282                 return 0;
283             }
284         }
285
286         return pkey_gost_ctrl(ctx, EVP_PKEY_CTRL_GOST_PARAMSET,
287                               param_nid, NULL);
288     }
289     return -2;
290 }
291
292 static int pkey_gost_ec_ctrl_str_512(EVP_PKEY_CTX *ctx,
293                                      const char *type, const char *value)
294 {
295     int param_nid = NID_undef;
296
297     if (strcmp(type, param_ctrl_string))
298         return -2;
299
300     if (!value)
301         return 0;
302
303     if (strlen(value) == 1) {
304         switch (toupper((unsigned char)value[0])) {
305         case 'A':
306             param_nid = NID_id_tc26_gost_3410_2012_512_paramSetA;
307             break;
308
309         case 'B':
310             param_nid = NID_id_tc26_gost_3410_2012_512_paramSetB;
311             break;
312
313         default:
314             return 0;
315         }
316     } else {
317         R3410_ec_params *p = R3410_2012_512_paramset;
318         param_nid = OBJ_txt2nid(value);
319         if (param_nid == NID_undef)
320             return 0;
321
322         while (p->nid != NID_undef && p->nid != param_nid)
323             p++;
324
325         if (p->nid == NID_undef) {
326             GOSTerr(GOST_F_PKEY_GOST_EC_CTRL_STR_512,
327                     GOST_R_INVALID_PARAMSET);
328             return 0;
329         }
330     }
331
332     return pkey_gost_ctrl(ctx, EVP_PKEY_CTRL_GOST_PARAMSET, param_nid, NULL);
333 }
334
335 /* --------------------- key generation  --------------------------------*/
336
337 static int pkey_gost_paramgen_init(EVP_PKEY_CTX *ctx)
338 {
339     return 1;
340 }
341
342 static int pkey_gost94_paramgen(EVP_PKEY_CTX *ctx, EVP_PKEY *pkey)
343 {
344     struct gost_pmeth_data *data = EVP_PKEY_CTX_get_data(ctx);
345     DSA *dsa = NULL;
346     if (!data || data->sign_param_nid == NID_undef) {
347         GOSTerr(GOST_F_PKEY_GOST94_PARAMGEN, GOST_R_NO_PARAMETERS_SET);
348         return 0;
349     }
350     dsa = DSA_new();
351     if (!fill_GOST94_params(dsa, data->sign_param_nid)
352         || !EVP_PKEY_assign(pkey, NID_id_GostR3410_94, dsa)) {
353         DSA_free(dsa);
354         return 0;
355     }
356     return 1;
357 }
358
359 static int pkey_gost2001_paramgen(EVP_PKEY_CTX *ctx, EVP_PKEY *pkey)
360 {
361     struct gost_pmeth_data *data = EVP_PKEY_CTX_get_data(ctx);
362     EC_KEY *ec = NULL;
363
364     if (!data || data->sign_param_nid == NID_undef) {
365         GOSTerr(GOST_F_PKEY_GOST01_PARAMGEN, GOST_R_NO_PARAMETERS_SET);
366         return 0;
367     }
368
369     ec = EC_KEY_new();
370     if (!fill_GOST_EC_params(ec, data->sign_param_nid)
371         || !EVP_PKEY_assign(pkey, NID_id_GostR3410_2001, ec)) {
372         EC_KEY_free(ec);
373         return 0;
374     }
375     return 1;
376 }
377
378 static int pkey_gost2012_paramgen(EVP_PKEY_CTX *ctx, EVP_PKEY *pkey)
379 {
380     struct gost_pmeth_data *data = EVP_PKEY_CTX_get_data(ctx);
381     EC_KEY *ec;
382     int result = 0;
383
384     if (!data || data->sign_param_nid == NID_undef) {
385         GOSTerr(GOST_F_PKEY_GOST12_PARAMGEN, GOST_R_NO_PARAMETERS_SET);
386         return 0;
387     }
388
389     ec = EC_KEY_new();
390     if (!fill_GOST_EC_params(ec, data->sign_param_nid)) {
391         EC_KEY_free(ec);
392         return 0;
393     }
394
395     switch (data->sign_param_nid) {
396     case NID_id_tc26_gost_3410_2012_512_paramSetA:
397     case NID_id_tc26_gost_3410_2012_512_paramSetB:
398         result =
399             (EVP_PKEY_assign(pkey, NID_id_GostR3410_2012_512, ec)) ? 1 : 0;
400         break;
401
402     case NID_id_GostR3410_2001_CryptoPro_A_ParamSet:
403     case NID_id_GostR3410_2001_CryptoPro_B_ParamSet:
404     case NID_id_GostR3410_2001_CryptoPro_C_ParamSet:
405     case NID_id_GostR3410_2001_CryptoPro_XchA_ParamSet:
406     case NID_id_GostR3410_2001_CryptoPro_XchB_ParamSet:
407     case NID_id_GostR3410_2001_TestParamSet:
408         result =
409             (EVP_PKEY_assign(pkey, NID_id_GostR3410_2012_256, ec)) ? 1 : 0;
410         break;
411     default:
412         result = 0;
413         break;
414     }
415
416     if (result == 0)
417         EC_KEY_free(ec);
418
419     return result;
420 }
421
422 /* ----------- keygen callbacks --------------------------------------*/
423 /* Generates Gost_R3410_94_cp key */
424 static int pkey_gost94cp_keygen(EVP_PKEY_CTX *ctx, EVP_PKEY *pkey)
425 {
426     DSA *dsa;
427     if (!pkey_gost94_paramgen(ctx, pkey))
428         return 0;
429     dsa = EVP_PKEY_get0(pkey);
430     gost_sign_keygen(dsa);
431     return 1;
432 }
433
434 /* Generates GOST_R3410 2001 key and assigns it using specified type */
435 static int pkey_gost2001cp_keygen(EVP_PKEY_CTX *ctx, EVP_PKEY *pkey)
436 {
437     EC_KEY *ec;
438     if (!pkey_gost2001_paramgen(ctx, pkey))
439         return 0;
440     ec = EVP_PKEY_get0(pkey);
441     gost_ec_keygen(ec);
442     return 1;
443 }
444
445 /* Generates GOST_R3410 2012 key and assigns it using specified type */
446 static int pkey_gost2012cp_keygen(EVP_PKEY_CTX *ctx, EVP_PKEY *pkey)
447 {
448     if (!pkey_gost2012_paramgen(ctx, pkey))
449         return 0;
450
451     gost_ec_keygen(EVP_PKEY_get0(pkey));
452     return 1;
453 }
454
455 /* ----------- sign callbacks --------------------------------------*/
456
457 static int pkey_gost94_cp_sign(EVP_PKEY_CTX *ctx, unsigned char *sig,
458                                size_t *siglen, const unsigned char *tbs,
459                                size_t tbs_len)
460 {
461     DSA_SIG *unpacked_sig = NULL;
462     EVP_PKEY *pkey = EVP_PKEY_CTX_get0_pkey(ctx);
463     if (!siglen)
464         return 0;
465     if (!sig) {
466         *siglen = 64;           /* better to check size of pkey->pkey.dsa-q */
467         return 1;
468     }
469     unpacked_sig = gost_do_sign(tbs, tbs_len, EVP_PKEY_get0(pkey));
470     if (!unpacked_sig) {
471         return 0;
472     }
473     return pack_sign_cp(unpacked_sig, 32, sig, siglen);
474 }
475
476 static int pkey_gost_ec_cp_sign(EVP_PKEY_CTX *ctx, unsigned char *sig,
477                                 size_t *siglen, const unsigned char *tbs,
478                                 size_t tbs_len)
479 {
480     DSA_SIG *unpacked_sig = NULL;
481     EVP_PKEY *pkey = EVP_PKEY_CTX_get0_pkey(ctx);
482     int order = 0;
483
484     if (!siglen)
485         return 0;
486     if (!pkey)
487         return 0;
488
489     switch (EVP_PKEY_base_id(pkey)) {
490     case NID_id_GostR3410_2001:
491     case NID_id_GostR3410_2012_256:
492         order = 64;
493         break;
494     case NID_id_GostR3410_2012_512:
495         order = 128;
496         break;
497     default:
498         return 0;
499     }
500
501     if (!sig) {
502         *siglen = order;
503         return 1;
504     }
505     unpacked_sig = gost_ec_sign(tbs, tbs_len, EVP_PKEY_get0(pkey));
506     if (!unpacked_sig) {
507         return 0;
508     }
509     return pack_sign_cp(unpacked_sig, order / 2, sig, siglen);
510 }
511
512 /* ------------------- verify callbacks ---------------------------*/
513
514 static int pkey_gost94_cp_verify(EVP_PKEY_CTX *ctx, const unsigned char *sig,
515                                  size_t siglen, const unsigned char *tbs,
516                                  size_t tbs_len)
517 {
518     int ok = 0;
519     EVP_PKEY *pub_key = EVP_PKEY_CTX_get0_pkey(ctx);
520     DSA_SIG *s = (sig) ? unpack_cp_signature(sig, siglen) : NULL;
521     if (!s)
522         return 0;
523     if (pub_key)
524         ok = gost_do_verify(tbs, tbs_len, s, EVP_PKEY_get0(pub_key));
525     DSA_SIG_free(s);
526     return ok;
527 }
528
529 static int pkey_gost_ec_cp_verify(EVP_PKEY_CTX *ctx, const unsigned char *sig,
530                                   size_t siglen, const unsigned char *tbs,
531                                   size_t tbs_len)
532 {
533     int ok = 0;
534     EVP_PKEY *pub_key = EVP_PKEY_CTX_get0_pkey(ctx);
535     DSA_SIG *s = (sig) ? unpack_cp_signature(sig, siglen) : NULL;
536     if (!s)
537         return 0;
538 #ifdef DEBUG_SIGN
539     fprintf(stderr, "R=");
540     BN_print_fp(stderr, s->r);
541     fprintf(stderr, "\nS=");
542     BN_print_fp(stderr, s->s);
543     fprintf(stderr, "\n");
544 #endif
545     if (pub_key)
546         ok = gost_ec_verify(tbs, tbs_len, s, EVP_PKEY_get0(pub_key));
547     DSA_SIG_free(s);
548     return ok;
549 }
550
551 /* ------------- encrypt init -------------------------------------*/
552 /* Generates ephermeral key */
553 static int pkey_gost_encrypt_init(EVP_PKEY_CTX *ctx)
554 {
555     return 1;
556 }
557
558 /* --------------- Derive init ------------------------------------*/
559 static int pkey_gost_derive_init(EVP_PKEY_CTX *ctx)
560 {
561     return 1;
562 }
563
564 /* -------- PKEY_METHOD for GOST MAC algorithm --------------------*/
565 static int pkey_gost_mac_init(EVP_PKEY_CTX *ctx)
566 {
567     struct gost_mac_pmeth_data *data;
568     data = OPENSSL_malloc(sizeof(struct gost_mac_pmeth_data));
569     if (!data)
570         return 0;
571     memset(data, 0, sizeof(struct gost_mac_pmeth_data));
572     EVP_PKEY_CTX_set_data(ctx, data);
573     return 1;
574 }
575
576 static void pkey_gost_mac_cleanup(EVP_PKEY_CTX *ctx)
577 {
578     struct gost_mac_pmeth_data *data = EVP_PKEY_CTX_get_data(ctx);
579     if (data)
580         OPENSSL_free(data);
581 }
582
583 static int pkey_gost_mac_copy(EVP_PKEY_CTX *dst, EVP_PKEY_CTX *src)
584 {
585     struct gost_mac_pmeth_data *dst_data, *src_data;
586     if (!pkey_gost_mac_init(dst)) {
587         return 0;
588     }
589     src_data = EVP_PKEY_CTX_get_data(src);
590     dst_data = EVP_PKEY_CTX_get_data(dst);
591     if (!src_data || !dst_data)
592         return 0;
593
594     *dst_data = *src_data;
595     return 1;
596 }
597
598 static int pkey_gost_mac_ctrl(EVP_PKEY_CTX *ctx, int type, int p1, void *p2)
599 {
600     struct gost_mac_pmeth_data *data =
601         (struct gost_mac_pmeth_data *)EVP_PKEY_CTX_get_data(ctx);
602
603     switch (type) {
604     case EVP_PKEY_CTRL_MD:
605         {
606             int nid = EVP_MD_type((const EVP_MD *)p2);
607             if (nid != NID_id_Gost28147_89_MAC && nid != NID_gost_mac_12) {
608                 GOSTerr(GOST_F_PKEY_GOST_MAC_CTRL,
609                         GOST_R_INVALID_DIGEST_TYPE);
610                 return 0;
611             }
612             data->md = (EVP_MD *)p2;
613             return 1;
614         }
615         break;
616
617     case EVP_PKEY_CTRL_GET_MD:
618         *(const EVP_MD **)p2 = data->md;
619         return 1;
620
621     case EVP_PKEY_CTRL_PKCS7_ENCRYPT:
622     case EVP_PKEY_CTRL_PKCS7_DECRYPT:
623     case EVP_PKEY_CTRL_PKCS7_SIGN:
624         return 1;
625     case EVP_PKEY_CTRL_SET_MAC_KEY:
626         if (p1 != 32) {
627             GOSTerr(GOST_F_PKEY_GOST_MAC_CTRL, GOST_R_INVALID_MAC_KEY_LENGTH);
628             return 0;
629         }
630
631         memcpy(data->key, p2, 32);
632         data->key_set = 1;
633         return 1;
634     case EVP_PKEY_CTRL_DIGESTINIT:
635         {
636             EVP_MD_CTX *mctx = p2;
637             void *key;
638             if (!data->key_set) {
639                 EVP_PKEY *pkey = EVP_PKEY_CTX_get0_pkey(ctx);
640                 if (!pkey) {
641                     GOSTerr(GOST_F_PKEY_GOST_MAC_CTRL,
642                             GOST_R_MAC_KEY_NOT_SET);
643                     return 0;
644                 }
645                 key = EVP_PKEY_get0(pkey);
646                 if (!key) {
647                     GOSTerr(GOST_F_PKEY_GOST_MAC_CTRL,
648                             GOST_R_MAC_KEY_NOT_SET);
649                     return 0;
650                 }
651             } else {
652                 key = &(data->key);
653             }
654             return mctx->digest->md_ctrl(mctx, EVP_MD_CTRL_SET_KEY, 32, key);
655         }
656     }
657     return -2;
658 }
659
660 static int pkey_gost_mac_ctrl_str(EVP_PKEY_CTX *ctx,
661                                   const char *type, const char *value)
662 {
663     if (!strcmp(type, key_ctrl_string)) {
664         if (strlen(value) != 32) {
665             GOSTerr(GOST_F_PKEY_GOST_MAC_CTRL_STR,
666                     GOST_R_INVALID_MAC_KEY_LENGTH);
667             return 0;
668         }
669         return pkey_gost_mac_ctrl(ctx, EVP_PKEY_CTRL_SET_MAC_KEY,
670                                   32, (char *)value);
671     }
672     if (!strcmp(type, hexkey_ctrl_string)) {
673         long keylen = 0;
674         int ret;
675         unsigned char *keybuf = string_to_hex(value, &keylen);
676         if (!keybuf || keylen != 32) {
677             GOSTerr(GOST_F_PKEY_GOST_MAC_CTRL_STR,
678                     GOST_R_INVALID_MAC_KEY_LENGTH);
679             OPENSSL_free(keybuf);
680             return 0;
681         }
682         ret = pkey_gost_mac_ctrl(ctx, EVP_PKEY_CTRL_SET_MAC_KEY, 32, keybuf);
683         OPENSSL_free(keybuf);
684         return ret;
685
686     }
687     return -2;
688 }
689
690 static int pkey_gost_mac_keygen_base(EVP_PKEY_CTX *ctx,
691                                      EVP_PKEY *pkey, int mac_nid)
692 {
693     struct gost_mac_pmeth_data *data = EVP_PKEY_CTX_get_data(ctx);
694     unsigned char *keydata;
695     if (!data || !data->key_set) {
696         GOSTerr(GOST_F_PKEY_GOST_MAC_KEYGEN, GOST_R_MAC_KEY_NOT_SET);
697         return 0;
698     }
699     keydata = OPENSSL_malloc(32);
700     if (!keydata)
701         return 0;
702     memcpy(keydata, data->key, 32);
703     EVP_PKEY_assign(pkey, mac_nid, keydata);
704     return 1;
705 }
706
707 static int pkey_gost_mac_keygen_12(EVP_PKEY_CTX *ctx, EVP_PKEY *pkey)
708 {
709     return pkey_gost_mac_keygen_base(ctx, pkey, NID_gost_mac_12);
710 }
711
712 static int pkey_gost_mac_keygen(EVP_PKEY_CTX *ctx, EVP_PKEY *pkey)
713 {
714     return pkey_gost_mac_keygen_base(ctx, pkey, NID_id_Gost28147_89_MAC);
715 }
716
717 static int pkey_gost_mac_signctx_init(EVP_PKEY_CTX *ctx, EVP_MD_CTX *mctx)
718 {
719     return 1;
720 }
721
722 static int pkey_gost_mac_signctx(EVP_PKEY_CTX *ctx, unsigned char *sig,
723                                  size_t *siglen, EVP_MD_CTX *mctx)
724 {
725     unsigned int tmpsiglen;
726     int ret;
727
728     if (!siglen)
729         return 0;
730     tmpsiglen = *siglen;        /* for platforms where sizeof(int) !=
731                                  * sizeof(size_t) */
732
733     if (!sig) {
734         *siglen = 4;
735         return 1;
736     }
737     ret = EVP_DigestFinal_ex(mctx, sig, &tmpsiglen);
738     *siglen = tmpsiglen;
739     return ret;
740 }
741
742 /* ----------------------------------------------------------------*/
743 int register_pmeth_gost(int id, EVP_PKEY_METHOD **pmeth, int flags)
744 {
745     *pmeth = EVP_PKEY_meth_new(id, flags);
746     if (!*pmeth)
747         return 0;
748
749     switch (id) {
750     case NID_id_GostR3410_94:
751         EVP_PKEY_meth_set_ctrl(*pmeth, pkey_gost_ctrl, pkey_gost94_ctrl_str);
752         EVP_PKEY_meth_set_keygen(*pmeth, NULL, pkey_gost94cp_keygen);
753         EVP_PKEY_meth_set_sign(*pmeth, NULL, pkey_gost94_cp_sign);
754         EVP_PKEY_meth_set_verify(*pmeth, NULL, pkey_gost94_cp_verify);
755         EVP_PKEY_meth_set_encrypt(*pmeth,
756                                   pkey_gost_encrypt_init,
757                                   pkey_GOST94cp_encrypt);
758         EVP_PKEY_meth_set_decrypt(*pmeth, NULL, pkey_GOST94cp_decrypt);
759         EVP_PKEY_meth_set_derive(*pmeth,
760                                  pkey_gost_derive_init, pkey_gost94_derive);
761         EVP_PKEY_meth_set_paramgen(*pmeth, pkey_gost_paramgen_init,
762                                    pkey_gost94_paramgen);
763         break;
764     case NID_id_GostR3410_2001:
765         EVP_PKEY_meth_set_ctrl(*pmeth,
766                                pkey_gost_ctrl, pkey_gost_ec_ctrl_str_256);
767         EVP_PKEY_meth_set_sign(*pmeth, NULL, pkey_gost_ec_cp_sign);
768         EVP_PKEY_meth_set_verify(*pmeth, NULL, pkey_gost_ec_cp_verify);
769
770         EVP_PKEY_meth_set_keygen(*pmeth, NULL, pkey_gost2001cp_keygen);
771
772         EVP_PKEY_meth_set_encrypt(*pmeth,
773                                   pkey_gost_encrypt_init,
774                                   pkey_GOST_ECcp_encrypt);
775         EVP_PKEY_meth_set_decrypt(*pmeth, NULL, pkey_GOST_ECcp_decrypt);
776         EVP_PKEY_meth_set_derive(*pmeth,
777                                  pkey_gost_derive_init, pkey_gost_ec_derive);
778         EVP_PKEY_meth_set_paramgen(*pmeth, pkey_gost_paramgen_init,
779                                    pkey_gost2001_paramgen);
780         break;
781     case NID_id_GostR3410_2012_256:
782         EVP_PKEY_meth_set_ctrl(*pmeth,
783                                pkey_gost_ctrl, pkey_gost_ec_ctrl_str_256);
784         EVP_PKEY_meth_set_sign(*pmeth, NULL, pkey_gost_ec_cp_sign);
785         EVP_PKEY_meth_set_verify(*pmeth, NULL, pkey_gost_ec_cp_verify);
786
787         EVP_PKEY_meth_set_keygen(*pmeth, NULL, pkey_gost2012cp_keygen);
788
789         EVP_PKEY_meth_set_encrypt(*pmeth,
790                                   pkey_gost_encrypt_init,
791                                   pkey_GOST_ECcp_encrypt);
792         EVP_PKEY_meth_set_decrypt(*pmeth, NULL, pkey_GOST_ECcp_decrypt);
793         EVP_PKEY_meth_set_derive(*pmeth,
794                                  pkey_gost_derive_init, pkey_gost_ec_derive);
795         EVP_PKEY_meth_set_paramgen(*pmeth,
796                                    pkey_gost_paramgen_init,
797                                    pkey_gost2012_paramgen);
798         break;
799     case NID_id_GostR3410_2012_512:
800         EVP_PKEY_meth_set_ctrl(*pmeth,
801                                pkey_gost_ctrl, pkey_gost_ec_ctrl_str_512);
802         EVP_PKEY_meth_set_sign(*pmeth, NULL, pkey_gost_ec_cp_sign);
803         EVP_PKEY_meth_set_verify(*pmeth, NULL, pkey_gost_ec_cp_verify);
804
805         EVP_PKEY_meth_set_keygen(*pmeth, NULL, pkey_gost2012cp_keygen);
806
807         EVP_PKEY_meth_set_encrypt(*pmeth,
808                                   pkey_gost_encrypt_init,
809                                   pkey_GOST_ECcp_encrypt);
810         EVP_PKEY_meth_set_decrypt(*pmeth, NULL, pkey_GOST_ECcp_decrypt);
811         EVP_PKEY_meth_set_derive(*pmeth,
812                                  pkey_gost_derive_init, pkey_gost_ec_derive);
813         EVP_PKEY_meth_set_paramgen(*pmeth,
814                                    pkey_gost_paramgen_init,
815                                    pkey_gost2012_paramgen);
816         break;
817     case NID_id_Gost28147_89_MAC:
818         EVP_PKEY_meth_set_ctrl(*pmeth, pkey_gost_mac_ctrl,
819                                pkey_gost_mac_ctrl_str);
820         EVP_PKEY_meth_set_signctx(*pmeth, pkey_gost_mac_signctx_init,
821                                   pkey_gost_mac_signctx);
822         EVP_PKEY_meth_set_keygen(*pmeth, NULL, pkey_gost_mac_keygen);
823         EVP_PKEY_meth_set_init(*pmeth, pkey_gost_mac_init);
824         EVP_PKEY_meth_set_cleanup(*pmeth, pkey_gost_mac_cleanup);
825         EVP_PKEY_meth_set_copy(*pmeth, pkey_gost_mac_copy);
826         return 1;
827     case NID_gost_mac_12:
828         EVP_PKEY_meth_set_ctrl(*pmeth, pkey_gost_mac_ctrl,
829                                pkey_gost_mac_ctrl_str);
830         EVP_PKEY_meth_set_signctx(*pmeth, pkey_gost_mac_signctx_init,
831                                   pkey_gost_mac_signctx);
832         EVP_PKEY_meth_set_keygen(*pmeth, NULL, pkey_gost_mac_keygen_12);
833         EVP_PKEY_meth_set_init(*pmeth, pkey_gost_mac_init);
834         EVP_PKEY_meth_set_cleanup(*pmeth, pkey_gost_mac_cleanup);
835         EVP_PKEY_meth_set_copy(*pmeth, pkey_gost_mac_copy);
836         return 1;
837     default:                   /* Unsupported method */
838         return 0;
839     }
840     EVP_PKEY_meth_set_init(*pmeth, pkey_gost_init);
841     EVP_PKEY_meth_set_cleanup(*pmeth, pkey_gost_cleanup);
842
843     EVP_PKEY_meth_set_copy(*pmeth, pkey_gost_copy);
844     /*
845      * FIXME derive etc...
846      */
847
848     return 1;
849 }