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/sha.h>
33 #include <openssl/rand.h>
34 #include <openssl/rsa.h>
35 #include <openssl/opensslv.h>
36 #include <openssl/err.h>
37 #include "opensslsigners.hh"
38 #include "dnssecinfra.hh"
39 #include "dnsseckeeper.hh"
41 #if (OPENSSL_VERSION_NUMBER < 0x1010000fL || defined LIBRESSL_VERSION_NUMBER)
42 /* OpenSSL < 1.1.0 needs support for threading/locking in the calling application. */
43 static pthread_mutex_t
*openssllocks
;
46 void openssl_pthreads_locking_callback(int mode
, int type
, const char *file
, int line
)
48 if (mode
& CRYPTO_LOCK
) {
49 pthread_mutex_lock(&(openssllocks
[type
]));
52 pthread_mutex_unlock(&(openssllocks
[type
]));
56 unsigned long openssl_pthreads_id_callback()
58 return (unsigned long)pthread_self();
62 void openssl_thread_setup()
64 openssllocks
= (pthread_mutex_t
*)OPENSSL_malloc(CRYPTO_num_locks() * sizeof(pthread_mutex_t
));
66 for (int i
= 0; i
< CRYPTO_num_locks(); i
++)
67 pthread_mutex_init(&(openssllocks
[i
]), NULL
);
69 CRYPTO_set_id_callback(openssl_pthreads_id_callback
);
70 CRYPTO_set_locking_callback(openssl_pthreads_locking_callback
);
73 void openssl_thread_cleanup()
75 CRYPTO_set_locking_callback(NULL
);
77 for (int i
=0; i
<CRYPTO_num_locks(); i
++) {
78 pthread_mutex_destroy(&(openssllocks
[i
]));
81 OPENSSL_free(openssllocks
);
84 #if !defined(LIBRESSL_VERSION_NUMBER) || LIBRESSL_VERSION_NUMBER < 0x2070000fL
85 /* those symbols are defined in LibreSSL 2.7.0+ */
86 /* compat helpers. These DO NOT do any of the checking that the libssl 1.1 functions do. */
87 static inline void RSA_get0_key(const RSA
* rsakey
, const BIGNUM
** n
, const BIGNUM
** e
, const BIGNUM
** d
) {
93 static inline int RSA_set0_key(RSA
* rsakey
, BIGNUM
* n
, BIGNUM
* e
, BIGNUM
* d
) {
95 BN_clear_free(rsakey
->n
);
99 BN_clear_free(rsakey
->e
);
103 BN_clear_free(rsakey
->d
);
109 static inline void RSA_get0_factors(const RSA
* rsakey
, const BIGNUM
** p
, const BIGNUM
** q
) {
114 static inline int RSA_set0_factors(RSA
* rsakey
, BIGNUM
* p
, BIGNUM
* q
) {
115 BN_clear_free(rsakey
->p
);
117 BN_clear_free(rsakey
->q
);
122 static inline void RSA_get0_crt_params(const RSA
* rsakey
, const BIGNUM
** dmp1
, const BIGNUM
** dmq1
, const BIGNUM
** iqmp
) {
123 *dmp1
= rsakey
->dmp1
;
124 *dmq1
= rsakey
->dmq1
;
125 *iqmp
= rsakey
->iqmp
;
128 static inline int RSA_set0_crt_params(RSA
* rsakey
, BIGNUM
* dmp1
, BIGNUM
* dmq1
, BIGNUM
* iqmp
) {
129 BN_clear_free(rsakey
->dmp1
);
131 BN_clear_free(rsakey
->dmq1
);
133 BN_clear_free(rsakey
->iqmp
);
138 #ifdef HAVE_LIBCRYPTO_ECDSA
139 static inline void ECDSA_SIG_get0(const ECDSA_SIG
* signature
, const BIGNUM
** pr
, const BIGNUM
** ps
) {
144 static inline int ECDSA_SIG_set0(ECDSA_SIG
* signature
, BIGNUM
* pr
, BIGNUM
* ps
) {
145 BN_clear_free(signature
->r
);
146 BN_clear_free(signature
->s
);
151 #endif /* HAVE_LIBCRYPTO_ECDSA */
153 #endif /* !defined(LIBRESSL_VERSION_NUMBER) || LIBRESSL_VERSION_NUMBER < 0x2070000fL */
156 void openssl_thread_setup() {}
157 void openssl_thread_cleanup() {}
166 entropy
.reserve(1024);
169 for(int i
=0; i
<1024; i
+=4) {
170 r
=dns_random(0xffffffff);
171 entropy
.append((const char*)&r
, 4);
174 RAND_seed((const unsigned char*)entropy
.c_str(), 1024);
178 class OpenSSLRSADNSCryptoKeyEngine
: public DNSCryptoKeyEngine
181 explicit OpenSSLRSADNSCryptoKeyEngine(unsigned int algo
): DNSCryptoKeyEngine(algo
), d_key(std::unique_ptr
<RSA
, void(*)(RSA
*)>(nullptr, RSA_free
))
183 int ret
= RAND_status();
185 throw runtime_error(getName()+" insufficient entropy");
189 ~OpenSSLRSADNSCryptoKeyEngine()
193 string
getName() const override
{ return "OpenSSL RSA"; }
194 int getBits() const override
{ return RSA_size(d_key
.get()) << 3; }
196 void create(unsigned int bits
) override
;
197 storvector_t
convertToISCVector() const override
;
198 std::string
hash(const std::string
& hash
) const override
;
199 std::string
sign(const std::string
& hash
) const override
;
200 bool verify(const std::string
& hash
, const std::string
& signature
) const override
;
201 std::string
getPubKeyHash() const override
;
202 std::string
getPublicKeyString() const override
;
203 void fromISCMap(DNSKEYRecordContent
& drc
, std::map
<std::string
, std::string
>& stormap
) override
;
204 void fromPublicKeyString(const std::string
& content
) override
;
205 bool checkKey(vector
<string
> *errorMessages
) const override
;
207 static std::shared_ptr
<DNSCryptoKeyEngine
> maker(unsigned int algorithm
)
209 return std::make_shared
<OpenSSLRSADNSCryptoKeyEngine
>(algorithm
);
213 static int hashSizeToKind(size_t hashSize
);
215 std::unique_ptr
<RSA
, void(*)(RSA
*)> d_key
;
219 void OpenSSLRSADNSCryptoKeyEngine::create(unsigned int bits
)
221 // When changing the bitsizes, also edit them in ::checkKey
222 if ((d_algorithm
== DNSSECKeeper::RSASHA1
|| d_algorithm
== DNSSECKeeper::RSASHA1NSEC3SHA1
) && (bits
< 512 || bits
> 4096)) {
224 throw runtime_error(getName()+" RSASHA1 key generation failed for invalid bits size " + std::to_string(bits
));
226 if (d_algorithm
== DNSSECKeeper::RSASHA256
&& (bits
< 512 || bits
> 4096)) {
228 throw runtime_error(getName()+" RSASHA256 key generation failed for invalid bits size " + std::to_string(bits
));
230 if (d_algorithm
== DNSSECKeeper::RSASHA512
&& (bits
< 1024 || bits
> 4096)) {
232 throw runtime_error(getName()+" RSASHA512 key generation failed for invalid bits size " + std::to_string(bits
));
235 auto e
= std::unique_ptr
<BIGNUM
, void(*)(BIGNUM
*)>(BN_new(), BN_clear_free
);
237 throw runtime_error(getName()+" key generation failed, unable to allocate e");
240 /* RSA_F4 is a public exponent value of 65537 */
241 int res
= BN_set_word(e
.get(), RSA_F4
);
244 throw runtime_error(getName()+" key generation failed while setting e");
247 auto key
= std::unique_ptr
<RSA
, void(*)(RSA
*)>(RSA_new(), RSA_free
);
249 throw runtime_error(getName()+" allocation of key structure failed");
252 res
= RSA_generate_key_ex(key
.get(), bits
, e
.get(), nullptr);
254 throw runtime_error(getName()+" key generation failed");
257 d_key
= std::move(key
);
261 DNSCryptoKeyEngine::storvector_t
OpenSSLRSADNSCryptoKeyEngine::convertToISCVector() const
263 storvector_t storvect
;
264 typedef vector
<pair
<string
, const BIGNUM
*> > outputs_t
;
266 const BIGNUM
*n
, *e
, *d
, *p
, *q
, *dmp1
, *dmq1
, *iqmp
;
267 RSA_get0_key(d_key
.get(), &n
, &e
, &d
);
268 RSA_get0_factors(d_key
.get(), &p
, &q
);
269 RSA_get0_crt_params(d_key
.get(), &dmp1
, &dmq1
, &iqmp
);
270 outputs
.push_back(make_pair("Modulus", n
));
271 outputs
.push_back(make_pair("PublicExponent", e
));
272 outputs
.push_back(make_pair("PrivateExponent", d
));
273 outputs
.push_back(make_pair("Prime1", p
));
274 outputs
.push_back(make_pair("Prime2", q
));
275 outputs
.push_back(make_pair("Exponent1", dmp1
));
276 outputs
.push_back(make_pair("Exponent2", dmq1
));
277 outputs
.push_back(make_pair("Coefficient", iqmp
));
279 string algorithm
=std::to_string(d_algorithm
);
280 switch(d_algorithm
) {
281 case DNSSECKeeper::RSASHA1
:
282 case DNSSECKeeper::RSASHA1NSEC3SHA1
:
283 algorithm
+= " (RSASHA1)";
285 case DNSSECKeeper::RSASHA256
:
286 algorithm
+= " (RSASHA256)";
288 case DNSSECKeeper::RSASHA512
:
289 algorithm
+= " (RSASHA512)";
294 storvect
.push_back(make_pair("Algorithm", algorithm
));
296 for(outputs_t::value_type value
: outputs
) {
298 tmp
.resize(BN_num_bytes(value
.second
));
299 int len
= BN_bn2bin(value
.second
, reinterpret_cast<unsigned char*>(&tmp
.at(0)));
302 storvect
.push_back(make_pair(value
.first
, tmp
));
310 std::string
OpenSSLRSADNSCryptoKeyEngine::hash(const std::string
& orig
) const
312 if (d_algorithm
== DNSSECKeeper::RSASHA1
|| d_algorithm
== DNSSECKeeper::RSASHA1NSEC3SHA1
) {
313 unsigned char hash
[SHA_DIGEST_LENGTH
];
314 SHA1((unsigned char*) orig
.c_str(), orig
.length(), hash
);
315 return string((char*) hash
, sizeof(hash
));
317 else if (d_algorithm
== DNSSECKeeper::RSASHA256
) {
318 unsigned char hash
[SHA256_DIGEST_LENGTH
];
319 SHA256((unsigned char*) orig
.c_str(), orig
.length(), hash
);
320 return string((char*) hash
, sizeof(hash
));
322 else if (d_algorithm
== DNSSECKeeper::RSASHA512
) {
323 unsigned char hash
[SHA512_DIGEST_LENGTH
];
324 SHA512((unsigned char*) orig
.c_str(), orig
.length(), hash
);
325 return string((char*) hash
, sizeof(hash
));
328 throw runtime_error(getName()+" does not support hash operation for algorithm "+std::to_string(d_algorithm
));
331 int OpenSSLRSADNSCryptoKeyEngine::hashSizeToKind(const size_t hashSize
)
334 case SHA_DIGEST_LENGTH
:
336 case SHA256_DIGEST_LENGTH
:
338 case SHA384_DIGEST_LENGTH
:
340 case SHA512_DIGEST_LENGTH
:
343 throw runtime_error("OpenSSL RSA does not handle hash of size " + std::to_string(hashSize
));
347 std::string
OpenSSLRSADNSCryptoKeyEngine::sign(const std::string
& msg
) const
349 string hash
= this->hash(msg
);
350 int hashKind
= hashSizeToKind(hash
.size());
351 std::string signature
;
352 signature
.resize(RSA_size(d_key
.get()));
353 unsigned int signatureLen
= 0;
355 int res
= RSA_sign(hashKind
, reinterpret_cast<unsigned char*>(&hash
.at(0)), hash
.length(), reinterpret_cast<unsigned char*>(&signature
.at(0)), &signatureLen
, d_key
.get());
357 throw runtime_error(getName()+" failed to generate signature");
360 signature
.resize(signatureLen
);
365 bool OpenSSLRSADNSCryptoKeyEngine::verify(const std::string
& msg
, const std::string
& signature
) const
367 string hash
= this->hash(msg
);
368 int hashKind
= hashSizeToKind(hash
.size());
370 int ret
= RSA_verify(hashKind
, (const unsigned char*) hash
.c_str(), hash
.length(), (unsigned char*) signature
.c_str(), signature
.length(), d_key
.get());
376 std::string
OpenSSLRSADNSCryptoKeyEngine::getPubKeyHash() const
378 const BIGNUM
*n
, *e
, *d
;
379 RSA_get0_key(d_key
.get(), &n
, &e
, &d
);
380 std::vector
<unsigned char> tmp
;
381 tmp
.resize(std::max(BN_num_bytes(e
), BN_num_bytes(n
)));
382 unsigned char hash
[SHA_DIGEST_LENGTH
];
385 int res
= SHA1_Init(&ctx
);
388 throw runtime_error(getName()+" failed to init hash context for generating the public key hash");
391 int len
= BN_bn2bin(e
, 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 len
= BN_bn2bin(n
, tmp
.data());
398 res
= SHA1_Update(&ctx
, tmp
.data(), len
);
400 throw runtime_error(getName()+" failed to update hash context for generating the public key hash");
403 res
= SHA1_Final(hash
, &ctx
);
405 throw runtime_error(getName()+" failed to finish hash context for generating the public key hash");
408 return string((char*) hash
, sizeof(hash
));
412 std::string
OpenSSLRSADNSCryptoKeyEngine::getPublicKeyString() const
414 const BIGNUM
*n
, *e
, *d
;
415 RSA_get0_key(d_key
.get(), &n
, &e
, &d
);
418 tmp
.resize(std::max(BN_num_bytes(e
), BN_num_bytes(n
)));
420 int len
= BN_bn2bin(e
, reinterpret_cast<unsigned char*>(&tmp
.at(0)));
422 keystring
.assign(1, (char) (unsigned int) len
);
424 keystring
.assign(1, 0);
425 uint16_t tempLen
= len
;
426 tempLen
= htons(tempLen
);
427 keystring
.append((char*)&tempLen
, 2);
429 keystring
.append(&tmp
.at(0), len
);
431 len
= BN_bn2bin(n
, reinterpret_cast<unsigned char*>(&tmp
.at(0)));
432 keystring
.append(&tmp
.at(0), len
);
438 void OpenSSLRSADNSCryptoKeyEngine::fromISCMap(DNSKEYRecordContent
& drc
, std::map
<std::string
, std::string
>& stormap
)
440 typedef map
<string
, BIGNUM
**> places_t
;
442 auto key
= std::unique_ptr
<RSA
, void(*)(RSA
*)>(RSA_new(), RSA_free
);
444 throw runtime_error(getName()+" allocation of key structure failed");
447 BIGNUM
*n
, *e
, *d
, *p
, *q
, *dmp1
, *dmq1
, *iqmp
;
450 throw runtime_error(getName()+" allocation of BIGNUM n failed");
455 throw runtime_error(getName()+" allocation of BIGNUM e failed");
461 throw runtime_error(getName()+" allocation of BIGNUM d failed");
463 RSA_set0_key(key
.get(), n
, e
, d
);
467 throw runtime_error(getName()+" allocation of BIGNUM p failed");
472 throw runtime_error(getName()+" allocation of BIGNUM q failed");
474 RSA_set0_factors(key
.get(), p
, q
);
477 if (dmp1
== nullptr) {
478 throw runtime_error(getName()+" allocation of BIGNUM dmp1 failed");
481 if (dmq1
== nullptr) {
483 throw runtime_error(getName()+" allocation of BIGNUM dmq1 failed");
486 if (iqmp
== nullptr) {
489 throw runtime_error(getName()+" allocation of BIGNUM iqmp failed");
491 RSA_set0_crt_params(key
.get(), dmp1
, dmq1
, iqmp
);
493 places
["Modulus"]=&n
;
494 places
["PublicExponent"]=&e
;
495 places
["PrivateExponent"]=&d
;
498 places
["Exponent1"]=&dmp1
;
499 places
["Exponent2"]=&dmq1
;
500 places
["Coefficient"]=&iqmp
;
502 drc
.d_algorithm
= pdns_stou(stormap
["algorithm"]);
505 for(const places_t::value_type
& val
: places
) {
506 raw
=stormap
[toLower(val
.first
)];
511 *val
.second
= BN_bin2bn((unsigned char*) raw
.c_str(), raw
.length(), *val
.second
);
513 throw runtime_error(getName()+" error loading " + val
.first
);
517 if (drc
.d_algorithm
!= d_algorithm
) {
518 throw runtime_error(getName()+" tried to feed an algorithm "+std::to_string(drc
.d_algorithm
)+" to a "+std::to_string(d_algorithm
)+" key");
521 d_key
= std::move(key
);
524 bool OpenSSLRSADNSCryptoKeyEngine::checkKey(vector
<string
> *errorMessages
) const
527 // When changing the bitsizes, also edit them in ::create
528 if ((d_algorithm
== DNSSECKeeper::RSASHA1
|| d_algorithm
== DNSSECKeeper::RSASHA1NSEC3SHA1
|| d_algorithm
== DNSSECKeeper::RSASHA256
) && (getBits() < 512 || getBits()> 4096)) {
530 if (errorMessages
!= nullptr) {
531 errorMessages
->push_back("key is " + std::to_string(getBits()) + " bytes, should be between 512 and 4096");
534 if (d_algorithm
== DNSSECKeeper::RSASHA512
&& (getBits() < 1024 || getBits() > 4096)) {
536 if (errorMessages
!= nullptr) {
537 errorMessages
->push_back("key is " + std::to_string(getBits()) + " bytes, should be between 1024 and 4096");
540 if (RSA_check_key(d_key
.get()) != 1) {
542 if (errorMessages
!= nullptr) {
543 errorMessages
->push_back(ERR_reason_error_string(ERR_get_error()));
549 void OpenSSLRSADNSCryptoKeyEngine::fromPublicKeyString(const std::string
& input
)
551 string exponent
, modulus
;
552 const size_t inputLen
= input
.length();
553 const unsigned char* raw
= (const unsigned char*)input
.c_str();
556 throw runtime_error(getName()+" invalid input size for the public key");
560 const size_t exponentSize
= raw
[0];
561 if (inputLen
< (exponentSize
+ 2)) {
562 throw runtime_error(getName()+" invalid input size for the public key");
564 exponent
= input
.substr(1, exponentSize
);
565 modulus
= input
.substr(exponentSize
+ 1);
568 throw runtime_error(getName()+" invalid input size for the public key");
570 const size_t exponentSize
= raw
[1]*0xff + raw
[2];
571 if (inputLen
< (exponentSize
+ 4)) {
572 throw runtime_error(getName()+" invalid input size for the public key");
574 exponent
= input
.substr(3, exponentSize
);
575 modulus
= input
.substr(exponentSize
+ 3);
578 auto key
= std::unique_ptr
<RSA
, void(*)(RSA
*)>(RSA_new(), RSA_free
);
580 throw runtime_error(getName()+" allocation of key structure failed");
583 auto e
= std::unique_ptr
<BIGNUM
, void(*)(BIGNUM
*)>(BN_bin2bn((unsigned char*)exponent
.c_str(), exponent
.length(), nullptr), BN_clear_free
);
585 throw runtime_error(getName()+" error loading e value of public key");
587 auto n
= std::unique_ptr
<BIGNUM
, void(*)(BIGNUM
*)>(BN_bin2bn((unsigned char*)modulus
.c_str(), modulus
.length(), nullptr), BN_clear_free
);
589 throw runtime_error(getName()+" error loading n value of public key");
592 RSA_set0_key(key
.get(), n
.release(), e
.release(), nullptr);
593 d_key
= std::move(key
);
596 #ifdef HAVE_LIBCRYPTO_ECDSA
597 class OpenSSLECDSADNSCryptoKeyEngine
: public DNSCryptoKeyEngine
600 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
))
603 int ret
= RAND_status();
605 throw runtime_error(getName()+" insufficient entropy");
609 throw runtime_error(getName()+" allocation of key structure failed");
612 if(d_algorithm
== 13) {
613 d_ecgroup
= std::unique_ptr
<EC_GROUP
, void(*)(EC_GROUP
*)>(EC_GROUP_new_by_curve_name(NID_X9_62_prime256v1
), EC_GROUP_clear_free
);
615 } else if (d_algorithm
== 14) {
616 d_ecgroup
= std::unique_ptr
<EC_GROUP
, void(*)(EC_GROUP
*)>(EC_GROUP_new_by_curve_name(NID_secp384r1
), EC_GROUP_clear_free
);
619 throw runtime_error(getName()+" unknown algorithm "+std::to_string(d_algorithm
));
623 throw runtime_error(getName()+" allocation of group structure failed");
626 ret
= EC_KEY_set_group(d_eckey
.get(), d_ecgroup
.get());
628 throw runtime_error(getName()+" setting key group failed");
632 ~OpenSSLECDSADNSCryptoKeyEngine()
636 string
getName() const override
{ return "OpenSSL ECDSA"; }
637 int getBits() const override
{ return d_len
<< 3; }
639 void create(unsigned int bits
) override
;
640 storvector_t
convertToISCVector() const override
;
641 std::string
hash(const std::string
& hash
) const override
;
642 std::string
sign(const std::string
& hash
) const override
;
643 bool verify(const std::string
& hash
, const std::string
& signature
) const override
;
644 std::string
getPubKeyHash() const override
;
645 std::string
getPublicKeyString() const override
;
646 void fromISCMap(DNSKEYRecordContent
& drc
, std::map
<std::string
, std::string
>& stormap
) override
;
647 void fromPublicKeyString(const std::string
& content
) override
;
648 bool checkKey(vector
<string
> *errorMessages
) const override
;
650 static std::shared_ptr
<DNSCryptoKeyEngine
> maker(unsigned int algorithm
)
652 return std::make_shared
<OpenSSLECDSADNSCryptoKeyEngine
>(algorithm
);
658 std::unique_ptr
<EC_KEY
, void(*)(EC_KEY
*)> d_eckey
;
659 std::unique_ptr
<EC_GROUP
, void(*)(EC_GROUP
*)> d_ecgroup
;
663 void OpenSSLECDSADNSCryptoKeyEngine::create(unsigned int bits
)
665 if (bits
>> 3 != d_len
) {
666 throw runtime_error(getName()+" unknown key length of "+std::to_string(bits
)+" bits requested");
669 int res
= EC_KEY_generate_key(d_eckey
.get());
671 throw runtime_error(getName()+" key generation failed");
676 DNSCryptoKeyEngine::storvector_t
OpenSSLECDSADNSCryptoKeyEngine::convertToISCVector() const
678 storvector_t storvect
;
681 if(d_algorithm
== 13)
682 algorithm
= "13 (ECDSAP256SHA256)";
683 else if(d_algorithm
== 14)
684 algorithm
= "14 (ECDSAP384SHA384)";
686 algorithm
= " ? (?)";
688 storvect
.push_back(make_pair("Algorithm", algorithm
));
690 const BIGNUM
*key
= EC_KEY_get0_private_key(d_eckey
.get());
691 if (key
== nullptr) {
692 throw runtime_error(getName()+" private key not set");
696 tmp
.resize(BN_num_bytes(key
));
697 int len
= BN_bn2bin(key
, reinterpret_cast<unsigned char*>(&tmp
.at(0)));
701 prefix
.append(d_len
- len
, 0x00);
703 storvect
.push_back(make_pair("PrivateKey", prefix
+ tmp
));
709 std::string
OpenSSLECDSADNSCryptoKeyEngine::hash(const std::string
& orig
) const
711 if(getBits() == 256) {
712 unsigned char hash
[SHA256_DIGEST_LENGTH
];
713 SHA256((unsigned char*) orig
.c_str(), orig
.length(), hash
);
714 return string((char*) hash
, sizeof(hash
));
716 else if(getBits() == 384) {
717 unsigned char hash
[SHA384_DIGEST_LENGTH
];
718 SHA384((unsigned char*) orig
.c_str(), orig
.length(), hash
);
719 return string((char*) hash
, sizeof(hash
));
722 throw runtime_error(getName()+" does not support a hash size of "+std::to_string(getBits())+" bits");
726 std::string
OpenSSLECDSADNSCryptoKeyEngine::sign(const std::string
& msg
) const
728 string hash
= this->hash(msg
);
730 auto signature
= std::unique_ptr
<ECDSA_SIG
, void(*)(ECDSA_SIG
*)>(ECDSA_do_sign((unsigned char*) hash
.c_str(), hash
.length(), d_eckey
.get()), ECDSA_SIG_free
);
732 throw runtime_error(getName()+" failed to generate signature");
739 const BIGNUM
*pr
, *ps
;
740 ECDSA_SIG_get0(signature
.get(), &pr
, &ps
);
741 int len
= BN_bn2bin(pr
, reinterpret_cast<unsigned char*>(&tmp
.at(0)));
743 ret
.append(d_len
- len
, 0x00);
744 ret
.append(&tmp
.at(0), len
);
746 len
= BN_bn2bin(ps
, reinterpret_cast<unsigned char*>(&tmp
.at(0)));
748 ret
.append(d_len
- len
, 0x00);
749 ret
.append(&tmp
.at(0), len
);
755 bool OpenSSLECDSADNSCryptoKeyEngine::verify(const std::string
& msg
, const std::string
& signature
) const
757 if (signature
.length() != (d_len
* 2)) {
758 throw runtime_error(getName()+" invalid signature size "+std::to_string(signature
.length()));
761 string hash
= this->hash(msg
);
763 auto sig
= std::unique_ptr
<ECDSA_SIG
, void(*)(ECDSA_SIG
*)>(ECDSA_SIG_new(), ECDSA_SIG_free
);
765 throw runtime_error(getName()+" allocation of signature structure failed");
768 auto r
= std::unique_ptr
<BIGNUM
, void(*)(BIGNUM
*)>(BN_bin2bn((unsigned char*) signature
.c_str(), d_len
, nullptr), BN_clear_free
);
769 auto s
= std::unique_ptr
<BIGNUM
, void(*)(BIGNUM
*)>(BN_bin2bn((unsigned char*) signature
.c_str() + d_len
, d_len
, nullptr), BN_clear_free
);
771 throw runtime_error(getName()+" invalid signature");
774 ECDSA_SIG_set0(sig
.get(), r
.release(), s
.release());
775 int ret
= ECDSA_do_verify((unsigned char*) hash
.c_str(), hash
.length(), sig
.get(), d_eckey
.get());
778 throw runtime_error(getName()+" verify error");
785 std::string
OpenSSLECDSADNSCryptoKeyEngine::getPubKeyHash() const
787 string pubKey
= getPublicKeyString();
788 unsigned char hash
[SHA_DIGEST_LENGTH
];
789 SHA1((unsigned char*) pubKey
.c_str(), pubKey
.length(), hash
);
790 return string((char*) hash
, sizeof(hash
));
794 std::string
OpenSSLECDSADNSCryptoKeyEngine::getPublicKeyString() const
796 std::string binaryPoint
;
797 binaryPoint
.resize((d_len
* 2) + 1);
799 int ret
= EC_POINT_point2oct(d_ecgroup
.get(), EC_KEY_get0_public_key(d_eckey
.get()), POINT_CONVERSION_UNCOMPRESSED
, reinterpret_cast<unsigned char*>(&binaryPoint
.at(0)), binaryPoint
.size(), nullptr);
801 throw runtime_error(getName()+" exporting point to binary failed");
804 /* we skip the first byte as the other backends use
805 raw field elements, as opposed to the format described in
806 SEC1: "2.3.3 Elliptic-Curve-Point-to-Octet-String Conversion" */
807 binaryPoint
.erase(0, 1);
812 void OpenSSLECDSADNSCryptoKeyEngine::fromISCMap(DNSKEYRecordContent
& drc
, std::map
<std::string
, std::string
>& stormap
)
814 drc
.d_algorithm
= atoi(stormap
["algorithm"].c_str());
816 if (drc
.d_algorithm
!= d_algorithm
) {
817 throw runtime_error(getName()+" tried to feed an algorithm "+std::to_string(drc
.d_algorithm
)+" to a "+std::to_string(d_algorithm
)+" key");
820 string privateKey
= stormap
["privatekey"];
822 auto prv_key
= std::unique_ptr
<BIGNUM
, void(*)(BIGNUM
*)>(BN_bin2bn((unsigned char*) privateKey
.c_str(), privateKey
.length(), nullptr), BN_clear_free
);
824 throw runtime_error(getName()+" reading private key from binary failed");
827 int ret
= EC_KEY_set_private_key(d_eckey
.get(), prv_key
.get());
829 throw runtime_error(getName()+" setting private key failed");
832 auto pub_key
= std::unique_ptr
<EC_POINT
, void(*)(EC_POINT
*)>(EC_POINT_new(d_ecgroup
.get()), EC_POINT_free
);
834 throw runtime_error(getName()+" allocation of public key point failed");
837 ret
= EC_POINT_mul(d_ecgroup
.get(), pub_key
.get(), prv_key
.get(), nullptr, nullptr, nullptr);
839 throw runtime_error(getName()+" computing public key from private failed");
842 ret
= EC_KEY_set_public_key(d_eckey
.get(), pub_key
.get());
844 throw runtime_error(getName()+" setting public key failed");
848 bool OpenSSLECDSADNSCryptoKeyEngine::checkKey(vector
<string
> *errorMessages
) const
851 if (EC_KEY_check_key(d_eckey
.get()) != 1) {
853 if (errorMessages
!= nullptr) {
854 errorMessages
->push_back(ERR_reason_error_string(ERR_get_error()));
860 void OpenSSLECDSADNSCryptoKeyEngine::fromPublicKeyString(const std::string
& input
)
862 /* uncompressed point, from SEC1:
863 "2.3.4 Octet-String-to-Elliptic-Curve-Point Conversion" */
864 string ecdsaPoint
= "\x04";
865 ecdsaPoint
.append(input
);
867 auto pub_key
= std::unique_ptr
<EC_POINT
, void(*)(EC_POINT
*)>(EC_POINT_new(d_ecgroup
.get()), EC_POINT_free
);
869 throw runtime_error(getName()+" allocation of point structure failed");
872 int ret
= EC_POINT_oct2point(d_ecgroup
.get(), pub_key
.get(), (unsigned char*) ecdsaPoint
.c_str(), ecdsaPoint
.length(), nullptr);
874 throw runtime_error(getName()+" reading ECP point from binary failed");
877 ret
= EC_KEY_set_private_key(d_eckey
.get(), nullptr);
879 throw runtime_error(getName()+" setting private key failed");
882 ret
= EC_KEY_set_public_key(d_eckey
.get(), pub_key
.get());
884 throw runtime_error(getName()+" setting public key failed");
889 #ifdef HAVE_LIBCRYPTO_EDDSA
890 class OpenSSLEDDSADNSCryptoKeyEngine
: public DNSCryptoKeyEngine
893 explicit OpenSSLEDDSADNSCryptoKeyEngine(unsigned int algo
) : DNSCryptoKeyEngine(algo
), d_edkey(std::unique_ptr
<EVP_PKEY
, void(*)(EVP_PKEY
*)>(nullptr, EVP_PKEY_free
))
896 int ret
= RAND_status();
898 throw runtime_error(getName()+" insufficient entropy");
901 #ifdef HAVE_LIBCRYPTO_ED25519
902 if(d_algorithm
== 15) {
907 #ifdef HAVE_LIBCRYPTO_ED448
908 if (d_algorithm
== 16) {
914 throw runtime_error(getName()+" unknown algorithm "+std::to_string(d_algorithm
));
918 ~OpenSSLEDDSADNSCryptoKeyEngine()
922 string
getName() const override
{ return "OpenSSL EDDSA"; }
923 int getBits() const override
{ return d_len
; }
925 void create(unsigned int bits
) override
;
926 storvector_t
convertToISCVector() const override
;
927 std::string
sign(const std::string
& hash
) const override
;
928 bool verify(const std::string
& msg
, const std::string
& signature
) const override
;
929 std::string
getPubKeyHash() const override
;
930 std::string
getPublicKeyString() const override
;
931 void fromISCMap(DNSKEYRecordContent
& drc
, std::map
<std::string
, std::string
>& stormap
) override
;
932 void fromPublicKeyString(const std::string
& content
) override
;
933 bool checkKey(vector
<string
> *errorMessages
) const override
;
935 static std::shared_ptr
<DNSCryptoKeyEngine
> maker(unsigned int algorithm
)
937 return std::make_shared
<OpenSSLEDDSADNSCryptoKeyEngine
>(algorithm
);
944 std::unique_ptr
<EVP_PKEY
, void(*)(EVP_PKEY
*)> d_edkey
;
947 bool OpenSSLEDDSADNSCryptoKeyEngine::checkKey(vector
<string
> *errorMessages
) const
949 return (d_edkey
? true : false);
952 void OpenSSLEDDSADNSCryptoKeyEngine::create(unsigned int bits
)
954 auto pctx
= std::unique_ptr
<EVP_PKEY_CTX
, void(*)(EVP_PKEY_CTX
*)>(EVP_PKEY_CTX_new_id(d_id
, nullptr), EVP_PKEY_CTX_free
);
956 throw runtime_error(getName()+" context initialization failed");
958 if (EVP_PKEY_keygen_init(pctx
.get()) < 1) {
959 throw runtime_error(getName()+" keygen initialization failed");
961 EVP_PKEY
* newKey
= nullptr;
962 if (EVP_PKEY_keygen(pctx
.get(), &newKey
) < 1) {
963 throw runtime_error(getName()+" key generation failed");
965 d_edkey
= std::unique_ptr
<EVP_PKEY
, void(*)(EVP_PKEY
*)>(newKey
, EVP_PKEY_free
);
968 DNSCryptoKeyEngine::storvector_t
OpenSSLEDDSADNSCryptoKeyEngine::convertToISCVector() const
970 storvector_t storvect
;
973 #ifdef HAVE_LIBCRYPTO_ED25519
974 if(d_algorithm
== 15) {
975 algorithm
= "15 (ED25519)";
978 #ifdef HAVE_LIBCRYPTO_ED448
979 if(d_algorithm
== 16) {
980 algorithm
= "16 (ED448)";
983 if (algorithm
.empty()) {
984 algorithm
= " ? (?)";
987 storvect
.push_back(make_pair("Algorithm", algorithm
));
992 if (EVP_PKEY_get_raw_private_key(d_edkey
.get(), reinterpret_cast<unsigned char*>(&buf
.at(0)), &len
) < 1) {
993 throw runtime_error(getName() + " Could not get private key from d_edkey");
995 storvect
.push_back(make_pair("PrivateKey", buf
));
999 std::string
OpenSSLEDDSADNSCryptoKeyEngine::sign(const std::string
& msg
) const
1001 auto mdctx
= std::unique_ptr
<EVP_MD_CTX
, void(*)(EVP_MD_CTX
*)>(EVP_MD_CTX_new(), EVP_MD_CTX_free
);
1003 throw runtime_error(getName()+" MD context initialization failed");
1005 if(EVP_DigestSignInit(mdctx
.get(), nullptr, nullptr, nullptr, d_edkey
.get()) < 1) {
1006 throw runtime_error(getName()+" unable to initialize signer");
1009 string msgToSign
= msg
;
1011 size_t siglen
= d_len
* 2;
1013 signature
.resize(siglen
);
1015 if (EVP_DigestSign(mdctx
.get(),
1016 reinterpret_cast<unsigned char*>(&signature
.at(0)), &siglen
,
1017 reinterpret_cast<unsigned char*>(&msgToSign
.at(0)), msgToSign
.length()) < 1) {
1018 throw runtime_error(getName()+" signing error");
1024 bool OpenSSLEDDSADNSCryptoKeyEngine::verify(const std::string
& msg
, const std::string
& signature
) const
1026 auto mdctx
= std::unique_ptr
<EVP_MD_CTX
, void(*)(EVP_MD_CTX
*)>(EVP_MD_CTX_new(), EVP_MD_CTX_free
);
1028 throw runtime_error(getName()+" MD context initialization failed");
1030 if(EVP_DigestVerifyInit(mdctx
.get(), nullptr, nullptr, nullptr, d_edkey
.get()) < 1) {
1031 throw runtime_error(getName()+" unable to initialize signer");
1034 string checkSignature
= signature
;
1035 string checkMsg
= msg
;
1037 auto r
= EVP_DigestVerify(mdctx
.get(),
1038 reinterpret_cast<unsigned char*>(&checkSignature
.at(0)), checkSignature
.length(),
1039 reinterpret_cast<unsigned char*>(&checkMsg
.at(0)), checkMsg
.length());
1041 throw runtime_error(getName()+" verification failure");
1047 std::string
OpenSSLEDDSADNSCryptoKeyEngine::getPubKeyHash() const
1049 return this->getPublicKeyString();
1052 std::string
OpenSSLEDDSADNSCryptoKeyEngine::getPublicKeyString() const
1057 if (EVP_PKEY_get_raw_public_key(d_edkey
.get(), reinterpret_cast<unsigned char*>(&buf
.at(0)), &len
) < 1) {
1058 throw std::runtime_error(getName() + " unable to get public key from key struct");
1063 void OpenSSLEDDSADNSCryptoKeyEngine::fromISCMap(DNSKEYRecordContent
& drc
, std::map
<std::string
, std::string
>& stormap
) {
1064 drc
.d_algorithm
= atoi(stormap
["algorithm"].c_str());
1065 if (drc
.d_algorithm
!= d_algorithm
) {
1066 throw runtime_error(getName()+" tried to feed an algorithm "+std::to_string(drc
.d_algorithm
)+" to a "+std::to_string(d_algorithm
)+" key");
1069 d_edkey
= std::unique_ptr
<EVP_PKEY
, void(*)(EVP_PKEY
*)>(EVP_PKEY_new_raw_private_key(d_id
, nullptr, reinterpret_cast<unsigned char*>(&stormap
["privatekey"].at(0)), stormap
["privatekey"].length()), EVP_PKEY_free
);
1071 throw std::runtime_error(getName() + " could not create key structure from private key");
1075 void OpenSSLEDDSADNSCryptoKeyEngine::fromPublicKeyString(const std::string
& content
)
1077 if (content
.length() != d_len
) {
1078 throw runtime_error(getName() + " wrong public key length for algorithm " + std::to_string(d_algorithm
));
1081 const unsigned char* raw
= reinterpret_cast<const unsigned char*>(content
.c_str());
1083 d_edkey
= std::unique_ptr
<EVP_PKEY
, void(*)(EVP_PKEY
*)>(EVP_PKEY_new_raw_public_key(d_id
, nullptr, raw
, d_len
), EVP_PKEY_free
);
1085 throw runtime_error(getName()+" allocation of public key structure failed");
1088 #endif // HAVE_LIBCRYPTO_EDDSA
1095 DNSCryptoKeyEngine::report(5, &OpenSSLRSADNSCryptoKeyEngine::maker
);
1096 DNSCryptoKeyEngine::report(7, &OpenSSLRSADNSCryptoKeyEngine::maker
);
1097 DNSCryptoKeyEngine::report(8, &OpenSSLRSADNSCryptoKeyEngine::maker
);
1098 DNSCryptoKeyEngine::report(10, &OpenSSLRSADNSCryptoKeyEngine::maker
);
1099 #ifdef HAVE_LIBCRYPTO_ECDSA
1100 DNSCryptoKeyEngine::report(13, &OpenSSLECDSADNSCryptoKeyEngine::maker
);
1101 DNSCryptoKeyEngine::report(14, &OpenSSLECDSADNSCryptoKeyEngine::maker
);
1103 #ifdef HAVE_LIBCRYPTO_ED25519
1104 DNSCryptoKeyEngine::report(15, &OpenSSLEDDSADNSCryptoKeyEngine::maker
);
1106 #ifdef HAVE_LIBCRYPTO_ED448
1107 DNSCryptoKeyEngine::report(16, &OpenSSLEDDSADNSCryptoKeyEngine::maker
);