1*de0e0e4dSAntonio Huete Jimenez /* $OpenBSD: gostr341001_ameth.c,v 1.19 2021/12/26 15:38:49 tb Exp $ */
2f5b1c8a1SJohn Marino /*
3f5b1c8a1SJohn Marino  * Copyright (c) 2014 Dmitry Eremin-Solenikov <dbaryshkov@gmail.com>
4f5b1c8a1SJohn Marino  * Copyright (c) 2005-2006 Cryptocom LTD
5f5b1c8a1SJohn Marino  *
6f5b1c8a1SJohn Marino  * Redistribution and use in source and binary forms, with or without
7f5b1c8a1SJohn Marino  * modification, are permitted provided that the following conditions
8f5b1c8a1SJohn Marino  * are met:
9f5b1c8a1SJohn Marino  *
10f5b1c8a1SJohn Marino  * 1. Redistributions of source code must retain the above copyright
11f5b1c8a1SJohn Marino  *    notice, this list of conditions and the following disclaimer.
12f5b1c8a1SJohn Marino  *
13f5b1c8a1SJohn Marino  * 2. Redistributions in binary form must reproduce the above copyright
14f5b1c8a1SJohn Marino  *    notice, this list of conditions and the following disclaimer in
15f5b1c8a1SJohn Marino  *    the documentation and/or other materials provided with the
16f5b1c8a1SJohn Marino  *    distribution.
17f5b1c8a1SJohn Marino  *
18f5b1c8a1SJohn Marino  * 3. All advertising materials mentioning features or use of this
19f5b1c8a1SJohn Marino  *    software must display the following acknowledgment:
20f5b1c8a1SJohn Marino  *    "This product includes software developed by the OpenSSL Project
21f5b1c8a1SJohn Marino  *    for use in the OpenSSL Toolkit. (http://www.openssl.org/)"
22f5b1c8a1SJohn Marino  *
23f5b1c8a1SJohn Marino  * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
24f5b1c8a1SJohn Marino  *    endorse or promote products derived from this software without
25f5b1c8a1SJohn Marino  *    prior written permission. For written permission, please contact
26f5b1c8a1SJohn Marino  *    openssl-core@openssl.org.
27f5b1c8a1SJohn Marino  *
28f5b1c8a1SJohn Marino  * 5. Products derived from this software may not be called "OpenSSL"
29f5b1c8a1SJohn Marino  *    nor may "OpenSSL" appear in their names without prior written
30f5b1c8a1SJohn Marino  *    permission of the OpenSSL Project.
31f5b1c8a1SJohn Marino  *
32f5b1c8a1SJohn Marino  * 6. Redistributions of any form whatsoever must retain the following
33f5b1c8a1SJohn Marino  *    acknowledgment:
34f5b1c8a1SJohn Marino  *    "This product includes software developed by the OpenSSL Project
35f5b1c8a1SJohn Marino  *    for use in the OpenSSL Toolkit (http://www.openssl.org/)"
36f5b1c8a1SJohn Marino  *
37f5b1c8a1SJohn Marino  * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
38f5b1c8a1SJohn Marino  * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
39f5b1c8a1SJohn Marino  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
40f5b1c8a1SJohn Marino  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE OpenSSL PROJECT OR
41f5b1c8a1SJohn Marino  * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
42f5b1c8a1SJohn Marino  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
43f5b1c8a1SJohn Marino  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
44f5b1c8a1SJohn Marino  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
45f5b1c8a1SJohn Marino  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
46f5b1c8a1SJohn Marino  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
47f5b1c8a1SJohn Marino  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
48f5b1c8a1SJohn Marino  * OF THE POSSIBILITY OF SUCH DAMAGE.
49f5b1c8a1SJohn Marino  * ====================================================================
50f5b1c8a1SJohn Marino  */
51f5b1c8a1SJohn Marino 
52f5b1c8a1SJohn Marino #include <string.h>
53f5b1c8a1SJohn Marino 
54f5b1c8a1SJohn Marino #include <openssl/opensslconf.h>
55f5b1c8a1SJohn Marino 
56f5b1c8a1SJohn Marino #ifndef OPENSSL_NO_GOST
57f5b1c8a1SJohn Marino #include <openssl/bn.h>
58f5b1c8a1SJohn Marino #include <openssl/evp.h>
59f5b1c8a1SJohn Marino #include <openssl/ec.h>
60f5b1c8a1SJohn Marino #include <openssl/err.h>
61f5b1c8a1SJohn Marino #include <openssl/x509.h>
62f5b1c8a1SJohn Marino #include <openssl/gost.h>
63f5b1c8a1SJohn Marino 
64f5b1c8a1SJohn Marino 
65f5b1c8a1SJohn Marino #include "asn1_locl.h"
66*de0e0e4dSAntonio Huete Jimenez #include "evp_locl.h"
67f5b1c8a1SJohn Marino #include "gost_locl.h"
68f5b1c8a1SJohn Marino #include "gost_asn1.h"
69f5b1c8a1SJohn Marino 
70f5b1c8a1SJohn Marino static void
pkey_free_gost01(EVP_PKEY * key)71f5b1c8a1SJohn Marino pkey_free_gost01(EVP_PKEY *key)
72f5b1c8a1SJohn Marino {
73f5b1c8a1SJohn Marino 	GOST_KEY_free(key->pkey.gost);
74f5b1c8a1SJohn Marino }
75f5b1c8a1SJohn Marino 
76f5b1c8a1SJohn Marino /*
77f5b1c8a1SJohn Marino  * Parses GOST algorithm parameters from X509_ALGOR and
78f5b1c8a1SJohn Marino  * modifies pkey setting NID and parameters
79f5b1c8a1SJohn Marino  */
80f5b1c8a1SJohn Marino static int
decode_gost01_algor_params(EVP_PKEY * pkey,const unsigned char ** p,int len)81f5b1c8a1SJohn Marino decode_gost01_algor_params(EVP_PKEY *pkey, const unsigned char **p, int len)
82f5b1c8a1SJohn Marino {
83f5b1c8a1SJohn Marino 	int param_nid = NID_undef, digest_nid = NID_undef;
84f5b1c8a1SJohn Marino 	GOST_KEY_PARAMS *gkp = NULL;
85f5b1c8a1SJohn Marino 	EC_GROUP *group;
86f5b1c8a1SJohn Marino 	GOST_KEY *ec;
87f5b1c8a1SJohn Marino 
88f5b1c8a1SJohn Marino 	gkp = d2i_GOST_KEY_PARAMS(NULL, p, len);
89f5b1c8a1SJohn Marino 	if (gkp == NULL) {
9072c33676SMaxim Ag 		GOSTerror(GOST_R_BAD_PKEY_PARAMETERS_FORMAT);
91f5b1c8a1SJohn Marino 		return 0;
92f5b1c8a1SJohn Marino 	}
93f5b1c8a1SJohn Marino 	param_nid = OBJ_obj2nid(gkp->key_params);
94f5b1c8a1SJohn Marino 	digest_nid = OBJ_obj2nid(gkp->hash_params);
95f5b1c8a1SJohn Marino 	GOST_KEY_PARAMS_free(gkp);
96f5b1c8a1SJohn Marino 
97f5b1c8a1SJohn Marino 	ec = pkey->pkey.gost;
98f5b1c8a1SJohn Marino 	if (ec == NULL) {
99f5b1c8a1SJohn Marino 		ec = GOST_KEY_new();
1008edacedfSDaniel Fojt 		if (ec == NULL) {
1018edacedfSDaniel Fojt 			GOSTerror(ERR_R_MALLOC_FAILURE);
102f5b1c8a1SJohn Marino 			return 0;
1038edacedfSDaniel Fojt 		}
104f5b1c8a1SJohn Marino 		if (EVP_PKEY_assign_GOST(pkey, ec) == 0)
105f5b1c8a1SJohn Marino 			return 0;
106f5b1c8a1SJohn Marino 	}
107f5b1c8a1SJohn Marino 
108f5b1c8a1SJohn Marino 	group = EC_GROUP_new_by_curve_name(param_nid);
1098edacedfSDaniel Fojt 	if (group == NULL) {
1108edacedfSDaniel Fojt 		GOSTerror(EC_R_EC_GROUP_NEW_BY_NAME_FAILURE);
111f5b1c8a1SJohn Marino 		return 0;
1128edacedfSDaniel Fojt 	}
113f5b1c8a1SJohn Marino 	EC_GROUP_set_asn1_flag(group, OPENSSL_EC_NAMED_CURVE);
114f5b1c8a1SJohn Marino 	if (GOST_KEY_set_group(ec, group) == 0) {
115f5b1c8a1SJohn Marino 		EC_GROUP_free(group);
116f5b1c8a1SJohn Marino 		return 0;
117f5b1c8a1SJohn Marino 	}
118f5b1c8a1SJohn Marino 	EC_GROUP_free(group);
119f5b1c8a1SJohn Marino 	if (GOST_KEY_set_digest(ec, digest_nid) == 0)
120f5b1c8a1SJohn Marino 		return 0;
121f5b1c8a1SJohn Marino 	return 1;
122f5b1c8a1SJohn Marino }
123f5b1c8a1SJohn Marino 
124f5b1c8a1SJohn Marino static ASN1_STRING *
encode_gost01_algor_params(const EVP_PKEY * key)125f5b1c8a1SJohn Marino encode_gost01_algor_params(const EVP_PKEY *key)
126f5b1c8a1SJohn Marino {
127f5b1c8a1SJohn Marino 	ASN1_STRING *params = ASN1_STRING_new();
128f5b1c8a1SJohn Marino 	GOST_KEY_PARAMS *gkp = GOST_KEY_PARAMS_new();
129f5b1c8a1SJohn Marino 	int pkey_param_nid = NID_undef;
130f5b1c8a1SJohn Marino 
131f5b1c8a1SJohn Marino 	if (params == NULL || gkp == NULL) {
13272c33676SMaxim Ag 		GOSTerror(ERR_R_MALLOC_FAILURE);
133f5b1c8a1SJohn Marino 		ASN1_STRING_free(params);
134f5b1c8a1SJohn Marino 		params = NULL;
135f5b1c8a1SJohn Marino 		goto err;
136f5b1c8a1SJohn Marino 	}
137f5b1c8a1SJohn Marino 
138f5b1c8a1SJohn Marino 	pkey_param_nid =
139f5b1c8a1SJohn Marino 	    EC_GROUP_get_curve_name(GOST_KEY_get0_group(key->pkey.gost));
140f5b1c8a1SJohn Marino 	gkp->key_params = OBJ_nid2obj(pkey_param_nid);
141f5b1c8a1SJohn Marino 	gkp->hash_params = OBJ_nid2obj(GOST_KEY_get_digest(key->pkey.gost));
142f5b1c8a1SJohn Marino 	/*gkp->cipher_params = OBJ_nid2obj(cipher_param_nid); */
143f5b1c8a1SJohn Marino 	params->length = i2d_GOST_KEY_PARAMS(gkp, &params->data);
144f5b1c8a1SJohn Marino 	if (params->length <= 0) {
14572c33676SMaxim Ag 		GOSTerror(ERR_R_MALLOC_FAILURE);
146f5b1c8a1SJohn Marino 		ASN1_STRING_free(params);
147f5b1c8a1SJohn Marino 		params = NULL;
148f5b1c8a1SJohn Marino 		goto err;
149f5b1c8a1SJohn Marino 	}
150f5b1c8a1SJohn Marino 	params->type = V_ASN1_SEQUENCE;
151f5b1c8a1SJohn Marino err:
152f5b1c8a1SJohn Marino 	GOST_KEY_PARAMS_free(gkp);
153f5b1c8a1SJohn Marino 	return params;
154f5b1c8a1SJohn Marino }
155f5b1c8a1SJohn Marino 
156f5b1c8a1SJohn Marino static int
pub_cmp_gost01(const EVP_PKEY * a,const EVP_PKEY * b)157f5b1c8a1SJohn Marino pub_cmp_gost01(const EVP_PKEY *a, const EVP_PKEY *b)
158f5b1c8a1SJohn Marino {
159f5b1c8a1SJohn Marino 	const GOST_KEY *ea = a->pkey.gost;
160f5b1c8a1SJohn Marino 	const GOST_KEY *eb = b->pkey.gost;
161f5b1c8a1SJohn Marino 	const EC_POINT *ka, *kb;
162f5b1c8a1SJohn Marino 	int ret = 0;
163f5b1c8a1SJohn Marino 
164f5b1c8a1SJohn Marino 	if (ea == NULL || eb == NULL)
165f5b1c8a1SJohn Marino 		return 0;
166f5b1c8a1SJohn Marino 	ka = GOST_KEY_get0_public_key(ea);
167f5b1c8a1SJohn Marino 	kb = GOST_KEY_get0_public_key(eb);
168f5b1c8a1SJohn Marino 	if (ka == NULL || kb == NULL)
169f5b1c8a1SJohn Marino 		return 0;
170f5b1c8a1SJohn Marino 	ret = (0 == EC_POINT_cmp(GOST_KEY_get0_group(ea), ka, kb, NULL));
171f5b1c8a1SJohn Marino 	return ret;
172f5b1c8a1SJohn Marino }
173f5b1c8a1SJohn Marino 
174f5b1c8a1SJohn Marino static int
pkey_size_gost01(const EVP_PKEY * pk)175f5b1c8a1SJohn Marino pkey_size_gost01(const EVP_PKEY *pk)
176f5b1c8a1SJohn Marino {
177f5b1c8a1SJohn Marino 	if (GOST_KEY_get_digest(pk->pkey.gost) == NID_id_tc26_gost3411_2012_512)
178f5b1c8a1SJohn Marino 		return 128;
179f5b1c8a1SJohn Marino 	return 64;
180f5b1c8a1SJohn Marino }
181f5b1c8a1SJohn Marino 
182f5b1c8a1SJohn Marino static int
pkey_bits_gost01(const EVP_PKEY * pk)183f5b1c8a1SJohn Marino pkey_bits_gost01(const EVP_PKEY *pk)
184f5b1c8a1SJohn Marino {
185f5b1c8a1SJohn Marino 	if (GOST_KEY_get_digest(pk->pkey.gost) == NID_id_tc26_gost3411_2012_512)
186f5b1c8a1SJohn Marino 		return 512;
187f5b1c8a1SJohn Marino 	return 256;
188f5b1c8a1SJohn Marino }
189f5b1c8a1SJohn Marino 
190f5b1c8a1SJohn Marino static int
pub_decode_gost01(EVP_PKEY * pk,X509_PUBKEY * pub)191f5b1c8a1SJohn Marino pub_decode_gost01(EVP_PKEY *pk, X509_PUBKEY *pub)
192f5b1c8a1SJohn Marino {
193f5b1c8a1SJohn Marino 	X509_ALGOR *palg = NULL;
194f5b1c8a1SJohn Marino 	const unsigned char *pubkey_buf = NULL;
195f5b1c8a1SJohn Marino 	const unsigned char *p;
196f5b1c8a1SJohn Marino 	ASN1_OBJECT *palgobj = NULL;
197f5b1c8a1SJohn Marino 	int pub_len;
198f5b1c8a1SJohn Marino 	BIGNUM *X, *Y;
199f5b1c8a1SJohn Marino 	ASN1_OCTET_STRING *octet = NULL;
200f5b1c8a1SJohn Marino 	int len;
201f5b1c8a1SJohn Marino 	int ret;
202f5b1c8a1SJohn Marino 	int ptype = V_ASN1_UNDEF;
203f5b1c8a1SJohn Marino 	ASN1_STRING *pval = NULL;
204f5b1c8a1SJohn Marino 
205f5b1c8a1SJohn Marino 	if (X509_PUBKEY_get0_param(&palgobj, &pubkey_buf, &pub_len, &palg, pub)
206f5b1c8a1SJohn Marino 	    == 0)
207f5b1c8a1SJohn Marino 		return 0;
208f5b1c8a1SJohn Marino 	(void)EVP_PKEY_assign_GOST(pk, NULL);
20972c33676SMaxim Ag 	X509_ALGOR_get0(NULL, &ptype, (const void **)&pval, palg);
210f5b1c8a1SJohn Marino 	if (ptype != V_ASN1_SEQUENCE) {
21172c33676SMaxim Ag 		GOSTerror(GOST_R_BAD_KEY_PARAMETERS_FORMAT);
212f5b1c8a1SJohn Marino 		return 0;
213f5b1c8a1SJohn Marino 	}
214f5b1c8a1SJohn Marino 	p = pval->data;
2158edacedfSDaniel Fojt 	if (decode_gost01_algor_params(pk, &p, pval->length) == 0) {
2168edacedfSDaniel Fojt 		GOSTerror(GOST_R_BAD_KEY_PARAMETERS_FORMAT);
217f5b1c8a1SJohn Marino 		return 0;
2188edacedfSDaniel Fojt 	}
219f5b1c8a1SJohn Marino 
220f5b1c8a1SJohn Marino 	octet = d2i_ASN1_OCTET_STRING(NULL, &pubkey_buf, pub_len);
221f5b1c8a1SJohn Marino 	if (octet == NULL) {
22272c33676SMaxim Ag 		GOSTerror(ERR_R_MALLOC_FAILURE);
223f5b1c8a1SJohn Marino 		return 0;
224f5b1c8a1SJohn Marino 	}
225f5b1c8a1SJohn Marino 	len = octet->length / 2;
226f5b1c8a1SJohn Marino 
227f5b1c8a1SJohn Marino 	X = GOST_le2bn(octet->data, len, NULL);
228f5b1c8a1SJohn Marino 	Y = GOST_le2bn(octet->data + len, len, NULL);
229f5b1c8a1SJohn Marino 
230f5b1c8a1SJohn Marino 	ASN1_OCTET_STRING_free(octet);
231f5b1c8a1SJohn Marino 
232f5b1c8a1SJohn Marino 	ret = GOST_KEY_set_public_key_affine_coordinates(pk->pkey.gost, X, Y);
233f5b1c8a1SJohn Marino 	if (ret == 0)
23472c33676SMaxim Ag 		GOSTerror(ERR_R_EC_LIB);
235f5b1c8a1SJohn Marino 
236f5b1c8a1SJohn Marino 	BN_free(X);
237f5b1c8a1SJohn Marino 	BN_free(Y);
238f5b1c8a1SJohn Marino 
239f5b1c8a1SJohn Marino 	return ret;
240f5b1c8a1SJohn Marino }
241f5b1c8a1SJohn Marino 
242f5b1c8a1SJohn Marino static int
pub_encode_gost01(X509_PUBKEY * pub,const EVP_PKEY * pk)243f5b1c8a1SJohn Marino pub_encode_gost01(X509_PUBKEY *pub, const EVP_PKEY *pk)
244f5b1c8a1SJohn Marino {
245f5b1c8a1SJohn Marino 	ASN1_OBJECT *algobj = NULL;
246f5b1c8a1SJohn Marino 	ASN1_OCTET_STRING *octet = NULL;
247f5b1c8a1SJohn Marino 	ASN1_STRING *params = NULL;
248f5b1c8a1SJohn Marino 	void *pval = NULL;
249f5b1c8a1SJohn Marino 	unsigned char *buf = NULL, *sptr;
250f5b1c8a1SJohn Marino 	int key_size, ret = 0;
251f5b1c8a1SJohn Marino 	const EC_POINT *pub_key;
252f5b1c8a1SJohn Marino 	BIGNUM *X = NULL, *Y = NULL;
253f5b1c8a1SJohn Marino 	const GOST_KEY *ec = pk->pkey.gost;
254f5b1c8a1SJohn Marino 	int ptype = V_ASN1_UNDEF;
255f5b1c8a1SJohn Marino 
256f5b1c8a1SJohn Marino 	algobj = OBJ_nid2obj(GostR3410_get_pk_digest(GOST_KEY_get_digest(ec)));
257f5b1c8a1SJohn Marino 	if (pk->save_parameters) {
258f5b1c8a1SJohn Marino 		params = encode_gost01_algor_params(pk);
259f5b1c8a1SJohn Marino 		if (params == NULL)
260f5b1c8a1SJohn Marino 			return 0;
261f5b1c8a1SJohn Marino 		pval = params;
262f5b1c8a1SJohn Marino 		ptype = V_ASN1_SEQUENCE;
263f5b1c8a1SJohn Marino 	}
264f5b1c8a1SJohn Marino 
265f5b1c8a1SJohn Marino 	key_size = GOST_KEY_get_size(ec);
266f5b1c8a1SJohn Marino 
267f5b1c8a1SJohn Marino 	pub_key = GOST_KEY_get0_public_key(ec);
268f5b1c8a1SJohn Marino 	if (pub_key == NULL) {
26972c33676SMaxim Ag 		GOSTerror(GOST_R_PUBLIC_KEY_UNDEFINED);
270f5b1c8a1SJohn Marino 		goto err;
271f5b1c8a1SJohn Marino 	}
272f5b1c8a1SJohn Marino 
273f5b1c8a1SJohn Marino 	octet = ASN1_OCTET_STRING_new();
274f5b1c8a1SJohn Marino 	if (octet == NULL) {
27572c33676SMaxim Ag 		GOSTerror(ERR_R_MALLOC_FAILURE);
276f5b1c8a1SJohn Marino 		goto err;
277f5b1c8a1SJohn Marino 	}
278f5b1c8a1SJohn Marino 
279f5b1c8a1SJohn Marino 	ret = ASN1_STRING_set(octet, NULL, 2 * key_size);
280f5b1c8a1SJohn Marino 	if (ret == 0) {
28172c33676SMaxim Ag 		GOSTerror(ERR_R_INTERNAL_ERROR);
282f5b1c8a1SJohn Marino 		goto err;
283f5b1c8a1SJohn Marino 	}
284f5b1c8a1SJohn Marino 
285f5b1c8a1SJohn Marino 	sptr = ASN1_STRING_data(octet);
286f5b1c8a1SJohn Marino 
287f5b1c8a1SJohn Marino 	X = BN_new();
288f5b1c8a1SJohn Marino 	Y = BN_new();
289f5b1c8a1SJohn Marino 	if (X == NULL || Y == NULL) {
29072c33676SMaxim Ag 		GOSTerror(ERR_R_MALLOC_FAILURE);
291f5b1c8a1SJohn Marino 		goto err;
292f5b1c8a1SJohn Marino 	}
293f5b1c8a1SJohn Marino 
294*de0e0e4dSAntonio Huete Jimenez 	if (EC_POINT_get_affine_coordinates(GOST_KEY_get0_group(ec),
295f5b1c8a1SJohn Marino 	    pub_key, X, Y, NULL) == 0) {
29672c33676SMaxim Ag 		GOSTerror(ERR_R_EC_LIB);
297f5b1c8a1SJohn Marino 		goto err;
298f5b1c8a1SJohn Marino 	}
299f5b1c8a1SJohn Marino 
300f5b1c8a1SJohn Marino 	GOST_bn2le(X, sptr, key_size);
301f5b1c8a1SJohn Marino 	GOST_bn2le(Y, sptr + key_size, key_size);
302f5b1c8a1SJohn Marino 
303f5b1c8a1SJohn Marino 	BN_free(Y);
304f5b1c8a1SJohn Marino 	BN_free(X);
305f5b1c8a1SJohn Marino 
306f5b1c8a1SJohn Marino 	ret = i2d_ASN1_OCTET_STRING(octet, &buf);
307f5b1c8a1SJohn Marino 	ASN1_BIT_STRING_free(octet);
308f5b1c8a1SJohn Marino 	if (ret < 0)
309f5b1c8a1SJohn Marino 		return 0;
310f5b1c8a1SJohn Marino 
311f5b1c8a1SJohn Marino 	return X509_PUBKEY_set0_param(pub, algobj, ptype, pval, buf, ret);
312f5b1c8a1SJohn Marino 
313f5b1c8a1SJohn Marino err:
314f5b1c8a1SJohn Marino 	BN_free(Y);
315f5b1c8a1SJohn Marino 	BN_free(X);
316f5b1c8a1SJohn Marino 	ASN1_BIT_STRING_free(octet);
317f5b1c8a1SJohn Marino 	ASN1_STRING_free(params);
318f5b1c8a1SJohn Marino 	return 0;
319f5b1c8a1SJohn Marino }
320f5b1c8a1SJohn Marino 
321f5b1c8a1SJohn Marino static int
param_print_gost01(BIO * out,const EVP_PKEY * pkey,int indent,ASN1_PCTX * pctx)322f5b1c8a1SJohn Marino param_print_gost01(BIO *out, const EVP_PKEY *pkey, int indent, ASN1_PCTX *pctx)
323f5b1c8a1SJohn Marino {
324f5b1c8a1SJohn Marino 	int param_nid =
325f5b1c8a1SJohn Marino 	    EC_GROUP_get_curve_name(GOST_KEY_get0_group(pkey->pkey.gost));
326f5b1c8a1SJohn Marino 
327f5b1c8a1SJohn Marino 	if (BIO_indent(out, indent, 128) == 0)
328f5b1c8a1SJohn Marino 		return 0;
329f5b1c8a1SJohn Marino 	BIO_printf(out, "Parameter set: %s\n", OBJ_nid2ln(param_nid));
330f5b1c8a1SJohn Marino 	if (BIO_indent(out, indent, 128) == 0)
331f5b1c8a1SJohn Marino 		return 0;
332f5b1c8a1SJohn Marino 	BIO_printf(out, "Digest Algorithm: %s\n",
333f5b1c8a1SJohn Marino 	    OBJ_nid2ln(GOST_KEY_get_digest(pkey->pkey.gost)));
334f5b1c8a1SJohn Marino 	return 1;
335f5b1c8a1SJohn Marino }
336f5b1c8a1SJohn Marino 
337f5b1c8a1SJohn Marino static int
pub_print_gost01(BIO * out,const EVP_PKEY * pkey,int indent,ASN1_PCTX * pctx)338f5b1c8a1SJohn Marino pub_print_gost01(BIO *out, const EVP_PKEY *pkey, int indent, ASN1_PCTX *pctx)
339f5b1c8a1SJohn Marino {
340f5b1c8a1SJohn Marino 	BN_CTX *ctx = BN_CTX_new();
341f5b1c8a1SJohn Marino 	BIGNUM *X, *Y;
342f5b1c8a1SJohn Marino 	const EC_POINT *pubkey;
343f5b1c8a1SJohn Marino 	const EC_GROUP *group;
344f5b1c8a1SJohn Marino 
345f5b1c8a1SJohn Marino 	if (ctx == NULL) {
34672c33676SMaxim Ag 		GOSTerror(ERR_R_MALLOC_FAILURE);
347f5b1c8a1SJohn Marino 		return 0;
348f5b1c8a1SJohn Marino 	}
349f5b1c8a1SJohn Marino 	BN_CTX_start(ctx);
350f5b1c8a1SJohn Marino 	if ((X = BN_CTX_get(ctx)) == NULL)
351f5b1c8a1SJohn Marino 		goto err;
352f5b1c8a1SJohn Marino 	if ((Y = BN_CTX_get(ctx)) == NULL)
353f5b1c8a1SJohn Marino 		goto err;
354f5b1c8a1SJohn Marino 	pubkey = GOST_KEY_get0_public_key(pkey->pkey.gost);
355f5b1c8a1SJohn Marino 	group = GOST_KEY_get0_group(pkey->pkey.gost);
356*de0e0e4dSAntonio Huete Jimenez 	if (EC_POINT_get_affine_coordinates(group, pubkey, X, Y, ctx) == 0) {
35772c33676SMaxim Ag 		GOSTerror(ERR_R_EC_LIB);
358f5b1c8a1SJohn Marino 		goto err;
359f5b1c8a1SJohn Marino 	}
360f5b1c8a1SJohn Marino 	if (BIO_indent(out, indent, 128) == 0)
361f5b1c8a1SJohn Marino 		goto err;
362f5b1c8a1SJohn Marino 	BIO_printf(out, "Public key:\n");
363f5b1c8a1SJohn Marino 	if (BIO_indent(out, indent + 3, 128) == 0)
364f5b1c8a1SJohn Marino 		goto err;
365f5b1c8a1SJohn Marino 	BIO_printf(out, "X:");
366f5b1c8a1SJohn Marino 	BN_print(out, X);
367f5b1c8a1SJohn Marino 	BIO_printf(out, "\n");
368*de0e0e4dSAntonio Huete Jimenez 	if (BIO_indent(out, indent + 3, 128) == 0)
369*de0e0e4dSAntonio Huete Jimenez 		goto err;
370f5b1c8a1SJohn Marino 	BIO_printf(out, "Y:");
371f5b1c8a1SJohn Marino 	BN_print(out, Y);
372f5b1c8a1SJohn Marino 	BIO_printf(out, "\n");
373f5b1c8a1SJohn Marino 
374f5b1c8a1SJohn Marino 	BN_CTX_end(ctx);
375f5b1c8a1SJohn Marino 	BN_CTX_free(ctx);
376f5b1c8a1SJohn Marino 
377f5b1c8a1SJohn Marino 	return param_print_gost01(out, pkey, indent, pctx);
378f5b1c8a1SJohn Marino 
379f5b1c8a1SJohn Marino err:
380f5b1c8a1SJohn Marino 	BN_CTX_end(ctx);
381f5b1c8a1SJohn Marino 	BN_CTX_free(ctx);
382f5b1c8a1SJohn Marino 	return 0;
383f5b1c8a1SJohn Marino }
384f5b1c8a1SJohn Marino 
385f5b1c8a1SJohn Marino static int
priv_print_gost01(BIO * out,const EVP_PKEY * pkey,int indent,ASN1_PCTX * pctx)386f5b1c8a1SJohn Marino priv_print_gost01(BIO *out, const EVP_PKEY *pkey, int indent, ASN1_PCTX *pctx)
387f5b1c8a1SJohn Marino {
388f5b1c8a1SJohn Marino 	const BIGNUM *key;
389f5b1c8a1SJohn Marino 
390f5b1c8a1SJohn Marino 	if (BIO_indent(out, indent, 128) == 0)
391f5b1c8a1SJohn Marino 		return 0;
392f5b1c8a1SJohn Marino 	BIO_printf(out, "Private key: ");
393f5b1c8a1SJohn Marino 	key = GOST_KEY_get0_private_key(pkey->pkey.gost);
394f5b1c8a1SJohn Marino 	if (key == NULL)
395f5b1c8a1SJohn Marino 		BIO_printf(out, "<undefined)");
396f5b1c8a1SJohn Marino 	else
397f5b1c8a1SJohn Marino 		BN_print(out, key);
398f5b1c8a1SJohn Marino 	BIO_printf(out, "\n");
399f5b1c8a1SJohn Marino 
400f5b1c8a1SJohn Marino 	return pub_print_gost01(out, pkey, indent, pctx);
401f5b1c8a1SJohn Marino }
402f5b1c8a1SJohn Marino 
403f5b1c8a1SJohn Marino static int
priv_decode_gost01(EVP_PKEY * pk,const PKCS8_PRIV_KEY_INFO * p8inf)40472c33676SMaxim Ag priv_decode_gost01(EVP_PKEY *pk, const PKCS8_PRIV_KEY_INFO *p8inf)
405f5b1c8a1SJohn Marino {
406f5b1c8a1SJohn Marino 	const unsigned char *pkey_buf = NULL, *p = NULL;
407f5b1c8a1SJohn Marino 	int priv_len = 0;
408f5b1c8a1SJohn Marino 	BIGNUM *pk_num = NULL;
409f5b1c8a1SJohn Marino 	int ret = 0;
41072c33676SMaxim Ag 	const X509_ALGOR *palg = NULL;
41172c33676SMaxim Ag 	const ASN1_OBJECT *palg_obj = NULL;
412f5b1c8a1SJohn Marino 	ASN1_INTEGER *priv_key = NULL;
413f5b1c8a1SJohn Marino 	GOST_KEY *ec;
414f5b1c8a1SJohn Marino 	int ptype = V_ASN1_UNDEF;
415f5b1c8a1SJohn Marino 	ASN1_STRING *pval = NULL;
416f5b1c8a1SJohn Marino 
4178edacedfSDaniel Fojt 	if (PKCS8_pkey_get0(&palg_obj, &pkey_buf, &priv_len, &palg, p8inf) == 0) {
4188edacedfSDaniel Fojt 		GOSTerror(GOST_R_BAD_KEY_PARAMETERS_FORMAT);
419f5b1c8a1SJohn Marino 		return 0;
4208edacedfSDaniel Fojt 	}
421f5b1c8a1SJohn Marino 	(void)EVP_PKEY_assign_GOST(pk, NULL);
42272c33676SMaxim Ag 	X509_ALGOR_get0(NULL, &ptype, (const void **)&pval, palg);
423f5b1c8a1SJohn Marino 	if (ptype != V_ASN1_SEQUENCE) {
42472c33676SMaxim Ag 		GOSTerror(GOST_R_BAD_KEY_PARAMETERS_FORMAT);
425f5b1c8a1SJohn Marino 		return 0;
426f5b1c8a1SJohn Marino 	}
427f5b1c8a1SJohn Marino 	p = pval->data;
4288edacedfSDaniel Fojt 	if (decode_gost01_algor_params(pk, &p, pval->length) == 0) {
4298edacedfSDaniel Fojt 		GOSTerror(GOST_R_BAD_KEY_PARAMETERS_FORMAT);
430f5b1c8a1SJohn Marino 		return 0;
4318edacedfSDaniel Fojt 	}
432f5b1c8a1SJohn Marino 	p = pkey_buf;
433f5b1c8a1SJohn Marino 	if (V_ASN1_OCTET_STRING == *p) {
434f5b1c8a1SJohn Marino 		/* New format - Little endian octet string */
435f5b1c8a1SJohn Marino 		ASN1_OCTET_STRING *s =
436f5b1c8a1SJohn Marino 		    d2i_ASN1_OCTET_STRING(NULL, &p, priv_len);
437f5b1c8a1SJohn Marino 
43872c33676SMaxim Ag 		if (s == NULL) {
43972c33676SMaxim Ag 			GOSTerror(EVP_R_DECODE_ERROR);
440f5b1c8a1SJohn Marino 			ASN1_STRING_free(s);
441f5b1c8a1SJohn Marino 			return 0;
442f5b1c8a1SJohn Marino 		}
44372c33676SMaxim Ag 
44472c33676SMaxim Ag 		pk_num = GOST_le2bn(s->data, s->length, NULL);
445f5b1c8a1SJohn Marino 		ASN1_STRING_free(s);
446f5b1c8a1SJohn Marino 	} else {
447f5b1c8a1SJohn Marino 		priv_key = d2i_ASN1_INTEGER(NULL, &p, priv_len);
448f5b1c8a1SJohn Marino 		if (priv_key == NULL)
449f5b1c8a1SJohn Marino 			return 0;
450f5b1c8a1SJohn Marino 		ret = ((pk_num = ASN1_INTEGER_to_BN(priv_key, NULL)) != NULL);
451f5b1c8a1SJohn Marino 		ASN1_INTEGER_free(priv_key);
452f5b1c8a1SJohn Marino 		if (ret == 0) {
45372c33676SMaxim Ag 			GOSTerror(EVP_R_DECODE_ERROR);
454f5b1c8a1SJohn Marino 			return 0;
455f5b1c8a1SJohn Marino 		}
456f5b1c8a1SJohn Marino 	}
457f5b1c8a1SJohn Marino 
458f5b1c8a1SJohn Marino 	ec = pk->pkey.gost;
459f5b1c8a1SJohn Marino 	if (ec == NULL) {
460f5b1c8a1SJohn Marino 		ec = GOST_KEY_new();
461f5b1c8a1SJohn Marino 		if (ec == NULL) {
462f5b1c8a1SJohn Marino 			BN_free(pk_num);
463f5b1c8a1SJohn Marino 			return 0;
464f5b1c8a1SJohn Marino 		}
465f5b1c8a1SJohn Marino 		if (EVP_PKEY_assign_GOST(pk, ec) == 0) {
466f5b1c8a1SJohn Marino 			BN_free(pk_num);
467f5b1c8a1SJohn Marino 			GOST_KEY_free(ec);
468f5b1c8a1SJohn Marino 			return 0;
469f5b1c8a1SJohn Marino 		}
470f5b1c8a1SJohn Marino 	}
471f5b1c8a1SJohn Marino 	if (GOST_KEY_set_private_key(ec, pk_num) == 0) {
472f5b1c8a1SJohn Marino 		BN_free(pk_num);
473f5b1c8a1SJohn Marino 		return 0;
474f5b1c8a1SJohn Marino 	}
475f5b1c8a1SJohn Marino 	ret = 0;
476f5b1c8a1SJohn Marino 	if (EVP_PKEY_missing_parameters(pk) == 0)
477f5b1c8a1SJohn Marino 		ret = gost2001_compute_public(ec) != 0;
478f5b1c8a1SJohn Marino 	BN_free(pk_num);
479f5b1c8a1SJohn Marino 
480f5b1c8a1SJohn Marino 	return ret;
481f5b1c8a1SJohn Marino }
482f5b1c8a1SJohn Marino 
483f5b1c8a1SJohn Marino static int
priv_encode_gost01(PKCS8_PRIV_KEY_INFO * p8,const EVP_PKEY * pk)484f5b1c8a1SJohn Marino priv_encode_gost01(PKCS8_PRIV_KEY_INFO *p8, const EVP_PKEY *pk)
485f5b1c8a1SJohn Marino {
486f5b1c8a1SJohn Marino 	ASN1_OBJECT *algobj =
487f5b1c8a1SJohn Marino 	    OBJ_nid2obj(GostR3410_get_pk_digest(GOST_KEY_get_digest(pk->pkey.gost)));
488f5b1c8a1SJohn Marino 	ASN1_STRING *params = encode_gost01_algor_params(pk);
489f5b1c8a1SJohn Marino 	unsigned char *priv_buf = NULL;
490f5b1c8a1SJohn Marino 	int priv_len;
491f5b1c8a1SJohn Marino 	ASN1_INTEGER *asn1key = NULL;
492f5b1c8a1SJohn Marino 
493f5b1c8a1SJohn Marino 	if (params == NULL)
494f5b1c8a1SJohn Marino 		return 0;
495f5b1c8a1SJohn Marino 
496f5b1c8a1SJohn Marino 	asn1key = BN_to_ASN1_INTEGER(GOST_KEY_get0_private_key(pk->pkey.gost),
497f5b1c8a1SJohn Marino 	    NULL);
498f5b1c8a1SJohn Marino 	if (asn1key == NULL) {
499f5b1c8a1SJohn Marino 		ASN1_STRING_free(params);
500f5b1c8a1SJohn Marino 		return 0;
501f5b1c8a1SJohn Marino 	}
502f5b1c8a1SJohn Marino 	priv_len = i2d_ASN1_INTEGER(asn1key, &priv_buf);
503f5b1c8a1SJohn Marino 	ASN1_INTEGER_free(asn1key);
504f5b1c8a1SJohn Marino 	return PKCS8_pkey_set0(p8, algobj, 0, V_ASN1_SEQUENCE, params, priv_buf,
505f5b1c8a1SJohn Marino 	    priv_len);
506f5b1c8a1SJohn Marino }
507f5b1c8a1SJohn Marino 
508f5b1c8a1SJohn Marino static int
param_encode_gost01(const EVP_PKEY * pkey,unsigned char ** pder)509f5b1c8a1SJohn Marino param_encode_gost01(const EVP_PKEY *pkey, unsigned char **pder)
510f5b1c8a1SJohn Marino {
511f5b1c8a1SJohn Marino 	ASN1_STRING *params = encode_gost01_algor_params(pkey);
512f5b1c8a1SJohn Marino 	int len;
513f5b1c8a1SJohn Marino 
514f5b1c8a1SJohn Marino 	if (params == NULL)
515f5b1c8a1SJohn Marino 		return 0;
516f5b1c8a1SJohn Marino 	len = params->length;
517f5b1c8a1SJohn Marino 	if (pder != NULL)
518f5b1c8a1SJohn Marino 		memcpy(*pder, params->data, params->length);
519f5b1c8a1SJohn Marino 	ASN1_STRING_free(params);
520f5b1c8a1SJohn Marino 	return len;
521f5b1c8a1SJohn Marino }
522f5b1c8a1SJohn Marino 
523f5b1c8a1SJohn Marino static int
param_decode_gost01(EVP_PKEY * pkey,const unsigned char ** pder,int derlen)524f5b1c8a1SJohn Marino param_decode_gost01(EVP_PKEY *pkey, const unsigned char **pder, int derlen)
525f5b1c8a1SJohn Marino {
526f5b1c8a1SJohn Marino 	ASN1_OBJECT *obj = NULL;
527f5b1c8a1SJohn Marino 	int nid;
528f5b1c8a1SJohn Marino 	GOST_KEY *ec;
529f5b1c8a1SJohn Marino 	EC_GROUP *group;
530f5b1c8a1SJohn Marino 	int ret;
531f5b1c8a1SJohn Marino 
532f5b1c8a1SJohn Marino 	/* New format */
533f5b1c8a1SJohn Marino 	if ((V_ASN1_SEQUENCE | V_ASN1_CONSTRUCTED) == **pder)
534f5b1c8a1SJohn Marino 		return decode_gost01_algor_params(pkey, pder, derlen);
535f5b1c8a1SJohn Marino 
536f5b1c8a1SJohn Marino 	/* Compatibility */
537f5b1c8a1SJohn Marino 	if (d2i_ASN1_OBJECT(&obj, pder, derlen) == NULL) {
53872c33676SMaxim Ag 		GOSTerror(ERR_R_MALLOC_FAILURE);
539f5b1c8a1SJohn Marino 		return 0;
540f5b1c8a1SJohn Marino 	}
541f5b1c8a1SJohn Marino 	nid = OBJ_obj2nid(obj);
542f5b1c8a1SJohn Marino 	ASN1_OBJECT_free(obj);
543f5b1c8a1SJohn Marino 
544f5b1c8a1SJohn Marino 	ec = GOST_KEY_new();
545f5b1c8a1SJohn Marino 	if (ec == NULL) {
54672c33676SMaxim Ag 		GOSTerror(ERR_R_MALLOC_FAILURE);
547f5b1c8a1SJohn Marino 		return 0;
548f5b1c8a1SJohn Marino 	}
549f5b1c8a1SJohn Marino 	group = EC_GROUP_new_by_curve_name(nid);
550f5b1c8a1SJohn Marino 	if (group == NULL) {
55172c33676SMaxim Ag 		GOSTerror(EC_R_EC_GROUP_NEW_BY_NAME_FAILURE);
552f5b1c8a1SJohn Marino 		GOST_KEY_free(ec);
553f5b1c8a1SJohn Marino 		return 0;
554f5b1c8a1SJohn Marino 	}
555f5b1c8a1SJohn Marino 
556f5b1c8a1SJohn Marino 	EC_GROUP_set_asn1_flag(group, OPENSSL_EC_NAMED_CURVE);
557f5b1c8a1SJohn Marino 	if (GOST_KEY_set_group(ec, group) == 0) {
55872c33676SMaxim Ag 		GOSTerror(ERR_R_EC_LIB);
559f5b1c8a1SJohn Marino 		EC_GROUP_free(group);
560f5b1c8a1SJohn Marino 		GOST_KEY_free(ec);
561f5b1c8a1SJohn Marino 		return 0;
562f5b1c8a1SJohn Marino 	}
563f5b1c8a1SJohn Marino 	EC_GROUP_free(group);
564f5b1c8a1SJohn Marino 	if (GOST_KEY_set_digest(ec,
565f5b1c8a1SJohn Marino 	    NID_id_GostR3411_94_CryptoProParamSet) == 0) {
56672c33676SMaxim Ag 		GOSTerror(GOST_R_INVALID_DIGEST_TYPE);
567f5b1c8a1SJohn Marino 		GOST_KEY_free(ec);
568f5b1c8a1SJohn Marino 		return 0;
569f5b1c8a1SJohn Marino 	}
570f5b1c8a1SJohn Marino 	ret = EVP_PKEY_assign_GOST(pkey, ec);
571f5b1c8a1SJohn Marino 	if (ret == 0)
572f5b1c8a1SJohn Marino 		GOST_KEY_free(ec);
573f5b1c8a1SJohn Marino 	return ret;
574f5b1c8a1SJohn Marino }
575f5b1c8a1SJohn Marino 
576f5b1c8a1SJohn Marino static int
param_missing_gost01(const EVP_PKEY * pk)577f5b1c8a1SJohn Marino param_missing_gost01(const EVP_PKEY *pk)
578f5b1c8a1SJohn Marino {
579f5b1c8a1SJohn Marino 	const GOST_KEY *ec = pk->pkey.gost;
580f5b1c8a1SJohn Marino 
581f5b1c8a1SJohn Marino 	if (ec == NULL)
582f5b1c8a1SJohn Marino 		return 1;
583f5b1c8a1SJohn Marino 	if (GOST_KEY_get0_group(ec) == NULL)
584f5b1c8a1SJohn Marino 		return 1;
585f5b1c8a1SJohn Marino 	if (GOST_KEY_get_digest(ec) == NID_undef)
586f5b1c8a1SJohn Marino 		return 1;
587f5b1c8a1SJohn Marino 	return 0;
588f5b1c8a1SJohn Marino }
589f5b1c8a1SJohn Marino 
590f5b1c8a1SJohn Marino static int
param_copy_gost01(EVP_PKEY * to,const EVP_PKEY * from)591f5b1c8a1SJohn Marino param_copy_gost01(EVP_PKEY *to, const EVP_PKEY *from)
592f5b1c8a1SJohn Marino {
593f5b1c8a1SJohn Marino 	GOST_KEY *eto = to->pkey.gost;
594f5b1c8a1SJohn Marino 	const GOST_KEY *efrom = from->pkey.gost;
595f5b1c8a1SJohn Marino 	int ret = 1;
596f5b1c8a1SJohn Marino 
597f5b1c8a1SJohn Marino 	if (EVP_PKEY_base_id(from) != EVP_PKEY_base_id(to)) {
59872c33676SMaxim Ag 		GOSTerror(GOST_R_INCOMPATIBLE_ALGORITHMS);
599f5b1c8a1SJohn Marino 		return 0;
600f5b1c8a1SJohn Marino 	}
601f5b1c8a1SJohn Marino 	if (efrom == NULL) {
60272c33676SMaxim Ag 		GOSTerror(GOST_R_KEY_PARAMETERS_MISSING);
603f5b1c8a1SJohn Marino 		return 0;
604f5b1c8a1SJohn Marino 	}
605f5b1c8a1SJohn Marino 	if (eto == NULL) {
606f5b1c8a1SJohn Marino 		eto = GOST_KEY_new();
607f5b1c8a1SJohn Marino 		if (eto == NULL) {
60872c33676SMaxim Ag 			GOSTerror(ERR_R_MALLOC_FAILURE);
609f5b1c8a1SJohn Marino 			return 0;
610f5b1c8a1SJohn Marino 		}
611f5b1c8a1SJohn Marino 		if (EVP_PKEY_assign(to, EVP_PKEY_base_id(from), eto) == 0) {
612f5b1c8a1SJohn Marino 			GOST_KEY_free(eto);
613f5b1c8a1SJohn Marino 			return 0;
614f5b1c8a1SJohn Marino 		}
615f5b1c8a1SJohn Marino 	}
616f5b1c8a1SJohn Marino 	GOST_KEY_set_group(eto, GOST_KEY_get0_group(efrom));
617f5b1c8a1SJohn Marino 	GOST_KEY_set_digest(eto, GOST_KEY_get_digest(efrom));
618f5b1c8a1SJohn Marino 	if (GOST_KEY_get0_private_key(eto) != NULL)
619f5b1c8a1SJohn Marino 		ret = gost2001_compute_public(eto);
620f5b1c8a1SJohn Marino 
621f5b1c8a1SJohn Marino 	return ret;
622f5b1c8a1SJohn Marino }
623f5b1c8a1SJohn Marino 
624f5b1c8a1SJohn Marino static int
param_cmp_gost01(const EVP_PKEY * a,const EVP_PKEY * b)625f5b1c8a1SJohn Marino param_cmp_gost01(const EVP_PKEY *a, const EVP_PKEY *b)
626f5b1c8a1SJohn Marino {
627f5b1c8a1SJohn Marino 	if (EC_GROUP_get_curve_name(GOST_KEY_get0_group(a->pkey.gost)) !=
628f5b1c8a1SJohn Marino 	    EC_GROUP_get_curve_name(GOST_KEY_get0_group(b->pkey.gost)))
629f5b1c8a1SJohn Marino 		return 0;
630f5b1c8a1SJohn Marino 
631f5b1c8a1SJohn Marino 	if (GOST_KEY_get_digest(a->pkey.gost) !=
632f5b1c8a1SJohn Marino 	    GOST_KEY_get_digest(b->pkey.gost))
633f5b1c8a1SJohn Marino 		return 0;
634f5b1c8a1SJohn Marino 
635f5b1c8a1SJohn Marino 	return 1;
636f5b1c8a1SJohn Marino }
637f5b1c8a1SJohn Marino 
638f5b1c8a1SJohn Marino static int
pkey_ctrl_gost01(EVP_PKEY * pkey,int op,long arg1,void * arg2)639f5b1c8a1SJohn Marino pkey_ctrl_gost01(EVP_PKEY *pkey, int op, long arg1, void *arg2)
640f5b1c8a1SJohn Marino {
641f5b1c8a1SJohn Marino 	X509_ALGOR *alg1 = NULL, *alg2 = NULL, *alg3 = NULL;
642f5b1c8a1SJohn Marino 	int digest = GOST_KEY_get_digest(pkey->pkey.gost);
643f5b1c8a1SJohn Marino 
644f5b1c8a1SJohn Marino 	switch (op) {
645f5b1c8a1SJohn Marino 	case ASN1_PKEY_CTRL_PKCS7_SIGN:
646f5b1c8a1SJohn Marino 		if (arg1 == 0)
647f5b1c8a1SJohn Marino 			PKCS7_SIGNER_INFO_get0_algs(arg2, NULL, &alg1, &alg2);
648f5b1c8a1SJohn Marino 		break;
649f5b1c8a1SJohn Marino 
650f5b1c8a1SJohn Marino 	case ASN1_PKEY_CTRL_PKCS7_ENCRYPT:
651f5b1c8a1SJohn Marino 		if (arg1 == 0)
652f5b1c8a1SJohn Marino 			PKCS7_RECIP_INFO_get0_alg(arg2, &alg3);
653f5b1c8a1SJohn Marino 		break;
654f5b1c8a1SJohn Marino 	case ASN1_PKEY_CTRL_DEFAULT_MD_NID:
655f5b1c8a1SJohn Marino 		*(int *)arg2 = GostR3410_get_md_digest(digest);
656f5b1c8a1SJohn Marino 		return 2;
657f5b1c8a1SJohn Marino 
658f5b1c8a1SJohn Marino 	default:
659f5b1c8a1SJohn Marino 		return -2;
660f5b1c8a1SJohn Marino 	}
661f5b1c8a1SJohn Marino 
662f5b1c8a1SJohn Marino 	if (alg1)
663f5b1c8a1SJohn Marino 		X509_ALGOR_set0(alg1, OBJ_nid2obj(GostR3410_get_md_digest(digest)), V_ASN1_NULL, 0);
664f5b1c8a1SJohn Marino 	if (alg2)
665f5b1c8a1SJohn Marino 		X509_ALGOR_set0(alg2, OBJ_nid2obj(GostR3410_get_pk_digest(digest)), V_ASN1_NULL, 0);
666f5b1c8a1SJohn Marino 	if (alg3) {
667f5b1c8a1SJohn Marino 		ASN1_STRING *params = encode_gost01_algor_params(pkey);
668f5b1c8a1SJohn Marino 		if (params == NULL) {
669f5b1c8a1SJohn Marino 			return -1;
670f5b1c8a1SJohn Marino 		}
671f5b1c8a1SJohn Marino 		X509_ALGOR_set0(alg3,
672f5b1c8a1SJohn Marino 		    OBJ_nid2obj(GostR3410_get_pk_digest(digest)),
673f5b1c8a1SJohn Marino 		    V_ASN1_SEQUENCE, params);
674f5b1c8a1SJohn Marino 	}
675f5b1c8a1SJohn Marino 
676f5b1c8a1SJohn Marino 	return 1;
677f5b1c8a1SJohn Marino }
678f5b1c8a1SJohn Marino 
679f5b1c8a1SJohn Marino const EVP_PKEY_ASN1_METHOD gostr01_asn1_meths[] = {
680f5b1c8a1SJohn Marino 	{
681f5b1c8a1SJohn Marino 		.pkey_id = EVP_PKEY_GOSTR01,
682f5b1c8a1SJohn Marino 		.pkey_base_id = EVP_PKEY_GOSTR01,
683f5b1c8a1SJohn Marino 		.pkey_flags = ASN1_PKEY_SIGPARAM_NULL,
684f5b1c8a1SJohn Marino 
685f5b1c8a1SJohn Marino 		.pem_str = "GOST2001",
686f5b1c8a1SJohn Marino 		.info = "GOST R 34.10-2001",
687f5b1c8a1SJohn Marino 
688f5b1c8a1SJohn Marino 		.pkey_free = pkey_free_gost01,
689f5b1c8a1SJohn Marino 		.pkey_ctrl = pkey_ctrl_gost01,
690f5b1c8a1SJohn Marino 
691f5b1c8a1SJohn Marino 		.priv_decode = priv_decode_gost01,
692f5b1c8a1SJohn Marino 		.priv_encode = priv_encode_gost01,
693f5b1c8a1SJohn Marino 		.priv_print = priv_print_gost01,
694f5b1c8a1SJohn Marino 
695f5b1c8a1SJohn Marino 		.param_decode = param_decode_gost01,
696f5b1c8a1SJohn Marino 		.param_encode = param_encode_gost01,
697f5b1c8a1SJohn Marino 		.param_missing = param_missing_gost01,
698f5b1c8a1SJohn Marino 		.param_copy = param_copy_gost01,
699f5b1c8a1SJohn Marino 		.param_cmp = param_cmp_gost01,
700f5b1c8a1SJohn Marino 		.param_print = param_print_gost01,
701f5b1c8a1SJohn Marino 
702f5b1c8a1SJohn Marino 		.pub_decode = pub_decode_gost01,
703f5b1c8a1SJohn Marino 		.pub_encode = pub_encode_gost01,
704f5b1c8a1SJohn Marino 		.pub_cmp = pub_cmp_gost01,
705f5b1c8a1SJohn Marino 		.pub_print = pub_print_gost01,
706f5b1c8a1SJohn Marino 		.pkey_size = pkey_size_gost01,
707f5b1c8a1SJohn Marino 		.pkey_bits = pkey_bits_gost01,
708f5b1c8a1SJohn Marino 	},
709f5b1c8a1SJohn Marino 	{
710f5b1c8a1SJohn Marino 		.pkey_id = EVP_PKEY_GOSTR12_256,
711f5b1c8a1SJohn Marino 		.pkey_base_id = EVP_PKEY_GOSTR01,
712f5b1c8a1SJohn Marino 		.pkey_flags = ASN1_PKEY_ALIAS
713f5b1c8a1SJohn Marino 	},
714f5b1c8a1SJohn Marino 	{
715f5b1c8a1SJohn Marino 		.pkey_id = EVP_PKEY_GOSTR12_512,
716f5b1c8a1SJohn Marino 		.pkey_base_id = EVP_PKEY_GOSTR01,
717f5b1c8a1SJohn Marino 		.pkey_flags = ASN1_PKEY_ALIAS
718f5b1c8a1SJohn Marino 	},
719f5b1c8a1SJohn Marino };
720f5b1c8a1SJohn Marino 
721f5b1c8a1SJohn Marino #endif
722