From: Fred Morcos Date: Mon, 14 Mar 2022 10:26:43 +0000 (+0100) Subject: Support the export of ECDSA keys to PEM X-Git-Tag: rec-4.7.0-beta1~51^2~8 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=18567bc6d796a5553766b2c613098ef02fabb0ba;p=thirdparty%2Fpdns.git Support the export of ECDSA keys to PEM Part of #11325 --- diff --git a/pdns/dnssecinfra.hh b/pdns/dnssecinfra.hh index 9341c2fb67..4b9e5f56c7 100644 --- a/pdns/dnssecinfra.hh +++ b/pdns/dnssecinfra.hh @@ -47,6 +47,10 @@ class DNSCryptoKeyEngine } virtual storvector_t convertToISCVector() const =0; std::string convertToISC() const ; + virtual void convertToPEM(std::FILE& fp) const + { + throw std::runtime_error(getName() + ": Conversion to PEM not supported"); + }; virtual std::string sign(const std::string& msg) const =0; virtual std::string hash(const std::string& msg) const { diff --git a/pdns/opensslsigners.cc b/pdns/opensslsigners.cc index e6c4f0a421..280d8b15ef 100644 --- a/pdns/opensslsigners.cc +++ b/pdns/opensslsigners.cc @@ -613,6 +613,18 @@ public: */ void createFromPEMFile(DNSKEYRecordContent& drc, const std::string& filename, std::FILE& fp) override; + /** + * \brief Writes this key's contents to a file. + * + * Receives an open file handle and writes this key's contents to the + * file. + * + * \param[in] fp An open file handle for writing. + * + * \exception std::runtime_error In case of OpenSSL errors. + */ + void convertToPEM(std::FILE& fp) const override; + storvector_t convertToISCVector() const override; std::string hash(const std::string& hash) const override; std::string sign(const std::string& hash) const override; @@ -682,6 +694,14 @@ void OpenSSLECDSADNSCryptoKeyEngine::createFromPEMFile(DNSKEYRecordContent& drc, EC_KEY_set_asn1_flag(d_eckey.get(), OPENSSL_EC_NAMED_CURVE); } +void OpenSSLECDSADNSCryptoKeyEngine::convertToPEM(std::FILE& fp) const +{ + auto ret = PEM_write_ECPrivateKey(&fp, d_eckey.get(), nullptr, nullptr, 0, nullptr, nullptr); + if (ret == 0) { + throw runtime_error(getName() + ": Could not convert private key to PEM"); + } +} + DNSCryptoKeyEngine::storvector_t OpenSSLECDSADNSCryptoKeyEngine::convertToISCVector() const { storvector_t storvect; diff --git a/pdns/pdnsutil.cc b/pdns/pdnsutil.cc index 285d9bbbf1..ef3593b307 100644 --- a/pdns/pdnsutil.cc +++ b/pdns/pdnsutil.cc @@ -3272,6 +3272,17 @@ try DNSSECPrivateKey dpk = dk.getKeyById(DNSName(zone), id); cout << dpk.getKey()->convertToISC() << endl; } + else if (cmds.at(0) == "export-zone-key-pem") { + if (cmds.size() < 3) { + cerr << "Syntax: pdnsutil export-zone-key-pem ZONE KEY-ID" << endl; + return 1; + } + + string zone = cmds.at(1); + auto id = pdns::checked_stoi(cmds.at(2)); + DNSSECPrivateKey dpk = dk.getKeyById(DNSName(zone), id); + dpk.getKey()->convertToPEM(*stdout); + } else if (cmds.at(0) == "increase-serial") { if (cmds.size() < 2) { cerr << "Syntax: pdnsutil increase-serial ZONE" << endl; diff --git a/pdns/test-signers.cc b/pdns/test-signers.cc index 21654f7ec7..364017d58c 100644 --- a/pdns/test-signers.cc +++ b/pdns/test-signers.cc @@ -276,6 +276,26 @@ BOOST_AUTO_TEST_CASE(test_generic_signers) BOOST_CHECK_EQUAL(pemKey->convertToISC(), dcke->convertToISC()); test_generic_signer(pemKey, pemDRC, signer); + + const size_t buflen = 4096; + + std::string dckePEMOutput{}; + dckePEMOutput.resize(buflen); + unique_ptr dckePEMOutputFp{fmemopen(static_cast(dckePEMOutput.data()), dckePEMOutput.length() - 1, "w"), &std::fclose}; + dcke->convertToPEM(*dckePEMOutputFp); + std::fflush(dckePEMOutputFp.get()); + dckePEMOutput.resize(std::ftell(dckePEMOutputFp.get())); + + BOOST_CHECK_EQUAL(dckePEMOutput, *signer.pem); + + std::string pemKeyOutput{}; + pemKeyOutput.resize(buflen); + unique_ptr pemKeyOutputFp{fmemopen(static_cast(pemKeyOutput.data()), pemKeyOutput.length() - 1, "w"), &std::fclose}; + pemKey->convertToPEM(*pemKeyOutputFp); + std::fflush(pemKeyOutputFp.get()); + pemKeyOutput.resize(std::ftell(pemKeyOutputFp.get())); + + BOOST_CHECK_EQUAL(pemKeyOutput, *signer.pem); } } }