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<string> *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)
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<string> *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)
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");
}
- bool checkKey() const override;
+ }
+ #endif
+
+ #ifdef HAVE_LIBCRYPTO_EDDSA
+ class OpenSSLEDDSADNSCryptoKeyEngine : public DNSCryptoKeyEngine
+ {
+ public:
+ explicit OpenSSLEDDSADNSCryptoKeyEngine(unsigned int algo) : DNSCryptoKeyEngine(algo), d_edkey(std::unique_ptr<EVP_PKEY, void(*)(EVP_PKEY*)>(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<std::string, std::string>& stormap) override;
+ void fromPublicKeyString(const std::string& content) override;
++ bool checkKey(vector<string> *errorMessages) const override;
+
+ static std::shared_ptr<DNSCryptoKeyEngine> maker(unsigned int algorithm)
+ {
+ return std::make_shared<OpenSSLEDDSADNSCryptoKeyEngine>(algorithm);
+ }
+
+ private:
+ size_t d_len{0};
+ int d_id{0};
+
+ std::unique_ptr<EVP_PKEY, void(*)(EVP_PKEY*)> d_edkey;
+ };
- EC_POINT_free(pub_key);
-bool OpenSSLEDDSADNSCryptoKeyEngine::checkKey() const
++bool OpenSSLEDDSADNSCryptoKeyEngine::checkKey(vector<string> *errorMessages) const
+ {
+ return (d_edkey ? true : false);
+ }
+
+ void OpenSSLEDDSADNSCryptoKeyEngine::create(unsigned int bits)
+ {
+ auto pctx = std::unique_ptr<EVP_PKEY_CTX, void(*)(EVP_PKEY_CTX*)>(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<EVP_PKEY, void(*)(EVP_PKEY*)>(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<unsigned char*>(&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, void(*)(EVP_MD_CTX*)>(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<unsigned char*>(&signature.at(0)), &siglen,
+ reinterpret_cast<unsigned char*>(&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, void(*)(EVP_MD_CTX*)>(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<unsigned char*>(&checkSignature.at(0)), checkSignature.length(),
+ reinterpret_cast<unsigned char*>(&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<unsigned char*>(&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<std::string, std::string>& 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, 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);
+ 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<const unsigned char*>(content.c_str());
+
+ 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);
+ if (!d_edkey) {
+ throw runtime_error(getName()+" allocation of public key structure failed");
+ }
+ }
+ #endif // HAVE_LIBCRYPTO_EDDSA
namespace {
struct LoaderStruct