1238384Sjkim/**********************************************************************
2238384Sjkim *                          gost2001.c                                *
3238384Sjkim *             Copyright (c) 2005-2006 Cryptocom LTD                  *
4238384Sjkim *         This file is distributed under the same license as OpenSSL *
5238384Sjkim *                                                                    *
6296341Sdelphij *          Implementation of GOST R 34.10-2001                                   *
7238384Sjkim *          Requires OpenSSL 0.9.9 for compilation                    *
8238384Sjkim **********************************************************************/
9238384Sjkim#include "gost_lcl.h"
10238384Sjkim#include "gost_params.h"
11238384Sjkim#include <string.h>
12238384Sjkim#include <openssl/rand.h>
13238384Sjkim#include <openssl/ecdsa.h>
14238384Sjkim#include <openssl/err.h>
15238384Sjkim#include "e_gost_err.h"
16238384Sjkim#ifdef DEBUG_SIGN
17296341Sdelphijextern
18296341Sdelphijvoid dump_signature(const char *message, const unsigned char *buffer,
19296341Sdelphij                    size_t len);
20238384Sjkimvoid dump_dsa_sig(const char *message, DSA_SIG *sig);
21238384Sjkim#else
22238384Sjkim
23296341Sdelphij# define dump_signature(a,b,c)
24296341Sdelphij# define dump_dsa_sig(a,b)
25238384Sjkim#endif
26238384Sjkim
27238384Sjkim/*
28238384Sjkim * Fills EC_KEY structure hidden in the app_data field of DSA structure
29238384Sjkim * with parameter information, extracted from parameter array in
30238384Sjkim * params.c file.
31238384Sjkim *
32238384Sjkim * Also fils DSA->q field with copy of EC_GROUP order field to make
33238384Sjkim * DSA_size function work
34296341Sdelphij */
35238384Sjkimint fill_GOST2001_params(EC_KEY *eckey, int nid)
36296341Sdelphij{
37296341Sdelphij    R3410_2001_params *params = R3410_2001_paramset;
38296341Sdelphij    EC_GROUP *grp = NULL;
39296341Sdelphij    BIGNUM *p = NULL, *q = NULL, *a = NULL, *b = NULL, *x = NULL, *y = NULL;
40296341Sdelphij    EC_POINT *P = NULL;
41296341Sdelphij    BN_CTX *ctx = BN_CTX_new();
42296341Sdelphij    int ok = 0;
43238384Sjkim
44296341Sdelphij    if(!ctx) {
45296341Sdelphij        GOSTerr(GOST_F_FILL_GOST2001_PARAMS, ERR_R_MALLOC_FAILURE);
46296341Sdelphij        goto err;
47296341Sdelphij    }
48238384Sjkim
49296341Sdelphij    BN_CTX_start(ctx);
50296341Sdelphij    p = BN_CTX_get(ctx);
51296341Sdelphij    a = BN_CTX_get(ctx);
52296341Sdelphij    b = BN_CTX_get(ctx);
53296341Sdelphij    x = BN_CTX_get(ctx);
54296341Sdelphij    y = BN_CTX_get(ctx);
55296341Sdelphij    q = BN_CTX_get(ctx);
56296341Sdelphij    if(!p || !a || !b || !x || !y || !q) {
57296341Sdelphij        GOSTerr(GOST_F_FILL_GOST2001_PARAMS, ERR_R_MALLOC_FAILURE);
58296341Sdelphij        goto err;
59296341Sdelphij    }
60296341Sdelphij    while (params->nid != NID_undef && params->nid != nid)
61296341Sdelphij        params++;
62296341Sdelphij    if (params->nid == NID_undef) {
63296341Sdelphij        GOSTerr(GOST_F_FILL_GOST2001_PARAMS,
64296341Sdelphij                GOST_R_UNSUPPORTED_PARAMETER_SET);
65296341Sdelphij        goto err;
66296341Sdelphij    }
67296341Sdelphij    if(!BN_hex2bn(&p, params->p)
68296341Sdelphij        || !BN_hex2bn(&a, params->a)
69296341Sdelphij        || !BN_hex2bn(&b, params->b)) {
70296341Sdelphij        GOSTerr(GOST_F_FILL_GOST2001_PARAMS,
71296341Sdelphij                ERR_R_INTERNAL_ERROR);
72296341Sdelphij        goto err;
73296341Sdelphij    }
74238384Sjkim
75296341Sdelphij    grp = EC_GROUP_new_curve_GFp(p, a, b, ctx);
76296341Sdelphij    if(!grp)  {
77296341Sdelphij        GOSTerr(GOST_F_FILL_GOST2001_PARAMS, ERR_R_MALLOC_FAILURE);
78296341Sdelphij        goto err;
79296341Sdelphij    }
80238384Sjkim
81296341Sdelphij    P = EC_POINT_new(grp);
82296341Sdelphij    if(!P)  {
83296341Sdelphij        GOSTerr(GOST_F_FILL_GOST2001_PARAMS, ERR_R_MALLOC_FAILURE);
84296341Sdelphij        goto err;
85296341Sdelphij    }
86238384Sjkim
87296341Sdelphij    if(!BN_hex2bn(&x, params->x)
88296341Sdelphij        || !BN_hex2bn(&y, params->y)
89296341Sdelphij        || !EC_POINT_set_affine_coordinates_GFp(grp, P, x, y, ctx)
90296341Sdelphij        || !BN_hex2bn(&q, params->q))  {
91296341Sdelphij        GOSTerr(GOST_F_FILL_GOST2001_PARAMS, ERR_R_INTERNAL_ERROR);
92296341Sdelphij        goto err;
93296341Sdelphij    }
94296341Sdelphij#ifdef DEBUG_KEYS
95296341Sdelphij    fprintf(stderr, "Set params index %d oid %s\nq=",
96296341Sdelphij            (params - R3410_2001_paramset), OBJ_nid2sn(params->nid));
97296341Sdelphij    BN_print_fp(stderr, q);
98296341Sdelphij    fprintf(stderr, "\n");
99296341Sdelphij#endif
100238384Sjkim
101296341Sdelphij    if(!EC_GROUP_set_generator(grp, P, q, NULL)) {
102296341Sdelphij        GOSTerr(GOST_F_FILL_GOST2001_PARAMS, ERR_R_INTERNAL_ERROR);
103296341Sdelphij        goto err;
104296341Sdelphij    }
105296341Sdelphij    EC_GROUP_set_curve_name(grp, params->nid);
106296341Sdelphij    if(!EC_KEY_set_group(eckey, grp)) {
107296341Sdelphij        GOSTerr(GOST_F_FILL_GOST2001_PARAMS, ERR_R_INTERNAL_ERROR);
108296341Sdelphij        goto err;
109296341Sdelphij    }
110296341Sdelphij    ok = 1;
111296341Sdelphij err:
112296341Sdelphij    if (P) EC_POINT_free(P);
113296341Sdelphij    if (grp) EC_GROUP_free(grp);
114296341Sdelphij    if (ctx) {
115296341Sdelphij        BN_CTX_end(ctx);
116296341Sdelphij        BN_CTX_free(ctx);
117296341Sdelphij    }
118296341Sdelphij    return ok;
119296341Sdelphij}
120296341Sdelphij
121238384Sjkim/*
122296341Sdelphij * Computes gost2001 signature as DSA_SIG structure
123238384Sjkim *
124238384Sjkim *
125296341Sdelphij */
126296341SdelphijDSA_SIG *gost2001_do_sign(const unsigned char *dgst, int dlen, EC_KEY *eckey)
127296341Sdelphij{
128296341Sdelphij    DSA_SIG *newsig = NULL, *ret = NULL;
129296341Sdelphij    BIGNUM *md = hashsum2bn(dgst);
130296341Sdelphij    BIGNUM *order = NULL;
131296341Sdelphij    const EC_GROUP *group;
132296341Sdelphij    const BIGNUM *priv_key;
133296341Sdelphij    BIGNUM *r = NULL, *s = NULL, *X = NULL, *tmp = NULL, *tmp2 = NULL, *k =
134296341Sdelphij        NULL, *e = NULL;
135296341Sdelphij    EC_POINT *C = NULL;
136296341Sdelphij    BN_CTX *ctx = BN_CTX_new();
137296341Sdelphij    if(!ctx || !md) {
138296341Sdelphij        GOSTerr(GOST_F_GOST2001_DO_SIGN, ERR_R_MALLOC_FAILURE);
139296341Sdelphij        goto err;
140296341Sdelphij    }
141296341Sdelphij    BN_CTX_start(ctx);
142296341Sdelphij    OPENSSL_assert(dlen == 32);
143296341Sdelphij    newsig = DSA_SIG_new();
144296341Sdelphij    if (!newsig) {
145296341Sdelphij        GOSTerr(GOST_F_GOST2001_DO_SIGN, GOST_R_NO_MEMORY);
146296341Sdelphij        goto err;
147296341Sdelphij    }
148296341Sdelphij    group = EC_KEY_get0_group(eckey);
149296341Sdelphij    if(!group) {
150296341Sdelphij        GOSTerr(GOST_F_GOST2001_DO_SIGN, ERR_R_INTERNAL_ERROR);
151296341Sdelphij        goto err;
152296341Sdelphij    }
153296341Sdelphij    order = BN_CTX_get(ctx);
154296341Sdelphij    if(!order || !EC_GROUP_get_order(group, order, ctx)) {
155296341Sdelphij        GOSTerr(GOST_F_GOST2001_DO_SIGN, ERR_R_INTERNAL_ERROR);
156296341Sdelphij        goto err;
157296341Sdelphij    }
158296341Sdelphij    priv_key = EC_KEY_get0_private_key(eckey);
159296341Sdelphij    if(!priv_key) {
160296341Sdelphij        GOSTerr(GOST_F_GOST2001_DO_SIGN, ERR_R_INTERNAL_ERROR);
161296341Sdelphij        goto err;
162296341Sdelphij    }
163296341Sdelphij    e = BN_CTX_get(ctx);
164296341Sdelphij    if(!e || !BN_mod(e, md, order, ctx)) {
165296341Sdelphij        GOSTerr(GOST_F_GOST2001_DO_SIGN, ERR_R_INTERNAL_ERROR);
166296341Sdelphij        goto err;
167296341Sdelphij    }
168238384Sjkim#ifdef DEBUG_SIGN
169296341Sdelphij    fprintf(stderr, "digest as bignum=");
170296341Sdelphij    BN_print_fp(stderr, md);
171296341Sdelphij    fprintf(stderr, "\ndigest mod q=");
172296341Sdelphij    BN_print_fp(stderr, e);
173296341Sdelphij    fprintf(stderr, "\n");
174296341Sdelphij#endif
175296341Sdelphij    if (BN_is_zero(e)) {
176296341Sdelphij        BN_one(e);
177296341Sdelphij    }
178296341Sdelphij    k = BN_CTX_get(ctx);
179296341Sdelphij    C = EC_POINT_new(group);
180296341Sdelphij    if(!k || !C) {
181296341Sdelphij        GOSTerr(GOST_F_GOST2001_DO_SIGN, ERR_R_MALLOC_FAILURE);
182296341Sdelphij        goto err;
183296341Sdelphij    }
184296341Sdelphij    do {
185296341Sdelphij        do {
186296341Sdelphij            if (!BN_rand_range(k, order)) {
187296341Sdelphij                GOSTerr(GOST_F_GOST2001_DO_SIGN,
188296341Sdelphij                        GOST_R_RANDOM_NUMBER_GENERATOR_FAILED);
189296341Sdelphij                goto err;
190296341Sdelphij            }
191296341Sdelphij            if (!EC_POINT_mul(group, C, k, NULL, NULL, ctx)) {
192296341Sdelphij                GOSTerr(GOST_F_GOST2001_DO_SIGN, ERR_R_EC_LIB);
193296341Sdelphij                goto err;
194296341Sdelphij            }
195296341Sdelphij            if (!X)
196296341Sdelphij                X = BN_CTX_get(ctx);
197296341Sdelphij            if (!r)
198296341Sdelphij                r = BN_CTX_get(ctx);
199296341Sdelphij            if (!X || !r) {
200296341Sdelphij                GOSTerr(GOST_F_GOST2001_DO_SIGN, ERR_R_MALLOC_FAILURE);
201296341Sdelphij                goto err;
202296341Sdelphij            }
203296341Sdelphij            if (!EC_POINT_get_affine_coordinates_GFp(group, C, X, NULL, ctx)) {
204296341Sdelphij                GOSTerr(GOST_F_GOST2001_DO_SIGN, ERR_R_EC_LIB);
205296341Sdelphij                goto err;
206296341Sdelphij            }
207238384Sjkim
208296341Sdelphij            if(!BN_nnmod(r, X, order, ctx)) {
209296341Sdelphij                GOSTerr(GOST_F_GOST2001_DO_SIGN, ERR_R_INTERNAL_ERROR);
210296341Sdelphij                goto err;
211296341Sdelphij            }
212296341Sdelphij        }
213296341Sdelphij        while (BN_is_zero(r));
214296341Sdelphij        /* s =  (r*priv_key+k*e) mod order */
215296341Sdelphij        if (!tmp)
216296341Sdelphij            tmp = BN_CTX_get(ctx);
217296341Sdelphij        if (!tmp2)
218296341Sdelphij            tmp2 = BN_CTX_get(ctx);
219296341Sdelphij        if (!s)
220296341Sdelphij            s = BN_CTX_get(ctx);
221296341Sdelphij        if (!tmp || !tmp2 || !s) {
222296341Sdelphij            GOSTerr(GOST_F_GOST2001_DO_SIGN, ERR_R_MALLOC_FAILURE);
223296341Sdelphij            goto err;
224296341Sdelphij        }
225296341Sdelphij
226296341Sdelphij        if(!BN_mod_mul(tmp, priv_key, r, order, ctx)
227296341Sdelphij            || !BN_mod_mul(tmp2, k, e, order, ctx)
228296341Sdelphij            || !BN_mod_add(s, tmp, tmp2, order, ctx)) {
229296341Sdelphij            GOSTerr(GOST_F_GOST2001_DO_SIGN, ERR_R_INTERNAL_ERROR);
230296341Sdelphij            goto err;
231296341Sdelphij        }
232296341Sdelphij    }
233296341Sdelphij    while (BN_is_zero(s));
234296341Sdelphij
235296341Sdelphij    newsig->s = BN_dup(s);
236296341Sdelphij    newsig->r = BN_dup(r);
237296341Sdelphij    if(!newsig->s || !newsig->r) {
238296341Sdelphij        GOSTerr(GOST_F_GOST2001_DO_SIGN, ERR_R_MALLOC_FAILURE);
239296341Sdelphij        goto err;
240296341Sdelphij    }
241296341Sdelphij
242296341Sdelphij    ret = newsig;
243296341Sdelphij err:
244296341Sdelphij    if(ctx) {
245296341Sdelphij        BN_CTX_end(ctx);
246296341Sdelphij        BN_CTX_free(ctx);
247296341Sdelphij    }
248296341Sdelphij    if (C) EC_POINT_free(C);
249296341Sdelphij    if (md) BN_free(md);
250296341Sdelphij    if (!ret && newsig) {
251296341Sdelphij        DSA_SIG_free(newsig);
252296341Sdelphij    }
253296341Sdelphij    return ret;
254296341Sdelphij}
255296341Sdelphij
256238384Sjkim/*
257238384Sjkim * Verifies gost 2001 signature
258238384Sjkim *
259296341Sdelphij */
260296341Sdelphijint gost2001_do_verify(const unsigned char *dgst, int dgst_len,
261296341Sdelphij                       DSA_SIG *sig, EC_KEY *ec)
262296341Sdelphij{
263296341Sdelphij    BN_CTX *ctx = BN_CTX_new();
264296341Sdelphij    const EC_GROUP *group = EC_KEY_get0_group(ec);
265296341Sdelphij    BIGNUM *order;
266296341Sdelphij    BIGNUM *md = NULL, *e = NULL, *R = NULL, *v = NULL, *z1 = NULL, *z2 =
267296341Sdelphij        NULL;
268296341Sdelphij    BIGNUM *X = NULL, *tmp = NULL;
269296341Sdelphij    EC_POINT *C = NULL;
270296341Sdelphij    const EC_POINT *pub_key = NULL;
271296341Sdelphij    int ok = 0;
272238384Sjkim
273296341Sdelphij    if(!ctx || !group) {
274296341Sdelphij        GOSTerr(GOST_F_GOST2001_DO_VERIFY, ERR_R_INTERNAL_ERROR);
275296341Sdelphij        goto err;
276296341Sdelphij    }
277238384Sjkim
278296341Sdelphij    BN_CTX_start(ctx);
279296341Sdelphij    order = BN_CTX_get(ctx);
280296341Sdelphij    e = BN_CTX_get(ctx);
281296341Sdelphij    z1 = BN_CTX_get(ctx);
282296341Sdelphij    z2 = BN_CTX_get(ctx);
283296341Sdelphij    tmp = BN_CTX_get(ctx);
284296341Sdelphij    X = BN_CTX_get(ctx);
285296341Sdelphij    R = BN_CTX_get(ctx);
286296341Sdelphij    v = BN_CTX_get(ctx);
287296341Sdelphij    if(!order || !e || !z1 || !z2 || !tmp || !X || !R || !v) {
288296341Sdelphij        GOSTerr(GOST_F_GOST2001_DO_VERIFY, ERR_R_MALLOC_FAILURE);
289296341Sdelphij        goto err;
290296341Sdelphij    }
291238384Sjkim
292296341Sdelphij    pub_key = EC_KEY_get0_public_key(ec);
293296341Sdelphij    if(!pub_key || !EC_GROUP_get_order(group, order, ctx)) {
294296341Sdelphij        GOSTerr(GOST_F_GOST2001_DO_VERIFY, ERR_R_INTERNAL_ERROR);
295296341Sdelphij        goto err;
296296341Sdelphij    }
297296341Sdelphij
298296341Sdelphij    if (BN_is_zero(sig->s) || BN_is_zero(sig->r) ||
299296341Sdelphij        (BN_cmp(sig->s, order) >= 1) || (BN_cmp(sig->r, order) >= 1)) {
300296341Sdelphij        GOSTerr(GOST_F_GOST2001_DO_VERIFY,
301296341Sdelphij                GOST_R_SIGNATURE_PARTS_GREATER_THAN_Q);
302296341Sdelphij        goto err;
303296341Sdelphij
304296341Sdelphij    }
305296341Sdelphij    md = hashsum2bn(dgst);
306296341Sdelphij
307296341Sdelphij    if(!md || !BN_mod(e, md, order, ctx)) {
308296341Sdelphij        GOSTerr(GOST_F_GOST2001_DO_VERIFY, ERR_R_INTERNAL_ERROR);
309296341Sdelphij        goto err;
310296341Sdelphij    }
311238384Sjkim#ifdef DEBUG_SIGN
312296341Sdelphij    fprintf(stderr, "digest as bignum: ");
313296341Sdelphij    BN_print_fp(stderr, md);
314296341Sdelphij    fprintf(stderr, "\ndigest mod q: ");
315296341Sdelphij    BN_print_fp(stderr, e);
316296341Sdelphij#endif
317296341Sdelphij    if (BN_is_zero(e) && !BN_one(e)) {
318296341Sdelphij        GOSTerr(GOST_F_GOST2001_DO_VERIFY, ERR_R_INTERNAL_ERROR);
319296341Sdelphij        goto err;
320296341Sdelphij    }
321296341Sdelphij    v = BN_mod_inverse(v, e, order, ctx);
322296341Sdelphij    if(!v
323296341Sdelphij        || !BN_mod_mul(z1, sig->s, v, order, ctx)
324296341Sdelphij        || !BN_sub(tmp, order, sig->r)
325296341Sdelphij        || !BN_mod_mul(z2, tmp, v, order, ctx)) {
326296341Sdelphij        GOSTerr(GOST_F_GOST2001_DO_VERIFY, ERR_R_INTERNAL_ERROR);
327296341Sdelphij        goto err;
328296341Sdelphij    }
329238384Sjkim#ifdef DEBUG_SIGN
330296341Sdelphij    fprintf(stderr, "\nInverted digest value: ");
331296341Sdelphij    BN_print_fp(stderr, v);
332296341Sdelphij    fprintf(stderr, "\nz1: ");
333296341Sdelphij    BN_print_fp(stderr, z1);
334296341Sdelphij    fprintf(stderr, "\nz2: ");
335296341Sdelphij    BN_print_fp(stderr, z2);
336296341Sdelphij#endif
337296341Sdelphij    C = EC_POINT_new(group);
338296341Sdelphij    if (!C) {
339296341Sdelphij        GOSTerr(GOST_F_GOST2001_DO_VERIFY, ERR_R_MALLOC_FAILURE);
340296341Sdelphij        goto err;
341296341Sdelphij    }
342296341Sdelphij    if (!EC_POINT_mul(group, C, z1, pub_key, z2, ctx)) {
343296341Sdelphij        GOSTerr(GOST_F_GOST2001_DO_VERIFY, ERR_R_EC_LIB);
344296341Sdelphij        goto err;
345296341Sdelphij    }
346296341Sdelphij    if (!EC_POINT_get_affine_coordinates_GFp(group, C, X, NULL, ctx)) {
347296341Sdelphij        GOSTerr(GOST_F_GOST2001_DO_VERIFY, ERR_R_EC_LIB);
348296341Sdelphij        goto err;
349296341Sdelphij    }
350296341Sdelphij    if(!BN_mod(R, X, order, ctx)) {
351296341Sdelphij        GOSTerr(GOST_F_GOST2001_DO_VERIFY, ERR_R_INTERNAL_ERROR);
352296341Sdelphij        goto err;
353296341Sdelphij    }
354238384Sjkim#ifdef DEBUG_SIGN
355296341Sdelphij    fprintf(stderr, "\nX=");
356296341Sdelphij    BN_print_fp(stderr, X);
357296341Sdelphij    fprintf(stderr, "\nX mod q=");
358296341Sdelphij    BN_print_fp(stderr, R);
359296341Sdelphij    fprintf(stderr, "\n");
360296341Sdelphij#endif
361296341Sdelphij    if (BN_cmp(R, sig->r) != 0) {
362296341Sdelphij        GOSTerr(GOST_F_GOST2001_DO_VERIFY, GOST_R_SIGNATURE_MISMATCH);
363296341Sdelphij    } else {
364296341Sdelphij        ok = 1;
365296341Sdelphij    }
366296341Sdelphij err:
367296341Sdelphij    if (C) EC_POINT_free(C);
368296341Sdelphij    if (ctx) {
369296341Sdelphij        BN_CTX_end(ctx);
370296341Sdelphij        BN_CTX_free(ctx);
371296341Sdelphij    }
372296341Sdelphij    if (md) BN_free(md);
373296341Sdelphij    return ok;
374296341Sdelphij}
375296341Sdelphij
376238384Sjkim/*
377238384Sjkim * Computes GOST R 34.10-2001 public key
378238384Sjkim *
379238384Sjkim *
380296341Sdelphij */
381296341Sdelphijint gost2001_compute_public(EC_KEY *ec)
382296341Sdelphij{
383296341Sdelphij    const EC_GROUP *group = EC_KEY_get0_group(ec);
384296341Sdelphij    EC_POINT *pub_key = NULL;
385296341Sdelphij    const BIGNUM *priv_key = NULL;
386296341Sdelphij    BN_CTX *ctx = NULL;
387296341Sdelphij    int ok = 0;
388238384Sjkim
389296341Sdelphij    if (!group) {
390296341Sdelphij        GOSTerr(GOST_F_GOST2001_COMPUTE_PUBLIC,
391296341Sdelphij                GOST_R_KEY_IS_NOT_INITIALIZED);
392296341Sdelphij        return 0;
393296341Sdelphij    }
394296341Sdelphij    ctx = BN_CTX_new();
395296341Sdelphij    if(!ctx) {
396296341Sdelphij        GOSTerr(GOST_F_GOST2001_COMPUTE_PUBLIC, ERR_R_MALLOC_FAILURE);
397296341Sdelphij        goto err;
398296341Sdelphij    }
399296341Sdelphij    BN_CTX_start(ctx);
400296341Sdelphij    if (!(priv_key = EC_KEY_get0_private_key(ec))) {
401296341Sdelphij        GOSTerr(GOST_F_GOST2001_COMPUTE_PUBLIC, ERR_R_EC_LIB);
402296341Sdelphij        goto err;
403296341Sdelphij    }
404238384Sjkim
405296341Sdelphij    pub_key = EC_POINT_new(group);
406296341Sdelphij    if(!pub_key) {
407296341Sdelphij        GOSTerr(GOST_F_GOST2001_COMPUTE_PUBLIC, ERR_R_MALLOC_FAILURE);
408296341Sdelphij        goto err;
409296341Sdelphij    }
410296341Sdelphij    if (!EC_POINT_mul(group, pub_key, priv_key, NULL, NULL, ctx)) {
411296341Sdelphij        GOSTerr(GOST_F_GOST2001_COMPUTE_PUBLIC, ERR_R_EC_LIB);
412296341Sdelphij        goto err;
413296341Sdelphij    }
414296341Sdelphij    if (!EC_KEY_set_public_key(ec, pub_key)) {
415296341Sdelphij        GOSTerr(GOST_F_GOST2001_COMPUTE_PUBLIC, ERR_R_EC_LIB);
416296341Sdelphij        goto err;
417296341Sdelphij    }
418296341Sdelphij    ok = 256;
419296341Sdelphij err:
420296341Sdelphij    if (pub_key) EC_POINT_free(pub_key);
421296341Sdelphij    if (ctx) {
422296341Sdelphij        BN_CTX_end(ctx);
423296341Sdelphij        BN_CTX_free(ctx);
424296341Sdelphij    }
425296341Sdelphij    return ok;
426296341Sdelphij}
427296341Sdelphij
428238384Sjkim/*
429296341Sdelphij *
430238384Sjkim * Generates GOST R 34.10-2001 keypair
431238384Sjkim *
432238384Sjkim *
433296341Sdelphij */
434238384Sjkimint gost2001_keygen(EC_KEY *ec)
435296341Sdelphij{
436296341Sdelphij    BIGNUM *order = BN_new(), *d = BN_new();
437296341Sdelphij    const EC_GROUP *group = EC_KEY_get0_group(ec);
438238384Sjkim
439296341Sdelphij    if(!group || !EC_GROUP_get_order(group, order, NULL)) {
440296341Sdelphij        GOSTerr(GOST_F_GOST2001_KEYGEN, ERR_R_INTERNAL_ERROR);
441296341Sdelphij        BN_free(d);
442296341Sdelphij        BN_free(order);
443296341Sdelphij        return 0;
444296341Sdelphij    }
445296341Sdelphij
446296341Sdelphij    do {
447296341Sdelphij        if (!BN_rand_range(d, order)) {
448296341Sdelphij            GOSTerr(GOST_F_GOST2001_KEYGEN,
449296341Sdelphij                    GOST_R_RANDOM_NUMBER_GENERATOR_FAILED);
450296341Sdelphij            BN_free(d);
451296341Sdelphij            BN_free(order);
452296341Sdelphij            return 0;
453296341Sdelphij        }
454296341Sdelphij    }
455296341Sdelphij    while (BN_is_zero(d));
456296341Sdelphij
457296341Sdelphij    if(!EC_KEY_set_private_key(ec, d)) {
458296341Sdelphij        GOSTerr(GOST_F_GOST2001_KEYGEN, ERR_R_INTERNAL_ERROR);
459296341Sdelphij        BN_free(d);
460296341Sdelphij        BN_free(order);
461296341Sdelphij        return 0;
462296341Sdelphij    }
463296341Sdelphij    BN_free(d);
464296341Sdelphij    BN_free(order);
465296341Sdelphij    return gost2001_compute_public(ec);
466296341Sdelphij}
467