Coverage Report

Created: 2026-09-01 06:32

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/bind9/lib/dns/opensslecdsa_link.c
Line
Count
Source
1
/*
2
 * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
3
 *
4
 * SPDX-License-Identifier: MPL-2.0
5
 *
6
 * This Source Code Form is subject to the terms of the Mozilla Public
7
 * License, v. 2.0. If a copy of the MPL was not distributed with this
8
 * file, you can obtain one at https://mozilla.org/MPL/2.0/.
9
 *
10
 * See the COPYRIGHT file distributed with this work for additional
11
 * information regarding copyright ownership.
12
 */
13
14
/*! \file */
15
16
#include <stdbool.h>
17
18
#include <openssl/bn.h>
19
#include <openssl/ecdsa.h>
20
#include <openssl/evp.h>
21
#include <openssl/objects.h>
22
23
#include <isc/crypto.h>
24
#include <isc/md.h>
25
#include <isc/mem.h>
26
#include <isc/ossl_wrap.h>
27
#include <isc/result.h>
28
#include <isc/safe.h>
29
#include <isc/string.h>
30
#include <isc/util.h>
31
32
#include <dns/keyvalues.h>
33
34
#include "dst_internal.h"
35
#include "dst_openssl.h"
36
#include "dst_parse.h"
37
#include "openssl_shim.h"
38
39
#ifndef NID_X9_62_prime256v1
40
#error "P-256 group is not known (NID_X9_62_prime256v1)"
41
#endif /* ifndef NID_X9_62_prime256v1 */
42
#ifndef NID_secp384r1
43
#error "P-384 group is not known (NID_secp384r1)"
44
#endif /* ifndef NID_secp384r1 */
45
46
#define MAX_PUBKEY_SIZE DNS_KEY_ECDSA384SIZE
47
48
#define MAX_PRIVKEY_SIZE (MAX_PUBKEY_SIZE / 2)
49
50
static bool
51
0
opensslecdsa_valid_key_alg(unsigned int key_alg) {
52
0
  switch (key_alg) {
53
0
  case DST_ALG_ECDSA256:
54
0
  case DST_ALG_ECDSA384:
55
0
    return true;
56
0
  default:
57
0
    return false;
58
0
  }
59
0
}
60
61
static size_t
62
0
opensslecdsa_key_alg_to_publickey_size(unsigned int key_alg) {
63
0
  switch (key_alg) {
64
0
  case DST_ALG_ECDSA256:
65
0
    return DNS_KEY_ECDSA256SIZE;
66
0
  case DST_ALG_ECDSA384:
67
0
    return DNS_KEY_ECDSA384SIZE;
68
0
  default:
69
0
    UNREACHABLE();
70
0
  }
71
0
}
72
73
static int
74
0
BN_bn2bin_fixed(const BIGNUM *bn, unsigned char *buf, int size) {
75
0
  int bytes = size - BN_num_bytes(bn);
76
77
0
  INSIST(bytes >= 0);
78
79
0
  while (bytes-- > 0) {
80
0
    *buf++ = 0;
81
0
  }
82
0
  BN_bn2bin(bn, buf);
83
0
  return size;
84
0
}
85
86
static isc_result_t
87
0
opensslecdsa_createctx(dst_key_t *key, dst_context_t *dctx) {
88
0
  isc_result_t result = ISC_R_SUCCESS;
89
0
  EVP_MD_CTX *evp_md_ctx;
90
0
  EVP_PKEY_CTX *pctx = NULL;
91
0
  const EVP_MD *type = NULL;
92
0
  const char *md = NULL;
93
94
0
  UNUSED(key);
95
0
  REQUIRE(opensslecdsa_valid_key_alg(dctx->key->key_alg));
96
0
  REQUIRE(dctx->use == DO_SIGN || dctx->use == DO_VERIFY);
97
98
0
  evp_md_ctx = EVP_MD_CTX_create();
99
0
  if (evp_md_ctx == NULL) {
100
0
    return dst__openssl_toresult(ISC_R_NOMEMORY);
101
0
  }
102
0
  if (dctx->key->key_alg == DST_ALG_ECDSA256) {
103
0
    type = isc__crypto_md[ISC_MD_SHA256];
104
0
    md = "SHA256";
105
0
  } else {
106
0
    type = isc__crypto_md[ISC_MD_SHA384];
107
0
    md = "SHA384";
108
0
  }
109
110
0
  if (dctx->use == DO_SIGN) {
111
0
    if (EVP_DigestSignInit(evp_md_ctx, &pctx, type, NULL,
112
0
               dctx->key->keydata.pkeypair.priv) != 1)
113
0
    {
114
0
      EVP_MD_CTX_destroy(evp_md_ctx);
115
0
      return dst__openssl_toresult3(dctx->category,
116
0
                  "EVP_DigestSignInit",
117
0
                  ISC_R_FAILURE);
118
0
    }
119
120
0
    if (!isc_crypto_fips_mode()) {
121
0
      result = isc_ossl_wrap_ecdsa_set_deterministic(pctx,
122
0
                       md);
123
0
      if (result != ISC_R_SUCCESS &&
124
0
          result != ISC_R_NOTIMPLEMENTED)
125
0
      {
126
0
        EVP_MD_CTX_destroy(evp_md_ctx);
127
0
        return result;
128
0
      }
129
0
    }
130
131
0
  } else {
132
0
    if (EVP_DigestVerifyInit(evp_md_ctx, NULL, type, NULL,
133
0
           dctx->key->keydata.pkeypair.pub) != 1)
134
0
    {
135
0
      EVP_MD_CTX_destroy(evp_md_ctx);
136
0
      return dst__openssl_toresult3(dctx->category,
137
0
                  "EVP_DigestVerifyInit",
138
0
                  ISC_R_FAILURE);
139
0
    }
140
0
  }
141
142
0
  dctx->ctxdata.evp_md_ctx = evp_md_ctx;
143
0
  result = ISC_R_SUCCESS;
144
145
0
  return result;
146
0
}
147
148
static void
149
0
opensslecdsa_destroyctx(dst_context_t *dctx) {
150
0
  EVP_MD_CTX *evp_md_ctx = dctx->ctxdata.evp_md_ctx;
151
152
0
  REQUIRE(opensslecdsa_valid_key_alg(dctx->key->key_alg));
153
0
  REQUIRE(dctx->use == DO_SIGN || dctx->use == DO_VERIFY);
154
155
0
  if (evp_md_ctx != NULL) {
156
0
    EVP_MD_CTX_destroy(evp_md_ctx);
157
0
    dctx->ctxdata.evp_md_ctx = NULL;
158
0
  }
159
0
}
160
161
static isc_result_t
162
0
opensslecdsa_adddata(dst_context_t *dctx, const isc_region_t *data) {
163
0
  isc_result_t result = ISC_R_SUCCESS;
164
0
  EVP_MD_CTX *evp_md_ctx = dctx->ctxdata.evp_md_ctx;
165
166
0
  REQUIRE(opensslecdsa_valid_key_alg(dctx->key->key_alg));
167
0
  REQUIRE(dctx->use == DO_SIGN || dctx->use == DO_VERIFY);
168
169
0
  if (dctx->use == DO_SIGN) {
170
0
    if (EVP_DigestSignUpdate(evp_md_ctx, data->base,
171
0
           data->length) != 1)
172
0
    {
173
0
      return dst__openssl_toresult3(dctx->category,
174
0
                  "EVP_DigestSignUpdate",
175
0
                  ISC_R_FAILURE);
176
0
    }
177
0
  } else {
178
0
    if (EVP_DigestVerifyUpdate(evp_md_ctx, data->base,
179
0
             data->length) != 1)
180
0
    {
181
0
      return dst__openssl_toresult3(dctx->category,
182
0
                  "EVP_DigestVerifyUpdate",
183
0
                  ISC_R_FAILURE);
184
0
    }
185
0
  }
186
187
0
  return result;
188
0
}
189
190
static isc_result_t
191
0
opensslecdsa_sign(dst_context_t *dctx, isc_buffer_t *sig) {
192
0
  isc_result_t result;
193
0
  dst_key_t *key = dctx->key;
194
0
  isc_region_t region;
195
0
  EVP_MD_CTX *evp_md_ctx = dctx->ctxdata.evp_md_ctx;
196
0
  ECDSA_SIG *ecdsasig = NULL;
197
0
  size_t siglen, sigder_len = 0, sigder_alloced = 0;
198
0
  unsigned char *sigder = NULL;
199
0
  const unsigned char *sigder_copy;
200
0
  const BIGNUM *r, *s;
201
202
0
  REQUIRE(opensslecdsa_valid_key_alg(key->key_alg));
203
0
  REQUIRE(dctx->use == DO_SIGN);
204
205
0
  if (key->key_alg == DST_ALG_ECDSA256) {
206
0
    siglen = DNS_SIG_ECDSA256SIZE;
207
0
  } else {
208
0
    siglen = DNS_SIG_ECDSA384SIZE;
209
0
  }
210
211
0
  isc_buffer_availableregion(sig, &region);
212
0
  if (region.length < siglen) {
213
0
    CLEANUP(ISC_R_NOSPACE);
214
0
  }
215
216
0
  if (EVP_DigestSignFinal(evp_md_ctx, NULL, &sigder_len) != 1) {
217
0
    CLEANUP(dst__openssl_toresult3(
218
0
      dctx->category, "EVP_DigestSignFinal", ISC_R_FAILURE));
219
0
  }
220
0
  if (sigder_len == 0) {
221
0
    CLEANUP(ISC_R_FAILURE);
222
0
  }
223
0
  sigder = isc_mem_get(dctx->mctx, sigder_len);
224
0
  sigder_alloced = sigder_len;
225
0
  if (EVP_DigestSignFinal(evp_md_ctx, sigder, &sigder_len) != 1) {
226
0
    CLEANUP(dst__openssl_toresult3(
227
0
      dctx->category, "EVP_DigestSignFinal", ISC_R_FAILURE));
228
0
  }
229
0
  sigder_copy = sigder;
230
0
  if (d2i_ECDSA_SIG(&ecdsasig, &sigder_copy, sigder_len) == NULL) {
231
0
    CLEANUP(dst__openssl_toresult3(dctx->category, "d2i_ECDSA_SIG",
232
0
                 ISC_R_FAILURE));
233
0
  }
234
235
0
  ECDSA_SIG_get0(ecdsasig, &r, &s);
236
0
  BN_bn2bin_fixed(r, region.base, siglen / 2);
237
0
  isc_region_consume(&region, siglen / 2);
238
0
  BN_bn2bin_fixed(s, region.base, siglen / 2);
239
0
  isc_region_consume(&region, siglen / 2);
240
0
  ECDSA_SIG_free(ecdsasig);
241
0
  isc_buffer_add(sig, siglen);
242
0
  result = ISC_R_SUCCESS;
243
244
0
cleanup:
245
0
  if (sigder != NULL && sigder_alloced != 0) {
246
0
    isc_mem_put(dctx->mctx, sigder, sigder_alloced);
247
0
  }
248
249
0
  return result;
250
0
}
251
252
static isc_result_t
253
0
opensslecdsa_verify(dst_context_t *dctx, const isc_region_t *sig) {
254
0
  isc_result_t result;
255
0
  dst_key_t *key = dctx->key;
256
0
  int status;
257
0
  unsigned char *cp = sig->base;
258
0
  ECDSA_SIG *ecdsasig = NULL;
259
0
  EVP_MD_CTX *evp_md_ctx = dctx->ctxdata.evp_md_ctx;
260
0
  size_t siglen, sigder_len = 0, sigder_alloced = 0;
261
0
  unsigned char *sigder = NULL;
262
0
  unsigned char *sigder_copy;
263
0
  BIGNUM *r = NULL, *s = NULL;
264
265
0
  REQUIRE(opensslecdsa_valid_key_alg(key->key_alg));
266
0
  REQUIRE(dctx->use == DO_VERIFY);
267
268
0
  if (key->key_alg == DST_ALG_ECDSA256) {
269
0
    siglen = DNS_SIG_ECDSA256SIZE;
270
0
  } else {
271
0
    siglen = DNS_SIG_ECDSA384SIZE;
272
0
  }
273
274
0
  if (sig->length != siglen) {
275
0
    CLEANUP(DST_R_VERIFYFAILURE);
276
0
  }
277
278
0
  ecdsasig = ECDSA_SIG_new();
279
0
  if (ecdsasig == NULL) {
280
0
    CLEANUP(dst__openssl_toresult(ISC_R_NOMEMORY));
281
0
  }
282
0
  r = BN_bin2bn(cp, siglen / 2, NULL);
283
0
  cp += siglen / 2;
284
0
  s = BN_bin2bn(cp, siglen / 2, NULL);
285
  /* cp += siglen / 2; */
286
0
  ECDSA_SIG_set0(ecdsasig, r, s);
287
288
0
  status = i2d_ECDSA_SIG(ecdsasig, NULL);
289
0
  if (status < 0) {
290
0
    CLEANUP(dst__openssl_toresult3(dctx->category, "i2d_ECDSA_SIG",
291
0
                 DST_R_VERIFYFAILURE));
292
0
  }
293
294
0
  sigder_len = (size_t)status;
295
0
  sigder = isc_mem_get(dctx->mctx, sigder_len);
296
0
  sigder_alloced = sigder_len;
297
298
0
  sigder_copy = sigder;
299
0
  status = i2d_ECDSA_SIG(ecdsasig, &sigder_copy);
300
0
  if (status < 0) {
301
0
    CLEANUP(dst__openssl_toresult3(dctx->category, "i2d_ECDSA_SIG",
302
0
                 DST_R_VERIFYFAILURE));
303
0
  }
304
305
0
  status = EVP_DigestVerifyFinal(evp_md_ctx, sigder, sigder_len);
306
307
0
  switch (status) {
308
0
  case 1:
309
0
    result = ISC_R_SUCCESS;
310
0
    break;
311
0
  case 0:
312
0
    result = dst__openssl_toresult(DST_R_VERIFYFAILURE);
313
0
    break;
314
0
  default:
315
0
    result = dst__openssl_toresult3(dctx->category,
316
0
            "EVP_DigestVerifyFinal",
317
0
            DST_R_VERIFYFAILURE);
318
0
    break;
319
0
  }
320
321
0
cleanup:
322
0
  if (ecdsasig != NULL) {
323
0
    ECDSA_SIG_free(ecdsasig);
324
0
  }
325
0
  if (sigder != NULL && sigder_alloced != 0) {
326
0
    isc_mem_put(dctx->mctx, sigder, sigder_alloced);
327
0
  }
328
329
0
  return result;
330
0
}
331
332
static isc_result_t
333
0
opensslecdsa_generate(dst_key_t *key, int unused, void (*callback)(int)) {
334
0
  EVP_PKEY *pkey = NULL;
335
336
0
  REQUIRE(opensslecdsa_valid_key_alg(key->key_alg));
337
0
  UNUSED(unused);
338
0
  UNUSED(callback);
339
340
0
  if (key->label != NULL) {
341
0
    switch (key->key_alg) {
342
0
    case DST_ALG_ECDSA256:
343
0
      RETERR(isc_ossl_wrap_generate_pkcs11_p256_key(
344
0
        key->label, &pkey));
345
0
      break;
346
0
    case DST_ALG_ECDSA384:
347
0
      RETERR(isc_ossl_wrap_generate_pkcs11_p384_key(
348
0
        key->label, &pkey));
349
0
      break;
350
0
    default:
351
0
      UNREACHABLE();
352
0
    }
353
0
  } else {
354
0
    switch (key->key_alg) {
355
0
    case DST_ALG_ECDSA256:
356
0
      RETERR(isc_ossl_wrap_generate_p256_key(&pkey));
357
0
      break;
358
0
    case DST_ALG_ECDSA384:
359
0
      RETERR(isc_ossl_wrap_generate_p384_key(&pkey));
360
0
      break;
361
0
    default:
362
0
      UNREACHABLE();
363
0
    }
364
0
  }
365
366
0
  key->key_size = EVP_PKEY_bits(pkey);
367
0
  key->keydata.pkeypair.priv = pkey;
368
0
  key->keydata.pkeypair.pub = pkey;
369
0
  return ISC_R_SUCCESS;
370
0
}
371
372
static isc_result_t
373
0
opensslecdsa_todns(const dst_key_t *key, isc_buffer_t *data) {
374
0
  isc_result_t result;
375
0
  isc_region_t r;
376
0
  EVP_PKEY *pkey;
377
0
  size_t keysize;
378
379
0
  REQUIRE(opensslecdsa_valid_key_alg(key->key_alg));
380
0
  REQUIRE(key->keydata.pkeypair.pub != NULL);
381
382
0
  keysize = opensslecdsa_key_alg_to_publickey_size(key->key_alg);
383
0
  isc_buffer_availableregion(data, &r);
384
0
  if (r.length < keysize) {
385
0
    return ISC_R_NOSPACE;
386
0
  }
387
388
0
  pkey = key->keydata.pkeypair.pub;
389
0
  switch (key->key_alg) {
390
0
  case DST_ALG_ECDSA256:
391
0
    if (isc_ossl_wrap_p256_public_region(pkey, r) != ISC_R_SUCCESS)
392
0
    {
393
0
      return dst__openssl_toresult(DST_R_OPENSSLFAILURE);
394
0
    }
395
0
    break;
396
0
  case DST_ALG_ECDSA384:
397
0
    if (isc_ossl_wrap_p384_public_region(pkey, r) != ISC_R_SUCCESS)
398
0
    {
399
0
      return dst__openssl_toresult(DST_R_OPENSSLFAILURE);
400
0
    }
401
0
    break;
402
0
  default:
403
0
    UNREACHABLE();
404
0
  }
405
406
0
  isc_buffer_add(data, keysize);
407
0
  result = ISC_R_SUCCESS;
408
409
0
  return result;
410
0
}
411
412
static isc_result_t
413
0
opensslecdsa_fromdns(dst_key_t *key, isc_buffer_t *data) {
414
0
  isc_result_t result;
415
0
  EVP_PKEY *pkey = NULL;
416
0
  isc_region_t r;
417
0
  size_t len;
418
419
0
  REQUIRE(opensslecdsa_valid_key_alg(key->key_alg));
420
0
  len = opensslecdsa_key_alg_to_publickey_size(key->key_alg);
421
422
0
  isc_buffer_remainingregion(data, &r);
423
0
  if (r.length == 0) {
424
0
    return ISC_R_SUCCESS;
425
0
  }
426
0
  if (r.length != len) {
427
0
    return DST_R_INVALIDPUBLICKEY;
428
0
  }
429
430
0
  switch (key->key_alg) {
431
0
  case DST_ALG_ECDSA256:
432
0
    RETERR(isc_ossl_wrap_load_p256_public_from_region(r, &pkey));
433
0
    break;
434
0
  case DST_ALG_ECDSA384:
435
0
    RETERR(isc_ossl_wrap_load_p384_public_from_region(r, &pkey));
436
0
    break;
437
0
  default:
438
0
    UNREACHABLE();
439
0
  }
440
441
0
  isc_buffer_forward(data, len);
442
0
  key->key_size = EVP_PKEY_bits(pkey);
443
0
  key->keydata.pkeypair.pub = pkey;
444
0
  result = ISC_R_SUCCESS;
445
446
0
  return result;
447
0
}
448
449
static isc_result_t
450
0
opensslecdsa_tofile(const dst_key_t *key, const char *directory) {
451
0
  isc_result_t result;
452
0
  dst_private_t priv;
453
0
  unsigned char buf[MAX_PRIVKEY_SIZE];
454
0
  size_t keylen = 0;
455
0
  unsigned short i;
456
0
  EVP_PKEY *pkey;
457
458
0
  if (key->keydata.pkeypair.pub == NULL) {
459
0
    CLEANUP(DST_R_NULLKEY);
460
0
  }
461
462
0
  if (key->external) {
463
0
    priv.nelements = 0;
464
0
    CLEANUP(dst__privstruct_writefile(key, &priv, directory));
465
0
  }
466
467
0
  if (key->keydata.pkeypair.priv == NULL) {
468
0
    CLEANUP(DST_R_NULLKEY);
469
0
  }
470
471
0
  keylen = opensslecdsa_key_alg_to_publickey_size(key->key_alg) / 2;
472
0
  INSIST(keylen <= sizeof(buf));
473
474
0
  pkey = key->keydata.pkeypair.priv;
475
476
0
  i = 0;
477
0
  switch (key->key_alg) {
478
0
  case DST_ALG_ECDSA256:
479
0
    result = isc_ossl_wrap_p256_secret_region(
480
0
      pkey, (isc_region_t){ buf, keylen });
481
0
    break;
482
0
  case DST_ALG_ECDSA384:
483
0
    result = isc_ossl_wrap_p384_secret_region(
484
0
      pkey, (isc_region_t){ buf, keylen });
485
0
    break;
486
0
  default:
487
0
    UNREACHABLE();
488
0
  }
489
490
0
  if (result == ISC_R_SUCCESS) {
491
0
    priv.elements[i].tag = TAG_ECDSA_PRIVATEKEY;
492
0
    priv.elements[i].length = keylen;
493
0
    priv.elements[i].data = buf;
494
0
    i++;
495
0
  }
496
497
0
  if (key->label != NULL) {
498
0
    priv.elements[i].tag = TAG_ECDSA_LABEL;
499
0
    priv.elements[i].length = (unsigned short)strlen(key->label) +
500
0
            1;
501
0
    priv.elements[i].data = (unsigned char *)key->label;
502
0
    i++;
503
0
  }
504
505
0
  priv.nelements = i;
506
0
  result = dst__privstruct_writefile(key, &priv, directory);
507
508
0
cleanup:
509
0
  isc_safe_memwipe(buf, keylen);
510
0
  return result;
511
0
}
512
513
static isc_result_t
514
opensslecdsa_fromlabel(dst_key_t *key, const char *label, const char *pin);
515
516
static isc_result_t
517
0
opensslecdsa_parse(dst_key_t *key, isc_lex_t *lexer, dst_key_t *pub) {
518
0
  dst_private_t priv;
519
0
  isc_result_t result;
520
0
  isc_region_t r;
521
0
  EVP_PKEY *pkey = NULL;
522
0
  const char *label = NULL;
523
0
  int i, privkey_index = -1;
524
525
0
  REQUIRE(opensslecdsa_valid_key_alg(key->key_alg));
526
527
  /* read private key file */
528
0
  CHECK(dst__privstruct_parse(key, DST_ALG_ECDSA256, lexer, key->mctx,
529
0
            &priv));
530
531
0
  if (key->external) {
532
0
    if (priv.nelements != 0 || pub == NULL) {
533
0
      CLEANUP(dst__openssl_toresult(DST_R_INVALIDPRIVATEKEY));
534
0
    }
535
0
    key->keydata.pkeypair.priv = pub->keydata.pkeypair.priv;
536
0
    key->keydata.pkeypair.pub = pub->keydata.pkeypair.pub;
537
0
    pub->keydata.pkeypair.priv = NULL;
538
0
    pub->keydata.pkeypair.pub = NULL;
539
0
    CLEANUP(ISC_R_SUCCESS);
540
0
  }
541
542
0
  for (i = 0; i < priv.nelements; i++) {
543
0
    switch (priv.elements[i].tag) {
544
0
    case TAG_ECDSA_ENGINE:
545
      /* The Engine: tag is explicitly ignored */
546
0
      break;
547
0
    case TAG_ECDSA_LABEL:
548
      /* NUL terminated data? */
549
0
      CHECK(dst__privelement_is_nul_terminated(
550
0
        &priv.elements[i]));
551
0
      label = (char *)priv.elements[i].data;
552
0
      break;
553
0
    case TAG_ECDSA_PRIVATEKEY:
554
0
      privkey_index = i;
555
0
      break;
556
0
    default:
557
0
      break;
558
0
    }
559
0
  }
560
561
0
  if (label != NULL) {
562
0
    CHECK(opensslecdsa_fromlabel(key, label, NULL));
563
    /* Check that the public component matches if given */
564
0
    if (pub != NULL && EVP_PKEY_eq(key->keydata.pkeypair.pub,
565
0
                 pub->keydata.pkeypair.pub) != 1)
566
0
    {
567
0
      CLEANUP(DST_R_INVALIDPRIVATEKEY);
568
0
    }
569
0
    CLEANUP(ISC_R_SUCCESS);
570
0
  }
571
572
0
  if (privkey_index < 0) {
573
0
    CLEANUP(dst__openssl_toresult(DST_R_INVALIDPRIVATEKEY));
574
0
  }
575
576
0
  r = (isc_region_t){
577
0
    .base = priv.elements[privkey_index].data,
578
0
    .length = priv.elements[privkey_index].length,
579
0
  };
580
581
0
  switch (key->key_alg) {
582
0
  case DST_ALG_ECDSA256:
583
0
    CHECK(isc_ossl_wrap_load_p256_secret_from_region(r, &pkey));
584
0
    break;
585
0
  case DST_ALG_ECDSA384:
586
0
    CHECK(isc_ossl_wrap_load_p384_secret_from_region(r, &pkey));
587
0
    break;
588
0
  default:
589
0
    UNREACHABLE();
590
0
  }
591
592
  /* Check that the public component matches if given */
593
0
  if (pub != NULL && EVP_PKEY_eq(pkey, pub->keydata.pkeypair.pub) != 1) {
594
0
    CLEANUP(DST_R_INVALIDPRIVATEKEY);
595
0
  }
596
597
0
  key->key_size = EVP_PKEY_bits(pkey);
598
0
  key->keydata.pkeypair.priv = pkey;
599
0
  key->keydata.pkeypair.pub = pkey;
600
0
  pkey = NULL;
601
602
0
cleanup:
603
0
  EVP_PKEY_free(pkey);
604
0
  if (result != ISC_R_SUCCESS) {
605
0
    key->keydata.generic = NULL;
606
0
  }
607
0
  dst__privstruct_free(&priv, key->mctx);
608
0
  isc_safe_memwipe(&priv, sizeof(priv));
609
610
0
  return result;
611
0
}
612
613
static isc_result_t
614
0
opensslecdsa_fromlabel(dst_key_t *key, const char *label, const char *pin) {
615
0
  EVP_PKEY *privpkey = NULL, *pubpkey = NULL;
616
0
  isc_result_t result;
617
618
0
  REQUIRE(opensslecdsa_valid_key_alg(key->key_alg));
619
0
  UNUSED(pin);
620
621
0
  CHECK(dst__openssl_fromlabel(EVP_PKEY_EC, label, pin, &pubpkey,
622
0
             &privpkey));
623
624
0
  switch (key->key_alg) {
625
0
  case DST_ALG_ECDSA256:
626
0
    CHECK(isc_ossl_wrap_validate_p256_pkey(privpkey));
627
0
    CHECK(isc_ossl_wrap_validate_p256_pkey(pubpkey));
628
0
    break;
629
0
  case DST_ALG_ECDSA384:
630
0
    CHECK(isc_ossl_wrap_validate_p384_pkey(privpkey));
631
0
    CHECK(isc_ossl_wrap_validate_p384_pkey(pubpkey));
632
0
    break;
633
0
  default:
634
0
    UNREACHABLE();
635
0
  }
636
637
0
  key->label = isc_mem_strdup(key->mctx, label);
638
0
  key->key_size = EVP_PKEY_bits(privpkey);
639
0
  key->keydata.pkeypair.priv = privpkey;
640
0
  key->keydata.pkeypair.pub = pubpkey;
641
0
  privpkey = NULL;
642
0
  pubpkey = NULL;
643
644
0
cleanup:
645
0
  EVP_PKEY_free(privpkey);
646
0
  EVP_PKEY_free(pubpkey);
647
0
  return result;
648
0
}
649
650
static dst_func_t opensslecdsa_functions = {
651
  .createctx = opensslecdsa_createctx,
652
  .destroyctx = opensslecdsa_destroyctx,
653
  .adddata = opensslecdsa_adddata,
654
  .sign = opensslecdsa_sign,
655
  .verify = opensslecdsa_verify,
656
  .compare = dst__openssl_keypair_compare,
657
  .generate = opensslecdsa_generate,
658
  .isprivate = dst__openssl_keypair_isprivate,
659
  .destroy = dst__openssl_keypair_destroy,
660
  .todns = opensslecdsa_todns,
661
  .fromdns = opensslecdsa_fromdns,
662
  .tofile = opensslecdsa_tofile,
663
  .parse = opensslecdsa_parse,
664
  .fromlabel = opensslecdsa_fromlabel,
665
};
666
667
void
668
44
dst__opensslecdsa_init(dst_func_t **funcp) {
669
44
  REQUIRE(funcp != NULL);
670
671
44
  if (*funcp == NULL) {
672
44
    *funcp = &opensslecdsa_functions;
673
44
  }
674
44
}