]> git.ipfire.org Git - thirdparty/pdns.git/commitdiff
Merge pull request #5429 from gertvdijk/rec-docs-dont-query
authorPieter Lexis <pieterlexis@users.noreply.github.com>
Wed, 21 Jun 2017 08:57:07 +0000 (10:57 +0200)
committerGitHub <noreply@github.com>
Wed, 21 Jun 2017 08:57:07 +0000 (10:57 +0200)
rec: Document behaviour of dont-query with forward-zones.

16 files changed:
build-scripts/build-auth-rpm
configure.ac
m4/pdns_check_libdecaf.m4 [new file with mode: 0644]
pdns/Makefile.am
pdns/README-dnsdist.md
pdns/dbdnsseckeeper.cc
pdns/decafsigners.cc [new file with mode: 0644]
pdns/dnssecinfra.cc
pdns/dnsseckeeper.hh
pdns/pdnsutil.cc
pdns/recursordist/Makefile.am
pdns/recursordist/configure.ac
pdns/recursordist/decafsigners.cc [new symlink]
pdns/recursordist/m4/pdns_check_libdecaf.m4 [new symlink]
pdns/test-signers.cc [new file with mode: 0644]
pdns/version.cc

index 8966d5ce1a2bccde12de6fadac174a2a3c4e5eb2..91ff63c52910e6d594ebcaab7c7dc3056eaafb13 100755 (executable)
@@ -490,6 +490,7 @@ fi
 %doc %{_defaultdocdir}/%{name}/schema.mysql.sql
 %doc %{_defaultdocdir}/%{name}/nodnssec-3.x_to_3.4.0_schema.mysql.sql
 %doc %{_defaultdocdir}/%{name}/dnssec-3.x_to_3.4.0_schema.mysql.sql
+%doc %{_defaultdocdir}/%{name}/3.4.0_to_4.1.0_schema.mysql.sql
 %{_libdir}/%{name}/libgmysqlbackend.so
 
 %files backend-postgresql
index 5d228ed3918cbb09836db758a146cc89e8345b61..a5a597cbf799d9908ef57233e5100e8ee07b58fa 100644 (file)
@@ -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 (file)
index 0000000..6e4e823
--- /dev/null
@@ -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"
+  )
+])
index 8d8b509ec9956e79c459ef0530b6f07cf28f4806..43515c44107bd827bd392f46546774fcc03f5d6b 100644 (file)
@@ -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)
@@ -1121,6 +1131,7 @@ testrunner_SOURCES = \
        base64.cc \
        bindlexer.l \
        bindparser.yy \
+       dbdnsseckeeper.cc \
        dns.cc \
        dns_random.cc \
        dnsbackend.cc \
@@ -1131,6 +1142,7 @@ testrunner_SOURCES = \
        dnsparser.hh dnsparser.cc \
        dnsrecords.cc \
        dnssecinfra.cc \
+       dnssecsigner.cc \
        dnswriter.cc \
        ednsoptions.cc ednsoptions.hh \
        ednssubnet.cc \
@@ -1166,6 +1178,7 @@ testrunner_SOURCES = \
        test-nmtree.cc \
        test-packetcache_cc.cc \
        test-rcpgenerator_cc.cc \
+       test-signers.cc \
        test-sha_hh.cc \
        test-statbag_cc.cc \
        test-tsig.cc \
@@ -1191,6 +1204,16 @@ testrunner_SOURCES += pkcs11signers.cc pkcs11signers.hh
 testrunner_LDADD += $(P11KIT1_LIBS)
 endif
 
+if LIBSODIUM
+testrunner_SOURCES += sodiumsigners.cc
+testrunner_LDADD += $(LIBSODIUM_LIBS)
+endif
+
+if LIBDECAF
+testrunner_SOURCES += decafsigners.cc
+testrunner_LDADD += $(LIBDECAF_LIBS)
+endif
+
 pdns_control_SOURCES = \
        arguments.cc \
        dynloader.cc \
