]> 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)
committerAlexander A. Klimov <alexander.klimov@icinga.com>
Fri, 22 Feb 2019 15:59:36 +0000 (16:59 +0100)
lib/base/utility.cpp
lib/base/utility.hpp
lib/remote/apiuser.cpp

index e6582de590deba303f75f40a85e64ada8a35cf3a..e44d50f239629b6c804ac5492437e6ae972ab88e 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>
@@ -1948,3 +1949,38 @@ String Utility::GetFromEnvironment(const String& env)
        else
                return String(envValue);
 }
+
+/**
+ * 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 b07ca1474ebf3f16e0c0cfc86b1c896db5113c13..67d2a27680b305b23416412b4e7c0c170c92c0cd 100644 (file)
@@ -151,6 +151,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;