Coverage Report

Created: 2026-07-16 07:05

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/bind9/lib/isc/ossl_wrap/ossl3.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
#include <stdbool.h>
15
#include <string.h>
16
17
#include <openssl/bn.h>
18
#include <openssl/core_names.h>
19
#include <openssl/ec.h>
20
#include <openssl/err.h>
21
#include <openssl/evp.h>
22
#include <openssl/param_build.h>
23
#include <openssl/rsa.h>
24
25
#include <isc/crypto.h>
26
#include <isc/ossl_wrap.h>
27
#include <isc/region.h>
28
#include <isc/util.h>
29
30
#define MAX_PUBLIC_KEY_SIZE 96
31
#define MAX_SECRET_KEY_SIZE 48
32
33
#define OSSL_WRAP_ERROR(fn)                                        \
34
  isc__ossl_wrap_logged_toresult(                            \
35
    ISC_LOGCATEGORY_GENERAL, ISC_LOGMODULE_CRYPTO, fn, \
36
    ISC_R_CRYPTOFAILURE, __FILE__, __LINE__)
37
38
#define P_CURVE_IMPL(curve, nid)                                               \
39
0
  isc_result_t isc_ossl_wrap_generate_##curve##_key(EVP_PKEY **pkeyp) {  \
40
0
    REQUIRE(pkeyp != NULL && *pkeyp == NULL);                      \
41
0
    return generate_ec_key(pkeyp, curve##_params);                 \
42
0
  }                                                                      \
Unexecuted instantiation: isc_ossl_wrap_generate_p256_key
Unexecuted instantiation: isc_ossl_wrap_generate_p384_key
43
  isc_result_t isc_ossl_wrap_generate_pkcs11_##curve##_key(              \
44
0
    char *uri, EVP_PKEY **pkeyp) {                                 \
45
0
    REQUIRE(pkeyp != NULL && *pkeyp == NULL);                      \
46
0
    REQUIRE(uri != NULL);                                          \
47
0
    return generate_pkcs11_ec_key(uri, pkeyp, nid);                \
48
0
  }                                                                      \
Unexecuted instantiation: isc_ossl_wrap_generate_pkcs11_p256_key
Unexecuted instantiation: isc_ossl_wrap_generate_pkcs11_p384_key
49
0
  isc_result_t isc_ossl_wrap_validate_##curve##_pkey(EVP_PKEY *pkey) {   \
50
0
    REQUIRE(pkey != NULL);                                         \
51
0
    return validate_ec_pkey(pkey, curve##_params);                 \
52
0
  }                                                                      \
Unexecuted instantiation: isc_ossl_wrap_validate_p256_pkey
Unexecuted instantiation: isc_ossl_wrap_validate_p384_pkey
53
  isc_result_t isc_ossl_wrap_load_##curve##_public_from_region(          \
