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