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. */
44 static pthread_mutex_t
*openssllocks
;
47 void openssl_pthreads_locking_callback(int mode
, int type
, const char *file
, int line
)
49 if (mode
& CRYPTO_LOCK
) {
50 pthread_mutex_lock(&(openssllocks
[type
]));
53 pthread_mutex_unlock(&(openssllocks
[type
]));
57 unsigned long openssl_pthreads_id_callback()
59 return (unsigned long)pthread_self();
63 void openssl_thread_setup()
65 openssllocks
= (pthread_mutex_t
*)OPENSSL_malloc(CRYPTO_num_locks() * sizeof(pthread_mutex_t
));
67 for (int i
= 0; i
< CRYPTO_num_locks(); i
++)
68 pthread_mutex_init(&(openssllocks
[i
]), NULL
);
70 CRYPTO_set_id_callback(openssl_pthreads_id_callback
);
71 CRYPTO_set_locking_callback(openssl_pthreads_locking_callback
);
74 void openssl_thread_cleanup()
76 CRYPTO_set_locking_callback(NULL
);
78 for (int i
=0; i
<CRYPTO_num_locks(); i
++) {
79 pthread_mutex_destroy(&(openssllocks
[i
]));
82 OPENSSL_free(openssllocks
);
85 #ifndef HAVE_RSA_GET0_KEY
86 /* those symbols are defined in LibreSSL 2.7.0+ */
87 /* compat helpers. These DO NOT do any of the checking that the libssl 1.1 functions do. */
88 static inline void RSA_get0_key(const RSA
* rsakey
, const BIGNUM
** n
, const BIGNUM
** e
, const BIGNUM
** d
) {
94 static inline int RSA_set0_key(RSA
* rsakey
, BIGNUM
* n
, BIGNUM
* e
, BIGNUM
* d
) {
96 BN_clear_free(rsakey
->n
);
100 BN_clear_free(rsakey
->e
);
104 BN_clear_free(rsakey
->d
);
110 static inline void RSA_get0_factors(const RSA
* rsakey
, const BIGNUM
** p
, const BIGNUM
** q
) {
115 static inline int RSA_set0_factors(RSA
* rsakey
, BIGNUM
* p
, BIGNUM
* q
) {
116 BN_clear_free(rsakey
->p
);
118 BN_clear_free(rsakey
->q
);
123 static inline void RSA_get0_crt_params(const RSA
* rsakey
, const BIGNUM
** dmp1
, const BIGNUM
** dmq1
, const BIGNUM
** iqmp
) {
124 *dmp1
= rsakey
->dmp1
;
125 *dmq1
= rsakey
->dmq1
;
126 *iqmp
= rsakey
->iqmp
;
129 static inline int RSA_set0_crt_params(RSA
* rsakey
, BIGNUM
* dmp1
, BIGNUM
* dmq1
, BIGNUM
* iqmp
) {
130 BN_clear_free(rsakey
->dmp1
);
132 BN_clear_free(rsakey
->dmq1
);
134 BN_clear_free(rsakey
->iqmp
);
139 #ifdef HAVE_LIBCRYPTO_ECDSA
140 static inline void ECDSA_SIG_get0(const ECDSA_SIG
* signature
, const BIGNUM
** pr
, const BIGNUM
** ps
) {
145 static inline int ECDSA_SIG_set0(ECDSA_SIG
* signature
, BIGNUM
* pr
, BIGNUM
* ps
) {
146 BN_clear_free(signature
->r
);
147 BN_clear_free(signature
->s
);
152 #endif /* HAVE_LIBCRYPTO_ECDSA */
154 #endif /* HAVE_RSA_GET0_KEY */
157 void openssl_thread_setup() {}
158 void openssl_thread_cleanup() {}
167 entropy
.reserve(1024);
170 for(int i
=0; i
<1024; i
+=4) {
171 r
=dns_random(0xffffffff);
172 entropy
.append((const char*)&r
, 4);
175 RAND_seed((const unsigned char*)entropy
.c_str(), 1024);
179 class OpenSSLRSADNSCryptoKeyEngine
: public DNSCryptoKeyEngine
182 explicit OpenSSLRSADNSCryptoKeyEngine(unsigned int algo
): DNSCryptoKeyEngine(algo
), d_key(std::unique_ptr
<RSA
, void(*)(RSA
*)>(nullptr, RSA_free
))
184 int ret
= RAND_status();
186 throw runtime_error(getName()+" insufficient entropy");
190 ~OpenSSLRSADNSCryptoKeyEngine()
194 string
getName() const override
{ return "OpenSSL RSA"; }
195 int getBits() const override
{ return RSA_size(d_key
.get()) << 3; }
197 void create(unsigned int bits
) override
;
198 storvector_t
convertToISCVector() const override
;
199 std::string
hash(const std::string
& hash
) const override
;
200 std::string
sign(const std::string
& hash
) const override
;
201 bool verify(const std::string
& hash
, const std::string
& signature
) const override
;
202 std::string
getPubKeyHash() const override
;
203 std::string
getPublicKeyString() const override
;
204 void fromISCMap(DNSKEYRecordContent
& drc
, std::map
<std::string
, std::string
>& stormap
) override
;
205 void fromPublicKeyString(const std::string
& content
) override
;
206 bool checkKey(vector
<string
> *errorMessages
) const override
;
208 static std::shared_ptr
<DNSCryptoKeyEngine
> maker(unsigned int algorithm
)
210 return std::make_shared
<OpenSSLRSADNSCryptoKeyEngine
>(algorithm
);
214 static int hashSizeToKind(size_t hashSize
);
216 std::unique_ptr
<RSA
, void(*)(RSA
*)> d_key
;
220 void OpenSSLRSADNSCryptoKeyEngine::create(unsigned int bits
)
222 // When changing the bitsizes, also edit them in ::checkKey
223 if ((d_algorithm
== DNSSECKeeper::RSASHA1
|| d_algorithm
== DNSSECKeeper::RSASHA1NSEC3SHA1
) && (bits
< 512 || bits
> 4096)) {
225 throw runtime_error(getName()+" RSASHA1 key generation failed for invalid bits size " + std::to_string(bits
));
227 if (d_algorithm
== DNSSECKeeper::RSASHA256
&& (bits
< 512 || bits
> 4096)) {
229 throw runtime_error(getName()+" RSASHA256 key generation failed for invalid bits size " + std::to_string(bits
));
231 if (d_algorithm
== DNSSECKeeper::RSASHA512
&& (bits
< 1024 || bits
> 4096)) {
233 throw runtime_error(getName()+" RSASHA512 key generation failed for invalid bits size " + std::to_string(bits
));
236 auto e
= std::unique_ptr
<BIGNUM
, void(*)(BIGNUM
*)>(BN_new(), BN_clear_free
);
238 throw runtime_error(getName()+" key generation failed, unable to allocate e");
241 /* RSA_F4 is a public exponent value of 65537 */
242 int res
= BN_set_word(e
.get(), RSA_F4
);
245 throw runtime_error(getName()+" key generation failed while setting e");
248 auto key
= std::unique_ptr
<RSA
, void(*)(RSA
*)>(RSA_new(), RSA_free
);
250 throw runtime_error(getName()+" allocation of key structure failed");
253 res
= RSA_generate_key_ex(key
.get(), bits
, e
.get(), nullptr);
255 throw runtime_error(getName()+" key generation failed");
258 d_key
= std::move(key
);
262 DNSCryptoKeyEngine::storvector_t
OpenSSLRSADNSCryptoKeyEngine::convertToISCVector() const
264 storvector_t storvect
;
265 typedef vector
<pair
<string
, const BIGNUM
*> > outputs_t
;
267 const BIGNUM
*n
, *e
, *d
, *p
, *q
, *dmp1
, *dmq1
, *iqmp
;
268 RSA_get0_key(d_key
.get(), &n
, &e
, &d
);
269 RSA_get0_factors(d_key
.get(), &p
, &q
);
270 RSA_get0_crt_params(d_key
.get(), &dmp1
, &dmq1
, &iqmp
);
271 outputs
.push_back(make_pair("Modulus", n
));
272 outputs
.push_back(make_pair("PublicExponent", e
));
273 outputs
.push_back(make_pair("PrivateExponent", d
));
274 outputs
.push_back(make_pair("Prime1", p
));
275 outputs
.push_back(make_pair("Prime2", q
));
276 outputs
.push_back(make_pair("Exponent1", dmp1
));
277 outputs
.push_back(make_pair("Exponent2", dmq1
));
278 outputs
.push_back(make_pair("Coefficient", iqmp
));
280 string algorithm
=std::to_string(d_algorithm
);
281 switch(d_algorithm
) {
282 case DNSSECKeeper::RSASHA1
:
283 case DNSSECKeeper::RSASHA1NSEC3SHA1
:
284 algorithm
+= " (RSASHA1)";
286 case DNSSECKeeper::RSASHA256
:
287 algorithm
+= " (RSASHA256)";
289 case DNSSECKeeper::RSASHA512
:
290 algorithm
+= " (RSASHA512)";
295 storvect
.push_back(make_pair("Algorithm", algorithm
));
297 for(outputs_t::value_type value
: outputs
) {
299 tmp
.resize(BN_num_bytes(value
.second
));
300 int len
= BN_bn2bin(value
.second
, reinterpret_cast<unsigned char*>(&tmp
.at(0)));
303 storvect
.push_back(make_pair(value
.first
, tmp
));
311 std::string
OpenSSLRSADNSCryptoKeyEngine::hash(const std::string
& orig
) const
313 if (d_algorithm
== DNSSECKeeper::RSASHA1
|| d_algorithm
== DNSSECKeeper::RSASHA1NSEC3SHA1
) {
314 unsigned char l_hash
[SHA_DIGEST_LENGTH
];
315 SHA1((unsigned char*) orig
.c_str(), orig
.length(), l_hash
);
316 return string((char*) l_hash
, sizeof(l_hash
));
318 else if (d_algorithm
== DNSSECKeeper::RSASHA256
) {
319 unsigned char l_hash
[SHA256_DIGEST_LENGTH
];
320 SHA256((unsigned char*) orig
.c_str(), orig
.length(), l_hash
);
321 return string((char*) l_hash
, sizeof(l_hash
));
323 else if (d_algorithm
== DNSSECKeeper::RSASHA512
) {
324 unsigned char l_hash
[SHA512_DIGEST_LENGTH
];
325 SHA512((unsigned char*) orig
.c_str(), orig
.length(), l_hash
);
326 return string((char*) l_hash
, sizeof(l_hash
));
329 throw runtime_error(getName()+" does not support hash operation for algorithm "+std::to_string(d_algorithm
));
332 int OpenSSLRSADNSCryptoKeyEngine::hashSizeToKind(const size_t hashSize
)
335 case SHA_DIGEST_LENGTH
:
337 case SHA256_DIGEST_LENGTH
:
339 case SHA384_DIGEST_LENGTH
:
341 case SHA512_DIGEST_LENGTH
:
344 throw runtime_error("OpenSSL RSA does not handle hash of size " + std::to_string(hashSize
));
348 std::string
OpenSSLRSADNSCryptoKeyEngine::sign(const std::string
& msg
) const
350 string l_hash
= this->hash(msg
);
351 int hashKind
= hashSizeToKind(l_hash
.size());
352 std::string signature
;
353 signature
.resize(RSA_size(d_key
.get()));
354 unsigned int signatureLen
= 0;
356 int res
= RSA_sign(hashKind
, reinterpret_cast<unsigned char*>(&l_hash
.at(0)), l_hash
.length(), reinterpret_cast<unsigned char*>(&signature
.at(0)), &signatureLen
, d_key
.get());
358 throw runtime_error(getName()+" failed to generate signature");
361 signature
.resize(signatureLen
);
366 bool OpenSSLRSADNSCryptoKeyEngine::verify(const std::string
& msg
, const std::string
& signature
) const
368 string l_hash
= this->hash(msg
);
369 int hashKind
= hashSizeToKind(l_hash
.size());
371 int ret
= RSA_verify(hashKind
, (const unsigned char*)l_hash
.c_str(), l_hash
.length(), (unsigned char*)signature
.c_str(), signature
.length(), d_key
.get());
377 std::string
OpenSSLRSADNSCryptoKeyEngine::getPubKeyHash() const
379 const BIGNUM
*n
, *e
, *d
;
380 RSA_get0_key(d_key
.get(), &n
, &e
, &d
);
381 std::vector
<unsigned char> tmp
;
382 tmp
.resize(std::max(BN_num_bytes(e
), BN_num_bytes(n
)));
383 unsigned char l_hash
[SHA_DIGEST_LENGTH
];
386 int res
= SHA1_Init(&ctx
);
389 throw runtime_error(getName()+" failed to init hash context for generating the public key hash");
392 int len
= BN_bn2bin(e
, tmp
.data());
393 res
= SHA1_Update(&ctx
, tmp
.data(), len
);
395 throw runtime_error(getName()+" failed to update hash context for generating the public key hash");
398 len
= BN_bn2bin(n
, tmp
.data());
399 res
= SHA1_Update(&ctx
, tmp
.data(), len
);
401 throw runtime_error(getName()+" failed to update hash context for generating the public key hash");
404 res
= SHA1_Final(l_hash
, &ctx
);
406 throw runtime_error(getName()+" failed to finish hash context for generating the public key hash");
409 return string((char*)l_hash
, sizeof(l_hash
));
413 std::string
OpenSSLRSADNSCryptoKeyEngine::getPublicKeyString() const
415 const BIGNUM
*n
, *e
, *d
;
416 RSA_get0_key(d_key
.get(), &n
, &e
, &d
);
419 tmp
.resize(std::max(BN_num_bytes(e
), BN_num_bytes(n
)));
421 int len
= BN_bn2bin(e
, reinterpret_cast<unsigned char*>(&tmp
.at(0)));
423 keystring
.assign(1, (char) (unsigned int) len
);
425 keystring
.assign(1, 0);
426 uint16_t tempLen
= len
;
427 tempLen
= htons(tempLen
);
428 keystring
.append((char*)&tempLen
, 2);
430 keystring
.append(&tmp
.at(0), len
);
432 len
= BN_bn2bin(n
, reinterpret_cast<unsigned char*>(&tmp
.at(0)));
433 keystring
.append(&tmp
.at(0), len
);
439 void OpenSSLRSADNSCryptoKeyEngine::fromISCMap(DNSKEYRecordContent
& drc
, std::map
<std::string
, std::string
>& stormap
)
441 typedef map
<string
, BIGNUM
**> places_t
;
443 auto key
= std::unique_ptr
<RSA
, void(*)(RSA
*)>(RSA_new(), RSA_free
);
445 throw runtime_error(getName()+" allocation of key structure failed");
448 BIGNUM
*n
, *e
, *d
, *p
, *q
, *dmp1
, *dmq1
, *iqmp
;
451 throw runtime_error(getName()+" allocation of BIGNUM n failed");
456 throw runtime_error(getName()+" allocation of BIGNUM e failed");
462 throw runtime_error(getName()+" allocation of BIGNUM d failed");
464 RSA_set0_key(key
.get(), n
, e
, d
);
468 throw runtime_error(getName()+" allocation of BIGNUM p failed");
473 throw runtime_error(getName()+" allocation of BIGNUM q failed");
475 RSA_set0_factors(key
.get(), p
, q
);
478 if (dmp1
== nullptr) {
479 throw runtime_error(getName()+" allocation of BIGNUM dmp1 failed");
482 if (dmq1
== nullptr) {
484 throw runtime_error(getName()+" allocation of BIGNUM dmq1 failed");
487 if (iqmp
== nullptr) {
490 throw runtime_error(getName()+" allocation of BIGNUM iqmp failed");
492 RSA_set0_crt_params(key
.get(), dmp1
, dmq1
, iqmp
);
494 places
["Modulus"]=&n
;
495 places
["PublicExponent"]=&e
;
496 places
["PrivateExponent"]=&d
;
499 places
["Exponent1"]=&dmp1
;
500 places
["Exponent2"]=&dmq1
;
501 places
["Coefficient"]=&iqmp
;
503 drc
.d_algorithm
= pdns_stou(stormap
["algorithm"]);
506 for(const places_t::value_type
& val
: places
) {
507 raw
=stormap
[toLower(val
.first
)];
512 *val
.second
= BN_bin2bn((unsigned char*) raw
.c_str(), raw
.length(), *val
.second
);
514 throw runtime_error(getName()+" error loading " + val
.first
);
518 if (drc
.d_algorithm
!= d_algorithm
) {
519 throw runtime_error(getName()+" tried to feed an algorithm "+std::to_string(drc
.d_algorithm
)+" to a "+std::to_string(d_algorithm
)+" key");
522 d_key
= std::move(key
);
525 bool OpenSSLRSADNSCryptoKeyEngine::checkKey(vector
<string
> *errorMessages
) const
528 // When changing the bitsizes, also edit them in ::create
529 if ((d_algorithm
== DNSSECKeeper::RSASHA1
|| d_algorithm
== DNSSECKeeper::RSASHA1NSEC3SHA1
|| d_algorithm
== DNSSECKeeper::RSASHA256
) && (getBits() < 512 || getBits()> 4096)) {
531 if (errorMessages
!= nullptr) {
532 errorMessages
->push_back("key is " + std::to_string(getBits()) + " bytes, should be between 512 and 4096");
535 if (d_algorithm
== DNSSECKeeper::RSASHA512
&& (getBits() < 1024 || getBits() > 4096)) {
537 if (errorMessages
!= nullptr) {
538 errorMessages
->push_back("key is " + std::to_string(getBits()) + " bytes, should be between 1024 and 4096");
541 if (RSA_check_key(d_key
.get()) != 1) {
543 if (errorMessages
!= nullptr) {
544 errorMessages
->push_back(ERR_reason_error_string(ERR_get_error()));
550 void OpenSSLRSADNSCryptoKeyEngine::fromPublicKeyString(const std::string
& input
)
552 string exponent
, modulus
;
553 const size_t inputLen
= input
.length();
554 const unsigned char* raw
= (const unsigned char*)input
.c_str();
557 throw runtime_error(getName()+" invalid input size for the public key");
561 const size_t exponentSize
= raw
[0];
562 if (inputLen
< (exponentSize
+ 2)) {
563 throw runtime_error(getName()+" invalid input size for the public key");
565 exponent
= input
.substr(1, exponentSize
);
566 modulus
= input
.substr(exponentSize
+ 1);
569 throw runtime_error(getName()+" invalid input size for the public key");
571 const size_t exponentSize
= raw
[1]*0xff + raw
[2];
572 if (inputLen
< (exponentSize
+ 4)) {
573 throw runtime_error(getName()+" invalid input size for the public key");
575 exponent
= input
.substr(3, exponentSize
);
576 modulus
= input
.substr(exponentSize
+ 3);
579 auto key
= std::unique_ptr
<RSA
, void(*)(RSA
*)>(RSA_new(), RSA_free
);
581 throw runtime_error(getName()+" allocation of key structure failed");
584 auto e
= std::unique_ptr
<BIGNUM
, void(*)(BIGNUM
*)>(BN_bin2bn((unsigned char*)exponent
.c_str(), exponent
.length(), nullptr), BN_clear_free
);
586 throw runtime_error(getName()+" error loading e value of public key");
588 auto n
= std::unique_ptr
<BIGNUM
, void(*)(BIGNUM
*)>(BN_bin2bn((unsigned char*)modulus
.c_str(), modulus
.length(), nullptr), BN_clear_free
);
590 throw runtime_error(getName()+" error loading n value of public key");
593 RSA_set0_key(key
.get(), n
.release(), e
.release(), nullptr);
594 d_key
= std::move(key
);
597 #ifdef HAVE_LIBCRYPTO_ECDSA
598 class OpenSSLECDSADNSCryptoKeyEngine
: public DNSCryptoKeyEngine
601 explicit OpenSSLECDSADNSCryptoKeyEngine(unsigned int algo
) : DNSCryptoKeyEngine(algo
), d_eckey(std::unique_ptr
<EC_KEY
, void(*)(EC_KEY
*)>(EC_KEY_new(), EC_KEY_free
)), d_ecgroup(std::unique_ptr
<EC_GROUP
, void(*)(EC_GROUP
*)>(nullptr, EC_GROUP_clear_free
))
604 int ret
= RAND_status();
606 throw runtime_error(getName()+" insufficient entropy");
610 throw runtime_error(getName()+" allocation of key structure failed");
613 if(d_algorithm
== 13) {
614 d_ecgroup
= std::unique_ptr
<EC_GROUP
, void(*)(EC_GROUP
*)>(EC_GROUP_new_by_curve_name(NID_X9_62_prime256v1
), EC_GROUP_clear_free
);
616 } else if (d_algorithm
== 14) {
617 d_ecgroup
= std::unique_ptr
<EC_GROUP
, void(*)(EC_GROUP
*)>(EC_GROUP_new_by_curve_name(NID_secp384r1
), EC_GROUP_clear_free
);
620 throw runtime_error(getName()+" unknown algorithm "+std::to_string(d_algorithm
));
624 throw runtime_error(getName()+" allocation of group structure failed");
627 ret
= EC_KEY_set_group(d_eckey
.get(), d_ecgroup
.get());
629 throw runtime_error(getName()+" setting key group failed");
633 ~OpenSSLECDSADNSCryptoKeyEngine()
637 string
getName() const override
{ return "OpenSSL ECDSA"; }
638 int getBits() const override
{ return d_len
<< 3; }
640 void create(unsigned int bits
) override
;
641 storvector_t
convertToISCVector() const override
;
642 std::string
hash(const std::string
& hash
) const override
;
643 std::string
sign(const std::string
& hash
) const override
;
644 bool verify(const std::string
& hash
, const std::string
& signature
) const override
;
645 std::string
getPubKeyHash() const override
;
646 std::string
getPublicKeyString() const override
;
647 void fromISCMap(DNSKEYRecordContent
& drc
, std::map
<std::string
, std::string
>& stormap
) override
;
648 void fromPublicKeyString(const std::string
& content
) override
;
649 bool checkKey(vector
<string
> *errorMessages
) const override
;
651 static std::shared_ptr
<DNSCryptoKeyEngine
> maker(unsigned int algorithm
)
653 return std::make_shared
<OpenSSLECDSADNSCryptoKeyEngine
>(algorithm
);
659 std::unique_ptr
<EC_KEY
, void(*)(EC_KEY
*)> d_eckey
;
660 std::unique_ptr
<EC_GROUP
, void(*)(EC_GROUP
*)> d_ecgroup
;
664 void OpenSSLECDSADNSCryptoKeyEngine::create(unsigned int bits
)
666 if (bits
>> 3 != d_len
) {
667 throw runtime_error(getName()+" unknown key length of "+std::to_string(bits
)+" bits requested");
670 int res
= EC_KEY_generate_key(d_eckey
.get());
672 throw runtime_error(getName()+" key generation failed");
677 DNSCryptoKeyEngine::storvector_t
OpenSSLECDSADNSCryptoKeyEngine::convertToISCVector() const
679 storvector_t storvect
;
682 if(d_algorithm
== 13)
683 algorithm
= "13 (ECDSAP256SHA256)";
684 else if(d_algorithm
== 14)
685 algorithm
= "14 (ECDSAP384SHA384)";
687 algorithm
= " ? (?)";
689 storvect
.push_back(make_pair("Algorithm", algorithm
));
691 const BIGNUM
*key
= EC_KEY_get0_private_key(d_eckey
.get());
692 if (key
== nullptr) {
693 throw runtime_error(getName()+" private key not set");
697 tmp
.resize(BN_num_bytes(key
));
698 int len
= BN_bn2bin(key
, reinterpret_cast<unsigned char*>(&tmp
.at(0)));
702 prefix
.append(d_len
- len
, 0x00);
704 storvect
.push_back(make_pair("PrivateKey", prefix
+ tmp
));
710 std::string
OpenSSLECDSADNSCryptoKeyEngine::hash(const std::string
& orig
) const
712 if(getBits() == 256) {
713 unsigned char l_hash
[SHA256_DIGEST_LENGTH
];
714 SHA256((unsigned char*) orig
.c_str(), orig
.length(), l_hash
);
715 return string((char*)l_hash
, sizeof(l_hash
));
717 else if(getBits() == 384) {
718 unsigned char l_hash
[SHA384_DIGEST_LENGTH
];
719 SHA384((unsigned char*) orig
.c_str(), orig
.length(), l_hash
);
720 return string((char*)l_hash
, sizeof(l_hash
));
723 throw runtime_error(getName()+" does not support a hash size of "+std::to_string(getBits())+" bits");
727 std::string
OpenSSLECDSADNSCryptoKeyEngine::sign(const std::string
& msg
) const
729 string l_hash
= this->hash(msg
);
731 auto signature
= std::unique_ptr
<ECDSA_SIG
, void(*)(ECDSA_SIG
*)>(ECDSA_do_sign((unsigned char*) l_hash
.c_str(), l_hash
.length(), d_eckey
.get()), ECDSA_SIG_free
);
733 throw runtime_error(getName()+" failed to generate signature");
740 const BIGNUM
*pr
, *ps
;
741 ECDSA_SIG_get0(signature
.get(), &pr
, &ps
);
742 int len
= BN_bn2bin(pr
, reinterpret_cast<unsigned char*>(&tmp
.at(0)));
744 ret
.append(d_len
- len
, 0x00);
745 ret
.append(&tmp
.at(0), len
);
747 len
= BN_bn2bin(ps
, reinterpret_cast<unsigned char*>(&tmp
.at(0)));
749 ret
.append(d_len
- len
, 0x00);
750 ret
.append(&tmp
.at(0), len
);
756 bool OpenSSLECDSADNSCryptoKeyEngine::verify(const std::string
& msg
, const std::string
& signature
) const
758 if (signature
.length() != (d_len
* 2)) {
759 throw runtime_error(getName()+" invalid signature size "+std::to_string(signature
.length()));
762 string l_hash
= this->hash(msg
);
764 auto sig
= std::unique_ptr
<ECDSA_SIG
, void(*)(ECDSA_SIG
*)>(ECDSA_SIG_new(), ECDSA_SIG_free
);
766 throw runtime_error(getName()+" allocation of signature structure failed");
769 auto r
= std::unique_ptr
<BIGNUM
, void(*)(BIGNUM
*)>(BN_bin2bn((unsigned char*) signature
.c_str(), d_len
, nullptr), BN_clear_free
);
770 auto s
= std::unique_ptr
<BIGNUM
, void(*)(BIGNUM
*)>(BN_bin2bn((unsigned char*) signature
.c_str() + d_len
, d_len
, nullptr), BN_clear_free
);
772 throw runtime_error(getName()+" invalid signature");
775 ECDSA_SIG_set0(sig
.get(), r
.release(), s
.release());
776 int ret
= ECDSA_do_verify((unsigned char*) l_hash
.c_str(), l_hash
.length(), sig
.get(), d_eckey
.get());
779 throw runtime_error(getName()+" verify error");
786 std::string
OpenSSLECDSADNSCryptoKeyEngine::getPubKeyHash() const
788 string pubKey
= getPublicKeyString();
789 unsigned char l_hash
[SHA_DIGEST_LENGTH
];
790 SHA1((unsigned char*) pubKey
.c_str(), pubKey
.length(), l_hash
);
791 return string((char*) l_hash
, sizeof(l_hash
));
795 std::string
OpenSSLECDSADNSCryptoKeyEngine::getPublicKeyString() const
797 std::string binaryPoint
;
798 binaryPoint
.resize((d_len
* 2) + 1);
800 int ret
= EC_POINT_point2oct(d_ecgroup
.get(), EC_KEY_get0_public_key(d_eckey
.get()), POINT_CONVERSION_UNCOMPRESSED
, reinterpret_cast<unsigned char*>(&binaryPoint
.at(0)), binaryPoint
.size(), nullptr);
802 throw runtime_error(getName()+" exporting point to binary failed");
805 /* we skip the first byte as the other backends use
806 raw field elements, as opposed to the format described in
807 SEC1: "2.3.3 Elliptic-Curve-Point-to-Octet-String Conversion" */
808 binaryPoint
.erase(0, 1);
813 void OpenSSLECDSADNSCryptoKeyEngine::fromISCMap(DNSKEYRecordContent
& drc
, std::map
<std::string
, std::string
>& stormap
)
815 drc
.d_algorithm
= atoi(stormap
["algorithm"].c_str());
817 if (drc
.d_algorithm
!= d_algorithm
) {
818 throw runtime_error(getName()+" tried to feed an algorithm "+std::to_string(drc
.d_algorithm
)+" to a "+std::to_string(d_algorithm
)+" key");
821 string privateKey
= stormap
["privatekey"];
823 auto prv_key
= std::unique_ptr
<BIGNUM
, void(*)(BIGNUM
*)>(BN_bin2bn((unsigned char*) privateKey
.c_str(), privateKey
.length(), nullptr), BN_clear_free
);
825 throw runtime_error(getName()+" reading private key from binary failed");
828 int ret
= EC_KEY_set_private_key(d_eckey
.get(), prv_key
.get());
830 throw runtime_error(getName()+" setting private key failed");
833 auto pub_key
= std::unique_ptr
<EC_POINT
, void(*)(EC_POINT
*)>(EC_POINT_new(d_ecgroup
.get()), EC_POINT_free
);
835 throw runtime_error(getName()+" allocation of public key point failed");
838 ret
= EC_POINT_mul(d_ecgroup
.get(), pub_key
.get(), prv_key
.get(), nullptr, nullptr, nullptr);
840 throw runtime_error(getName()+" computing public key from private failed");
843 ret
= EC_KEY_set_public_key(d_eckey
.get(), pub_key
.get());
845 throw runtime_error(getName()+" setting public key failed");
849 bool OpenSSLECDSADNSCryptoKeyEngine::checkKey(vector
<string
> *errorMessages
) const
852 if (EC_KEY_check_key(d_eckey
.get()) != 1) {
854 if (errorMessages
!= nullptr) {
855 errorMessages
->push_back(ERR_reason_error_string(ERR_get_error()));
861 void OpenSSLECDSADNSCryptoKeyEngine::fromPublicKeyString(const std::string
& input
)
863 /* uncompressed point, from SEC1:
864 "2.3.4 Octet-String-to-Elliptic-Curve-Point Conversion" */
865 string ecdsaPoint
= "\x04";
866 ecdsaPoint
.append(input
);
868 auto pub_key
= std::unique_ptr
<EC_POINT
, void(*)(EC_POINT
*)>(EC_POINT_new(d_ecgroup
.get()), EC_POINT_free
);
870 throw runtime_error(getName()+" allocation of point structure failed");
873 int ret
= EC_POINT_oct2point(d_ecgroup
.get(), pub_key
.get(), (unsigned char*) ecdsaPoint
.c_str(), ecdsaPoint
.length(), nullptr);
875 throw runtime_error(getName()+" reading ECP point from binary failed");
878 ret
= EC_KEY_set_private_key(d_eckey
.get(), nullptr);
880 throw runtime_error(getName()+" setting private key failed");
883 ret
= EC_KEY_set_public_key(d_eckey
.get(), pub_key
.get());
885 throw runtime_error(getName()+" setting public key failed");
890 #ifdef HAVE_LIBCRYPTO_EDDSA
891 class OpenSSLEDDSADNSCryptoKeyEngine
: public DNSCryptoKeyEngine
894 explicit OpenSSLEDDSADNSCryptoKeyEngine(unsigned int algo
) : DNSCryptoKeyEngine(algo
), d_edkey(std::unique_ptr
<EVP_PKEY
, void(*)(EVP_PKEY
*)>(nullptr, EVP_PKEY_free
))
897 int ret
= RAND_status();
899 throw runtime_error(getName()+" insufficient entropy");
902 #ifdef HAVE_LIBCRYPTO_ED25519
903 if(d_algorithm
== 15) {
908 #ifdef HAVE_LIBCRYPTO_ED448
909 if (d_algorithm
== 16) {
915 throw runtime_error(getName()+" unknown algorithm "+std::to_string(d_algorithm
));
919 ~OpenSSLEDDSADNSCryptoKeyEngine()
923 string
getName() const override
{ return "OpenSSL EDDSA"; }
924 int getBits() const override
{ return d_len
<< 3; }
926 void create(unsigned int bits
) override
;
927 storvector_t
convertToISCVector() const override
;
928 std::string
sign(const std::string
& msg
) const override
;
929 bool verify(const std::string
& msg
, const std::string
& signature
) const override
;
930 std::string
getPubKeyHash() const override
;
931 std::string
getPublicKeyString() const override
;
932 void fromISCMap(DNSKEYRecordContent
& drc
, std::map
<std::string
, std::string
>& stormap
) override
;
933 void fromPublicKeyString(const std::string
& content
) override
;
934 bool checkKey(vector
<string
> *errorMessages
) const override
;
936 static std::shared_ptr
<DNSCryptoKeyEngine
> maker(unsigned int algorithm
)
938 return std::make_shared
<OpenSSLEDDSADNSCryptoKeyEngine
>(algorithm
);
945 std::unique_ptr
<EVP_PKEY
, void(*)(EVP_PKEY
*)> d_edkey
;
948 bool OpenSSLEDDSADNSCryptoKeyEngine::checkKey(vector
<string
> *errorMessages
) const
950 return (d_edkey
? true : false);
953 void OpenSSLEDDSADNSCryptoKeyEngine::create(unsigned int bits
)
955 auto pctx
= std::unique_ptr
<EVP_PKEY_CTX
, void(*)(EVP_PKEY_CTX
*)>(EVP_PKEY_CTX_new_id(d_id
, nullptr), EVP_PKEY_CTX_free
);
957 throw runtime_error(getName()+" context initialization failed");
959 if (EVP_PKEY_keygen_init(pctx
.get()) < 1) {
960 throw runtime_error(getName()+" keygen initialization failed");
962 EVP_PKEY
* newKey
= nullptr;
963 if (EVP_PKEY_keygen(pctx
.get(), &newKey
) < 1) {
964 throw runtime_error(getName()+" key generation failed");
966 d_edkey
= std::unique_ptr
<EVP_PKEY
, void(*)(EVP_PKEY
*)>(newKey
, EVP_PKEY_free
);
969 DNSCryptoKeyEngine::storvector_t
OpenSSLEDDSADNSCryptoKeyEngine::convertToISCVector() const
971 storvector_t storvect
;
974 #ifdef HAVE_LIBCRYPTO_ED25519
975 if(d_algorithm
== 15) {
976 algorithm
= "15 (ED25519)";
979 #ifdef HAVE_LIBCRYPTO_ED448
980 if(d_algorithm
== 16) {
981 algorithm
= "16 (ED448)";
984 if (algorithm
.empty()) {
985 algorithm
= " ? (?)";
988 storvect
.push_back(make_pair("Algorithm", algorithm
));
993 if (EVP_PKEY_get_raw_private_key(d_edkey
.get(), reinterpret_cast<unsigned char*>(&buf
.at(0)), &len
) < 1) {
994 throw runtime_error(getName() + " Could not get private key from d_edkey");
996 storvect
.push_back(make_pair("PrivateKey", buf
));
1000 std::string
OpenSSLEDDSADNSCryptoKeyEngine::sign(const std::string
& msg
) const
1002 auto mdctx
= std::unique_ptr
<EVP_MD_CTX
, void(*)(EVP_MD_CTX
*)>(EVP_MD_CTX_new(), EVP_MD_CTX_free
);
1004 throw runtime_error(getName()+" MD context initialization failed");
1006 if(EVP_DigestSignInit(mdctx
.get(), nullptr, nullptr, nullptr, d_edkey
.get()) < 1) {
1007 throw runtime_error(getName()+" unable to initialize signer");
1010 string msgToSign
= msg
;
1012 size_t siglen
= d_len
* 2;
1014 signature
.resize(siglen
);
1016 if (EVP_DigestSign(mdctx
.get(),
1017 reinterpret_cast<unsigned char*>(&signature
.at(0)), &siglen
,
1018 reinterpret_cast<unsigned char*>(&msgToSign
.at(0)), msgToSign
.length()) < 1) {
1019 throw runtime_error(getName()+" signing error");
1025 bool OpenSSLEDDSADNSCryptoKeyEngine::verify(const std::string
& msg
, const std::string
& signature
) const
1027 auto mdctx
= std::unique_ptr
<EVP_MD_CTX
, void(*)(EVP_MD_CTX
*)>(EVP_MD_CTX_new(), EVP_MD_CTX_free
);
1029 throw runtime_error(getName()+" MD context initialization failed");
1031 if(EVP_DigestVerifyInit(mdctx
.get(), nullptr, nullptr, nullptr, d_edkey
.get()) < 1) {
1032 throw runtime_error(getName()+" unable to initialize signer");
1035 string checkSignature
= signature
;
1036 string checkMsg
= msg
;
1038 auto r
= EVP_DigestVerify(mdctx
.get(),
1039 reinterpret_cast<unsigned char*>(&checkSignature
.at(0)), checkSignature
.length(),
1040 reinterpret_cast<unsigned char*>(&checkMsg
.at(0)), checkMsg
.length());
1042 throw runtime_error(getName()+" verification failure");
1048 std::string
OpenSSLEDDSADNSCryptoKeyEngine::getPubKeyHash() const
1050 return this->getPublicKeyString();
1053 std::string
OpenSSLEDDSADNSCryptoKeyEngine::getPublicKeyString() const
1058 if (EVP_PKEY_get_raw_public_key(d_edkey
.get(), reinterpret_cast<unsigned char*>(&buf
.at(0)), &len
) < 1) {
1059 throw std::runtime_error(getName() + " unable to get public key from key struct");
1064 void OpenSSLEDDSADNSCryptoKeyEngine::fromISCMap(DNSKEYRecordContent
& drc
, std::map
<std::string
, std::string
>& stormap
) {
1065 drc
.d_algorithm
= atoi(stormap
["algorithm"].c_str());
1066 if (drc
.d_algorithm
!= d_algorithm
) {
1067 throw runtime_error(getName()+" tried to feed an algorithm "+std::to_string(drc
.d_algorithm
)+" to a "+std::to_string(d_algorithm
)+" key");
1070 d_edkey
= std::unique_ptr
<EVP_PKEY
, void(*)(EVP_PKEY
*)>(EVP_PKEY_new_raw_private_key(d_id
, nullptr, reinterpret_cast<unsigned char*>(&stormap
["privatekey"].at(0)), stormap
["privatekey"].length()), EVP_PKEY_free
);
1072 throw std::runtime_error(getName() + " could not create key structure from private key");
1076 void OpenSSLEDDSADNSCryptoKeyEngine::fromPublicKeyString(const std::string
& content
)
1078 if (content
.length() != d_len
) {
1079 throw runtime_error(getName() + " wrong public key length for algorithm " + std::to_string(d_algorithm
));
1082 const unsigned char* raw
= reinterpret_cast<const unsigned char*>(content
.c_str());
1084 d_edkey
= std::unique_ptr
<EVP_PKEY
, void(*)(EVP_PKEY
*)>(EVP_PKEY_new_raw_public_key(d_id
, nullptr, raw
, d_len
), EVP_PKEY_free
);
1086 throw runtime_error(getName()+" allocation of public key structure failed");
1089 #endif // HAVE_LIBCRYPTO_EDDSA
1096 DNSCryptoKeyEngine::report(5, &OpenSSLRSADNSCryptoKeyEngine::maker
);
1097 DNSCryptoKeyEngine::report(7, &OpenSSLRSADNSCryptoKeyEngine::maker
);
1098 DNSCryptoKeyEngine::report(8, &OpenSSLRSADNSCryptoKeyEngine::maker
);
1099 DNSCryptoKeyEngine::report(10, &OpenSSLRSADNSCryptoKeyEngine::maker
);
1100 #ifdef HAVE_LIBCRYPTO_ECDSA
1101 DNSCryptoKeyEngine::report(13, &OpenSSLECDSADNSCryptoKeyEngine::maker
);
1102 DNSCryptoKeyEngine::report(14, &OpenSSLECDSADNSCryptoKeyEngine::maker
);
1104 #ifdef HAVE_LIBCRYPTO_ED25519
1105 DNSCryptoKeyEngine::report(15, &OpenSSLEDDSADNSCryptoKeyEngine::maker
);
1107 #ifdef HAVE_LIBCRYPTO_ED448
1108 DNSCryptoKeyEngine::report(16, &OpenSSLEDDSADNSCryptoKeyEngine::maker
);