]> git.ipfire.org Git - thirdparty/pdns.git/blob - pdns/opensslsigners.cc
Merge pull request #14021 from Habbie/auth-lua-join-whitespace
[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 #ifdef HAVE_CONFIG_H
23 #include "config.h"
24 #endif
25 #include <openssl/obj_mac.h>
26 #ifdef HAVE_LIBCRYPTO_ECDSA
27 #include <openssl/ecdsa.h>
28 #endif
29 #if defined(HAVE_LIBCRYPTO_ED25519) || defined(HAVE_LIBCRYPTO_ED448)
30 #include <openssl/evp.h>
31 #endif
32 #include <openssl/sha.h>
33 #include <openssl/rand.h>
34 #include <openssl/rsa.h>
35 #include <openssl/opensslv.h>
36 #include <openssl/err.h>
37 #include "opensslsigners.hh"
38 #include "dnssecinfra.hh"
39 #include "dnsseckeeper.hh"
40
41 #if (OPENSSL_VERSION_NUMBER < 0x1010000fL || defined LIBRESSL_VERSION_NUMBER)
42 /* OpenSSL < 1.1.0 needs support for threading/locking in the calling application. */
43 static pthread_mutex_t *openssllocks;
44
45 extern "C" {
46 void openssl_pthreads_locking_callback(int mode, int type, const char *file, int line)
47 {
48 if (mode & CRYPTO_LOCK) {
49 pthread_mutex_lock(&(openssllocks[type]));
50
51 }else {
52 pthread_mutex_unlock(&(openssllocks[type]));
53 }
54 }
55
56 unsigned long openssl_pthreads_id_callback()
57 {
58 return (unsigned long)pthread_self();
59 }
60 }
61
62 void openssl_thread_setup()
63 {
64 openssllocks = (pthread_mutex_t*)OPENSSL_malloc(CRYPTO_num_locks() * sizeof(pthread_mutex_t));
65
66 for (int i = 0; i < CRYPTO_num_locks(); i++)
67 pthread_mutex_init(&(openssllocks[i]), NULL);
68
69 CRYPTO_set_id_callback(openssl_pthreads_id_callback);
70 CRYPTO_set_locking_callback(openssl_pthreads_locking_callback);
71 }
72
73 void openssl_thread_cleanup()
74 {
75 CRYPTO_set_locking_callback(NULL);
76
77 for (int i=0; i<CRYPTO_num_locks(); i++) {
78 pthread_mutex_destroy(&(openssllocks[i]));
79 }
80
81 OPENSSL_free(openssllocks);
82 }
83
84 #if !defined(LIBRESSL_VERSION_NUMBER) || LIBRESSL_VERSION_NUMBER < 0x2070000fL
85 /* those symbols are defined in LibreSSL 2.7.0+ */
86 /* compat helpers. These DO NOT do any of the checking that the libssl 1.1 functions do. */
87 static inline void RSA_get0_key(const RSA* rsakey, const BIGNUM** n, const BIGNUM** e, const BIGNUM** d) {
88 *n = rsakey->n;
89 *e = rsakey->e;
90 *d = rsakey->d;
91 }
92
93 static inline int RSA_set0_key(RSA* rsakey, BIGNUM* n, BIGNUM* e, BIGNUM* d) {
94 if (n) {
95 BN_clear_free(rsakey->n);
96 rsakey->n = n;
97 }
98 if (e) {
99 BN_clear_free(rsakey->e);
100 rsakey->e = e;
101 }
102 if (d) {
103 BN_clear_free(rsakey->d);
104 rsakey->d = d;
105 }
106 return 1;
107 }
108
109 static inline void RSA_get0_factors(const RSA* rsakey, const BIGNUM** p, const BIGNUM** q) {
110 *p = rsakey->p;
111 *q = rsakey->q;
112 }
113
114 static inline int RSA_set0_factors(RSA* rsakey, BIGNUM* p, BIGNUM* q) {
115 BN_clear_free(rsakey->p);
116 rsakey->p = p;
117 BN_clear_free(rsakey->q);
118 rsakey->q = q;
119 return 1;
120 }
121
122 static inline void RSA_get0_crt_params(const RSA* rsakey, const BIGNUM** dmp1, const BIGNUM** dmq1, const BIGNUM** iqmp) {
123 *dmp1 = rsakey->dmp1;
124 *dmq1 = rsakey->dmq1;
125 *iqmp = rsakey->iqmp;
126 }
127
128 static inline int RSA_set0_crt_params(RSA* rsakey, BIGNUM* dmp1, BIGNUM* dmq1, BIGNUM* iqmp) {
129 BN_clear_free(rsakey->dmp1);
130 rsakey->dmp1 = dmp1;
131 BN_clear_free(rsakey->dmq1);
132 rsakey->dmq1 = dmq1;
133 BN_clear_free(rsakey->iqmp);
134 rsakey->iqmp = iqmp;
135 return 1;
136 }
137
138 #ifdef HAVE_LIBCRYPTO_ECDSA
139 static inline void ECDSA_SIG_get0(const ECDSA_SIG* signature, const BIGNUM** pr, const BIGNUM** ps) {
140 *pr = signature->r;
141 *ps = signature->s;
142 }
143
144 static inline int ECDSA_SIG_set0(ECDSA_SIG* signature, BIGNUM* pr, BIGNUM* ps) {
145 BN_clear_free(signature->r);
146 BN_clear_free(signature->s);
147 signature->r = pr;
148 signature->s = ps;
149 return 1;
150 }
151 #endif /* HAVE_LIBCRYPTO_ECDSA */
152
153 #endif /* !defined(LIBRESSL_VERSION_NUMBER) || LIBRESSL_VERSION_NUMBER < 0x2070000fL */
154
155 #else
156 void openssl_thread_setup() {}
157 void openssl_thread_cleanup() {}
158 #endif
159
160
161 /* seeding PRNG */
162
163 void openssl_seed()
164 {
165 std::string entropy;
166 entropy.reserve(1024);
167
168 unsigned int r;
169 for(int i=0; i<1024; i+=4) {
170 r=dns_random(0xffffffff);
171 entropy.append((const char*)&r, 4);
172 }
173
174 RAND_seed((const unsigned char*)entropy.c_str(), 1024);
175 }
176
177
178 class OpenSSLRSADNSCryptoKeyEngine : public DNSCryptoKeyEngine
179 {
180 public:
181 explicit OpenSSLRSADNSCryptoKeyEngine(unsigned int algo): DNSCryptoKeyEngine(algo), d_key(std::unique_ptr<RSA, void(*)(RSA*)>(nullptr, RSA_free))
182 {
183 int ret = RAND_status();
184 if (ret != 1) {
185 throw runtime_error(getName()+" insufficient entropy");
186 }
187 }
188
189 ~OpenSSLRSADNSCryptoKeyEngine()
190 {
191 }
192
193 string getName() const override { return "OpenSSL RSA"; }
194 int getBits() const override { return RSA_size(d_key.get()) << 3; }
195
196 void create(unsigned int bits) override;
197 storvector_t convertToISCVector() const override;
198 std::string hash(const std::string& hash) const override;
199 std::string sign(const std::string& hash) const override;
200 bool verify(const std::string& hash, const std::string& signature) const override;
201 std::string getPubKeyHash() const override;
202 std::string getPublicKeyString() const override;
203 void fromISCMap(DNSKEYRecordContent& drc, std::map<std::string, std::string>& stormap) override;
204 void fromPublicKeyString(const std::string& content) override;
205 bool checkKey(vector<string> *errorMessages) const override;
206
207 static std::shared_ptr<DNSCryptoKeyEngine> maker(unsigned int algorithm)
208 {
209 return std::make_shared<OpenSSLRSADNSCryptoKeyEngine>(algorithm);
210 }
211
212 private:
213 static int hashSizeToKind(size_t hashSize);
214
215 std::unique_ptr<RSA, void(*)(RSA*)> d_key;
216 };
217
218
219 void OpenSSLRSADNSCryptoKeyEngine::create(unsigned int bits)
220 {
221 // When changing the bitsizes, also edit them in ::checkKey
222 if ((d_algorithm == DNSSECKeeper::RSASHA1 || d_algorithm == DNSSECKeeper::RSASHA1NSEC3SHA1) && (bits < 512 || bits > 4096)) {
223 /* RFC3110 */
224 throw runtime_error(getName()+" RSASHA1 key generation failed for invalid bits size " + std::to_string(bits));
225 }
226 if (d_algorithm == DNSSECKeeper::RSASHA256 && (bits < 512 || bits > 4096)) {
227 /* RFC5702 */
228 throw runtime_error(getName()+" RSASHA256 key generation failed for invalid bits size " + std::to_string(bits));
229 }
230 if (d_algorithm == DNSSECKeeper::RSASHA512 && (bits < 1024 || bits > 4096)) {
231 /* RFC5702 */
232 throw runtime_error(getName()+" RSASHA512 key generation failed for invalid bits size " + std::to_string(bits));
233 }
234
235 auto e = std::unique_ptr<BIGNUM, void(*)(BIGNUM*)>(BN_new(), BN_clear_free);
236 if (!e) {
237 throw runtime_error(getName()+" key generation failed, unable to allocate e");
238 }
239
240 /* RSA_F4 is a public exponent value of 65537 */
241 int res = BN_set_word(e.get(), RSA_F4);
242
243 if (res == 0) {
244 throw runtime_error(getName()+" key generation failed while setting e");
245 }
246
247 auto key = std::unique_ptr<RSA, void(*)(RSA*)>(RSA_new(), RSA_free);
248 if (!key) {
249 throw runtime_error(getName()+" allocation of key structure failed");
250 }
251
252 res = RSA_generate_key_ex(key.get(), bits, e.get(), nullptr);
253 if (res == 0) {
254 throw runtime_error(getName()+" key generation failed");
255 }
256
257 d_key = std::move(key);
258 }
259
260
261 DNSCryptoKeyEngine::storvector_t OpenSSLRSADNSCryptoKeyEngine::convertToISCVector() const
262 {
263 storvector_t storvect;
264 typedef vector<pair<string, const BIGNUM*> > outputs_t;
265 outputs_t outputs;
266 const BIGNUM *n, *e, *d, *p, *q, *dmp1, *dmq1, *iqmp;
267 RSA_get0_key(d_key.get(), &n, &e, &d);
268 RSA_get0_factors(d_key.get(), &p, &q);
269 RSA_get0_crt_params(d_key.get(), &dmp1, &dmq1, &iqmp);
270 outputs.push_back(make_pair("Modulus", n));
271 outputs.push_back(make_pair("PublicExponent", e));
272 outputs.push_back(make_pair("PrivateExponent", d));
273 outputs.push_back(make_pair("Prime1", p));
274 outputs.push_back(make_pair("Prime2", q));
275 outputs.push_back(make_pair("Exponent1", dmp1));
276 outputs.push_back(make_pair("Exponent2", dmq1));
277 outputs.push_back(make_pair("Coefficient", iqmp));
278
279 string algorithm=std::to_string(d_algorithm);
280 switch(d_algorithm) {
281 case DNSSECKeeper::RSASHA1:
282 case DNSSECKeeper::RSASHA1NSEC3SHA1:
283 algorithm += " (RSASHA1)";
284 break;
285 case DNSSECKeeper::RSASHA256:
286 algorithm += " (RSASHA256)";
287 break;
288 case DNSSECKeeper::RSASHA512:
289 algorithm += " (RSASHA512)";
290 break;
291 default:
292 algorithm += " (?)";
293 }
294 storvect.push_back(make_pair("Algorithm", algorithm));
295
296 for(outputs_t::value_type value : outputs) {
297 std::string tmp;
298 tmp.resize(BN_num_bytes(value.second));
299 int len = BN_bn2bin(value.second, reinterpret_cast<unsigned char*>(&tmp.at(0)));
300 if (len >= 0) {
301 tmp.resize(len);
302 storvect.push_back(make_pair(value.first, tmp));
303 }
304 }
305
306 return storvect;
307 }
308
309
310 std::string OpenSSLRSADNSCryptoKeyEngine::hash(const std::string& orig) const
311 {
312 if (d_algorithm == DNSSECKeeper::RSASHA1 || d_algorithm == DNSSECKeeper::RSASHA1NSEC3SHA1) {
313 unsigned char hash[SHA_DIGEST_LENGTH];
314 SHA1((unsigned char*) orig.c_str(), orig.length(), hash);
315 return string((char*) hash, sizeof(hash));
316 }
317 else if (d_algorithm == DNSSECKeeper::RSASHA256) {
318 unsigned char hash[SHA256_DIGEST_LENGTH];
319 SHA256((unsigned char*) orig.c_str(), orig.length(), hash);
320 return string((char*) hash, sizeof(hash));
321 }
322 else if (d_algorithm == DNSSECKeeper::RSASHA512) {
323 unsigned char hash[SHA512_DIGEST_LENGTH];
324 SHA512((unsigned char*) orig.c_str(), orig.length(), hash);
325 return string((char*) hash, sizeof(hash));
326 }
327
328 throw runtime_error(getName()+" does not support hash operation for algorithm "+std::to_string(d_algorithm));
329 }
330
331 int OpenSSLRSADNSCryptoKeyEngine::hashSizeToKind(const size_t hashSize)
332 {
333 switch(hashSize) {
334 case SHA_DIGEST_LENGTH:
335 return NID_sha1;
336 case SHA256_DIGEST_LENGTH:
337 return NID_sha256;
338 case SHA384_DIGEST_LENGTH:
339 return NID_sha384;
340 case SHA512_DIGEST_LENGTH:
341 return NID_sha512;
342 default:
343 throw runtime_error("OpenSSL RSA does not handle hash of size " + std::to_string(hashSize));
344 }
345 }
346
347 std::string OpenSSLRSADNSCryptoKeyEngine::sign(const std::string& msg) const
348 {
349 string hash = this->hash(msg);
350 int hashKind = hashSizeToKind(hash.size());
351 std::string signature;
352 signature.resize(RSA_size(d_key.get()));
353 unsigned int signatureLen = 0;
354
355 int res = RSA_sign(hashKind, reinterpret_cast<unsigned char*>(&hash.at(0)), hash.length(), reinterpret_cast<unsigned char*>(&signature.at(0)), &signatureLen, d_key.get());
356 if (res != 1) {
357 throw runtime_error(getName()+" failed to generate signature");
358 }
359
360 signature.resize(signatureLen);
361 return signature;
362 }
363
364
365 bool OpenSSLRSADNSCryptoKeyEngine::verify(const std::string& msg, const std::string& signature) const
366 {
367 string hash = this->hash(msg);
368 int hashKind = hashSizeToKind(hash.size());
369
370 int ret = RSA_verify(hashKind, (const unsigned char*) hash.c_str(), hash.length(), (unsigned char*) signature.c_str(), signature.length(), d_key.get());
371
372 return (ret == 1);
373 }
374
375
376 std::string OpenSSLRSADNSCryptoKeyEngine::getPubKeyHash() const
377 {
378 const BIGNUM *n, *e, *d;
379 RSA_get0_key(d_key.get(), &n, &e, &d);
380 std::vector<unsigned char> tmp;
381 tmp.resize(std::max(BN_num_bytes(e), BN_num_bytes(n)));
382 unsigned char hash[SHA_DIGEST_LENGTH];
383 SHA_CTX ctx;
384
385 int res = SHA1_Init(&ctx);
386
387 if (res != 1) {
388 throw runtime_error(getName()+" failed to init hash context for generating the public key hash");
389 }
390
391 int len = BN_bn2bin(e, tmp.data());
392 res = SHA1_Update(&ctx, tmp.data(), len);
393 if (res != 1) {
394 throw runtime_error(getName()+" failed to update hash context for generating the public key hash");
395 }
396
397 len = BN_bn2bin(n, tmp.data());
398 res = SHA1_Update(&ctx, tmp.data(), len);
399 if (res != 1) {
400 throw runtime_error(getName()+" failed to update hash context for generating the public key hash");
401 }
402
403 res = SHA1_Final(hash, &ctx);
404 if (res != 1) {
405 throw runtime_error(getName()+" failed to finish hash context for generating the public key hash");
406 }
407
408 return string((char*) hash, sizeof(hash));
409 }
410
411
412 std::string OpenSSLRSADNSCryptoKeyEngine::getPublicKeyString() const
413 {
414 const BIGNUM *n, *e, *d;
415 RSA_get0_key(d_key.get(), &n, &e, &d);
416 string keystring;
417 std::string tmp;
418 tmp.resize(std::max(BN_num_bytes(e), BN_num_bytes(n)));
419
420 int len = BN_bn2bin(e, reinterpret_cast<unsigned char*>(&tmp.at(0)));
421 if (len < 255) {
422 keystring.assign(1, (char) (unsigned int) len);
423 } else {
424 keystring.assign(1, 0);
425 uint16_t tempLen = len;
426 tempLen = htons(tempLen);
427 keystring.append((char*)&tempLen, 2);
428 }
429 keystring.append(&tmp.at(0), len);
430
431 len = BN_bn2bin(n, reinterpret_cast<unsigned char*>(&tmp.at(0)));
432 keystring.append(&tmp.at(0), len);
433
434 return keystring;
435 }
436
437
438 void OpenSSLRSADNSCryptoKeyEngine::fromISCMap(DNSKEYRecordContent& drc, std::map<std::string, std::string>& stormap)
439 {
440 typedef map<string, BIGNUM**> places_t;
441 places_t places;
442 auto key = std::unique_ptr<RSA, void(*)(RSA*)>(RSA_new(), RSA_free);
443 if (!key) {
444 throw runtime_error(getName()+" allocation of key structure failed");
445 }
446
447 BIGNUM *n, *e, *d, *p, *q, *dmp1, *dmq1, *iqmp;
448 n = BN_new();
449 if (n == nullptr) {
450 throw runtime_error(getName()+" allocation of BIGNUM n failed");
451 }
452 e = BN_new();
453 if (e == nullptr) {
454 BN_clear_free(n);
455 throw runtime_error(getName()+" allocation of BIGNUM e failed");
456 }
457 d = BN_new();
458 if (d == nullptr) {
459 BN_clear_free(n);
460 BN_clear_free(e);
461 throw runtime_error(getName()+" allocation of BIGNUM d failed");
462 }
463 RSA_set0_key(key.get(), n, e, d);
464
465 p = BN_new();
466 if (p == nullptr) {
467 throw runtime_error(getName()+" allocation of BIGNUM p failed");
468 }
469 q = BN_new();
470 if (q == nullptr) {
471 BN_clear_free(p);
472 throw runtime_error(getName()+" allocation of BIGNUM q failed");
473 }
474 RSA_set0_factors(key.get(), p, q);
475
476 dmp1 = BN_new();
477 if (dmp1 == nullptr) {
478 throw runtime_error(getName()+" allocation of BIGNUM dmp1 failed");
479 }
480 dmq1 = BN_new();
481 if (dmq1 == nullptr) {
482 BN_clear_free(dmp1);
483 throw runtime_error(getName()+" allocation of BIGNUM dmq1 failed");
484 }
485 iqmp = BN_new();
486 if (iqmp == nullptr) {
487 BN_clear_free(dmq1);
488 BN_clear_free(dmp1);
489 throw runtime_error(getName()+" allocation of BIGNUM iqmp failed");
490 }
491 RSA_set0_crt_params(key.get(), dmp1, dmq1, iqmp);
492
493 places["Modulus"]=&n;
494 places["PublicExponent"]=&e;
495 places["PrivateExponent"]=&d;
496 places["Prime1"]=&p;
497 places["Prime2"]=&q;
498 places["Exponent1"]=&dmp1;
499 places["Exponent2"]=&dmq1;
500 places["Coefficient"]=&iqmp;
501
502 drc.d_algorithm = pdns_stou(stormap["algorithm"]);
503
504 string raw;
505 for(const places_t::value_type& val : places) {
506 raw=stormap[toLower(val.first)];
507
508 if (!val.second)
509 continue;
510
511 *val.second = BN_bin2bn((unsigned char*) raw.c_str(), raw.length(), *val.second);
512 if (!*val.second) {
513 throw runtime_error(getName()+" error loading " + val.first);
514 }
515 }
516
517 if (drc.d_algorithm != d_algorithm) {
518 throw runtime_error(getName()+" tried to feed an algorithm "+std::to_string(drc.d_algorithm)+" to a "+std::to_string(d_algorithm)+" key");
519 }
520
521 d_key = std::move(key);
522 }
523
524 bool OpenSSLRSADNSCryptoKeyEngine::checkKey(vector<string> *errorMessages) const
525 {
526 bool retval = true;
527 // When changing the bitsizes, also edit them in ::create
528 if ((d_algorithm == DNSSECKeeper::RSASHA1 || d_algorithm == DNSSECKeeper::RSASHA1NSEC3SHA1 || d_algorithm == DNSSECKeeper::RSASHA256) && (getBits() < 512 || getBits()> 4096)) {
529 retval = false;
530 if (errorMessages != nullptr) {
531 errorMessages->push_back("key is " + std::to_string(getBits()) + " bytes, should be between 512 and 4096");
532 }
533 }
534 if (d_algorithm == DNSSECKeeper::RSASHA512 && (getBits() < 1024 || getBits() > 4096)) {
535 retval = false;
536 if (errorMessages != nullptr) {
537 errorMessages->push_back("key is " + std::to_string(getBits()) + " bytes, should be between 1024 and 4096");
538 }
539 }
540 if (RSA_check_key(d_key.get()) != 1) {
541 retval = false;
542 if (errorMessages != nullptr) {
543 errorMessages->push_back(ERR_reason_error_string(ERR_get_error()));
544 }
545 }
546 return retval;
547 }
548
549 void OpenSSLRSADNSCryptoKeyEngine::fromPublicKeyString(const std::string& input)
550 {
551 string exponent, modulus;
552 const size_t inputLen = input.length();
553 const unsigned char* raw = (const unsigned char*)input.c_str();
554
555 if (inputLen < 1) {
556 throw runtime_error(getName()+" invalid input size for the public key");
557 }
558
559 if (raw[0] != 0) {
560 const size_t exponentSize = raw[0];
561 if (inputLen < (exponentSize + 2)) {
562 throw runtime_error(getName()+" invalid input size for the public key");
563 }
564 exponent = input.substr(1, exponentSize);
565 modulus = input.substr(exponentSize + 1);
566 } else {
567 if (inputLen < 3) {
568 throw runtime_error(getName()+" invalid input size for the public key");
569 }
570 const size_t exponentSize = raw[1]*0xff + raw[2];
571 if (inputLen < (exponentSize + 4)) {
572 throw runtime_error(getName()+" invalid input size for the public key");
573 }
574 exponent = input.substr(3, exponentSize);
575 modulus = input.substr(exponentSize + 3);
576 }
577
578 auto key = std::unique_ptr<RSA, void(*)(RSA*)>(RSA_new(), RSA_free);
579 if (!key) {
580 throw runtime_error(getName()+" allocation of key structure failed");
581 }
582
583 auto e = std::unique_ptr<BIGNUM, void(*)(BIGNUM*)>(BN_bin2bn((unsigned char*)exponent.c_str(), exponent.length(), nullptr), BN_clear_free);
584 if (!e) {
585 throw runtime_error(getName()+" error loading e value of public key");
586 }
587 auto n = std::unique_ptr<BIGNUM, void(*)(BIGNUM*)>(BN_bin2bn((unsigned char*)modulus.c_str(), modulus.length(), nullptr), BN_clear_free);
588 if (!n) {
589 throw runtime_error(getName()+" error loading n value of public key");
590 }
591
592 RSA_set0_key(key.get(), n.release(), e.release(), nullptr);
593 d_key = std::move(key);
594 }
595
596 #ifdef HAVE_LIBCRYPTO_ECDSA
597 class OpenSSLECDSADNSCryptoKeyEngine : public DNSCryptoKeyEngine
598 {
599 public:
600 explicit OpenSSLECDSADNSCryptoKeyEngine(unsigned int algo) : DNSCryptoKeyEngine(algo), d_eckey(std::unique_ptr<EC_KEY, void(*)(EC_KEY*)>(EC_KEY_new(), EC_KEY_free)), d_ecgroup(std::unique_ptr<EC_GROUP, void(*)(EC_GROUP*)>(nullptr, EC_GROUP_clear_free))
601 {
602
603 int ret = RAND_status();
604 if (ret != 1) {
605 throw runtime_error(getName()+" insufficient entropy");
606 }
607
608 if (!d_eckey) {
609 throw runtime_error(getName()+" allocation of key structure failed");
610 }
611
612 if(d_algorithm == 13) {
613 d_ecgroup = std::unique_ptr<EC_GROUP, void(*)(EC_GROUP*)>(EC_GROUP_new_by_curve_name(NID_X9_62_prime256v1), EC_GROUP_clear_free);
614 d_len = 32;
615 } else if (d_algorithm == 14) {
616 d_ecgroup = std::unique_ptr<EC_GROUP, void(*)(EC_GROUP*)>(EC_GROUP_new_by_curve_name(NID_secp384r1), EC_GROUP_clear_free);
617 d_len = 48;
618 } else {
619 throw runtime_error(getName()+" unknown algorithm "+std::to_string(d_algorithm));
620 }
621
622 if (!d_ecgroup) {
623 throw runtime_error(getName()+" allocation of group structure failed");
624 }
625
626 ret = EC_KEY_set_group(d_eckey.get(), d_ecgroup.get());
627 if (ret != 1) {
628 throw runtime_error(getName()+" setting key group failed");
629 }
630 }
631
632 ~OpenSSLECDSADNSCryptoKeyEngine()
633 {
634 }
635
636 string getName() const override { return "OpenSSL ECDSA"; }
637 int getBits() const override { return d_len << 3; }
638
639 void create(unsigned int bits) override;
640 storvector_t convertToISCVector() const override;
641 std::string hash(const std::string& hash) const override;
642 std::string sign(const std::string& hash) const override;
643 bool verify(const std::string& hash, const std::string& signature) const override;
644 std::string getPubKeyHash() const override;
645 std::string getPublicKeyString() const override;
646 void fromISCMap(DNSKEYRecordContent& drc, std::map<std::string, std::string>& stormap) override;
647 void fromPublicKeyString(const std::string& content) override;
648 bool checkKey(vector<string> *errorMessages) const override;
649
650 static std::shared_ptr<DNSCryptoKeyEngine> maker(unsigned int algorithm)
651 {
652 return std::make_shared<OpenSSLECDSADNSCryptoKeyEngine>(algorithm);
653 }
654
655 private:
656 unsigned int d_len;
657
658 std::unique_ptr<EC_KEY, void(*)(EC_KEY*)> d_eckey;
659 std::unique_ptr<EC_GROUP, void(*)(EC_GROUP*)> d_ecgroup;
660 };
661
662
663 void OpenSSLECDSADNSCryptoKeyEngine::create(unsigned int bits)
664 {
665 if (bits >> 3 != d_len) {
666 throw runtime_error(getName()+" unknown key length of "+std::to_string(bits)+" bits requested");
667 }
668
669 int res = EC_KEY_generate_key(d_eckey.get());
670 if (res == 0) {
671 throw runtime_error(getName()+" key generation failed");
672 }
673 }
674
675
676 DNSCryptoKeyEngine::storvector_t OpenSSLECDSADNSCryptoKeyEngine::convertToISCVector() const
677 {
678 storvector_t storvect;
679 string algorithm;
680
681 if(d_algorithm == 13)
682 algorithm = "13 (ECDSAP256SHA256)";
683 else if(d_algorithm == 14)
684 algorithm = "14 (ECDSAP384SHA384)";
685 else
686 algorithm = " ? (?)";
687
688 storvect.push_back(make_pair("Algorithm", algorithm));
689
690 const BIGNUM *key = EC_KEY_get0_private_key(d_eckey.get());
691 if (key == nullptr) {
692 throw runtime_error(getName()+" private key not set");
693 }
694
695 std::string tmp;
696 tmp.resize(BN_num_bytes(key));
697 int len = BN_bn2bin(key, reinterpret_cast<unsigned char*>(&tmp.at(0)));
698
699 string prefix;
700 if (d_len - len)
701 prefix.append(d_len - len, 0x00);
702
703 storvect.push_back(make_pair("PrivateKey", prefix + tmp));
704
705 return storvect;
706 }
707
708
709 std::string OpenSSLECDSADNSCryptoKeyEngine::hash(const std::string& orig) const
710 {
711 if(getBits() == 256) {
712 unsigned char hash[SHA256_DIGEST_LENGTH];
713 SHA256((unsigned char*) orig.c_str(), orig.length(), hash);
714 return string((char*) hash, sizeof(hash));
715 }
716 else if(getBits() == 384) {
717 unsigned char hash[SHA384_DIGEST_LENGTH];
718 SHA384((unsigned char*) orig.c_str(), orig.length(), hash);
719 return string((char*) hash, sizeof(hash));
720 }
721
722 throw runtime_error(getName()+" does not support a hash size of "+std::to_string(getBits())+" bits");
723 }
724
725
726 std::string OpenSSLECDSADNSCryptoKeyEngine::sign(const std::string& msg) const
727 {
728 string hash = this->hash(msg);
729
730 auto signature = std::unique_ptr<ECDSA_SIG, void(*)(ECDSA_SIG*)>(ECDSA_do_sign((unsigned char*) hash.c_str(), hash.length(), d_eckey.get()), ECDSA_SIG_free);
731 if (!signature) {
732 throw runtime_error(getName()+" failed to generate signature");
733 }
734
735 string ret;
736 std::string tmp;
737 tmp.resize(d_len);
738
739 const BIGNUM *pr, *ps;
740 ECDSA_SIG_get0(signature.get(), &pr, &ps);
741 int len = BN_bn2bin(pr, reinterpret_cast<unsigned char*>(&tmp.at(0)));
742 if (d_len - len)
743 ret.append(d_len - len, 0x00);
744 ret.append(&tmp.at(0), len);
745
746 len = BN_bn2bin(ps, reinterpret_cast<unsigned char*>(&tmp.at(0)));
747 if (d_len - len)
748 ret.append(d_len - len, 0x00);
749 ret.append(&tmp.at(0), len);
750
751 return ret;
752 }
753
754
755 bool OpenSSLECDSADNSCryptoKeyEngine::verify(const std::string& msg, const std::string& signature) const
756 {
757 if (signature.length() != (d_len * 2)) {
758 throw runtime_error(getName()+" invalid signature size "+std::to_string(signature.length()));
759 }
760
761 string hash = this->hash(msg);
762
763 auto sig = std::unique_ptr<ECDSA_SIG, void(*)(ECDSA_SIG*)>(ECDSA_SIG_new(), ECDSA_SIG_free);
764 if (!sig) {
765 throw runtime_error(getName()+" allocation of signature structure failed");
766 }
767
768 auto r = std::unique_ptr<BIGNUM, void(*)(BIGNUM*)>(BN_bin2bn((unsigned char*) signature.c_str(), d_len, nullptr), BN_clear_free);
769 auto s = std::unique_ptr<BIGNUM, void(*)(BIGNUM*)>(BN_bin2bn((unsigned char*) signature.c_str() + d_len, d_len, nullptr), BN_clear_free);
770 if (!r || !s) {
771 throw runtime_error(getName()+" invalid signature");
772 }
773
774 ECDSA_SIG_set0(sig.get(), r.release(), s.release());
775 int ret = ECDSA_do_verify((unsigned char*) hash.c_str(), hash.length(), sig.get(), d_eckey.get());
776
777 if (ret == -1){
778 throw runtime_error(getName()+" verify error");
779 }
780
781 return (ret == 1);
782 }
783
784
785 std::string OpenSSLECDSADNSCryptoKeyEngine::getPubKeyHash() const
786 {
787 string pubKey = getPublicKeyString();
788 unsigned char hash[SHA_DIGEST_LENGTH];
789 SHA1((unsigned char*) pubKey.c_str(), pubKey.length(), hash);
790 return string((char*) hash, sizeof(hash));
791 }
792
793
794 std::string OpenSSLECDSADNSCryptoKeyEngine::getPublicKeyString() const
795 {
796 std::string binaryPoint;
797 binaryPoint.resize((d_len * 2) + 1);
798
799 int ret = EC_POINT_point2oct(d_ecgroup.get(), EC_KEY_get0_public_key(d_eckey.get()), POINT_CONVERSION_UNCOMPRESSED, reinterpret_cast<unsigned char*>(&binaryPoint.at(0)), binaryPoint.size(), nullptr);
800 if (ret == 0) {
801 throw runtime_error(getName()+" exporting point to binary failed");
802 }
803
804 /* we skip the first byte as the other backends use
805 raw field elements, as opposed to the format described in
806 SEC1: "2.3.3 Elliptic-Curve-Point-to-Octet-String Conversion" */
807 binaryPoint.erase(0, 1);
808 return binaryPoint;
809 }
810
811
812 void OpenSSLECDSADNSCryptoKeyEngine::fromISCMap(DNSKEYRecordContent& drc, std::map<std::string, std::string>& stormap)
813 {
814 drc.d_algorithm = atoi(stormap["algorithm"].c_str());
815
816 if (drc.d_algorithm != d_algorithm) {
817 throw runtime_error(getName()+" tried to feed an algorithm "+std::to_string(drc.d_algorithm)+" to a "+std::to_string(d_algorithm)+" key");
818 }
819
820 string privateKey = stormap["privatekey"];
821
822 auto prv_key = std::unique_ptr<BIGNUM, void(*)(BIGNUM*)>(BN_bin2bn((unsigned char*) privateKey.c_str(), privateKey.length(), nullptr), BN_clear_free);
823 if (!prv_key) {
824 throw runtime_error(getName()+" reading private key from binary failed");
825 }
826
827 int ret = EC_KEY_set_private_key(d_eckey.get(), prv_key.get());
828 if (ret != 1) {
829 throw runtime_error(getName()+" setting private key failed");
830 }
831
832 auto pub_key = std::unique_ptr<EC_POINT, void(*)(EC_POINT*)>(EC_POINT_new(d_ecgroup.get()), EC_POINT_free);
833 if (!pub_key) {
834 throw runtime_error(getName()+" allocation of public key point failed");
835 }
836
837 ret = EC_POINT_mul(d_ecgroup.get(), pub_key.get(), prv_key.get(), nullptr, nullptr, nullptr);
838 if (ret != 1) {
839 throw runtime_error(getName()+" computing public key from private failed");
840 }
841
842 ret = EC_KEY_set_public_key(d_eckey.get(), pub_key.get());
843 if (ret != 1) {
844 throw runtime_error(getName()+" setting public key failed");
845 }
846 }
847
848 bool OpenSSLECDSADNSCryptoKeyEngine::checkKey(vector<string> *errorMessages) const
849 {
850 bool retval = true;
851 if (EC_KEY_check_key(d_eckey.get()) != 1) {
852 retval = false;
853 if (errorMessages != nullptr) {
854 errorMessages->push_back(ERR_reason_error_string(ERR_get_error()));
855 }
856 }
857 return retval;
858 }
859
860 void OpenSSLECDSADNSCryptoKeyEngine::fromPublicKeyString(const std::string& input)
861 {
862 /* uncompressed point, from SEC1:
863 "2.3.4 Octet-String-to-Elliptic-Curve-Point Conversion" */
864 string ecdsaPoint= "\x04";
865 ecdsaPoint.append(input);
866
867 auto pub_key = std::unique_ptr<EC_POINT, void(*)(EC_POINT*)>(EC_POINT_new(d_ecgroup.get()), EC_POINT_free);
868 if (!pub_key) {
869 throw runtime_error(getName()+" allocation of point structure failed");
870 }
871
872 int ret = EC_POINT_oct2point(d_ecgroup.get(), pub_key.get(), (unsigned char*) ecdsaPoint.c_str(), ecdsaPoint.length(), nullptr);
873 if (ret != 1) {
874 throw runtime_error(getName()+" reading ECP point from binary failed");
875 }
876
877 ret = EC_KEY_set_private_key(d_eckey.get(), nullptr);
878 if (ret == 1) {
879 throw runtime_error(getName()+" setting private key failed");
880 }
881
882 ret = EC_KEY_set_public_key(d_eckey.get(), pub_key.get());
883 if (ret != 1) {
884 throw runtime_error(getName()+" setting public key failed");
885 }
886 }
887 #endif
888
889 #ifdef HAVE_LIBCRYPTO_EDDSA
890 class OpenSSLEDDSADNSCryptoKeyEngine : public DNSCryptoKeyEngine
891 {
892 public:
893 explicit OpenSSLEDDSADNSCryptoKeyEngine(unsigned int algo) : DNSCryptoKeyEngine(algo), d_edkey(std::unique_ptr<EVP_PKEY, void(*)(EVP_PKEY*)>(nullptr, EVP_PKEY_free))
894 {
895
896 int ret = RAND_status();
897 if (ret != 1) {
898 throw runtime_error(getName()+" insufficient entropy");
899 }
900
901 #ifdef HAVE_LIBCRYPTO_ED25519
902 if(d_algorithm == 15) {
903 d_len = 32;
904 d_id = NID_ED25519;
905 }
906 #endif
907 #ifdef HAVE_LIBCRYPTO_ED448
908 if (d_algorithm == 16) {
909 d_len = 57;
910 d_id = NID_ED448;
911 }
912 #endif
913 if (d_len == 0) {
914 throw runtime_error(getName()+" unknown algorithm "+std::to_string(d_algorithm));
915 }
916 }
917
918 ~OpenSSLEDDSADNSCryptoKeyEngine()
919 {
920 }
921
922 string getName() const override { return "OpenSSL EDDSA"; }
923 int getBits() const override { return d_len; }
924
925 void create(unsigned int bits) override;
926 storvector_t convertToISCVector() const override;
927 std::string sign(const std::string& hash) const override;
928 bool verify(const std::string& msg, const std::string& signature) const override;
929 std::string getPubKeyHash() const override;
930 std::string getPublicKeyString() const override;
931 void fromISCMap(DNSKEYRecordContent& drc, std::map<std::string, std::string>& stormap) override;
932 void fromPublicKeyString(const std::string& content) override;
933 bool checkKey(vector<string> *errorMessages) const override;
934
935 static std::shared_ptr<DNSCryptoKeyEngine> maker(unsigned int algorithm)
936 {
937 return std::make_shared<OpenSSLEDDSADNSCryptoKeyEngine>(algorithm);
938 }
939
940 private:
941 size_t d_len{0};
942 int d_id{0};
943
944 std::unique_ptr<EVP_PKEY, void(*)(EVP_PKEY*)> d_edkey;
945 };
946
947 bool OpenSSLEDDSADNSCryptoKeyEngine::checkKey(vector<string> *errorMessages) const
948 {
949 return (d_edkey ? true : false);
950 }
951
952 void OpenSSLEDDSADNSCryptoKeyEngine::create(unsigned int bits)
953 {
954 auto pctx = std::unique_ptr<EVP_PKEY_CTX, void(*)(EVP_PKEY_CTX*)>(EVP_PKEY_CTX_new_id(d_id, nullptr), EVP_PKEY_CTX_free);
955 if (!pctx) {
956 throw runtime_error(getName()+" context initialization failed");
957 }
958 if (EVP_PKEY_keygen_init(pctx.get()) < 1) {
959 throw runtime_error(getName()+" keygen initialization failed");
960 }
961 EVP_PKEY* newKey = nullptr;
962 if (EVP_PKEY_keygen(pctx.get(), &newKey) < 1) {
963 throw runtime_error(getName()+" key generation failed");
964 }
965 d_edkey = std::unique_ptr<EVP_PKEY, void(*)(EVP_PKEY*)>(newKey, EVP_PKEY_free);
966 }
967
968 DNSCryptoKeyEngine::storvector_t OpenSSLEDDSADNSCryptoKeyEngine::convertToISCVector() const
969 {
970 storvector_t storvect;
971 string algorithm;
972
973 #ifdef HAVE_LIBCRYPTO_ED25519
974 if(d_algorithm == 15) {
975 algorithm = "15 (ED25519)";
976 }
977 #endif
978 #ifdef HAVE_LIBCRYPTO_ED448
979 if(d_algorithm == 16) {
980 algorithm = "16 (ED448)";
981 }
982 #endif
983 if (algorithm.empty()) {
984 algorithm = " ? (?)";
985 }
986
987 storvect.push_back(make_pair("Algorithm", algorithm));
988
989 string buf;
990 size_t len = d_len;
991 buf.resize(len);
992 if (EVP_PKEY_get_raw_private_key(d_edkey.get(), reinterpret_cast<unsigned char*>(&buf.at(0)), &len) < 1) {
993 throw runtime_error(getName() + " Could not get private key from d_edkey");
994 }
995 storvect.push_back(make_pair("PrivateKey", buf));
996 return storvect;
997 }
998
999 std::string OpenSSLEDDSADNSCryptoKeyEngine::sign(const std::string& msg) const
1000 {
1001 auto mdctx = std::unique_ptr<EVP_MD_CTX, void(*)(EVP_MD_CTX*)>(EVP_MD_CTX_new(), EVP_MD_CTX_free);
1002 if (!mdctx) {
1003 throw runtime_error(getName()+" MD context initialization failed");
1004 }
1005 if(EVP_DigestSignInit(mdctx.get(), nullptr, nullptr, nullptr, d_edkey.get()) < 1) {
1006 throw runtime_error(getName()+" unable to initialize signer");
1007 }
1008
1009 string msgToSign = msg;
1010
1011 size_t siglen = d_len * 2;
1012 string signature;
1013 signature.resize(siglen);
1014
1015 if (EVP_DigestSign(mdctx.get(),
1016 reinterpret_cast<unsigned char*>(&signature.at(0)), &siglen,
1017 reinterpret_cast<unsigned char*>(&msgToSign.at(0)), msgToSign.length()) < 1) {
1018 throw runtime_error(getName()+" signing error");
1019 }
1020
1021 return signature;
1022 }
1023
1024 bool OpenSSLEDDSADNSCryptoKeyEngine::verify(const std::string& msg, const std::string& signature) const
1025 {
1026 auto mdctx = std::unique_ptr<EVP_MD_CTX, void(*)(EVP_MD_CTX*)>(EVP_MD_CTX_new(), EVP_MD_CTX_free);
1027 if (!mdctx) {
1028 throw runtime_error(getName()+" MD context initialization failed");
1029 }
1030 if(EVP_DigestVerifyInit(mdctx.get(), nullptr, nullptr, nullptr, d_edkey.get()) < 1) {
1031 throw runtime_error(getName()+" unable to initialize signer");
1032 }
1033
1034 string checkSignature = signature;
1035 string checkMsg = msg;
1036
1037 auto r = EVP_DigestVerify(mdctx.get(),
1038 reinterpret_cast<unsigned char*>(&checkSignature.at(0)), checkSignature.length(),
1039 reinterpret_cast<unsigned char*>(&checkMsg.at(0)), checkMsg.length());
1040 if (r < 0) {
1041 throw runtime_error(getName()+" verification failure");
1042 }
1043
1044 return (r == 1);
1045 }
1046
1047 std::string OpenSSLEDDSADNSCryptoKeyEngine::getPubKeyHash() const
1048 {
1049 return this->getPublicKeyString();
1050 }
1051
1052 std::string OpenSSLEDDSADNSCryptoKeyEngine::getPublicKeyString() const
1053 {
1054 string buf;
1055 size_t len = d_len;
1056 buf.resize(len);
1057 if (EVP_PKEY_get_raw_public_key(d_edkey.get(), reinterpret_cast<unsigned char*>(&buf.at(0)), &len) < 1) {
1058 throw std::runtime_error(getName() + " unable to get public key from key struct");
1059 }
1060 return buf;
1061 }
1062
1063 void OpenSSLEDDSADNSCryptoKeyEngine::fromISCMap(DNSKEYRecordContent& drc, std::map<std::string, std::string>& stormap) {
1064 drc.d_algorithm = atoi(stormap["algorithm"].c_str());
1065 if (drc.d_algorithm != d_algorithm) {
1066 throw runtime_error(getName()+" tried to feed an algorithm "+std::to_string(drc.d_algorithm)+" to a "+std::to_string(d_algorithm)+" key");
1067 }
1068
1069 d_edkey = std::unique_ptr<EVP_PKEY, void(*)(EVP_PKEY*)>(EVP_PKEY_new_raw_private_key(d_id, nullptr, reinterpret_cast<unsigned char*>(&stormap["privatekey"].at(0)), stormap["privatekey"].length()), EVP_PKEY_free);
1070 if (!d_edkey) {
1071 throw std::runtime_error(getName() + " could not create key structure from private key");
1072 }
1073 }
1074
1075 void OpenSSLEDDSADNSCryptoKeyEngine::fromPublicKeyString(const std::string& content)
1076 {
1077 if (content.length() != d_len) {
1078 throw runtime_error(getName() + " wrong public key length for algorithm " + std::to_string(d_algorithm));
1079 }
1080
1081 const unsigned char* raw = reinterpret_cast<const unsigned char*>(content.c_str());
1082
1083 d_edkey = std::unique_ptr<EVP_PKEY, void(*)(EVP_PKEY*)>(EVP_PKEY_new_raw_public_key(d_id, nullptr, raw, d_len), EVP_PKEY_free);
1084 if (!d_edkey) {
1085 throw runtime_error(getName()+" allocation of public key structure failed");
1086 }
1087 }
1088 #endif // HAVE_LIBCRYPTO_EDDSA
1089
1090 namespace {
1091 struct LoaderStruct
1092 {
1093 LoaderStruct()
1094 {
1095 DNSCryptoKeyEngine::report(5, &OpenSSLRSADNSCryptoKeyEngine::maker);
1096 DNSCryptoKeyEngine::report(7, &OpenSSLRSADNSCryptoKeyEngine::maker);
1097 DNSCryptoKeyEngine::report(8, &OpenSSLRSADNSCryptoKeyEngine::maker);
1098 DNSCryptoKeyEngine::report(10, &OpenSSLRSADNSCryptoKeyEngine::maker);
1099 #ifdef HAVE_LIBCRYPTO_ECDSA
1100 DNSCryptoKeyEngine::report(13, &OpenSSLECDSADNSCryptoKeyEngine::maker);
1101 DNSCryptoKeyEngine::report(14, &OpenSSLECDSADNSCryptoKeyEngine::maker);
1102 #endif
1103 #ifdef HAVE_LIBCRYPTO_ED25519
1104 DNSCryptoKeyEngine::report(15, &OpenSSLEDDSADNSCryptoKeyEngine::maker);
1105 #endif
1106 #ifdef HAVE_LIBCRYPTO_ED448
1107 DNSCryptoKeyEngine::report(16, &OpenSSLEDDSADNSCryptoKeyEngine::maker);
1108 #endif
1109 }
1110 } loaderOpenSSL;
1111 }