1 #include <openssl/err.h>
2 #include <openssl/pem.h>
6 #pragma GCC diagnostic push
7 #pragma GCC diagnostic ignored "-Wdeprecated-copy"
9 #pragma GCC diagnostic pop
10 #include <decaf/eddsa.hxx>
11 #pragma GCC diagnostic push
12 #pragma GCC diagnostic ignored "-Wshadow"
13 #include <decaf/spongerng.hxx>
14 #pragma GCC diagnostic pop
15 #include "dnsseckeeper.hh"
17 #include "dnssecinfra.hh"
19 using namespace decaf
;
21 class DecafED25519DNSCryptoKeyEngine
: public DNSCryptoKeyEngine
24 explicit DecafED25519DNSCryptoKeyEngine(unsigned int algo
) :
25 DNSCryptoKeyEngine(algo
)
28 string
getName() const override
{ return "Decaf ED25519"; }
29 void create(unsigned int bits
) override
;
31 #if defined(HAVE_LIBCRYPTO_ED25519)
33 * \brief Creates an ED25519 key engine from a PEM file.
35 * Receives an open file handle with PEM contents and creates an ED25519 key engine.
37 * \param[in] drc Key record contents to be populated.
39 * \param[in] inputFile An open file handle to a file containing ED25519 PEM contents.
41 * \param[in] filename Only used for providing filename information in error messages.
43 * \return An ED25519 key engine populated with the contents of the PEM file.
45 void createFromPEMFile(DNSKEYRecordContent
& drc
, std::FILE& inputFile
, std::optional
<std::reference_wrapper
<const std::string
>> filename
= std::nullopt
) override
;
48 * \brief Writes this key's contents to a file.
50 * Receives an open file handle and writes this key's contents to the
53 * \param[in] outputFile An open file handle for writing.
55 * \exception std::runtime_error In case of OpenSSL errors.
57 void convertToPEMFile(std::FILE& outputFile
) const override
;
60 [[nodiscard
]] storvector_t
convertToISCVector() const override
;
61 [[nodiscard
]] std::string
sign(const std::string
& msg
) const override
;
62 [[nodiscard
]] bool verify(const std::string
& msg
, const std::string
& signature
) const override
;
63 [[nodiscard
]] std::string
getPublicKeyString() const override
;
64 [[nodiscard
]] int getBits() const override
;
65 void fromISCMap(DNSKEYRecordContent
& drc
, std::map
<std::string
, std::string
>& stormap
) override
;
66 void fromPublicKeyString(const std::string
& content
) override
;
68 static std::unique_ptr
<DNSCryptoKeyEngine
> maker(unsigned int algorithm
)
70 return make_unique
<DecafED25519DNSCryptoKeyEngine
>(algorithm
);
74 unsigned char d_pubkey
[DECAF_EDDSA_25519_PUBLIC_BYTES
];
75 unsigned char d_seckey
[DECAF_EDDSA_25519_PRIVATE_BYTES
];
78 void DecafED25519DNSCryptoKeyEngine::create(unsigned int bits
)
80 if (bits
!= (unsigned int)getBits()) {
81 throw runtime_error("Unsupported key length of " + std::to_string(bits
) + " bits requested, DecafED25519 class");
84 SpongeRng
rng("/dev/urandom");
86 typename EdDSA
<IsoEd25519
>::PrivateKey
priv(rng
);
87 typename EdDSA
<IsoEd25519
>::PublicKey
pub(priv
);
89 priv
.serialize_into(d_seckey
);
90 pub
.serialize_into(d_pubkey
);
93 #if defined(HAVE_LIBCRYPTO_ED25519)
94 void DecafED25519DNSCryptoKeyEngine::createFromPEMFile(DNSKEYRecordContent
& drc
, std::FILE& inputFile
, std::optional
<std::reference_wrapper
<const std::string
>> filename
)
96 drc
.d_algorithm
= d_algorithm
;
97 auto key
= std::unique_ptr
<EVP_PKEY
, decltype(&EVP_PKEY_free
)>(PEM_read_PrivateKey(&inputFile
, nullptr, nullptr, nullptr), &EVP_PKEY_free
);
99 if (filename
.has_value()) {
100 throw runtime_error(getName() + ": Failed to read private key from PEM file `" + filename
->get() + "`");
103 throw runtime_error(getName() + ": Failed to read private key from PEM contents");
106 std::size_t keylen
= DECAF_EDDSA_25519_PRIVATE_BYTES
;
107 int ret
= EVP_PKEY_get_raw_private_key(key
.get(), d_seckey
, &keylen
);
109 if (filename
.has_value()) {
110 throw runtime_error(getName() + ": Failed to get private key from PEM file contents `" + filename
->get() + "`");
113 throw runtime_error(getName() + ": Failed to get private key from PEM contents");
116 keylen
= DECAF_EDDSA_25519_PUBLIC_BYTES
;
117 ret
= EVP_PKEY_get_raw_public_key(key
.get(), d_pubkey
, &keylen
);
119 if (filename
.has_value()) {
120 throw runtime_error(getName() + ": Failed to get public key from PEM file contents `" + filename
->get() + "`");
123 throw runtime_error(getName() + ": Failed to get public key from PEM contents");
127 void DecafED25519DNSCryptoKeyEngine::convertToPEMFile(std::FILE& outputFile
) const
129 auto key
= std::unique_ptr
<EVP_PKEY
, void (*)(EVP_PKEY
*)>(EVP_PKEY_new_raw_private_key(EVP_PKEY_ED25519
, nullptr, d_seckey
, DECAF_EDDSA_25519_PRIVATE_BYTES
), EVP_PKEY_free
);
130 if (key
== nullptr) {
131 throw runtime_error(getName() + ": Could not create private key from buffer");
134 auto ret
= PEM_write_PrivateKey(&outputFile
, key
.get(), nullptr, nullptr, 0, nullptr, nullptr);
136 throw runtime_error(getName() + ": Could not convert private key to PEM");
141 int DecafED25519DNSCryptoKeyEngine::getBits() const
143 return DECAF_EDDSA_25519_PRIVATE_BYTES
<< 3;
146 DNSCryptoKeyEngine::storvector_t
DecafED25519DNSCryptoKeyEngine::convertToISCVector() const
149 Private-key-format: v1.2
150 Algorithm: 15 (ED25519)
151 PrivateKey: ODIyNjAzODQ2MjgwODAxMjI2NDUxOTAyMDQxNDIyNjI=
154 auto storvector
= storvector_t
{
155 {"Algorithm", "15 (ED25519)"},
156 {"PrivateKey", string((char*)d_seckey
, DECAF_EDDSA_25519_PRIVATE_BYTES
)},
162 void DecafED25519DNSCryptoKeyEngine::fromISCMap(DNSKEYRecordContent
& drc
, std::map
<std::string
, std::string
>& stormap
)
165 Private-key-format: v1.2
166 Algorithm: 15 (ED25519)
167 PrivateKey: ODIyNjAzODQ2MjgwODAxMjI2NDUxOTAyMDQxNDIyNjI=
170 pdns::checked_stoi_into(drc
.d_algorithm
, stormap
["algorithm"]);
171 string privateKey
= stormap
["privatekey"];
173 if (privateKey
.length() != DECAF_EDDSA_25519_PRIVATE_BYTES
)
174 throw runtime_error("Private key size mismatch in ISCMap, DecafED25519 class");
176 typename EdDSA
<IsoEd25519
>::PrivateKey
priv(Block((const unsigned char*)privateKey
.c_str(), DECAF_EDDSA_25519_PRIVATE_BYTES
));
177 typename EdDSA
<IsoEd25519
>::PublicKey
pub(priv
);
179 priv
.serialize_into(d_seckey
);
180 pub
.serialize_into(d_pubkey
);
183 std::string
DecafED25519DNSCryptoKeyEngine::getPublicKeyString() const
185 return string((char*)d_pubkey
, DECAF_EDDSA_25519_PUBLIC_BYTES
);
188 void DecafED25519DNSCryptoKeyEngine::fromPublicKeyString(const std::string
& input
)
190 if (input
.length() != DECAF_EDDSA_25519_PUBLIC_BYTES
)
191 throw runtime_error("Public key size mismatch, DecafED25519 class");
193 memcpy(d_pubkey
, input
.c_str(), DECAF_EDDSA_25519_PUBLIC_BYTES
);
196 std::string
DecafED25519DNSCryptoKeyEngine::sign(const std::string
& msg
) const
198 typename EdDSA
<IsoEd25519
>::PrivateKey
priv(Block(d_seckey
, DECAF_EDDSA_25519_PRIVATE_BYTES
));
200 SecureBuffer
message(msg
.begin(), msg
.end());
202 SecureBuffer sig
= priv
.sign(message
);
204 return string(sig
.begin(), sig
.end());
207 bool DecafED25519DNSCryptoKeyEngine::verify(const std::string
& msg
, const std::string
& signature
) const
209 if (signature
.length() != DECAF_EDDSA_25519_SIGNATURE_BYTES
)
212 typename EdDSA
<IsoEd25519
>::PublicKey
pub(Block(d_pubkey
, DECAF_EDDSA_25519_PUBLIC_BYTES
));
214 SecureBuffer
sig(signature
.begin(), signature
.end());
215 SecureBuffer
message(msg
.begin(), msg
.end());
218 pub
.verify(sig
, message
);
220 catch (const CryptoException
& e
) {
227 class DecafED448DNSCryptoKeyEngine
: public DNSCryptoKeyEngine
230 explicit DecafED448DNSCryptoKeyEngine(unsigned int algo
) :
231 DNSCryptoKeyEngine(algo
)
234 string
getName() const override
{ return "Decaf ED448"; }
235 void create(unsigned int bits
) override
;
237 #if defined(HAVE_LIBCRYPTO_ED448)
239 * \brief Creates an ED448 key engine from a PEM file.
241 * Receives an open file handle with PEM contents and creates an ED448 key engine.
243 * \param[in] drc Key record contents to be populated.
245 * \param[in] inputFile An open file handle to a file containing ED448 PEM contents.
247 * \param[in] filename Only used for providing filename information in error messages.
249 * \return An ED448 key engine populated with the contents of the PEM file.
251 void createFromPEMFile(DNSKEYRecordContent
& drc
, std::FILE& inputFile
, std::optional
<std::reference_wrapper
<const std::string
>> filename
= std::nullopt
) override
;
254 * \brief Writes this key's contents to a file.
256 * Receives an open file handle and writes this key's contents to the
259 * \param[in] outputFile An open file handle for writing.
261 * \exception std::runtime_error In case of OpenSSL errors.
263 void convertToPEMFile(std::FILE& outputFile
) const override
;
266 storvector_t
convertToISCVector() const override
;
267 std::string
sign(const std::string
& msg
) const override
;
268 bool verify(const std::string
& msg
, const std::string
& signature
) const override
;
269 std::string
getPublicKeyString() const override
;
270 int getBits() const override
;
271 void fromISCMap(DNSKEYRecordContent
& drc
, std::map
<std::string
, std::string
>& stormap
) override
;
272 void fromPublicKeyString(const std::string
& content
) override
;
274 static std::unique_ptr
<DNSCryptoKeyEngine
> maker(unsigned int algorithm
)
276 return make_unique
<DecafED448DNSCryptoKeyEngine
>(algorithm
);
280 unsigned char d_pubkey
[DECAF_EDDSA_448_PUBLIC_BYTES
];
281 unsigned char d_seckey
[DECAF_EDDSA_448_PRIVATE_BYTES
];
284 void DecafED448DNSCryptoKeyEngine::create(unsigned int bits
)
286 if (bits
!= (unsigned int)getBits()) {
287 throw runtime_error("Unsupported key length of " + std::to_string(bits
) + " bits requested, DecafED448 class");
290 SpongeRng
rng("/dev/urandom");
292 typename EdDSA
<Ed448Goldilocks
>::PrivateKey
priv(rng
);
293 typename EdDSA
<Ed448Goldilocks
>::PublicKey
pub(priv
);
295 priv
.serialize_into(d_seckey
);
296 pub
.serialize_into(d_pubkey
);
299 #if defined(HAVE_LIBCRYPTO_ED448)
300 void DecafED448DNSCryptoKeyEngine::createFromPEMFile(DNSKEYRecordContent
& drc
, std::FILE& inputFile
, std::optional
<std::reference_wrapper
<const std::string
>> filename
)
302 drc
.d_algorithm
= d_algorithm
;
303 auto key
= std::unique_ptr
<EVP_PKEY
, decltype(&EVP_PKEY_free
)>(PEM_read_PrivateKey(&inputFile
, nullptr, nullptr, nullptr), &EVP_PKEY_free
);
304 if (key
== nullptr) {
305 if (filename
.has_value()) {
306 throw runtime_error(getName() + ": Failed to read private key from PEM file `" + filename
->get() + "`");
309 throw runtime_error(getName() + ": Failed to read private key from PEM contents");
312 std::size_t keylen
= DECAF_EDDSA_448_PRIVATE_BYTES
;
313 int ret
= EVP_PKEY_get_raw_private_key(key
.get(), d_seckey
, &keylen
);
315 if (filename
.has_value()) {
316 throw runtime_error(getName() + ": Failed to get private key from PEM file contents `" + filename
->get() + "`");
319 throw runtime_error(getName() + ": Failed to get private key from PEM contents");
322 keylen
= DECAF_EDDSA_448_PUBLIC_BYTES
;
323 ret
= EVP_PKEY_get_raw_public_key(key
.get(), d_pubkey
, &keylen
);
325 if (filename
.has_value()) {
326 throw runtime_error(getName() + ": Failed to get public key from PEM file contents `" + filename
->get() + "`");
329 throw runtime_error(getName() + ": Failed to get public key from PEM contents");
333 void DecafED448DNSCryptoKeyEngine::convertToPEMFile(std::FILE& outputFile
) const
335 auto key
= std::unique_ptr
<EVP_PKEY
, void (*)(EVP_PKEY
*)>(EVP_PKEY_new_raw_private_key(EVP_PKEY_ED448
, nullptr, d_seckey
, DECAF_EDDSA_448_PRIVATE_BYTES
), EVP_PKEY_free
);
336 if (key
== nullptr) {
337 throw runtime_error(getName() + ": Could not create private key from buffer");
340 auto ret
= PEM_write_PrivateKey(&outputFile
, key
.get(), nullptr, nullptr, 0, nullptr, nullptr);
342 throw runtime_error(getName() + ": Could not convert private key to PEM");
347 int DecafED448DNSCryptoKeyEngine::getBits() const
349 return DECAF_EDDSA_448_PRIVATE_BYTES
<< 3;
352 DNSCryptoKeyEngine::storvector_t
DecafED448DNSCryptoKeyEngine::convertToISCVector() const
355 Private-key-format: v1.2
356 Algorithm: 16 (ED448)
357 PrivateKey: xZ+5Cgm463xugtkY5B0Jx6erFTXp13rYegst0qRtNsOYnaVpMx0Z/c5EiA9x8wWbDDct/U3FhYWA
360 auto storvector
= storvector_t
{
361 {"Algorithm", "16 (ED448)"},
362 {"PrivateKey", string((char*)d_seckey
, DECAF_EDDSA_448_PRIVATE_BYTES
)},
368 void DecafED448DNSCryptoKeyEngine::fromISCMap(DNSKEYRecordContent
& drc
, std::map
<std::string
, std::string
>& stormap
)
371 Private-key-format: v1.2
372 Algorithm: 16 (ED448)
373 PrivateKey: xZ+5Cgm463xugtkY5B0Jx6erFTXp13rYegst0qRtNsOYnaVpMx0Z/c5EiA9x8wWbDDct/U3FhYWA
376 pdns::checked_stoi_into(drc
.d_algorithm
, stormap
["algorithm"]);
377 string privateKey
= stormap
["privatekey"];
379 if (privateKey
.length() != DECAF_EDDSA_448_PRIVATE_BYTES
)
380 throw runtime_error("Private key size mismatch in ISCMap, DecafED448 class");
382 typename EdDSA
<Ed448Goldilocks
>::PrivateKey
priv(Block((const unsigned char*)privateKey
.c_str(), DECAF_EDDSA_448_PRIVATE_BYTES
));
383 typename EdDSA
<Ed448Goldilocks
>::PublicKey
pub(priv
);
385 priv
.serialize_into(d_seckey
);
386 pub
.serialize_into(d_pubkey
);
389 std::string
DecafED448DNSCryptoKeyEngine::getPublicKeyString() const
391 return string((char*)d_pubkey
, DECAF_EDDSA_448_PUBLIC_BYTES
);
394 void DecafED448DNSCryptoKeyEngine::fromPublicKeyString(const std::string
& input
)
396 if (input
.length() != DECAF_EDDSA_448_PUBLIC_BYTES
)
397 throw runtime_error("Public key size mismatch, DecafED448 class");
399 memcpy(d_pubkey
, input
.c_str(), DECAF_EDDSA_448_PUBLIC_BYTES
);
402 std::string
DecafED448DNSCryptoKeyEngine::sign(const std::string
& msg
) const
404 typename EdDSA
<Ed448Goldilocks
>::PrivateKey
priv(Block(d_seckey
, DECAF_EDDSA_448_PRIVATE_BYTES
));
406 SecureBuffer
message(msg
.begin(), msg
.end());
408 SecureBuffer sig
= priv
.sign(message
);
410 return string(sig
.begin(), sig
.end());
413 bool DecafED448DNSCryptoKeyEngine::verify(const std::string
& msg
, const std::string
& signature
) const
415 if (signature
.length() != DECAF_EDDSA_448_SIGNATURE_BYTES
)
418 typename EdDSA
<Ed448Goldilocks
>::PublicKey
pub(Block(d_pubkey
, DECAF_EDDSA_448_PUBLIC_BYTES
));
420 SecureBuffer
sig(signature
.begin(), signature
.end());
421 SecureBuffer
message(msg
.begin(), msg
.end());
424 pub
.verify(sig
, message
);
426 catch (const CryptoException
& e
) {
435 const struct LoaderDecafStruct
439 DNSCryptoKeyEngine::report(DNSSECKeeper::ED25519
, &DecafED25519DNSCryptoKeyEngine::maker
, true);
440 DNSCryptoKeyEngine::report(DNSSECKeeper::ED448
, &DecafED448DNSCryptoKeyEngine::maker
);