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