]> www.wagner.pp.ru Git - openssl-gost/engine.git/blob - gost_ec_sign.c
tcl_tests: ca.try: Ignore openssl crl exit status for 'corrupted CRL' test
[openssl-gost/engine.git] / gost_ec_sign.c
1 /**********************************************************************
2  *                        gost_ec_sign.c                              *
3  *             Copyright (c) 2005-2013 Cryptocom LTD                  *
4  *         This file is distributed under the same license as OpenSSL *
5  *                                                                    *
6  *          Implementation of GOST R 34.10-2001                       *
7  *          Requires OpenSSL 1.0.0+ for compilation                   *
8  **********************************************************************/
9 #include "gost_lcl.h"
10 #include <string.h>
11 #include <openssl/rand.h>
12 #include <openssl/ecdsa.h>
13 #include <openssl/err.h>
14 #include "e_gost_err.h"
15 #ifdef DEBUG_SIGN
16 extern
17 void dump_signature(const char *message, const unsigned char *buffer,
18                     size_t len);
19 void dump_dsa_sig(const char *message, ECDSA_SIG *sig);
20 #else
21
22 # define dump_signature(a,b,c)
23 # define dump_dsa_sig(a,b)
24 #endif
25
26 static R3410_ec_params *gost_nid2params(int nid)
27 {
28     R3410_ec_params *params;
29
30     /* Map tc26-2012 256-bit parameters to cp-2001 parameters */
31     switch (nid) {
32     case NID_id_tc26_gost_3410_2012_256_paramSetB:
33         nid = NID_id_GostR3410_2001_CryptoPro_A_ParamSet;
34         break;
35     case NID_id_tc26_gost_3410_2012_256_paramSetC:
36         nid = NID_id_GostR3410_2001_CryptoPro_B_ParamSet;
37         break;
38     case NID_id_tc26_gost_3410_2012_256_paramSetD:
39         nid = NID_id_GostR3410_2001_CryptoPro_C_ParamSet;
40     }
41
42     /* Search nid in 2012 paramset */
43     params = R3410_2012_512_paramset;
44     while (params->nid != NID_undef) {
45         if (params->nid == nid)
46             return params;
47         params++;
48     }
49
50     /* Search nid in 2001 paramset */
51     params = R3410_2001_paramset;
52     while (params->nid != NID_undef) {
53         if (params->nid == nid)
54             return params;
55         params++;
56     }
57
58     return NULL;
59 }
60
61 void free_cached_groups()
62 {
63     R3410_ec_params *params;
64
65     /* Search nid in 2012 paramset */
66     params = R3410_2012_512_paramset;
67     while (params->nid != NID_undef) {
68         EC_GROUP_free(params->group);
69         params->group = NULL;
70         params++;
71     }
72
73     /* Search nid in 2001 paramset */
74     params = R3410_2001_paramset;
75     while (params->nid != NID_undef) {
76         EC_GROUP_free(params->group);
77         params->group = NULL;
78         params++;
79     }
80 }
81
82 /*
83  * Fills EC_KEY structure hidden in the app_data field of DSA structure
84  * with parameter information, extracted from parameter array in
85  * params.c file.
86  *
87  * Also fils DSA->q field with copy of EC_GROUP order field to make
88  * DSA_size function work
89  */
90 int fill_GOST_EC_params(EC_KEY *eckey, int nid)
91 {
92     R3410_ec_params *params = gost_nid2params(nid);
93     EC_GROUP *grp = NULL;
94     EC_POINT *P = NULL;
95     BIGNUM *p = NULL, *q = NULL, *a = NULL, *b = NULL, *x = NULL, *y =
96         NULL, *cofactor = NULL;
97     BN_CTX *ctx = NULL;
98     int ok = 0;
99
100     if (!eckey || !params) {
101         GOSTerr(GOST_F_FILL_GOST_EC_PARAMS, GOST_R_UNSUPPORTED_PARAMETER_SET);
102         return 0;
103     }
104
105     if (params->group) {
106         EC_GROUP_set_curve_name(params->group, nid);
107         if (!EC_KEY_set_group(eckey, params->group)) {
108             GOSTerr(GOST_F_FILL_GOST_EC_PARAMS, ERR_R_INTERNAL_ERROR);
109             goto end;
110         }
111         return 1;
112     }
113
114     if (!(ctx = BN_CTX_new())) {
115         GOSTerr(GOST_F_FILL_GOST_EC_PARAMS, ERR_R_MALLOC_FAILURE);
116         return 0;
117     }
118
119     BN_CTX_start(ctx);
120     p = BN_CTX_get(ctx);
121     a = BN_CTX_get(ctx);
122     b = BN_CTX_get(ctx);
123     x = BN_CTX_get(ctx);
124     y = BN_CTX_get(ctx);
125     q = BN_CTX_get(ctx);
126     cofactor = BN_CTX_get(ctx);
127     if (!p || !a || !b || !x || !y || !q || !cofactor) {
128         GOSTerr(GOST_F_FILL_GOST_EC_PARAMS, ERR_R_MALLOC_FAILURE);
129         goto end;
130     }
131
132     if (!BN_hex2bn(&p, params->p)
133         || !BN_hex2bn(&a, params->a)
134         || !BN_hex2bn(&b, params->b)
135         || !BN_hex2bn(&cofactor, params->cofactor)) {
136         GOSTerr(GOST_F_FILL_GOST_EC_PARAMS, ERR_R_INTERNAL_ERROR);
137         goto end;
138     }
139
140     grp = EC_GROUP_new_curve_GFp(p, a, b, ctx);
141     if (!grp) {
142         GOSTerr(GOST_F_FILL_GOST_EC_PARAMS, ERR_R_MALLOC_FAILURE);
143         goto end;
144     }
145
146     P = EC_POINT_new(grp);
147     if (!P) {
148         GOSTerr(GOST_F_FILL_GOST_EC_PARAMS, ERR_R_MALLOC_FAILURE);
149         goto end;
150     }
151
152     if (!BN_hex2bn(&x, params->x)
153         || !BN_hex2bn(&y, params->y)
154         || !EC_POINT_set_affine_coordinates(grp, P, x, y, ctx)
155         || !BN_hex2bn(&q, params->q)) {
156         GOSTerr(GOST_F_FILL_GOST_EC_PARAMS, ERR_R_INTERNAL_ERROR);
157         goto end;
158     }
159
160     if (!EC_GROUP_set_generator(grp, P, q, cofactor)) {
161         GOSTerr(GOST_F_FILL_GOST_EC_PARAMS, ERR_R_INTERNAL_ERROR);
162         goto end;
163     }
164     EC_GROUP_set_curve_name(grp, nid);
165     params->group = grp;
166     if (!EC_KEY_set_group(eckey, grp)) {
167         GOSTerr(GOST_F_FILL_GOST_EC_PARAMS, ERR_R_INTERNAL_ERROR);
168         goto end;
169     }
170     ok = 1;
171  end:
172     EC_POINT_free(P);
173     BN_CTX_end(ctx);
174     BN_CTX_free(ctx);
175     return ok;
176 }
177
178 /*
179  * Computes gost_ec signature as ECDSA_SIG structure
180  *
181  */
182 ECDSA_SIG *gost_ec_sign(const unsigned char *dgst, int dlen, EC_KEY *eckey)
183 {
184     ECDSA_SIG *newsig = NULL, *ret = NULL;
185     BIGNUM *md = NULL;
186     BIGNUM *order = NULL;
187     const EC_GROUP *group;
188     const BIGNUM *priv_key;
189     BIGNUM *r = NULL, *s = NULL, *X = NULL, *tmp = NULL, *tmp2 = NULL,
190         *k = NULL, *e = NULL;
191
192     BIGNUM *new_r = NULL, *new_s = NULL;
193
194     EC_POINT *C = NULL;
195     BN_CTX *ctx;
196
197     OPENSSL_assert(dgst != NULL && eckey != NULL);
198
199     if (!(ctx = BN_CTX_secure_new())) {
200         GOSTerr(GOST_F_GOST_EC_SIGN, ERR_R_MALLOC_FAILURE);
201         return NULL;
202     }
203
204     BN_CTX_start(ctx);
205     OPENSSL_assert(dlen == 32 || dlen == 64);
206     md = BN_lebin2bn(dgst, dlen, NULL);
207     newsig = ECDSA_SIG_new();
208     if (!newsig || !md) {
209         GOSTerr(GOST_F_GOST_EC_SIGN, ERR_R_MALLOC_FAILURE);
210         goto err;
211     }
212     group = EC_KEY_get0_group(eckey);
213     if (!group) {
214         GOSTerr(GOST_F_GOST_EC_SIGN, ERR_R_INTERNAL_ERROR);
215         goto err;
216     }
217     order = BN_CTX_get(ctx);
218     if (!order || !EC_GROUP_get_order(group, order, ctx)) {
219         GOSTerr(GOST_F_GOST_EC_SIGN, ERR_R_INTERNAL_ERROR);
220         goto err;
221     }
222     priv_key = EC_KEY_get0_private_key(eckey);
223     if (!priv_key) {
224         GOSTerr(GOST_F_GOST_EC_SIGN, ERR_R_INTERNAL_ERROR);
225         goto err;
226     }
227     e = BN_CTX_get(ctx);
228     if (!e || !BN_mod(e, md, order, ctx)) {
229         GOSTerr(GOST_F_GOST_EC_SIGN, ERR_R_INTERNAL_ERROR);
230         goto err;
231     }
232 #ifdef DEBUG_SIGN
233     fprintf(stderr, "digest as bignum=");
234     BN_print_fp(stderr, md);
235     fprintf(stderr, "\ndigest mod q=");
236     BN_print_fp(stderr, e);
237     fprintf(stderr, "\n");
238 #endif
239     if (BN_is_zero(e)) {
240         BN_one(e);
241     }
242     k = BN_CTX_get(ctx);
243     C = EC_POINT_new(group);
244     if (!k || !C) {
245         GOSTerr(GOST_F_GOST_EC_SIGN, ERR_R_MALLOC_FAILURE);
246         goto err;
247     }
248
249     do {
250         do {
251             if (!BN_rand_range(k, order)) {
252                 GOSTerr(GOST_F_GOST_EC_SIGN, GOST_R_RNG_ERROR);
253                 goto err;
254             }
255             if (!gost_ec_point_mul(group, C, k, NULL, NULL, ctx)) {
256                 GOSTerr(GOST_F_GOST_EC_SIGN, ERR_R_EC_LIB);
257                 goto err;
258             }
259             if (!X)
260                 X = BN_CTX_get(ctx);
261             if (!r)
262                 r = BN_CTX_get(ctx);
263             if (!X || !r) {
264                 GOSTerr(GOST_F_GOST_EC_SIGN, ERR_R_MALLOC_FAILURE);
265                 goto err;
266             }
267             if (!EC_POINT_get_affine_coordinates(group, C, X, NULL, ctx)) {
268                 GOSTerr(GOST_F_GOST_EC_SIGN, ERR_R_EC_LIB);
269                 goto err;
270             }
271
272             if (!BN_nnmod(r, X, order, ctx)) {
273                 GOSTerr(GOST_F_GOST_EC_SIGN, ERR_R_INTERNAL_ERROR);
274                 goto err;
275             }
276         }
277         while (BN_is_zero(r));
278         /* s =  (r*priv_key+k*e) mod order */
279         if (!tmp)
280             tmp = BN_CTX_get(ctx);
281         if (!tmp2)
282             tmp2 = BN_CTX_get(ctx);
283         if (!s)
284             s = BN_CTX_get(ctx);
285         if (!tmp || !tmp2 || !s) {
286             GOSTerr(GOST_F_GOST_EC_SIGN, ERR_R_MALLOC_FAILURE);
287             goto err;
288         }
289
290         if (!BN_mod_mul(tmp, priv_key, r, order, ctx)
291             || !BN_mod_mul(tmp2, k, e, order, ctx)
292             || !BN_mod_add(s, tmp, tmp2, order, ctx)) {
293             GOSTerr(GOST_F_GOST_EC_SIGN, ERR_R_INTERNAL_ERROR);
294             goto err;
295         }
296     }
297     while (BN_is_zero(s));
298
299     new_s = BN_dup(s);
300     new_r = BN_dup(r);
301     if (!new_s || !new_r) {
302         GOSTerr(GOST_F_GOST_EC_SIGN, ERR_R_MALLOC_FAILURE);
303         goto err;
304     }
305     ECDSA_SIG_set0(newsig, new_r, new_s);
306
307     ret = newsig;
308  err:
309     BN_CTX_end(ctx);
310     BN_CTX_free(ctx);
311     if (C)
312         EC_POINT_free(C);
313     if (md)
314         BN_free(md);
315     if (!ret && newsig) {
316         ECDSA_SIG_free(newsig);
317     }
318     return ret;
319 }
320
321 /*
322  * Verifies gost ec signature
323  *
324  */
325 int gost_ec_verify(const unsigned char *dgst, int dgst_len,
326                    ECDSA_SIG *sig, EC_KEY *ec)
327 {
328     BN_CTX *ctx;
329     const EC_GROUP *group = (ec) ? EC_KEY_get0_group(ec) : NULL;
330     BIGNUM *order;
331     BIGNUM *md = NULL, *e = NULL, *R = NULL, *v = NULL, *z1 = NULL, *z2 = NULL;
332     const BIGNUM *sig_s = NULL, *sig_r = NULL;
333     BIGNUM *X = NULL, *tmp = NULL;
334     EC_POINT *C = NULL;
335     const EC_POINT *pub_key = NULL;
336     int ok = 0;
337
338     OPENSSL_assert(dgst != NULL && sig != NULL && group != NULL);
339
340     if (!(ctx = BN_CTX_new())) {
341         GOSTerr(GOST_F_GOST_EC_VERIFY, ERR_R_MALLOC_FAILURE);
342         return 0;
343     }
344
345     BN_CTX_start(ctx);
346     order = BN_CTX_get(ctx);
347     e = BN_CTX_get(ctx);
348     z1 = BN_CTX_get(ctx);
349     z2 = BN_CTX_get(ctx);
350     tmp = BN_CTX_get(ctx);
351     X = BN_CTX_get(ctx);
352     R = BN_CTX_get(ctx);
353     v = BN_CTX_get(ctx);
354     if (!order || !e || !z1 || !z2 || !tmp || !X || !R || !v) {
355         GOSTerr(GOST_F_GOST_EC_VERIFY, ERR_R_MALLOC_FAILURE);
356         goto err;
357     }
358
359     pub_key = EC_KEY_get0_public_key(ec);
360     if (!pub_key || !EC_GROUP_get_order(group, order, ctx)) {
361         GOSTerr(GOST_F_GOST_EC_VERIFY, ERR_R_INTERNAL_ERROR);
362         goto err;
363     }
364
365     ECDSA_SIG_get0(sig, &sig_r, &sig_s);
366
367     if (BN_is_zero(sig_s) || BN_is_zero(sig_r) ||
368         BN_is_negative(sig_s) || BN_is_negative(sig_r) ||
369         BN_ucmp(sig_s, order) >= 0 || BN_ucmp(sig_r, order) >= 0) {
370         GOSTerr(GOST_F_GOST_EC_VERIFY, GOST_R_SIGNATURE_PARTS_GREATER_THAN_Q);
371         goto err;
372     }
373
374     OPENSSL_assert(dgst_len == 32 || dgst_len == 64);
375     md = BN_lebin2bn(dgst, dgst_len, NULL);
376     if (!md || !BN_mod(e, md, order, ctx)) {
377         GOSTerr(GOST_F_GOST_EC_VERIFY, ERR_R_INTERNAL_ERROR);
378         goto err;
379     }
380 #ifdef DEBUG_SIGN
381     fprintf(stderr, "digest as bignum: ");
382     BN_print_fp(stderr, md);
383     fprintf(stderr, "\ndigest mod q: ");
384     BN_print_fp(stderr, e);
385 #endif
386     if (BN_is_zero(e) && !BN_one(e)) {
387         GOSTerr(GOST_F_GOST_EC_VERIFY, ERR_R_INTERNAL_ERROR);
388         goto err;
389     }
390     v = BN_mod_inverse(v, e, order, ctx);
391     if (!v || !BN_mod_mul(z1, sig_s, v, order, ctx)
392         || !BN_sub(tmp, order, sig_r)
393         || !BN_mod_mul(z2, tmp, v, order, ctx)) {
394         GOSTerr(GOST_F_GOST_EC_VERIFY, ERR_R_INTERNAL_ERROR);
395         goto err;
396     }
397 #ifdef DEBUG_SIGN
398     fprintf(stderr, "\nInverted digest value: ");
399     BN_print_fp(stderr, v);
400     fprintf(stderr, "\nz1: ");
401     BN_print_fp(stderr, z1);
402     fprintf(stderr, "\nz2: ");
403     BN_print_fp(stderr, z2);
404 #endif
405     C = EC_POINT_new(group);
406     if (!C) {
407         GOSTerr(GOST_F_GOST_EC_VERIFY, ERR_R_MALLOC_FAILURE);
408         goto err;
409     }
410     if (!gost_ec_point_mul(group, C, z1, pub_key, z2, ctx)) {
411         GOSTerr(GOST_F_GOST_EC_VERIFY, ERR_R_EC_LIB);
412         goto err;
413     }
414     if (!EC_POINT_get_affine_coordinates(group, C, X, NULL, ctx)) {
415         GOSTerr(GOST_F_GOST_EC_VERIFY, ERR_R_EC_LIB);
416         goto err;
417     }
418     if (!BN_mod(R, X, order, ctx)) {
419         GOSTerr(GOST_F_GOST_EC_VERIFY, ERR_R_INTERNAL_ERROR);
420         goto err;
421     }
422 #ifdef DEBUG_SIGN
423     fprintf(stderr, "\nX=");
424     BN_print_fp(stderr, X);
425     fprintf(stderr, "\nX mod q=");
426     BN_print_fp(stderr, R);
427     fprintf(stderr, "\n");
428 #endif
429     if (BN_cmp(R, sig_r) != 0) {
430         GOSTerr(GOST_F_GOST_EC_VERIFY, GOST_R_SIGNATURE_MISMATCH);
431     } else {
432         ok = 1;
433     }
434  err:
435     if (C)
436         EC_POINT_free(C);
437     BN_CTX_end(ctx);
438     BN_CTX_free(ctx);
439     if (md)
440         BN_free(md);
441     return ok;
442 }
443
444 /*
445  * Computes GOST R 34.10-2001 public key
446  * or GOST R 34.10-2012 public key
447  *
448  */
449 int gost_ec_compute_public(EC_KEY *ec)
450 {
451     const EC_GROUP *group = (ec) ? EC_KEY_get0_group(ec) : NULL;
452     EC_POINT *pub_key = NULL;
453     const BIGNUM *priv_key = NULL;
454     BN_CTX *ctx = NULL;
455     int ok = 0;
456
457     if (!group) {
458         GOSTerr(GOST_F_GOST_EC_COMPUTE_PUBLIC, GOST_R_KEY_IS_NOT_INITIALIZED);
459         return 0;
460     }
461
462     ctx = BN_CTX_secure_new();
463     if (!ctx) {
464         GOSTerr(GOST_F_GOST_EC_COMPUTE_PUBLIC, ERR_R_MALLOC_FAILURE);
465         return 0;
466     }
467
468     BN_CTX_start(ctx);
469     priv_key = EC_KEY_get0_private_key(ec);
470     if (!priv_key) {
471         GOSTerr(GOST_F_GOST_EC_COMPUTE_PUBLIC, ERR_R_EC_LIB);
472         goto err;
473     }
474
475     pub_key = EC_POINT_new(group);
476     if (!pub_key) {
477         GOSTerr(GOST_F_GOST_EC_COMPUTE_PUBLIC, ERR_R_MALLOC_FAILURE);
478         goto err;
479     }
480
481     if (!gost_ec_point_mul(group, pub_key, priv_key, NULL, NULL, ctx)) {
482         GOSTerr(GOST_F_GOST_EC_COMPUTE_PUBLIC, ERR_R_EC_LIB);
483         goto err;
484     }
485     if (!EC_KEY_set_public_key(ec, pub_key)) {
486         GOSTerr(GOST_F_GOST_EC_COMPUTE_PUBLIC, ERR_R_EC_LIB);
487         goto err;
488     }
489     ok = 1;
490  err:
491     if (pub_key)
492         EC_POINT_free(pub_key);
493     BN_CTX_end(ctx);
494     BN_CTX_free(ctx);
495     return ok;
496 }
497
498 int gost_ec_point_mul(const EC_GROUP *group, EC_POINT *r, const BIGNUM *n,
499                       const EC_POINT *q, const BIGNUM *m, BN_CTX *ctx)
500 {
501     if (group == NULL || r == NULL || ctx == NULL)
502         return 0;
503
504     if (m != NULL && n != NULL) {
505         /* verification */
506         if (q == NULL)
507             return 0;
508         switch(EC_GROUP_get_curve_name(group)) {
509             case NID_id_GostR3410_2001_CryptoPro_A_ParamSet:
510             case NID_id_GostR3410_2001_CryptoPro_XchA_ParamSet:
511             case NID_id_tc26_gost_3410_2012_256_paramSetB:
512                 return point_mul_two_id_GostR3410_2001_CryptoPro_A_ParamSet(group, r, n, q, m, ctx);
513             case NID_id_GostR3410_2001_CryptoPro_B_ParamSet:
514             case NID_id_tc26_gost_3410_2012_256_paramSetC:
515                 return point_mul_two_id_GostR3410_2001_CryptoPro_B_ParamSet(group, r, n, q, m, ctx);
516             case NID_id_GostR3410_2001_CryptoPro_C_ParamSet:
517             case NID_id_GostR3410_2001_CryptoPro_XchB_ParamSet:
518             case NID_id_tc26_gost_3410_2012_256_paramSetD:
519                 return point_mul_two_id_GostR3410_2001_CryptoPro_C_ParamSet(group, r, n, q, m, ctx);
520             case NID_id_GostR3410_2001_TestParamSet:
521                 return point_mul_two_id_GostR3410_2001_TestParamSet(group, r, n, q, m, ctx);
522             case NID_id_tc26_gost_3410_2012_256_paramSetA:
523                 return point_mul_two_id_tc26_gost_3410_2012_256_paramSetA(group, r, n, q, m, ctx);
524             case NID_id_tc26_gost_3410_2012_512_paramSetA:
525                 return point_mul_two_id_tc26_gost_3410_2012_512_paramSetA(group, r, n, q, m, ctx);
526             case NID_id_tc26_gost_3410_2012_512_paramSetB:
527                 return point_mul_two_id_tc26_gost_3410_2012_512_paramSetB(group, r, n, q, m, ctx);
528             case NID_id_tc26_gost_3410_2012_512_paramSetC:
529                 return point_mul_two_id_tc26_gost_3410_2012_512_paramSetC(group, r, n, q, m, ctx);
530             default:
531                 return EC_POINT_mul(group, r, n, q, m, ctx);
532         }
533     } else if (n != NULL) {
534         /* mul g */
535         switch(EC_GROUP_get_curve_name(group)) {
536             case NID_id_GostR3410_2001_CryptoPro_A_ParamSet:
537             case NID_id_GostR3410_2001_CryptoPro_XchA_ParamSet:
538             case NID_id_tc26_gost_3410_2012_256_paramSetB:
539                 return point_mul_g_id_GostR3410_2001_CryptoPro_A_ParamSet(group, r, n, ctx);
540             case NID_id_GostR3410_2001_CryptoPro_B_ParamSet:
541             case NID_id_tc26_gost_3410_2012_256_paramSetC:
542                 return point_mul_g_id_GostR3410_2001_CryptoPro_B_ParamSet(group, r, n, ctx);
543             case NID_id_GostR3410_2001_CryptoPro_C_ParamSet:
544             case NID_id_GostR3410_2001_CryptoPro_XchB_ParamSet:
545             case NID_id_tc26_gost_3410_2012_256_paramSetD:
546                 return point_mul_g_id_GostR3410_2001_CryptoPro_C_ParamSet(group, r, n, ctx);
547             case NID_id_GostR3410_2001_TestParamSet:
548                 return point_mul_g_id_GostR3410_2001_TestParamSet(group, r, n, ctx);
549             case NID_id_tc26_gost_3410_2012_256_paramSetA:
550                 return point_mul_g_id_tc26_gost_3410_2012_256_paramSetA(group, r, n, ctx);
551             case NID_id_tc26_gost_3410_2012_512_paramSetA:
552                 return point_mul_g_id_tc26_gost_3410_2012_512_paramSetA(group, r, n, ctx);
553             case NID_id_tc26_gost_3410_2012_512_paramSetB:
554                 return point_mul_g_id_tc26_gost_3410_2012_512_paramSetB(group, r, n, ctx);
555             case NID_id_tc26_gost_3410_2012_512_paramSetC:
556                 return point_mul_g_id_tc26_gost_3410_2012_512_paramSetC(group, r, n, ctx);
557             default:
558                 return EC_POINT_mul(group, r, n, q, m, ctx);
559         }
560     } else if (m != NULL) {
561         if (q == NULL)
562             return 0;
563         /* mul */
564         switch(EC_GROUP_get_curve_name(group)) {
565             case NID_id_GostR3410_2001_CryptoPro_A_ParamSet:
566             case NID_id_GostR3410_2001_CryptoPro_XchA_ParamSet:
567             case NID_id_tc26_gost_3410_2012_256_paramSetB:
568                 return point_mul_id_GostR3410_2001_CryptoPro_A_ParamSet(group, r, q, m, ctx);
569             case NID_id_GostR3410_2001_CryptoPro_B_ParamSet:
570             case NID_id_tc26_gost_3410_2012_256_paramSetC:
571                 return point_mul_id_GostR3410_2001_CryptoPro_B_ParamSet(group, r, q, m, ctx);
572             case NID_id_GostR3410_2001_CryptoPro_C_ParamSet:
573             case NID_id_GostR3410_2001_CryptoPro_XchB_ParamSet:
574             case NID_id_tc26_gost_3410_2012_256_paramSetD:
575                 return point_mul_id_GostR3410_2001_CryptoPro_C_ParamSet(group, r, q, m, ctx);
576             case NID_id_GostR3410_2001_TestParamSet:
577                 return point_mul_id_GostR3410_2001_TestParamSet(group, r, q, m, ctx);
578             case NID_id_tc26_gost_3410_2012_256_paramSetA:
579                 return point_mul_id_tc26_gost_3410_2012_256_paramSetA(group, r, q, m, ctx);
580             case NID_id_tc26_gost_3410_2012_512_paramSetA:
581                 return point_mul_id_tc26_gost_3410_2012_512_paramSetA(group, r, q, m, ctx);
582             case NID_id_tc26_gost_3410_2012_512_paramSetB:
583                 return point_mul_id_tc26_gost_3410_2012_512_paramSetB(group, r, q, m, ctx);
584             case NID_id_tc26_gost_3410_2012_512_paramSetC:
585                 return point_mul_id_tc26_gost_3410_2012_512_paramSetC(group, r, q, m, ctx);
586             default:
587                 return EC_POINT_mul(group, r, n, q, m, ctx);
588         }
589     }
590     return 0;
591 }
592
593 /*
594  *
595  * Generates GOST R 34.10-2001
596  * or GOST R 34.10-2012 keypair
597  *
598  */
599 int gost_ec_keygen(EC_KEY *ec)
600 {
601     BIGNUM *order = NULL, *d = NULL;
602     const EC_GROUP *group = (ec) ? EC_KEY_get0_group(ec) : NULL;
603     int ok = 0;
604
605     if (!group) {
606         GOSTerr(GOST_F_GOST_EC_KEYGEN, ERR_R_INTERNAL_ERROR);
607         return 0;
608     }
609
610     order = BN_new();
611     d = BN_secure_new();
612     if (!order || !d) {
613         GOSTerr(GOST_F_GOST_EC_KEYGEN, ERR_R_MALLOC_FAILURE);
614         goto end;
615     }
616
617     if (!EC_GROUP_get_order(group, order, NULL)) {
618         GOSTerr(GOST_F_GOST_EC_KEYGEN, ERR_R_INTERNAL_ERROR);
619         goto end;
620     }
621
622     do {
623         if (!BN_rand_range(d, order)) {
624             GOSTerr(GOST_F_GOST_EC_KEYGEN, GOST_R_RNG_ERROR);
625             goto end;
626         }
627     }
628     while (BN_is_zero(d));
629
630     if (!EC_KEY_set_private_key(ec, d)) {
631         GOSTerr(GOST_F_GOST_EC_KEYGEN, ERR_R_INTERNAL_ERROR);
632         goto end;
633     }
634
635     ok = 1;
636  end:
637     if (d)
638         BN_free(d);
639     if (order)
640         BN_free(order);
641
642     return (ok) ? gost_ec_compute_public(ec) : 0;
643 }