Import LibreSSL v2.4.2 to vendor branch
[dragonfly.git] / crypto / libressl / crypto / gost / gostr341001_pmeth.c
1 /* $OpenBSD: gostr341001_pmeth.c,v 1.11 2015/02/14 06:40:04 jsing 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 "evp_locl.h"
66 #include "gost_locl.h"
67 #include "gost_asn1.h"
68
69 static ECDSA_SIG *
70 unpack_signature_cp(const unsigned char *sig, size_t siglen)
71 {
72         ECDSA_SIG *s;
73
74         s = ECDSA_SIG_new();
75         if (s == NULL) {
76                 GOSTerr(GOST_F_UNPACK_SIGNATURE_CP, ERR_R_MALLOC_FAILURE);
77                 return NULL;
78         }
79         BN_bin2bn(sig, siglen / 2, s->s);
80         BN_bin2bn(sig + siglen / 2, siglen / 2, s->r);
81         return s;
82 }
83
84 static int
85 pack_signature_cp(ECDSA_SIG *s, int order, unsigned char *sig, size_t *siglen)
86 {
87         int r_len = BN_num_bytes(s->r);
88         int s_len = BN_num_bytes(s->s);
89
90         if (r_len > order || s_len > order)
91                 return 0;
92
93         *siglen = 2 * order;
94
95         memset(sig, 0, *siglen);
96         BN_bn2bin(s->s, sig + order - s_len);
97         BN_bn2bin(s->r, sig + 2 * order - r_len);
98         ECDSA_SIG_free(s);
99         return 1;
100 }
101
102 static ECDSA_SIG *
103 unpack_signature_le(const unsigned char *sig, size_t siglen)
104 {
105         ECDSA_SIG *s;
106
107         s = ECDSA_SIG_new();
108         if (s == NULL) {
109                 GOSTerr(GOST_F_UNPACK_SIGNATURE_LE, ERR_R_MALLOC_FAILURE);
110                 return NULL;
111         }
112         GOST_le2bn(sig, siglen / 2, s->r);
113         GOST_le2bn(sig + siglen / 2, siglen / 2, s->s);
114         return s;
115 }
116
117 static int
118 pack_signature_le(ECDSA_SIG *s, int order, unsigned char *sig, size_t *siglen)
119 {
120         *siglen = 2 * order;
121         memset(sig, 0, *siglen);
122         GOST_bn2le(s->r, sig, order);
123         GOST_bn2le(s->s, sig + order, order);
124         ECDSA_SIG_free(s);
125         return 1;
126 }
127
128 struct gost_pmeth_data {
129         int sign_param_nid; /* Should be set whenever parameters are filled */
130         int digest_nid;
131         EVP_MD *md;
132         unsigned char *shared_ukm;
133         int peer_key_used;
134         int sig_format;
135 };
136
137 static int
138 pkey_gost01_init(EVP_PKEY_CTX *ctx)
139 {
140         struct gost_pmeth_data *data;
141         EVP_PKEY *pkey = EVP_PKEY_CTX_get0_pkey(ctx);
142
143         data = calloc(1, sizeof(struct gost_pmeth_data));
144         if (data == NULL)
145                 return 0;
146
147         if (pkey != NULL && pkey->pkey.gost != NULL) {
148                 data->sign_param_nid =
149                     EC_GROUP_get_curve_name(GOST_KEY_get0_group(pkey->pkey.gost));
150                 data->digest_nid = GOST_KEY_get_digest(pkey->pkey.gost);
151         }
152         EVP_PKEY_CTX_set_data(ctx, data);
153         return 1;
154 }
155
156 /* Copies contents of gost_pmeth_data structure */
157 static int
158 pkey_gost01_copy(EVP_PKEY_CTX *dst, EVP_PKEY_CTX *src)
159 {
160         struct gost_pmeth_data *dst_data, *src_data;
161
162         if (pkey_gost01_init(dst) == 0)
163                 return 0;
164
165         src_data = EVP_PKEY_CTX_get_data(src);
166         dst_data = EVP_PKEY_CTX_get_data(dst);
167         *dst_data = *src_data;
168         if (src_data->shared_ukm != NULL)
169                 dst_data->shared_ukm = NULL;
170         return 1;
171 }
172
173 /* Frees up gost_pmeth_data structure */
174 static void
175 pkey_gost01_cleanup(EVP_PKEY_CTX *ctx)
176 {
177         struct gost_pmeth_data *data = EVP_PKEY_CTX_get_data(ctx);
178
179         free(data->shared_ukm);
180         free(data);
181 }
182
183 static int
184 pkey_gost01_paramgen(EVP_PKEY_CTX *ctx, EVP_PKEY *pkey)
185 {
186         struct gost_pmeth_data *data = EVP_PKEY_CTX_get_data(ctx);
187         EC_GROUP *group = NULL;
188         GOST_KEY *gost = NULL;
189         int ret = 0;
190
191         if (data->sign_param_nid == NID_undef ||
192             data->digest_nid == NID_undef) {
193                 GOSTerr(GOST_F_PKEY_GOST01_PARAMGEN, GOST_R_NO_PARAMETERS_SET);
194                 return 0;
195         }
196
197         group = EC_GROUP_new_by_curve_name(data->sign_param_nid);
198         if (group == NULL)
199                 goto done;
200
201         EC_GROUP_set_asn1_flag(group, OPENSSL_EC_NAMED_CURVE);
202
203         gost = GOST_KEY_new();
204         if (gost == NULL)
205                 goto done;
206
207         if (GOST_KEY_set_digest(gost, data->digest_nid) == 0)
208                 goto done;
209
210         if (GOST_KEY_set_group(gost, group) != 0)
211                 ret = EVP_PKEY_assign_GOST(pkey, gost);
212
213 done:
214         if (ret == 0)
215                 GOST_KEY_free(gost);
216         EC_GROUP_free(group);
217         return ret;
218 }
219
220 static int
221 pkey_gost01_keygen(EVP_PKEY_CTX *ctx, EVP_PKEY *pkey)
222 {
223         if (pkey_gost01_paramgen(ctx, pkey) == 0)
224                 return 0;
225         return gost2001_keygen(pkey->pkey.gost) != 0;
226 }
227
228 static int
229 pkey_gost01_sign(EVP_PKEY_CTX *ctx, unsigned char *sig, size_t *siglen,
230     const unsigned char *tbs, size_t tbs_len)
231 {
232         ECDSA_SIG *unpacked_sig = NULL;
233         EVP_PKEY *pkey = EVP_PKEY_CTX_get0_pkey(ctx);
234         struct gost_pmeth_data *pctx = EVP_PKEY_CTX_get_data(ctx);
235         BIGNUM *md;
236         size_t size;
237         int ret;
238
239         if (pkey == NULL || pkey->pkey.gost == NULL)
240                 return 0;
241         size = GOST_KEY_get_size(pkey->pkey.gost);
242
243         if (siglen == NULL)
244                 return 0;
245         if (sig == NULL) {
246                 *siglen = 2 * size;
247                 return 1;
248         } else if (*siglen < 2 * size) {
249                 GOSTerr(GOST_F_PKEY_GOST01_SIGN, EC_R_BUFFER_TOO_SMALL);
250                 return 0;
251         }
252         if (tbs_len != 32 && tbs_len != 64) {
253                 GOSTerr(GOST_F_PKEY_GOST01_SIGN, EVP_R_BAD_BLOCK_LENGTH);
254                 return 0;
255         }
256         md = GOST_le2bn(tbs, tbs_len, NULL);
257         if (md == NULL)
258                 return 0;
259         unpacked_sig = gost2001_do_sign(md, pkey->pkey.gost);
260         BN_free(md);
261         if (unpacked_sig == NULL) {
262                 return 0;
263         }
264         switch (pctx->sig_format) {
265         case GOST_SIG_FORMAT_SR_BE:
266                 ret = pack_signature_cp(unpacked_sig, size, sig, siglen);
267                 break;
268         case GOST_SIG_FORMAT_RS_LE:
269                 ret = pack_signature_le(unpacked_sig, size, sig, siglen);
270                 break;
271         default:
272                 ret = -1;
273                 break;
274         }
275         if (ret <= 0)
276                 ECDSA_SIG_free(unpacked_sig);
277         return ret;
278 }
279
280 static int
281 pkey_gost01_verify(EVP_PKEY_CTX *ctx, const unsigned char *sig, size_t siglen,
282     const unsigned char *tbs, size_t tbs_len)
283 {
284         int ok = 0;
285         EVP_PKEY *pub_key = EVP_PKEY_CTX_get0_pkey(ctx);
286         struct gost_pmeth_data *pctx = EVP_PKEY_CTX_get_data(ctx);
287         ECDSA_SIG *s = NULL;
288         BIGNUM *md;
289
290         if (pub_key == NULL)
291                 return 0;
292         switch (pctx->sig_format) {
293         case GOST_SIG_FORMAT_SR_BE:
294                 s = unpack_signature_cp(sig, siglen);
295                 break;
296         case GOST_SIG_FORMAT_RS_LE:
297                 s = unpack_signature_le(sig, siglen);
298                 break;
299         }
300         if (s == NULL)
301                 return 0;
302         md = GOST_le2bn(tbs, tbs_len, NULL);
303         if (md == NULL)
304                 goto err;
305         ok = gost2001_do_verify(md, s, pub_key->pkey.gost);
306
307 err:
308         BN_free(md);
309         ECDSA_SIG_free(s);
310         return ok;
311 }
312
313 static int
314 gost01_VKO_key(EVP_PKEY *pub_key, EVP_PKEY *priv_key, const unsigned char *ukm,
315     unsigned char *key)
316 {
317         unsigned char hashbuf[128];
318         int digest_nid;
319         int ret = 0;
320         BN_CTX *ctx = BN_CTX_new();
321         BIGNUM *UKM, *X, *Y;
322
323         if (ctx == NULL)
324                 return 0;
325
326         BN_CTX_start(ctx);
327         if ((UKM = BN_CTX_get(ctx)) == NULL)
328                 goto err;
329         if ((X = BN_CTX_get(ctx)) == NULL)
330                 goto err;
331         if ((Y = BN_CTX_get(ctx)) == NULL)
332                 goto err;
333
334         GOST_le2bn(ukm, 8, UKM);
335
336         digest_nid = GOST_KEY_get_digest(priv_key->pkey.gost);
337         if (VKO_compute_key(X, Y, pub_key->pkey.gost, priv_key->pkey.gost,
338             UKM) == 0)
339                 goto err;
340
341         switch (digest_nid) {
342         case NID_id_GostR3411_94_CryptoProParamSet:
343                 GOST_bn2le(X, hashbuf, 32);
344                 GOST_bn2le(Y, hashbuf + 32, 32);
345                 GOSTR341194(hashbuf, 64, key, digest_nid);
346                 ret = 1;
347                 break;
348         case NID_id_tc26_gost3411_2012_256:
349                 GOST_bn2le(X, hashbuf, 32);
350                 GOST_bn2le(Y, hashbuf + 32, 32);
351                 STREEBOG256(hashbuf, 64, key);
352                 ret = 1;
353                 break;
354         case NID_id_tc26_gost3411_2012_512:
355                 GOST_bn2le(X, hashbuf, 64);
356                 GOST_bn2le(Y, hashbuf + 64, 64);
357                 STREEBOG256(hashbuf, 128, key);
358                 ret = 1;
359                 break;
360         default:
361                 ret = -2;
362                 break;
363         }
364 err:
365         BN_CTX_end(ctx);
366         BN_CTX_free(ctx);
367         return ret;
368 }
369
370 int
371 pkey_gost01_decrypt(EVP_PKEY_CTX *pctx, unsigned char *key, size_t *key_len,
372     const unsigned char *in, size_t in_len)
373 {
374         const unsigned char *p = in;
375         EVP_PKEY *priv = EVP_PKEY_CTX_get0_pkey(pctx);
376         GOST_KEY_TRANSPORT *gkt = NULL;
377         int ret = 0;
378         unsigned char wrappedKey[44];
379         unsigned char sharedKey[32];
380         EVP_PKEY *eph_key = NULL, *peerkey = NULL;
381         int nid;
382
383         if (key == NULL) {
384                 *key_len = 32;
385                 return 1;
386         }
387         gkt = d2i_GOST_KEY_TRANSPORT(NULL, (const unsigned char **)&p, in_len);
388         if (gkt == NULL) {
389                 GOSTerr(GOST_F_PKEY_GOST01_DECRYPT,
390                     GOST_R_ERROR_PARSING_KEY_TRANSPORT_INFO);
391                 return -1;
392         }
393
394         /* If key transport structure contains public key, use it */
395         eph_key = X509_PUBKEY_get(gkt->key_agreement_info->ephem_key);
396         if (eph_key != NULL) {
397                 if (EVP_PKEY_derive_set_peer(pctx, eph_key) <= 0) {
398                         GOSTerr(GOST_F_PKEY_GOST01_DECRYPT,
399                             GOST_R_INCOMPATIBLE_PEER_KEY);
400                         goto err;
401                 }
402         } else {
403                 /* Set control "public key from client certificate used" */
404                 if (EVP_PKEY_CTX_ctrl(pctx, -1, -1, EVP_PKEY_CTRL_PEER_KEY, 3,
405                     NULL) <= 0) {
406                         GOSTerr(GOST_F_PKEY_GOST01_DECRYPT,
407                             GOST_R_CTRL_CALL_FAILED);
408                         goto err;
409                 }
410         }
411         peerkey = EVP_PKEY_CTX_get0_peerkey(pctx);
412         if (peerkey == NULL) {
413                 GOSTerr(GOST_F_PKEY_GOST01_DECRYPT, GOST_R_NO_PEER_KEY);
414                 goto err;
415         }
416
417         nid = OBJ_obj2nid(gkt->key_agreement_info->cipher);
418
419         if (gkt->key_agreement_info->eph_iv->length != 8) {
420                 GOSTerr(GOST_F_PKEY_GOST01_DECRYPT,
421                     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                 GOSTerr(GOST_F_PKEY_GOST01_DECRYPT,
427                     EVP_R_BAD_KEY_LENGTH);
428                 goto err;
429         }
430         memcpy(wrappedKey + 8, gkt->key_info->encrypted_key->data, 32);
431         if (gkt->key_info->imit->length != 4) {
432                 GOSTerr(GOST_F_PKEY_GOST01_DECRYPT,
433                     ERR_R_INTERNAL_ERROR);
434                 goto err;
435         }
436         memcpy(wrappedKey + 40, gkt->key_info->imit->data, 4);
437         if (gost01_VKO_key(peerkey, priv, wrappedKey, sharedKey) <= 0)
438                 goto err;
439         if (gost_key_unwrap_crypto_pro(nid, sharedKey, wrappedKey, key) == 0) {
440                 GOSTerr(GOST_F_PKEY_GOST01_DECRYPT,
441                     GOST_R_ERROR_COMPUTING_SHARED_KEY);
442                 goto err;
443         }
444
445         ret = 1;
446 err:
447         EVP_PKEY_free(eph_key);
448         GOST_KEY_TRANSPORT_free(gkt);
449         return ret;
450 }
451
452 int
453 pkey_gost01_derive(EVP_PKEY_CTX *ctx, unsigned char *key, size_t *keylen)
454 {
455         /*
456          * Public key of peer in the ctx field peerkey
457          * Our private key in the ctx pkey
458          * ukm is in the algorithm specific context data
459          */
460         EVP_PKEY *my_key = EVP_PKEY_CTX_get0_pkey(ctx);
461         EVP_PKEY *peer_key = EVP_PKEY_CTX_get0_peerkey(ctx);
462         struct gost_pmeth_data *data = EVP_PKEY_CTX_get_data(ctx);
463
464         if (data->shared_ukm == NULL) {
465                 GOSTerr(GOST_F_PKEY_GOST01_DERIVE, GOST_R_UKM_NOT_SET);
466                 return 0;
467         }
468
469         if (key == NULL) {
470                 *keylen = 32;
471                 return 32;
472         }
473
474         if (gost01_VKO_key(peer_key, my_key, data->shared_ukm, key) <= 0)
475                 return 0;
476
477         *keylen = 32;
478         return 1;
479 }
480
481 int
482 pkey_gost01_encrypt(EVP_PKEY_CTX *pctx, unsigned char *out, size_t *out_len,
483     const unsigned char *key, size_t key_len)
484 {
485         GOST_KEY_TRANSPORT *gkt = NULL;
486         EVP_PKEY *pubk = EVP_PKEY_CTX_get0_pkey(pctx);
487         struct gost_pmeth_data *data = EVP_PKEY_CTX_get_data(pctx);
488         unsigned char ukm[8], shared_key[32], crypted_key[44];
489         int ret = 0;
490         int key_is_ephemeral;
491         EVP_PKEY *sec_key = EVP_PKEY_CTX_get0_peerkey(pctx);
492         int nid = NID_id_Gost28147_89_CryptoPro_A_ParamSet;
493
494         if (data->shared_ukm != NULL) {
495                 memcpy(ukm, data->shared_ukm, 8);
496         } else /* if (out != NULL) */ {
497                 arc4random_buf(ukm, 8);
498         }
499         /* Check for private key in the peer_key of context */
500         if (sec_key) {
501                 key_is_ephemeral = 0;
502                 if (GOST_KEY_get0_private_key(sec_key->pkey.gost) == 0) {
503                         GOSTerr(GOST_F_PKEY_GOST01_ENCRYPT,
504                             GOST_R_NO_PRIVATE_PART_OF_NON_EPHEMERAL_KEYPAIR);
505                         goto err;
506                 }
507         } else {
508                 key_is_ephemeral = 1;
509                 if (out != NULL) {
510                         GOST_KEY *tmp_key;
511
512                         sec_key = EVP_PKEY_new();
513                         if (sec_key == NULL)
514                                 goto err;
515                         tmp_key = GOST_KEY_new();
516                         if (tmp_key == NULL)
517                                 goto err;
518                         if (EVP_PKEY_assign(sec_key, EVP_PKEY_base_id(pubk),
519                             tmp_key) == 0) {
520                                 GOST_KEY_free(tmp_key);
521                                 goto err;
522                         }
523                         if (EVP_PKEY_copy_parameters(sec_key, pubk) == 0)
524                                 goto err;
525                         if (gost2001_keygen(sec_key->pkey.gost) == 0) {
526                                 goto err;
527                         }
528                 }
529         }
530
531         if (out != NULL) {
532                 if (gost01_VKO_key(pubk, sec_key, ukm, shared_key) <= 0)
533                         goto err;
534                 gost_key_wrap_crypto_pro(nid, shared_key, ukm, key,
535                     crypted_key);
536         }
537         gkt = GOST_KEY_TRANSPORT_new();
538         if (gkt == NULL)
539                 goto err;
540         if (ASN1_OCTET_STRING_set(gkt->key_agreement_info->eph_iv, ukm, 8) == 0)
541                 goto err;
542         if (ASN1_OCTET_STRING_set(gkt->key_info->imit, crypted_key + 40,
543             4) == 0)
544                 goto err;
545         if (ASN1_OCTET_STRING_set(gkt->key_info->encrypted_key, crypted_key + 8,
546             32) == 0)
547                 goto err;
548         if (key_is_ephemeral) {
549                 if (X509_PUBKEY_set(&gkt->key_agreement_info->ephem_key,
550                     out != NULL ? sec_key : pubk) == 0) {
551                         GOSTerr(GOST_F_PKEY_GOST01_ENCRYPT,
552                             GOST_R_CANNOT_PACK_EPHEMERAL_KEY);
553                         goto err;
554                 }
555         }
556         ASN1_OBJECT_free(gkt->key_agreement_info->cipher);
557         gkt->key_agreement_info->cipher = OBJ_nid2obj(nid);
558         if (key_is_ephemeral)
559                 EVP_PKEY_free(sec_key);
560         else {
561                 /* Set control "public key from client certificate used" */
562                 if (EVP_PKEY_CTX_ctrl(pctx, -1, -1, EVP_PKEY_CTRL_PEER_KEY, 3,
563                     NULL) <= 0) {
564                         GOSTerr(GOST_F_PKEY_GOST01_ENCRYPT,
565                             GOST_R_CTRL_CALL_FAILED);
566                         goto err;
567                 }
568         }
569         if ((*out_len = i2d_GOST_KEY_TRANSPORT(gkt, out ? &out : NULL)) > 0)
570                 ret = 1;
571         GOST_KEY_TRANSPORT_free(gkt);
572         return ret;
573
574 err:
575         if (key_is_ephemeral)
576                 EVP_PKEY_free(sec_key);
577         GOST_KEY_TRANSPORT_free(gkt);
578         return -1;
579 }
580
581
582 static int
583 pkey_gost01_ctrl(EVP_PKEY_CTX *ctx, int type, int p1, void *p2)
584 {
585         struct gost_pmeth_data *pctx = EVP_PKEY_CTX_get_data(ctx);
586
587         switch (type) {
588         case EVP_PKEY_CTRL_MD:
589                 if (EVP_MD_type(p2) !=
590                     GostR3410_get_md_digest(pctx->digest_nid)) {
591                         GOSTerr(GOST_F_PKEY_GOST01_CTRL,
592                             GOST_R_INVALID_DIGEST_TYPE);
593                         return 0;
594                 }
595                 pctx->md = p2;
596                 return 1;
597         case EVP_PKEY_CTRL_PKCS7_ENCRYPT:
598         case EVP_PKEY_CTRL_PKCS7_DECRYPT:
599         case EVP_PKEY_CTRL_PKCS7_SIGN:
600         case EVP_PKEY_CTRL_DIGESTINIT:
601 #ifndef OPENSSL_NO_CMS
602         case EVP_PKEY_CTRL_CMS_ENCRYPT:
603         case EVP_PKEY_CTRL_CMS_DECRYPT:
604         case EVP_PKEY_CTRL_CMS_SIGN:
605 #endif
606                 return 1;
607
608         case EVP_PKEY_CTRL_GOST_PARAMSET:
609                 pctx->sign_param_nid = (int)p1;
610                 return 1;
611
612         case EVP_PKEY_CTRL_SET_IV:
613             {
614                 char *ukm = malloc(p1);
615
616                 if (ukm == NULL) {
617                         GOSTerr(GOST_F_PKEY_GOST01_CTRL,
618                             ERR_R_MALLOC_FAILURE);
619                         return 0;
620                 }
621                 memcpy(ukm, p2, p1);
622                 free(pctx->shared_ukm);
623                 pctx->shared_ukm = ukm;
624                 return 1;
625             }
626
627         case EVP_PKEY_CTRL_PEER_KEY:
628                 if (p1 == 0 || p1 == 1) /* call from EVP_PKEY_derive_set_peer */
629                         return 1;
630                 if (p1 == 2)    /* TLS: peer key used? */
631                         return pctx->peer_key_used;
632                 if (p1 == 3)    /* TLS: peer key used! */
633                         return (pctx->peer_key_used = 1);
634                 return -2;
635         case EVP_PKEY_CTRL_GOST_SIG_FORMAT:
636                 switch (p1) {
637                 case GOST_SIG_FORMAT_SR_BE:
638                 case GOST_SIG_FORMAT_RS_LE:
639                         pctx->sig_format = p1;
640                         return 1;
641                 default:
642                         return 0;
643                 }
644                 break;
645         case EVP_PKEY_CTRL_GOST_SET_DIGEST:
646                 pctx->digest_nid = (int)p1;
647                 return 1;
648         case EVP_PKEY_CTRL_GOST_GET_DIGEST:
649                 *(int *)p2 = pctx->digest_nid;
650                 return 1;
651         default:
652                 return -2;
653         }
654 }
655
656 static int
657 pkey_gost01_ctrl_str(EVP_PKEY_CTX *ctx, const char *type, const char *value)
658 {
659         int param_nid = NID_undef;
660         int digest_nid = NID_undef;
661
662         if (strcmp(type, "paramset") == 0) {
663                 if (value == NULL)
664                         return 0;
665                 if (pkey_gost01_ctrl(ctx, EVP_PKEY_CTRL_GOST_GET_DIGEST, 0,
666                     &digest_nid) == 0)
667                         return 0;
668                 if (digest_nid == NID_id_tc26_gost3411_2012_512)
669                         param_nid = GostR3410_512_param_id(value);
670                 else
671                         param_nid = GostR3410_256_param_id(value);
672                 if (param_nid == NID_undef)
673                         param_nid = OBJ_txt2nid(value);
674                 if (param_nid == NID_undef)
675                         return 0;
676
677                 return pkey_gost01_ctrl(ctx, EVP_PKEY_CTRL_GOST_PARAMSET,
678                     param_nid, NULL);
679         }
680         if (strcmp(type, "dgst") == 0) {
681                 if (value == NULL)
682                         return 0;
683                 else if (strcmp(value, "gost94") == 0 ||
684                     strcmp(value, "md_gost94") == 0)
685                         digest_nid = NID_id_GostR3411_94_CryptoProParamSet;
686                 else if (strcmp(value, "streebog256") == 0)
687                         digest_nid = NID_id_tc26_gost3411_2012_256;
688                 else if (strcmp(value, "streebog512") == 0)
689                         digest_nid = NID_id_tc26_gost3411_2012_512;
690
691                 if (digest_nid == NID_undef)
692                         return 0;
693
694                 return pkey_gost01_ctrl(ctx, EVP_PKEY_CTRL_GOST_SET_DIGEST,
695                     digest_nid, NULL);
696         }
697         return -2;
698 }
699
700 const EVP_PKEY_METHOD gostr01_pkey_meth = {
701         .pkey_id = EVP_PKEY_GOSTR01,
702
703         .init = pkey_gost01_init,
704         .copy = pkey_gost01_copy,
705         .cleanup = pkey_gost01_cleanup,
706
707         .paramgen = pkey_gost01_paramgen,
708         .keygen = pkey_gost01_keygen,
709         .sign = pkey_gost01_sign,
710         .verify = pkey_gost01_verify,
711
712         .encrypt = pkey_gost01_encrypt,
713         .decrypt = pkey_gost01_decrypt,
714         .derive = pkey_gost01_derive,
715
716         .ctrl = pkey_gost01_ctrl,
717         .ctrl_str = pkey_gost01_ctrl_str,
718 };
719 #endif