2 * This file is part of PowerDNS or dnsdist.
3 * Copyright -- PowerDNS.COM B.V. and its contributors
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.
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.
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.
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.
25 #include <openssl/obj_mac.h>
26 #ifdef HAVE_LIBCRYPTO_ECDSA
27 #include <openssl/ecdsa.h>
29 #if defined(HAVE_LIBCRYPTO_ED25519) || defined(HAVE_LIBCRYPTO_ED448)
30 #include <openssl/evp.h>
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"
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. */
46 static std::vector
<std::mutex
> openssllocks
;
49 void openssl_pthreads_locking_callback(int mode
, int type
, const char *file
, int line
)
51 if (mode
& CRYPTO_LOCK
) {
52 openssllocks
.at(type
).lock();
55 openssllocks
.at(type
).unlock();
59 unsigned long openssl_pthreads_id_callback()
61 return (unsigned long)pthread_self();
65 void openssl_thread_setup()
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
);
72 void openssl_thread_cleanup()
74 CRYPTO_set_locking_callback(nullptr);
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
) {
87 static inline int RSA_set0_key(RSA
* rsakey
, BIGNUM
* n
, BIGNUM
* e
, BIGNUM
* d
) {
89 BN_clear_free(rsakey
->n
);
93 BN_clear_free(rsakey
->e
);
97 BN_clear_free(rsakey
->d
);
103 static inline void RSA_get0_factors(const RSA
* rsakey
, const BIGNUM
** p
, const BIGNUM
** q
) {
108 static inline int RSA_set0_factors(RSA
* rsakey
, BIGNUM
* p
, BIGNUM
* q
) {
109 BN_clear_free(rsakey
->p
);
111 BN_clear_free(rsakey
->q
);
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
;
122 static inline int RSA_set0_crt_params(RSA
* rsakey
, BIGNUM
* dmp1
, BIGNUM
* dmq1
, BIGNUM
* iqmp
) {
123 BN_clear_free(rsakey
->dmp1
);
125 BN_clear_free(rsakey
->dmq1
);
127 BN_clear_free(rsakey
->iqmp
);
132 #ifdef HAVE_LIBCRYPTO_ECDSA
133 static inline void ECDSA_SIG_get0(const ECDSA_SIG
* signature
, const BIGNUM
** pr
, const 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
);
145 #endif /* HAVE_LIBCRYPTO_ECDSA */
147 #endif /* HAVE_RSA_GET0_KEY */
150 void openssl_thread_setup() {}
151 void openssl_thread_cleanup() {}
160 entropy
.reserve(1024);
163 for(int i
=0; i
<1024; i
+=4) {
164 r
=dns_random(0xffffffff);
165 entropy
.append((const char*)&r
, 4);
168 RAND_seed((const unsigned char*)entropy
.c_str(), 1024);
172 class OpenSSLRSADNSCryptoKeyEngine
: public DNSCryptoKeyEngine
175 explicit OpenSSLRSADNSCryptoKeyEngine(unsigned int algo
): DNSCryptoKeyEngine(algo
), d_key(std::unique_ptr
<RSA
, void(*)(RSA
*)>(nullptr, RSA_free
))
177 int ret
= RAND_status();
179 throw runtime_error(getName()+" insufficient entropy");
183 ~OpenSSLRSADNSCryptoKeyEngine()
187 string
getName() const override
{ return "OpenSSL RSA"; }
188 int getBits() const override
{ return RSA_size(d_key
.get()) << 3; }
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
;
201 static std::shared_ptr
<DNSCryptoKeyEngine
> maker(unsigned int algorithm
)
203 return std::make_shared
<OpenSSLRSADNSCryptoKeyEngine
>(algorithm
);
207 static int hashSizeToKind(size_t hashSize
);
209 std::unique_ptr
<RSA
, void(*)(RSA
*)> d_key
;
213 void OpenSSLRSADNSCryptoKeyEngine::create(unsigned int bits
)
215 // When changing the bitsizes, also edit them in ::checkKey
216 if ((d_algorithm
== DNSSECKeeper::RSASHA1
|| d_algorithm
== DNSSECKeeper::RSASHA1NSEC3SHA1
) && (bits
< 512 || bits
> 4096)) {
218 throw runtime_error(getName()+" RSASHA1 key generation failed for invalid bits size " + std::to_string(bits
));
220 if (d_algorithm
== DNSSECKeeper::RSASHA256
&& (bits
< 512 || bits
> 4096)) {
222 throw runtime_error(getName()+" RSASHA256 key generation failed for invalid bits size " + std::to_string(bits
));
224 if (d_algorithm
== DNSSECKeeper::RSASHA512
&& (bits
< 1024 || bits
> 4096)) {
226 throw runtime_error(getName()+" RSASHA512 key generation failed for invalid bits size " + std::to_string(bits
));
229 auto e
= std::unique_ptr
<BIGNUM
, void(*)(BIGNUM
*)>(BN_new(), BN_clear_free
);
231 throw runtime_error(getName()+" key generation failed, unable to allocate e");
234 /* RSA_F4 is a public exponent value of 65537 */
235 int res
= BN_set_word(e
.get(), RSA_F4
);
238 throw runtime_error(getName()+" key generation failed while setting e");
241 auto key
= std::unique_ptr
<RSA
, void(*)(RSA
*)>(RSA_new(), RSA_free
);
243 throw runtime_error(getName()+" allocation of key structure failed");
246 res
= RSA_generate_key_ex(key
.get(), bits
, e
.get(), nullptr);
248 throw runtime_error(getName()+" key generation failed");
251 d_key
= std::move(key
);
255 DNSCryptoKeyEngine::storvector_t
OpenSSLRSADNSCryptoKeyEngine::convertToISCVector() const
257 storvector_t storvect
;
258 typedef vector
<pair
<string
, const BIGNUM
*> > outputs_t
;
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
));
273 string algorithm
=std::to_string(d_algorithm
);
274 switch(d_algorithm
) {
275 case DNSSECKeeper::RSASHA1
:
276 case DNSSECKeeper::RSASHA1NSEC3SHA1
:
277 algorithm
+= " (RSASHA1)";
279 case DNSSECKeeper::RSASHA256
:
280 algorithm
+= " (RSASHA256)";
282 case DNSSECKeeper::RSASHA512
:
283 algorithm
+= " (RSASHA512)";
288 storvect
.push_back(make_pair("Algorithm", algorithm
));
290 for(outputs_t::value_type value
: outputs
) {
292 tmp
.resize(BN_num_bytes(value
.second
));
293 int len
= BN_bn2bin(value
.second
, reinterpret_cast<unsigned char*>(&tmp
.at(0)));
296 storvect
.push_back(make_pair(value
.first
, tmp
));
304 std::string
OpenSSLRSADNSCryptoKeyEngine::hash(const std::string
& orig
) const
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
));
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
));
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
));
322 throw runtime_error(getName()+" does not support hash operation for algorithm "+std::to_string(d_algorithm
));
325 int OpenSSLRSADNSCryptoKeyEngine::hashSizeToKind(const size_t hashSize
)
328 case SHA_DIGEST_LENGTH
:
330 case SHA256_DIGEST_LENGTH
:
332 case SHA384_DIGEST_LENGTH
:
334 case SHA512_DIGEST_LENGTH
:
337 throw runtime_error("OpenSSL RSA does not handle hash of size " + std::to_string(hashSize
));
341 std::string
OpenSSLRSADNSCryptoKeyEngine::sign(const std::string
& msg
) const
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;
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());
351 throw runtime_error(getName()+" failed to generate signature");
354 signature
.resize(signatureLen
);
359 bool OpenSSLRSADNSCryptoKeyEngine::verify(const std::string
& msg
, const std::string
& signature
) const
361 string l_hash
= this->hash(msg
);
362 int hashKind
= hashSizeToKind(l_hash
.size());
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());
370 std::string
OpenSSLRSADNSCryptoKeyEngine::getPubKeyHash() const
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
];
379 int res
= SHA1_Init(&ctx
);
382 throw runtime_error(getName()+" failed to init hash context for generating the public key hash");
385 int len
= BN_bn2bin(e
, tmp
.data());
386 res
= SHA1_Update(&ctx
, tmp
.data(), len
);
388 throw runtime_error(getName()+" failed to update hash context for generating the public key hash");
391 len
= BN_bn2bin(n
, tmp
.data());
392 res
= SHA1_Update(&ctx
, tmp
.data(), len
);
394 throw runtime_error(getName()+" failed to update hash context for generating the public key hash");
397 res
= SHA1_Final(l_hash
, &ctx
);
399 throw runtime_error(getName()+" failed to finish hash context for generating the public key hash");
402 return string((char*)l_hash
, sizeof(l_hash
));
406 std::string
OpenSSLRSADNSCryptoKeyEngine::getPublicKeyString() const
408 const BIGNUM
*n
, *e
, *d
;
409 RSA_get0_key(d_key
.get(), &n
, &e
, &d
);
412 tmp
.resize(std::max(BN_num_bytes(e
), BN_num_bytes(n
)));
414 int len
= BN_bn2bin(e
, reinterpret_cast<unsigned char*>(&tmp
.at(0)));
416 keystring
.assign(1, (char) (unsigned int) len
);
418 keystring
.assign(1, 0);
419 uint16_t tempLen
= len
;
420 tempLen
= htons(tempLen
);
421 keystring
.append((char*)&tempLen
, 2);
423 keystring
.append(&tmp
.at(0), len
);
425 len
= BN_bn2bin(n
, reinterpret_cast<unsigned char*>(&tmp
.at(0)));
426 keystring
.append(&tmp
.at(0), len
);
432 void OpenSSLRSADNSCryptoKeyEngine::fromISCMap(DNSKEYRecordContent
& drc
, std::map
<std::string
, std::string
>& stormap
)
434 typedef map
<string
, BIGNUM
**> places_t
;
436 auto key
= std::unique_ptr
<RSA
, void(*)(RSA
*)>(RSA_new(), RSA_free
);
438 throw runtime_error(getName()+" allocation of key structure failed");
441 BIGNUM
*n
, *e
, *d
, *p
, *q
, *dmp1
, *dmq1
, *iqmp
;
444 throw runtime_error(getName()+" allocation of BIGNUM n failed");
449 throw runtime_error(getName()+" allocation of BIGNUM e failed");
455 throw runtime_error(getName()+" allocation of BIGNUM d failed");
457 RSA_set0_key(key
.get(), n
, e
, d
);
461 throw runtime_error(getName()+" allocation of BIGNUM p failed");
466 throw runtime_error(getName()+" allocation of BIGNUM q failed");
468 RSA_set0_factors(key
.get(), p
, q
);
471 if (dmp1
== nullptr) {
472 throw runtime_error(getName()+" allocation of BIGNUM dmp1 failed");
475 if (dmq1
== nullptr) {
477 throw runtime_error(getName()+" allocation of BIGNUM dmq1 failed");
480 if (iqmp
== nullptr) {
483 throw runtime_error(getName()+" allocation of BIGNUM iqmp failed");
485 RSA_set0_crt_params(key
.get(), dmp1
, dmq1
, iqmp
);
487 places
["Modulus"]=&n
;
488 places
["PublicExponent"]=&e
;
489 places
["PrivateExponent"]=&d
;
492 places
["Exponent1"]=&dmp1
;
493 places
["Exponent2"]=&dmq1
;
494 places
["Coefficient"]=&iqmp
;
496 drc
.d_algorithm
= pdns_stou(stormap
["algorithm"]);
499 for(const places_t::value_type
& val
: places
) {
500 raw
=stormap
[toLower(val
.first
)];
505 *val
.second
= BN_bin2bn((unsigned char*) raw
.c_str(), raw
.length(), *val
.second
);
507 throw runtime_error(getName()+" error loading " + val
.first
);
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");
515 d_key
= std::move(key
);
518 bool OpenSSLRSADNSCryptoKeyEngine::checkKey(vector
<string
> *errorMessages
) const
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)) {
524 if (errorMessages
!= nullptr) {
525 errorMessages
->push_back("key is " + std::to_string(getBits()) + " bytes, should be between 512 and 4096");
528 if (d_algorithm
== DNSSECKeeper::RSASHA512
&& (getBits() < 1024 || getBits() > 4096)) {
530 if (errorMessages
!= nullptr) {
531 errorMessages
->push_back("key is " + std::to_string(getBits()) + " bytes, should be between 1024 and 4096");
534 if (RSA_check_key(d_key
.get()) != 1) {
536 if (errorMessages
!= nullptr) {
537 errorMessages
->push_back(ERR_reason_error_string(ERR_get_error()));
543 void OpenSSLRSADNSCryptoKeyEngine::fromPublicKeyString(const std::string
& input
)
545 string exponent
, modulus
;
546 const size_t inputLen
= input
.length();
547 const unsigned char* raw
= (const unsigned char*)input
.c_str();
550 throw runtime_error(getName()+" invalid input size for the public key");
554 const size_t exponentSize
= raw
[0];
555 if (inputLen
< (exponentSize
+ 2)) {
556 throw runtime_error(getName()+" invalid input size for the public key");
558 exponent
= input
.substr(1, exponentSize
);
559 modulus
= input
.substr(exponentSize
+ 1);
562 throw runtime_error(getName()+" invalid input size for the public key");
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");
568 exponent
= input
.substr(3, exponentSize
);
569 modulus
= input
.substr(exponentSize
+ 3);
572 auto key
= std::unique_ptr
<RSA
, void(*)(RSA
*)>(RSA_new(), RSA_free
);
574 throw runtime_error(getName()+" allocation of key structure failed");
577 auto e
= std::unique_ptr
<BIGNUM
, void(*)(BIGNUM
*)>(BN_bin2bn((unsigned char*)exponent
.c_str(), exponent
.length(), nullptr), BN_clear_free
);
579 throw runtime_error(getName()+" error loading e value of public key");
581 auto n
= std::unique_ptr
<BIGNUM
, void(*)(BIGNUM
*)>(BN_bin2bn((unsigned char*)modulus
.c_str(), modulus
.length(), nullptr), BN_clear_free
);
583 throw runtime_error(getName()+" error loading n value of public key");
586 RSA_set0_key(key
.get(), n
.release(), e
.release(), nullptr);
587 d_key
= std::move(key
);
590 #ifdef HAVE_LIBCRYPTO_ECDSA
591 class OpenSSLECDSADNSCryptoKeyEngine
: public DNSCryptoKeyEngine
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
))
597 int ret
= RAND_status();
599 throw runtime_error(getName()+" insufficient entropy");
603 throw runtime_error(getName()+" allocation of key structure failed");
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
);
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
);
613 throw runtime_error(getName()+" unknown algorithm "+std::to_string(d_algorithm
));
617 throw runtime_error(getName()+" allocation of group structure failed");
620 ret
= EC_KEY_set_group(d_eckey
.get(), d_ecgroup
.get());
622 throw runtime_error(getName()+" setting key group failed");
626 ~OpenSSLECDSADNSCryptoKeyEngine()
630 string
getName() const override
{ return "OpenSSL ECDSA"; }
631 int getBits() const override
{ return d_len
<< 3; }
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
;
644 static std::shared_ptr
<DNSCryptoKeyEngine
> maker(unsigned int algorithm
)
646 return std::make_shared
<OpenSSLECDSADNSCryptoKeyEngine
>(algorithm
);
652 std::unique_ptr
<EC_KEY
, void(*)(EC_KEY
*)> d_eckey
;
653 std::unique_ptr
<EC_GROUP
, void(*)(EC_GROUP
*)> d_ecgroup
;
657 void OpenSSLECDSADNSCryptoKeyEngine::create(unsigned int bits
)
659 if (bits
>> 3 != d_len
) {
660 throw runtime_error(getName()+" unknown key length of "+std::to_string(bits
)+" bits requested");
663 int res
= EC_KEY_generate_key(d_eckey
.get());
665 throw runtime_error(getName()+" key generation failed");
670 DNSCryptoKeyEngine::storvector_t
OpenSSLECDSADNSCryptoKeyEngine::convertToISCVector() const
672 storvector_t storvect
;
675 if(d_algorithm
== 13)
676 algorithm
= "13 (ECDSAP256SHA256)";
677 else if(d_algorithm
== 14)
678 algorithm
= "14 (ECDSAP384SHA384)";
680 algorithm
= " ? (?)";
682 storvect
.push_back(make_pair("Algorithm", algorithm
));
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");
690 tmp
.resize(BN_num_bytes(key
));
691 int len
= BN_bn2bin(key
, reinterpret_cast<unsigned char*>(&tmp
.at(0)));
695 prefix
.append(d_len
- len
, 0x00);
697 storvect
.push_back(make_pair("PrivateKey", prefix
+ tmp
));
703 std::string
OpenSSLECDSADNSCryptoKeyEngine::hash(const std::string
& orig
) const
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
));
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
));
716 throw runtime_error(getName()+" does not support a hash size of "+std::to_string(getBits())+" bits");
720 std::string
OpenSSLECDSADNSCryptoKeyEngine::sign(const std::string
& msg
) const
722 string l_hash
= this->hash(msg
);
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
);
726 throw runtime_error(getName()+" failed to generate signature");
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)));
737 ret
.append(d_len
- len
, 0x00);
738 ret
.append(&tmp
.at(0), len
);
740 len
= BN_bn2bin(ps
, reinterpret_cast<unsigned char*>(&tmp
.at(0)));
742 ret
.append(d_len
- len
, 0x00);
743 ret
.append(&tmp
.at(0), len
);
749 bool OpenSSLECDSADNSCryptoKeyEngine::verify(const std::string
& msg
, const std::string
& signature
) const
751 if (signature
.length() != (d_len
* 2)) {
752 throw runtime_error(getName()+" invalid signature size "+std::to_string(signature
.length()));
755 string l_hash
= this->hash(msg
);
757 auto sig
= std::unique_ptr
<ECDSA_SIG
, void(*)(ECDSA_SIG
*)>(ECDSA_SIG_new(), ECDSA_SIG_free
);
759 throw runtime_error(getName()+" allocation of signature structure failed");
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
);
765 throw runtime_error(getName()+" invalid signature");
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());
772 throw runtime_error(getName()+" verify error");
779 std::string
OpenSSLECDSADNSCryptoKeyEngine::getPubKeyHash() const
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
));
788 std::string
OpenSSLECDSADNSCryptoKeyEngine::getPublicKeyString() const
790 std::string binaryPoint
;
791 binaryPoint
.resize((d_len
* 2) + 1);
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);
795 throw runtime_error(getName()+" exporting point to binary failed");
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);
806 void OpenSSLECDSADNSCryptoKeyEngine::fromISCMap(DNSKEYRecordContent
& drc
, std::map
<std::string
, std::string
>& stormap
)
808 drc
.d_algorithm
= atoi(stormap
["algorithm"].c_str());
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");
814 string privateKey
= stormap
["privatekey"];
816 auto prv_key
= std::unique_ptr
<BIGNUM
, void(*)(BIGNUM
*)>(BN_bin2bn((unsigned char*) privateKey
.c_str(), privateKey
.length(), nullptr), BN_clear_free
);
818 throw runtime_error(getName()+" reading private key from binary failed");
821 int ret
= EC_KEY_set_private_key(d_eckey
.get(), prv_key
.get());
823 throw runtime_error(getName()+" setting private key failed");
826 auto pub_key
= std::unique_ptr
<EC_POINT
, void(*)(EC_POINT
*)>(EC_POINT_new(d_ecgroup
.get()), EC_POINT_free
);
828 throw runtime_error(getName()+" allocation of public key point failed");
831 ret
= EC_POINT_mul(d_ecgroup
.get(), pub_key
.get(), prv_key
.get(), nullptr, nullptr, nullptr);
833 throw runtime_error(getName()+" computing public key from private failed");
836 ret
= EC_KEY_set_public_key(d_eckey
.get(), pub_key
.get());
838 throw runtime_error(getName()+" setting public key failed");
842 bool OpenSSLECDSADNSCryptoKeyEngine::checkKey(vector
<string
> *errorMessages
) const
845 if (EC_KEY_check_key(d_eckey
.get()) != 1) {
847 if (errorMessages
!= nullptr) {
848 errorMessages
->push_back(ERR_reason_error_string(ERR_get_error()));
854 void OpenSSLECDSADNSCryptoKeyEngine::fromPublicKeyString(const std::string
& input
)
856 /* uncompressed point, from SEC1:
857 "2.3.4 Octet-String-to-Elliptic-Curve-Point Conversion" */
858 string ecdsaPoint
= "\x04";
859 ecdsaPoint
.append(input
);
861 auto pub_key
= std::unique_ptr
<EC_POINT
, void(*)(EC_POINT
*)>(EC_POINT_new(d_ecgroup
.get()), EC_POINT_free
);
863 throw runtime_error(getName()+" allocation of point structure failed");
866 int ret
= EC_POINT_oct2point(d_ecgroup
.get(), pub_key
.get(), (unsigned char*) ecdsaPoint
.c_str(), ecdsaPoint
.length(), nullptr);
868 throw runtime_error(getName()+" reading ECP point from binary failed");
871 ret
= EC_KEY_set_private_key(d_eckey
.get(), nullptr);
873 throw runtime_error(getName()+" setting private key failed");
876 ret
= EC_KEY_set_public_key(d_eckey
.get(), pub_key
.get());
878 throw runtime_error(getName()+" setting public key failed");
883 #ifdef HAVE_LIBCRYPTO_EDDSA
884 class OpenSSLEDDSADNSCryptoKeyEngine
: public DNSCryptoKeyEngine
887 explicit OpenSSLEDDSADNSCryptoKeyEngine(unsigned int algo
) : DNSCryptoKeyEngine(algo
), d_edkey(std::unique_ptr
<EVP_PKEY
, void(*)(EVP_PKEY
*)>(nullptr, EVP_PKEY_free
))
890 int ret
= RAND_status();
892 throw runtime_error(getName()+" insufficient entropy");
895 #ifdef HAVE_LIBCRYPTO_ED25519
896 if(d_algorithm
== 15) {
901 #ifdef HAVE_LIBCRYPTO_ED448
902 if (d_algorithm
== 16) {
908 throw runtime_error(getName()+" unknown algorithm "+std::to_string(d_algorithm
));
912 ~OpenSSLEDDSADNSCryptoKeyEngine()
916 string
getName() const override
{ return "OpenSSL EDDSA"; }
917 int getBits() const override
{ return d_len
<< 3; }
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
;
929 static std::shared_ptr
<DNSCryptoKeyEngine
> maker(unsigned int algorithm
)
931 return std::make_shared
<OpenSSLEDDSADNSCryptoKeyEngine
>(algorithm
);
938 std::unique_ptr
<EVP_PKEY
, void(*)(EVP_PKEY
*)> d_edkey
;
941 bool OpenSSLEDDSADNSCryptoKeyEngine::checkKey(vector
<string
> *errorMessages
) const
943 return (d_edkey
? true : false);
946 void OpenSSLEDDSADNSCryptoKeyEngine::create(unsigned int bits
)
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
);
950 throw runtime_error(getName()+" context initialization failed");
952 if (EVP_PKEY_keygen_init(pctx
.get()) < 1) {
953 throw runtime_error(getName()+" keygen initialization failed");
955 EVP_PKEY
* newKey
= nullptr;
956 if (EVP_PKEY_keygen(pctx
.get(), &newKey
) < 1) {
957 throw runtime_error(getName()+" key generation failed");
959 d_edkey
= std::unique_ptr
<EVP_PKEY
, void(*)(EVP_PKEY
*)>(newKey
, EVP_PKEY_free
);
962 DNSCryptoKeyEngine::storvector_t
OpenSSLEDDSADNSCryptoKeyEngine::convertToISCVector() const
964 storvector_t storvect
;
967 #ifdef HAVE_LIBCRYPTO_ED25519
968 if(d_algorithm
== 15) {
969 algorithm
= "15 (ED25519)";
972 #ifdef HAVE_LIBCRYPTO_ED448
973 if(d_algorithm
== 16) {
974 algorithm
= "16 (ED448)";
977 if (algorithm
.empty()) {
978 algorithm
= " ? (?)";
981 storvect
.push_back(make_pair("Algorithm", algorithm
));
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");
989 storvect
.push_back(make_pair("PrivateKey", buf
));
993 std::string
OpenSSLEDDSADNSCryptoKeyEngine::sign(const std::string
& msg
) const
995 auto mdctx
= std::unique_ptr
<EVP_MD_CTX
, void(*)(EVP_MD_CTX
*)>(EVP_MD_CTX_new(), EVP_MD_CTX_free
);
997 throw runtime_error(getName()+" MD context initialization failed");
999 if(EVP_DigestSignInit(mdctx
.get(), nullptr, nullptr, nullptr, d_edkey
.get()) < 1) {
1000 throw runtime_error(getName()+" unable to initialize signer");
1003 string msgToSign
= msg
;
1005 size_t siglen
= d_len
* 2;
1007 signature
.resize(siglen
);
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");
1018 bool OpenSSLEDDSADNSCryptoKeyEngine::verify(const std::string
& msg
, const std::string
& signature
) const
1020 auto mdctx
= std::unique_ptr
<EVP_MD_CTX
, void(*)(EVP_MD_CTX
*)>(EVP_MD_CTX_new(), EVP_MD_CTX_free
);
1022 throw runtime_error(getName()+" MD context initialization failed");
1024 if(EVP_DigestVerifyInit(mdctx
.get(), nullptr, nullptr, nullptr, d_edkey
.get()) < 1) {
1025 throw runtime_error(getName()+" unable to initialize signer");
1028 string checkSignature
= signature
;
1029 string checkMsg
= msg
;
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());
1035 throw runtime_error(getName()+" verification failure");
1041 std::string
OpenSSLEDDSADNSCryptoKeyEngine::getPubKeyHash() const
1043 return this->getPublicKeyString();
1046 std::string
OpenSSLEDDSADNSCryptoKeyEngine::getPublicKeyString() const
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");
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");
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
);
1065 throw std::runtime_error(getName() + " could not create key structure from private key");
1069 void OpenSSLEDDSADNSCryptoKeyEngine::fromPublicKeyString(const std::string
& content
)
1071 if (content
.length() != d_len
) {
1072 throw runtime_error(getName() + " wrong public key length for algorithm " + std::to_string(d_algorithm
));
1075 const unsigned char* raw
= reinterpret_cast<const unsigned char*>(content
.c_str());
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
);
1079 throw runtime_error(getName()+" allocation of public key structure failed");
1082 #endif // HAVE_LIBCRYPTO_EDDSA
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
);
1097 #ifdef HAVE_LIBCRYPTO_ED25519
1098 DNSCryptoKeyEngine::report(15, &OpenSSLEDDSADNSCryptoKeyEngine::maker
);
1100 #ifdef HAVE_LIBCRYPTO_ED448
1101 DNSCryptoKeyEngine::report(16, &OpenSSLEDDSADNSCryptoKeyEngine::maker
);