index 1a8c0a6adff90cf60964f48f87ea277456b42405..827a7e9007147511f2680f717f493e6f27b8c562 100644 (file)
@@ -471,6 +471,7 @@ single operation with `setRules()`:
 > setRules( { newRuleAction(TCPRule(), AllowAction()), newRuleAction(AllRule(), DropAction()) } )
 ```
 
+NOTE: Adding large numbers of rules (200+) is slow, and will also impact performance significantly. Instead of creating numerous rules, consider using smaller numbers of individual rules that match large numbers of domains or IP addresses, for example using a `SuffixMatchNodeRule` or a `NetmaskGroupRule`. These rules are optimized for hosting thousands or millions of domain names or IP addresses. 
 
 More power
 ----------
index 35e70977092469113c6af49da258d66ef991c712..c121f125ba89db0d7413eacf490193174dd6a6ac 100644 (file)
@@ -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 (file)
index 0000000..5e2bbc4
--- /dev/null
@@ -0,0 +1,293 @@
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+#include <decaf.hxx>
+#include <decaf/eddsa.hxx>
+#include <decaf/spongerng.hxx>
+
+#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<std::string, std::string>& stormap) override;
+  void fromPublicKeyString(const std::string& content) override;
+  void fromPEMString(DNSKEYRecordContent& drc, const std::string& raw) override
+  {}
+
+  static std::shared_ptr<DNSCryptoKeyEngine> maker(unsigned int algorithm)
+  {
+    return std::make_shared<DecafED25519DNSCryptoKeyEngine>(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<IsoEd25519>::PrivateKey priv(rng);
+  typename EdDSA<IsoEd25519>::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<std::string, std::string>& 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<IsoEd25519>::PrivateKey priv(Block((const unsigned char*)privateKey.c_str(), DECAF_EDDSA_25519_PRIVATE_BYTES));
+  typename EdDSA<IsoEd25519>::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<IsoEd25519>::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<IsoEd25519>::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<std::string, std::string>& stormap) override;
+  void fromPublicKeyString(const std::string& content) override;
+  void fromPEMString(DNSKEYRecordContent& drc, const std::string& raw) override
+  {}
+
+  static std::shared_ptr<DNSCryptoKeyEngine> maker(unsigned int algorithm)
+  {
+    return std::make_shared<DecafED448DNSCryptoKeyEngine>(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<Ed448Goldilocks>::PrivateKey priv(rng);
+  typename EdDSA<Ed448Goldilocks>::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<std::string, std::string>& 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<Ed448Goldilocks>::PrivateKey priv(Block((const unsigned char*)privateKey.c_str(), DECAF_EDDSA_448_PRIVATE_BYTES));
+  typename EdDSA<Ed448Goldilocks>::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<Ed448Goldilocks>::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<Ed448Goldilocks>::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;
+}
index 2ec9549cda3feec9c759ea783cbcc4f2e6c7ae23..474a597d40af72e5c1fc28fa4b88ef000a04e7cf 100644 (file)
@@ -239,6 +239,8 @@ pair<unsigned int, unsigned int> 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));
 
index da79a796adadf64af0e7db183019854dfabf4986..b24d55538096bd1b3c663a636afea86efc4728b9 100644 (file)
@@ -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:
index b4f80ab986db939a2d13ef4280ec32bc3a42c314..fba2c382868dd2935430d122bb143693f2b7a2e9 100644 (file)
@@ -2012,8 +2012,11 @@ try
     cout<<"             [content..]           Add one or more records to ZONE"<<endl;
     cout<<"add-zone-key ZONE {zsk|ksk} [BITS] [active|inactive]"<<endl;
     cout<<"             [rsasha1|rsasha256|rsasha512|gost|ecdsa256|ecdsa384";
-#ifdef HAVE_LIBSODIUM
+#if defined(HAVE_LIBSODIUM) || defined(HAVE_LIBDECAF)
     cout<<"|ed25519";
+#endif
+#ifdef HAVE_LIBDECAF
+    cout<<"|ed448";
 #endif
     cout<<"]"<<endl;
     cout<<"                                   Add a ZSK or KSK to zone and specify algo&bits"<<endl;
@@ -2853,6 +2856,8 @@ try
           bits = 256;
         else if(algorithm == 14)
           bits = 384;
+        else if(algorithm == 16) // ED448
+          bits = 456;
         else {
           throw runtime_error("Can't guess key size for algorithm "+std::to_string(algorithm));
         }
index 72ab7451bbcb5cf7408a75f5dbc70401ac912269..2299dfdfc098da0404a85864a9df50528c38764d 100644 (file)
@@ -259,6 +259,12 @@ pdns_recursor_SOURCES += \
 pdns_recursor_LDADD += $(LIBSODIUM_LIBS)
 endif
 
+if LIBDECAF
+pdns_recursor_SOURCES += \
+       decafsigners.cc
+pdns_recursor_LDADD += $(LIBDECAF_LIBS)
+endif
+
 if MALLOC_TRACE
 pdns_recursor_SOURCES += \
        malloctrace.cc \
index 6f411e4a4e381d2b1b55d76d8ee01d58b41f6c82..58b9bb2cc018b6afad3bd54dbb4fd09774bc3fb1 100644 (file)
@@ -117,6 +117,7 @@ PDNS_CHECK_LIBCRYPTO([
 )
 PDNS_CHECK_LIBCRYPTO_ECDSA
 PDNS_CHECK_LIBSODIUM
+PDNS_CHECK_LIBDECAF
 
 PDNS_WITH_NET_SNMP
 
@@ -212,6 +213,10 @@ AS_IF([test "x$LIBSODIUM_LIBS" != "x"],
   [AC_MSG_NOTICE([libsodium ed25519: yes])],
   [AC_MSG_NOTICE([libsodium ed25519: no])]
 )
+AS_IF([test "x$LIBDECAF_LIBS" != "x"],
+  [AC_MSG_NOTICE([libdecaf ed25519 and ed448: yes])],
+  [AC_MSG_NOTICE([libdecaf ed25519 and ed448: no])]
+)
 AS_IF([test "x$PROTOBUF_LIBS" != "x" -a x"$PROTOC" != "x"],
   [AC_MSG_NOTICE([Protobuf: yes])],
   [AC_MSG_NOTICE([Protobuf: no])]
diff --git a/pdns/recursordist/decafsigners.cc b/pdns/recursordist/decafsigners.cc
new file mode 120000 (symlink)
index 0000000..4aaed31
--- /dev/null
@@ -0,0 +1 @@
+../decafsigners.cc
\ No newline at end of file
diff --git a/pdns/recursordist/m4/pdns_check_libdecaf.m4 b/pdns/recursordist/m4/pdns_check_libdecaf.m4
new file mode 120000 (symlink)
index 0000000..01bef52
--- /dev/null
@@ -0,0 +1 @@
+../../../m4/pdns_check_libdecaf.m4
\ No newline at end of file
diff --git a/pdns/test-signers.cc b/pdns/test-signers.cc
new file mode 100644 (file)
index 0000000..043b1ab
--- /dev/null
@@ -0,0 +1,105 @@
+#define BOOST_TEST_DYN_LINK
+#define BOOST_TEST_NO_MAIN
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+#include <boost/test/unit_test.hpp>
+#include <boost/assign/list_of.hpp>
+
+#include <boost/tuple/tuple.hpp>
+#include <boost/scoped_ptr.hpp>
+
+#include "base64.hh"
+#include "dnsseckeeper.hh"
+#include "dnssecinfra.hh"
+#include "misc.hh"
+
+BOOST_AUTO_TEST_SUITE(test_signers)
+
+#if defined(HAVE_LIBSODIUM) || defined(HAVE_LIBDECAF)
+BOOST_AUTO_TEST_CASE(test_ed25519_signer) {
+    vector<std::shared_ptr<DNSRecordContent> > rrs;
+    DNSName qname("example.com.");
+    DNSKEYRecordContent drc;
+
+    // TODO: make this a collection of inputs and resulting sigs for various algos
+    shared_ptr<DNSCryptoKeyEngine> engine = DNSCryptoKeyEngine::makeFromISCString(drc,
+"Private-key-format: v1.2\n"
+"Algorithm: 15 (ED25519)\n"
+"PrivateKey: ODIyNjAzODQ2MjgwODAxMjI2NDUxOTAyMDQxNDIyNjI=");
+
+    DNSSECPrivateKey dpk;
+    dpk.setKey(engine);
+
+    reportBasicTypes();
+
+    rrs.push_back(DNSRecordContent::makeunique(QType::MX, 1, "10 mail.example.com."));
+
+    RRSIGRecordContent rrc;
+    rrc.d_originalttl = 3600;
+    rrc.d_sigexpire = 1440021600;
+    rrc.d_siginception = 1438207200;
+    rrc.d_signer = qname;
+    rrc.d_type = QType::MX;
+    rrc.d_labels = 2;
+    // TODO: derive the next two from the key
+    rrc.d_tag = 3613;
+    rrc.d_algorithm = 15;
+
+    string msg = getMessageForRRSET(qname, rrc, rrs, false);
+
+    // vector extracted from https://gitlab.labs.nic.cz/labs/ietf/blob/master/dnskey.py (rev 476d6ded) by printing signature_data
+    BOOST_CHECK_EQUAL(makeHexDump(msg), "00 0f 0f 02 00 00 0e 10 55 d4 fc 60 55 b9 4c e0 0e 1d 07 65 78 61 6d 70 6c 65 03 63 6f 6d 00 07 65 78 61 6d 70 6c 65 03 63 6f 6d 00 00 0f 00 01 00 00 0e 10 00 14 00 0a 04 6d 61 69 6c 07 65 78 61 6d 70 6c 65 03 63 6f 6d 00 ");
+
+    string signature = engine->sign(msg);
+    string b64 = Base64Encode(signature);
+
+    // vector verified from dnskey.py as above, and confirmed with https://www.rfc-editor.org/errata_search.php?rfc=8080&eid=4935
+    BOOST_CHECK_EQUAL(b64, "oL9krJun7xfBOIWcGHi7mag5/hdZrKWw15jPGrHpjQeRAvTdszaPD+QLs3fx8A4M3e23mRZ9VrbpMngwcrqNAg==");
+}
+#endif
+
+#ifdef HAVE_LIBDECAF
+BOOST_AUTO_TEST_CASE(test_ed448_signer) {
+    vector<std::shared_ptr<DNSRecordContent> > rrs;
+    DNSName qname("example.com.");
+    DNSKEYRecordContent drc;
+
+    // TODO: make this a collection of inputs and resulting sigs for various algos
+    shared_ptr<DNSCryptoKeyEngine> engine = DNSCryptoKeyEngine::makeFromISCString(drc,
+"Private-key-format: v1.2\n"
+"Algorithm: 16 (ED448)\n"
+"PrivateKey: xZ+5Cgm463xugtkY5B0Jx6erFTXp13rYegst0qRtNsOYnaVpMx0Z/c5EiA9x8wWbDDct/U3FhYWA\n");
+
+    DNSSECPrivateKey dpk;
+    dpk.setKey(engine);
+
+    reportBasicTypes();
+
+    rrs.push_back(DNSRecordContent::makeunique(QType::MX, 1, "10 mail.example.com."));
+
+    RRSIGRecordContent rrc;
+    rrc.d_originalttl = 3600;
+    rrc.d_sigexpire = 1440021600;
+    rrc.d_siginception = 1438207200;
+    rrc.d_signer = qname;
+    rrc.d_type = QType::MX;
+    rrc.d_labels = 2;
+    // TODO: derive the next two from the key
+    rrc.d_tag = 9713;
+    rrc.d_algorithm = 16;
+
+    string msg = getMessageForRRSET(qname, rrc, rrs, false);
+
+    // vector extracted from https://gitlab.labs.nic.cz/labs/ietf/blob/master/dnskey.py (rev 476d6ded) by printing signature_data
+    BOOST_CHECK_EQUAL(makeHexDump(msg), "00 0f 10 02 00 00 0e 10 55 d4 fc 60 55 b9 4c e0 25 f1 07 65 78 61 6d 70 6c 65 03 63 6f 6d 00 07 65 78 61 6d 70 6c 65 03 63 6f 6d 00 00 0f 00 01 00 00 0e 10 00 14 00 0a 04 6d 61 69 6c 07 65 78 61 6d 70 6c 65 03 63 6f 6d 00 ");
+
+    string signature = engine->sign(msg);
+    string b64 = Base64Encode(signature);
+
+    // vector verified from dnskey.py as above, and confirmed with https://www.rfc-editor.org/errata_search.php?rfc=8080&eid=4935
+    BOOST_CHECK_EQUAL(b64, "3cPAHkmlnxcDHMyg7vFC34l0blBhuG1qpwLmjInI8w1CMB29FkEAIJUA0amxWndkmnBZ6SKiwZSAxGILn/NBtOXft0+Gj7FSvOKxE/07+4RQvE581N3Aj/JtIyaiYVdnYtyMWbSNyGEY2213WKsJlwEA");
+}
+#endif
+
+BOOST_AUTO_TEST_SUITE_END()
index 98189300f11155b8e5abb51bf8447d367f6e2582..4ed8b7be0b1a17179bc9f6afecbf96a58e57ef43 100644 (file)
@@ -88,6 +88,9 @@ void showBuildConfiguration()
 #endif
 #ifdef HAVE_LIBSODIUM
     "sodium " <<
+#endif
+#ifdef HAVE_LIBDECAF
+    "decaf " <<
 #endif
     "openssl " <<
 #ifdef HAVE_LIBDL