]> granicus.if.org Git - icinga2/commitdiff
Secure ApiUser::GetByAuthHeader() against timing attacks
authorAlexander A. Klimov <alexander.klimov@icinga.com>
Fri, 22 Feb 2019 10:37:07 +0000 (11:37 +0100)
committerMichael Friedrich <michael.friedrich@icinga.com>
Mon, 25 Feb 2019 12:34:51 +0000 (13:34 +0100)
(cherry picked from commit 9558ebc0f46febc7692bbb65394708b78b276d46)

lib/base/utility.cpp
lib/base/utility.hpp
lib/remote/apiuser.cpp

index cf8bc588fce639f7e828ace14137ae05f1339b0e..bf50159e58a0f004fb0857bab9637a254c60b6e2 100644 (file)
@@ -26,6 +26,7 @@
 #include "base/utility.hpp"
 #include "base/json.hpp"
 #include "base/objectlock.hpp"
+#include <cstdint>
 #include <mmatch.h>
 #include <boost/lexical_cast.hpp>
 #include <boost/thread/tss.hpp>
@@ -1949,3 +1950,38 @@ String Utility::GetFromEnvironment(const String& env)
        return String();
 #endif /* _WIN32 */
 }
+
+/**
+ * Compare the password entered by a client with the actual password.
+ * The comparision is safe against timing attacks.
+ */
+bool Utility::ComparePasswords(const String& enteredPassword, const String& actualPassword)
+{
+       volatile const char * volatile enteredPasswordCStr = enteredPassword.CStr();
+       volatile size_t enteredPasswordLen = enteredPassword.GetLength();
+
+       volatile const char * volatile actualPasswordCStr = actualPassword.CStr();
+       volatile size_t actualPasswordLen = actualPassword.GetLength();
+
+       volatile uint_fast8_t result = enteredPasswordLen == actualPasswordLen;
+
+       if (result) {
+               auto cStr (actualPasswordCStr);
+               auto len (actualPasswordLen);
+
+               actualPasswordCStr = cStr;
+               actualPasswordLen = len;
+       } else {
+               auto cStr (enteredPasswordCStr);
+               auto len (enteredPasswordLen);
+
+               actualPasswordCStr = cStr;
+               actualPasswordLen = len;
+       }
+
+       for (volatile size_t i = 0; i < enteredPasswordLen; ++i) {
+               result &= uint_fast8_t(enteredPasswordCStr[i] == actualPasswordCStr[i]);
+       }
+
+       return result;
+}
index e75ebfefafc1398fe2f9e3cdf2f70b3960e8aff4..0adfc9e5cf05c401049e44b260d5cf7b0caf0a2f 100644 (file)
@@ -149,6 +149,8 @@ public:
 
        static String GetFromEnvironment(const String& env);
 
+       static bool ComparePasswords(const String& enteredPassword, const String& actualPassword);
+
 #ifdef I2_DEBUG
        static void SetTime(double);
        static void IncrementTime(double);
index 346aadbefa1405a0416a35a96aad055ac488a7aa..320935a0710344ee286ee3c7a489eb7f8c4bafa8 100644 (file)
@@ -22,6 +22,7 @@
 #include "base/configtype.hpp"
 #include "base/base64.hpp"
 #include "base/tlsutility.hpp"
+#include "base/utility.hpp"
 
 using namespace icinga;
 
@@ -63,7 +64,7 @@ ApiUser::Ptr ApiUser::GetByAuthHeader(const String& auth_header)
         */
        if (!user || password.IsEmpty())
                return nullptr;
-       else if (user && user->GetPassword() != password)
+       else if (user && !Utility::ComparePasswords(password, user->GetPassword()))
                return nullptr;
 
        return user;