]> git.ipfire.org Git - thirdparty/pdns.git/commitdiff
Attempt at constant-time credentials verification without sodium
authorRemi Gacogne <remi.gacogne@powerdns.com>
Tue, 30 Mar 2021 17:25:11 +0000 (19:25 +0200)
committerRemi Gacogne <remi.gacogne@powerdns.com>
Thu, 16 Sep 2021 12:12:27 +0000 (14:12 +0200)
pdns/Makefile.am
pdns/credentials.cc
pdns/credentials.hh
pdns/dns_random.hh
pdns/dnsdistdist/Makefile.am
pdns/dnssecinfra.cc
pdns/misc.cc
pdns/misc.hh
pdns/recursordist/Makefile.am

index 6e14a2effa920c8d903573f257c66730142f5363..5982b705723624d65d763d1768c1ed4dd8cd5c18 100644 (file)
@@ -17,6 +17,7 @@ AM_CXXFLAGS = \
 
 AM_LDFLAGS = \
        $(PROGRAM_LDFLAGS) \
+       $(LIBCRYPTO_LIBS) \
        $(THREADFLAGS)
 
 AM_LFLAGS = -i
index c25ed3c195a82bf2d13cbd407ec797295c61e2e6..e829a412885b20f6a3c6b359c616860cc349e463 100644 (file)
@@ -28,6 +28,7 @@
 #endif
 
 #include "credentials.hh"
+#include "misc.hh"
 
 std::string hashPassword(const std::string& password)
 {
@@ -106,6 +107,8 @@ CredentialsHolder::CredentialsHolder(std::string&& password)
     }
   }
   else {
+    d_fallbackHashPerturb = random();
+    d_fallbackHash = burtle(reinterpret_cast<const unsigned char*>(password.data()), password.size(), d_fallbackHashPerturb);
     d_credentials = std::move(password);
   }
 
@@ -122,6 +125,8 @@ CredentialsHolder::~CredentialsHolder()
 #ifdef HAVE_LIBSODIUM
   sodium_munlock(d_credentials.data(), d_credentials.size());
 #endif
+  d_fallbackHashPerturb = 0;
+  d_fallbackHash = 0;
 }
 
 bool CredentialsHolder::matches(const std::string& password) const
@@ -130,8 +135,12 @@ bool CredentialsHolder::matches(const std::string& password) const
     return verifyPassword(d_credentials, password);
   }
   else {
-#warning FIXME: would be better to do a poor-man hashing using burtle and a random seed first
-    return password == d_credentials;
+    uint32_t fallback = burtle(reinterpret_cast<const unsigned char*>(password.data()), password.size(), d_fallbackHashPerturb);
+    if (fallback != d_fallbackHash) {
+      return false;
+    }
+
+    return constantTimeStringEquals(password, d_credentials);
   }
 }
 
index 1b5a67f6794b2132b6b7af3c2bd2cfa2693c8708..03978d1655fcc65f562749811d2d89564bb11341 100644 (file)
@@ -48,5 +48,7 @@ public:
 
 private:
   std::string d_credentials;
+  uint32_t d_fallbackHashPerturb;
+  uint32_t d_fallbackHash{0};
   bool d_hashed{false};
 };
index b968b0766b0d432422e200c8db8ccad82476dc50..52f2812314af02c6e461786c3c2641c122a47303 100644 (file)
@@ -48,4 +48,3 @@ namespace pdns {
     }
   };
 }
-
index ab7f66149061790f1c9c178b00d63b19e2131adf..277b1a9b98fc22cdb13c07ff07491bfbb6128439 100644 (file)
@@ -351,6 +351,7 @@ endif
 
 if HAVE_LIBCRYPTO
 dnsdist_LDADD += $(LIBCRYPTO_LDFLAGS) $(LIBCRYPTO_LIBS)
+testrunner_LDADD += $(LIBCRYPTO_LDFLAGS) $(LIBCRYPTO_LIBS)
 dnsdist_SOURCES += ipcipher.cc ipcipher.hh
 endif
 
index e2db27f07ca6bc26be71b4d93bd683a020804c20..e4f77e795f2278e3805f168708498fb7de7b222e 100644 (file)
@@ -632,27 +632,6 @@ static string calculateHMAC(const std::string& key, const std::string& text, TSI
   return string((char*) hash, outlen);
 }
 
-static bool constantTimeStringEquals(const std::string& a, const std::string& b)
-{
-  if (a.size() != b.size()) {
-    return false;
-  }
-  const size_t size = a.size();
-#ifdef HAVE_CRYPTO_MEMCMP
-  return CRYPTO_memcmp(a.c_str(), b.c_str(), size) == 0;
-#else
-  const volatile unsigned char *_a = (const volatile unsigned char *) a.c_str();
-  const volatile unsigned char *_b = (const volatile unsigned char *) b.c_str();
-  unsigned char res = 0;
-
-  for (size_t idx = 0; idx < size; idx++) {
-    res |= _a[idx] ^ _b[idx];
-  }
-
-  return res == 0;
-#endif
-}
-
 static string makeTSIGPayload(const string& previous, const char* packetBegin, size_t packetSize, const DNSName& tsigKeyName, const TSIGRecordContent& trc, bool timersonly)
 {
   string message;
index af667bf668b2439a4e9e5e0a138c5f72c9c2837f..ca480c8f54c1c9601c69785dff8a5ebecc5fae83 100644 (file)
@@ -1645,3 +1645,29 @@ size_t parseSVCBValueList(const std::string &in, vector<std::string> &val) {
   parseSVCBValueListFromParsedRFC1035CharString(parsed, val);
   return ret;
 };
+
+#ifdef HAVE_CRYPTO_MEMCMP
+#include <openssl/crypto.h>
+#endif
+
+bool constantTimeStringEquals(const std::string& a, const std::string& b)
+{
+  if (a.size() != b.size()) {
+    return false;
+  }
+  const size_t size = a.size();
+#ifdef HAVE_CRYPTO_MEMCMP
+  return CRYPTO_memcmp(a.c_str(), b.c_str(), size) == 0;
+#else
+  const volatile unsigned char *_a = (const volatile unsigned char *) a.c_str();
+  const volatile unsigned char *_b = (const volatile unsigned char *) b.c_str();
+  unsigned char res = 0;
+
+  for (size_t idx = 0; idx < size; idx++) {
+    res |= _a[idx] ^ _b[idx];
+  }
+
+  return res == 0;
+#endif
+}
+
index 3c54329e0ee3d81f9fe0ae58b04a5fbf59c7b26f..6307293f55cb91bd934da9192e6d003ee4d39c3b 100644 (file)
@@ -633,6 +633,8 @@ size_t parseSVCBValueList(const std::string &in, vector<std::string> &val);
 
 std::string makeLuaString(const std::string& in);
 
+bool constantTimeStringEquals(const std::string& a, const std::string& b);
+
 // Used in NID and L64 records
 struct NodeOrLocatorID { uint8_t content[8]; };
 
index 39a5fb3c2428ec6286b85a5989e5be37f65ab146..d4d49da8cce4ca78db931327d724ff2cccf4f3b6 100644 (file)
@@ -367,7 +367,8 @@ pdns_recursor_SOURCES += \
        sodiumsigners.cc
 pdns_recursor_LDADD += $(LIBSODIUM_LIBS)
 
-rec_control_LDADD = $(LIBSODIUM_LIBS)
+rec_control_LDADD = $(LIBSODIUM_LIBS) \
+       $(LIBCRYPTO_LIBS)
 
 testrunner_SOURCES += \
        sodiumsigners.cc