]> git.ipfire.org Git - thirdparty/pdns.git/blob - pdns/opensslsigners.cc
rec: allow exception to proxy protocal usage for specific listen addresses
[thirdparty/pdns.git] / pdns / opensslsigners.cc
1 /*
2 * This file is part of PowerDNS or dnsdist.
3 * Copyright -- PowerDNS.COM B.V. and its contributors
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of version 2 of the GNU General Public License as
7 * published by the Free Software Foundation.
8 *
9 * In addition, for the avoidance of any doubt, permission is granted to
10 * link this program with OpenSSL and to (re)distribute the binaries
11 * produced as the result of such linking.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
21 */
22 #include "misc.hh"
23 #include <memory>
24 #include <openssl/crypto.h>
25 #include <openssl/ec.h>
26 #include <optional>
27 #ifdef HAVE_CONFIG_H
28 #include "config.h"
29 #endif
30 #include <openssl/obj_mac.h>
31 #ifdef HAVE_LIBCRYPTO_ECDSA
32 #include <openssl/ecdsa.h>
33 #endif
34 #if defined(HAVE_LIBCRYPTO_ED25519) || defined(HAVE_LIBCRYPTO_ED448)
35 #include <openssl/evp.h>
36 #endif
37 #include <openssl/bn.h>
38 #include <openssl/sha.h>
39 #include <openssl/rand.h>
40 #include <openssl/rsa.h>
41 #if OPENSSL_VERSION_MAJOR >= 3
42 #include <openssl/types.h>
43 #include <openssl/core_names.h>
44 #include <openssl/param_build.h>
45 #include <openssl/params.h>
46 #endif
47 #include <openssl/opensslv.h>
48 #include <openssl/err.h>
49 #include <openssl/pem.h>
50 #include "opensslsigners.hh"
51 #include "dnssecinfra.hh"
52 #include "dnsseckeeper.hh"
53
54 #if (OPENSSL_VERSION_NUMBER < 0x1010000fL || (defined LIBRESSL_VERSION_NUMBER) && LIBRESSL_VERSION_NUMBER < 0x2090100fL)
55 /* OpenSSL < 1.1.0 needs support for threading/locking in the calling application. */
56
57 #include "lock.hh"
58 static std::vector<std::mutex> openssllocks;
59
60 extern "C"
61 {
62 static void openssl_pthreads_locking_callback(int mode, int type, const char* file, int line)
63 {
64 if (mode & CRYPTO_LOCK) {
65 openssllocks.at(type).lock();
66 }
67 else {
68 openssllocks.at(type).unlock();
69 }
70 }
71
72 static unsigned long openssl_pthreads_id_callback(void)
73 {
74 return (unsigned long)pthread_self();
75 }
76 }
77
78 void openssl_thread_setup()
79 {
80 openssllocks = std::vector<std::mutex>(CRYPTO_num_locks());
81 CRYPTO_set_id_callback(&openssl_pthreads_id_callback);
82 CRYPTO_set_locking_callback(&openssl_pthreads_locking_callback);
83 }
84
85 void openssl_thread_cleanup()
86 {
87 CRYPTO_set_locking_callback(nullptr);
88 openssllocks.clear();
89 }
90
91 #ifndef HAVE_RSA_GET0_KEY
92 /* those symbols are defined in LibreSSL 2.7.0+ */
93 /* compat helpers. These DO NOT do any of the checking that the libssl 1.1 functions do. */
94 static inline void RSA_get0_key(const RSA* rsakey, const BIGNUM** n, const BIGNUM** e, const BIGNUM** d)
95 {
96 *n = rsakey->n;
97 *e = rsakey->e;
98 *d = rsakey->d;
99 }
100
101 static inline int RSA_set0_key(RSA* rsakey, BIGNUM* n, BIGNUM* e, BIGNUM* d)
102 {
103 if (n) {
104 BN_clear_free(rsakey->n);
105 rsakey->n = n;
106 }
107 if (e) {
108 BN_clear_free(rsakey->e);
109 rsakey->e = e;
110 }
111 if (d) {
112 BN_clear_free(rsakey->d);
113 rsakey->d = d;
114 }
115 return 1;
116 }
117
118 static inline void RSA_get0_factors(const RSA* rsakey, const BIGNUM** p, const BIGNUM** q)
119 {
120 *p = rsakey->p;
121 *q = rsakey->q;
122 }
123
124 static inline int RSA_set0_factors(RSA* rsakey, BIGNUM* p, BIGNUM* q)
125 {
126 BN_clear_free(rsakey->p);
127 rsakey->p = p;
128 BN_clear_free(rsakey->q);
129 rsakey->q = q;
130 return 1;
131 }
132
133 static inline void RSA_get0_crt_params(const RSA* rsakey, const BIGNUM** dmp1, const BIGNUM** dmq1, const BIGNUM** iqmp)
134 {
135 *dmp1 = rsakey->dmp1;
136 *dmq1 = rsakey->dmq1;
137 *iqmp = rsakey->iqmp;
138 }
139
140 static inline int RSA_set0_crt_params(RSA* rsakey, BIGNUM* dmp1, BIGNUM* dmq1, BIGNUM* iqmp)
141 {
142 BN_clear_free(rsakey->dmp1);
143 rsakey->dmp1 = dmp1;
144 BN_clear_free(rsakey->dmq1);
145 rsakey->dmq1 = dmq1;
146 BN_clear_free(rsakey->iqmp);
147 rsakey->iqmp = iqmp;
148 return 1;
149 }
150
151 #ifdef HAVE_LIBCRYPTO_ECDSA
152 static inline void ECDSA_SIG_get0(const ECDSA_SIG* signature, const BIGNUM** pr, const BIGNUM** ps)
153 {
154 *pr = signature->r;
155 *ps = signature->s;
156 }
157
158 static inline int ECDSA_SIG_set0(ECDSA_SIG* signature, BIGNUM* pr, BIGNUM* ps)
159 {
160 BN_clear_free(signature->r);
161 BN_clear_free(signature->s);
162 signature->r = pr;
163 signature->s = ps;
164 return 1;
165 }
166 #endif /* HAVE_LIBCRYPTO_ECDSA */
167
168 #endif /* HAVE_RSA_GET0_KEY */
169
170 #else
171 void openssl_thread_setup() {}
172 void openssl_thread_cleanup() {}
173 #endif
174
175 /* seeding PRNG */
176 void openssl_seed()
177 {
178 std::string entropy;
179 entropy.reserve(1024);
180
181 unsigned int r;
182 for (int i = 0; i < 1024; i += 4) {
183 r = dns_random_uint32();
184 entropy.append((const char*)&r, 4);
185 }
186
187 RAND_seed((const unsigned char*)entropy.c_str(), 1024);
188 }
189
190 using BigNum = unique_ptr<BIGNUM, decltype(&BN_clear_free)>;
191
192 static auto mapToBN(const std::string& componentName, const std::map<std::string, std::string>& stormap, const std::string& key) -> BigNum
193 {
194 const std::string& value = stormap.at(key);
195
196 // NOLINTNEXTLINE(*-cast): Using OpenSSL C APIs.
197 const auto* valueCStr = reinterpret_cast<const unsigned char*>(value.c_str());
198 auto number = BigNum{BN_bin2bn(valueCStr, static_cast<int>(value.length()), nullptr), BN_clear_free};
199 if (number == nullptr) {
200 throw pdns::OpenSSL::error(componentName, "Failed to parse key `" + key + "`");
201 }
202
203 return number;
204 }
205
206 class OpenSSLRSADNSCryptoKeyEngine : public DNSCryptoKeyEngine
207 {
208 public:
209 explicit OpenSSLRSADNSCryptoKeyEngine(unsigned int algo);
210
211 [[nodiscard]] string getName() const override { return "OpenSSL RSA"; }
212 [[nodiscard]] int getBits() const override;
213 void create(unsigned int bits) override;
214
215 /**
216 * \brief Creates an RSA key engine from a PEM file.
217 *
218 * Receives an open file handle with PEM contents and creates an RSA key engine.
219 *
220 * \param[in] drc Key record contents to be populated.
221 *
222 * \param[in] inputFile An open file handle to a file containing RSA PEM contents.
223 *
224 * \param[in] filename Only used for providing filename information in error messages.
225 *
226 * \return An RSA key engine populated with the contents of the PEM file.
227 */
228 void createFromPEMFile(DNSKEYRecordContent& drc, std::FILE& inputFile, std::optional<std::reference_wrapper<const std::string>> filename = std::nullopt) override;
229
230 /**
231 * \brief Writes this key's contents to a file.
232 *
233 * Receives an open file handle and writes this key's contents to the
234 * file.
235 *
236 * \param[in] outputFile An open file handle for writing.
237 *
238 * \exception std::runtime_error In case of OpenSSL errors.
239 */
240 void convertToPEMFile(std::FILE& outputFile) const override;
241
242 [[nodiscard]] storvector_t convertToISCVector() const override;
243
244 // TODO Fred: hash() can probably be completely removed. See #12464.
245 [[nodiscard]] std::string hash(const std::string& message) const override;
246 [[nodiscard]] std::string sign(const std::string& message) const override;
247 [[nodiscard]] bool verify(const std::string& message, const std::string& signature) const override;
248 [[nodiscard]] std::string getPublicKeyString() const override;
249
250 void fromISCMap(DNSKEYRecordContent& drc, std::map<std::string, std::string>& stormap) override;
251 void fromPublicKeyString(const std::string& content) override;
252 [[nodiscard]] bool checkKey(std::optional<std::reference_wrapper<std::vector<std::string>>> errorMessages) const override;
253
254 static std::unique_ptr<DNSCryptoKeyEngine> maker(unsigned int algorithm)
255 {
256 return make_unique<OpenSSLRSADNSCryptoKeyEngine>(algorithm);
257 }
258
259 private:
260 #if OPENSSL_VERSION_MAJOR >= 3
261 [[nodiscard]] BigNum getKeyParamModulus() const;
262 [[nodiscard]] BigNum getKeyParamPublicExponent() const;
263 [[nodiscard]] BigNum getKeyParamPrivateExponent() const;
264 [[nodiscard]] BigNum getKeyParamPrime1() const;
265 [[nodiscard]] BigNum getKeyParamPrime2() const;
266 [[nodiscard]] BigNum getKeyParamDmp1() const;
267 [[nodiscard]] BigNum getKeyParamDmq1() const;
268 [[nodiscard]] BigNum getKeyParamIqmp() const;
269
270 using Params = std::unique_ptr<OSSL_PARAM, decltype(&OSSL_PARAM_free)>;
271 auto makeKeyParams(const BIGNUM* modulus, const BIGNUM* publicExponent, const BIGNUM* privateExponent, const BIGNUM* prime1, const BIGNUM* prime2, const BIGNUM* dmp1, const BIGNUM* dmq1, const BIGNUM* iqmp) const -> Params;
272 #endif
273
274 // TODO Fred: hashSize(), hasher() and hashSizeToKind() can probably be completely
275 // removed along with hash(). See #12464.
276 [[nodiscard]] std::size_t hashSize() const;
277 [[nodiscard]] const EVP_MD* hasher() const;
278 static int hashSizeToKind(size_t hashSize);
279
280 #if OPENSSL_VERSION_MAJOR >= 3
281 using KeyContext = std::unique_ptr<EVP_PKEY_CTX, decltype(&EVP_PKEY_CTX_free)>;
282 using Key = std::unique_ptr<EVP_PKEY, decltype(&EVP_PKEY_free)>;
283 using MessageDigestContext = std::unique_ptr<EVP_MD_CTX, decltype(&EVP_MD_CTX_free)>;
284 using ParamsBuilder = std::unique_ptr<OSSL_PARAM_BLD, decltype(&OSSL_PARAM_BLD_free)>;
285 using MessageDigest = std::unique_ptr<EVP_MD, decltype(&EVP_MD_free)>;
286 #else
287 using Key = std::unique_ptr<RSA, decltype(&RSA_free)>;
288 #endif
289
290 Key d_key;
291 };
292
293 OpenSSLRSADNSCryptoKeyEngine::OpenSSLRSADNSCryptoKeyEngine(unsigned int algo) :
294 DNSCryptoKeyEngine(algo),
295 #if OPENSSL_VERSION_MAJOR >= 3
296 d_key(Key(nullptr, EVP_PKEY_free))
297 #else
298 d_key(Key(nullptr, RSA_free))
299 #endif
300 {
301 int ret = RAND_status();
302 if (ret != 1) {
303 throw runtime_error(getName() + " insufficient entropy");
304 }
305 }
306
307 int OpenSSLRSADNSCryptoKeyEngine::getBits() const
308 {
309 #if OPENSSL_VERSION_MAJOR >= 3
310 return EVP_PKEY_get_bits(d_key.get());
311 #else
312 return RSA_size(d_key.get()) << 3;
313 #endif
314 }
315
316 void OpenSSLRSADNSCryptoKeyEngine::create(unsigned int bits)
317 {
318 // When changing the bitsizes, also edit them in ::checkKey
319 if ((d_algorithm == DNSSECKeeper::RSASHA1 || d_algorithm == DNSSECKeeper::RSASHA1NSEC3SHA1) && (bits < 512 || bits > 4096)) {
320 /* RFC3110 */
321 throw runtime_error(getName() + " RSASHA1 key generation failed for invalid bits size " + std::to_string(bits));
322 }
323 if (d_algorithm == DNSSECKeeper::RSASHA256 && (bits < 512 || bits > 4096)) {
324 /* RFC5702 */
325 throw runtime_error(getName() + " RSASHA256 key generation failed for invalid bits size " + std::to_string(bits));
326 }
327 if (d_algorithm == DNSSECKeeper::RSASHA512 && (bits < 1024 || bits > 4096)) {
328 /* RFC5702 */
329 throw runtime_error(getName() + " RSASHA512 key generation failed for invalid bits size " + std::to_string(bits));
330 }
331
332 auto exponent = BigNum(BN_new(), BN_clear_free);
333 if (!exponent) {
334 throw runtime_error(getName() + " key generation failed, unable to allocate e");
335 }
336
337 /* RSA_F4 is a public exponent value of 65537 */
338 int res = BN_set_word(exponent.get(), RSA_F4);
339
340 if (res == 0) {
341 throw runtime_error(getName() + " key generation failed while setting e");
342 }
343
344 #if OPENSSL_VERSION_MAJOR >= 3
345 auto ctx = KeyContext(EVP_PKEY_CTX_new_from_name(nullptr, "RSA", nullptr), EVP_PKEY_CTX_free);
346 if (ctx == nullptr) {
347 throw pdns::OpenSSL::error(getName(), "Could not initialize context");
348 }
349
350 if (EVP_PKEY_keygen_init(ctx.get()) != 1) {
351 throw pdns::OpenSSL::error(getName(), "Could not initialize keygen");
352 }
353
354 if (EVP_PKEY_CTX_set_rsa_keygen_bits(ctx.get(), (int)bits) <= 0) {
355 throw pdns::OpenSSL::error(getName(), "Could not set keygen bits to " + std::to_string(bits));
356 }
357
358 if (EVP_PKEY_CTX_set1_rsa_keygen_pubexp(ctx.get(), exponent.get()) <= 0) {
359 throw pdns::OpenSSL::error(getName(), "Could not set keygen public exponent");
360 }
361
362 EVP_PKEY* key = nullptr;
363 if (EVP_PKEY_generate(ctx.get(), &key) != 1) {
364 throw pdns::OpenSSL::error(getName(), "Could not generate key");
365 }
366
367 d_key.reset(key);
368 #else
369 auto key = Key(RSA_new(), RSA_free);
370 if (!key) {
371 throw runtime_error(getName() + " allocation of key structure failed");
372 }
373
374 res = RSA_generate_key_ex(key.get(), bits, exponent.get(), nullptr);
375 if (res == 0) {
376 throw runtime_error(getName() + " key generation failed");
377 }
378
379 d_key = std::move(key);
380 #endif
381 }
382
383 void OpenSSLRSADNSCryptoKeyEngine::createFromPEMFile(DNSKEYRecordContent& drc, std::FILE& inputFile, const std::optional<std::reference_wrapper<const std::string>> filename)
384 {
385 drc.d_algorithm = d_algorithm;
386
387 #if OPENSSL_VERSION_MAJOR >= 3
388 EVP_PKEY* key = nullptr;
389 if (PEM_read_PrivateKey(&inputFile, &key, nullptr, nullptr) == nullptr) {
390 if (filename.has_value()) {
391 throw pdns::OpenSSL::error(getName(), "Could not read private key from PEM file `" + filename->get() + "`");
392 }
393
394 throw pdns::OpenSSL::error(getName(), "Could not read private key from PEM contents");
395 }
396
397 d_key.reset(key);
398 #else
399 d_key = Key(PEM_read_RSAPrivateKey(&inputFile, nullptr, nullptr, nullptr), &RSA_free);
400 if (d_key == nullptr) {
401 if (filename.has_value()) {
402 throw runtime_error(getName() + ": Failed to read private key from PEM file `" + filename->get() + "`");
403 }
404
405 throw runtime_error(getName() + ": Failed to read private key from PEM contents");
406 }
407 #endif
408 }
409
410 void OpenSSLRSADNSCryptoKeyEngine::convertToPEMFile(std::FILE& outputFile) const
411 {
412 #if OPENSSL_VERSION_MAJOR >= 3
413 if (PEM_write_PrivateKey(&outputFile, d_key.get(), nullptr, nullptr, 0, nullptr, nullptr) == 0) {
414 throw pdns::OpenSSL::error(getName(), "Could not convert private key to PEM");
415 }
416 #else
417 auto ret = PEM_write_RSAPrivateKey(&outputFile, d_key.get(), nullptr, nullptr, 0, nullptr, nullptr);
418 if (ret == 0) {
419 throw runtime_error(getName() + ": Could not convert private key to PEM");
420 }
421 #endif
422 }
423
424 #if OPENSSL_VERSION_MAJOR >= 3
425 BigNum OpenSSLRSADNSCryptoKeyEngine::getKeyParamModulus() const
426 {
427 BIGNUM* modulus = nullptr;
428 if (EVP_PKEY_get_bn_param(d_key.get(), OSSL_PKEY_PARAM_RSA_N, &modulus) == 0) {
429 throw pdns::OpenSSL::error(getName(), "Could not get key's modulus (n) parameter");
430 }
431 return BigNum{modulus, BN_clear_free};
432 }
433
434 BigNum OpenSSLRSADNSCryptoKeyEngine::getKeyParamPublicExponent() const
435 {
436 BIGNUM* publicExponent = nullptr;
437 if (EVP_PKEY_get_bn_param(d_key.get(), OSSL_PKEY_PARAM_RSA_E, &publicExponent) == 0) {
438 throw pdns::OpenSSL::error(getName(), "Could not get key's public exponent (e) parameter");
439 }
440 return BigNum{publicExponent, BN_clear_free};
441 }
442
443 BigNum OpenSSLRSADNSCryptoKeyEngine::getKeyParamPrivateExponent() const
444 {
445 BIGNUM* privateExponent = nullptr;
446 if (EVP_PKEY_get_bn_param(d_key.get(), OSSL_PKEY_PARAM_RSA_D, &privateExponent) == 0) {
447 throw pdns::OpenSSL::error(getName(), "Could not get key's private exponent (d) parameter");
448 }
449 return BigNum{privateExponent, BN_clear_free};
450 }
451
452 BigNum OpenSSLRSADNSCryptoKeyEngine::getKeyParamPrime1() const
453 {
454 BIGNUM* prime1 = nullptr;
455 if (EVP_PKEY_get_bn_param(d_key.get(), OSSL_PKEY_PARAM_RSA_FACTOR1, &prime1) == 0) {
456 throw pdns::OpenSSL::error(getName(), "Could not get key's first prime (p) parameter");
457 }
458 return BigNum{prime1, BN_clear_free};
459 }
460
461 BigNum OpenSSLRSADNSCryptoKeyEngine::getKeyParamPrime2() const
462 {
463 BIGNUM* prime2 = nullptr;
464 if (EVP_PKEY_get_bn_param(d_key.get(), OSSL_PKEY_PARAM_RSA_FACTOR2, &prime2) == 0) {
465 throw pdns::OpenSSL::error(getName(), "Could not get key's second prime (q) parameter");
466 }
467 return BigNum{prime2, BN_clear_free};
468 }
469
470 BigNum OpenSSLRSADNSCryptoKeyEngine::getKeyParamDmp1() const
471 {
472 BIGNUM* dmp1 = nullptr;
473 if (EVP_PKEY_get_bn_param(d_key.get(), OSSL_PKEY_PARAM_RSA_EXPONENT1, &dmp1) == 0) {
474 throw pdns::OpenSSL::error(getName(), "Could not get key's first exponent parameter");
475 }
476 return BigNum{dmp1, BN_clear_free};
477 }
478
479 BigNum OpenSSLRSADNSCryptoKeyEngine::getKeyParamDmq1() const
480 {
481 BIGNUM* dmq1 = nullptr;
482 if (EVP_PKEY_get_bn_param(d_key.get(), OSSL_PKEY_PARAM_RSA_EXPONENT2, &dmq1) == 0) {
483 throw pdns::OpenSSL::error(getName(), "Could not get key's second exponent parameter");
484 }
485 return BigNum{dmq1, BN_clear_free};
486 }
487
488 BigNum OpenSSLRSADNSCryptoKeyEngine::getKeyParamIqmp() const
489 {
490 BIGNUM* iqmp = nullptr;
491 if (EVP_PKEY_get_bn_param(d_key.get(), OSSL_PKEY_PARAM_RSA_COEFFICIENT1, &iqmp) == 0) {
492 throw pdns::OpenSSL::error(getName(), "Could not get key's first coefficient parameter");
493 }
494 return BigNum{iqmp, BN_clear_free};
495 }
496 #endif
497
498 #if OPENSSL_VERSION_MAJOR >= 3
499 auto OpenSSLRSADNSCryptoKeyEngine::makeKeyParams(const BIGNUM* modulus, const BIGNUM* publicExponent, const BIGNUM* privateExponent, const BIGNUM* prime1, const BIGNUM* prime2, const BIGNUM* dmp1, const BIGNUM* dmq1, const BIGNUM* iqmp) const -> Params
500 {
501 auto params_build = ParamsBuilder(OSSL_PARAM_BLD_new(), OSSL_PARAM_BLD_free);
502 if (params_build == nullptr) {
503 throw pdns::OpenSSL::error(getName(), "Could not create key's parameters builder");
504 }
505
506 if ((modulus != nullptr) && OSSL_PARAM_BLD_push_BN(params_build.get(), OSSL_PKEY_PARAM_RSA_N, modulus) == 0) {
507 throw pdns::OpenSSL::error(getName(), "Could not create key's modulus parameter");
508 }
509
510 if ((publicExponent != nullptr) && OSSL_PARAM_BLD_push_BN(params_build.get(), OSSL_PKEY_PARAM_RSA_E, publicExponent) == 0) {
511 throw pdns::OpenSSL::error(getName(), "Could not create key's public exponent parameter");
512 }
513
514 if ((privateExponent != nullptr) && OSSL_PARAM_BLD_push_BN(params_build.get(), OSSL_PKEY_PARAM_RSA_D, privateExponent) == 0) {
515 throw pdns::OpenSSL::error(getName(), "Could not create key's private exponent parameter");
516 }
517
518 if ((prime1 != nullptr) && OSSL_PARAM_BLD_push_BN(params_build.get(), OSSL_PKEY_PARAM_RSA_FACTOR1, prime1) == 0) {
519 throw pdns::OpenSSL::error(getName(), "Could not create key's first prime parameter");
520 }
521
522 if ((prime2 != nullptr) && OSSL_PARAM_BLD_push_BN(params_build.get(), OSSL_PKEY_PARAM_RSA_FACTOR2, prime2) == 0) {
523 throw pdns::OpenSSL::error(getName(), "Could not create key's second prime parameter");
524 }
525
526 if ((dmp1 != nullptr) && OSSL_PARAM_BLD_push_BN(params_build.get(), OSSL_PKEY_PARAM_RSA_EXPONENT1, dmp1) == 0) {
527 throw pdns::OpenSSL::error(getName(), "Could not create key's first exponent parameter");
528 }
529
530 if ((dmq1 != nullptr) && OSSL_PARAM_BLD_push_BN(params_build.get(), OSSL_PKEY_PARAM_RSA_EXPONENT2, dmq1) == 0) {
531 throw pdns::OpenSSL::error(getName(), "Could not create key's second exponent parameter");
532 }
533
534 if ((iqmp != nullptr) && OSSL_PARAM_BLD_push_BN(params_build.get(), OSSL_PKEY_PARAM_RSA_COEFFICIENT1, iqmp) == 0) {
535 throw pdns::OpenSSL::error(getName(), "Could not create key's first coefficient parameter");
536 }
537
538 auto params = Params(OSSL_PARAM_BLD_to_param(params_build.get()), OSSL_PARAM_free);
539 if (params == nullptr) {
540 throw pdns::OpenSSL::error(getName(), "Could not create key's parameters");
541 }
542
543 return params;
544 }
545 #endif
546
547 DNSCryptoKeyEngine::storvector_t OpenSSLRSADNSCryptoKeyEngine::convertToISCVector() const
548 {
549 storvector_t storvect;
550 using outputs_t = vector<pair<string, const BIGNUM*>>;
551 outputs_t outputs;
552
553 #if OPENSSL_VERSION_MAJOR >= 3
554 // If any of those calls throw, we correctly free the BIGNUMs allocated before it.
555 BigNum modulusPtr = getKeyParamModulus();
556 BigNum publicExponentPtr = getKeyParamPublicExponent();
557 BigNum privateExponentPtr = getKeyParamPrivateExponent();
558 BigNum prime1Ptr = getKeyParamPrime1();
559 BigNum prime2Ptr = getKeyParamPrime2();
560 BigNum dmp1Ptr = getKeyParamDmp1();
561 BigNum dmq1Ptr = getKeyParamDmq1();
562 BigNum iqmpPtr = getKeyParamIqmp();
563
564 // All the calls succeeded, we can take references to the BIGNUM pointers.
565 BIGNUM* modulus = modulusPtr.get();
566 BIGNUM* publicExponent = publicExponentPtr.get();
567 BIGNUM* privateExponent = privateExponentPtr.get();
568 BIGNUM* prime1 = prime1Ptr.get();
569 BIGNUM* prime2 = prime2Ptr.get();
570 BIGNUM* dmp1 = dmp1Ptr.get();
571 BIGNUM* dmq1 = dmq1Ptr.get();
572 BIGNUM* iqmp = iqmpPtr.get();
573 #else
574 const BIGNUM* modulus = nullptr;
575 const BIGNUM* publicExponent = nullptr;
576 const BIGNUM* privateExponent = nullptr;
577 const BIGNUM* prime1 = nullptr;
578 const BIGNUM* prime2 = nullptr;
579 const BIGNUM* dmp1 = nullptr;
580 const BIGNUM* dmq1 = nullptr;
581 const BIGNUM* iqmp = nullptr;
582 RSA_get0_key(d_key.get(), &modulus, &publicExponent, &privateExponent);
583 RSA_get0_factors(d_key.get(), &prime1, &prime2);
584 RSA_get0_crt_params(d_key.get(), &dmp1, &dmq1, &iqmp);
585 #endif
586
587 outputs.emplace_back("Modulus", modulus);
588 outputs.emplace_back("PublicExponent", publicExponent);
589 outputs.emplace_back("PrivateExponent", privateExponent);
590 outputs.emplace_back("Prime1", prime1);
591 outputs.emplace_back("Prime2", prime2);
592 outputs.emplace_back("Exponent1", dmp1);
593 outputs.emplace_back("Exponent2", dmq1);
594 outputs.emplace_back("Coefficient", iqmp);
595
596 string algorithm = std::to_string(d_algorithm);
597 switch (d_algorithm) {
598 case DNSSECKeeper::RSASHA1:
599 case DNSSECKeeper::RSASHA1NSEC3SHA1:
600 algorithm += " (RSASHA1)";
601 break;
602 case DNSSECKeeper::RSASHA256:
603 algorithm += " (RSASHA256)";
604 break;
605 case DNSSECKeeper::RSASHA512:
606 algorithm += " (RSASHA512)";
607 break;
608 default:
609 algorithm += " (?)";
610 }
611 storvect.emplace_back("Algorithm", algorithm);
612
613 for (const outputs_t::value_type& value : outputs) {
614 std::string tmp;
615 tmp.resize(BN_num_bytes(value.second));
616 // NOLINTNEXTLINE(*-cast): Using OpenSSL C APIs.
617 int len = BN_bn2bin(value.second, reinterpret_cast<unsigned char*>(tmp.data()));
618 if (len >= 0) {
619 tmp.resize(len);
620 storvect.emplace_back(value.first, tmp);
621 }
622 }
623
624 return storvect;
625 }
626
627 std::size_t OpenSSLRSADNSCryptoKeyEngine::hashSize() const
628 {
629 switch (d_algorithm) {
630 case DNSSECKeeper::RSASHA1:
631 case DNSSECKeeper::RSASHA1NSEC3SHA1:
632 return SHA_DIGEST_LENGTH;
633 case DNSSECKeeper::RSASHA256:
634 return SHA256_DIGEST_LENGTH;
635 case DNSSECKeeper::RSASHA512:
636 return SHA512_DIGEST_LENGTH;
637 default:
638 throw runtime_error(getName() + " does not support hash operations for algorithm " + std::to_string(d_algorithm));
639 }
640 }
641
642 const EVP_MD* OpenSSLRSADNSCryptoKeyEngine::hasher() const
643 {
644 const EVP_MD* messageDigest = nullptr;
645
646 switch (d_algorithm) {
647 case DNSSECKeeper::RSASHA1:
648 case DNSSECKeeper::RSASHA1NSEC3SHA1:
649 messageDigest = EVP_sha1();
650 break;
651 case DNSSECKeeper::RSASHA256:
652 messageDigest = EVP_sha256();
653 break;
654 case DNSSECKeeper::RSASHA512:
655 messageDigest = EVP_sha512();
656 break;
657 default:
658 throw runtime_error(getName() + " does not support hash operations for algorithm " + std::to_string(d_algorithm));
659 }
660
661 if (messageDigest == nullptr) {
662 throw std::runtime_error("Could not retrieve a SHA implementation of size " + std::to_string(hashSize()) + " from OpenSSL");
663 }
664
665 return messageDigest;
666 }
667
668 std::string OpenSSLRSADNSCryptoKeyEngine::hash(const std::string& message) const
669 {
670 if (d_algorithm == DNSSECKeeper::RSASHA1 || d_algorithm == DNSSECKeeper::RSASHA1NSEC3SHA1) {
671 std::string l_hash{};
672 l_hash.resize(SHA_DIGEST_LENGTH);
673 // NOLINTNEXTLINE(*-cast): Using OpenSSL C APIs.
674 SHA1(reinterpret_cast<unsigned char*>(const_cast<char*>(message.c_str())), message.length(), reinterpret_cast<unsigned char*>(l_hash.data()));
675 return l_hash;
676 }
677
678 if (d_algorithm == DNSSECKeeper::RSASHA256) {
679 std::string l_hash{};
680 l_hash.resize(SHA256_DIGEST_LENGTH);
681 // NOLINTNEXTLINE(*-cast): Using OpenSSL C APIs.
682 SHA256(reinterpret_cast<unsigned char*>(const_cast<char*>(message.c_str())), message.length(), reinterpret_cast<unsigned char*>(l_hash.data()));
683 return l_hash;
684 }
685
686 if (d_algorithm == DNSSECKeeper::RSASHA512) {
687 std::string l_hash{};
688 l_hash.resize(SHA512_DIGEST_LENGTH);
689 // NOLINTNEXTLINE(*-cast): Using OpenSSL C APIs.
690 SHA512(reinterpret_cast<unsigned char*>(const_cast<char*>(message.c_str())), message.length(), reinterpret_cast<unsigned char*>(l_hash.data()));
691 return l_hash;
692 }
693
694 throw runtime_error(getName() + " does not support hash operation for algorithm " + std::to_string(d_algorithm));
695 }
696
697 int OpenSSLRSADNSCryptoKeyEngine::hashSizeToKind(const size_t hashSize)
698 {
699 switch (hashSize) {
700 case SHA_DIGEST_LENGTH:
701 return NID_sha1;
702 case SHA256_DIGEST_LENGTH:
703 return NID_sha256;
704 case SHA384_DIGEST_LENGTH:
705 return NID_sha384;
706 case SHA512_DIGEST_LENGTH:
707 return NID_sha512;
708 default:
709 throw runtime_error("OpenSSL RSA does not handle hash of size " + std::to_string(hashSize));
710 }
711 }
712
713 std::string OpenSSLRSADNSCryptoKeyEngine::sign(const std::string& message) const
714 {
715 std::string signature;
716
717 #if OPENSSL_VERSION_MAJOR >= 3
718 auto ctx = MessageDigestContext(EVP_MD_CTX_new(), EVP_MD_CTX_free);
719 if (ctx == nullptr) {
720 throw pdns::OpenSSL::error(getName(), "Could not create context for signing");
721 }
722
723 if (EVP_DigestSignInit(ctx.get(), nullptr, hasher(), nullptr, d_key.get()) == 0) {
724 throw pdns::OpenSSL::error(getName(), "Could not initialize context for signing");
725 }
726
727 std::size_t signatureLen = 0;
728 // NOLINTNEXTLINE(*-cast): Using OpenSSL C APIs.
729 const auto* messageData = reinterpret_cast<const unsigned char*>(message.data());
730 if (EVP_DigestSign(ctx.get(), nullptr, &signatureLen, messageData, message.size()) == 0) {
731 throw pdns::OpenSSL::error(getName(), "Could not get message signature length");
732 }
733
734 signature.resize(signatureLen);
735
736 // NOLINTNEXTLINE(*-cast): Using OpenSSL C APIs.
737 auto* signatureData = reinterpret_cast<unsigned char*>(signature.data());
738 if (EVP_DigestSign(ctx.get(), signatureData, &signatureLen, messageData, message.size()) == 0) {
739 throw pdns::OpenSSL::error(getName(), "Could not sign message");
740 }
741 #else
742 unsigned int signatureLen = 0;
743 string l_hash = this->hash(message);
744 int hashKind = hashSizeToKind(l_hash.size());
745 signature.resize(RSA_size(d_key.get()));
746
747 // NOLINTNEXTLINE(*-cast): Using OpenSSL C APIs.
748 int res = RSA_sign(hashKind, reinterpret_cast<unsigned char*>(&l_hash.at(0)), l_hash.length(), reinterpret_cast<unsigned char*>(&signature.at(0)), &signatureLen, d_key.get());
749 if (res != 1) {
750 throw runtime_error(getName() + " failed to generate signature");
751 }
752
753 signature.resize(signatureLen);
754 #endif
755
756 return signature;
757 }
758
759 bool OpenSSLRSADNSCryptoKeyEngine::verify(const std::string& message, const std::string& signature) const
760 {
761 #if OPENSSL_VERSION_MAJOR >= 3
762 auto ctx = MessageDigestContext(EVP_MD_CTX_new(), EVP_MD_CTX_free);
763 if (ctx == nullptr) {
764 throw pdns::OpenSSL::error(getName(), "Failed to create context for verifying signature");
765 }
766
767 if (EVP_DigestVerifyInit(ctx.get(), nullptr, hasher(), nullptr, d_key.get()) == 0) {
768 throw pdns::OpenSSL::error(getName(), "Failed to initialize context for verifying signature");
769 }
770
771 // NOLINTNEXTLINE(*-cast): Using OpenSSL C APIs.
772 const int ret = EVP_DigestVerify(ctx.get(), reinterpret_cast<const unsigned char*>(signature.data()), signature.size(), reinterpret_cast<const unsigned char*>(message.data()), message.size());
773 if (ret < 0) {
774 throw pdns::OpenSSL::error(getName(), "Failed to verify message signature");
775 }
776
777 return (ret == 1);
778 #else
779 string l_hash = this->hash(message);
780 int hashKind = hashSizeToKind(l_hash.size());
781
782 int ret = RSA_verify(hashKind, (const unsigned char*)l_hash.c_str(), l_hash.length(), (unsigned char*)signature.c_str(), signature.length(), d_key.get());
783
784 return (ret == 1);
785 #endif
786 }
787
788 std::string OpenSSLRSADNSCryptoKeyEngine::getPublicKeyString() const
789 {
790 #if OPENSSL_VERSION_MAJOR >= 3
791 // If any of those calls throw, we correctly free the BIGNUMs allocated before it.
792 BigNum modulusPtr = getKeyParamModulus();
793 BigNum publicExponentPtr = getKeyParamPublicExponent();
794
795 // All the calls succeeded, we can take references to the BIGNUM pointers.
796 BIGNUM* modulus = modulusPtr.get();
797 BIGNUM* publicExponent = publicExponentPtr.get();
798 #else
799 const BIGNUM* modulus = nullptr;
800 const BIGNUM* publicExponent = nullptr;
801 const BIGNUM* privateExponent = nullptr;
802 RSA_get0_key(d_key.get(), &modulus, &publicExponent, &privateExponent);
803 #endif
804
805 string keystring;
806 std::string tmp;
807 tmp.resize(std::max(BN_num_bytes(publicExponent), BN_num_bytes(modulus)));
808
809 // NOLINTNEXTLINE(*-cast): Using OpenSSL C APIs.
810 int len = BN_bn2bin(publicExponent, reinterpret_cast<unsigned char*>(&tmp.at(0)));
811 if (len < 255) {
812 keystring.assign(1, (char)(unsigned int)len);
813 }
814 else {
815 keystring.assign(1, 0);
816 uint16_t tempLen = len;
817 tempLen = htons(tempLen);
818 keystring.append((char*)&tempLen, 2);
819 }
820 keystring.append(&tmp.at(0), len);
821
822 // NOLINTNEXTLINE(*-cast): Using OpenSSL C APIs.
823 len = BN_bn2bin(modulus, reinterpret_cast<unsigned char*>(&tmp.at(0)));
824 keystring.append(&tmp.at(0), len);
825
826 return keystring;
827 }
828
829 void OpenSSLRSADNSCryptoKeyEngine::fromISCMap(DNSKEYRecordContent& drc, std::map<std::string, std::string>& stormap)
830 {
831 auto modulus = mapToBN(getName(), stormap, "modulus");
832 auto publicExponent = mapToBN(getName(), stormap, "publicexponent");
833 auto privateExponent = mapToBN(getName(), stormap, "privateexponent");
834
835 auto prime1 = mapToBN(getName(), stormap, "prime1");
836 auto prime2 = mapToBN(getName(), stormap, "prime2");
837
838 auto dmp1 = mapToBN(getName(), stormap, "exponent1");
839 auto dmq1 = mapToBN(getName(), stormap, "exponent2");
840 auto iqmp = mapToBN(getName(), stormap, "coefficient");
841
842 pdns::checked_stoi_into(drc.d_algorithm, stormap["algorithm"]);
843
844 if (drc.d_algorithm != d_algorithm) {
845 throw runtime_error(getName() + " tried to feed an algorithm " + std::to_string(drc.d_algorithm) + " to a " + std::to_string(d_algorithm) + " key");
846 }
847
848 #if OPENSSL_VERSION_MAJOR >= 3
849 auto params = makeKeyParams(modulus.get(), publicExponent.get(), privateExponent.get(), prime1.get(), prime2.get(), dmp1.get(), dmq1.get(), iqmp.get());
850
851 auto ctx = KeyContext(EVP_PKEY_CTX_new_from_name(nullptr, "RSA", nullptr), EVP_PKEY_CTX_free);
852 if (ctx == nullptr) {
853 throw pdns::OpenSSL::error(getName(), "Could not create key context");
854 }
855
856 if (EVP_PKEY_fromdata_init(ctx.get()) <= 0) {
857 throw pdns::OpenSSL::error(getName(), "Could not initialize key context for loading data from ISC");
858 }
859
860 EVP_PKEY* key = nullptr;
861 if (EVP_PKEY_fromdata(ctx.get(), &key, EVP_PKEY_KEYPAIR, params.get()) <= 0) {
862 throw pdns::OpenSSL::error(getName(), "Could not create key from parameters");
863 }
864
865 d_key.reset(key);
866 #else
867 auto key = Key(RSA_new(), RSA_free);
868 if (!key) {
869 throw runtime_error(getName() + " allocation of key structure failed");
870 }
871
872 // Everything OK, we're releasing ownership since the RSA_* functions want it
873 RSA_set0_key(key.get(), modulus.release(), publicExponent.release(), privateExponent.release());
874 RSA_set0_factors(key.get(), prime1.release(), prime2.release());
875 RSA_set0_crt_params(key.get(), dmp1.release(), dmq1.release(), iqmp.release());
876
877 d_key = std::move(key);
878 #endif
879 }
880
881 bool OpenSSLRSADNSCryptoKeyEngine::checkKey(std::optional<std::reference_wrapper<std::vector<std::string>>> errorMessages) const
882 {
883 bool retval = true;
884 // When changing the bitsizes, also edit them in ::create
885 if ((d_algorithm == DNSSECKeeper::RSASHA1 || d_algorithm == DNSSECKeeper::RSASHA1NSEC3SHA1 || d_algorithm == DNSSECKeeper::RSASHA256) && (getBits() < 512 || getBits() > 4096)) {
886 retval = false;
887 if (errorMessages.has_value()) {
888 errorMessages->get().push_back("key is " + std::to_string(getBits()) + " bytes, should be between 512 and 4096");
889 }
890 }
891 if (d_algorithm == DNSSECKeeper::RSASHA512 && (getBits() < 1024 || getBits() > 4096)) {
892 retval = false;
893 if (errorMessages.has_value()) {
894 errorMessages->get().push_back("key is " + std::to_string(getBits()) + " bytes, should be between 1024 and 4096");
895 }
896 }
897
898 #if OPENSSL_VERSION_MAJOR >= 3
899 auto ctx = KeyContext(EVP_PKEY_CTX_new_from_pkey(nullptr, d_key.get(), nullptr), EVP_PKEY_CTX_free);
900 if (ctx == nullptr) {
901 throw pdns::OpenSSL::error(getName(), "Cannot create context to check key");
902 }
903
904 if (EVP_PKEY_pairwise_check(ctx.get()) != 1) {
905 #else
906 if (RSA_check_key(d_key.get()) != 1) {
907 #endif
908 retval = false;
909 if (errorMessages.has_value()) {
910 const auto* errmsg = ERR_error_string(ERR_get_error(), nullptr);
911 if (errmsg == nullptr) {
912 errmsg = "Unknown OpenSSL error";
913 }
914 errorMessages->get().emplace_back(errmsg);
915 }
916 }
917 return retval;
918 }
919
920 void OpenSSLRSADNSCryptoKeyEngine::fromPublicKeyString(const std::string& content)
921 {
922 string publicExponent;
923 string modulus;
924 const size_t contentLen = content.length();
925
926 // NOLINTNEXTLINE(*-cast): Using OpenSSL C APIs.
927 const auto* raw = reinterpret_cast<const unsigned char*>(content.c_str());
928
929 if (contentLen < 1) {
930 throw runtime_error(getName() + " invalid input size for the public key");
931 }
932
933 if (raw[0] != 0) {
934 const size_t exponentSize = raw[0];
935 if (contentLen < (exponentSize + 2)) {
936 throw runtime_error(getName() + " invalid input size for the public key");
937 }
938 publicExponent = content.substr(1, exponentSize);
939 modulus = content.substr(exponentSize + 1);
940 }
941 else {
942 if (contentLen < 3) {
943 throw runtime_error(getName() + " invalid input size for the public key");
944 }
945 const size_t exponentSize = raw[1] * 0xff + raw[2];
946 if (contentLen < (exponentSize + 4)) {
947 throw runtime_error(getName() + " invalid input size for the public key");
948 }
949 publicExponent = content.substr(3, exponentSize);
950 modulus = content.substr(exponentSize + 3);
951 }
952
953 // NOLINTNEXTLINE(*-cast): Using OpenSSL C APIs.
954 auto publicExponentBN = BigNum(BN_bin2bn(reinterpret_cast<unsigned char*>(const_cast<char*>(publicExponent.c_str())), static_cast<int>(publicExponent.length()), nullptr), BN_clear_free);
955 if (!publicExponentBN) {
956 throw runtime_error(getName() + " error loading public exponent (e) value of public key");
957 }
958
959 // NOLINTNEXTLINE(*-cast): Using OpenSSL C APIs.
960 auto modulusBN = BigNum(BN_bin2bn(reinterpret_cast<unsigned char*>(const_cast<char*>(modulus.c_str())), static_cast<int>(modulus.length()), nullptr), BN_clear_free);
961 if (!modulusBN) {
962 throw runtime_error(getName() + " error loading modulus (n) value of public key");
963 }
964
965 #if OPENSSL_VERSION_MAJOR >= 3
966 auto params = makeKeyParams(modulusBN.get(), publicExponentBN.get(), nullptr, nullptr, nullptr, nullptr, nullptr, nullptr);
967
968 auto ctx = KeyContext(EVP_PKEY_CTX_new_from_name(nullptr, "RSA", nullptr), EVP_PKEY_CTX_free);
969 if (ctx == nullptr) {
970 throw pdns::OpenSSL::error(getName(), "Cannot create context to load key from public key data");
971 }
972
973 if (EVP_PKEY_fromdata_init(ctx.get()) <= 0) {
974 throw pdns::OpenSSL::error(getName(), "Could not initialize key context for loading data to check key");
975 }
976
977 EVP_PKEY* key = nullptr;
978 if (EVP_PKEY_fromdata(ctx.get(), &key, EVP_PKEY_PUBLIC_KEY, params.get()) <= 0) {
979 throw pdns::OpenSSL::error(getName(), "Could not create public key from parameters");
980 }
981
982 d_key.reset(key);
983 #else
984 auto key = Key(RSA_new(), RSA_free);
985 if (!key) {
986 throw runtime_error(getName() + " allocation of key structure failed");
987 }
988
989 RSA_set0_key(key.get(), modulusBN.release(), publicExponentBN.release(), nullptr);
990 d_key = std::move(key);
991 #endif
992 }
993
994 #ifdef HAVE_LIBCRYPTO_ECDSA
995 class OpenSSLECDSADNSCryptoKeyEngine : public DNSCryptoKeyEngine
996 {
997 public:
998 explicit OpenSSLECDSADNSCryptoKeyEngine(unsigned int algo);
999
1000 [[nodiscard]] string getName() const override { return "OpenSSL ECDSA"; }
1001 [[nodiscard]] int getBits() const override;
1002
1003 void create(unsigned int bits) override;
1004
1005 /**
1006 * \brief Creates an ECDSA key engine from a PEM file.
1007 *
1008 * Receives an open file handle with PEM contents and creates an ECDSA key engine.
1009 *
1010 * \param[in] drc Key record contents to be populated.
1011 *
1012 * \param[in] inputFile An open file handle to a file containing ECDSA PEM contents.
1013 *
1014 * \param[in] filename Only used for providing filename information in error messages.
1015 *
1016 * \return An ECDSA key engine populated with the contents of the PEM file.
1017 */
1018 void createFromPEMFile(DNSKEYRecordContent& drc, std::FILE& inputFile, std::optional<std::reference_wrapper<const std::string>> filename = std::nullopt) override;
1019
1020 /**
1021 * \brief Writes this key's contents to a file.
1022 *
1023 * Receives an open file handle and writes this key's contents to the
1024 * file.
1025 *
1026 * \param[in] outputFile An open file handle for writing.
1027 *
1028 * \exception std::runtime_error In case of OpenSSL errors.
1029 */
1030 void convertToPEMFile(std::FILE& outputFile) const override;
1031
1032 [[nodiscard]] storvector_t convertToISCVector() const override;
1033 [[nodiscard]] std::string hash(const std::string& message) const override;
1034 [[nodiscard]] std::string sign(const std::string& message) const override;
1035 [[nodiscard]] bool verify(const std::string& message, const std::string& signature) const override;
1036 [[nodiscard]] std::string getPublicKeyString() const override;
1037 void fromISCMap(DNSKEYRecordContent& drc, std::map<std::string, std::string>& stormap) override;
1038 void fromPublicKeyString(const std::string& content) override;
1039 [[nodiscard]] bool checkKey(std::optional<std::reference_wrapper<std::vector<std::string>>> errorMessages) const override;
1040
1041 // TODO Fred: hashSize() and hasher() can probably be completely removed along with
1042 // hash(). See #12464.
1043 [[nodiscard]] std::size_t hashSize() const;
1044 [[nodiscard]] const EVP_MD* hasher() const;
1045
1046 static std::unique_ptr<DNSCryptoKeyEngine> maker(unsigned int algorithm)
1047 {
1048 return make_unique<OpenSSLECDSADNSCryptoKeyEngine>(algorithm);
1049 }
1050
1051 private:
1052 #if OPENSSL_VERSION_MAJOR >= 3
1053 using BigNumContext = std::unique_ptr<BN_CTX, decltype(&BN_CTX_free)>;
1054 using ParamsBuilder = std::unique_ptr<OSSL_PARAM_BLD, decltype(&OSSL_PARAM_BLD_free)>;
1055 using Params = std::unique_ptr<OSSL_PARAM, decltype(&OSSL_PARAM_free)>;
1056 auto makeKeyParams(const std::string& group_name, const BIGNUM* privateKey, const std::optional<std::string>& publicKey) const -> Params;
1057 [[nodiscard]] auto getPrivateKey() const -> BigNum;
1058 #endif
1059
1060 #if OPENSSL_VERSION_MAJOR >= 3
1061 using Key = std::unique_ptr<EVP_PKEY, decltype(&EVP_PKEY_free)>;
1062 using MessageDigestContext = std::unique_ptr<EVP_MD_CTX, decltype(&EVP_MD_CTX_free)>;
1063 #else
1064 using Key = std::unique_ptr<EC_KEY, decltype(&EC_KEY_free)>;
1065 #endif
1066
1067 using KeyContext = std::unique_ptr<EVP_PKEY_CTX, decltype(&EVP_PKEY_CTX_free)>;
1068 using Group = std::unique_ptr<EC_GROUP, decltype(&EC_GROUP_free)>;
1069 using Point = std::unique_ptr<EC_POINT, decltype(&EC_POINT_free)>;
1070 using Signature = std::unique_ptr<ECDSA_SIG, decltype(&ECDSA_SIG_free)>;
1071
1072 int d_len{0};
1073 std::string d_group_name{};
1074 Group d_group{nullptr, EC_GROUP_free};
1075
1076 #if OPENSSL_VERSION_MAJOR >= 3
1077 Key d_eckey{Key(nullptr, EVP_PKEY_free)};
1078 #else
1079 Key d_eckey{Key(nullptr, EC_KEY_free)};
1080 #endif
1081 };
1082
1083 int OpenSSLECDSADNSCryptoKeyEngine::getBits() const
1084 {
1085 return d_len << 3;
1086 }
1087
1088 OpenSSLECDSADNSCryptoKeyEngine::OpenSSLECDSADNSCryptoKeyEngine(unsigned int algo) :
1089 DNSCryptoKeyEngine(algo)
1090 #if OPENSSL_VERSION_MAJOR < 3
1091 ,
1092 d_eckey(Key(EC_KEY_new(), EC_KEY_free))
1093 #endif
1094 {
1095 int ret = RAND_status();
1096 if (ret != 1) {
1097 throw runtime_error(getName() + " insufficient entropy");
1098 }
1099
1100 #if OPENSSL_VERSION_MAJOR < 3
1101 if (!d_eckey) {
1102 throw runtime_error(getName() + " allocation of key structure failed");
1103 }
1104 #endif
1105
1106 int d_id{0};
1107
1108 if (d_algorithm == 13) {
1109 d_group_name = "P-256";
1110 d_len = 32;
1111 d_id = NID_X9_62_prime256v1;
1112 }
1113 else if (d_algorithm == 14) {
1114 d_group_name = "P-384";
1115 d_len = 48;
1116 d_id = NID_secp384r1;
1117 }
1118 else {
1119 throw runtime_error(getName() + " unknown algorithm " + std::to_string(d_algorithm));
1120 }
1121
1122 d_group = Group(EC_GROUP_new_by_curve_name(d_id), EC_GROUP_free);
1123 if (d_group == nullptr) {
1124 throw pdns::OpenSSL::error(getName(), std::string() + "Failed to create EC group `" + d_group_name + "` to export public key");
1125 }
1126
1127 #if OPENSSL_VERSION_MAJOR < 3
1128 ret = EC_KEY_set_group(d_eckey.get(), d_group.get());
1129 if (ret != 1) {
1130 throw runtime_error(getName() + " setting key group failed");
1131 }
1132 #endif
1133 }
1134
1135 void OpenSSLECDSADNSCryptoKeyEngine::create(unsigned int bits)
1136 {
1137 if (bits >> 3 != static_cast<unsigned int>(d_len)) {
1138 throw runtime_error(getName() + " unknown key length of " + std::to_string(bits) + " bits requested");
1139 }
1140
1141 #if OPENSSL_VERSION_MAJOR >= 3
1142 // NOLINTNEXTLINE(*-vararg): Using OpenSSL C APIs.
1143 EVP_PKEY* key = EVP_PKEY_Q_keygen(nullptr, nullptr, "EC", d_group_name.c_str());
1144 if (key == nullptr) {
1145 throw pdns::OpenSSL::error(getName(), "Failed to generate key");
1146 }
1147
1148 d_eckey.reset(key);
1149 #else
1150 int res = EC_KEY_generate_key(d_eckey.get());
1151 if (res == 0) {
1152 throw runtime_error(getName() + " key generation failed");
1153 }
1154
1155 EC_KEY_set_asn1_flag(d_eckey.get(), OPENSSL_EC_NAMED_CURVE);
1156 #endif
1157 }
1158
1159 void OpenSSLECDSADNSCryptoKeyEngine::createFromPEMFile(DNSKEYRecordContent& drc, std::FILE& inputFile, std::optional<std::reference_wrapper<const std::string>> filename)
1160 {
1161 drc.d_algorithm = d_algorithm;
1162
1163 #if OPENSSL_VERSION_MAJOR >= 3
1164 EVP_PKEY* key = nullptr;
1165 if (PEM_read_PrivateKey(&inputFile, &key, nullptr, nullptr) == nullptr) {
1166 if (filename.has_value()) {
1167 throw pdns::OpenSSL::error(getName(), "Failed to read private key from PEM file `" + filename->get() + "`");
1168 }
1169
1170 throw pdns::OpenSSL::error(getName(), "Failed to read private key from PEM contents");
1171 }
1172
1173 d_eckey.reset(key);
1174 #else
1175 d_eckey = Key(PEM_read_ECPrivateKey(&inputFile, nullptr, nullptr, nullptr), &EC_KEY_free);
1176 if (d_eckey == nullptr) {
1177 if (filename.has_value()) {
1178 throw runtime_error(getName() + ": Failed to read private key from PEM file `" + filename->get() + "`");
1179 }
1180
1181 throw runtime_error(getName() + ": Failed to read private key from PEM contents");
1182 }
1183
1184 int ret = EC_KEY_set_group(d_eckey.get(), d_group.get());
1185 if (ret != 1) {
1186 throw runtime_error(getName() + " setting key group failed");
1187 }
1188
1189 const BIGNUM* privateKeyBN = EC_KEY_get0_private_key(d_eckey.get());
1190
1191 auto pub_key = Point(EC_POINT_new(d_group.get()), EC_POINT_free);
1192 if (!pub_key) {
1193 throw runtime_error(getName() + " allocation of public key point failed");
1194 }
1195
1196 ret = EC_POINT_mul(d_group.get(), pub_key.get(), privateKeyBN, nullptr, nullptr, nullptr);
1197 if (ret != 1) {
1198 throw runtime_error(getName() + " computing public key from private failed");
1199 }
1200
1201 ret = EC_KEY_set_public_key(d_eckey.get(), pub_key.get());
1202 if (ret != 1) {
1203 ERR_print_errors_fp(stderr);
1204 throw runtime_error(getName() + " setting public key failed");
1205 }
1206
1207 EC_KEY_set_asn1_flag(d_eckey.get(), OPENSSL_EC_NAMED_CURVE);
1208 #endif
1209 }
1210
1211 void OpenSSLECDSADNSCryptoKeyEngine::convertToPEMFile(std::FILE& outputFile) const
1212 {
1213 #if OPENSSL_VERSION_MAJOR >= 3
1214 if (PEM_write_PrivateKey(&outputFile, d_eckey.get(), nullptr, nullptr, 0, nullptr, nullptr) == 0) {
1215 throw pdns::OpenSSL::error(getName(), "Failed to convert private key to PEM");
1216 }
1217 #else
1218 auto ret = PEM_write_ECPrivateKey(&outputFile, d_eckey.get(), nullptr, nullptr, 0, nullptr, nullptr);
1219 if (ret == 0) {
1220 throw runtime_error(getName() + ": Could not convert private key to PEM");
1221 }
1222 #endif
1223 }
1224
1225 #if OPENSSL_VERSION_MAJOR >= 3
1226 auto OpenSSLECDSADNSCryptoKeyEngine::getPrivateKey() const -> BigNum
1227 {
1228 BIGNUM* privateKey = nullptr;
1229 if (EVP_PKEY_get_bn_param(d_eckey.get(), OSSL_PKEY_PARAM_PRIV_KEY, &privateKey) == 0) {
1230 throw pdns::OpenSSL::error(getName(), "Could not get private key parameter");
1231 }
1232 return BigNum{privateKey, BN_clear_free};
1233 }
1234 #endif
1235
1236 DNSCryptoKeyEngine::storvector_t OpenSSLECDSADNSCryptoKeyEngine::convertToISCVector() const
1237 {
1238 storvector_t storvect;
1239 string algorithm;
1240
1241 if (d_algorithm == 13) {
1242 algorithm = "13 (ECDSAP256SHA256)";
1243 }
1244 else if (d_algorithm == 14) {
1245 algorithm = "14 (ECDSAP384SHA384)";
1246 }
1247 else {
1248 algorithm = " ? (?)";
1249 }
1250
1251 storvect.emplace_back("Algorithm", algorithm);
1252
1253 #if OPENSSL_VERSION_MAJOR >= 3
1254 auto privateKeyBN = getPrivateKey();
1255
1256 std::string privateKey;
1257 privateKey.resize(BN_num_bytes(privateKeyBN.get()));
1258 // NOLINTNEXTLINE(*-cast): Using OpenSSL C APIs.
1259 int len = BN_bn2bin(privateKeyBN.get(), reinterpret_cast<unsigned char*>(privateKey.data()));
1260 if (len >= 0) {
1261 privateKey.resize(len);
1262
1263 std::string prefix;
1264 if (d_len - len != 0) {
1265 prefix.append(d_len - len, 0x00);
1266 }
1267
1268 storvect.emplace_back("PrivateKey", prefix + privateKey);
1269 }
1270 #else
1271 const BIGNUM* key = EC_KEY_get0_private_key(d_eckey.get());
1272 if (key == nullptr) {
1273 throw runtime_error(getName() + " private key not set");
1274 }
1275
1276 std::string tmp;
1277 tmp.resize(BN_num_bytes(key));
1278 int len = BN_bn2bin(key, reinterpret_cast<unsigned char*>(&tmp.at(0)));
1279
1280 string prefix;
1281 if (d_len - len) {
1282 prefix.append(d_len - len, 0x00);
1283 }
1284
1285 storvect.emplace_back("PrivateKey", prefix + tmp);
1286 #endif
1287
1288 return storvect;
1289 }
1290
1291 std::string OpenSSLECDSADNSCryptoKeyEngine::hash(const std::string& message) const
1292 {
1293 if (getBits() == 256) {
1294 std::string l_hash{};
1295 l_hash.resize(SHA256_DIGEST_LENGTH);
1296 // NOLINTNEXTLINE(*-cast): Using OpenSSL C APIs.
1297 SHA256(reinterpret_cast<unsigned char*>(const_cast<char*>(message.c_str())), message.length(), reinterpret_cast<unsigned char*>(l_hash.data()));
1298 return l_hash;
1299 }
1300
1301 if (getBits() == 384) {
1302 std::string l_hash{};
1303 l_hash.resize(SHA384_DIGEST_LENGTH);
1304 // NOLINTNEXTLINE(*-cast): Using OpenSSL C APIs.
1305 SHA384(reinterpret_cast<unsigned char*>(const_cast<char*>(message.c_str())), message.length(), reinterpret_cast<unsigned char*>(l_hash.data()));
1306 return l_hash;
1307 }
1308
1309 throw runtime_error(getName() + " does not support a hash size of " + std::to_string(getBits()) + " bits");
1310 }
1311
1312 const EVP_MD* OpenSSLECDSADNSCryptoKeyEngine::hasher() const
1313 {
1314 const EVP_MD* messageDigest = nullptr;
1315
1316 switch (d_algorithm) {
1317 case DNSSECKeeper::ECDSA256:
1318 messageDigest = EVP_sha256();
1319 break;
1320 case DNSSECKeeper::ECDSA384:
1321 messageDigest = EVP_sha384();
1322 break;
1323 default:
1324 throw runtime_error(getName() + " does not support hash operations for algorithm " + std::to_string(d_algorithm));
1325 }
1326
1327 if (messageDigest == nullptr) {
1328 throw std::runtime_error("Could not retrieve a SHA implementation of size " + std::to_string(hashSize()) + " from OpenSSL");
1329 }
1330
1331 return messageDigest;
1332 }
1333
1334 std::size_t OpenSSLECDSADNSCryptoKeyEngine::hashSize() const
1335 {
1336 switch (d_algorithm) {
1337 case DNSSECKeeper::ECDSA256:
1338 return SHA256_DIGEST_LENGTH;
1339 case DNSSECKeeper::ECDSA384:
1340 return SHA384_DIGEST_LENGTH;
1341 default:
1342 throw runtime_error(getName() + " does not support hash operations for algorithm " + std::to_string(d_algorithm));
1343 }
1344 }
1345
1346 std::string OpenSSLECDSADNSCryptoKeyEngine::sign(const std::string& message) const
1347 {
1348 #if OPENSSL_VERSION_MAJOR >= 3
1349 auto ctx = MessageDigestContext(EVP_MD_CTX_new(), EVP_MD_CTX_free);
1350 if (ctx == nullptr) {
1351 throw pdns::OpenSSL::error(getName(), "Could not create context for signing");
1352 }
1353
1354 if (EVP_DigestSignInit(ctx.get(), nullptr, hasher(), nullptr, d_eckey.get()) == 0) {
1355 throw pdns::OpenSSL::error(getName(), "Could not initialize context for signing");
1356 }
1357
1358 std::size_t signatureLen = 0;
1359
1360 // NOLINTNEXTLINE(*-cast): Using OpenSSL C APIs.
1361 const auto* messageData = reinterpret_cast<const unsigned char*>(message.data());
1362 if (EVP_DigestSign(ctx.get(), nullptr, &signatureLen, messageData, message.size()) == 0) {
1363 throw pdns::OpenSSL::error(getName(), "Could not get message signature length");
1364 }
1365
1366 std::string signatureBuffer;
1367 signatureBuffer.resize(signatureLen);
1368
1369 // NOLINTNEXTLINE(*-cast): Using OpenSSL C APIs.
1370 auto* signatureData = reinterpret_cast<unsigned char*>(signatureBuffer.data());
1371 if (EVP_DigestSign(ctx.get(), signatureData, &signatureLen, messageData, message.size()) == 0) {
1372 throw pdns::OpenSSL::error(getName(), "Could not sign message");
1373 }
1374
1375 signatureBuffer.resize(signatureLen);
1376
1377 // NOLINTNEXTLINE(*-cast): Using OpenSSL C APIs.
1378 auto signature = Signature(d2i_ECDSA_SIG(nullptr, const_cast<const unsigned char**>(&signatureData), (long)signatureLen), ECDSA_SIG_free);
1379 if (signature == nullptr) {
1380 throw pdns::OpenSSL::error(getName(), "Failed to convert DER signature to internal structure");
1381 }
1382 #else
1383 string l_hash = this->hash(message);
1384
1385 auto signature = Signature(ECDSA_do_sign((unsigned char*)l_hash.c_str(), l_hash.length(), d_eckey.get()), ECDSA_SIG_free);
1386 if (!signature) {
1387 throw runtime_error(getName() + " failed to generate signature");
1388 }
1389 #endif
1390
1391 string ret;
1392 std::string tmp;
1393 tmp.resize(d_len);
1394
1395 const BIGNUM* prComponent = nullptr;
1396 const BIGNUM* psComponent = nullptr;
1397 ECDSA_SIG_get0(signature.get(), &prComponent, &psComponent);
1398 // NOLINTNEXTLINE(*-cast): Using OpenSSL C APIs.
1399 int len = BN_bn2bin(prComponent, reinterpret_cast<unsigned char*>(&tmp.at(0)));
1400 if ((d_len - len) != 0) {
1401 ret.append(d_len - len, 0x00);
1402 }
1403 ret.append(&tmp.at(0), len);
1404
1405 // NOLINTNEXTLINE(*-cast): Using OpenSSL C APIs.
1406 len = BN_bn2bin(psComponent, reinterpret_cast<unsigned char*>(&tmp.at(0)));
1407 if ((d_len - len) != 0) {
1408 ret.append(d_len - len, 0x00);
1409 }
1410 ret.append(&tmp.at(0), len);
1411
1412 return ret;
1413 }
1414
1415 bool OpenSSLECDSADNSCryptoKeyEngine::verify(const std::string& message, const std::string& signature) const
1416 {
1417 if (signature.length() != (static_cast<unsigned long>(d_len) * 2)) {
1418 throw runtime_error(getName() + " invalid signature size " + std::to_string(signature.length()));
1419 }
1420
1421 // NOLINTNEXTLINE(*-cast): Using OpenSSL C APIs.
1422 auto* signatureCStr = const_cast<unsigned char*>(reinterpret_cast<const unsigned char*>(signature.c_str()));
1423 auto rComponent = BigNum(BN_bin2bn(signatureCStr, d_len, nullptr), BN_free);
1424 auto sComponent = BigNum(BN_bin2bn(signatureCStr + d_len, d_len, nullptr), BN_free);
1425 if (!rComponent || !sComponent) {
1426 throw runtime_error(getName() + " invalid signature");
1427 }
1428
1429 auto sig = Signature(ECDSA_SIG_new(), ECDSA_SIG_free);
1430 if (!sig) {
1431 throw runtime_error(getName() + " allocation of signature structure failed");
1432 }
1433 ECDSA_SIG_set0(sig.get(), rComponent.release(), sComponent.release());
1434
1435 #if OPENSSL_VERSION_MAJOR >= 3
1436 unsigned char* derBufferPointer = nullptr;
1437 const int derBufferSize = i2d_ECDSA_SIG(sig.get(), &derBufferPointer);
1438 if (derBufferSize < 0) {
1439 throw pdns::OpenSSL::error(getName(), "Failed to convert signature to DER");
1440 }
1441 // Because OPENSSL_free() is a macro.
1442 auto derBuffer = unique_ptr<unsigned char, void (*)(unsigned char*)>{derBufferPointer, [](auto* buffer) { OPENSSL_free(buffer); }};
1443
1444 auto ctx = MessageDigestContext(EVP_MD_CTX_new(), EVP_MD_CTX_free);
1445 if (ctx == nullptr) {
1446 throw pdns::OpenSSL::error(getName(), "Could not create message digest context for signing");
1447 }
1448
1449 if (EVP_DigestVerifyInit(ctx.get(), nullptr, hasher(), nullptr, d_eckey.get()) == 0) {
1450 throw pdns::OpenSSL::error(getName(), "Could not initialize context for verifying signature");
1451 }
1452
1453 // NOLINTNEXTLINE(*-cast): Using OpenSSL C APIs.
1454 const auto ret = EVP_DigestVerify(ctx.get(), derBuffer.get(), derBufferSize, reinterpret_cast<const unsigned char*>(message.data()), message.size());
1455 if (ret < 0) {
1456 throw pdns::OpenSSL::error(getName(), "Could not verify message signature");
1457 }
1458
1459 return (ret == 1);
1460 #else
1461 string l_hash = this->hash(message);
1462
1463 int ret = ECDSA_do_verify((unsigned char*)l_hash.c_str(), l_hash.length(), sig.get(), d_eckey.get());
1464 if (ret == -1) {
1465 throw runtime_error(getName() + " verify error");
1466 }
1467
1468 return (ret == 1);
1469 #endif
1470 }
1471
1472 std::string OpenSSLECDSADNSCryptoKeyEngine::getPublicKeyString() const
1473 {
1474 #if OPENSSL_VERSION_MAJOR >= 3
1475 size_t bufsize = 0;
1476 if (EVP_PKEY_get_octet_string_param(d_eckey.get(), OSSL_PKEY_PARAM_PUB_KEY, nullptr, 0, &bufsize) == 0) {
1477 throw pdns::OpenSSL::error(getName(), "Failed to get public key buffer size");
1478 }
1479
1480 std::string publicKey{};
1481 publicKey.resize(bufsize);
1482
1483 // NOLINTNEXTLINE(*-cast): Using OpenSSL C APIs.
1484 auto* publicKeyCStr = const_cast<unsigned char*>(reinterpret_cast<const unsigned char*>(publicKey.c_str()));
1485 if (EVP_PKEY_get_octet_string_param(d_eckey.get(), OSSL_PKEY_PARAM_PUB_KEY, publicKeyCStr, bufsize, &bufsize) == 0) {
1486 throw pdns::OpenSSL::error(getName(), "Failed to get public key");
1487 }
1488
1489 publicKey.resize(bufsize);
1490
1491 auto publicKeyECPoint = Point(EC_POINT_new(d_group.get()), EC_POINT_free);
1492 if (publicKeyECPoint == nullptr) {
1493 throw pdns::OpenSSL::error(getName(), "Failed to create public key point for export");
1494 }
1495
1496 auto ctx = BigNumContext(BN_CTX_new(), BN_CTX_free);
1497
1498 // NOLINTNEXTLINE(*-cast): Using OpenSSL C APIs.
1499 publicKeyCStr = const_cast<unsigned char*>(reinterpret_cast<const unsigned char*>(publicKey.c_str()));
1500 if (EC_POINT_oct2point(d_group.get(), publicKeyECPoint.get(), publicKeyCStr, publicKey.length(), ctx.get()) == 0) {
1501 throw pdns::OpenSSL::error(getName(), "Failed to export public key to point");
1502 }
1503
1504 std::string publicKeyUncompressed{};
1505 bufsize = EC_POINT_point2oct(d_group.get(), publicKeyECPoint.get(), POINT_CONVERSION_UNCOMPRESSED, nullptr, 0, nullptr);
1506 if (bufsize == 0) {
1507 throw pdns::OpenSSL::error(getName(), "Failed to get public key binary buffer size");
1508 }
1509 publicKeyUncompressed.resize(bufsize);
1510
1511 // NOLINTNEXTLINE(*-cast): Using OpenSSL C APIs.
1512 auto* publicKeyUncompressedCStr = const_cast<unsigned char*>(reinterpret_cast<const unsigned char*>(publicKeyUncompressed.c_str()));
1513 bufsize = EC_POINT_point2oct(d_group.get(), publicKeyECPoint.get(), POINT_CONVERSION_UNCOMPRESSED, publicKeyUncompressedCStr, publicKeyUncompressed.length(), nullptr);
1514 if (bufsize == 0) {
1515 throw pdns::OpenSSL::error(getName(), "Failed to convert public key to oct");
1516 }
1517
1518 /* We skip the first byte as the other backends use raw field elements, as opposed to
1519 * the format described in SEC1: "2.3.3 Elliptic-Curve-Point-to-Octet-String
1520 * Conversion" */
1521 publicKeyUncompressed.erase(0, 1);
1522
1523 return publicKeyUncompressed;
1524 #else
1525 std::string binaryPoint;
1526 binaryPoint.resize((d_len * 2) + 1);
1527
1528 int ret = EC_POINT_point2oct(d_group.get(), EC_KEY_get0_public_key(d_eckey.get()), POINT_CONVERSION_UNCOMPRESSED, reinterpret_cast<unsigned char*>(&binaryPoint.at(0)), binaryPoint.size(), nullptr);
1529 if (ret == 0) {
1530 throw runtime_error(getName() + " exporting point to binary failed");
1531 }
1532
1533 /* we skip the first byte as the other backends use
1534 raw field elements, as opposed to the format described in
1535 SEC1: "2.3.3 Elliptic-Curve-Point-to-Octet-String Conversion" */
1536 binaryPoint.erase(0, 1);
1537 return binaryPoint;
1538 #endif
1539 }
1540
1541 #if OPENSSL_VERSION_MAJOR >= 3
1542 auto OpenSSLECDSADNSCryptoKeyEngine::makeKeyParams(const std::string& group_name, const BIGNUM* privateKey, const std::optional<std::string>& publicKey) const -> Params
1543 {
1544 auto params_build = ParamsBuilder(OSSL_PARAM_BLD_new(), OSSL_PARAM_BLD_free);
1545 if (params_build == nullptr) {
1546 throw pdns::OpenSSL::error(getName(), "Failed to create key's parameters builder");
1547 }
1548
1549 if ((!group_name.empty()) && OSSL_PARAM_BLD_push_utf8_string(params_build.get(), OSSL_PKEY_PARAM_GROUP_NAME, group_name.c_str(), group_name.length()) == 0) {
1550 throw pdns::OpenSSL::error(getName(), "Failed to create key's group parameter");
1551 }
1552
1553 if ((privateKey != nullptr) && OSSL_PARAM_BLD_push_BN(params_build.get(), OSSL_PKEY_PARAM_PRIV_KEY, privateKey) == 0) {
1554 throw pdns::OpenSSL::error(getName(), "Failed to create private key parameter");
1555 }
1556
1557 if (publicKey.has_value()) {
1558 if (OSSL_PARAM_BLD_push_octet_string(params_build.get(), OSSL_PKEY_PARAM_PUB_KEY, publicKey->c_str(), publicKey->length()) == 0) {
1559 throw pdns::OpenSSL::error(getName(), "Failed to create public key parameter");
1560 }
1561 }
1562
1563 auto params = Params(OSSL_PARAM_BLD_to_param(params_build.get()), OSSL_PARAM_free);
1564 if (params == nullptr) {
1565 throw pdns::OpenSSL::error(getName(), "Failed to create key's parameters");
1566 }
1567
1568 return params;
1569 }
1570 #endif
1571
1572 void OpenSSLECDSADNSCryptoKeyEngine::fromISCMap(DNSKEYRecordContent& drc, std::map<std::string, std::string>& stormap)
1573 {
1574 drc.d_algorithm = atoi(stormap["algorithm"].c_str());
1575
1576 if (drc.d_algorithm != d_algorithm) {
1577 throw runtime_error(getName() + " tried to feed an algorithm " + std::to_string(drc.d_algorithm) + " to a " + std::to_string(d_algorithm) + " key");
1578 }
1579
1580 auto privateKey = mapToBN(getName(), stormap, "privatekey");
1581
1582 #if OPENSSL_VERSION_MAJOR >= 3
1583 auto publicKeyECPoint = Point(EC_POINT_new(d_group.get()), EC_POINT_free);
1584 if (publicKeyECPoint == nullptr) {
1585 throw pdns::OpenSSL::error(getName(), "Failed to create public key point to import from ISC");
1586 }
1587
1588 if (EC_POINT_mul(d_group.get(), publicKeyECPoint.get(), privateKey.get(), nullptr, nullptr, nullptr) == 0) {
1589 throw pdns::OpenSSL::error(getName(), "Failed to derive public key from ISC private key");
1590 }
1591
1592 std::string publicKey{};
1593 size_t bufsize = EC_POINT_point2oct(d_group.get(), publicKeyECPoint.get(), POINT_CONVERSION_COMPRESSED, nullptr, 0, nullptr);
1594 if (bufsize == 0) {
1595 throw pdns::OpenSSL::error(getName(), "Failed to get public key binary buffer size");
1596 }
1597 publicKey.resize(bufsize);
1598
1599 // NOLINTNEXTLINE(*-cast): Using OpenSSL C APIs.
1600 auto* publicKeyData = reinterpret_cast<unsigned char*>(publicKey.data());
1601 bufsize = EC_POINT_point2oct(d_group.get(), publicKeyECPoint.get(), POINT_CONVERSION_COMPRESSED, publicKeyData, publicKey.length(), nullptr);
1602 if (bufsize == 0) {
1603 throw pdns::OpenSSL::error(getName(), "Failed to convert public key to oct");
1604 }
1605
1606 auto params = makeKeyParams(d_group_name, privateKey.get(), std::make_optional(publicKey));
1607
1608 auto ctx = KeyContext(EVP_PKEY_CTX_new_from_name(nullptr, "EC", nullptr), EVP_PKEY_CTX_free);
1609 if (ctx == nullptr) {
1610 throw pdns::OpenSSL::error(getName(), "Could not create key context");
1611 }
1612
1613 if (EVP_PKEY_fromdata_init(ctx.get()) <= 0) {
1614 throw pdns::OpenSSL::error(getName(), "Could not initialize key context for loading data from ISC");
1615 }
1616
1617 EVP_PKEY* key = nullptr;
1618 if (EVP_PKEY_fromdata(ctx.get(), &key, EVP_PKEY_KEYPAIR, params.get()) <= 0) {
1619 throw pdns::OpenSSL::error(getName(), "Could not create key from parameters");
1620 }
1621
1622 d_eckey.reset(key);
1623 #else
1624 int ret = EC_KEY_set_private_key(d_eckey.get(), privateKey.get());
1625 if (ret != 1) {
1626 throw runtime_error(getName() + " setting private key failed");
1627 }
1628
1629 auto pub_key = Point(EC_POINT_new(d_group.get()), EC_POINT_free);
1630 if (!pub_key) {
1631 throw runtime_error(getName() + " allocation of public key point failed");
1632 }
1633
1634 ret = EC_POINT_mul(d_group.get(), pub_key.get(), privateKey.get(), nullptr, nullptr, nullptr);
1635 if (ret != 1) {
1636 throw runtime_error(getName() + " computing public key from private failed");
1637 }
1638
1639 ret = EC_KEY_set_public_key(d_eckey.get(), pub_key.get());
1640 if (ret != 1) {
1641 throw runtime_error(getName() + " setting public key failed");
1642 }
1643
1644 EC_KEY_set_asn1_flag(d_eckey.get(), OPENSSL_EC_NAMED_CURVE);
1645 #endif
1646 }
1647
1648 bool OpenSSLECDSADNSCryptoKeyEngine::checkKey(std::optional<std::reference_wrapper<std::vector<std::string>>> errorMessages) const
1649 {
1650 #if OPENSSL_VERSION_MAJOR >= 3
1651 auto ctx = KeyContext{EVP_PKEY_CTX_new_from_pkey(nullptr, d_eckey.get(), nullptr), EVP_PKEY_CTX_free};
1652 if (ctx == nullptr) {
1653 throw pdns::OpenSSL::error(getName(), "Failed to create context to check key");
1654 }
1655
1656 bool retval = true;
1657
1658 auto addOpenSSLErrorMessageOnFail = [errorMessages, &retval](const int errorCode, const auto defaultErrorMessage) {
1659 // Error code of -2 means the check is not supported for the algorithm, which is fine.
1660 if (errorCode != 1 && errorCode != -2) {
1661 retval = false;
1662
1663 if (errorMessages.has_value()) {
1664 const auto* errorMessage = ERR_reason_error_string(ERR_get_error());
1665 if (errorMessage == nullptr) {
1666 errorMessages->get().push_back(defaultErrorMessage);
1667 }
1668 else {
1669 errorMessages->get().emplace_back(errorMessage);
1670 }
1671 }
1672 }
1673 };
1674
1675 addOpenSSLErrorMessageOnFail(EVP_PKEY_param_check(ctx.get()), getName() + "Unknown OpenSSL error during key param check");
1676 addOpenSSLErrorMessageOnFail(EVP_PKEY_public_check(ctx.get()), getName() + "Unknown OpenSSL error during public key check");
1677 addOpenSSLErrorMessageOnFail(EVP_PKEY_private_check(ctx.get()), getName() + "Unknown OpenSSL error during private key check");
1678 addOpenSSLErrorMessageOnFail(EVP_PKEY_pairwise_check(ctx.get()), getName() + "Unknown OpenSSL error during key pairwise check");
1679
1680 return retval;
1681 #else
1682 bool retval = true;
1683 if (EC_KEY_check_key(d_eckey.get()) != 1) {
1684 retval = false;
1685 if (errorMessages.has_value()) {
1686 const auto* errmsg = ERR_reason_error_string(ERR_get_error());
1687 if (errmsg == nullptr) {
1688 errmsg = "Unknown OpenSSL error";
1689 }
1690 errorMessages->get().push_back(errmsg);
1691 }
1692 }
1693 return retval;
1694 #endif
1695 }
1696
1697 void OpenSSLECDSADNSCryptoKeyEngine::fromPublicKeyString(const std::string& content)
1698 {
1699 #if OPENSSL_VERSION_MAJOR >= 3
1700 /* uncompressed point, from SEC1: "2.3.4 Octet-String-to-Elliptic-Curve-Point
1701 * Conversion"
1702 */
1703 std::string publicKey = "\x04";
1704 publicKey.append(content);
1705
1706 auto params = makeKeyParams(d_group_name, nullptr, std::make_optional(publicKey));
1707
1708 auto ctx = KeyContext(EVP_PKEY_CTX_new_from_name(nullptr, "EC", nullptr), EVP_PKEY_CTX_free);
1709 if (ctx == nullptr) {
1710 throw pdns::OpenSSL::error(getName(), "Failed to create key context");
1711 }
1712
1713 if (EVP_PKEY_fromdata_init(ctx.get()) <= 0) {
1714 throw pdns::OpenSSL::error(getName(), "Failed to initialize key context for loading data from ISC");
1715 }
1716
1717 EVP_PKEY* key = nullptr;
1718 if (EVP_PKEY_fromdata(ctx.get(), &key, EVP_PKEY_PUBLIC_KEY, params.get()) <= 0) {
1719 throw pdns::OpenSSL::error(getName(), "Failed to create key from parameters");
1720 }
1721
1722 d_eckey.reset(key);
1723 #else
1724 /* uncompressed point, from SEC1: "2.3.4 Octet-String-to-Elliptic-Curve-Point
1725 * Conversion"
1726 */
1727 string ecdsaPoint = "\x04";
1728 ecdsaPoint.append(content);
1729
1730 auto pub_key = Point(EC_POINT_new(d_group.get()), EC_POINT_free);
1731 if (!pub_key) {
1732 throw runtime_error(getName() + " allocation of point structure failed");
1733 }
1734
1735 int ret = EC_POINT_oct2point(d_group.get(), pub_key.get(), (unsigned char*)ecdsaPoint.c_str(), ecdsaPoint.length(), nullptr);
1736 if (ret != 1) {
1737 throw runtime_error(getName() + " reading ECP point from binary failed");
1738 }
1739
1740 ret = EC_KEY_set_private_key(d_eckey.get(), nullptr);
1741 if (ret == 1) {
1742 throw runtime_error(getName() + " setting private key failed");
1743 }
1744
1745 ret = EC_KEY_set_public_key(d_eckey.get(), pub_key.get());
1746 if (ret != 1) {
1747 throw runtime_error(getName() + " setting public key failed");
1748 }
1749 #endif
1750 }
1751 #endif
1752
1753 #ifdef HAVE_LIBCRYPTO_EDDSA
1754 class OpenSSLEDDSADNSCryptoKeyEngine : public DNSCryptoKeyEngine
1755 {
1756 public:
1757 explicit OpenSSLEDDSADNSCryptoKeyEngine(unsigned int algo);
1758
1759 [[nodiscard]] string getName() const override { return "OpenSSL EdDSA"; }
1760 [[nodiscard]] int getBits() const override;
1761
1762 void create(unsigned int bits) override;
1763
1764 /**
1765 * \brief Creates an EDDSA key engine from a PEM file.
1766 *
1767 * Receives an open file handle with PEM contents and creates an EDDSA key engine.
1768 *
1769 * \param[in] drc Key record contents to be populated.
1770 *
1771 * \param[in] inputFile An open file handle to a file containing EDDSA PEM contents.
1772 *
1773 * \param[in] filename Only used for providing filename information in error messages.
1774 *
1775 * \return An EDDSA key engine populated with the contents of the PEM file.
1776 */
1777 void createFromPEMFile(DNSKEYRecordContent& drc, std::FILE& inputFile, std::optional<std::reference_wrapper<const std::string>> filename = std::nullopt) override;
1778
1779 /**
1780 * \brief Writes this key's contents to a file.
1781 *
1782 * Receives an open file handle and writes this key's contents to the
1783 * file.
1784 *
1785 * \param[in] outputFile An open file handle for writing.
1786 *
1787 * \exception std::runtime_error In case of OpenSSL errors.
1788 */
1789 void convertToPEMFile(std::FILE& outputFile) const override;
1790
1791 [[nodiscard]] storvector_t convertToISCVector() const override;
1792 [[nodiscard]] std::string sign(const std::string& msg) const override;
1793 [[nodiscard]] bool verify(const std::string& message, const std::string& signature) const override;
1794 [[nodiscard]] std::string getPublicKeyString() const override;
1795 void fromISCMap(DNSKEYRecordContent& drc, std::map<std::string, std::string>& stormap) override;
1796 void fromPublicKeyString(const std::string& content) override;
1797 [[nodiscard]] bool checkKey(std::optional<std::reference_wrapper<std::vector<std::string>>> errorMessages) const override;
1798
1799 static std::unique_ptr<DNSCryptoKeyEngine> maker(unsigned int algorithm)
1800 {
1801 return make_unique<OpenSSLEDDSADNSCryptoKeyEngine>(algorithm);
1802 }
1803
1804 using Key = unique_ptr<EVP_PKEY, decltype(&EVP_PKEY_free)>;
1805 using KeyContext = std::unique_ptr<EVP_PKEY_CTX, decltype(&EVP_PKEY_CTX_free)>;
1806 using MessageDigestContext = std::unique_ptr<EVP_MD_CTX, decltype(&EVP_MD_CTX_free)>;
1807
1808 private:
1809 size_t d_len{0};
1810 int d_id{0};
1811
1812 Key d_edkey;
1813 };
1814
1815 OpenSSLEDDSADNSCryptoKeyEngine::OpenSSLEDDSADNSCryptoKeyEngine(unsigned int algo) :
1816 DNSCryptoKeyEngine(algo),
1817 d_edkey(Key(nullptr, EVP_PKEY_free))
1818 {
1819 int ret = RAND_status();
1820 if (ret != 1) {
1821 throw runtime_error(getName() + " insufficient entropy");
1822 }
1823
1824 #ifdef HAVE_LIBCRYPTO_ED25519
1825 if (d_algorithm == 15) {
1826 d_len = 32;
1827 d_id = NID_ED25519;
1828 }
1829 #endif
1830 #ifdef HAVE_LIBCRYPTO_ED448
1831 if (d_algorithm == 16) {
1832 d_len = 57;
1833 d_id = NID_ED448;
1834 }
1835 #endif
1836 if (d_len == 0) {
1837 throw runtime_error(getName() + " unknown algorithm " + std::to_string(d_algorithm));
1838 }
1839 }
1840
1841 int OpenSSLEDDSADNSCryptoKeyEngine::getBits() const
1842 {
1843 return (int)d_len << 3;
1844 }
1845
1846 bool OpenSSLEDDSADNSCryptoKeyEngine::checkKey([[maybe_unused]] std::optional<std::reference_wrapper<std::vector<std::string>>> errorMessages) const
1847 {
1848 #if OPENSSL_VERSION_MAJOR >= 3
1849 auto ctx = KeyContext{EVP_PKEY_CTX_new_from_pkey(nullptr, d_edkey.get(), nullptr), EVP_PKEY_CTX_free};
1850 if (ctx == nullptr) {
1851 throw pdns::OpenSSL::error(getName(), "Failed to create context to check key");
1852 }
1853
1854 bool retval = true;
1855
1856 auto addOpenSSLErrorMessageOnFail = [errorMessages, &retval](const int errorCode, const auto defaultErrorMessage) {
1857 // Error code of -2 means the check is not supported for the algorithm, which is fine.
1858 if (errorCode != 1 && errorCode != -2) {
1859 retval = false;
1860
1861 if (errorMessages.has_value()) {
1862 const auto* errorMessage = ERR_reason_error_string(ERR_get_error());
1863 if (errorMessage == nullptr) {
1864 errorMessages->get().push_back(defaultErrorMessage);
1865 }
1866 else {
1867 errorMessages->get().emplace_back(errorMessage);
1868 }
1869 }
1870 }
1871 };
1872
1873 addOpenSSLErrorMessageOnFail(EVP_PKEY_param_check(ctx.get()), getName() + "Unknown OpenSSL error during key param check");
1874 addOpenSSLErrorMessageOnFail(EVP_PKEY_public_check(ctx.get()), getName() + "Unknown OpenSSL error during public key check");
1875 addOpenSSLErrorMessageOnFail(EVP_PKEY_private_check(ctx.get()), getName() + "Unknown OpenSSL error during private key check");
1876 addOpenSSLErrorMessageOnFail(EVP_PKEY_pairwise_check(ctx.get()), getName() + "Unknown OpenSSL error during key pairwise check");
1877
1878 return retval;
1879 #else
1880 return (d_edkey ? true : false);
1881 #endif
1882 }
1883
1884 void OpenSSLEDDSADNSCryptoKeyEngine::create(unsigned int /* bits */)
1885 {
1886 auto pctx = KeyContext(EVP_PKEY_CTX_new_id(d_id, nullptr), EVP_PKEY_CTX_free);
1887 if (!pctx) {
1888 throw pdns::OpenSSL::error(getName(), "Context initialization failed");
1889 }
1890
1891 if (EVP_PKEY_keygen_init(pctx.get()) < 1) {
1892 throw pdns::OpenSSL::error(getName(), "Keygen initialization failed");
1893 }
1894
1895 EVP_PKEY* newKey = nullptr;
1896 if (EVP_PKEY_keygen(pctx.get(), &newKey) < 1) {
1897 throw pdns::OpenSSL::error(getName(), "Key generation failed");
1898 }
1899
1900 d_edkey.reset(newKey);
1901 }
1902
1903 void OpenSSLEDDSADNSCryptoKeyEngine::createFromPEMFile(DNSKEYRecordContent& drc, std::FILE& inputFile, std::optional<std::reference_wrapper<const std::string>> filename)
1904 {
1905 drc.d_algorithm = d_algorithm;
1906 d_edkey = Key(PEM_read_PrivateKey(&inputFile, nullptr, nullptr, nullptr), &EVP_PKEY_free);
1907 if (d_edkey == nullptr) {
1908 if (filename.has_value()) {
1909 throw pdns::OpenSSL::error(getName(), "Failed to read private key from PEM file `" + filename->get() + "`");
1910 }
1911
1912 throw pdns::OpenSSL::error(getName(), "Failed to read private key from PEM contents");
1913 }
1914 }
1915
1916 void OpenSSLEDDSADNSCryptoKeyEngine::convertToPEMFile(std::FILE& outputFile) const
1917 {
1918 auto ret = PEM_write_PrivateKey(&outputFile, d_edkey.get(), nullptr, nullptr, 0, nullptr, nullptr);
1919 if (ret == 0) {
1920 throw pdns::OpenSSL::error(getName(), "Could not convert private key to PEM");
1921 }
1922 }
1923
1924 DNSCryptoKeyEngine::storvector_t OpenSSLEDDSADNSCryptoKeyEngine::convertToISCVector() const
1925 {
1926 storvector_t storvect;
1927 string algorithm;
1928
1929 #ifdef HAVE_LIBCRYPTO_ED25519
1930 if (d_algorithm == 15) {
1931 algorithm = "15 (ED25519)";
1932 }
1933 #endif
1934 #ifdef HAVE_LIBCRYPTO_ED448
1935 if (d_algorithm == 16) {
1936 algorithm = "16 (ED448)";
1937 }
1938 #endif
1939 if (algorithm.empty()) {
1940 algorithm = " ? (?)";
1941 }
1942
1943 storvect.emplace_back("Algorithm", algorithm);
1944
1945 string buf;
1946 size_t len = d_len;
1947 buf.resize(len);
1948
1949 // NOLINTNEXTLINE(*-cast): Using OpenSSL C APIs.
1950 if (EVP_PKEY_get_raw_private_key(d_edkey.get(), reinterpret_cast<unsigned char*>(&buf.at(0)), &len) < 1) {
1951 throw pdns::OpenSSL::error(getName(), "Could not get private key from d_edkey");
1952 }
1953 storvect.emplace_back("PrivateKey", buf);
1954 return storvect;
1955 }
1956
1957 std::string OpenSSLEDDSADNSCryptoKeyEngine::sign(const std::string& msg) const
1958 {
1959 auto mdctx = MessageDigestContext(EVP_MD_CTX_new(), EVP_MD_CTX_free);
1960 if (!mdctx) {
1961 throw pdns::OpenSSL::error(getName(), "MD context initialization failed");
1962 }
1963 if (EVP_DigestSignInit(mdctx.get(), nullptr, nullptr, nullptr, d_edkey.get()) < 1) {
1964 throw pdns::OpenSSL::error(getName(), "Unable to initialize signer");
1965 }
1966
1967 string msgToSign = msg;
1968
1969 size_t siglen = d_len * 2;
1970 string signature;
1971 signature.resize(siglen);
1972
1973 if (EVP_DigestSign(mdctx.get(),
1974 // NOLINTNEXTLINE(*-cast): Using OpenSSL C APIs.
1975 reinterpret_cast<unsigned char*>(&signature.at(0)), &siglen,
1976 // NOLINTNEXTLINE(*-cast): Using OpenSSL C APIs.
1977 reinterpret_cast<unsigned char*>(&msgToSign.at(0)), msgToSign.length())
1978 < 1) {
1979 throw pdns::OpenSSL::error(getName(), "Signing error");
1980 }
1981
1982 return signature;
1983 }
1984
1985 bool OpenSSLEDDSADNSCryptoKeyEngine::verify(const std::string& message, const std::string& signature) const
1986 {
1987 auto ctx = MessageDigestContext(EVP_MD_CTX_new(), EVP_MD_CTX_free);
1988 if (!ctx) {
1989 throw pdns::OpenSSL::error(getName(), "MD context initialization failed");
1990 }
1991 if (EVP_DigestVerifyInit(ctx.get(), nullptr, nullptr, nullptr, d_edkey.get()) < 1) {
1992 throw pdns::OpenSSL::error(getName(), "Unable to initialize signer");
1993 }
1994
1995 auto ret = EVP_DigestVerify(ctx.get(),
1996 // NOLINTNEXTLINE(*-cast): Using OpenSSL C APIs.
1997 reinterpret_cast<const unsigned char*>(&signature.at(0)), signature.length(),
1998 // NOLINTNEXTLINE(*-cast): Using OpenSSL C APIs.
1999 reinterpret_cast<const unsigned char*>(&message.at(0)), message.length());
2000 if (ret < 0) {
2001 throw pdns::OpenSSL::error(getName(), "Verification failure");
2002 }
2003
2004 return (ret == 1);
2005 }
2006
2007 std::string OpenSSLEDDSADNSCryptoKeyEngine::getPublicKeyString() const
2008 {
2009 string buf;
2010 size_t len = d_len;
2011 buf.resize(len);
2012
2013 // NOLINTNEXTLINE(*-cast): Using OpenSSL C APIs.
2014 if (EVP_PKEY_get_raw_public_key(d_edkey.get(), reinterpret_cast<unsigned char*>(&buf.at(0)), &len) < 1) {
2015 throw pdns::OpenSSL::error(getName(), "Unable to get public key from key struct");
2016 }
2017
2018 return buf;
2019 }
2020
2021 void OpenSSLEDDSADNSCryptoKeyEngine::fromISCMap(DNSKEYRecordContent& drc, std::map<std::string, std::string>& stormap)
2022 {
2023 drc.d_algorithm = atoi(stormap["algorithm"].c_str());
2024 if (drc.d_algorithm != d_algorithm) {
2025 throw runtime_error(getName() + " tried to feed an algorithm " + std::to_string(drc.d_algorithm) + " to a " + std::to_string(d_algorithm) + " key");
2026 }
2027
2028 // NOLINTNEXTLINE(*-cast): Using OpenSSL C APIs.
2029 d_edkey = Key(EVP_PKEY_new_raw_private_key(d_id, nullptr, reinterpret_cast<unsigned char*>(&stormap["privatekey"].at(0)), stormap["privatekey"].length()), EVP_PKEY_free);
2030 if (!d_edkey) {
2031 throw pdns::OpenSSL::error(getName(), "Could not create key structure from private key");
2032 }
2033 }
2034
2035 void OpenSSLEDDSADNSCryptoKeyEngine::fromPublicKeyString(const std::string& content)
2036 {
2037 if (content.length() != d_len) {
2038 throw runtime_error(getName() + " wrong public key length for algorithm " + std::to_string(d_algorithm));
2039 }
2040
2041 // NOLINTNEXTLINE(*-cast): Using OpenSSL C APIs.
2042 const auto* raw = reinterpret_cast<const unsigned char*>(content.c_str());
2043
2044 d_edkey = Key(EVP_PKEY_new_raw_public_key(d_id, nullptr, raw, d_len), EVP_PKEY_free);
2045 if (!d_edkey) {
2046 throw pdns::OpenSSL::error(getName(), "Allocation of public key structure failed");
2047 }
2048 }
2049 #endif // HAVE_LIBCRYPTO_EDDSA
2050
2051 namespace
2052 {
2053 const struct LoaderStruct
2054 {
2055 LoaderStruct()
2056 {
2057 DNSCryptoKeyEngine::report(DNSSECKeeper::RSASHA1, &OpenSSLRSADNSCryptoKeyEngine::maker);
2058 DNSCryptoKeyEngine::report(DNSSECKeeper::RSASHA1NSEC3SHA1, &OpenSSLRSADNSCryptoKeyEngine::maker);
2059 DNSCryptoKeyEngine::report(DNSSECKeeper::RSASHA256, &OpenSSLRSADNSCryptoKeyEngine::maker);
2060 DNSCryptoKeyEngine::report(DNSSECKeeper::RSASHA512, &OpenSSLRSADNSCryptoKeyEngine::maker);
2061 #ifdef HAVE_LIBCRYPTO_ECDSA
2062 DNSCryptoKeyEngine::report(DNSSECKeeper::ECDSA256, &OpenSSLECDSADNSCryptoKeyEngine::maker);
2063 DNSCryptoKeyEngine::report(DNSSECKeeper::ECDSA384, &OpenSSLECDSADNSCryptoKeyEngine::maker);
2064 #endif
2065 #ifdef HAVE_LIBCRYPTO_ED25519
2066 DNSCryptoKeyEngine::report(DNSSECKeeper::ED25519, &OpenSSLEDDSADNSCryptoKeyEngine::maker);
2067 #endif
2068 #ifdef HAVE_LIBCRYPTO_ED448
2069 DNSCryptoKeyEngine::report(DNSSECKeeper::ED448, &OpenSSLEDDSADNSCryptoKeyEngine::maker);
2070 #endif
2071 }
2072 } loaderOpenSSL;
2073 }