From: Pieter Lexis Date: Wed, 24 Oct 2018 07:57:57 +0000 (+0200) Subject: Merge remote-tracking branch 'origin/master' into rsakey-warn-keysize X-Git-Tag: auth-4.2.0-alpha1~34^2 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=128bc6d2a3199264fbaa23343cb5019889d015b5;p=thirdparty%2Fpdns.git Merge remote-tracking branch 'origin/master' into rsakey-warn-keysize --- 128bc6d2a3199264fbaa23343cb5019889d015b5 diff --cc pdns/opensslsigners.cc index afa55b87cc,dc746006d5..694264eb80 --- a/pdns/opensslsigners.cc +++ b/pdns/opensslsigners.cc @@@ -533,36 -516,12 +518,32 @@@ void OpenSSLRSADNSCryptoKeyEngine::from throw runtime_error(getName()+" tried to feed an algorithm "+std::to_string(drc.d_algorithm)+" to a "+std::to_string(d_algorithm)+" key"); } - if (d_key) - RSA_free(d_key); - - d_key = key; + d_key = std::move(key); } -bool OpenSSLRSADNSCryptoKeyEngine::checkKey() const +bool OpenSSLRSADNSCryptoKeyEngine::checkKey(vector *errorMessages) const { - return (RSA_check_key(d_key.get()) == 1); + bool retval = true; + // When changing the bitsizes, also edit them in ::create + if ((d_algorithm == DNSSECKeeper::RSASHA1 || d_algorithm == DNSSECKeeper::RSASHA1NSEC3SHA1 || d_algorithm == DNSSECKeeper::RSASHA256) && (getBits() < 512 || getBits()> 4096)) { + retval = false; + if (errorMessages != nullptr) { + errorMessages->push_back("key is " + std::to_string(getBits()) + " bytes, should be between 512 and 4096"); + } + } + if (d_algorithm == DNSSECKeeper::RSASHA512 && (getBits() < 1024 || getBits() > 4096)) { + retval = false; + if (errorMessages != nullptr) { + errorMessages->push_back("key is " + std::to_string(getBits()) + " bytes, should be between 1024 and 4096"); + } + } - if (RSA_check_key(d_key) != 1) { ++ if (RSA_check_key(d_key.get()) != 1) { + retval = false; + if (errorMessages != nullptr) { + errorMessages->push_back(ERR_reason_error_string(ERR_get_error())); + } + } + return retval; } void OpenSSLRSADNSCryptoKeyEngine::fromPublicKeyString(const std::string& input) @@@ -889,29 -817,15 +839,22 @@@ void OpenSSLECDSADNSCryptoKeyEngine::fr throw runtime_error(getName()+" computing public key from private failed"); } - BN_clear_free(prv_key); - - ret = EC_KEY_set_public_key(d_eckey, pub_key); + ret = EC_KEY_set_public_key(d_eckey.get(), pub_key.get()); if (ret != 1) { - EC_POINT_free(pub_key); throw runtime_error(getName()+" setting public key failed"); } - - EC_POINT_free(pub_key); } -bool OpenSSLECDSADNSCryptoKeyEngine::checkKey() const +bool OpenSSLECDSADNSCryptoKeyEngine::checkKey(vector *errorMessages) const { - return (EC_KEY_check_key(d_eckey.get()) == 1); + bool retval = true; - if (EC_KEY_check_key(d_eckey) != 1) { ++ if (EC_KEY_check_key(d_eckey.get()) != 1) { + retval = false; + if (errorMessages != nullptr) { + errorMessages->push_back(ERR_reason_error_string(ERR_get_error())); + } + } + return retval; } void OpenSSLECDSADNSCryptoKeyEngine::fromPublicKeyString(const std::string& input) @@@ -937,17 -850,213 +879,213 @@@ throw runtime_error(getName()+" setting private key failed"); } - ret = EC_KEY_set_public_key(d_eckey, pub_key); + ret = EC_KEY_set_public_key(d_eckey.get(), pub_key.get()); if (ret != 1) { - EC_POINT_free(pub_key); throw runtime_error(getName()+" setting public key failed"); } + } + #endif + + #ifdef HAVE_LIBCRYPTO_EDDSA + class OpenSSLEDDSADNSCryptoKeyEngine : public DNSCryptoKeyEngine + { + public: + explicit OpenSSLEDDSADNSCryptoKeyEngine(unsigned int algo) : DNSCryptoKeyEngine(algo), d_edkey(std::unique_ptr(nullptr, EVP_PKEY_free)) + { + + int ret = RAND_status(); + if (ret != 1) { + throw runtime_error(getName()+" insufficient entropy"); + } + + #ifdef HAVE_LIBCRYPTO_ED25519 + if(d_algorithm == 15) { + d_len = 32; + d_id = NID_ED25519; + } + #endif + #ifdef HAVE_LIBCRYPTO_ED448 + if (d_algorithm == 16) { + d_len = 57; + d_id = NID_ED448; + } + #endif + if (d_len == 0) { + throw runtime_error(getName()+" unknown algorithm "+std::to_string(d_algorithm)); + } + } + + ~OpenSSLEDDSADNSCryptoKeyEngine() + { + } + + string getName() const override { return "OpenSSL EDDSA"; } + int getBits() const override { return d_len; } + + void create(unsigned int bits) override; + storvector_t convertToISCVector() const override; + std::string sign(const std::string& hash) const override; + bool verify(const std::string& msg, const std::string& signature) const override; + std::string getPubKeyHash() const override; + std::string getPublicKeyString() const override; + void fromISCMap(DNSKEYRecordContent& drc, std::map& stormap) override; + void fromPublicKeyString(const std::string& content) override; - bool checkKey() const override; ++ bool checkKey(vector *errorMessages) const override; + + static std::shared_ptr maker(unsigned int algorithm) + { + return std::make_shared(algorithm); + } + + private: + size_t d_len{0}; + int d_id{0}; + + std::unique_ptr d_edkey; + }; - EC_POINT_free(pub_key); -bool OpenSSLEDDSADNSCryptoKeyEngine::checkKey() const ++bool OpenSSLEDDSADNSCryptoKeyEngine::checkKey(vector *errorMessages) const + { + return (d_edkey ? true : false); + } + + void OpenSSLEDDSADNSCryptoKeyEngine::create(unsigned int bits) + { + auto pctx = std::unique_ptr(EVP_PKEY_CTX_new_id(d_id, nullptr), EVP_PKEY_CTX_free); + if (!pctx) { + throw runtime_error(getName()+" context initialization failed"); + } + if (EVP_PKEY_keygen_init(pctx.get()) < 1) { + throw runtime_error(getName()+" keygen initialization failed"); + } + EVP_PKEY* newKey = nullptr; + if (EVP_PKEY_keygen(pctx.get(), &newKey) < 1) { + throw runtime_error(getName()+" key generation failed"); + } + d_edkey = std::unique_ptr(newKey, EVP_PKEY_free); } + + DNSCryptoKeyEngine::storvector_t OpenSSLEDDSADNSCryptoKeyEngine::convertToISCVector() const + { + storvector_t storvect; + string algorithm; + + #ifdef HAVE_LIBCRYPTO_ED25519 + if(d_algorithm == 15) { + algorithm = "15 (ED25519)"; + } #endif + #ifdef HAVE_LIBCRYPTO_ED448 + if(d_algorithm == 16) { + algorithm = "16 (ED448)"; + } + #endif + if (algorithm.empty()) { + algorithm = " ? (?)"; + } + + storvect.push_back(make_pair("Algorithm", algorithm)); + + string buf; + size_t len = d_len; + buf.resize(len); + if (EVP_PKEY_get_raw_private_key(d_edkey.get(), reinterpret_cast(&buf.at(0)), &len) < 1) { + throw runtime_error(getName() + " Could not get private key from d_edkey"); + } + storvect.push_back(make_pair("PrivateKey", buf)); + return storvect; + } + + std::string OpenSSLEDDSADNSCryptoKeyEngine::sign(const std::string& msg) const + { + auto mdctx = std::unique_ptr(EVP_MD_CTX_new(), EVP_MD_CTX_free); + if (!mdctx) { + throw runtime_error(getName()+" MD context initialization failed"); + } + if(EVP_DigestSignInit(mdctx.get(), nullptr, nullptr, nullptr, d_edkey.get()) < 1) { + throw runtime_error(getName()+" unable to initialize signer"); + } + + string msgToSign = msg; + + size_t siglen = d_len * 2; + string signature; + signature.resize(siglen); + + if (EVP_DigestSign(mdctx.get(), + reinterpret_cast(&signature.at(0)), &siglen, + reinterpret_cast(&msgToSign.at(0)), msgToSign.length()) < 1) { + throw runtime_error(getName()+" signing error"); + } + + return signature; + } + + bool OpenSSLEDDSADNSCryptoKeyEngine::verify(const std::string& msg, const std::string& signature) const + { + auto mdctx = std::unique_ptr(EVP_MD_CTX_new(), EVP_MD_CTX_free); + if (!mdctx) { + throw runtime_error(getName()+" MD context initialization failed"); + } + if(EVP_DigestVerifyInit(mdctx.get(), nullptr, nullptr, nullptr, d_edkey.get()) < 1) { + throw runtime_error(getName()+" unable to initialize signer"); + } + + string checkSignature = signature; + string checkMsg = msg; + + auto r = EVP_DigestVerify(mdctx.get(), + reinterpret_cast(&checkSignature.at(0)), checkSignature.length(), + reinterpret_cast(&checkMsg.at(0)), checkMsg.length()); + if (r < 0) { + throw runtime_error(getName()+" verification failure"); + } + + return (r == 1); + } + + std::string OpenSSLEDDSADNSCryptoKeyEngine::getPubKeyHash() const + { + return this->getPublicKeyString(); + } + + std::string OpenSSLEDDSADNSCryptoKeyEngine::getPublicKeyString() const + { + string buf; + size_t len = d_len; + buf.resize(len); + if (EVP_PKEY_get_raw_public_key(d_edkey.get(), reinterpret_cast(&buf.at(0)), &len) < 1) { + throw std::runtime_error(getName() + " unable to get public key from key struct"); + } + return buf; + } + + void OpenSSLEDDSADNSCryptoKeyEngine::fromISCMap(DNSKEYRecordContent& drc, std::map& stormap) { + drc.d_algorithm = atoi(stormap["algorithm"].c_str()); + if (drc.d_algorithm != d_algorithm) { + throw runtime_error(getName()+" tried to feed an algorithm "+std::to_string(drc.d_algorithm)+" to a "+std::to_string(d_algorithm)+" key"); + } + d_edkey = std::unique_ptr(EVP_PKEY_new_raw_private_key(d_id, nullptr, reinterpret_cast(&stormap["privatekey"].at(0)), stormap["privatekey"].length()), EVP_PKEY_free); + if (!d_edkey) { + throw std::runtime_error(getName() + " could not create key structure from private key"); + } + } + + void OpenSSLEDDSADNSCryptoKeyEngine::fromPublicKeyString(const std::string& content) + { + if (content.length() != d_len) { + throw runtime_error(getName() + " wrong public key length for algorithm " + std::to_string(d_algorithm)); + } + + const unsigned char* raw = reinterpret_cast(content.c_str()); + + d_edkey = std::unique_ptr(EVP_PKEY_new_raw_public_key(d_id, nullptr, raw, d_len), EVP_PKEY_free); + if (!d_edkey) { + throw runtime_error(getName()+" allocation of public key structure failed"); + } + } + #endif // HAVE_LIBCRYPTO_EDDSA namespace { struct LoaderStruct