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 *
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
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 *
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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