Coverage Report

Created: 2026-03-07 06:55

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
validate_ec_pkey(EVP_PKEY *pkey, const OSSL_PARAM *const curve_params) {
244
0
  isc_result_t result;
245
0
  const char *expected = curve_params[0].data;
246
0
  char actual[64];
247
248
0
  if (EVP_PKEY_get_group_name(pkey, actual, sizeof(actual), NULL) != 1) {
249
0
    CLEANUP(OSSL_WRAP_ERROR("EVP_PKEY_get_group_name"));
250
0
  }
251
252
0
  if (strncmp(expected, actual, curve_params[0].data_size) != 0) {
253
0
    return ISC_R_FAILURE;
254
0
  }
255
256
0
  result = ISC_R_SUCCESS;
257
258
0
cleanup:
259
0
  return result;
260
0
}
261
262
static isc_result_t
263
load_ec_public_from_region(isc_region_t region, EVP_PKEY **pkeyp,
264
0
         const OSSL_PARAM *const curve_params) {
265
0
  isc_result_t result;
266
0
  EVP_PKEY_CTX *pctx = NULL;
267
0
  uint8_t buffer[MAX_PUBLIC_KEY_SIZE + 1];
268
0
  OSSL_PARAM params[] = {
269
0
    curve_params[0], /* group */
270
0
    OSSL_PARAM_octet_string(OSSL_PKEY_PARAM_PUB_KEY, buffer,
271
0
          region.length + 1),
272
0
    OSSL_PARAM_END,
273
0
  };
274
275
0
  buffer[0] = POINT_CONVERSION_UNCOMPRESSED;
276
0
  memmove(buffer + 1, region.base, region.length);
277
278
0
  pctx = EVP_PKEY_CTX_new_from_name(NULL, "EC", NULL);
279
0
  if (pctx == NULL) {
280
0
    CLEANUP(OSSL_WRAP_ERROR("EVP_PKEY_CTX_new_from_name"));
281
0
  }
282
283
0
  if (EVP_PKEY_fromdata_init(pctx) != 1) {
284
0
    CLEANUP(OSSL_WRAP_ERROR("EVP_PKEY_fromdata_init"));
285
0
  }
286
287
0
  if (EVP_PKEY_fromdata(pctx, pkeyp, EVP_PKEY_PUBLIC_KEY, params) != 1) {
288
0
    CLEANUP(OSSL_WRAP_ERROR("EVP_PKEY_fromdata"));
289
0
  }
290
291
0
  result = ISC_R_SUCCESS;
292
293
0
cleanup:
294
0
  EVP_PKEY_CTX_free(pctx);
295
0
  return result;
296
0
}
297
298
static isc_result_t
299
load_ec_secret_from_region(isc_region_t region, EVP_PKEY **pkeyp,
300
0
         const OSSL_PARAM *const curve_params) {
301
0
  uint8_t public[MAX_PUBLIC_KEY_SIZE + 1];
302
0
  OSSL_PARAM_BLD *bld = NULL;
303
0
  OSSL_PARAM *params = NULL;
304
0
  EVP_PKEY_CTX *pctx = NULL;
305
0
  EC_POINT *pub_point = NULL;
306
0
  EC_GROUP *group = NULL;
307
0
  BIGNUM *private = NULL;
308
0
  isc_result_t result;
309
0
  size_t public_len;
310
311
  /*
312
   * OpenSSL requires us to set the public key portion, but since our
313
   * private key file format does not contain it directly, we generate it
314
   * as needed.
315
   */
316
0
  group = EC_GROUP_new_from_params(curve_params, NULL, NULL);
317
0
  if (group == NULL) {
318
0
    CLEANUP(OSSL_WRAP_ERROR("EC_GROUP_new_by_curve_name"));
319
0
  }
320
321
0
  private = BN_bin2bn(region.base, region.length, NULL);
322
0
  if (private == NULL) {
323
0
    CLEANUP(OSSL_WRAP_ERROR("BN_bin2bn"));
324
0
  }
325
326
0
  pub_point = EC_POINT_new(group);
327
0
  if (pub_point == NULL) {
328
0
    CLEANUP(OSSL_WRAP_ERROR("EC_POINT_new"));
329
0
  }
330
331
0
  if (EC_POINT_mul(group, pub_point, private, NULL, NULL, NULL) != 1) {
332
0
    CLEANUP(OSSL_WRAP_ERROR("EC_POINT_mul"));
333
0
  }
334
335
0
  public_len = EC_POINT_point2oct(group, pub_point,
336
0
          POINT_CONVERSION_UNCOMPRESSED, public,
337
0
          sizeof(public), NULL);
338
0
  if (public_len == 0) {
339
0
    CLEANUP(OSSL_WRAP_ERROR("EC_POINT_point2oct"));
340
0
  }
341
342
0
  bld = OSSL_PARAM_BLD_new();
343
0
  if (bld == NULL) {
344
0
    CLEANUP(OSSL_WRAP_ERROR("OSSL_PARAM_BLD_new"));
345
0
  }
346
347
0
  if (OSSL_PARAM_BLD_push_utf8_string(bld, curve_params[0].key,
348
0
              curve_params[0].data,
349
0
              curve_params[0].data_size) != 1)
350
0
  {
351
0
    CLEANUP(OSSL_WRAP_ERROR("OSSL_PARAM_BLD_push_utf8_string"));
352
0
  }
353
354
0
  if (OSSL_PARAM_BLD_push_BN(bld, OSSL_PKEY_PARAM_PRIV_KEY, private) != 1)
355
0
  {
356
0
    CLEANUP(OSSL_WRAP_ERROR("OSSL_PARAM_BLD_push_BN"));
357
0
  }
358
359
0
  if (OSSL_PARAM_BLD_push_octet_string(bld, OSSL_PKEY_PARAM_PUB_KEY,
360
0
               public, public_len) != 1)
361
0
  {
362
0
    CLEANUP(OSSL_WRAP_ERROR("OSSL_PARAM_BLD_push_octet_string"));
363
0
  }
364
365
0
  params = OSSL_PARAM_BLD_to_param(bld);
366
0
  if (params == NULL) {
367
0
    CLEANUP(OSSL_WRAP_ERROR("OSSL_PARAM_BLD_to_param"));
368
0
  }
369
370
0
  pctx = EVP_PKEY_CTX_new_from_name(NULL, "EC", NULL);
371
0
  if (pctx == NULL) {
372
0
    CLEANUP(OSSL_WRAP_ERROR("EVP_PKEY_CTX_new_from_name"));
373
0
  }
374
375
0
  if (EVP_PKEY_fromdata_init(pctx) != 1) {
376
0
    CLEANUP(OSSL_WRAP_ERROR("EVP_PKEY_fromdata_init"));
377
0
  }
378
379
0
  if (EVP_PKEY_fromdata(pctx, pkeyp, EVP_PKEY_KEYPAIR, params) != 1) {
380
0
    CLEANUP(OSSL_WRAP_ERROR("EVP_PKEY_fromdata"));
381
0
  }
382
383
0
  result = ISC_R_SUCCESS;
384
385
0
cleanup:
386
0
  OSSL_PARAM_free(params);
387
0
  OSSL_PARAM_BLD_free(bld);
388
0
  EC_POINT_free(pub_point);
389
0
  BN_clear_free(private);
390
0
  EC_GROUP_free(group);
391
0
  EVP_PKEY_CTX_free(pctx);
392
0
  return result;
393
0
}
394
395
static isc_result_t
396
0
ec_public_region(EVP_PKEY *pkey, isc_region_t pub) {
397
0
  isc_result_t result;
398
0
  BIGNUM *x = NULL;
399
0
  BIGNUM *y = NULL;
400
401
0
  if (EVP_PKEY_get_bn_param(pkey, OSSL_PKEY_PARAM_EC_PUB_X, &x) != 1) {
402
0
    CLEANUP(OSSL_WRAP_ERROR("EVP_PKEY_get_bn_param"));
403
0
  }
404
405
0
  if (EVP_PKEY_get_bn_param(pkey, OSSL_PKEY_PARAM_EC_PUB_Y, &y) != 1) {
406
0
    CLEANUP(OSSL_WRAP_ERROR("EVP_PKEY_get_bn_param"));
407
0
  }
408
409
0
  BN_bn2bin_fixed(x, &pub.base[0], pub.length / 2);
410
0
  BN_bn2bin_fixed(y, &pub.base[pub.length / 2], pub.length / 2);
411
412
0
  result = ISC_R_SUCCESS;
413
414
0
cleanup:
415
0
  BN_clear_free(x);
416
0
  BN_clear_free(y);
417
0
  return result;
418
0
}
419
420
static isc_result_t
421
0
ec_secret_region(EVP_PKEY *pkey, isc_region_t sec) {
422
0
  isc_result_t result;
423
0
  BIGNUM *priv = NULL;
424
425
0
  if (EVP_PKEY_get_bn_param(pkey, OSSL_PKEY_PARAM_PRIV_KEY, &priv) != 1) {
426
0
    CLEANUP(OSSL_WRAP_ERROR("EVP_PKEY_get_bn_param"));
427
0
  }
428
429
0
  BN_bn2bin_fixed(priv, sec.base, sec.length);
430
431
0
  result = ISC_R_SUCCESS;
432
433
0
cleanup:
434
0
  BN_clear_free(priv);
435
0
  return result;
436
0
}
437
438
P_CURVE_IMPL(p256, NID_X9_62_prime256v1);
439
P_CURVE_IMPL(p384, NID_secp384r1);
440
441
isc_result_t
442
0
isc_ossl_wrap_ecdsa_set_deterministic(EVP_PKEY_CTX *pctx, const char *hash) {
443
0
  unsigned int rfc6979 = 1;
444
0
  isc_result_t result;
445
0
  OSSL_PARAM params[3] = {
446
0
    OSSL_PARAM_construct_utf8_string("digest", UNCONST(hash), 0),
447
0
    OSSL_PARAM_construct_uint("nonce-type", &rfc6979),
448
0
    OSSL_PARAM_END,
449
0
  };
450
451
0
  REQUIRE(pctx != NULL && hash != NULL);
452
453
0
  if (EVP_PKEY_CTX_set_params(pctx, params) != 1) {
454
0
    CLEANUP(OSSL_WRAP_ERROR("EVP_PKEY_CTX_set_params"));
455
0
  }
456
457
0
  result = ISC_R_SUCCESS;
458
459
0
cleanup:
460
0
  return result;
461
0
}
462
463
isc_result_t
464
isc_ossl_wrap_generate_rsa_key(void (*callback)(int), size_t bit_size,
465
0
             EVP_PKEY **pkeyp) {
466
0
  isc_result_t result;
467
0
  EVP_PKEY_CTX *ctx;
468
0
  uint32_t e = 65537;
469
470
0
  REQUIRE(pkeyp != NULL && *pkeyp == NULL);
471
472
  /*
473
   * https://docs.openssl.org/master/man7/EVP_PKEY-RSA/#rsa-key-generation-parameters
474
   */
475
0
  const OSSL_PARAM params[3] = {
476
0
    OSSL_PARAM_uint(OSSL_PKEY_PARAM_RSA_E, &e),
477
0
    OSSL_PARAM_size_t(OSSL_PKEY_PARAM_RSA_BITS, &bit_size),
478
0
    OSSL_PARAM_END,
479
0
  };
480
481
0
  ctx = EVP_PKEY_CTX_new_from_name(NULL, "RSA", NULL);
482
0
  if (ctx == NULL) {
483
0
    CLEANUP(OSSL_WRAP_ERROR("EVP_PKEY_CTX_new_from_name"));
484
0
  }
485
486
0
  if (EVP_PKEY_keygen_init(ctx) != 1) {
487
0
    CLEANUP(OSSL_WRAP_ERROR("EVP_PKEY_keygen_init"));
488
0
  }
489
490
0
  if (EVP_PKEY_CTX_set_params(ctx, params) != 1) {
491
0
    CLEANUP(OSSL_WRAP_ERROR("EVP_PKEY_CTX_set_params"));
492
0
  }
493
494
0
  if (callback != NULL) {
495
0
    EVP_PKEY_CTX_set_app_data(ctx, (void *)callback);
496
0
    EVP_PKEY_CTX_set_cb(ctx, rsa_keygen_progress_cb);
497
0
  }
498
499
  /*
500
   * EVP_PKEY_keygen is an older function now equivalent to
501
   * EVP_PKEY_generate with an additional check that EVP_PKEY_CTX has been
502
   * initialized with EVP_PKEY_keygen_init.
503
   *
504
   * Since we can guarantee such condition we use EVP_PKEY_generate
505
   * directly.
506
   */
507
0
  if (EVP_PKEY_generate(ctx, pkeyp) != 1) {
508
0
    CLEANUP(OSSL_WRAP_ERROR("EVP_PKEY_keygen"));
509
0
  }
510
511
0
  result = ISC_R_SUCCESS;
512
513
0
cleanup:
514
0
  EVP_PKEY_CTX_free(ctx);
515
0
  return result;
516
0
}
517
518
isc_result_t
519
isc_ossl_wrap_generate_pkcs11_rsa_key(char *uri, size_t bit_size,
520
0
              EVP_PKEY **pkeyp) {
521
0
  EVP_PKEY_CTX *ctx = NULL;
522
0
  isc_result_t result;
523
0
  int status;
524
0
  size_t len;
525
526
0
  len = strlen(uri);
527
0
  INSIST(len != 0);
528
529
  /* NUL-terminator should be left out */
530
0
  const OSSL_PARAM params[] = {
531
0
    OSSL_PARAM_utf8_string("pkcs11_uri", uri, len),
532
0
    OSSL_PARAM_utf8_string("pkcs11_key_usage", pkcs11_key_usage,
533
0
               sizeof(pkcs11_key_usage) - 1),
534
0
    OSSL_PARAM_size_t(OSSL_PKEY_PARAM_RSA_BITS, &bit_size),
535
0
    OSSL_PARAM_END,
536
0
  };
537
538
0
  ctx = EVP_PKEY_CTX_new_from_name(NULL, "RSA", "provider=pkcs11");
539
0
  if (ctx == NULL) {
540
0
    CLEANUP(OSSL_WRAP_ERROR("EVP_PKEY_CTX_new_from_name"));
541
0
  }
542
543
0
  status = EVP_PKEY_keygen_init(ctx);
544
0
  if (status != 1) {
545
0
    CLEANUP(OSSL_WRAP_ERROR("EVP_PKEY_keygen_init"));
546
0
  }
547
548
0
  status = EVP_PKEY_CTX_set_params(ctx, params);
549
0
  if (status != 1) {
550
0
    CLEANUP(OSSL_WRAP_ERROR("EVP_PKEY_CTX_set_params"));
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
  status = EVP_PKEY_generate(ctx, pkeyp);
562
0
  if (status != 1) {
563
0
    CLEANUP(OSSL_WRAP_ERROR("EVP_PKEY_generate"));
564
0
  }
565
566
0
  result = ISC_R_SUCCESS;
567
568
0
cleanup:
569
0
  EVP_PKEY_CTX_free(ctx);
570
0
  return result;
571
0
}
572
573
bool
574
10
isc_ossl_wrap_rsa_key_bits_leq(EVP_PKEY *pkey, size_t limit) {
575
10
  size_t bits = SIZE_MAX;
576
10
  BIGNUM *e = NULL;
577
10
  if (EVP_PKEY_get_bn_param(pkey, OSSL_PKEY_PARAM_RSA_E, &e) == 1) {
578
10
    bits = BN_num_bits(e);
579
10
    BN_free(e);
580
10
  }
581
10
  return bits <= limit;
582
10
}
583
584
isc_result_t
585
isc_ossl_wrap_rsa_public_components(EVP_PKEY *pkey,
586
0
            isc_ossl_wrap_rsa_components_t *c) {
587
0
  isc_result_t result;
588
589
0
  REQUIRE(pkey != NULL);
590
0
  REQUIRE(c != NULL && c->e == NULL && c->n == NULL);
591
592
0
  c->needs_cleanup = true;
593
594
0
  if (EVP_PKEY_get_bn_param(pkey, OSSL_PKEY_PARAM_RSA_E, &c->e) != 1) {
595
0
    CLEANUP(OSSL_WRAP_ERROR("EVP_PKEY_get_bn_param"));
596
0
  }
597
598
0
  if (EVP_PKEY_get_bn_param(pkey, OSSL_PKEY_PARAM_RSA_N, &c->n) != 1) {
599
0
    CLEANUP(OSSL_WRAP_ERROR("EVP_PKEY_get_bn_param"));
600
0
  }
601
602
0
  result = ISC_R_SUCCESS;
603
604
0
cleanup:
605
0
  return result;
606
0
}
607
608
isc_result_t
609
isc_ossl_wrap_rsa_secret_components(EVP_PKEY *pkey,
610
0
            isc_ossl_wrap_rsa_components_t *c) {
611
0
  REQUIRE(pkey != NULL);
612
0
  REQUIRE(c != NULL && c->d == NULL && c->p == NULL && c->q == NULL &&
613
0
    c->dmp1 == NULL && c->dmq1 == NULL && c->iqmp == NULL);
614
615
0
  c->needs_cleanup = true;
616
617
  /*
618
   * NOTE: Errors regarding private compoments are ignored.
619
   *
620
   * OpenSSL allows omitting the parameters for CRT based calculations
621
   * (factors, exponents, coefficients). Only the 'd'  parameter is
622
   * mandatory for software keys.
623
   *
624
   * However, for a label based keys, all private key component queries
625
   * can fail if they key is e.g. on a hardware device.
626
   */
627
0
  (void)EVP_PKEY_get_bn_param(pkey, OSSL_PKEY_PARAM_RSA_D, &c->d);
628
0
  (void)EVP_PKEY_get_bn_param(pkey, OSSL_PKEY_PARAM_RSA_FACTOR1, &c->p);
629
0
  (void)EVP_PKEY_get_bn_param(pkey, OSSL_PKEY_PARAM_RSA_FACTOR2, &c->q);
630
0
  (void)EVP_PKEY_get_bn_param(pkey, OSSL_PKEY_PARAM_RSA_EXPONENT1,
631
0
            &c->dmp1);
632
0
  (void)EVP_PKEY_get_bn_param(pkey, OSSL_PKEY_PARAM_RSA_EXPONENT2,
633
0
            &c->dmq1);
634
0
  (void)EVP_PKEY_get_bn_param(pkey, OSSL_PKEY_PARAM_RSA_COEFFICIENT1,
635
0
            &c->iqmp);
636
637
0
  ERR_clear_error();
638
639
0
  return ISC_R_SUCCESS;
640
0
}
641
642
isc_result_t
643
isc_ossl_wrap_load_rsa_public_from_components(isc_ossl_wrap_rsa_components_t *c,
644
221
                EVP_PKEY **pkeyp) {
645
221
  OSSL_PARAM_BLD *bld = NULL;
646
221
  EVP_PKEY_CTX *pctx = NULL;
647
221
  OSSL_PARAM *params = NULL;
648
221
  isc_result_t result;
649
650
221
  result = ISC_R_SUCCESS;
651
652
221
  REQUIRE(pkeyp != NULL && *pkeyp == NULL);
653
221
  REQUIRE(c != NULL && c->n != NULL && c->e != NULL);
654
655
221
  bld = OSSL_PARAM_BLD_new();
656
221
  if (bld == NULL) {
657
0
    CLEANUP(OSSL_WRAP_ERROR("OSSL_PARAM_BLD_new"));
658
0
  }
659
660
221
  if (OSSL_PARAM_BLD_push_BN(bld, OSSL_PKEY_PARAM_RSA_N, c->n) != 1) {
661
0
    CLEANUP(OSSL_WRAP_ERROR("OSSL_PARAM_BLD_push_BN"));
662
0
  }
663
664
221
  if (OSSL_PARAM_BLD_push_BN(bld, OSSL_PKEY_PARAM_RSA_E, c->e) != 1) {
665
0
    CLEANUP(OSSL_WRAP_ERROR("OSSL_PARAM_BLD_push_BN"));
666
0
  }
667
668
221
  params = OSSL_PARAM_BLD_to_param(bld);
669
221
  if (params == NULL) {
670
0
    CLEANUP(OSSL_WRAP_ERROR("OSSL_PARAM_BLD_to_param"));
671
0
  }
672
673
221
  pctx = EVP_PKEY_CTX_new_from_name(NULL, "RSA", NULL);
674
221
  if (pctx == NULL) {
675
0
    CLEANUP(OSSL_WRAP_ERROR("EVP_PKEY_CTX_new_from_name"));
676
0
  }
677
678
221
  if (EVP_PKEY_fromdata_init(pctx) != 1) {
679
0
    CLEANUP(OSSL_WRAP_ERROR("EVP_PKEY_fromdata_init"));
680
0
  }
681
682
221
  if (EVP_PKEY_fromdata(pctx, pkeyp, EVP_PKEY_PUBLIC_KEY, params) != 1) {
683
0
    CLEANUP(OSSL_WRAP_ERROR("EVP_PKEY_fromdata"));
684
0
  }
685
686
221
  result = ISC_R_SUCCESS;
687
688
221
cleanup:
689
221
  EVP_PKEY_CTX_free(pctx);
690
221
  OSSL_PARAM_free(params);
691
221
  OSSL_PARAM_BLD_free(bld);
692
221
  return result;
693
221
}
694
695
isc_result_t
696
isc_ossl_wrap_load_rsa_secret_from_components(isc_ossl_wrap_rsa_components_t *c,
697
0
                EVP_PKEY **pkeyp) {
698
0
  isc_result_t result;
699
0
  OSSL_PARAM_BLD *bld = NULL;
700
0
  EVP_PKEY_CTX *pctx = NULL;
701
0
  OSSL_PARAM *params = NULL;
702
703
0
  REQUIRE(pkeyp != NULL && *pkeyp == NULL);
704
705
0
  bld = OSSL_PARAM_BLD_new();
706
0
  if (bld == NULL) {
707
0
    CLEANUP(OSSL_WRAP_ERROR("OSSL_PARAM_BLD_new"));
708
0
  }
709
710
0
  if (OSSL_PARAM_BLD_push_BN(bld, OSSL_PKEY_PARAM_RSA_N, c->n) != 1) {
711
0
    CLEANUP(OSSL_WRAP_ERROR("OSSL_PARAM_BLD_push_BN"));
712
0
  }
713
714
0
  if (OSSL_PARAM_BLD_push_BN(bld, OSSL_PKEY_PARAM_RSA_E, c->e) != 1) {
715
0
    CLEANUP(OSSL_WRAP_ERROR("OSSL_PARAM_BLD_push_BN"));
716
0
  }
717
718
0
  if (c->d != NULL &&
719
0
      OSSL_PARAM_BLD_push_BN(bld, OSSL_PKEY_PARAM_RSA_D, c->d) != 1)
720
0
  {
721
0
    CLEANUP(OSSL_WRAP_ERROR("OSSL_PARAM_BLD_push_BN"));
722
0
  }
723
724
0
  if (c->p != NULL &&
725
0
      OSSL_PARAM_BLD_push_BN(bld, OSSL_PKEY_PARAM_RSA_FACTOR1, c->p) != 1)
726
0
  {
727
0
    CLEANUP(OSSL_WRAP_ERROR("OSSL_PARAM_BLD_push_BN"));
728
0
  }
729
730
0
  if (c->q != NULL &&
731
0
      OSSL_PARAM_BLD_push_BN(bld, OSSL_PKEY_PARAM_RSA_FACTOR2, c->q) != 1)
732
0
  {
733
0
    CLEANUP(OSSL_WRAP_ERROR("OSSL_PARAM_BLD_push_BN"));
734
0
  }
735
736
0
  if (c->dmp1 != NULL &&
737
0
      OSSL_PARAM_BLD_push_BN(bld, OSSL_PKEY_PARAM_RSA_EXPONENT1,
738
0
           c->dmp1) != 1)
739
0
  {
740
0
    CLEANUP(OSSL_WRAP_ERROR("OSSL_PARAM_BLD_push_BN"));
741
0
  }
742
743
0
  if (c->dmq1 != NULL &&
744
0
      OSSL_PARAM_BLD_push_BN(bld, OSSL_PKEY_PARAM_RSA_EXPONENT2,
745
0
           c->dmq1) != 1)
746
0
  {
747
0
    CLEANUP(OSSL_WRAP_ERROR("OSSL_PARAM_BLD_push_BN"));
748
0
  }
749
750
0
  if (c->iqmp != NULL &&
751
0
      OSSL_PARAM_BLD_push_BN(bld, OSSL_PKEY_PARAM_RSA_COEFFICIENT1,
752
0
           c->iqmp) != 1)
753
0
  {
754
0
    CLEANUP(OSSL_WRAP_ERROR("OSSL_PARAM_BLD_push_BN"));
755
0
  }
756
757
0
  params = OSSL_PARAM_BLD_to_param(bld);
758
0
  if (params == NULL) {
759
0
    CLEANUP(OSSL_WRAP_ERROR("OSSL_PARAM_BLD_to_param"));
760
0
  }
761
762
0
  pctx = EVP_PKEY_CTX_new_from_name(NULL, "RSA", NULL);
763
0
  if (pctx == NULL) {
764
0
    CLEANUP(OSSL_WRAP_ERROR("EVP_PKEY_CTX_new_from_name"));
765
0
  }
766
767
0
  if (EVP_PKEY_fromdata_init(pctx) != 1) {
768
0
    CLEANUP(OSSL_WRAP_ERROR("EVP_PKEY_fromdata_init"));
769
0
  }
770
771
0
  if (EVP_PKEY_fromdata(pctx, pkeyp, EVP_PKEY_KEYPAIR, params) != 1) {
772
0
    CLEANUP(OSSL_WRAP_ERROR("EVP_PKEY_fromdata"));
773
0
  }
774
775
0
  result = ISC_R_SUCCESS;
776
777
0
cleanup:
778
0
  EVP_PKEY_CTX_free(pctx);
779
0
  OSSL_PARAM_free(params);
780
0
  OSSL_PARAM_BLD_free(bld);
781
0
  return result;
782
0
}