From 21a8834aaa73614a3e8150a03f29d2fc75b115d5 Mon Sep 17 00:00:00 2001 From: Kees Monshouwer Date: Sat, 17 Jun 2017 17:31:41 +0200 Subject: [PATCH] hello decaf signers (ED25519 and ED448) Testing algorithm 15: 'Decaf ED25519' ->'Decaf ED25519' -> 'Decaf ED25519' Signature & verify ok, signature 68usec, verify 93usec Testing algorithm 16: 'Decaf ED448' ->'Decaf ED448' -> 'Decaf ED448' Signature & verify ok, signature 163usec, verify 252usec --- configure.ac | 11 +- m4/pdns_check_libdecaf.m4 | 23 ++ pdns/Makefile.am | 10 + pdns/dbdnsseckeeper.cc | 2 + pdns/decafsigners.cc | 293 ++++++++++++++++++++ pdns/dnssecinfra.cc | 2 + pdns/dnsseckeeper.hh | 6 +- pdns/pdnsutil.cc | 7 +- pdns/recursordist/Makefile.am | 6 + pdns/recursordist/configure.ac | 5 + pdns/recursordist/decafsigners.cc | 1 + pdns/recursordist/m4/pdns_check_libdecaf.m4 | 1 + pdns/version.cc | 3 + 13 files changed, 365 insertions(+), 5 deletions(-) create mode 100644 m4/pdns_check_libdecaf.m4 create mode 100644 pdns/decafsigners.cc create mode 120000 pdns/recursordist/decafsigners.cc create mode 120000 pdns/recursordist/m4/pdns_check_libdecaf.m4 diff --git a/configure.ac b/configure.ac index 5d228ed39..a5a597cbf 100644 --- a/configure.ac +++ b/configure.ac @@ -95,6 +95,7 @@ AC_CHECK_HEADERS( PDNS_ENABLE_BOTAN PDNS_CHECK_LIBSODIUM +PDNS_CHECK_LIBDECAF PDNS_CHECK_LIBCRYPTO([ ],[ AC_MSG_ERROR([OpenSSL/libcrypto not found]) @@ -348,9 +349,13 @@ AS_IF([test "x$libcrypto_ecdsa" = "xyes"], [AC_MSG_NOTICE([OpenSSL ecdsa: yes])], [AC_MSG_NOTICE([OpenSSL ecdsa: no])] ) -AS_IF([test "x$LIBSODIUM_LIBS" != "x"], - [AC_MSG_NOTICE([libsodium ed25519: yes])], - [AC_MSG_NOTICE([libsodium ed25519: no])] +AS_IF([test "x$LIBSODIUM_LIBS" != "x" || test "x$LIBDECAF_LIBS" != "x"], + [AC_MSG_NOTICE([ed25519: yes])], + [AC_MSG_NOTICE([ed25519: no])] +) +AS_IF([test "x$LIBDECAF_LIBS" != "x"], + [AC_MSG_NOTICE([ed448: yes])], + [AC_MSG_NOTICE([ed448: no])] ) AS_IF([test "x$needsqlite3" != "x"], [AC_MSG_NOTICE([SQLite3: yes])], diff --git a/m4/pdns_check_libdecaf.m4 b/m4/pdns_check_libdecaf.m4 new file mode 100644 index 000000000..6e4e82314 --- /dev/null +++ b/m4/pdns_check_libdecaf.m4 @@ -0,0 +1,23 @@ +AC_DEFUN([PDNS_CHECK_LIBDECAF],[ + AC_MSG_CHECKING([whether we will be linking in libdecaf]) + AC_ARG_ENABLE([libdecaf], + [AS_HELP_STRING([--enable-libdecaf],[use libdecaf @<:@default=no@:>@])], + [enable_libdecaf=$enableval], + [enable_libdecaf=no] + ) + AC_MSG_RESULT([$enable_libdecaf]) + + AM_CONDITIONAL([LIBDECAF],[test "x$enable_libdecaf" != "xno"]) + + AS_IF([test "x$enable_libdecaf" != "xno"],[ + save_LIBS=$LIBS + LIBS="" + AC_SEARCH_LIBS([decaf_ed25519_sign],[decaf],[ + AC_DEFINE([HAVE_LIBDECAF],[1],[Define to 1 if you have libdecaf]) + AC_SUBST([LIBDECAF_LIBS],["$LIBS"]) + ],[ + AC_MSG_ERROR([Could not find libdecaf])] + )] + LIBS="$save_LIBS" + ) +]) diff --git a/pdns/Makefile.am b/pdns/Makefile.am index 8d8b509ec..08d6162b9 100644 --- a/pdns/Makefile.am +++ b/pdns/Makefile.am @@ -240,6 +240,11 @@ pdns_server_SOURCES += sodiumsigners.cc pdns_server_LDADD += $(LIBSODIUM_LIBS) endif +if LIBDECAF +pdns_server_SOURCES += decafsigners.cc +pdns_server_LDADD += $(LIBDECAF_LIBS) +endif + if SQLITE3 pdns_server_SOURCES += ssqlite3.cc ssqlite3.hh pdns_server_LDADD += $(SQLITE3_LIBS) @@ -334,6 +339,11 @@ pdnsutil_SOURCES += sodiumsigners.cc pdnsutil_LDADD += $(LIBSODIUM_LIBS) endif +if LIBDECAF +pdnsutil_SOURCES += decafsigners.cc +pdnsutil_LDADD += $(LIBDECAF_LIBS) +endif + if SQLITE3 pdnsutil_SOURCES += ssqlite3.cc ssqlite3.hh pdnsutil_LDADD += $(SQLITE3_LIBS) diff --git a/pdns/dbdnsseckeeper.cc b/pdns/dbdnsseckeeper.cc index 35e709770..c121f125b 100644 --- a/pdns/dbdnsseckeeper.cc +++ b/pdns/dbdnsseckeeper.cc @@ -88,6 +88,8 @@ bool DNSSECKeeper::addKey(const DNSName& name, bool setSEPBit, int algorithm, in bits = 256; else if(algorithm == 14) // ECDSAP384SHA384 bits = 384; + else if(algorithm == 16) // ED448 + bits = 456; else { throw runtime_error("Can not guess key size for algorithm "+std::to_string(algorithm)); } diff --git a/pdns/decafsigners.cc b/pdns/decafsigners.cc new file mode 100644 index 000000000..5e2bbc4ce --- /dev/null +++ b/pdns/decafsigners.cc @@ -0,0 +1,293 @@ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif +#include +#include +#include + +#include "dnssecinfra.hh" + +using namespace decaf; + +class DecafED25519DNSCryptoKeyEngine : public DNSCryptoKeyEngine +{ +public: + explicit DecafED25519DNSCryptoKeyEngine(unsigned int algo) : DNSCryptoKeyEngine(algo) + { + + } + string getName() const override { return "Decaf ED25519"; } + void create(unsigned int bits) override; + storvector_t convertToISCVector() const override; + std::string getPubKeyHash() const override; + std::string sign(const std::string& msg) const override; + bool verify(const std::string& msg, const std::string& signature) const override; + std::string getPublicKeyString() const override; + int getBits() const override; + void fromISCMap(DNSKEYRecordContent& drc, std::map& stormap) override; + void fromPublicKeyString(const std::string& content) override; + void fromPEMString(DNSKEYRecordContent& drc, const std::string& raw) override + {} + + static std::shared_ptr maker(unsigned int algorithm) + { + return std::make_shared(algorithm); + } + +private: + unsigned char d_pubkey[DECAF_EDDSA_25519_PUBLIC_BYTES]; + unsigned char d_seckey[DECAF_EDDSA_25519_PRIVATE_BYTES]; +}; + +void DecafED25519DNSCryptoKeyEngine::create(unsigned int bits) +{ + if(bits != (unsigned int)getBits()) { + throw runtime_error("Unsupported key length of "+std::to_string(bits)+" bits requested, DecafED25519 class"); + } + + SpongeRng rng("/dev/urandom"); + + typename EdDSA::PrivateKey priv(rng); + typename EdDSA::PublicKey pub(priv); + + priv.serialize_into(d_seckey); + pub.serialize_into(d_pubkey); +} + +int DecafED25519DNSCryptoKeyEngine::getBits() const +{ + return DECAF_EDDSA_25519_PRIVATE_BYTES << 3; +} + +DNSCryptoKeyEngine::storvector_t DecafED25519DNSCryptoKeyEngine::convertToISCVector() const +{ + /* + Private-key-format: v1.2 + Algorithm: 15 (ED25519) + PrivateKey: ODIyNjAzODQ2MjgwODAxMjI2NDUxOTAyMDQxNDIyNjI= + */ + + storvector_t storvector; + + storvector.push_back(make_pair("Algorithm", "15 (ED25519)")); + storvector.push_back(make_pair("PrivateKey", string((char*)d_seckey, DECAF_EDDSA_25519_PRIVATE_BYTES))); + + return storvector; +} + +void DecafED25519DNSCryptoKeyEngine::fromISCMap(DNSKEYRecordContent& drc, std::map& stormap ) +{ + /* + Private-key-format: v1.2 + Algorithm: 15 (ED25519) + PrivateKey: ODIyNjAzODQ2MjgwODAxMjI2NDUxOTAyMDQxNDIyNjI= + */ + + drc.d_algorithm = pdns_stou(stormap["algorithm"]); + string privateKey = stormap["privatekey"]; + + if (privateKey.length() != DECAF_EDDSA_25519_PRIVATE_BYTES) + throw runtime_error("Private key size mismatch in ISCMap, DecafED25519 class"); + + typename EdDSA::PrivateKey priv(Block((const unsigned char*)privateKey.c_str(), DECAF_EDDSA_25519_PRIVATE_BYTES)); + typename EdDSA::PublicKey pub(priv); + + priv.serialize_into(d_seckey); + pub.serialize_into(d_pubkey); +} + +std::string DecafED25519DNSCryptoKeyEngine::getPubKeyHash() const +{ + return this->getPublicKeyString(); +} + +std::string DecafED25519DNSCryptoKeyEngine::getPublicKeyString() const +{ + return string((char*)d_pubkey, DECAF_EDDSA_25519_PUBLIC_BYTES); +} + +void DecafED25519DNSCryptoKeyEngine::fromPublicKeyString(const std::string& input) +{ + if (input.length() != DECAF_EDDSA_25519_PUBLIC_BYTES) + throw runtime_error("Public key size mismatch, DecafED25519 class"); + + memcpy(d_pubkey, input.c_str(), DECAF_EDDSA_25519_PUBLIC_BYTES); +} + +std::string DecafED25519DNSCryptoKeyEngine::sign(const std::string& msg) const +{ + typename EdDSA::PrivateKey priv(Block(d_seckey, DECAF_EDDSA_25519_PRIVATE_BYTES)); + + SecureBuffer message(msg.begin(), msg.end()); + + SecureBuffer sig = priv.sign(message); + + return string(sig.begin(), sig.end()); +} + +bool DecafED25519DNSCryptoKeyEngine::verify(const std::string& msg, const std::string& signature) const +{ + if (signature.length() != DECAF_EDDSA_25519_SIGNATURE_BYTES) + return false; + + typename EdDSA::PublicKey pub(Block(d_pubkey, DECAF_EDDSA_25519_PUBLIC_BYTES)); + + SecureBuffer sig(signature.begin(), signature.end()); + SecureBuffer message(msg.begin(), msg.end()); + + try { + pub.verify(sig, message); + } catch(CryptoException) { + return false; + } + + return true; +} + + +class DecafED448DNSCryptoKeyEngine : public DNSCryptoKeyEngine +{ +public: + explicit DecafED448DNSCryptoKeyEngine(unsigned int algo) : DNSCryptoKeyEngine(algo) + { + + } + string getName() const override { return "Decaf ED448"; } + void create(unsigned int bits) override; + storvector_t convertToISCVector() const override; + std::string getPubKeyHash() const override; + std::string sign(const std::string& msg) const override; + bool verify(const std::string& msg, const std::string& signature) const override; + std::string getPublicKeyString() const override; + int getBits() const override; + void fromISCMap(DNSKEYRecordContent& drc, std::map& stormap) override; + void fromPublicKeyString(const std::string& content) override; + void fromPEMString(DNSKEYRecordContent& drc, const std::string& raw) override + {} + + static std::shared_ptr maker(unsigned int algorithm) + { + return std::make_shared(algorithm); + } + +private: + unsigned char d_pubkey[DECAF_EDDSA_448_PUBLIC_BYTES]; + unsigned char d_seckey[DECAF_EDDSA_448_PRIVATE_BYTES]; +}; + +void DecafED448DNSCryptoKeyEngine::create(unsigned int bits) +{ + if(bits != (unsigned int)getBits()) { + throw runtime_error("Unsupported key length of "+std::to_string(bits)+" bits requested, DecafED448 class"); + } + + SpongeRng rng("/dev/urandom"); + + typename EdDSA::PrivateKey priv(rng); + typename EdDSA::PublicKey pub(priv); + + priv.serialize_into(d_seckey); + pub.serialize_into(d_pubkey); +} + +int DecafED448DNSCryptoKeyEngine::getBits() const +{ + return DECAF_EDDSA_448_PRIVATE_BYTES << 3; +} + +DNSCryptoKeyEngine::storvector_t DecafED448DNSCryptoKeyEngine::convertToISCVector() const +{ + /* + Private-key-format: v1.2 + Algorithm: 16 (ED448) + PrivateKey: xZ+5Cgm463xugtkY5B0Jx6erFTXp13rYegst0qRtNsOYnaVpMx0Z/c5EiA9x8wWbDDct/U3FhYWA + */ + + storvector_t storvector; + + storvector.push_back(make_pair("Algorithm", "16 (ED448)")); + storvector.push_back(make_pair("PrivateKey", string((char*)d_seckey, DECAF_EDDSA_448_PRIVATE_BYTES))); + + return storvector; +} + +void DecafED448DNSCryptoKeyEngine::fromISCMap(DNSKEYRecordContent& drc, std::map& stormap ) +{ + /* + Private-key-format: v1.2 + Algorithm: 16 (ED448) + PrivateKey: xZ+5Cgm463xugtkY5B0Jx6erFTXp13rYegst0qRtNsOYnaVpMx0Z/c5EiA9x8wWbDDct/U3FhYWA + */ + + drc.d_algorithm = pdns_stou(stormap["algorithm"]); + string privateKey = stormap["privatekey"]; + + if (privateKey.length() != DECAF_EDDSA_448_PRIVATE_BYTES) + throw runtime_error("Private key size mismatch in ISCMap, DecafED448 class"); + + typename EdDSA::PrivateKey priv(Block((const unsigned char*)privateKey.c_str(), DECAF_EDDSA_448_PRIVATE_BYTES)); + typename EdDSA::PublicKey pub(priv); + + priv.serialize_into(d_seckey); + pub.serialize_into(d_pubkey); +} + +std::string DecafED448DNSCryptoKeyEngine::getPubKeyHash() const +{ + return this->getPublicKeyString(); +} + +std::string DecafED448DNSCryptoKeyEngine::getPublicKeyString() const +{ + return string((char*)d_pubkey, DECAF_EDDSA_448_PUBLIC_BYTES); +} + +void DecafED448DNSCryptoKeyEngine::fromPublicKeyString(const std::string& input) +{ + if (input.length() != DECAF_EDDSA_448_PUBLIC_BYTES) + throw runtime_error("Public key size mismatch, DecafED448 class"); + + memcpy(d_pubkey, input.c_str(), DECAF_EDDSA_448_PUBLIC_BYTES); +} + +std::string DecafED448DNSCryptoKeyEngine::sign(const std::string& msg) const +{ + typename EdDSA::PrivateKey priv(Block(d_seckey, DECAF_EDDSA_448_PRIVATE_BYTES)); + + SecureBuffer message(msg.begin(), msg.end()); + + SecureBuffer sig = priv.sign(message); + + return string(sig.begin(), sig.end()); +} + +bool DecafED448DNSCryptoKeyEngine::verify(const std::string& msg, const std::string& signature) const +{ + if (signature.length() != DECAF_EDDSA_448_SIGNATURE_BYTES) + return false; + + typename EdDSA::PublicKey pub(Block(d_pubkey, DECAF_EDDSA_448_PUBLIC_BYTES)); + + SecureBuffer sig(signature.begin(), signature.end()); + SecureBuffer message(msg.begin(), msg.end()); + + try { + pub.verify(sig, message); + } catch(CryptoException) { + return false; + } + + return true; +} + + +namespace { +struct LoaderDecafStruct +{ + LoaderDecafStruct() + { + DNSCryptoKeyEngine::report(15, &DecafED25519DNSCryptoKeyEngine::maker); + DNSCryptoKeyEngine::report(16, &DecafED448DNSCryptoKeyEngine::maker); + } +} loaderdecaf; +} diff --git a/pdns/dnssecinfra.cc b/pdns/dnssecinfra.cc index 2ec9549cd..474a597d4 100644 --- a/pdns/dnssecinfra.cc +++ b/pdns/dnssecinfra.cc @@ -239,6 +239,8 @@ pair DNSCryptoKeyEngine::testMakers(unsigned int alg bits=256; else if(algo == 14) // ECDSAP384SHA384 bits = 384; + else if(algo == 16) // ED448 + bits = 456; else throw runtime_error("Can't guess key size for algorithm "+std::to_string(algo)); diff --git a/pdns/dnsseckeeper.hh b/pdns/dnsseckeeper.hh index da79a796a..b24d55538 100644 --- a/pdns/dnsseckeeper.hh +++ b/pdns/dnsseckeeper.hh @@ -51,7 +51,8 @@ public: ECCGOST=12, ECDSA256=13, ECDSA384=14, - ED25519=15 + ED25519=15, + ED448=16 }; struct KeyMetaData @@ -92,6 +93,7 @@ public: if (!algorithm.compare("ecdsa256")) return ECDSA256; if (!algorithm.compare("ecdsa384")) return ECDSA384; if (!algorithm.compare("ed25519")) return ED25519; + if (!algorithm.compare("ed448")) return ED448; return -1; } @@ -126,6 +128,8 @@ public: return "ECDSAP384SHA384"; case ED25519: return "ED25519"; + case ED448: + return "ED448"; case 252: return "INDIRECT"; case 253: diff --git a/pdns/pdnsutil.cc b/pdns/pdnsutil.cc index b4f80ab98..fba2c3828 100644 --- a/pdns/pdnsutil.cc +++ b/pdns/pdnsutil.cc @@ -2012,8 +2012,11 @@ try cout<<" [content..] Add one or more records to ZONE"<