xref: /dragonfly/crypto/libressl/crypto/gost/gostr341001_pmeth.c (revision 961e30ea7dc61d1112b778ea4981eac68129fb86)
1 /* $OpenBSD: gostr341001_pmeth.c,v 1.16 2022/03/30 07:17:48 tb Exp $ */
2 /*
3  * Copyright (c) 2014 Dmitry Eremin-Solenikov <dbaryshkov@gmail.com>
4  * Copyright (c) 2005-2006 Cryptocom LTD
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  *
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  *
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in
15  *    the documentation and/or other materials provided with the
16  *    distribution.
17  *
18  * 3. All advertising materials mentioning features or use of this
19  *    software must display the following acknowledgment:
20  *    "This product includes software developed by the OpenSSL Project
21  *    for use in the OpenSSL Toolkit. (http://www.openssl.org/)"
22  *
23  * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
24  *    endorse or promote products derived from this software without
25  *    prior written permission. For written permission, please contact
26  *    openssl-core@openssl.org.
27  *
28  * 5. Products derived from this software may not be called "OpenSSL"
29  *    nor may "OpenSSL" appear in their names without prior written
30  *    permission of the OpenSSL Project.
31  *
32  * 6. Redistributions of any form whatsoever must retain the following
33  *    acknowledgment:
34  *    "This product includes software developed by the OpenSSL Project
35  *    for use in the OpenSSL Toolkit (http://www.openssl.org/)"
36  *
37  * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
38  * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
39  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
40  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE OpenSSL PROJECT OR
41  * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
42  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
43  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
44  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
45  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
46  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
47  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
48  * OF THE POSSIBILITY OF SUCH DAMAGE.
49  * ====================================================================
50  */
51 
52 #include <string.h>
53 
54 #include <openssl/opensslconf.h>
55 
56 #ifndef OPENSSL_NO_GOST
57 #include <openssl/bn.h>
58 #include <openssl/evp.h>
59 #include <openssl/err.h>
60 #include <openssl/gost.h>
61 #include <openssl/ec.h>
62 #include <openssl/ecdsa.h>
63 #include <openssl/x509.h>
64 
65 #include "ecs_locl.h"
66 #include "evp_locl.h"
67 #include "gost_locl.h"
68 #include "gost_asn1.h"
69 
70 static ECDSA_SIG *
unpack_signature_cp(const unsigned char * sig,size_t siglen)71 unpack_signature_cp(const unsigned char *sig, size_t siglen)
72 {
73           ECDSA_SIG *s;
74 
75           s = ECDSA_SIG_new();
76           if (s == NULL) {
77                     GOSTerror(ERR_R_MALLOC_FAILURE);
78                     return NULL;
79           }
80           BN_bin2bn(sig, siglen / 2, s->s);
81           BN_bin2bn(sig + siglen / 2, siglen / 2, s->r);
82           return s;
83 }
84 
85 static int
pack_signature_cp(ECDSA_SIG * s,int order,unsigned char * sig,size_t * siglen)86 pack_signature_cp(ECDSA_SIG *s, int order, unsigned char *sig, size_t *siglen)
87 {
88           int r_len = BN_num_bytes(s->r);
89           int s_len = BN_num_bytes(s->s);
90 
91           if (r_len > order || s_len > order)
92                     return 0;
93 
94           *siglen = 2 * order;
95 
96           memset(sig, 0, *siglen);
97           BN_bn2bin(s->s, sig + order - s_len);
98           BN_bn2bin(s->r, sig + 2 * order - r_len);
99           ECDSA_SIG_free(s);
100           return 1;
101 }
102 
103 static ECDSA_SIG *
unpack_signature_le(const unsigned char * sig,size_t siglen)104 unpack_signature_le(const unsigned char *sig, size_t siglen)
105 {
106           ECDSA_SIG *s;
107 
108           s = ECDSA_SIG_new();
109           if (s == NULL) {
110                     GOSTerror(ERR_R_MALLOC_FAILURE);
111                     return NULL;
112           }
113           GOST_le2bn(sig, siglen / 2, s->r);
114           GOST_le2bn(sig + siglen / 2, siglen / 2, s->s);
115           return s;
116 }
117 
118 static int
pack_signature_le(ECDSA_SIG * s,int order,unsigned char * sig,size_t * siglen)119 pack_signature_le(ECDSA_SIG *s, int order, unsigned char *sig, size_t *siglen)
120 {
121           *siglen = 2 * order;
122           memset(sig, 0, *siglen);
123           GOST_bn2le(s->r, sig, order);
124           GOST_bn2le(s->s, sig + order, order);
125           ECDSA_SIG_free(s);
126           return 1;
127 }
128 
129 struct gost_pmeth_data {
130           int sign_param_nid; /* Should be set whenever parameters are filled */
131           int digest_nid;
132           EVP_MD *md;
133           unsigned char *shared_ukm;
134           int peer_key_used;
135           int sig_format;
136 };
137 
138 static int
pkey_gost01_init(EVP_PKEY_CTX * ctx)139 pkey_gost01_init(EVP_PKEY_CTX *ctx)
140 {
141           struct gost_pmeth_data *data;
142           EVP_PKEY *pkey = EVP_PKEY_CTX_get0_pkey(ctx);
143 
144           data = calloc(1, sizeof(struct gost_pmeth_data));
145           if (data == NULL)
146                     return 0;
147 
148           if (pkey != NULL && pkey->pkey.gost != NULL) {
149                     data->sign_param_nid =
150                         EC_GROUP_get_curve_name(GOST_KEY_get0_group(pkey->pkey.gost));
151                     data->digest_nid = GOST_KEY_get_digest(pkey->pkey.gost);
152           }
153           EVP_PKEY_CTX_set_data(ctx, data);
154           return 1;
155 }
156 
157 /* Copies contents of gost_pmeth_data structure */
158 static int
pkey_gost01_copy(EVP_PKEY_CTX * dst,EVP_PKEY_CTX * src)159 pkey_gost01_copy(EVP_PKEY_CTX *dst, EVP_PKEY_CTX *src)
160 {
161           struct gost_pmeth_data *dst_data, *src_data;
162 
163           if (pkey_gost01_init(dst) == 0)
164                     return 0;
165 
166           src_data = EVP_PKEY_CTX_get_data(src);
167           dst_data = EVP_PKEY_CTX_get_data(dst);
168           *dst_data = *src_data;
169           if (src_data->shared_ukm != NULL)
170                     dst_data->shared_ukm = NULL;
171           return 1;
172 }
173 
174 /* Frees up gost_pmeth_data structure */
175 static void
pkey_gost01_cleanup(EVP_PKEY_CTX * ctx)176 pkey_gost01_cleanup(EVP_PKEY_CTX *ctx)
177 {
178           struct gost_pmeth_data *data;
179 
180           if ((data = EVP_PKEY_CTX_get_data(ctx)) == NULL)
181                     return;
182 
183           free(data->shared_ukm);
184           free(data);
185 }
186 
187 static int
pkey_gost01_paramgen(EVP_PKEY_CTX * ctx,EVP_PKEY * pkey)188 pkey_gost01_paramgen(EVP_PKEY_CTX *ctx, EVP_PKEY *pkey)
189 {
190           struct gost_pmeth_data *data = EVP_PKEY_CTX_get_data(ctx);
191           EC_GROUP *group = NULL;
192           GOST_KEY *gost = NULL;
193           int ret = 0;
194 
195           if (data->sign_param_nid == NID_undef ||
196               data->digest_nid == NID_undef) {
197                     GOSTerror(GOST_R_NO_PARAMETERS_SET);
198                     return 0;
199           }
200 
201           group = EC_GROUP_new_by_curve_name(data->sign_param_nid);
202           if (group == NULL)
203                     goto done;
204 
205           EC_GROUP_set_asn1_flag(group, OPENSSL_EC_NAMED_CURVE);
206 
207           gost = GOST_KEY_new();
208           if (gost == NULL)
209                     goto done;
210 
211           if (GOST_KEY_set_digest(gost, data->digest_nid) == 0)
212                     goto done;
213 
214           if (GOST_KEY_set_group(gost, group) != 0)
215                     ret = EVP_PKEY_assign_GOST(pkey, gost);
216 
217 done:
218           if (ret == 0)
219                     GOST_KEY_free(gost);
220           EC_GROUP_free(group);
221           return ret;
222 }
223 
224 static int
pkey_gost01_keygen(EVP_PKEY_CTX * ctx,EVP_PKEY * pkey)225 pkey_gost01_keygen(EVP_PKEY_CTX *ctx, EVP_PKEY *pkey)
226 {
227           if (pkey_gost01_paramgen(ctx, pkey) == 0)
228                     return 0;
229           return gost2001_keygen(pkey->pkey.gost) != 0;
230 }
231 
232 static int
pkey_gost01_sign(EVP_PKEY_CTX * ctx,unsigned char * sig,size_t * siglen,const unsigned char * tbs,size_t tbs_len)233 pkey_gost01_sign(EVP_PKEY_CTX *ctx, unsigned char *sig, size_t *siglen,
234     const unsigned char *tbs, size_t tbs_len)
235 {
236           ECDSA_SIG *unpacked_sig = NULL;
237           EVP_PKEY *pkey = EVP_PKEY_CTX_get0_pkey(ctx);
238           struct gost_pmeth_data *pctx = EVP_PKEY_CTX_get_data(ctx);
239           BIGNUM *md;
240           size_t size;
241           int ret;
242 
243           if (pkey == NULL || pkey->pkey.gost == NULL)
244                     return 0;
245           size = GOST_KEY_get_size(pkey->pkey.gost);
246 
247           if (siglen == NULL)
248                     return 0;
249           if (sig == NULL) {
250                     *siglen = 2 * size;
251                     return 1;
252           } else if (*siglen < 2 * size) {
253                     GOSTerror(EC_R_BUFFER_TOO_SMALL);
254                     return 0;
255           }
256           if (tbs_len != 32 && tbs_len != 64) {
257                     GOSTerror(EVP_R_BAD_BLOCK_LENGTH);
258                     return 0;
259           }
260           md = GOST_le2bn(tbs, tbs_len, NULL);
261           if (md == NULL)
262                     return 0;
263           unpacked_sig = gost2001_do_sign(md, pkey->pkey.gost);
264           BN_free(md);
265           if (unpacked_sig == NULL) {
266                     return 0;
267           }
268           switch (pctx->sig_format) {
269           case GOST_SIG_FORMAT_SR_BE:
270                     ret = pack_signature_cp(unpacked_sig, size, sig, siglen);
271                     break;
272           case GOST_SIG_FORMAT_RS_LE:
273                     ret = pack_signature_le(unpacked_sig, size, sig, siglen);
274                     break;
275           default:
276                     ret = -1;
277                     break;
278           }
279           if (ret <= 0)
280                     ECDSA_SIG_free(unpacked_sig);
281           return ret;
282 }
283 
284 static int
pkey_gost01_verify(EVP_PKEY_CTX * ctx,const unsigned char * sig,size_t siglen,const unsigned char * tbs,size_t tbs_len)285 pkey_gost01_verify(EVP_PKEY_CTX *ctx, const unsigned char *sig, size_t siglen,
286     const unsigned char *tbs, size_t tbs_len)
287 {
288           int ok = 0;
289           EVP_PKEY *pub_key = EVP_PKEY_CTX_get0_pkey(ctx);
290           struct gost_pmeth_data *pctx = EVP_PKEY_CTX_get_data(ctx);
291           ECDSA_SIG *s = NULL;
292           BIGNUM *md;
293 
294           if (pub_key == NULL)
295                     return 0;
296           switch (pctx->sig_format) {
297           case GOST_SIG_FORMAT_SR_BE:
298                     s = unpack_signature_cp(sig, siglen);
299                     break;
300           case GOST_SIG_FORMAT_RS_LE:
301                     s = unpack_signature_le(sig, siglen);
302                     break;
303           }
304           if (s == NULL)
305                     return 0;
306           md = GOST_le2bn(tbs, tbs_len, NULL);
307           if (md == NULL)
308                     goto err;
309           ok = gost2001_do_verify(md, s, pub_key->pkey.gost);
310 
311 err:
312           BN_free(md);
313           ECDSA_SIG_free(s);
314           return ok;
315 }
316 
317 static int
gost01_VKO_key(EVP_PKEY * pub_key,EVP_PKEY * priv_key,const unsigned char * ukm,unsigned char * key)318 gost01_VKO_key(EVP_PKEY *pub_key, EVP_PKEY *priv_key, const unsigned char *ukm,
319     unsigned char *key)
320 {
321           unsigned char hashbuf[128];
322           int digest_nid;
323           int ret = 0;
324           BN_CTX *ctx = BN_CTX_new();
325           BIGNUM *UKM, *X, *Y;
326 
327           if (ctx == NULL)
328                     return 0;
329 
330           BN_CTX_start(ctx);
331           if ((UKM = BN_CTX_get(ctx)) == NULL)
332                     goto err;
333           if ((X = BN_CTX_get(ctx)) == NULL)
334                     goto err;
335           if ((Y = BN_CTX_get(ctx)) == NULL)
336                     goto err;
337 
338           GOST_le2bn(ukm, 8, UKM);
339 
340           digest_nid = GOST_KEY_get_digest(priv_key->pkey.gost);
341           if (VKO_compute_key(X, Y, pub_key->pkey.gost, priv_key->pkey.gost,
342               UKM) == 0)
343                     goto err;
344 
345           switch (digest_nid) {
346           case NID_id_GostR3411_94_CryptoProParamSet:
347                     GOST_bn2le(X, hashbuf, 32);
348                     GOST_bn2le(Y, hashbuf + 32, 32);
349                     GOSTR341194(hashbuf, 64, key, digest_nid);
350                     ret = 1;
351                     break;
352           case NID_id_tc26_gost3411_2012_256:
353                     GOST_bn2le(X, hashbuf, 32);
354                     GOST_bn2le(Y, hashbuf + 32, 32);
355                     STREEBOG256(hashbuf, 64, key);
356                     ret = 1;
357                     break;
358           case NID_id_tc26_gost3411_2012_512:
359                     GOST_bn2le(X, hashbuf, 64);
360                     GOST_bn2le(Y, hashbuf + 64, 64);
361                     STREEBOG256(hashbuf, 128, key);
362                     ret = 1;
363                     break;
364           default:
365                     ret = -2;
366                     break;
367           }
368 err:
369           BN_CTX_end(ctx);
370           BN_CTX_free(ctx);
371           return ret;
372 }
373 
374 int
pkey_gost01_decrypt(EVP_PKEY_CTX * pctx,unsigned char * key,size_t * key_len,const unsigned char * in,size_t in_len)375 pkey_gost01_decrypt(EVP_PKEY_CTX *pctx, unsigned char *key, size_t *key_len,
376     const unsigned char *in, size_t in_len)
377 {
378           const unsigned char *p = in;
379           EVP_PKEY *priv = EVP_PKEY_CTX_get0_pkey(pctx);
380           GOST_KEY_TRANSPORT *gkt = NULL;
381           int ret = 0;
382           unsigned char wrappedKey[44];
383           unsigned char sharedKey[32];
384           EVP_PKEY *eph_key = NULL, *peerkey = NULL;
385           int nid;
386 
387           if (key == NULL) {
388                     *key_len = 32;
389                     return 1;
390           }
391           gkt = d2i_GOST_KEY_TRANSPORT(NULL, (const unsigned char **)&p, in_len);
392           if (gkt == NULL) {
393                     GOSTerror(GOST_R_ERROR_PARSING_KEY_TRANSPORT_INFO);
394                     return -1;
395           }
396 
397           /* If key transport structure contains public key, use it */
398           eph_key = X509_PUBKEY_get(gkt->key_agreement_info->ephem_key);
399           if (eph_key != NULL) {
400                     if (EVP_PKEY_derive_set_peer(pctx, eph_key) <= 0) {
401                               GOSTerror(GOST_R_INCOMPATIBLE_PEER_KEY);
402                               goto err;
403                     }
404           } else {
405                     /* Set control "public key from client certificate used" */
406                     if (EVP_PKEY_CTX_ctrl(pctx, -1, -1, EVP_PKEY_CTRL_PEER_KEY, 3,
407                         NULL) <= 0) {
408                               GOSTerror(GOST_R_CTRL_CALL_FAILED);
409                               goto err;
410                     }
411           }
412           peerkey = EVP_PKEY_CTX_get0_peerkey(pctx);
413           if (peerkey == NULL) {
414                     GOSTerror(GOST_R_NO_PEER_KEY);
415                     goto err;
416           }
417 
418           nid = OBJ_obj2nid(gkt->key_agreement_info->cipher);
419 
420           if (gkt->key_agreement_info->eph_iv->length != 8) {
421                     GOSTerror(GOST_R_INVALID_IV_LENGTH);
422                     goto err;
423           }
424           memcpy(wrappedKey, gkt->key_agreement_info->eph_iv->data, 8);
425           if (gkt->key_info->encrypted_key->length != 32) {
426                     GOSTerror(EVP_R_BAD_KEY_LENGTH);
427                     goto err;
428           }
429           memcpy(wrappedKey + 8, gkt->key_info->encrypted_key->data, 32);
430           if (gkt->key_info->imit->length != 4) {
431                     GOSTerror(ERR_R_INTERNAL_ERROR);
432                     goto err;
433           }
434           memcpy(wrappedKey + 40, gkt->key_info->imit->data, 4);
435           if (gost01_VKO_key(peerkey, priv, wrappedKey, sharedKey) <= 0)
436                     goto err;
437           if (gost_key_unwrap_crypto_pro(nid, sharedKey, wrappedKey, key) == 0) {
438                     GOSTerror(GOST_R_ERROR_COMPUTING_SHARED_KEY);
439                     goto err;
440           }
441 
442           ret = 1;
443 err:
444           EVP_PKEY_free(eph_key);
445           GOST_KEY_TRANSPORT_free(gkt);
446           return ret;
447 }
448 
449 int
pkey_gost01_derive(EVP_PKEY_CTX * ctx,unsigned char * key,size_t * keylen)450 pkey_gost01_derive(EVP_PKEY_CTX *ctx, unsigned char *key, size_t *keylen)
451 {
452           /*
453            * Public key of peer in the ctx field peerkey
454            * Our private key in the ctx pkey
455            * ukm is in the algorithm specific context data
456            */
457           EVP_PKEY *my_key = EVP_PKEY_CTX_get0_pkey(ctx);
458           EVP_PKEY *peer_key = EVP_PKEY_CTX_get0_peerkey(ctx);
459           struct gost_pmeth_data *data = EVP_PKEY_CTX_get_data(ctx);
460 
461           if (data->shared_ukm == NULL) {
462                     GOSTerror(GOST_R_UKM_NOT_SET);
463                     return 0;
464           }
465 
466           if (key == NULL) {
467                     *keylen = 32;
468                     return 32;
469           }
470 
471           if (gost01_VKO_key(peer_key, my_key, data->shared_ukm, key) <= 0)
472                     return 0;
473 
474           *keylen = 32;
475           return 1;
476 }
477 
478 int
pkey_gost01_encrypt(EVP_PKEY_CTX * pctx,unsigned char * out,size_t * out_len,const unsigned char * key,size_t key_len)479 pkey_gost01_encrypt(EVP_PKEY_CTX *pctx, unsigned char *out, size_t *out_len,
480     const unsigned char *key, size_t key_len)
481 {
482           GOST_KEY_TRANSPORT *gkt = NULL;
483           EVP_PKEY *pubk = EVP_PKEY_CTX_get0_pkey(pctx);
484           struct gost_pmeth_data *data = EVP_PKEY_CTX_get_data(pctx);
485           unsigned char ukm[8], shared_key[32], crypted_key[44];
486           int ret = 0;
487           int key_is_ephemeral;
488           EVP_PKEY *sec_key = EVP_PKEY_CTX_get0_peerkey(pctx);
489           int nid = NID_id_Gost28147_89_CryptoPro_A_ParamSet;
490 
491           if (data->shared_ukm != NULL) {
492                     memcpy(ukm, data->shared_ukm, 8);
493           } else /* if (out != NULL) */ {
494                     arc4random_buf(ukm, 8);
495           }
496           /* Check for private key in the peer_key of context */
497           if (sec_key) {
498                     key_is_ephemeral = 0;
499                     if (GOST_KEY_get0_private_key(sec_key->pkey.gost) == 0) {
500                               GOSTerror(GOST_R_NO_PRIVATE_PART_OF_NON_EPHEMERAL_KEYPAIR);
501                               goto err;
502                     }
503           } else {
504                     key_is_ephemeral = 1;
505                     if (out != NULL) {
506                               GOST_KEY *tmp_key;
507 
508                               sec_key = EVP_PKEY_new();
509                               if (sec_key == NULL)
510                                         goto err;
511                               tmp_key = GOST_KEY_new();
512                               if (tmp_key == NULL)
513                                         goto err;
514                               if (EVP_PKEY_assign(sec_key, EVP_PKEY_base_id(pubk),
515                                   tmp_key) == 0) {
516                                         GOST_KEY_free(tmp_key);
517                                         goto err;
518                               }
519                               if (EVP_PKEY_copy_parameters(sec_key, pubk) == 0)
520                                         goto err;
521                               if (gost2001_keygen(sec_key->pkey.gost) == 0) {
522                                         goto err;
523                               }
524                     }
525           }
526 
527           if (out != NULL) {
528                     if (gost01_VKO_key(pubk, sec_key, ukm, shared_key) <= 0)
529                               goto err;
530                     gost_key_wrap_crypto_pro(nid, shared_key, ukm, key,
531                         crypted_key);
532           }
533           gkt = GOST_KEY_TRANSPORT_new();
534           if (gkt == NULL)
535                     goto err;
536           if (ASN1_OCTET_STRING_set(gkt->key_agreement_info->eph_iv, ukm, 8) == 0)
537                     goto err;
538           if (ASN1_OCTET_STRING_set(gkt->key_info->imit, crypted_key + 40,
539               4) == 0)
540                     goto err;
541           if (ASN1_OCTET_STRING_set(gkt->key_info->encrypted_key, crypted_key + 8,
542               32) == 0)
543                     goto err;
544           if (key_is_ephemeral) {
545                     if (X509_PUBKEY_set(&gkt->key_agreement_info->ephem_key,
546                         out != NULL ? sec_key : pubk) == 0) {
547                               GOSTerror(GOST_R_CANNOT_PACK_EPHEMERAL_KEY);
548                               goto err;
549                     }
550           }
551           ASN1_OBJECT_free(gkt->key_agreement_info->cipher);
552           gkt->key_agreement_info->cipher = OBJ_nid2obj(nid);
553           if (key_is_ephemeral)
554                     EVP_PKEY_free(sec_key);
555           else {
556                     /* Set control "public key from client certificate used" */
557                     if (EVP_PKEY_CTX_ctrl(pctx, -1, -1, EVP_PKEY_CTRL_PEER_KEY, 3,
558                         NULL) <= 0) {
559                               GOSTerror(GOST_R_CTRL_CALL_FAILED);
560                               goto err;
561                     }
562           }
563           if ((*out_len = i2d_GOST_KEY_TRANSPORT(gkt, out ? &out : NULL)) > 0)
564                     ret = 1;
565           GOST_KEY_TRANSPORT_free(gkt);
566           return ret;
567 
568 err:
569           if (key_is_ephemeral)
570                     EVP_PKEY_free(sec_key);
571           GOST_KEY_TRANSPORT_free(gkt);
572           return -1;
573 }
574 
575 
576 static int
pkey_gost01_ctrl(EVP_PKEY_CTX * ctx,int type,int p1,void * p2)577 pkey_gost01_ctrl(EVP_PKEY_CTX *ctx, int type, int p1, void *p2)
578 {
579           struct gost_pmeth_data *pctx = EVP_PKEY_CTX_get_data(ctx);
580 
581           switch (type) {
582           case EVP_PKEY_CTRL_MD:
583                     if (EVP_MD_type(p2) !=
584                         GostR3410_get_md_digest(pctx->digest_nid)) {
585                               GOSTerror(GOST_R_INVALID_DIGEST_TYPE);
586                               return 0;
587                     }
588                     pctx->md = p2;
589                     return 1;
590           case EVP_PKEY_CTRL_PKCS7_ENCRYPT:
591           case EVP_PKEY_CTRL_PKCS7_DECRYPT:
592           case EVP_PKEY_CTRL_PKCS7_SIGN:
593           case EVP_PKEY_CTRL_DIGESTINIT:
594                     return 1;
595 
596           case EVP_PKEY_CTRL_GOST_PARAMSET:
597                     pctx->sign_param_nid = (int)p1;
598                     return 1;
599 
600           case EVP_PKEY_CTRL_SET_IV:
601               {
602                     char *ukm = malloc(p1);
603 
604                     if (ukm == NULL) {
605                               GOSTerror(ERR_R_MALLOC_FAILURE);
606                               return 0;
607                     }
608                     memcpy(ukm, p2, p1);
609                     free(pctx->shared_ukm);
610                     pctx->shared_ukm = ukm;
611                     return 1;
612               }
613 
614           case EVP_PKEY_CTRL_PEER_KEY:
615                     if (p1 == 0 || p1 == 1)       /* call from EVP_PKEY_derive_set_peer */
616                               return 1;
617                     if (p1 == 2)        /* TLS: peer key used? */
618                               return pctx->peer_key_used;
619                     if (p1 == 3)        /* TLS: peer key used! */
620                               return (pctx->peer_key_used = 1);
621                     return -2;
622           case EVP_PKEY_CTRL_GOST_SIG_FORMAT:
623                     switch (p1) {
624                     case GOST_SIG_FORMAT_SR_BE:
625                     case GOST_SIG_FORMAT_RS_LE:
626                               pctx->sig_format = p1;
627                               return 1;
628                     default:
629                               return 0;
630                     }
631                     break;
632           case EVP_PKEY_CTRL_GOST_SET_DIGEST:
633                     pctx->digest_nid = (int)p1;
634                     return 1;
635           case EVP_PKEY_CTRL_GOST_GET_DIGEST:
636                     *(int *)p2 = pctx->digest_nid;
637                     return 1;
638           default:
639                     return -2;
640           }
641 }
642 
643 static int
pkey_gost01_ctrl_str(EVP_PKEY_CTX * ctx,const char * type,const char * value)644 pkey_gost01_ctrl_str(EVP_PKEY_CTX *ctx, const char *type, const char *value)
645 {
646           int param_nid = NID_undef;
647           int digest_nid = NID_undef;
648 
649           if (strcmp(type, "paramset") == 0) {
650                     if (value == NULL)
651                               return 0;
652                     if (pkey_gost01_ctrl(ctx, EVP_PKEY_CTRL_GOST_GET_DIGEST, 0,
653                         &digest_nid) == 0)
654                               return 0;
655                     if (digest_nid == NID_id_tc26_gost3411_2012_512)
656                               param_nid = GostR3410_512_param_id(value);
657                     else
658                               param_nid = GostR3410_256_param_id(value);
659                     if (param_nid == NID_undef)
660                               param_nid = OBJ_txt2nid(value);
661                     if (param_nid == NID_undef)
662                               return 0;
663 
664                     return pkey_gost01_ctrl(ctx, EVP_PKEY_CTRL_GOST_PARAMSET,
665                         param_nid, NULL);
666           }
667           if (strcmp(type, "dgst") == 0) {
668                     if (value == NULL)
669                               return 0;
670                     else if (strcmp(value, "gost94") == 0 ||
671                         strcmp(value, "md_gost94") == 0)
672                               digest_nid = NID_id_GostR3411_94_CryptoProParamSet;
673                     else if (strcmp(value, "streebog256") == 0)
674                               digest_nid = NID_id_tc26_gost3411_2012_256;
675                     else if (strcmp(value, "streebog512") == 0)
676                               digest_nid = NID_id_tc26_gost3411_2012_512;
677 
678                     if (digest_nid == NID_undef)
679                               return 0;
680 
681                     return pkey_gost01_ctrl(ctx, EVP_PKEY_CTRL_GOST_SET_DIGEST,
682                         digest_nid, NULL);
683           }
684           return -2;
685 }
686 
687 const EVP_PKEY_METHOD gostr01_pkey_meth = {
688           .pkey_id = EVP_PKEY_GOSTR01,
689 
690           .init = pkey_gost01_init,
691           .copy = pkey_gost01_copy,
692           .cleanup = pkey_gost01_cleanup,
693 
694           .paramgen = pkey_gost01_paramgen,
695           .keygen = pkey_gost01_keygen,
696           .sign = pkey_gost01_sign,
697           .verify = pkey_gost01_verify,
698 
699           .encrypt = pkey_gost01_encrypt,
700           .decrypt = pkey_gost01_decrypt,
701           .derive = pkey_gost01_derive,
702 
703           .ctrl = pkey_gost01_ctrl,
704           .ctrl_str = pkey_gost01_ctrl_str,
705 };
706 #endif
707