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