]>
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 DSH |
19 | #include "gost_params.h" |
20 | #include "gost_lcl.h" | |
a04549cc DSH |
21 | #include "e_gost_err.h" |
22 | ||
0f113f3e MC |
23 | int gost94_nid_by_params(DSA *p) |
24 | { | |
25 | R3410_params *gost_params; | |
26 | BIGNUM *q = BN_new(); | |
27 | for (gost_params = R3410_paramset; gost_params->q != NULL; gost_params++) { | |
28 | BN_dec2bn(&q, gost_params->q); | |
29 | if (!BN_cmp(q, p->q)) { | |
30 | BN_free(q); | |
31 | return gost_params->nid; | |
32 | } | |
33 | } | |
34 | BN_free(q); | |
35 | return NID_undef; | |
36 | } | |
37 | ||
38 | static ASN1_STRING *encode_gost_algor_params(const EVP_PKEY *key) | |
39 | { | |
40 | ASN1_STRING *params = ASN1_STRING_new(); | |
41 | GOST_KEY_PARAMS *gkp = GOST_KEY_PARAMS_new(); | |
42 | int pkey_param_nid = NID_undef; | |
43 | ||
44 | if (!params || !gkp) { | |
45 | GOSTerr(GOST_F_ENCODE_GOST_ALGOR_PARAMS, ERR_R_MALLOC_FAILURE); | |
46 | ASN1_STRING_free(params); | |
47 | params = NULL; | |
48 | goto err; | |
49 | } | |
50 | switch (EVP_PKEY_base_id(key)) { | |
51 | case NID_id_GostR3410_2001: | |
52 | pkey_param_nid = | |
53 | EC_GROUP_get_curve_name(EC_KEY_get0_group | |
54 | (EVP_PKEY_get0((EVP_PKEY *)key))); | |
55 | break; | |
56 | case NID_id_GostR3410_94: | |
57 | pkey_param_nid = | |
58 | (int)gost94_nid_by_params(EVP_PKEY_get0((EVP_PKEY *)key)); | |
59 | if (pkey_param_nid == NID_undef) { | |
60 | GOSTerr(GOST_F_ENCODE_GOST_ALGOR_PARAMS, | |
61 | GOST_R_INVALID_GOST94_PARMSET); | |
62 | ASN1_STRING_free(params); | |
63 | params = NULL; | |
64 | goto err; | |
65 | } | |
66 | break; | |
67 | } | |
68 | gkp->key_params = OBJ_nid2obj(pkey_param_nid); | |
69 | gkp->hash_params = OBJ_nid2obj(NID_id_GostR3411_94_CryptoProParamSet); | |
70 | /* | |
71 | * gkp->cipher_params = OBJ_nid2obj(cipher_param_nid); | |
72 | */ | |
73 | params->length = i2d_GOST_KEY_PARAMS(gkp, ¶ms->data); | |
74 | if (params->length <= 0) { | |
75 | GOSTerr(GOST_F_ENCODE_GOST_ALGOR_PARAMS, ERR_R_MALLOC_FAILURE); | |
76 | ASN1_STRING_free(params); | |
77 | params = NULL; | |
78 | goto err; | |
79 | } | |
80 | params->type = V_ASN1_SEQUENCE; | |
81 | err: | |
82 | GOST_KEY_PARAMS_free(gkp); | |
83 | return params; | |
84 | } | |
85 | ||
86 | /* | |
87 | * Parses GOST algorithm parameters from X509_ALGOR and modifies pkey setting | |
88 | * NID and parameters | |
a04549cc | 89 | */ |
0f113f3e MC |
90 | static int decode_gost_algor_params(EVP_PKEY *pkey, X509_ALGOR *palg) |
91 | { | |
92 | ASN1_OBJECT *palg_obj = NULL; | |
93 | int ptype = V_ASN1_UNDEF; | |
94 | int pkey_nid = NID_undef, param_nid = NID_undef; | |
95 | void *_pval; | |
96 | ASN1_STRING *pval = NULL; | |
97 | const unsigned char *p; | |
98 | GOST_KEY_PARAMS *gkp = NULL; | |
99 | ||
100 | X509_ALGOR_get0(&palg_obj, &ptype, &_pval, palg); | |
101 | pval = _pval; | |
102 | if (ptype != V_ASN1_SEQUENCE) { | |
103 | GOSTerr(GOST_F_DECODE_GOST_ALGOR_PARAMS, | |
104 | GOST_R_BAD_KEY_PARAMETERS_FORMAT); | |
105 | return 0; | |
106 | } | |
107 | p = pval->data; | |
108 | pkey_nid = OBJ_obj2nid(palg_obj); | |
109 | ||
110 | gkp = d2i_GOST_KEY_PARAMS(NULL, &p, pval->length); | |
111 | if (!gkp) { | |
112 | GOSTerr(GOST_F_DECODE_GOST_ALGOR_PARAMS, | |
113 | GOST_R_BAD_PKEY_PARAMETERS_FORMAT); | |
114 | return 0; | |
115 | } | |
116 | param_nid = OBJ_obj2nid(gkp->key_params); | |
117 | GOST_KEY_PARAMS_free(gkp); | |
61986d32 | 118 | if (!EVP_PKEY_set_type(pkey, pkey_nid)) { |
8817e2e0 MC |
119 | GOSTerr(GOST_F_DECODE_GOST_ALGOR_PARAMS, ERR_R_INTERNAL_ERROR); |
120 | return 0; | |
121 | } | |
0f113f3e MC |
122 | switch (pkey_nid) { |
123 | case NID_id_GostR3410_94: | |
124 | { | |
125 | DSA *dsa = EVP_PKEY_get0(pkey); | |
126 | if (!dsa) { | |
127 | dsa = DSA_new(); | |
128 | if (!EVP_PKEY_assign(pkey, pkey_nid, dsa)) | |
129 | return 0; | |
130 | } | |
131 | if (!fill_GOST94_params(dsa, param_nid)) | |
132 | return 0; | |
133 | break; | |
134 | } | |
135 | case NID_id_GostR3410_2001: | |
136 | { | |
137 | EC_KEY *ec = EVP_PKEY_get0(pkey); | |
138 | if (!ec) { | |
139 | ec = EC_KEY_new(); | |
140 | if (!EVP_PKEY_assign(pkey, pkey_nid, ec)) | |
141 | return 0; | |
142 | } | |
143 | if (!fill_GOST2001_params(ec, param_nid)) | |
144 | return 0; | |
145 | } | |
146 | } | |
147 | ||
148 | return 1; | |
149 | } | |
150 | ||
151 | static int gost_set_priv_key(EVP_PKEY *pkey, BIGNUM *priv) | |
152 | { | |
153 | switch (EVP_PKEY_base_id(pkey)) { | |
154 | case NID_id_GostR3410_94: | |
155 | { | |
156 | DSA *dsa = EVP_PKEY_get0(pkey); | |
157 | if (!dsa) { | |
158 | dsa = DSA_new(); | |
159 | EVP_PKEY_assign(pkey, EVP_PKEY_base_id(pkey), dsa); | |
160 | } | |
161 | dsa->priv_key = BN_dup(priv); | |
162 | if (!EVP_PKEY_missing_parameters(pkey)) | |
163 | gost94_compute_public(dsa); | |
164 | break; | |
165 | } | |
166 | case NID_id_GostR3410_2001: | |
167 | { | |
168 | EC_KEY *ec = EVP_PKEY_get0(pkey); | |
169 | if (!ec) { | |
170 | ec = EC_KEY_new(); | |
171 | EVP_PKEY_assign(pkey, EVP_PKEY_base_id(pkey), ec); | |
172 | } | |
173 | if (!EC_KEY_set_private_key(ec, priv)) | |
174 | return 0; | |
175 | if (!EVP_PKEY_missing_parameters(pkey)) | |
176 | gost2001_compute_public(ec); | |
177 | break; | |
178 | } | |
179 | } | |
180 | return 1; | |
181 | } | |
182 | ||
183 | BIGNUM *gost_get0_priv_key(const EVP_PKEY *pkey) | |
184 | { | |
185 | switch (EVP_PKEY_base_id(pkey)) { | |
186 | case NID_id_GostR3410_94: | |
187 | { | |
188 | DSA *dsa = EVP_PKEY_get0((EVP_PKEY *)pkey); | |
189 | if (!dsa) { | |
190 | return NULL; | |
191 | } | |
192 | if (!dsa->priv_key) | |
193 | return NULL; | |
194 | return dsa->priv_key; | |
0f113f3e MC |
195 | } |
196 | case NID_id_GostR3410_2001: | |
197 | { | |
198 | EC_KEY *ec = EVP_PKEY_get0((EVP_PKEY *)pkey); | |
199 | const BIGNUM *priv; | |
200 | if (!ec) { | |
201 | return NULL; | |
202 | } | |
203 | if (!(priv = EC_KEY_get0_private_key(ec))) | |
204 | return NULL; | |
205 | return (BIGNUM *)priv; | |
0f113f3e MC |
206 | } |
207 | } | |
208 | return NULL; | |
209 | } | |
210 | ||
211 | static int pkey_ctrl_gost(EVP_PKEY *pkey, int op, long arg1, void *arg2) | |
212 | { | |
213 | switch (op) { | |
214 | case ASN1_PKEY_CTRL_PKCS7_SIGN: | |
215 | if (arg1 == 0) { | |
216 | X509_ALGOR *alg1 = NULL, *alg2 = NULL; | |
217 | int nid = EVP_PKEY_base_id(pkey); | |
218 | PKCS7_SIGNER_INFO_get0_algs((PKCS7_SIGNER_INFO *)arg2, | |
219 | NULL, &alg1, &alg2); | |
220 | X509_ALGOR_set0(alg1, OBJ_nid2obj(NID_id_GostR3411_94), | |
221 | V_ASN1_NULL, 0); | |
222 | if (nid == NID_undef) { | |
223 | return (-1); | |
224 | } | |
225 | X509_ALGOR_set0(alg2, OBJ_nid2obj(nid), V_ASN1_NULL, 0); | |
226 | } | |
227 | return 1; | |
174b07be | 228 | #ifndef OPENSSL_NO_CMS |
0f113f3e MC |
229 | case ASN1_PKEY_CTRL_CMS_SIGN: |
230 | if (arg1 == 0) { | |
231 | X509_ALGOR *alg1 = NULL, *alg2 = NULL; | |
232 | int nid = EVP_PKEY_base_id(pkey); | |
233 | CMS_SignerInfo_get0_algs((CMS_SignerInfo *)arg2, | |
234 | NULL, NULL, &alg1, &alg2); | |
235 | X509_ALGOR_set0(alg1, OBJ_nid2obj(NID_id_GostR3411_94), | |
236 | V_ASN1_NULL, 0); | |
237 | if (nid == NID_undef) { | |
238 | return (-1); | |
239 | } | |
240 | X509_ALGOR_set0(alg2, OBJ_nid2obj(nid), V_ASN1_NULL, 0); | |
241 | } | |
242 | return 1; | |
174b07be | 243 | #endif |
0f113f3e MC |
244 | case ASN1_PKEY_CTRL_PKCS7_ENCRYPT: |
245 | if (arg1 == 0) { | |
246 | X509_ALGOR *alg; | |
247 | ASN1_STRING *params = encode_gost_algor_params(pkey); | |
248 | if (!params) { | |
249 | return -1; | |
250 | } | |
251 | PKCS7_RECIP_INFO_get0_alg((PKCS7_RECIP_INFO *)arg2, &alg); | |
252 | X509_ALGOR_set0(alg, OBJ_nid2obj(pkey->type), | |
253 | V_ASN1_SEQUENCE, params); | |
254 | } | |
255 | return 1; | |
174b07be | 256 | #ifndef OPENSSL_NO_CMS |
0f113f3e MC |
257 | case ASN1_PKEY_CTRL_CMS_ENVELOPE: |
258 | if (arg1 == 0) { | |
259 | X509_ALGOR *alg = NULL; | |
260 | ASN1_STRING *params = encode_gost_algor_params(pkey); | |
261 | if (!params) { | |
262 | return -1; | |
263 | } | |
264 | CMS_RecipientInfo_ktri_get0_algs((CMS_RecipientInfo *)arg2, NULL, | |
265 | NULL, &alg); | |
266 | X509_ALGOR_set0(alg, OBJ_nid2obj(pkey->type), V_ASN1_SEQUENCE, | |
267 | params); | |
268 | } | |
269 | return 1; | |
174b07be | 270 | #endif |
0f113f3e MC |
271 | case ASN1_PKEY_CTRL_DEFAULT_MD_NID: |
272 | *(int *)arg2 = NID_id_GostR3411_94; | |
273 | return 2; | |
274 | } | |
275 | ||
276 | return -2; | |
277 | } | |
278 | ||
279 | /* --------------------- free functions * ------------------------------*/ | |
280 | static void pkey_free_gost94(EVP_PKEY *key) | |
281 | { | |
d6407083 | 282 | DSA_free(key->pkey.dsa); |
0f113f3e MC |
283 | } |
284 | ||
285 | static void pkey_free_gost01(EVP_PKEY *key) | |
286 | { | |
8fdc3734 | 287 | EC_KEY_free(key->pkey.ec); |
0f113f3e | 288 | } |
926c41bd | 289 | |
a04549cc | 290 | /* ------------------ private key functions -----------------------------*/ |
0f113f3e MC |
291 | static int priv_decode_gost(EVP_PKEY *pk, PKCS8_PRIV_KEY_INFO *p8inf) |
292 | { | |
293 | const unsigned char *pkey_buf = NULL, *p = NULL; | |
294 | int priv_len = 0; | |
295 | BIGNUM *pk_num = NULL; | |
296 | int ret = 0; | |
297 | X509_ALGOR *palg = NULL; | |
298 | ASN1_OBJECT *palg_obj = NULL; | |
299 | ASN1_INTEGER *priv_key = NULL; | |
300 | ||
301 | if (!PKCS8_pkey_get0(&palg_obj, &pkey_buf, &priv_len, &palg, p8inf)) | |
302 | return 0; | |
303 | p = pkey_buf; | |
304 | if (!decode_gost_algor_params(pk, palg)) { | |
305 | return 0; | |
306 | } | |
307 | if (V_ASN1_OCTET_STRING == *p) { | |
308 | /* New format - Little endian octet string */ | |
309 | unsigned char rev_buf[32]; | |
310 | int i; | |
311 | ASN1_OCTET_STRING *s = d2i_ASN1_OCTET_STRING(NULL, &p, priv_len); | |
312 | if (!s || s->length != 32) { | |
313 | GOSTerr(GOST_F_PRIV_DECODE_GOST, EVP_R_DECODE_ERROR); | |
314 | return 0; | |
315 | } | |
316 | for (i = 0; i < 32; i++) { | |
317 | rev_buf[31 - i] = s->data[i]; | |
318 | } | |
319 | ASN1_STRING_free(s); | |
320 | pk_num = getbnfrombuf(rev_buf, 32); | |
321 | } else { | |
322 | priv_key = d2i_ASN1_INTEGER(NULL, &p, priv_len); | |
323 | if (!priv_key) | |
324 | return 0; | |
325 | ret = ((pk_num = ASN1_INTEGER_to_BN(priv_key, NULL)) != NULL); | |
326 | ASN1_INTEGER_free(priv_key); | |
327 | if (!ret) { | |
328 | GOSTerr(GOST_F_PRIV_DECODE_GOST, EVP_R_DECODE_ERROR); | |
329 | return 0; | |
330 | } | |
331 | } | |
332 | ||
333 | ret = gost_set_priv_key(pk, pk_num); | |
334 | BN_free(pk_num); | |
335 | return ret; | |
336 | } | |
926c41bd | 337 | |
a04549cc DSH |
338 | /* ----------------------------------------------------------------------*/ |
339 | static int priv_encode_gost(PKCS8_PRIV_KEY_INFO *p8, const EVP_PKEY *pk) | |
0f113f3e MC |
340 | { |
341 | ASN1_OBJECT *algobj = OBJ_nid2obj(EVP_PKEY_base_id(pk)); | |
342 | ASN1_STRING *params = encode_gost_algor_params(pk); | |
343 | unsigned char *priv_buf = NULL; | |
344 | int priv_len; | |
345 | ||
346 | ASN1_INTEGER *asn1key = NULL; | |
347 | if (!params) { | |
348 | return 0; | |
349 | } | |
350 | asn1key = BN_to_ASN1_INTEGER(gost_get0_priv_key(pk), NULL); | |
351 | priv_len = i2d_ASN1_INTEGER(asn1key, &priv_buf); | |
352 | ASN1_INTEGER_free(asn1key); | |
353 | return PKCS8_pkey_set0(p8, algobj, 0, V_ASN1_SEQUENCE, params, | |
354 | priv_buf, priv_len); | |
355 | } | |
356 | ||
98057eba DSH |
357 | /* --------- printing keys --------------------------------*/ |
358 | static int print_gost_94(BIO *out, const EVP_PKEY *pkey, int indent, | |
0f113f3e MC |
359 | ASN1_PCTX *pctx, int type) |
360 | { | |
361 | int param_nid = NID_undef; | |
362 | ||
363 | if (type == 2) { | |
364 | BIGNUM *key; | |
365 | ||
366 | if (!BIO_indent(out, indent, 128)) | |
367 | return 0; | |
368 | BIO_printf(out, "Private key: "); | |
369 | key = gost_get0_priv_key(pkey); | |
370 | if (!key) | |
371 | BIO_printf(out, "<undefined>"); | |
372 | else | |
373 | BN_print(out, key); | |
374 | BIO_printf(out, "\n"); | |
375 | } | |
376 | if (type >= 1) { | |
377 | BIGNUM *pubkey; | |
378 | ||
379 | pubkey = ((DSA *)EVP_PKEY_get0((EVP_PKEY *)pkey))->pub_key; | |
380 | BIO_indent(out, indent, 128); | |
381 | BIO_printf(out, "Public key: "); | |
382 | BN_print(out, pubkey); | |
383 | BIO_printf(out, "\n"); | |
384 | } | |
385 | ||
386 | param_nid = gost94_nid_by_params(EVP_PKEY_get0((EVP_PKEY *)pkey)); | |
387 | BIO_indent(out, indent, 128); | |
388 | BIO_printf(out, "Parameter set: %s\n", OBJ_nid2ln(param_nid)); | |
389 | return 1; | |
98057eba DSH |
390 | } |
391 | ||
392 | static int param_print_gost94(BIO *out, const EVP_PKEY *pkey, int indent, | |
0f113f3e MC |
393 | ASN1_PCTX *pctx) |
394 | { | |
395 | return print_gost_94(out, pkey, indent, pctx, 0); | |
396 | } | |
a04549cc | 397 | |
98057eba | 398 | static int pub_print_gost94(BIO *out, const EVP_PKEY *pkey, int indent, |
0f113f3e MC |
399 | ASN1_PCTX *pctx) |
400 | { | |
401 | return print_gost_94(out, pkey, indent, pctx, 1); | |
402 | } | |
403 | ||
404 | static int priv_print_gost94(BIO *out, const EVP_PKEY *pkey, int indent, | |
405 | ASN1_PCTX *pctx) | |
406 | { | |
407 | return print_gost_94(out, pkey, indent, pctx, 2); | |
408 | } | |
98057eba DSH |
409 | |
410 | static int print_gost_01(BIO *out, const EVP_PKEY *pkey, int indent, | |
0f113f3e MC |
411 | ASN1_PCTX *pctx, int type) |
412 | { | |
413 | int param_nid = NID_undef; | |
414 | if (type == 2) { | |
415 | BIGNUM *key; | |
416 | ||
417 | if (!BIO_indent(out, indent, 128)) | |
418 | return 0; | |
419 | BIO_printf(out, "Private key: "); | |
420 | key = gost_get0_priv_key(pkey); | |
421 | if (!key) | |
422 | BIO_printf(out, "<undefined)"); | |
423 | else | |
424 | BN_print(out, key); | |
425 | BIO_printf(out, "\n"); | |
426 | } | |
427 | if (type >= 1) { | |
428 | BN_CTX *ctx = BN_CTX_new(); | |
429 | BIGNUM *X, *Y; | |
430 | const EC_POINT *pubkey; | |
431 | const EC_GROUP *group; | |
432 | ||
433 | if (!ctx) { | |
434 | GOSTerr(GOST_F_PRINT_GOST_01, ERR_R_MALLOC_FAILURE); | |
435 | return 0; | |
436 | } | |
437 | BN_CTX_start(ctx); | |
438 | X = BN_CTX_get(ctx); | |
439 | Y = BN_CTX_get(ctx); | |
440 | pubkey = | |
441 | EC_KEY_get0_public_key((EC_KEY *)EVP_PKEY_get0((EVP_PKEY *)pkey)); | |
442 | group = EC_KEY_get0_group((EC_KEY *)EVP_PKEY_get0((EVP_PKEY *)pkey)); | |
443 | if (!EC_POINT_get_affine_coordinates_GFp(group, pubkey, X, Y, ctx)) { | |
444 | GOSTerr(GOST_F_PRINT_GOST_01, ERR_R_EC_LIB); | |
445 | BN_CTX_free(ctx); | |
446 | return 0; | |
447 | } | |
448 | if (!BIO_indent(out, indent, 128)) | |
449 | return 0; | |
450 | BIO_printf(out, "Public key:\n"); | |
451 | if (!BIO_indent(out, indent + 3, 128)) | |
452 | return 0; | |
453 | BIO_printf(out, "X:"); | |
454 | BN_print(out, X); | |
455 | BIO_printf(out, "\n"); | |
456 | BIO_indent(out, indent + 3, 128); | |
457 | BIO_printf(out, "Y:"); | |
458 | BN_print(out, Y); | |
459 | BIO_printf(out, "\n"); | |
460 | BN_CTX_end(ctx); | |
461 | BN_CTX_free(ctx); | |
462 | } | |
463 | ||
464 | param_nid = | |
465 | EC_GROUP_get_curve_name(EC_KEY_get0_group | |
466 | (EVP_PKEY_get0((EVP_PKEY *)pkey))); | |
467 | if (!BIO_indent(out, indent, 128)) | |
468 | return 0; | |
469 | BIO_printf(out, "Parameter set: %s\n", OBJ_nid2ln(param_nid)); | |
470 | return 1; | |
98057eba | 471 | } |
0f113f3e | 472 | |
98057eba | 473 | static int param_print_gost01(BIO *out, const EVP_PKEY *pkey, int indent, |
0f113f3e MC |
474 | ASN1_PCTX *pctx) |
475 | { | |
476 | return print_gost_01(out, pkey, indent, pctx, 0); | |
477 | } | |
478 | ||
98057eba | 479 | static int pub_print_gost01(BIO *out, const EVP_PKEY *pkey, int indent, |
0f113f3e MC |
480 | ASN1_PCTX *pctx) |
481 | { | |
482 | return print_gost_01(out, pkey, indent, pctx, 1); | |
483 | } | |
484 | ||
485 | static int priv_print_gost01(BIO *out, const EVP_PKEY *pkey, int indent, | |
486 | ASN1_PCTX *pctx) | |
487 | { | |
488 | return print_gost_01(out, pkey, indent, pctx, 2); | |
489 | } | |
490 | ||
a04549cc | 491 | /* ---------------------------------------------------------------------*/ |
0f113f3e MC |
492 | static int param_missing_gost94(const EVP_PKEY *pk) |
493 | { | |
494 | const DSA *dsa = EVP_PKEY_get0((EVP_PKEY *)pk); | |
495 | if (!dsa) | |
496 | return 1; | |
497 | if (!dsa->q) | |
498 | return 1; | |
499 | return 0; | |
500 | } | |
501 | ||
502 | static int param_missing_gost01(const EVP_PKEY *pk) | |
503 | { | |
504 | const EC_KEY *ec = EVP_PKEY_get0((EVP_PKEY *)pk); | |
505 | if (!ec) | |
506 | return 1; | |
507 | if (!EC_KEY_get0_group(ec)) | |
508 | return 1; | |
509 | return 0; | |
510 | } | |
511 | ||
512 | static int param_copy_gost94(EVP_PKEY *to, const EVP_PKEY *from) | |
513 | { | |
514 | const DSA *dfrom = EVP_PKEY_get0((EVP_PKEY *)from); | |
515 | DSA *dto = EVP_PKEY_get0(to); | |
516 | if (EVP_PKEY_base_id(from) != EVP_PKEY_base_id(to)) { | |
517 | GOSTerr(GOST_F_PARAM_COPY_GOST94, GOST_R_INCOMPATIBLE_ALGORITHMS); | |
518 | return 0; | |
519 | } | |
520 | if (!dfrom) { | |
521 | GOSTerr(GOST_F_PARAM_COPY_GOST94, GOST_R_KEY_PARAMETERS_MISSING); | |
522 | return 0; | |
523 | } | |
524 | if (!dto) { | |
525 | dto = DSA_new(); | |
526 | EVP_PKEY_assign(to, EVP_PKEY_base_id(from), dto); | |
527 | } | |
23a1d5e9 RS |
528 | BN_free(dto->p); |
529 | dto->p = BN_dup(dfrom->p); | |
530 | BN_free(dto->q); | |
531 | dto->q = BN_dup(dfrom->q); | |
532 | BN_free(dto->g); | |
533 | dto->g = BN_dup(dfrom->g); | |
534 | ||
535 | if (dto->priv_key) | |
0f113f3e MC |
536 | gost94_compute_public(dto); |
537 | return 1; | |
538 | } | |
539 | ||
540 | static int param_copy_gost01(EVP_PKEY *to, const EVP_PKEY *from) | |
541 | { | |
542 | EC_KEY *eto = EVP_PKEY_get0(to); | |
543 | const EC_KEY *efrom = EVP_PKEY_get0((EVP_PKEY *)from); | |
544 | if (EVP_PKEY_base_id(from) != EVP_PKEY_base_id(to)) { | |
545 | GOSTerr(GOST_F_PARAM_COPY_GOST01, GOST_R_INCOMPATIBLE_ALGORITHMS); | |
546 | return 0; | |
547 | } | |
548 | if (!efrom) { | |
549 | GOSTerr(GOST_F_PARAM_COPY_GOST01, GOST_R_KEY_PARAMETERS_MISSING); | |
550 | return 0; | |
551 | } | |
552 | if (!eto) { | |
553 | eto = EC_KEY_new(); | |
61986d32 | 554 | if (!eto) { |
8817e2e0 MC |
555 | GOSTerr(GOST_F_PARAM_COPY_GOST01, ERR_R_MALLOC_FAILURE); |
556 | return 0; | |
557 | } | |
61986d32 | 558 | if (!EVP_PKEY_assign(to, EVP_PKEY_base_id(from), eto)) { |
8817e2e0 MC |
559 | GOSTerr(GOST_F_PARAM_COPY_GOST01, ERR_R_INTERNAL_ERROR); |
560 | return 0; | |
561 | } | |
562 | } | |
61986d32 | 563 | if (!EC_KEY_set_group(eto, EC_KEY_get0_group(efrom))) { |
8817e2e0 MC |
564 | GOSTerr(GOST_F_PARAM_COPY_GOST01, ERR_R_INTERNAL_ERROR); |
565 | return 0; | |
0f113f3e | 566 | } |
0f113f3e MC |
567 | if (EC_KEY_get0_private_key(eto)) { |
568 | gost2001_compute_public(eto); | |
569 | } | |
570 | return 1; | |
571 | } | |
572 | ||
573 | static int param_cmp_gost94(const EVP_PKEY *a, const EVP_PKEY *b) | |
574 | { | |
575 | const DSA *da = EVP_PKEY_get0((EVP_PKEY *)a); | |
576 | const DSA *db = EVP_PKEY_get0((EVP_PKEY *)b); | |
577 | if (!BN_cmp(da->q, db->q)) | |
578 | return 1; | |
579 | return 0; | |
580 | } | |
581 | ||
582 | static int param_cmp_gost01(const EVP_PKEY *a, const EVP_PKEY *b) | |
583 | { | |
584 | if (EC_GROUP_get_curve_name | |
585 | (EC_KEY_get0_group(EVP_PKEY_get0((EVP_PKEY *)a))) == | |
586 | EC_GROUP_get_curve_name(EC_KEY_get0_group | |
587 | (EVP_PKEY_get0((EVP_PKEY *)b)))) { | |
588 | return 1; | |
589 | } | |
590 | return 0; | |
591 | ||
592 | } | |
926c41bd | 593 | |
a04549cc DSH |
594 | /* ---------- Public key functions * --------------------------------------*/ |
595 | static int pub_decode_gost94(EVP_PKEY *pk, X509_PUBKEY *pub) | |
0f113f3e MC |
596 | { |
597 | X509_ALGOR *palg = NULL; | |
598 | const unsigned char *pubkey_buf = NULL; | |
599 | unsigned char *databuf; | |
600 | ASN1_OBJECT *palgobj = NULL; | |
601 | int pub_len, i, j; | |
602 | DSA *dsa; | |
603 | ASN1_OCTET_STRING *octet = NULL; | |
604 | ||
605 | if (!X509_PUBKEY_get0_param(&palgobj, &pubkey_buf, &pub_len, &palg, pub)) | |
606 | return 0; | |
607 | EVP_PKEY_assign(pk, OBJ_obj2nid(palgobj), NULL); | |
608 | if (!decode_gost_algor_params(pk, palg)) | |
609 | return 0; | |
610 | octet = d2i_ASN1_OCTET_STRING(NULL, &pubkey_buf, pub_len); | |
611 | if (!octet) { | |
612 | GOSTerr(GOST_F_PUB_DECODE_GOST94, ERR_R_MALLOC_FAILURE); | |
613 | return 0; | |
614 | } | |
615 | databuf = OPENSSL_malloc(octet->length); | |
616 | if (databuf == NULL) { | |
617 | GOSTerr(GOST_F_PUB_DECODE_GOST94, ERR_R_MALLOC_FAILURE); | |
618 | ASN1_OCTET_STRING_free(octet); | |
619 | return 0; | |
620 | } | |
621 | for (i = 0, j = octet->length - 1; i < octet->length; i++, j--) { | |
622 | databuf[j] = octet->data[i]; | |
623 | } | |
624 | dsa = EVP_PKEY_get0(pk); | |
625 | dsa->pub_key = BN_bin2bn(databuf, octet->length, NULL); | |
626 | ASN1_OCTET_STRING_free(octet); | |
a04549cc | 627 | OPENSSL_free(databuf); |
0f113f3e | 628 | return 1; |
926c41bd | 629 | |
0f113f3e MC |
630 | } |
631 | ||
632 | static int pub_encode_gost94(X509_PUBKEY *pub, const EVP_PKEY *pk) | |
633 | { | |
634 | ASN1_OBJECT *algobj = NULL; | |
635 | ASN1_OCTET_STRING *octet = NULL; | |
636 | void *pval = NULL; | |
637 | unsigned char *buf = NULL, *databuf, *sptr; | |
638 | int i, j, data_len, ret = 0; | |
639 | ||
640 | int ptype = V_ASN1_UNDEF; | |
641 | DSA *dsa = EVP_PKEY_get0((EVP_PKEY *)pk); | |
642 | algobj = OBJ_nid2obj(EVP_PKEY_base_id(pk)); | |
643 | if (pk->save_parameters) { | |
644 | ASN1_STRING *params = encode_gost_algor_params(pk); | |
645 | pval = params; | |
646 | ptype = V_ASN1_SEQUENCE; | |
647 | } | |
648 | data_len = BN_num_bytes(dsa->pub_key); | |
649 | databuf = OPENSSL_malloc(data_len); | |
650 | if (databuf == NULL) { | |
651 | GOSTerr(GOST_F_PUB_ENCODE_GOST94, ERR_R_MALLOC_FAILURE); | |
652 | return 0; | |
653 | } | |
654 | BN_bn2bin(dsa->pub_key, databuf); | |
655 | octet = ASN1_OCTET_STRING_new(); | |
656 | if (octet == NULL) { | |
657 | GOSTerr(GOST_F_PUB_ENCODE_GOST94, ERR_R_MALLOC_FAILURE); | |
658 | OPENSSL_free(databuf); | |
659 | return 0; | |
660 | } | |
661 | ASN1_STRING_set(octet, NULL, data_len); | |
662 | sptr = ASN1_STRING_data(octet); | |
663 | for (i = 0, j = data_len - 1; i < data_len; i++, j--) { | |
664 | sptr[i] = databuf[j]; | |
665 | } | |
666 | OPENSSL_free(databuf); | |
667 | ret = i2d_ASN1_OCTET_STRING(octet, &buf); | |
668 | ASN1_BIT_STRING_free(octet); | |
669 | if (ret < 0) | |
670 | return 0; | |
671 | return X509_PUBKEY_set0_param(pub, algobj, ptype, pval, buf, ret); | |
672 | } | |
926c41bd | 673 | |
0f113f3e MC |
674 | static int pub_decode_gost01(EVP_PKEY *pk, X509_PUBKEY *pub) |
675 | { | |
676 | X509_ALGOR *palg = NULL; | |
677 | const unsigned char *pubkey_buf = NULL; | |
678 | unsigned char *databuf; | |
679 | ASN1_OBJECT *palgobj = NULL; | |
680 | int pub_len, i, j; | |
681 | EC_POINT *pub_key; | |
682 | BIGNUM *X, *Y; | |
683 | ASN1_OCTET_STRING *octet = NULL; | |
684 | int len; | |
685 | const EC_GROUP *group; | |
686 | ||
687 | if (!X509_PUBKEY_get0_param(&palgobj, &pubkey_buf, &pub_len, &palg, pub)) | |
688 | return 0; | |
689 | EVP_PKEY_assign(pk, OBJ_obj2nid(palgobj), NULL); | |
690 | if (!decode_gost_algor_params(pk, palg)) | |
691 | return 0; | |
692 | group = EC_KEY_get0_group(EVP_PKEY_get0(pk)); | |
693 | octet = d2i_ASN1_OCTET_STRING(NULL, &pubkey_buf, pub_len); | |
694 | if (!octet) { | |
695 | GOSTerr(GOST_F_PUB_DECODE_GOST01, ERR_R_MALLOC_FAILURE); | |
696 | return 0; | |
697 | } | |
698 | databuf = OPENSSL_malloc(octet->length); | |
699 | if (databuf == NULL) { | |
700 | GOSTerr(GOST_F_PUB_DECODE_GOST01, ERR_R_MALLOC_FAILURE); | |
701 | ASN1_OCTET_STRING_free(octet); | |
702 | return 0; | |
703 | } | |
704 | for (i = 0, j = octet->length - 1; i < octet->length; i++, j--) { | |
705 | databuf[j] = octet->data[i]; | |
706 | } | |
707 | len = octet->length / 2; | |
708 | ASN1_OCTET_STRING_free(octet); | |
709 | ||
710 | Y = getbnfrombuf(databuf, len); | |
711 | X = getbnfrombuf(databuf + len, len); | |
712 | OPENSSL_free(databuf); | |
713 | pub_key = EC_POINT_new(group); | |
714 | if (!EC_POINT_set_affine_coordinates_GFp(group, pub_key, X, Y, NULL)) { | |
715 | GOSTerr(GOST_F_PUB_DECODE_GOST01, ERR_R_EC_LIB); | |
716 | EC_POINT_free(pub_key); | |
717 | BN_free(X); | |
718 | BN_free(Y); | |
719 | return 0; | |
720 | } | |
721 | BN_free(X); | |
722 | BN_free(Y); | |
723 | if (!EC_KEY_set_public_key(EVP_PKEY_get0(pk), pub_key)) { | |
724 | GOSTerr(GOST_F_PUB_DECODE_GOST01, ERR_R_EC_LIB); | |
725 | EC_POINT_free(pub_key); | |
726 | return 0; | |
727 | } | |
728 | EC_POINT_free(pub_key); | |
729 | return 1; | |
730 | ||
731 | } | |
732 | ||
733 | static int pub_encode_gost01(X509_PUBKEY *pub, const EVP_PKEY *pk) | |
734 | { | |
735 | ASN1_OBJECT *algobj = NULL; | |
736 | ASN1_OCTET_STRING *octet = NULL; | |
737 | void *pval = NULL; | |
738 | unsigned char *buf = NULL, *databuf, *sptr; | |
739 | int i, j, data_len, ret = 0; | |
740 | const EC_POINT *pub_key; | |
741 | BIGNUM *X, *Y, *order; | |
742 | const EC_KEY *ec = EVP_PKEY_get0((EVP_PKEY *)pk); | |
743 | int ptype = V_ASN1_UNDEF; | |
744 | ||
745 | algobj = OBJ_nid2obj(EVP_PKEY_base_id(pk)); | |
746 | if (pk->save_parameters) { | |
747 | ASN1_STRING *params = encode_gost_algor_params(pk); | |
748 | pval = params; | |
749 | ptype = V_ASN1_SEQUENCE; | |
750 | } | |
751 | order = BN_new(); | |
752 | EC_GROUP_get_order(EC_KEY_get0_group(ec), order, NULL); | |
753 | pub_key = EC_KEY_get0_public_key(ec); | |
754 | if (!pub_key) { | |
755 | GOSTerr(GOST_F_PUB_ENCODE_GOST01, GOST_R_PUBLIC_KEY_UNDEFINED); | |
756 | BN_free(order); | |
757 | return 0; | |
758 | } | |
759 | X = BN_new(); | |
760 | Y = BN_new(); | |
61986d32 | 761 | if (!X || !Y) { |
8817e2e0 | 762 | GOSTerr(GOST_F_PUB_ENCODE_GOST01, ERR_R_MALLOC_FAILURE); |
23a1d5e9 RS |
763 | BN_free(X); |
764 | BN_free(Y); | |
8817e2e0 MC |
765 | BN_free(order); |
766 | return 0; | |
767 | } | |
61986d32 | 768 | if (!EC_POINT_get_affine_coordinates_GFp(EC_KEY_get0_group(ec), |
8817e2e0 MC |
769 | pub_key, X, Y, NULL)) { |
770 | GOSTerr(GOST_F_PUB_ENCODE_GOST01, ERR_R_INTERNAL_ERROR); | |
771 | BN_free(X); | |
772 | BN_free(Y); | |
773 | BN_free(order); | |
774 | return 0; | |
775 | } | |
0f113f3e MC |
776 | data_len = 2 * BN_num_bytes(order); |
777 | BN_free(order); | |
778 | databuf = OPENSSL_malloc(data_len); | |
779 | if (databuf == NULL) { | |
780 | GOSTerr(GOST_F_PUB_ENCODE_GOST01, ERR_R_MALLOC_FAILURE); | |
781 | BN_free(X); | |
782 | BN_free(Y); | |
783 | return 0; | |
784 | } | |
785 | memset(databuf, 0, data_len); | |
786 | ||
787 | store_bignum(X, databuf + data_len / 2, data_len / 2); | |
788 | store_bignum(Y, databuf, data_len / 2); | |
789 | ||
790 | BN_free(X); | |
791 | BN_free(Y); | |
792 | octet = ASN1_OCTET_STRING_new(); | |
793 | if (octet == NULL) { | |
794 | GOSTerr(GOST_F_PUB_ENCODE_GOST01, ERR_R_MALLOC_FAILURE); | |
795 | OPENSSL_free(databuf); | |
796 | return 0; | |
797 | } | |
798 | ASN1_STRING_set(octet, NULL, data_len); | |
799 | sptr = ASN1_STRING_data(octet); | |
800 | for (i = 0, j = data_len - 1; i < data_len; i++, j--) { | |
801 | sptr[i] = databuf[j]; | |
802 | } | |
803 | OPENSSL_free(databuf); | |
804 | ret = i2d_ASN1_OCTET_STRING(octet, &buf); | |
805 | ASN1_BIT_STRING_free(octet); | |
806 | if (ret < 0) | |
807 | return 0; | |
808 | return X509_PUBKEY_set0_param(pub, algobj, ptype, pval, buf, ret); | |
809 | } | |
926c41bd | 810 | |
0f113f3e MC |
811 | static int pub_cmp_gost94(const EVP_PKEY *a, const EVP_PKEY *b) |
812 | { | |
813 | const DSA *da = EVP_PKEY_get0((EVP_PKEY *)a); | |
814 | const DSA *db = EVP_PKEY_get0((EVP_PKEY *)b); | |
815 | if (da && db && da->pub_key && db->pub_key | |
816 | && !BN_cmp(da->pub_key, db->pub_key)) { | |
817 | return 1; | |
818 | } | |
819 | return 0; | |
820 | } | |
98057eba | 821 | |
0f113f3e MC |
822 | static int pub_cmp_gost01(const EVP_PKEY *a, const EVP_PKEY *b) |
823 | { | |
824 | const EC_KEY *ea = EVP_PKEY_get0((EVP_PKEY *)a); | |
825 | const EC_KEY *eb = EVP_PKEY_get0((EVP_PKEY *)b); | |
826 | const EC_POINT *ka, *kb; | |
827 | int ret = 0; | |
828 | if (!ea || !eb) | |
829 | return 0; | |
830 | ka = EC_KEY_get0_public_key(ea); | |
831 | kb = EC_KEY_get0_public_key(eb); | |
832 | if (!ka || !kb) | |
833 | return 0; | |
834 | ret = (0 == EC_POINT_cmp(EC_KEY_get0_group(ea), ka, kb, NULL)); | |
835 | return ret; | |
836 | } | |
926c41bd | 837 | |
a04549cc | 838 | static int pkey_size_gost(const EVP_PKEY *pk) |
0f113f3e MC |
839 | { |
840 | return 64; | |
841 | } | |
926c41bd | 842 | |
a04549cc | 843 | static int pkey_bits_gost(const EVP_PKEY *pk) |
0f113f3e MC |
844 | { |
845 | return 256; | |
846 | } | |
847 | ||
848 | /* ---------------------- ASN1 METHOD for GOST MAC -------------------*/ | |
849 | static void mackey_free_gost(EVP_PKEY *pk) | |
850 | { | |
b548a1f1 | 851 | OPENSSL_free(pk->pkey.ptr); |
0f113f3e MC |
852 | } |
853 | ||
a4346646 DSH |
854 | static int mac_ctrl_gost(EVP_PKEY *pkey, int op, long arg1, void *arg2) |
855 | { | |
0f113f3e MC |
856 | switch (op) { |
857 | case ASN1_PKEY_CTRL_DEFAULT_MD_NID: | |
858 | *(int *)arg2 = NID_id_Gost28147_89_MAC; | |
859 | return 2; | |
860 | } | |
861 | return -2; | |
862 | } | |
b6af2c7e | 863 | |
0f113f3e MC |
864 | static int gost94_param_encode(const EVP_PKEY *pkey, unsigned char **pder) |
865 | { | |
866 | int nid = gost94_nid_by_params(EVP_PKEY_get0((EVP_PKEY *)pkey)); | |
867 | return i2d_ASN1_OBJECT(OBJ_nid2obj(nid), pder); | |
868 | } | |
b6af2c7e | 869 | |
0f113f3e MC |
870 | static int gost2001_param_encode(const EVP_PKEY *pkey, unsigned char **pder) |
871 | { | |
872 | int nid = | |
873 | EC_GROUP_get_curve_name(EC_KEY_get0_group | |
874 | (EVP_PKEY_get0((EVP_PKEY *)pkey))); | |
875 | return i2d_ASN1_OBJECT(OBJ_nid2obj(nid), pder); | |
876 | } | |
b6af2c7e | 877 | |
0f113f3e MC |
878 | static int gost94_param_decode(EVP_PKEY *pkey, const unsigned char **pder, |
879 | int derlen) | |
880 | { | |
881 | ASN1_OBJECT *obj = NULL; | |
882 | DSA *dsa = EVP_PKEY_get0(pkey); | |
883 | int nid; | |
884 | if (d2i_ASN1_OBJECT(&obj, pder, derlen) == NULL) { | |
885 | return 0; | |
886 | } | |
887 | nid = OBJ_obj2nid(obj); | |
888 | ASN1_OBJECT_free(obj); | |
889 | if (!dsa) { | |
890 | dsa = DSA_new(); | |
891 | if (!EVP_PKEY_assign(pkey, NID_id_GostR3410_94, dsa)) | |
892 | return 0; | |
893 | } | |
894 | if (!fill_GOST94_params(dsa, nid)) | |
895 | return 0; | |
896 | return 1; | |
897 | } | |
b6af2c7e | 898 | |
0f113f3e MC |
899 | static int gost2001_param_decode(EVP_PKEY *pkey, const unsigned char **pder, |
900 | int derlen) | |
901 | { | |
902 | ASN1_OBJECT *obj = NULL; | |
903 | int nid; | |
904 | EC_KEY *ec = EVP_PKEY_get0(pkey); | |
905 | if (d2i_ASN1_OBJECT(&obj, pder, derlen) == NULL) { | |
906 | return 0; | |
907 | } | |
908 | nid = OBJ_obj2nid(obj); | |
909 | ASN1_OBJECT_free(obj); | |
910 | if (!ec) { | |
911 | ec = EC_KEY_new(); | |
912 | if (!EVP_PKEY_assign(pkey, NID_id_GostR3410_2001, ec)) | |
913 | return 0; | |
914 | } | |
915 | if (!fill_GOST2001_params(ec, nid)) | |
916 | return 0; | |
917 | return 1; | |
918 | } | |
b6af2c7e | 919 | |
a04549cc | 920 | /* ----------------------------------------------------------------------*/ |
0f113f3e MC |
921 | int register_ameth_gost(int nid, EVP_PKEY_ASN1_METHOD **ameth, |
922 | const char *pemstr, const char *info) | |
923 | { | |
924 | *ameth = EVP_PKEY_asn1_new(nid, ASN1_PKEY_SIGPARAM_NULL, pemstr, info); | |
925 | if (!*ameth) | |
926 | return 0; | |
927 | switch (nid) { | |
928 | case NID_id_GostR3410_94: | |
929 | EVP_PKEY_asn1_set_free(*ameth, pkey_free_gost94); | |
930 | EVP_PKEY_asn1_set_private(*ameth, | |
931 | priv_decode_gost, priv_encode_gost, | |
932 | priv_print_gost94); | |
933 | ||
934 | EVP_PKEY_asn1_set_param(*ameth, | |
935 | gost94_param_decode, gost94_param_encode, | |
936 | param_missing_gost94, param_copy_gost94, | |
937 | param_cmp_gost94, param_print_gost94); | |
938 | EVP_PKEY_asn1_set_public(*ameth, | |
939 | pub_decode_gost94, pub_encode_gost94, | |
940 | pub_cmp_gost94, pub_print_gost94, | |
941 | pkey_size_gost, pkey_bits_gost); | |
942 | ||
943 | EVP_PKEY_asn1_set_ctrl(*ameth, pkey_ctrl_gost); | |
944 | break; | |
945 | case NID_id_GostR3410_2001: | |
946 | EVP_PKEY_asn1_set_free(*ameth, pkey_free_gost01); | |
947 | EVP_PKEY_asn1_set_private(*ameth, | |
948 | priv_decode_gost, priv_encode_gost, | |
949 | priv_print_gost01); | |
950 | ||
951 | EVP_PKEY_asn1_set_param(*ameth, | |
952 | gost2001_param_decode, gost2001_param_encode, | |
953 | param_missing_gost01, param_copy_gost01, | |
954 | param_cmp_gost01, param_print_gost01); | |
955 | EVP_PKEY_asn1_set_public(*ameth, | |
956 | pub_decode_gost01, pub_encode_gost01, | |
957 | pub_cmp_gost01, pub_print_gost01, | |
958 | pkey_size_gost, pkey_bits_gost); | |
959 | ||
960 | EVP_PKEY_asn1_set_ctrl(*ameth, pkey_ctrl_gost); | |
961 | break; | |
962 | case NID_id_Gost28147_89_MAC: | |
963 | EVP_PKEY_asn1_set_free(*ameth, mackey_free_gost); | |
964 | EVP_PKEY_asn1_set_ctrl(*ameth, mac_ctrl_gost); | |
965 | break; | |
966 | } | |
967 | return 1; | |
968 | } |