]>
Commit | Line | Data |
---|---|---|
a04549cc | 1 | /********************************************************************** |
926c41bd | 2 | * gost_ameth.c * |
a04549cc DSH |
3 | * Copyright (c) 2005-2006 Cryptocom LTD * |
4 | * This file is distributed under the same license as OpenSSL * | |
5 | * * | |
6 | * Implementation of RFC 4490/4491 ASN1 method * | |
7 | * for OpenSSL * | |
8 | * Requires OpenSSL 0.9.9 for compilation * | |
9 | **********************************************************************/ | |
1e26a8ba GT |
10 | #include <string.h> |
11 | #include <openssl/crypto.h> | |
12 | #include <openssl/err.h> | |
a04549cc DSH |
13 | #include <openssl/engine.h> |
14 | #include <openssl/evp.h> | |
a4346646 | 15 | #include <openssl/asn1.h> |
174b07be | 16 | #ifndef OPENSSL_NO_CMS |
0f113f3e | 17 | # include <openssl/cms.h> |
174b07be | 18 | #endif |
926c41bd | 19 | #include "gost_lcl.h" |
a04549cc DSH |
20 | #include "e_gost_err.h" |
21 | ||
ade44dcb RS |
22 | |
23 | /* Convert little-endian byte array into bignum */ | |
24 | BIGNUM *hashsum2bn(const unsigned char *dgst) | |
0f113f3e | 25 | { |
ade44dcb RS |
26 | unsigned char buf[32]; |
27 | ||
28 | BUF_reverse(buf, (unsigned char*)dgst, 32); | |
29 | return BN_bin2bn(buf, 32, NULL); | |
30 | } | |
31 | ||
32 | /* | |
33 | * Pack bignum into byte buffer of given size, filling all leading bytes by | |
34 | * zeros | |
35 | */ | |
36 | int store_bignum(BIGNUM *bn, unsigned char *buf, int len) | |
37 | { | |
38 | int bytes = BN_num_bytes(bn); | |
39 | ||
40 | if (bytes > len) | |
41 | return 0; | |
42 | memset(buf, 0, len); | |
43 | BN_bn2bin(bn, buf + len - bytes); | |
44 | return 1; | |
0f113f3e MC |
45 | } |
46 | ||
47 | static ASN1_STRING *encode_gost_algor_params(const EVP_PKEY *key) | |
48 | { | |
49 | ASN1_STRING *params = ASN1_STRING_new(); | |
50 | GOST_KEY_PARAMS *gkp = GOST_KEY_PARAMS_new(); | |
51 | int pkey_param_nid = NID_undef; | |
52 | ||
53 | if (!params || !gkp) { | |
54 | GOSTerr(GOST_F_ENCODE_GOST_ALGOR_PARAMS, ERR_R_MALLOC_FAILURE); | |
55 | ASN1_STRING_free(params); | |
56 | params = NULL; | |
57 | goto err; | |
58 | } | |
59 | switch (EVP_PKEY_base_id(key)) { | |
60 | case NID_id_GostR3410_2001: | |
61 | pkey_param_nid = | |
62 | EC_GROUP_get_curve_name(EC_KEY_get0_group | |
63 | (EVP_PKEY_get0((EVP_PKEY *)key))); | |
64 | break; | |
0f113f3e MC |
65 | } |
66 | gkp->key_params = OBJ_nid2obj(pkey_param_nid); | |
67 | gkp->hash_params = OBJ_nid2obj(NID_id_GostR3411_94_CryptoProParamSet); | |
68 | /* | |
69 | * gkp->cipher_params = OBJ_nid2obj(cipher_param_nid); | |
70 | */ | |
71 | params->length = i2d_GOST_KEY_PARAMS(gkp, ¶ms->data); | |
72 | if (params->length <= 0) { | |
73 | GOSTerr(GOST_F_ENCODE_GOST_ALGOR_PARAMS, ERR_R_MALLOC_FAILURE); | |
74 | ASN1_STRING_free(params); | |
75 | params = NULL; | |
76 | goto err; | |
77 | } | |
78 | params->type = V_ASN1_SEQUENCE; | |
79 | err: | |
80 | GOST_KEY_PARAMS_free(gkp); | |
81 | return params; | |
82 | } | |
83 | ||
84 | /* | |
85 | * Parses GOST algorithm parameters from X509_ALGOR and modifies pkey setting | |
86 | * NID and parameters | |
a04549cc | 87 | */ |
0f113f3e MC |
88 | static int decode_gost_algor_params(EVP_PKEY *pkey, X509_ALGOR *palg) |
89 | { | |
90 | ASN1_OBJECT *palg_obj = NULL; | |
91 | int ptype = V_ASN1_UNDEF; | |
92 | int pkey_nid = NID_undef, param_nid = NID_undef; | |
93 | void *_pval; | |
94 | ASN1_STRING *pval = NULL; | |
95 | const unsigned char *p; | |
96 | GOST_KEY_PARAMS *gkp = NULL; | |
97 | ||
98 | X509_ALGOR_get0(&palg_obj, &ptype, &_pval, palg); | |
99 | pval = _pval; | |
100 | if (ptype != V_ASN1_SEQUENCE) { | |
101 | GOSTerr(GOST_F_DECODE_GOST_ALGOR_PARAMS, | |
102 | GOST_R_BAD_KEY_PARAMETERS_FORMAT); | |
103 | return 0; | |
104 | } | |
105 | p = pval->data; | |
106 | pkey_nid = OBJ_obj2nid(palg_obj); | |
107 | ||
108 | gkp = d2i_GOST_KEY_PARAMS(NULL, &p, pval->length); | |
109 | if (!gkp) { | |
110 | GOSTerr(GOST_F_DECODE_GOST_ALGOR_PARAMS, | |
111 | GOST_R_BAD_PKEY_PARAMETERS_FORMAT); | |
112 | return 0; | |
113 | } | |
114 | param_nid = OBJ_obj2nid(gkp->key_params); | |
115 | GOST_KEY_PARAMS_free(gkp); | |
61986d32 | 116 | if (!EVP_PKEY_set_type(pkey, pkey_nid)) { |
8817e2e0 MC |
117 | GOSTerr(GOST_F_DECODE_GOST_ALGOR_PARAMS, ERR_R_INTERNAL_ERROR); |
118 | return 0; | |
119 | } | |
0f113f3e | 120 | switch (pkey_nid) { |
0f113f3e MC |
121 | case NID_id_GostR3410_2001: |
122 | { | |
123 | EC_KEY *ec = EVP_PKEY_get0(pkey); | |
124 | if (!ec) { | |
125 | ec = EC_KEY_new(); | |
126 | if (!EVP_PKEY_assign(pkey, pkey_nid, ec)) | |
127 | return 0; | |
128 | } | |
129 | if (!fill_GOST2001_params(ec, param_nid)) | |
130 | return 0; | |
131 | } | |
132 | } | |
133 | ||
134 | return 1; | |
135 | } | |
136 | ||
137 | static int gost_set_priv_key(EVP_PKEY *pkey, BIGNUM *priv) | |
138 | { | |
139 | switch (EVP_PKEY_base_id(pkey)) { | |
0f113f3e MC |
140 | case NID_id_GostR3410_2001: |
141 | { | |
142 | EC_KEY *ec = EVP_PKEY_get0(pkey); | |
143 | if (!ec) { | |
144 | ec = EC_KEY_new(); | |
145 | EVP_PKEY_assign(pkey, EVP_PKEY_base_id(pkey), ec); | |
146 | } | |
147 | if (!EC_KEY_set_private_key(ec, priv)) | |
148 | return 0; | |
149 | if (!EVP_PKEY_missing_parameters(pkey)) | |
150 | gost2001_compute_public(ec); | |
151 | break; | |
152 | } | |
153 | } | |
154 | return 1; | |
155 | } | |
156 | ||
157 | BIGNUM *gost_get0_priv_key(const EVP_PKEY *pkey) | |
158 | { | |
159 | switch (EVP_PKEY_base_id(pkey)) { | |
0f113f3e MC |
160 | case NID_id_GostR3410_2001: |
161 | { | |
162 | EC_KEY *ec = EVP_PKEY_get0((EVP_PKEY *)pkey); | |
163 | const BIGNUM *priv; | |
164 | if (!ec) { | |
165 | return NULL; | |
166 | } | |
75ebbd9a | 167 | if ((priv = EC_KEY_get0_private_key(ec)) == NULL) |
0f113f3e MC |
168 | return NULL; |
169 | return (BIGNUM *)priv; | |
0f113f3e MC |
170 | } |
171 | } | |
172 | return NULL; | |
173 | } | |
174 | ||
175 | static int pkey_ctrl_gost(EVP_PKEY *pkey, int op, long arg1, void *arg2) | |
176 | { | |
177 | switch (op) { | |
178 | case ASN1_PKEY_CTRL_PKCS7_SIGN: | |
179 | if (arg1 == 0) { | |
180 | X509_ALGOR *alg1 = NULL, *alg2 = NULL; | |
181 | int nid = EVP_PKEY_base_id(pkey); | |
182 | PKCS7_SIGNER_INFO_get0_algs((PKCS7_SIGNER_INFO *)arg2, | |
183 | NULL, &alg1, &alg2); | |
184 | X509_ALGOR_set0(alg1, OBJ_nid2obj(NID_id_GostR3411_94), | |
185 | V_ASN1_NULL, 0); | |
186 | if (nid == NID_undef) { | |
187 | return (-1); | |
188 | } | |
189 | X509_ALGOR_set0(alg2, OBJ_nid2obj(nid), V_ASN1_NULL, 0); | |
190 | } | |
191 | return 1; | |
174b07be | 192 | #ifndef OPENSSL_NO_CMS |
0f113f3e MC |
193 | case ASN1_PKEY_CTRL_CMS_SIGN: |
194 | if (arg1 == 0) { | |
195 | X509_ALGOR *alg1 = NULL, *alg2 = NULL; | |
196 | int nid = EVP_PKEY_base_id(pkey); | |
197 | CMS_SignerInfo_get0_algs((CMS_SignerInfo *)arg2, | |
198 | NULL, NULL, &alg1, &alg2); | |
199 | X509_ALGOR_set0(alg1, OBJ_nid2obj(NID_id_GostR3411_94), | |
200 | V_ASN1_NULL, 0); | |
201 | if (nid == NID_undef) { | |
202 | return (-1); | |
203 | } | |
204 | X509_ALGOR_set0(alg2, OBJ_nid2obj(nid), V_ASN1_NULL, 0); | |
205 | } | |
206 | return 1; | |
174b07be | 207 | #endif |
0f113f3e MC |
208 | case ASN1_PKEY_CTRL_PKCS7_ENCRYPT: |
209 | if (arg1 == 0) { | |
210 | X509_ALGOR *alg; | |
211 | ASN1_STRING *params = encode_gost_algor_params(pkey); | |
212 | if (!params) { | |
213 | return -1; | |
214 | } | |
215 | PKCS7_RECIP_INFO_get0_alg((PKCS7_RECIP_INFO *)arg2, &alg); | |
216 | X509_ALGOR_set0(alg, OBJ_nid2obj(pkey->type), | |
217 | V_ASN1_SEQUENCE, params); | |
218 | } | |
219 | return 1; | |
174b07be | 220 | #ifndef OPENSSL_NO_CMS |
0f113f3e MC |
221 | case ASN1_PKEY_CTRL_CMS_ENVELOPE: |
222 | if (arg1 == 0) { | |
223 | X509_ALGOR *alg = NULL; | |
224 | ASN1_STRING *params = encode_gost_algor_params(pkey); | |
225 | if (!params) { | |
226 | return -1; | |
227 | } | |
228 | CMS_RecipientInfo_ktri_get0_algs((CMS_RecipientInfo *)arg2, NULL, | |
229 | NULL, &alg); | |
230 | X509_ALGOR_set0(alg, OBJ_nid2obj(pkey->type), V_ASN1_SEQUENCE, | |
231 | params); | |
232 | } | |
233 | return 1; | |
174b07be | 234 | #endif |
0f113f3e MC |
235 | case ASN1_PKEY_CTRL_DEFAULT_MD_NID: |
236 | *(int *)arg2 = NID_id_GostR3411_94; | |
237 | return 2; | |
238 | } | |
239 | ||
240 | return -2; | |
241 | } | |
242 | ||
243 | /* --------------------- free functions * ------------------------------*/ | |
0f113f3e MC |
244 | static void pkey_free_gost01(EVP_PKEY *key) |
245 | { | |
8fdc3734 | 246 | EC_KEY_free(key->pkey.ec); |
0f113f3e | 247 | } |
926c41bd | 248 | |
a04549cc | 249 | /* ------------------ private key functions -----------------------------*/ |
0f113f3e MC |
250 | static int priv_decode_gost(EVP_PKEY *pk, PKCS8_PRIV_KEY_INFO *p8inf) |
251 | { | |
252 | const unsigned char *pkey_buf = NULL, *p = NULL; | |
253 | int priv_len = 0; | |
254 | BIGNUM *pk_num = NULL; | |
255 | int ret = 0; | |
256 | X509_ALGOR *palg = NULL; | |
257 | ASN1_OBJECT *palg_obj = NULL; | |
258 | ASN1_INTEGER *priv_key = NULL; | |
259 | ||
260 | if (!PKCS8_pkey_get0(&palg_obj, &pkey_buf, &priv_len, &palg, p8inf)) | |
261 | return 0; | |
262 | p = pkey_buf; | |
263 | if (!decode_gost_algor_params(pk, palg)) { | |
264 | return 0; | |
265 | } | |
266 | if (V_ASN1_OCTET_STRING == *p) { | |
267 | /* New format - Little endian octet string */ | |
268 | unsigned char rev_buf[32]; | |
269 | int i; | |
270 | ASN1_OCTET_STRING *s = d2i_ASN1_OCTET_STRING(NULL, &p, priv_len); | |
271 | if (!s || s->length != 32) { | |
272 | GOSTerr(GOST_F_PRIV_DECODE_GOST, EVP_R_DECODE_ERROR); | |
273 | return 0; | |
274 | } | |
275 | for (i = 0; i < 32; i++) { | |
276 | rev_buf[31 - i] = s->data[i]; | |
277 | } | |
278 | ASN1_STRING_free(s); | |
279 | pk_num = getbnfrombuf(rev_buf, 32); | |
280 | } else { | |
281 | priv_key = d2i_ASN1_INTEGER(NULL, &p, priv_len); | |
282 | if (!priv_key) | |
283 | return 0; | |
284 | ret = ((pk_num = ASN1_INTEGER_to_BN(priv_key, NULL)) != NULL); | |
285 | ASN1_INTEGER_free(priv_key); | |
286 | if (!ret) { | |
287 | GOSTerr(GOST_F_PRIV_DECODE_GOST, EVP_R_DECODE_ERROR); | |
288 | return 0; | |
289 | } | |
290 | } | |
291 | ||
292 | ret = gost_set_priv_key(pk, pk_num); | |
293 | BN_free(pk_num); | |
294 | return ret; | |
295 | } | |
926c41bd | 296 | |
a04549cc DSH |
297 | /* ----------------------------------------------------------------------*/ |
298 | static int priv_encode_gost(PKCS8_PRIV_KEY_INFO *p8, const EVP_PKEY *pk) | |
0f113f3e MC |
299 | { |
300 | ASN1_OBJECT *algobj = OBJ_nid2obj(EVP_PKEY_base_id(pk)); | |
301 | ASN1_STRING *params = encode_gost_algor_params(pk); | |
302 | unsigned char *priv_buf = NULL; | |
303 | int priv_len; | |
304 | ||
305 | ASN1_INTEGER *asn1key = NULL; | |
306 | if (!params) { | |
307 | return 0; | |
308 | } | |
309 | asn1key = BN_to_ASN1_INTEGER(gost_get0_priv_key(pk), NULL); | |
310 | priv_len = i2d_ASN1_INTEGER(asn1key, &priv_buf); | |
311 | ASN1_INTEGER_free(asn1key); | |
312 | return PKCS8_pkey_set0(p8, algobj, 0, V_ASN1_SEQUENCE, params, | |
313 | priv_buf, priv_len); | |
314 | } | |
315 | ||
98057eba | 316 | /* --------- printing keys --------------------------------*/ |
98057eba | 317 | static int print_gost_01(BIO *out, const EVP_PKEY *pkey, int indent, |
0f113f3e MC |
318 | ASN1_PCTX *pctx, int type) |
319 | { | |
320 | int param_nid = NID_undef; | |
321 | if (type == 2) { | |
322 | BIGNUM *key; | |
323 | ||
324 | if (!BIO_indent(out, indent, 128)) | |
325 | return 0; | |
326 | BIO_printf(out, "Private key: "); | |
327 | key = gost_get0_priv_key(pkey); | |
328 | if (!key) | |
329 | BIO_printf(out, "<undefined)"); | |
330 | else | |
331 | BN_print(out, key); | |
332 | BIO_printf(out, "\n"); | |
333 | } | |
334 | if (type >= 1) { | |
335 | BN_CTX *ctx = BN_CTX_new(); | |
336 | BIGNUM *X, *Y; | |
337 | const EC_POINT *pubkey; | |
338 | const EC_GROUP *group; | |
339 | ||
340 | if (!ctx) { | |
341 | GOSTerr(GOST_F_PRINT_GOST_01, ERR_R_MALLOC_FAILURE); | |
342 | return 0; | |
343 | } | |
344 | BN_CTX_start(ctx); | |
345 | X = BN_CTX_get(ctx); | |
346 | Y = BN_CTX_get(ctx); | |
347 | pubkey = | |
348 | EC_KEY_get0_public_key((EC_KEY *)EVP_PKEY_get0((EVP_PKEY *)pkey)); | |
349 | group = EC_KEY_get0_group((EC_KEY *)EVP_PKEY_get0((EVP_PKEY *)pkey)); | |
350 | if (!EC_POINT_get_affine_coordinates_GFp(group, pubkey, X, Y, ctx)) { | |
351 | GOSTerr(GOST_F_PRINT_GOST_01, ERR_R_EC_LIB); | |
352 | BN_CTX_free(ctx); | |
353 | return 0; | |
354 | } | |
355 | if (!BIO_indent(out, indent, 128)) | |
356 | return 0; | |
357 | BIO_printf(out, "Public key:\n"); | |
358 | if (!BIO_indent(out, indent + 3, 128)) | |
359 | return 0; | |
360 | BIO_printf(out, "X:"); | |
361 | BN_print(out, X); | |
362 | BIO_printf(out, "\n"); | |
363 | BIO_indent(out, indent + 3, 128); | |
364 | BIO_printf(out, "Y:"); | |
365 | BN_print(out, Y); | |
366 | BIO_printf(out, "\n"); | |
367 | BN_CTX_end(ctx); | |
368 | BN_CTX_free(ctx); | |
369 | } | |
370 | ||
371 | param_nid = | |
372 | EC_GROUP_get_curve_name(EC_KEY_get0_group | |
373 | (EVP_PKEY_get0((EVP_PKEY *)pkey))); | |
374 | if (!BIO_indent(out, indent, 128)) | |
375 | return 0; | |
376 | BIO_printf(out, "Parameter set: %s\n", OBJ_nid2ln(param_nid)); | |
377 | return 1; | |
98057eba | 378 | } |
0f113f3e | 379 | |
98057eba | 380 | static int param_print_gost01(BIO *out, const EVP_PKEY *pkey, int indent, |
0f113f3e MC |
381 | ASN1_PCTX *pctx) |
382 | { | |
383 | return print_gost_01(out, pkey, indent, pctx, 0); | |
384 | } | |
385 | ||
98057eba | 386 | static int pub_print_gost01(BIO *out, const EVP_PKEY *pkey, int indent, |
0f113f3e MC |
387 | ASN1_PCTX *pctx) |
388 | { | |
389 | return print_gost_01(out, pkey, indent, pctx, 1); | |
390 | } | |
391 | ||
392 | static int priv_print_gost01(BIO *out, const EVP_PKEY *pkey, int indent, | |
393 | ASN1_PCTX *pctx) | |
394 | { | |
395 | return print_gost_01(out, pkey, indent, pctx, 2); | |
396 | } | |
397 | ||
a04549cc | 398 | /* ---------------------------------------------------------------------*/ |
0f113f3e MC |
399 | static int param_missing_gost01(const EVP_PKEY *pk) |
400 | { | |
401 | const EC_KEY *ec = EVP_PKEY_get0((EVP_PKEY *)pk); | |
402 | if (!ec) | |
403 | return 1; | |
404 | if (!EC_KEY_get0_group(ec)) | |
405 | return 1; | |
406 | return 0; | |
407 | } | |
408 | ||
0f113f3e MC |
409 | |
410 | static int param_copy_gost01(EVP_PKEY *to, const EVP_PKEY *from) | |
411 | { | |
412 | EC_KEY *eto = EVP_PKEY_get0(to); | |
413 | const EC_KEY *efrom = EVP_PKEY_get0((EVP_PKEY *)from); | |
414 | if (EVP_PKEY_base_id(from) != EVP_PKEY_base_id(to)) { | |
415 | GOSTerr(GOST_F_PARAM_COPY_GOST01, GOST_R_INCOMPATIBLE_ALGORITHMS); | |
416 | return 0; | |
417 | } | |
418 | if (!efrom) { | |
419 | GOSTerr(GOST_F_PARAM_COPY_GOST01, GOST_R_KEY_PARAMETERS_MISSING); | |
420 | return 0; | |
421 | } | |
422 | if (!eto) { | |
423 | eto = EC_KEY_new(); | |
61986d32 | 424 | if (!eto) { |
8817e2e0 MC |
425 | GOSTerr(GOST_F_PARAM_COPY_GOST01, ERR_R_MALLOC_FAILURE); |
426 | return 0; | |
427 | } | |
61986d32 | 428 | if (!EVP_PKEY_assign(to, EVP_PKEY_base_id(from), eto)) { |
8817e2e0 MC |
429 | GOSTerr(GOST_F_PARAM_COPY_GOST01, ERR_R_INTERNAL_ERROR); |
430 | return 0; | |
431 | } | |
432 | } | |
61986d32 | 433 | if (!EC_KEY_set_group(eto, EC_KEY_get0_group(efrom))) { |
8817e2e0 MC |
434 | GOSTerr(GOST_F_PARAM_COPY_GOST01, ERR_R_INTERNAL_ERROR); |
435 | return 0; | |
0f113f3e | 436 | } |
0f113f3e MC |
437 | if (EC_KEY_get0_private_key(eto)) { |
438 | gost2001_compute_public(eto); | |
439 | } | |
440 | return 1; | |
441 | } | |
442 | ||
0f113f3e MC |
443 | static int param_cmp_gost01(const EVP_PKEY *a, const EVP_PKEY *b) |
444 | { | |
445 | if (EC_GROUP_get_curve_name | |
446 | (EC_KEY_get0_group(EVP_PKEY_get0((EVP_PKEY *)a))) == | |
447 | EC_GROUP_get_curve_name(EC_KEY_get0_group | |
448 | (EVP_PKEY_get0((EVP_PKEY *)b)))) { | |
449 | return 1; | |
450 | } | |
451 | return 0; | |
452 | ||
453 | } | |
926c41bd | 454 | |
a04549cc | 455 | /* ---------- Public key functions * --------------------------------------*/ |
926c41bd | 456 | |
0f113f3e MC |
457 | static int pub_decode_gost01(EVP_PKEY *pk, X509_PUBKEY *pub) |
458 | { | |
459 | X509_ALGOR *palg = NULL; | |
460 | const unsigned char *pubkey_buf = NULL; | |
461 | unsigned char *databuf; | |
462 | ASN1_OBJECT *palgobj = NULL; | |
463 | int pub_len, i, j; | |
464 | EC_POINT *pub_key; | |
465 | BIGNUM *X, *Y; | |
466 | ASN1_OCTET_STRING *octet = NULL; | |
467 | int len; | |
468 | const EC_GROUP *group; | |
469 | ||
470 | if (!X509_PUBKEY_get0_param(&palgobj, &pubkey_buf, &pub_len, &palg, pub)) | |
471 | return 0; | |
472 | EVP_PKEY_assign(pk, OBJ_obj2nid(palgobj), NULL); | |
473 | if (!decode_gost_algor_params(pk, palg)) | |
474 | return 0; | |
475 | group = EC_KEY_get0_group(EVP_PKEY_get0(pk)); | |
476 | octet = d2i_ASN1_OCTET_STRING(NULL, &pubkey_buf, pub_len); | |
477 | if (!octet) { | |
478 | GOSTerr(GOST_F_PUB_DECODE_GOST01, ERR_R_MALLOC_FAILURE); | |
479 | return 0; | |
480 | } | |
481 | databuf = OPENSSL_malloc(octet->length); | |
482 | if (databuf == NULL) { | |
483 | GOSTerr(GOST_F_PUB_DECODE_GOST01, ERR_R_MALLOC_FAILURE); | |
484 | ASN1_OCTET_STRING_free(octet); | |
485 | return 0; | |
486 | } | |
487 | for (i = 0, j = octet->length - 1; i < octet->length; i++, j--) { | |
488 | databuf[j] = octet->data[i]; | |
489 | } | |
490 | len = octet->length / 2; | |
491 | ASN1_OCTET_STRING_free(octet); | |
492 | ||
493 | Y = getbnfrombuf(databuf, len); | |
494 | X = getbnfrombuf(databuf + len, len); | |
495 | OPENSSL_free(databuf); | |
496 | pub_key = EC_POINT_new(group); | |
497 | if (!EC_POINT_set_affine_coordinates_GFp(group, pub_key, X, Y, NULL)) { | |
498 | GOSTerr(GOST_F_PUB_DECODE_GOST01, ERR_R_EC_LIB); | |
499 | EC_POINT_free(pub_key); | |
500 | BN_free(X); | |
501 | BN_free(Y); | |
502 | return 0; | |
503 | } | |
504 | BN_free(X); | |
505 | BN_free(Y); | |
506 | if (!EC_KEY_set_public_key(EVP_PKEY_get0(pk), pub_key)) { | |
507 | GOSTerr(GOST_F_PUB_DECODE_GOST01, ERR_R_EC_LIB); | |
508 | EC_POINT_free(pub_key); | |
509 | return 0; | |
510 | } | |
511 | EC_POINT_free(pub_key); | |
512 | return 1; | |
513 | ||
514 | } | |
515 | ||
516 | static int pub_encode_gost01(X509_PUBKEY *pub, const EVP_PKEY *pk) | |
517 | { | |
518 | ASN1_OBJECT *algobj = NULL; | |
519 | ASN1_OCTET_STRING *octet = NULL; | |
520 | void *pval = NULL; | |
521 | unsigned char *buf = NULL, *databuf, *sptr; | |
522 | int i, j, data_len, ret = 0; | |
523 | const EC_POINT *pub_key; | |
524 | BIGNUM *X, *Y, *order; | |
525 | const EC_KEY *ec = EVP_PKEY_get0((EVP_PKEY *)pk); | |
526 | int ptype = V_ASN1_UNDEF; | |
527 | ||
528 | algobj = OBJ_nid2obj(EVP_PKEY_base_id(pk)); | |
529 | if (pk->save_parameters) { | |
530 | ASN1_STRING *params = encode_gost_algor_params(pk); | |
531 | pval = params; | |
532 | ptype = V_ASN1_SEQUENCE; | |
533 | } | |
534 | order = BN_new(); | |
535 | EC_GROUP_get_order(EC_KEY_get0_group(ec), order, NULL); | |
536 | pub_key = EC_KEY_get0_public_key(ec); | |
537 | if (!pub_key) { | |
538 | GOSTerr(GOST_F_PUB_ENCODE_GOST01, GOST_R_PUBLIC_KEY_UNDEFINED); | |
539 | BN_free(order); | |
540 | return 0; | |
541 | } | |
542 | X = BN_new(); | |
543 | Y = BN_new(); | |
61986d32 | 544 | if (!X || !Y) { |
8817e2e0 | 545 | GOSTerr(GOST_F_PUB_ENCODE_GOST01, ERR_R_MALLOC_FAILURE); |
23a1d5e9 RS |
546 | BN_free(X); |
547 | BN_free(Y); | |
8817e2e0 MC |
548 | BN_free(order); |
549 | return 0; | |
550 | } | |
61986d32 | 551 | if (!EC_POINT_get_affine_coordinates_GFp(EC_KEY_get0_group(ec), |
8817e2e0 MC |
552 | pub_key, X, Y, NULL)) { |
553 | GOSTerr(GOST_F_PUB_ENCODE_GOST01, ERR_R_INTERNAL_ERROR); | |
554 | BN_free(X); | |
555 | BN_free(Y); | |
556 | BN_free(order); | |
557 | return 0; | |
558 | } | |
0f113f3e MC |
559 | data_len = 2 * BN_num_bytes(order); |
560 | BN_free(order); | |
561 | databuf = OPENSSL_malloc(data_len); | |
562 | if (databuf == NULL) { | |
563 | GOSTerr(GOST_F_PUB_ENCODE_GOST01, ERR_R_MALLOC_FAILURE); | |
564 | BN_free(X); | |
565 | BN_free(Y); | |
566 | return 0; | |
567 | } | |
568 | memset(databuf, 0, data_len); | |
569 | ||
570 | store_bignum(X, databuf + data_len / 2, data_len / 2); | |
571 | store_bignum(Y, databuf, data_len / 2); | |
572 | ||
573 | BN_free(X); | |
574 | BN_free(Y); | |
575 | octet = ASN1_OCTET_STRING_new(); | |
576 | if (octet == NULL) { | |
577 | GOSTerr(GOST_F_PUB_ENCODE_GOST01, ERR_R_MALLOC_FAILURE); | |
578 | OPENSSL_free(databuf); | |
579 | return 0; | |
580 | } | |
581 | ASN1_STRING_set(octet, NULL, data_len); | |
582 | sptr = ASN1_STRING_data(octet); | |
583 | for (i = 0, j = data_len - 1; i < data_len; i++, j--) { | |
584 | sptr[i] = databuf[j]; | |
585 | } | |
586 | OPENSSL_free(databuf); | |
587 | ret = i2d_ASN1_OCTET_STRING(octet, &buf); | |
588 | ASN1_BIT_STRING_free(octet); | |
589 | if (ret < 0) | |
590 | return 0; | |
591 | return X509_PUBKEY_set0_param(pub, algobj, ptype, pval, buf, ret); | |
592 | } | |
926c41bd | 593 | |
0f113f3e MC |
594 | static int pub_cmp_gost01(const EVP_PKEY *a, const EVP_PKEY *b) |
595 | { | |
596 | const EC_KEY *ea = EVP_PKEY_get0((EVP_PKEY *)a); | |
597 | const EC_KEY *eb = EVP_PKEY_get0((EVP_PKEY *)b); | |
598 | const EC_POINT *ka, *kb; | |
599 | int ret = 0; | |
600 | if (!ea || !eb) | |
601 | return 0; | |
602 | ka = EC_KEY_get0_public_key(ea); | |
603 | kb = EC_KEY_get0_public_key(eb); | |
604 | if (!ka || !kb) | |
605 | return 0; | |
606 | ret = (0 == EC_POINT_cmp(EC_KEY_get0_group(ea), ka, kb, NULL)); | |
607 | return ret; | |
608 | } | |
926c41bd | 609 | |
a04549cc | 610 | static int pkey_size_gost(const EVP_PKEY *pk) |
0f113f3e MC |
611 | { |
612 | return 64; | |
613 | } | |
926c41bd | 614 | |
a04549cc | 615 | static int pkey_bits_gost(const EVP_PKEY *pk) |
0f113f3e MC |
616 | { |
617 | return 256; | |
618 | } | |
619 | ||
620 | /* ---------------------- ASN1 METHOD for GOST MAC -------------------*/ | |
621 | static void mackey_free_gost(EVP_PKEY *pk) | |
622 | { | |
b548a1f1 | 623 | OPENSSL_free(pk->pkey.ptr); |
0f113f3e MC |
624 | } |
625 | ||
a4346646 DSH |
626 | static int mac_ctrl_gost(EVP_PKEY *pkey, int op, long arg1, void *arg2) |
627 | { | |
0f113f3e MC |
628 | switch (op) { |
629 | case ASN1_PKEY_CTRL_DEFAULT_MD_NID: | |
630 | *(int *)arg2 = NID_id_Gost28147_89_MAC; | |
631 | return 2; | |
632 | } | |
633 | return -2; | |
634 | } | |
b6af2c7e | 635 | |
0f113f3e MC |
636 | static int gost2001_param_encode(const EVP_PKEY *pkey, unsigned char **pder) |
637 | { | |
638 | int nid = | |
639 | EC_GROUP_get_curve_name(EC_KEY_get0_group | |
640 | (EVP_PKEY_get0((EVP_PKEY *)pkey))); | |
641 | return i2d_ASN1_OBJECT(OBJ_nid2obj(nid), pder); | |
642 | } | |
b6af2c7e | 643 | |
0f113f3e MC |
644 | static int gost2001_param_decode(EVP_PKEY *pkey, const unsigned char **pder, |
645 | int derlen) | |
646 | { | |
647 | ASN1_OBJECT *obj = NULL; | |
648 | int nid; | |
649 | EC_KEY *ec = EVP_PKEY_get0(pkey); | |
650 | if (d2i_ASN1_OBJECT(&obj, pder, derlen) == NULL) { | |
651 | return 0; | |
652 | } | |
653 | nid = OBJ_obj2nid(obj); | |
654 | ASN1_OBJECT_free(obj); | |
655 | if (!ec) { | |
656 | ec = EC_KEY_new(); | |
657 | if (!EVP_PKEY_assign(pkey, NID_id_GostR3410_2001, ec)) | |
658 | return 0; | |
659 | } | |
660 | if (!fill_GOST2001_params(ec, nid)) | |
661 | return 0; | |
662 | return 1; | |
663 | } | |
b6af2c7e | 664 | |
a04549cc | 665 | /* ----------------------------------------------------------------------*/ |
0f113f3e MC |
666 | int register_ameth_gost(int nid, EVP_PKEY_ASN1_METHOD **ameth, |
667 | const char *pemstr, const char *info) | |
668 | { | |
669 | *ameth = EVP_PKEY_asn1_new(nid, ASN1_PKEY_SIGPARAM_NULL, pemstr, info); | |
670 | if (!*ameth) | |
671 | return 0; | |
672 | switch (nid) { | |
0f113f3e MC |
673 | case NID_id_GostR3410_2001: |
674 | EVP_PKEY_asn1_set_free(*ameth, pkey_free_gost01); | |
675 | EVP_PKEY_asn1_set_private(*ameth, | |
676 | priv_decode_gost, priv_encode_gost, | |
677 | priv_print_gost01); | |
678 | ||
679 | EVP_PKEY_asn1_set_param(*ameth, | |
680 | gost2001_param_decode, gost2001_param_encode, | |
681 | param_missing_gost01, param_copy_gost01, | |
682 | param_cmp_gost01, param_print_gost01); | |
683 | EVP_PKEY_asn1_set_public(*ameth, | |
684 | pub_decode_gost01, pub_encode_gost01, | |
685 | pub_cmp_gost01, pub_print_gost01, | |
686 | pkey_size_gost, pkey_bits_gost); | |
687 | ||
688 | EVP_PKEY_asn1_set_ctrl(*ameth, pkey_ctrl_gost); | |
689 | break; | |
690 | case NID_id_Gost28147_89_MAC: | |
691 | EVP_PKEY_asn1_set_free(*ameth, mackey_free_gost); | |
692 | EVP_PKEY_asn1_set_ctrl(*ameth, mac_ctrl_gost); | |
693 | break; | |
694 | } | |
695 | return 1; | |
696 | } |