/src/libressl/crypto/gost/gostr341001_pmeth.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* $OpenBSD: gostr341001_pmeth.c,v 1.16 2022/03/30 07:17:48 tb Exp $ */ |
2 | | /* |
3 | | * Copyright (c) 2014 Dmitry Eremin-Solenikov <dbaryshkov@gmail.com> |
4 | | * Copyright (c) 2005-2006 Cryptocom LTD |
5 | | * |
6 | | * Redistribution and use in source and binary forms, with or without |
7 | | * modification, are permitted provided that the following conditions |
8 | | * are met: |
9 | | * |
10 | | * 1. Redistributions of source code must retain the above copyright |
11 | | * notice, this list of conditions and the following disclaimer. |
12 | | * |
13 | | * 2. Redistributions in binary form must reproduce the above copyright |
14 | | * notice, this list of conditions and the following disclaimer in |
15 | | * the documentation and/or other materials provided with the |
16 | | * distribution. |
17 | | * |
18 | | * 3. All advertising materials mentioning features or use of this |
19 | | * software must display the following acknowledgment: |
20 | | * "This product includes software developed by the OpenSSL Project |
21 | | * for use in the OpenSSL Toolkit. (http://www.openssl.org/)" |
22 | | * |
23 | | * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to |
24 | | * endorse or promote products derived from this software without |
25 | | * prior written permission. For written permission, please contact |
26 | | * openssl-core@openssl.org. |
27 | | * |
28 | | * 5. Products derived from this software may not be called "OpenSSL" |
29 | | * nor may "OpenSSL" appear in their names without prior written |
30 | | * permission of the OpenSSL Project. |
31 | | * |
32 | | * 6. Redistributions of any form whatsoever must retain the following |
33 | | * acknowledgment: |
34 | | * "This product includes software developed by the OpenSSL Project |
35 | | * for use in the OpenSSL Toolkit (http://www.openssl.org/)" |
36 | | * |
37 | | * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY |
38 | | * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
39 | | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
40 | | * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR |
41 | | * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
42 | | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT |
43 | | * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; |
44 | | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) |
45 | | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, |
46 | | * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) |
47 | | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED |
48 | | * OF THE POSSIBILITY OF SUCH DAMAGE. |
49 | | * ==================================================================== |
50 | | */ |
51 | | |
52 | | #include <string.h> |
53 | | |
54 | | #include <openssl/opensslconf.h> |
55 | | |
56 | | #ifndef OPENSSL_NO_GOST |
57 | | #include <openssl/bn.h> |
58 | | #include <openssl/evp.h> |
59 | | #include <openssl/err.h> |
60 | | #include <openssl/gost.h> |
61 | | #include <openssl/ec.h> |
62 | | #include <openssl/ecdsa.h> |
63 | | #include <openssl/x509.h> |
64 | | |
65 | | #include "ecs_locl.h" |
66 | | #include "evp_locl.h" |
67 | | #include "gost_locl.h" |
68 | | #include "gost_asn1.h" |
69 | | |
70 | | static ECDSA_SIG * |
71 | | unpack_signature_cp(const unsigned char *sig, size_t siglen) |
72 | 0 | { |
73 | 0 | ECDSA_SIG *s; |
74 | |
|
75 | 0 | s = ECDSA_SIG_new(); |
76 | 0 | if (s == NULL) { |
77 | 0 | GOSTerror(ERR_R_MALLOC_FAILURE); |
78 | 0 | return NULL; |
79 | 0 | } |
80 | 0 | BN_bin2bn(sig, siglen / 2, s->s); |
81 | 0 | BN_bin2bn(sig + siglen / 2, siglen / 2, s->r); |
82 | 0 | return s; |
83 | 0 | } |
84 | | |
85 | | static int |
86 | | pack_signature_cp(ECDSA_SIG *s, int order, unsigned char *sig, size_t *siglen) |
87 | 0 | { |
88 | 0 | int r_len = BN_num_bytes(s->r); |
89 | 0 | int s_len = BN_num_bytes(s->s); |
90 | |
|
91 | 0 | if (r_len > order || s_len > order) |
92 | 0 | return 0; |
93 | | |
94 | 0 | *siglen = 2 * order; |
95 | |
|
96 | 0 | memset(sig, 0, *siglen); |
97 | 0 | BN_bn2bin(s->s, sig + order - s_len); |
98 | 0 | BN_bn2bin(s->r, sig + 2 * order - r_len); |
99 | 0 | ECDSA_SIG_free(s); |
100 | 0 | return 1; |
101 | 0 | } |
102 | | |
103 | | static ECDSA_SIG * |
104 | | unpack_signature_le(const unsigned char *sig, size_t siglen) |
105 | 0 | { |
106 | 0 | ECDSA_SIG *s; |
107 | |
|
108 | 0 | s = ECDSA_SIG_new(); |
109 | 0 | if (s == NULL) { |
110 | 0 | GOSTerror(ERR_R_MALLOC_FAILURE); |
111 | 0 | return NULL; |
112 | 0 | } |
113 | 0 | GOST_le2bn(sig, siglen / 2, s->r); |
114 | 0 | GOST_le2bn(sig + siglen / 2, siglen / 2, s->s); |
115 | 0 | return s; |
116 | 0 | } |
117 | | |
118 | | static int |
119 | | pack_signature_le(ECDSA_SIG *s, int order, unsigned char *sig, size_t *siglen) |
120 | 0 | { |
121 | 0 | *siglen = 2 * order; |
122 | 0 | memset(sig, 0, *siglen); |
123 | 0 | GOST_bn2le(s->r, sig, order); |
124 | 0 | GOST_bn2le(s->s, sig + order, order); |
125 | 0 | ECDSA_SIG_free(s); |
126 | 0 | return 1; |
127 | 0 | } |
128 | | |
129 | | struct gost_pmeth_data { |
130 | | int sign_param_nid; /* Should be set whenever parameters are filled */ |
131 | | int digest_nid; |
132 | | EVP_MD *md; |
133 | | unsigned char *shared_ukm; |
134 | | int peer_key_used; |
135 | | int sig_format; |
136 | | }; |
137 | | |
138 | | static int |
139 | | pkey_gost01_init(EVP_PKEY_CTX *ctx) |
140 | 0 | { |
141 | 0 | struct gost_pmeth_data *data; |
142 | 0 | EVP_PKEY *pkey = EVP_PKEY_CTX_get0_pkey(ctx); |
143 | |
|
144 | 0 | data = calloc(1, sizeof(struct gost_pmeth_data)); |
145 | 0 | if (data == NULL) |
146 | 0 | return 0; |
147 | | |
148 | 0 | if (pkey != NULL && pkey->pkey.gost != NULL) { |
149 | 0 | data->sign_param_nid = |
150 | 0 | EC_GROUP_get_curve_name(GOST_KEY_get0_group(pkey->pkey.gost)); |
151 | 0 | data->digest_nid = GOST_KEY_get_digest(pkey->pkey.gost); |
152 | 0 | } |
153 | 0 | EVP_PKEY_CTX_set_data(ctx, data); |
154 | 0 | return 1; |
155 | 0 | } |
156 | | |
157 | | /* Copies contents of gost_pmeth_data structure */ |
158 | | static int |
159 | | pkey_gost01_copy(EVP_PKEY_CTX *dst, EVP_PKEY_CTX *src) |
160 | 0 | { |
161 | 0 | struct gost_pmeth_data *dst_data, *src_data; |
162 | |
|
163 | 0 | if (pkey_gost01_init(dst) == 0) |
164 | 0 | return 0; |
165 | | |
166 | 0 | src_data = EVP_PKEY_CTX_get_data(src); |
167 | 0 | dst_data = EVP_PKEY_CTX_get_data(dst); |
168 | 0 | *dst_data = *src_data; |
169 | 0 | if (src_data->shared_ukm != NULL) |
170 | 0 | dst_data->shared_ukm = NULL; |
171 | 0 | return 1; |
172 | 0 | } |
173 | | |
174 | | /* Frees up gost_pmeth_data structure */ |
175 | | static void |
176 | | pkey_gost01_cleanup(EVP_PKEY_CTX *ctx) |
177 | 0 | { |
178 | 0 | struct gost_pmeth_data *data; |
179 | |
|
180 | 0 | if ((data = EVP_PKEY_CTX_get_data(ctx)) == NULL) |
181 | 0 | return; |
182 | | |
183 | 0 | free(data->shared_ukm); |
184 | 0 | free(data); |
185 | 0 | } |
186 | | |
187 | | static int |
188 | | pkey_gost01_paramgen(EVP_PKEY_CTX *ctx, EVP_PKEY *pkey) |
189 | 0 | { |
190 | 0 | struct gost_pmeth_data *data = EVP_PKEY_CTX_get_data(ctx); |
191 | 0 | EC_GROUP *group = NULL; |
192 | 0 | GOST_KEY *gost = NULL; |
193 | 0 | int ret = 0; |
194 | |
|
195 | 0 | if (data->sign_param_nid == NID_undef || |
196 | 0 | data->digest_nid == NID_undef) { |
197 | 0 | GOSTerror(GOST_R_NO_PARAMETERS_SET); |
198 | 0 | return 0; |
199 | 0 | } |
200 | | |
201 | 0 | group = EC_GROUP_new_by_curve_name(data->sign_param_nid); |
202 | 0 | if (group == NULL) |
203 | 0 | goto done; |
204 | | |
205 | 0 | EC_GROUP_set_asn1_flag(group, OPENSSL_EC_NAMED_CURVE); |
206 | |
|
207 | 0 | gost = GOST_KEY_new(); |
208 | 0 | if (gost == NULL) |
209 | 0 | goto done; |
210 | | |
211 | 0 | if (GOST_KEY_set_digest(gost, data->digest_nid) == 0) |
212 | 0 | goto done; |
213 | | |
214 | 0 | if (GOST_KEY_set_group(gost, group) != 0) |
215 | 0 | ret = EVP_PKEY_assign_GOST(pkey, gost); |
216 | |
|
217 | 0 | done: |
218 | 0 | if (ret == 0) |
219 | 0 | GOST_KEY_free(gost); |
220 | 0 | EC_GROUP_free(group); |
221 | 0 | return ret; |
222 | 0 | } |
223 | | |
224 | | static int |
225 | | pkey_gost01_keygen(EVP_PKEY_CTX *ctx, EVP_PKEY *pkey) |
226 | 0 | { |
227 | 0 | if (pkey_gost01_paramgen(ctx, pkey) == 0) |
228 | 0 | return 0; |
229 | 0 | return gost2001_keygen(pkey->pkey.gost) != 0; |
230 | 0 | } |
231 | | |
232 | | static int |
233 | | pkey_gost01_sign(EVP_PKEY_CTX *ctx, unsigned char *sig, size_t *siglen, |
234 | | const unsigned char *tbs, size_t tbs_len) |
235 | 0 | { |
236 | 0 | ECDSA_SIG *unpacked_sig = NULL; |
237 | 0 | EVP_PKEY *pkey = EVP_PKEY_CTX_get0_pkey(ctx); |
238 | 0 | struct gost_pmeth_data *pctx = EVP_PKEY_CTX_get_data(ctx); |
239 | 0 | BIGNUM *md; |
240 | 0 | size_t size; |
241 | 0 | int ret; |
242 | |
|
243 | 0 | if (pkey == NULL || pkey->pkey.gost == NULL) |
244 | 0 | return 0; |
245 | 0 | size = GOST_KEY_get_size(pkey->pkey.gost); |
246 | |
|
247 | 0 | if (siglen == NULL) |
248 | 0 | return 0; |
249 | 0 | if (sig == NULL) { |
250 | 0 | *siglen = 2 * size; |
251 | 0 | return 1; |
252 | 0 | } else if (*siglen < 2 * size) { |
253 | 0 | GOSTerror(EC_R_BUFFER_TOO_SMALL); |
254 | 0 | return 0; |
255 | 0 | } |
256 | 0 | if (tbs_len != 32 && tbs_len != 64) { |
257 | 0 | GOSTerror(EVP_R_BAD_BLOCK_LENGTH); |
258 | 0 | return 0; |
259 | 0 | } |
260 | 0 | md = GOST_le2bn(tbs, tbs_len, NULL); |
261 | 0 | if (md == NULL) |
262 | 0 | return 0; |
263 | 0 | unpacked_sig = gost2001_do_sign(md, pkey->pkey.gost); |
264 | 0 | BN_free(md); |
265 | 0 | if (unpacked_sig == NULL) { |
266 | 0 | return 0; |
267 | 0 | } |
268 | 0 | switch (pctx->sig_format) { |
269 | 0 | case GOST_SIG_FORMAT_SR_BE: |
270 | 0 | ret = pack_signature_cp(unpacked_sig, size, sig, siglen); |
271 | 0 | break; |
272 | 0 | case GOST_SIG_FORMAT_RS_LE: |
273 | 0 | ret = pack_signature_le(unpacked_sig, size, sig, siglen); |
274 | 0 | break; |
275 | 0 | default: |
276 | 0 | ret = -1; |
277 | 0 | break; |
278 | 0 | } |
279 | 0 | if (ret <= 0) |
280 | 0 | ECDSA_SIG_free(unpacked_sig); |
281 | 0 | return ret; |
282 | 0 | } |
283 | | |
284 | | static int |
285 | | pkey_gost01_verify(EVP_PKEY_CTX *ctx, const unsigned char *sig, size_t siglen, |
286 | | const unsigned char *tbs, size_t tbs_len) |
287 | 0 | { |
288 | 0 | int ok = 0; |
289 | 0 | EVP_PKEY *pub_key = EVP_PKEY_CTX_get0_pkey(ctx); |
290 | 0 | struct gost_pmeth_data *pctx = EVP_PKEY_CTX_get_data(ctx); |
291 | 0 | ECDSA_SIG *s = NULL; |
292 | 0 | BIGNUM *md; |
293 | |
|
294 | 0 | if (pub_key == NULL) |
295 | 0 | return 0; |
296 | 0 | switch (pctx->sig_format) { |
297 | 0 | case GOST_SIG_FORMAT_SR_BE: |
298 | 0 | s = unpack_signature_cp(sig, siglen); |
299 | 0 | break; |
300 | 0 | case GOST_SIG_FORMAT_RS_LE: |
301 | 0 | s = unpack_signature_le(sig, siglen); |
302 | 0 | break; |
303 | 0 | } |
304 | 0 | if (s == NULL) |
305 | 0 | return 0; |
306 | 0 | md = GOST_le2bn(tbs, tbs_len, NULL); |
307 | 0 | if (md == NULL) |
308 | 0 | goto err; |
309 | 0 | ok = gost2001_do_verify(md, s, pub_key->pkey.gost); |
310 | |
|
311 | 0 | err: |
312 | 0 | BN_free(md); |
313 | 0 | ECDSA_SIG_free(s); |
314 | 0 | return ok; |
315 | 0 | } |
316 | | |
317 | | static int |
318 | | gost01_VKO_key(EVP_PKEY *pub_key, EVP_PKEY *priv_key, const unsigned char *ukm, |
319 | | unsigned char *key) |
320 | 0 | { |
321 | 0 | unsigned char hashbuf[128]; |
322 | 0 | int digest_nid; |
323 | 0 | int ret = 0; |
324 | 0 | BN_CTX *ctx = BN_CTX_new(); |
325 | 0 | BIGNUM *UKM, *X, *Y; |
326 | |
|
327 | 0 | if (ctx == NULL) |
328 | 0 | return 0; |
329 | | |
330 | 0 | BN_CTX_start(ctx); |
331 | 0 | if ((UKM = BN_CTX_get(ctx)) == NULL) |
332 | 0 | goto err; |
333 | 0 | if ((X = BN_CTX_get(ctx)) == NULL) |
334 | 0 | goto err; |
335 | 0 | if ((Y = BN_CTX_get(ctx)) == NULL) |
336 | 0 | goto err; |
337 | | |
338 | 0 | GOST_le2bn(ukm, 8, UKM); |
339 | |
|
340 | 0 | digest_nid = GOST_KEY_get_digest(priv_key->pkey.gost); |
341 | 0 | if (VKO_compute_key(X, Y, pub_key->pkey.gost, priv_key->pkey.gost, |
342 | 0 | UKM) == 0) |
343 | 0 | goto err; |
344 | | |
345 | 0 | switch (digest_nid) { |
346 | 0 | case NID_id_GostR3411_94_CryptoProParamSet: |
347 | 0 | GOST_bn2le(X, hashbuf, 32); |
348 | 0 | GOST_bn2le(Y, hashbuf + 32, 32); |
349 | 0 | GOSTR341194(hashbuf, 64, key, digest_nid); |
350 | 0 | ret = 1; |
351 | 0 | break; |
352 | 0 | case NID_id_tc26_gost3411_2012_256: |
353 | 0 | GOST_bn2le(X, hashbuf, 32); |
354 | 0 | GOST_bn2le(Y, hashbuf + 32, 32); |
355 | 0 | STREEBOG256(hashbuf, 64, key); |
356 | 0 | ret = 1; |
357 | 0 | break; |
358 | 0 | case NID_id_tc26_gost3411_2012_512: |
359 | 0 | GOST_bn2le(X, hashbuf, 64); |
360 | 0 | GOST_bn2le(Y, hashbuf + 64, 64); |
361 | 0 | STREEBOG256(hashbuf, 128, key); |
362 | 0 | ret = 1; |
363 | 0 | break; |
364 | 0 | default: |
365 | 0 | ret = -2; |
366 | 0 | break; |
367 | 0 | } |
368 | 0 | err: |
369 | 0 | BN_CTX_end(ctx); |
370 | 0 | BN_CTX_free(ctx); |
371 | 0 | return ret; |
372 | 0 | } |
373 | | |
374 | | int |
375 | | pkey_gost01_decrypt(EVP_PKEY_CTX *pctx, unsigned char *key, size_t *key_len, |
376 | | const unsigned char *in, size_t in_len) |
377 | 0 | { |
378 | 0 | const unsigned char *p = in; |
379 | 0 | EVP_PKEY *priv = EVP_PKEY_CTX_get0_pkey(pctx); |
380 | 0 | GOST_KEY_TRANSPORT *gkt = NULL; |
381 | 0 | int ret = 0; |
382 | 0 | unsigned char wrappedKey[44]; |
383 | 0 | unsigned char sharedKey[32]; |
384 | 0 | EVP_PKEY *eph_key = NULL, *peerkey = NULL; |
385 | 0 | int nid; |
386 | |
|
387 | 0 | if (key == NULL) { |
388 | 0 | *key_len = 32; |
389 | 0 | return 1; |
390 | 0 | } |
391 | 0 | gkt = d2i_GOST_KEY_TRANSPORT(NULL, (const unsigned char **)&p, in_len); |
392 | 0 | if (gkt == NULL) { |
393 | 0 | GOSTerror(GOST_R_ERROR_PARSING_KEY_TRANSPORT_INFO); |
394 | 0 | return -1; |
395 | 0 | } |
396 | | |
397 | | /* If key transport structure contains public key, use it */ |
398 | 0 | eph_key = X509_PUBKEY_get(gkt->key_agreement_info->ephem_key); |
399 | 0 | if (eph_key != NULL) { |
400 | 0 | if (EVP_PKEY_derive_set_peer(pctx, eph_key) <= 0) { |
401 | 0 | GOSTerror(GOST_R_INCOMPATIBLE_PEER_KEY); |
402 | 0 | goto err; |
403 | 0 | } |
404 | 0 | } else { |
405 | | /* Set control "public key from client certificate used" */ |
406 | 0 | if (EVP_PKEY_CTX_ctrl(pctx, -1, -1, EVP_PKEY_CTRL_PEER_KEY, 3, |
407 | 0 | NULL) <= 0) { |
408 | 0 | GOSTerror(GOST_R_CTRL_CALL_FAILED); |
409 | 0 | goto err; |
410 | 0 | } |
411 | 0 | } |
412 | 0 | peerkey = EVP_PKEY_CTX_get0_peerkey(pctx); |
413 | 0 | if (peerkey == NULL) { |
414 | 0 | GOSTerror(GOST_R_NO_PEER_KEY); |
415 | 0 | goto err; |
416 | 0 | } |
417 | | |
418 | 0 | nid = OBJ_obj2nid(gkt->key_agreement_info->cipher); |
419 | |
|
420 | 0 | if (gkt->key_agreement_info->eph_iv->length != 8) { |
421 | 0 | GOSTerror(GOST_R_INVALID_IV_LENGTH); |
422 | 0 | goto err; |
423 | 0 | } |
424 | 0 | memcpy(wrappedKey, gkt->key_agreement_info->eph_iv->data, 8); |
425 | 0 | if (gkt->key_info->encrypted_key->length != 32) { |
426 | 0 | GOSTerror(EVP_R_BAD_KEY_LENGTH); |
427 | 0 | goto err; |
428 | 0 | } |
429 | 0 | memcpy(wrappedKey + 8, gkt->key_info->encrypted_key->data, 32); |
430 | 0 | if (gkt->key_info->imit->length != 4) { |
431 | 0 | GOSTerror(ERR_R_INTERNAL_ERROR); |
432 | 0 | goto err; |
433 | 0 | } |
434 | 0 | memcpy(wrappedKey + 40, gkt->key_info->imit->data, 4); |
435 | 0 | if (gost01_VKO_key(peerkey, priv, wrappedKey, sharedKey) <= 0) |
436 | 0 | goto err; |
437 | 0 | if (gost_key_unwrap_crypto_pro(nid, sharedKey, wrappedKey, key) == 0) { |
438 | 0 | GOSTerror(GOST_R_ERROR_COMPUTING_SHARED_KEY); |
439 | 0 | goto err; |
440 | 0 | } |
441 | | |
442 | 0 | ret = 1; |
443 | 0 | err: |
444 | 0 | EVP_PKEY_free(eph_key); |
445 | 0 | GOST_KEY_TRANSPORT_free(gkt); |
446 | 0 | return ret; |
447 | 0 | } |
448 | | |
449 | | int |
450 | | pkey_gost01_derive(EVP_PKEY_CTX *ctx, unsigned char *key, size_t *keylen) |
451 | 0 | { |
452 | | /* |
453 | | * Public key of peer in the ctx field peerkey |
454 | | * Our private key in the ctx pkey |
455 | | * ukm is in the algorithm specific context data |
456 | | */ |
457 | 0 | EVP_PKEY *my_key = EVP_PKEY_CTX_get0_pkey(ctx); |
458 | 0 | EVP_PKEY *peer_key = EVP_PKEY_CTX_get0_peerkey(ctx); |
459 | 0 | struct gost_pmeth_data *data = EVP_PKEY_CTX_get_data(ctx); |
460 | |
|
461 | 0 | if (data->shared_ukm == NULL) { |
462 | 0 | GOSTerror(GOST_R_UKM_NOT_SET); |
463 | 0 | return 0; |
464 | 0 | } |
465 | | |
466 | 0 | if (key == NULL) { |
467 | 0 | *keylen = 32; |
468 | 0 | return 32; |
469 | 0 | } |
470 | | |
471 | 0 | if (gost01_VKO_key(peer_key, my_key, data->shared_ukm, key) <= 0) |
472 | 0 | return 0; |
473 | | |
474 | 0 | *keylen = 32; |
475 | 0 | return 1; |
476 | 0 | } |
477 | | |
478 | | int |
479 | | pkey_gost01_encrypt(EVP_PKEY_CTX *pctx, unsigned char *out, size_t *out_len, |
480 | | const unsigned char *key, size_t key_len) |
481 | 0 | { |
482 | 0 | GOST_KEY_TRANSPORT *gkt = NULL; |
483 | 0 | EVP_PKEY *pubk = EVP_PKEY_CTX_get0_pkey(pctx); |
484 | 0 | struct gost_pmeth_data *data = EVP_PKEY_CTX_get_data(pctx); |
485 | 0 | unsigned char ukm[8], shared_key[32], crypted_key[44]; |
486 | 0 | int ret = 0; |
487 | 0 | int key_is_ephemeral; |
488 | 0 | EVP_PKEY *sec_key = EVP_PKEY_CTX_get0_peerkey(pctx); |
489 | 0 | int nid = NID_id_Gost28147_89_CryptoPro_A_ParamSet; |
490 | |
|
491 | 0 | if (data->shared_ukm != NULL) { |
492 | 0 | memcpy(ukm, data->shared_ukm, 8); |
493 | 0 | } else /* if (out != NULL) */ { |
494 | 0 | arc4random_buf(ukm, 8); |
495 | 0 | } |
496 | | /* Check for private key in the peer_key of context */ |
497 | 0 | if (sec_key) { |
498 | 0 | key_is_ephemeral = 0; |
499 | 0 | if (GOST_KEY_get0_private_key(sec_key->pkey.gost) == 0) { |
500 | 0 | GOSTerror(GOST_R_NO_PRIVATE_PART_OF_NON_EPHEMERAL_KEYPAIR); |
501 | 0 | goto err; |
502 | 0 | } |
503 | 0 | } else { |
504 | 0 | key_is_ephemeral = 1; |
505 | 0 | if (out != NULL) { |
506 | 0 | GOST_KEY *tmp_key; |
507 | |
|
508 | 0 | sec_key = EVP_PKEY_new(); |
509 | 0 | if (sec_key == NULL) |
510 | 0 | goto err; |
511 | 0 | tmp_key = GOST_KEY_new(); |
512 | 0 | if (tmp_key == NULL) |
513 | 0 | goto err; |
514 | 0 | if (EVP_PKEY_assign(sec_key, EVP_PKEY_base_id(pubk), |
515 | 0 | tmp_key) == 0) { |
516 | 0 | GOST_KEY_free(tmp_key); |
517 | 0 | goto err; |
518 | 0 | } |
519 | 0 | if (EVP_PKEY_copy_parameters(sec_key, pubk) == 0) |
520 | 0 | goto err; |
521 | 0 | if (gost2001_keygen(sec_key->pkey.gost) == 0) { |
522 | 0 | goto err; |
523 | 0 | } |
524 | 0 | } |
525 | 0 | } |
526 | | |
527 | 0 | if (out != NULL) { |
528 | 0 | if (gost01_VKO_key(pubk, sec_key, ukm, shared_key) <= 0) |
529 | 0 | goto err; |
530 | 0 | gost_key_wrap_crypto_pro(nid, shared_key, ukm, key, |
531 | 0 | crypted_key); |
532 | 0 | } |
533 | 0 | gkt = GOST_KEY_TRANSPORT_new(); |
534 | 0 | if (gkt == NULL) |
535 | 0 | goto err; |
536 | 0 | if (ASN1_OCTET_STRING_set(gkt->key_agreement_info->eph_iv, ukm, 8) == 0) |
537 | 0 | goto err; |
538 | 0 | if (ASN1_OCTET_STRING_set(gkt->key_info->imit, crypted_key + 40, |
539 | 0 | 4) == 0) |
540 | 0 | goto err; |
541 | 0 | if (ASN1_OCTET_STRING_set(gkt->key_info->encrypted_key, crypted_key + 8, |
542 | 0 | 32) == 0) |
543 | 0 | goto err; |
544 | 0 | if (key_is_ephemeral) { |
545 | 0 | if (X509_PUBKEY_set(&gkt->key_agreement_info->ephem_key, |
546 | 0 | out != NULL ? sec_key : pubk) == 0) { |
547 | 0 | GOSTerror(GOST_R_CANNOT_PACK_EPHEMERAL_KEY); |
548 | 0 | goto err; |
549 | 0 | } |
550 | 0 | } |
551 | 0 | ASN1_OBJECT_free(gkt->key_agreement_info->cipher); |
552 | 0 | gkt->key_agreement_info->cipher = OBJ_nid2obj(nid); |
553 | 0 | if (key_is_ephemeral) |
554 | 0 | EVP_PKEY_free(sec_key); |
555 | 0 | else { |
556 | | /* Set control "public key from client certificate used" */ |
557 | 0 | if (EVP_PKEY_CTX_ctrl(pctx, -1, -1, EVP_PKEY_CTRL_PEER_KEY, 3, |
558 | 0 | NULL) <= 0) { |
559 | 0 | GOSTerror(GOST_R_CTRL_CALL_FAILED); |
560 | 0 | goto err; |
561 | 0 | } |
562 | 0 | } |
563 | 0 | if ((*out_len = i2d_GOST_KEY_TRANSPORT(gkt, out ? &out : NULL)) > 0) |
564 | 0 | ret = 1; |
565 | 0 | GOST_KEY_TRANSPORT_free(gkt); |
566 | 0 | return ret; |
567 | | |
568 | 0 | err: |
569 | 0 | if (key_is_ephemeral) |
570 | 0 | EVP_PKEY_free(sec_key); |
571 | 0 | GOST_KEY_TRANSPORT_free(gkt); |
572 | 0 | return -1; |
573 | 0 | } |
574 | | |
575 | | |
576 | | static int |
577 | | pkey_gost01_ctrl(EVP_PKEY_CTX *ctx, int type, int p1, void *p2) |
578 | 0 | { |
579 | 0 | struct gost_pmeth_data *pctx = EVP_PKEY_CTX_get_data(ctx); |
580 | |
|
581 | 0 | switch (type) { |
582 | 0 | case EVP_PKEY_CTRL_MD: |
583 | 0 | if (EVP_MD_type(p2) != |
584 | 0 | GostR3410_get_md_digest(pctx->digest_nid)) { |
585 | 0 | GOSTerror(GOST_R_INVALID_DIGEST_TYPE); |
586 | 0 | return 0; |
587 | 0 | } |
588 | 0 | pctx->md = p2; |
589 | 0 | return 1; |
590 | 0 | case EVP_PKEY_CTRL_PKCS7_ENCRYPT: |
591 | 0 | case EVP_PKEY_CTRL_PKCS7_DECRYPT: |
592 | 0 | case EVP_PKEY_CTRL_PKCS7_SIGN: |
593 | 0 | case EVP_PKEY_CTRL_DIGESTINIT: |
594 | 0 | return 1; |
595 | | |
596 | 0 | case EVP_PKEY_CTRL_GOST_PARAMSET: |
597 | 0 | pctx->sign_param_nid = (int)p1; |
598 | 0 | return 1; |
599 | | |
600 | 0 | case EVP_PKEY_CTRL_SET_IV: |
601 | 0 | { |
602 | 0 | char *ukm = malloc(p1); |
603 | |
|
604 | 0 | if (ukm == NULL) { |
605 | 0 | GOSTerror(ERR_R_MALLOC_FAILURE); |
606 | 0 | return 0; |
607 | 0 | } |
608 | 0 | memcpy(ukm, p2, p1); |
609 | 0 | free(pctx->shared_ukm); |
610 | 0 | pctx->shared_ukm = ukm; |
611 | 0 | return 1; |
612 | 0 | } |
613 | | |
614 | 0 | case EVP_PKEY_CTRL_PEER_KEY: |
615 | 0 | if (p1 == 0 || p1 == 1) /* call from EVP_PKEY_derive_set_peer */ |
616 | 0 | return 1; |
617 | 0 | if (p1 == 2) /* TLS: peer key used? */ |
618 | 0 | return pctx->peer_key_used; |
619 | 0 | if (p1 == 3) /* TLS: peer key used! */ |
620 | 0 | return (pctx->peer_key_used = 1); |
621 | 0 | return -2; |
622 | 0 | case EVP_PKEY_CTRL_GOST_SIG_FORMAT: |
623 | 0 | switch (p1) { |
624 | 0 | case GOST_SIG_FORMAT_SR_BE: |
625 | 0 | case GOST_SIG_FORMAT_RS_LE: |
626 | 0 | pctx->sig_format = p1; |
627 | 0 | return 1; |
628 | 0 | default: |
629 | 0 | return 0; |
630 | 0 | } |
631 | 0 | break; |
632 | 0 | case EVP_PKEY_CTRL_GOST_SET_DIGEST: |
633 | 0 | pctx->digest_nid = (int)p1; |
634 | 0 | return 1; |
635 | 0 | case EVP_PKEY_CTRL_GOST_GET_DIGEST: |
636 | 0 | *(int *)p2 = pctx->digest_nid; |
637 | 0 | return 1; |
638 | 0 | default: |
639 | 0 | return -2; |
640 | 0 | } |
641 | 0 | } |
642 | | |
643 | | static int |
644 | | pkey_gost01_ctrl_str(EVP_PKEY_CTX *ctx, const char *type, const char *value) |
645 | 0 | { |
646 | 0 | int param_nid = NID_undef; |
647 | 0 | int digest_nid = NID_undef; |
648 | |
|
649 | 0 | if (strcmp(type, "paramset") == 0) { |
650 | 0 | if (value == NULL) |
651 | 0 | return 0; |
652 | 0 | if (pkey_gost01_ctrl(ctx, EVP_PKEY_CTRL_GOST_GET_DIGEST, 0, |
653 | 0 | &digest_nid) == 0) |
654 | 0 | return 0; |
655 | 0 | if (digest_nid == NID_id_tc26_gost3411_2012_512) |
656 | 0 | param_nid = GostR3410_512_param_id(value); |
657 | 0 | else |
658 | 0 | param_nid = GostR3410_256_param_id(value); |
659 | 0 | if (param_nid == NID_undef) |
660 | 0 | param_nid = OBJ_txt2nid(value); |
661 | 0 | if (param_nid == NID_undef) |
662 | 0 | return 0; |
663 | | |
664 | 0 | return pkey_gost01_ctrl(ctx, EVP_PKEY_CTRL_GOST_PARAMSET, |
665 | 0 | param_nid, NULL); |
666 | 0 | } |
667 | 0 | if (strcmp(type, "dgst") == 0) { |
668 | 0 | if (value == NULL) |
669 | 0 | return 0; |
670 | 0 | else if (strcmp(value, "gost94") == 0 || |
671 | 0 | strcmp(value, "md_gost94") == 0) |
672 | 0 | digest_nid = NID_id_GostR3411_94_CryptoProParamSet; |
673 | 0 | else if (strcmp(value, "streebog256") == 0) |
674 | 0 | digest_nid = NID_id_tc26_gost3411_2012_256; |
675 | 0 | else if (strcmp(value, "streebog512") == 0) |
676 | 0 | digest_nid = NID_id_tc26_gost3411_2012_512; |
677 | | |
678 | 0 | if (digest_nid == NID_undef) |
679 | 0 | return 0; |
680 | | |
681 | 0 | return pkey_gost01_ctrl(ctx, EVP_PKEY_CTRL_GOST_SET_DIGEST, |
682 | 0 | digest_nid, NULL); |
683 | 0 | } |
684 | 0 | return -2; |
685 | 0 | } |
686 | | |
687 | | const EVP_PKEY_METHOD gostr01_pkey_meth = { |
688 | | .pkey_id = EVP_PKEY_GOSTR01, |
689 | | |
690 | | .init = pkey_gost01_init, |
691 | | .copy = pkey_gost01_copy, |
692 | | .cleanup = pkey_gost01_cleanup, |
693 | | |
694 | | .paramgen = pkey_gost01_paramgen, |
695 | | .keygen = pkey_gost01_keygen, |
696 | | .sign = pkey_gost01_sign, |
697 | | .verify = pkey_gost01_verify, |
698 | | |
699 | | .encrypt = pkey_gost01_encrypt, |
700 | | .decrypt = pkey_gost01_decrypt, |
701 | | .derive = pkey_gost01_derive, |
702 | | |
703 | | .ctrl = pkey_gost01_ctrl, |
704 | | .ctrl_str = pkey_gost01_ctrl_str, |
705 | | }; |
706 | | #endif |