Coverage Report

Created: 2022-08-24 06:30

/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