54
0
    isc_region_t region, EVP_PKEY **pkeyp) {                       \
55
0
    REQUIRE(region.base != NULL &&                                 \
56
0
      region.length <= MAX_PUBLIC_KEY_SIZE);                 \
57
0
    REQUIRE(pkeyp != NULL && *pkeyp == NULL);                      \
58
0
    region.length = curve##_public_key_size;                       \
59
0
    return load_ec_public_from_region(region, pkeyp,               \
60
0
              curve##_params);             \
61
0
  }                                                                      \
Unexecuted instantiation: isc_ossl_wrap_load_p256_public_from_region
Unexecuted instantiation: isc_ossl_wrap_load_p384_public_from_region
62
  isc_result_t isc_ossl_wrap_load_##curve##_secret_from_region(          \
63
0
    isc_region_t region, EVP_PKEY **pkeyp) {                       \
64
0
    REQUIRE(pkeyp != NULL && *pkeyp == NULL);                      \
65
0
    REQUIRE(region.base != NULL &&                                 \
66
0
      region.length >= curve##_secret_key_size);             \
67
0
    region.length = curve##_secret_key_size;                       \
68
0
    return load_ec_secret_from_region(region, pkeyp,               \
69
0
              curve##_params);             \
70
0
  }                                                                      \
Unexecuted instantiation: isc_ossl_wrap_load_p256_secret_from_region
Unexecuted instantiation: isc_ossl_wrap_load_p384_secret_from_region
71
  isc_result_t isc_ossl_wrap_##curve##_public_region(EVP_PKEY *pkey,     \
72
0
                 isc_region_t pub) { \
73
0
    REQUIRE(pkey != NULL);                                         \
74
0
    REQUIRE(pub.base != NULL &&                                    \
75
0
      pub.length >= curve##_public_key_size);                \
76
0
    pub.length = curve##_public_key_size;                          \
77
0
    return ec_public_region(pkey, pub);                            \
78
0
  }                                                                      \
Unexecuted instantiation: isc_ossl_wrap_p256_public_region
Unexecuted instantiation: isc_ossl_wrap_p384_public_region
79
  isc_result_t isc_ossl_wrap_##curve##_secret_region(EVP_PKEY *pkey,     \
80
0
                 isc_region_t sec) { \
81
0
    REQUIRE(pkey != NULL);                                         \
82
0
    REQUIRE(sec.base != NULL &&                                    \
83
0
      sec.length >= curve##_secret_key_size);                \
84
0
    sec.length = curve##_secret_key_size;                          \
85
0
    return ec_secret_region(pkey, sec);                            \
86
0
  }
Unexecuted instantiation: isc_ossl_wrap_p256_secret_region
Unexecuted instantiation: isc_ossl_wrap_p384_secret_region
87
88
static char pkcs11_key_usage[] = "digitalSignature";
89
90
constexpr size_t p256_public_key_size = 64;
91
constexpr size_t p384_public_key_size = 96;
92
93
constexpr size_t p256_secret_key_size = 32;
94
constexpr size_t p384_secret_key_size = 48;
95
96
/*
97
 * "group" MUST be the first parameter, we rely on it to get the group name.
98
 */
99
100
/* clang-format off */
101
static const OSSL_PARAM p256_params[] = {
102
  OSSL_PARAM_utf8_string(OSSL_PKEY_PARAM_GROUP_NAME,
103
             UNCONST("prime256v1"), sizeof("prime256v1") - 1),
104
  OSSL_PARAM_utf8_string(OSSL_PKEY_PARAM_EC_ENCODING,
105
             UNCONST("named_curve"), sizeof("named_curve") - 1),
106
  OSSL_PARAM_utf8_string(OSSL_PKEY_PARAM_EC_POINT_CONVERSION_FORMAT,
107
             UNCONST("uncompressed"), sizeof("uncompressed") - 1),
108
  OSSL_PARAM_END,
109
};
110
111
static const OSSL_PARAM p384_params[] = {
112
  OSSL_PARAM_utf8_string(OSSL_PKEY_PARAM_GROUP_NAME,
113
             UNCONST("secp384r1"), sizeof("secp384r1") - 1),
114
  OSSL_PARAM_utf8_string(OSSL_PKEY_PARAM_EC_ENCODING,
115
             UNCONST("named_curve"), sizeof("named_curve") - 1),
116
  OSSL_PARAM_utf8_string(OSSL_PKEY_PARAM_EC_POINT_CONVERSION_FORMAT,
117
             UNCONST("uncompressed"), sizeof("uncompressed") - 1),
118
  OSSL_PARAM_END,
119
};
120
/* clang-format on */
121
122
static void
123
0
BN_bn2bin_fixed(const BIGNUM *bn, unsigned char *buf, int size) {
124
0
  int bytes = size - BN_num_bytes(bn);
125
126
0
  INSIST(bytes >= 0);
127
128
0
  while (bytes-- > 0) {
129
0
    *buf++ = 0;
130
0
  }
131
0
  BN_bn2bin(bn, buf);
132
0
}
133
134
static int
135
0
rsa_keygen_progress_cb(EVP_PKEY_CTX *ctx) {
136
0
  void (*fptr)(int);
137
138
0
  fptr = EVP_PKEY_CTX_get_app_data(ctx);
139
0
  if (fptr != NULL) {
140
0
    int p = EVP_PKEY_CTX_get_keygen_info(ctx, 0);
141
0
    fptr(p);
142
0
  }
143
0
  return 1;
144
0
}
145
146
static isc_result_t
147
0
generate_ec_key(EVP_PKEY **pkeyp, const OSSL_PARAM *const params) {
148
0
  isc_result_t result;
149
0
  EVP_PKEY_CTX *pctx = NULL;
150
151
0
  pctx = EVP_PKEY_CTX_new_from_name(NULL, "EC", NULL);
152
0
  if (pctx == NULL) {
153
0
    CLEANUP(OSSL_WRAP_ERROR("EVP_PKEY_CTX_new_from_name"));
154
0
  }
155
156
0
  if (EVP_PKEY_keygen_init(pctx) != 1) {
157
0
    CLEANUP(OSSL_WRAP_ERROR("EVP_PKEY_keygen_init"));
158
0
  }
159
160
0
  if (EVP_PKEY_CTX_set_params(pctx, params) != 1) {
161
0
    CLEANUP(OSSL_WRAP_ERROR("EVP_PKEY_CTX_set_params"));
162
0
  }
163
164
  /*
165
   * EVP_PKEY_keygen is an older function now equivalent to
166
   * EVP_PKEY_generate with an additional check that EVP_PKEY_CTX has been
167
   * initialized with EVP_PKEY_keygen_init.
168
   *
169
   * Since we can guarantee such condition we use EVP_PKEY_generate
170
   * directly.
171
   */
172
0
  if (EVP_PKEY_generate(pctx, pkeyp) != 1) {
173
0
    CLEANUP(OSSL_WRAP_ERROR("EVP_PKEY_generate"));
174
0
  }
175
176
0
  result = ISC_R_SUCCESS;
177
178
0
cleanup:
179
0
  EVP_PKEY_CTX_free(pctx);
180
0
  return result;
181
0
}
182
183
static isc_result_t
184
0
generate_pkcs11_ec_key(char *uri, EVP_PKEY **pkeyp, int nid) {
185
0
  isc_result_t result;
186
0
  EVP_PKEY_CTX *pctx;
187
0
  size_t len;
188
189
0
  INSIST(uri != NULL);
190
0
  len = strlen(uri);
191
192
0
  const OSSL_PARAM params[] = {
193
0
    OSSL_PARAM_utf8_string("pkcs11_uri", uri, len),
194
0
    OSSL_PARAM_utf8_string("pkcs11_key_usage", pkcs11_key_usage,
195
0
               sizeof(pkcs11_key_usage) - 1),
196
0
    OSSL_PARAM_END,
197
0
  };
198
199
0
  pctx = EVP_PKEY_CTX_new_from_name(NULL, "EC", "provider=pkcs11");
200
0
  if (pctx == NULL) {
201
0
    CLEANUP(OSSL_WRAP_ERROR("EVP_PKEY_CTX_new_from_name"));
202
0
  }
203
204
0
  if (EVP_PKEY_keygen_init(pctx) != 1) {
205
0
    CLEANUP(OSSL_WRAP_ERROR("EVP_PKEY_keygen_init"));
206
0
  }
207
208
0
  if (EVP_PKEY_CTX_set_params(pctx, params) != 1) {
209
0
    CLEANUP(OSSL_WRAP_ERROR("EVP_PKEY_CTX_set_params"));
210
0
  }
211
212
  /*
213
   * Setting the P-384 curve doesn't work correctly when using:
214
   * OSSL_PARAM_construct_utf8_string("ec_paramgen_curve", "P-384", 0);
215
   *
216
   * Instead use the OpenSSL function to set the curve nid param.
217
   */
218
0
  if (EVP_PKEY_CTX_set_ec_paramgen_curve_nid(pctx, nid) != 1) {
219
0
    CLEANUP(OSSL_WRAP_ERROR("EVP_PKEY_CTX_set_ec_paramgen_curve_"
220
0
          "nid"));
221
0
  }
222
223
  /*
224
   * EVP_PKEY_keygen is an older function now equivalent to
225
   * EVP_PKEY_generate with an additional check that EVP_PKEY_CTX has been
226
   * initialized with EVP_PKEY_keygen_init.
227
   *
228
   * Since we can guarantee such condition we use EVP_PKEY_generate
229
   * directly.
230
   */
231
0
  if (EVP_PKEY_generate(pctx, pkeyp) != 1) {
232
0
    CLEANUP(OSSL_WRAP_ERROR("EVP_PKEY_generate"));
233
0
  }
234
235
0
  result = ISC_R_SUCCESS;
236
237
0
cleanup:
238
0
  EVP_PKEY_CTX_free(pctx);
239
0
  return result;
240
0
}
241
242
static isc_result_t
243
0
generate_pkcs11_eddsa_key(char *uri, EVP_PKEY **pkeyp, const char *keytype) {
244
0
  isc_result_t result;
245
0
  EVP_PKEY_CTX *pctx = NULL;
246
0
  size_t len;
247
248
0
  INSIST(uri != NULL);
249
0
  len = strlen(uri);
250
251
0
  const OSSL_PARAM params[] = {
252
0
    OSSL_PARAM_utf8_string("pkcs11_uri", uri, len),
253
0
    OSSL_PARAM_utf8_string("pkcs11_key_usage", pkcs11_key_usage,
254
0
               sizeof(pkcs11_key_usage) - 1),
255
0
    OSSL_PARAM_END,
256
0
  };
257
258
0
  pctx = EVP_PKEY_CTX_new_from_name(NULL, keytype, "provider=pkcs11");
259
0
  if (pctx == NULL) {
260
0
    CLEANUP(OSSL_WRAP_ERROR("EVP_PKEY_CTX_new_from_name"));
261
0
  }
262
263
0
  if (EVP_PKEY_keygen_init(pctx) != 1) {
264
0
    CLEANUP(OSSL_WRAP_ERROR("EVP_PKEY_keygen_init"));
265
0
  }
266
267
0
  if (EVP_PKEY_CTX_set_params(pctx, params) != 1) {
268
0
    CLEANUP(OSSL_WRAP_ERROR("EVP_PKEY_CTX_set_params"));
269
0
  }
270
271
0
  if (EVP_PKEY_generate(pctx, pkeyp) != 1) {
272
0
    CLEANUP(OSSL_WRAP_ERROR("EVP_PKEY_generate"));
273
0
  }
274
275
0
  result = ISC_R_SUCCESS;
276
277
0
cleanup:
278
0
  EVP_PKEY_CTX_free(pctx);
279
0
  return result;
280
0
}
281
282
isc_result_t
283
0
isc_ossl_wrap_generate_pkcs11_ed25519_key(char *uri, EVP_PKEY **pkeyp) {
284
0
  REQUIRE(pkeyp != NULL && *pkeyp == NULL);
285
0
  REQUIRE(uri != NULL);
286
0
  return generate_pkcs11_eddsa_key(uri, pkeyp, "ED25519");
287
0
}
288
289
isc_result_t
290
0
isc_ossl_wrap_generate_pkcs11_ed448_key(char *uri, EVP_PKEY **pkeyp) {
291
0
  REQUIRE(pkeyp != NULL && *pkeyp == NULL);
292
0
  REQUIRE(uri != NULL);
293
0
  return generate_pkcs11_eddsa_key(uri, pkeyp, "ED448");
294
0
}
295
296
static isc_result_t
297
0
validate_ec_pkey(EVP_PKEY *pkey, const OSSL_PARAM *const curve_params) {
298
0
  isc_result_t result;
299
0
  const char *expected = curve_params[0].data;
300
0
  char actual[64];
301
302
0
  if (EVP_PKEY_get_group_name(pkey, actual, sizeof(actual), NULL) != 1) {
303
0
    CLEANUP(OSSL_WRAP_ERROR("EVP_PKEY_get_group_name"));
304
0
  }
305
306
0
  if (strncmp(expected, actual, curve_params[0].data_size) != 0) {
307
0
    return ISC_R_FAILURE;
308
0
  }
309
310
0
  result = ISC_R_SUCCESS;
311
312
0
cleanup:
313
0
  return result;
314
0
}
315
316
static isc_result_t
317
load_ec_public_from_region(isc_region_t region, EVP_PKEY **pkeyp,
318
0
         const OSSL_PARAM *const curve_params) {
319
0
  isc_result_t result;
320
0
  EVP_PKEY_CTX *pctx = NULL;
321
0
  uint8_t buffer[MAX_PUBLIC_KEY_SIZE + 1];
322
0
  OSSL_PARAM params[] = {
323
0
    curve_params[0], /* group */
324
0
    OSSL_PARAM_octet_string(OSSL_PKEY_PARAM_PUB_KEY, buffer,
325
0
          region.length + 1),
326
0
    OSSL_PARAM_END,
327
0
  };
328
329
0
  buffer[0] = POINT_CONVERSION_UNCOMPRESSED;
330
0
  memmove(buffer + 1, region.base, region.length);
331
332
0
  pctx = EVP_PKEY_CTX_new_from_name(NULL, "EC", NULL);
333
0
  if (pctx == NULL) {
334
0
    CLEANUP(OSSL_WRAP_ERROR("EVP_PKEY_CTX_new_from_name"));
335
0
  }
336
337
0
  if (EVP_PKEY_fromdata_init(pctx) != 1) {
338
0
    CLEANUP(OSSL_WRAP_ERROR("EVP_PKEY_fromdata_init"));
339
0
  }
340
341
0
  if (EVP_PKEY_fromdata(pctx, pkeyp, EVP_PKEY_PUBLIC_KEY, params) != 1) {
342
0
    CLEANUP(OSSL_WRAP_ERROR("EVP_PKEY_fromdata"));
343
0
  }
344
345
0
  result = ISC_R_SUCCESS;
346
347
0
cleanup:
348
0
  EVP_PKEY_CTX_free(pctx);
349
0
  return result;
350
0
}
351
352
static isc_result_t
353
load_ec_secret_from_region(isc_region_t region, EVP_PKEY **pkeyp,
354
0
         const OSSL_PARAM *const curve_params) {
355
0
  uint8_t public[MAX_PUBLIC_KEY_SIZE + 1];
356
0
  OSSL_PARAM_BLD *bld = NULL;
357
0
  OSSL_PARAM *params = NULL;
358
0
  EVP_PKEY_CTX *pctx = NULL;
359
0
  EC_POINT *pub_point = NULL;
360
0
  EC_GROUP *group = NULL;
361
0
  BIGNUM *private = NULL;
362
0
  isc_result_t result;
363
0
  size_t public_len;
364
365
  /*
366
   * OpenSSL requires us to set the public key portion, but since our
367
   * private key file format does not contain it directly, we generate it
368
   * as needed.
369
   */
370
0
  group = EC_GROUP_new_from_params(curve_params, NULL, NULL);
371
0
  if (group == NULL) {
372
0
    CLEANUP(OSSL_WRAP_ERROR("EC_GROUP_new_by_curve_name"));
373
0
  }
374
375
0
  private = BN_bin2bn(region.base, region.length, NULL);
376
0
  if (private == NULL) {
377
0
    CLEANUP(OSSL_WRAP_ERROR("BN_bin2bn"));
378
0
  }
379
380
0
  pub_point = EC_POINT_new(group);
381
0
  if (pub_point == NULL) {
382
0
    CLEANUP(OSSL_WRAP_ERROR("EC_POINT_new"));
383
0
  }
384
385
0
  if (EC_POINT_mul(group, pub_point, private, NULL, NULL, NULL) != 1) {
386
0
    CLEANUP(OSSL_WRAP_ERROR("EC_POINT_mul"));
387
0
  }
388
389
0
  public_len = EC_POINT_point2oct(group, pub_point,
390
0
          POINT_CONVERSION_UNCOMPRESSED, public,
391
0
          sizeof(public), NULL);
392
0
  if (public_len == 0) {
393
0
    CLEANUP(OSSL_WRAP_ERROR("EC_POINT_point2oct"));
394
0
  }
395
396
0
  bld = OSSL_PARAM_BLD_new();
397
0
  if (bld == NULL) {
398
0
    CLEANUP(OSSL_WRAP_ERROR("OSSL_PARAM_BLD_new"));
399
0
  }
400
401
0
  if (OSSL_PARAM_BLD_push_utf8_string(bld, curve_params[0].key,
402
0
              curve_params[0].data,
403
0
              curve_params[0].data_size) != 1)
404
0
  {
405
0
    CLEANUP(OSSL_WRAP_ERROR("OSSL_PARAM_BLD_push_utf8_string"));
406
0
  }
407
408
0
  if (OSSL_PARAM_BLD_push_BN(bld, OSSL_PKEY_PARAM_PRIV_KEY, private) != 1)
409
0
  {
410
0
    CLEANUP(OSSL_WRAP_ERROR("OSSL_PARAM_BLD_push_BN"));
411
0
  }
412
413
0
  if (OSSL_PARAM_BLD_push_octet_string(bld, OSSL_PKEY_PARAM_PUB_KEY,
414
0
               public, public_len) != 1)
415
0
  {
416
0
    CLEANUP(OSSL_WRAP_ERROR("OSSL_PARAM_BLD_push_octet_string"));
417
0
  }
418
419
0
  params = OSSL_PARAM_BLD_to_param(bld);
420
0
  if (params == NULL) {
421
0
    CLEANUP(OSSL_WRAP_ERROR("OSSL_PARAM_BLD_to_param"));
422
0
  }
423
424
0
  pctx = EVP_PKEY_CTX_new_from_name(NULL, "EC", NULL);
425
0
  if (pctx == NULL) {
426
0
    CLEANUP(OSSL_WRAP_ERROR("EVP_PKEY_CTX_new_from_name"));
427
0
  }
428
429
0
  if (EVP_PKEY_fromdata_init(pctx) != 1) {
430
0
    CLEANUP(OSSL_WRAP_ERROR("EVP_PKEY_fromdata_init"));
431
0
  }
432
433
0
  if (EVP_PKEY_fromdata(pctx, pkeyp, EVP_PKEY_KEYPAIR, params) != 1) {
434
0
    CLEANUP(OSSL_WRAP_ERROR("EVP_PKEY_fromdata"));
435
0
  }
436
437
0
  result = ISC_R_SUCCESS;
438
439
0
cleanup:
440
0
  OSSL_PARAM_free(params);
441
0
  OSSL_PARAM_BLD_free(bld);
442
0
  EC_POINT_free(pub_point);
443
0
  BN_clear_free(private);
444
0
  EC_GROUP_free(group);
445
0
  EVP_PKEY_CTX_free(pctx);
446
0
  return result;
447
0
}
448
449
static isc_result_t
450
0
ec_public_region(EVP_PKEY *pkey, isc_region_t pub) {
451
0
  isc_result_t result;
452
0
  BIGNUM *x = NULL;
453
0
  BIGNUM *y = NULL;
454
455
0
  if (EVP_PKEY_get_bn_param(pkey, OSSL_PKEY_PARAM_EC_PUB_X, &x) != 1) {
456
0
    CLEANUP(OSSL_WRAP_ERROR("EVP_PKEY_get_bn_param"));
457
0
  }
458
459
0
  if (EVP_PKEY_get_bn_param(pkey, OSSL_PKEY_PARAM_EC_PUB_Y, &y) != 1) {
460
0
    CLEANUP(OSSL_WRAP_ERROR("EVP_PKEY_get_bn_param"));
461
0
  }
462
463
0
  BN_bn2bin_fixed(x, &pub.base[0], pub.length / 2);
464
0
  BN_bn2bin_fixed(y, &pub.base[pub.length / 2], pub.length / 2);
465
466
0
  result = ISC_R_SUCCESS;
467
468
0
cleanup:
469
0
  BN_clear_free(x);
470
0
  BN_clear_free(y);
471
0
  return result;
472
0
}
473
474
static isc_result_t
475
0
ec_secret_region(EVP_PKEY *pkey, isc_region_t sec) {
476
0
  isc_result_t result;
477
0
  BIGNUM *priv = NULL;
478
479
0
  if (EVP_PKEY_get_bn_param(pkey, OSSL_PKEY_PARAM_PRIV_KEY, &priv) != 1) {
480
0
    CLEANUP(OSSL_WRAP_ERROR("EVP_PKEY_get_bn_param"));
481
0
  }
482
483
0
  BN_bn2bin_fixed(priv, sec.base, sec.length);
484
485
0
  result = ISC_R_SUCCESS;
486
487
0
cleanup:
488
0
  BN_clear_free(priv);
489
0
  return result;
490
0
}
491
492
P_CURVE_IMPL(p256, NID_X9_62_prime256v1);
493
P_CURVE_IMPL(p384, NID_secp384r1);
494
495
isc_result_t
496
0
isc_ossl_wrap_ecdsa_set_deterministic(EVP_PKEY_CTX *pctx, const char *hash) {
497
0
  unsigned int rfc6979 = 1;
498
0
  isc_result_t result;
499
0
  OSSL_PARAM params[3] = {
500
0
    OSSL_PARAM_construct_utf8_string("digest", UNCONST(hash), 0),
501
0
    OSSL_PARAM_construct_uint("nonce-type", &rfc6979),
502
0
    OSSL_PARAM_END,
503
0
  };
504
505
0
  REQUIRE(pctx != NULL && hash != NULL);
506
507
0
  if (EVP_PKEY_CTX_set_params(pctx, params) != 1) {
508
0
    CLEANUP(OSSL_WRAP_ERROR("EVP_PKEY_CTX_set_params"));
509
0
  }
510
511
0
  result = ISC_R_SUCCESS;
512
513
0
cleanup:
514
0
  return result;
515
0
}
516
517
isc_result_t
518
isc_ossl_wrap_generate_rsa_key(void (*callback)(int), size_t bit_size,
519
0
             EVP_PKEY **pkeyp) {
520
0
  isc_result_t result;
521
0
  EVP_PKEY_CTX *ctx;
522
0
  uint32_t e = 65537;
523
524
0
  REQUIRE(pkeyp != NULL && *pkeyp == NULL);
525
526
  /*
527
   * https://docs.openssl.org/master/man7/EVP_PKEY-RSA/#rsa-key-generation-parameters
528
   */
529
0
  const OSSL_PARAM params[3] = {
530
0
    OSSL_PARAM_uint(OSSL_PKEY_PARAM_RSA_E, &e),
531
0
    OSSL_PARAM_size_t(OSSL_PKEY_PARAM_RSA_BITS, &bit_size),
532
0
    OSSL_PARAM_END,
533
0
  };
534
535
0
  ctx = EVP_PKEY_CTX_new_from_name(NULL, "RSA", NULL);
536
0
  if (ctx == NULL) {
537
0
    CLEANUP(OSSL_WRAP_ERROR("EVP_PKEY_CTX_new_from_name"));
538
0
  }
539
540
0
  if (EVP_PKEY_keygen_init(ctx) != 1) {
541
0
    CLEANUP(OSSL_WRAP_ERROR("EVP_PKEY_keygen_init"));
542
0
  }
543
544
0
  if (EVP_PKEY_CTX_set_params(ctx, params) != 1) {
545
0
    CLEANUP(OSSL_WRAP_ERROR("EVP_PKEY_CTX_set_params"));
546
0
  }
547
548
0
  if (callback != NULL) {
549
0
    EVP_PKEY_CTX_set_app_data(ctx, (void *)callback);
550
0
    EVP_PKEY_CTX_set_cb(ctx, rsa_keygen_progress_cb);
551
0
  }
552
553
  /*
554
   * EVP_PKEY_keygen is an older function now equivalent to
555
   * EVP_PKEY_generate with an additional check that EVP_PKEY_CTX has been
556
   * initialized with EVP_PKEY_keygen_init.
557
   *
558
   * Since we can guarantee such condition we use EVP_PKEY_generate
559
   * directly.
560
   */
561
0
  if (EVP_PKEY_generate(ctx, pkeyp) != 1) {
562
0
    CLEANUP(OSSL_WRAP_ERROR("EVP_PKEY_keygen"));
563
0
  }
564
565
0
  result = ISC_R_SUCCESS;
566
567
0
cleanup:
568
0
  EVP_PKEY_CTX_free(ctx);
569
0
  return result;
570
0
}
571
572
isc_result_t
573
isc_ossl_wrap_generate_pkcs11_rsa_key(char *uri, size_t bit_size,
574
0
              EVP_PKEY **pkeyp) {
575
0
  EVP_PKEY_CTX *ctx = NULL;
576
0
  isc_result_t result;
577
0
  int status;
578
0
  size_t len;
579
580
0
  REQUIRE(uri != NULL);
581
0
  REQUIRE(pkeyp != NULL && *pkeyp == NULL);
582
583
0
  len = strlen(uri);
584
0
  INSIST(len != 0);
585
586
  /* NUL-terminator should be left out */
587
0
  const OSSL_PARAM params[] = {
588
0
    OSSL_PARAM_utf8_string("pkcs11_uri", uri, len),
589
0
    OSSL_PARAM_utf8_string("pkcs11_key_usage", pkcs11_key_usage,
590
0
               sizeof(pkcs11_key_usage) - 1),
591
0
    OSSL_PARAM_size_t(OSSL_PKEY_PARAM_RSA_BITS, &bit_size),
592
0
    OSSL_PARAM_END,
593
0
  };
594
595
0
  ctx = EVP_PKEY_CTX_new_from_name(NULL, "RSA", "provider=pkcs11");
596
0
  if (ctx == NULL) {
597
0
    CLEANUP(OSSL_WRAP_ERROR("EVP_PKEY_CTX_new_from_name"));
598
0
  }
599
600
0
  status = EVP_PKEY_keygen_init(ctx);
601
0
  if (status != 1) {
602
0
    CLEANUP(OSSL_WRAP_ERROR("EVP_PKEY_keygen_init"));
603
0
  }
604
605
0
  status = EVP_PKEY_CTX_set_params(ctx, params);
606
0
  if (status != 1) {
607
0
    CLEANUP(OSSL_WRAP_ERROR("EVP_PKEY_CTX_set_params"));
608
0
  }
609
610
  /*
611
   * EVP_PKEY_keygen is an older function now equivalent to
612
   * EVP_PKEY_generate with an additional check that EVP_PKEY_CTX has been
613
   * initialized with EVP_PKEY_keygen_init.
614
   *
615
   * Since we can guarantee such condition we use EVP_PKEY_generate
616
   * directly.
617
   */
618
0
  status = EVP_PKEY_generate(ctx, pkeyp);
619
0
  if (status != 1) {
620
0
    CLEANUP(OSSL_WRAP_ERROR("EVP_PKEY_generate"));
621
0
  }
622
623
0
  result = ISC_R_SUCCESS;
624
625
0
cleanup:
626
0
  EVP_PKEY_CTX_free(ctx);
627
0
  return result;
628
0
}
629
630
bool
631
9
isc_ossl_wrap_rsa_exponent_is_allowed(EVP_PKEY *pkey) {
632
9
  BIGNUM *e = NULL;
633
9
  BIGNUM *emin = NULL;
634
9
  BIGNUM *emax = NULL;
635
9
  bool ok = false;
636
637
9
  if (EVP_PKEY_get_bn_param(pkey, OSSL_PKEY_PARAM_RSA_E, &e) != 1) {
638
0
    goto cleanup;
639
0
  }
640
641
9
  emin = BN_new();
642
9
  if (emin == NULL || !BN_set_word(emin, 3)) {
643
0
    goto cleanup;
644
0
  }
645
9
  if (BN_hex2bn(&emax, "100000001") == 0) {
646
0
    goto cleanup;
647
0
  }
648
649
9
  ok = BN_is_odd(e) && BN_cmp(e, emin) >= 0 && BN_cmp(e, emax) <= 0;
650
651
9
cleanup:
652
9
  BN_free(e);
653
9
  BN_free(emin);
654
9
  BN_free(emax);
655
9
  return ok;
656
9
}
657
658
bool
659
isc_ossl_wrap_rsa_modulus_bits_in_range(EVP_PKEY *pkey, size_t min,
660
9
          size_t max) {
661
9
  REQUIRE(pkey != NULL);
662
663
9
  int bits = EVP_PKEY_bits(pkey);
664
9
  return bits > 0 && (size_t)bits >= min && (size_t)bits <= max;
665
9
}
666
667
isc_result_t
668
isc_ossl_wrap_rsa_public_components(EVP_PKEY *pkey,
669
0
            isc_ossl_wrap_rsa_components_t *c) {
670
0
  isc_result_t result;
671
672
0
  REQUIRE(pkey != NULL);
673
0
  REQUIRE(c != NULL && c->e == NULL && c->n == NULL);
674
675
0
  c->needs_cleanup = true;
676
677
0
  if (EVP_PKEY_get_bn_param(pkey, OSSL_PKEY_PARAM_RSA_E, &c->e) != 1) {
678
0
    CLEANUP(OSSL_WRAP_ERROR("EVP_PKEY_get_bn_param"));
679
0
  }
680
681
0
  if (EVP_PKEY_get_bn_param(pkey, OSSL_PKEY_PARAM_RSA_N, &c->n) != 1) {
682
0
    CLEANUP(OSSL_WRAP_ERROR("EVP_PKEY_get_bn_param"));
683
0
  }
684
685
0
  result = ISC_R_SUCCESS;
686
687
0
cleanup:
688
0
  return result;
689
0
}
690
691
isc_result_t
692
isc_ossl_wrap_rsa_secret_components(EVP_PKEY *pkey,
693
0
            isc_ossl_wrap_rsa_components_t *c) {
694
0
  REQUIRE(pkey != NULL);
695
0
  REQUIRE(c != NULL && c->d == NULL && c->p == NULL && c->q == NULL &&
696
0
    c->dmp1 == NULL && c->dmq1 == NULL && c->iqmp == NULL);
697
698
0
  c->needs_cleanup = true;
699
700
  /*
701
   * NOTE: Errors regarding private compoments are ignored.
702
   *
703
   * OpenSSL allows omitting the parameters for CRT based calculations
704
   * (factors, exponents, coefficients). Only the 'd'  parameter is
705
   * mandatory for software keys.
706
   *
707
   * However, for a label based keys, all private key component queries
708
   * can fail if they key is e.g. on a hardware device.
709
   */
710
0
  (void)EVP_PKEY_get_bn_param(pkey, OSSL_PKEY_PARAM_RSA_D, &c->d);
711
0
  (void)EVP_PKEY_get_bn_param(pkey, OSSL_PKEY_PARAM_RSA_FACTOR1, &c->p);
712
0
  (void)EVP_PKEY_get_bn_param(pkey, OSSL_PKEY_PARAM_RSA_FACTOR2, &c->q);
713
0
  (void)EVP_PKEY_get_bn_param(pkey, OSSL_PKEY_PARAM_RSA_EXPONENT1,
714
0
            &c->dmp1);
715
0
  (void)EVP_PKEY_get_bn_param(pkey, OSSL_PKEY_PARAM_RSA_EXPONENT2,
716
0
            &c->dmq1);
717
0
  (void)EVP_PKEY_get_bn_param(pkey, OSSL_PKEY_PARAM_RSA_COEFFICIENT1,
718
0
            &c->iqmp);
719
720
0
  ERR_clear_error();
721
722
0
  return ISC_R_SUCCESS;
723
0
}
724
725
isc_result_t
726
isc_ossl_wrap_load_rsa_public_from_components(isc_ossl_wrap_rsa_components_t *c,
727
211
                EVP_PKEY **pkeyp) {
728
211
  OSSL_PARAM_BLD *bld = NULL;
729
211
  EVP_PKEY_CTX *pctx = NULL;
730
211
  OSSL_PARAM *params = NULL;
731
211
  isc_result_t result;
732
733
211
  REQUIRE(pkeyp != NULL && *pkeyp == NULL);
734
211
  REQUIRE(c != NULL && c->n != NULL && c->e != NULL);
735
736
211
  bld = OSSL_PARAM_BLD_new();
737
211
  if (bld == NULL) {
738
0
    CLEANUP(OSSL_WRAP_ERROR("OSSL_PARAM_BLD_new"));
739
0
  }
740
741
211
  if (OSSL_PARAM_BLD_push_BN(bld, OSSL_PKEY_PARAM_RSA_N, c->n) != 1) {
742
0
    CLEANUP(OSSL_WRAP_ERROR("OSSL_PARAM_BLD_push_BN"));
743
0
  }
744
745
211
  if (OSSL_PARAM_BLD_push_BN(bld, OSSL_PKEY_PARAM_RSA_E, c->e) != 1) {
746
0
    CLEANUP(OSSL_WRAP_ERROR("OSSL_PARAM_BLD_push_BN"));
747
0
  }
748
749
211
  params = OSSL_PARAM_BLD_to_param(bld);
750
211
  if (params == NULL) {
751
0
    CLEANUP(OSSL_WRAP_ERROR("OSSL_PARAM_BLD_to_param"));
752
0
  }
753
754
211
  pctx = EVP_PKEY_CTX_new_from_name(NULL, "RSA", NULL);
755
211
  if (pctx == NULL) {
756
0
    CLEANUP(OSSL_WRAP_ERROR("EVP_PKEY_CTX_new_from_name"));
757
0
  }
758
759
211
  if (EVP_PKEY_fromdata_init(pctx) != 1) {
760
0
    CLEANUP(OSSL_WRAP_ERROR("EVP_PKEY_fromdata_init"));
761
0
  }
762
763
211
  if (EVP_PKEY_fromdata(pctx, pkeyp, EVP_PKEY_PUBLIC_KEY, params) != 1) {
764
0
    CLEANUP(OSSL_WRAP_ERROR("EVP_PKEY_fromdata"));
765
0
  }
766
767
211
  result = ISC_R_SUCCESS;
768
769
211
cleanup:
770
211
  EVP_PKEY_CTX_free(pctx);
771
211
  OSSL_PARAM_free(params);
772
211
  OSSL_PARAM_BLD_free(bld);
773
211
  return result;
774
211
}
775
776
isc_result_t
777
isc_ossl_wrap_load_rsa_secret_from_components(isc_ossl_wrap_rsa_components_t *c,
778
0
                EVP_PKEY **pkeyp) {
779
0
  isc_result_t result;
780
0
  OSSL_PARAM_BLD *bld = NULL;
781
0
  EVP_PKEY_CTX *pctx = NULL;
782
0
  OSSL_PARAM *params = NULL;
783
784
0
  REQUIRE(pkeyp != NULL && *pkeyp == NULL);
785
786
0
  bld = OSSL_PARAM_BLD_new();
787
0
  if (bld == NULL) {
788
0
    CLEANUP(OSSL_WRAP_ERROR("OSSL_PARAM_BLD_new"));
789
0
  }
790
791
0
  if (OSSL_PARAM_BLD_push_BN(bld, OSSL_PKEY_PARAM_RSA_N, c->n) != 1) {
792
0
    CLEANUP(OSSL_WRAP_ERROR("OSSL_PARAM_BLD_push_BN"));
793
0
  }
794
795
0
  if (OSSL_PARAM_BLD_push_BN(bld, OSSL_PKEY_PARAM_RSA_E, c->e) != 1) {
796
0
    CLEANUP(OSSL_WRAP_ERROR("OSSL_PARAM_BLD_push_BN"));
797
0
  }
798
799
0
  if (c->d != NULL &&
800
0
      OSSL_PARAM_BLD_push_BN(bld, OSSL_PKEY_PARAM_RSA_D, c->d) != 1)
801
0
  {
802
0
    CLEANUP(OSSL_WRAP_ERROR("OSSL_PARAM_BLD_push_BN"));
803
0
  }
804
805
0
  if (c->p != NULL &&
806
0
      OSSL_PARAM_BLD_push_BN(bld, OSSL_PKEY_PARAM_RSA_FACTOR1, c->p) != 1)
807
0
  {
808
0
    CLEANUP(OSSL_WRAP_ERROR("OSSL_PARAM_BLD_push_BN"));
809
0
  }
810
811
0
  if (c->q != NULL &&
812
0
      OSSL_PARAM_BLD_push_BN(bld, OSSL_PKEY_PARAM_RSA_FACTOR2, c->q) != 1)
813
0
  {
814
0
    CLEANUP(OSSL_WRAP_ERROR("OSSL_PARAM_BLD_push_BN"));
815
0
  }
816
817
0
  if (c->dmp1 != NULL &&
818
0
      OSSL_PARAM_BLD_push_BN(bld, OSSL_PKEY_PARAM_RSA_EXPONENT1,
819
0
           c->dmp1) != 1)
820
0
  {
821
0
    CLEANUP(OSSL_WRAP_ERROR("OSSL_PARAM_BLD_push_BN"));
822
0
  }
823
824
0
  if (c->dmq1 != NULL &&
825
0
      OSSL_PARAM_BLD_push_BN(bld, OSSL_PKEY_PARAM_RSA_EXPONENT2,
826
0
           c->dmq1) != 1)
827
0
  {
828
0
    CLEANUP(OSSL_WRAP_ERROR("OSSL_PARAM_BLD_push_BN"));
829
0
  }
830
831
0
  if (c->iqmp != NULL &&
832
0
      OSSL_PARAM_BLD_push_BN(bld, OSSL_PKEY_PARAM_RSA_COEFFICIENT1,
833
0
           c->iqmp) != 1)
834
0
  {
835
0
    CLEANUP(OSSL_WRAP_ERROR("OSSL_PARAM_BLD_push_BN"));
836
0
  }
837
838
0
  params = OSSL_PARAM_BLD_to_param(bld);
839
0
  if (params == NULL) {
840
0
    CLEANUP(OSSL_WRAP_ERROR("OSSL_PARAM_BLD_to_param"));
841
0
  }
842
843
0
  pctx = EVP_PKEY_CTX_new_from_name(NULL, "RSA", NULL);
844
0
  if (pctx == NULL) {
845
0
    CLEANUP(OSSL_WRAP_ERROR("EVP_PKEY_CTX_new_from_name"));
846
0
  }
847
848
0
  if (EVP_PKEY_fromdata_init(pctx) != 1) {
849
0
    CLEANUP(OSSL_WRAP_ERROR("EVP_PKEY_fromdata_init"));
850
0
  }
851
852
0
  if (EVP_PKEY_fromdata(pctx, pkeyp, EVP_PKEY_KEYPAIR, params) != 1) {
853
0
    CLEANUP(OSSL_WRAP_ERROR("EVP_PKEY_fromdata"));
854
0
  }
855
856
0
  result = ISC_R_SUCCESS;
857
858
0
cleanup:
859
0
  EVP_PKEY_CTX_free(pctx);
860
0
  OSSL_PARAM_free(params);
861
0
  OSSL_PARAM_BLD_free(bld);
862
0
  return result;
863
0
}