Use SecureString where there is data to be cleansed

SecureString has quite a few places it should be used in the user
management code.

Tested: ran set password, test password, and other commands

Change-Id: Ia53bc914d25f7965c3e72d5cf18346e0fa9339b9
Signed-off-by: Vernon Mauery <vernon.mauery@linux.intel.com>
diff --git a/user_channel/usercommands.cpp b/user_channel/usercommands.cpp
index c48c476..f6190d7 100644
--- a/user_channel/usercommands.cpp
+++ b/user_channel/usercommands.cpp
@@ -358,28 +358,33 @@
     }
     else if (req->operation == testPassword)
     {
-        auto password = ipmiUserGetPassword(userName);
-        std::string testPassword(
-            reinterpret_cast<const char*>(req->userPassword), 0,
-            passwordLength);
-        // Note: For security reasons password size won't be compared and
-        // wrong password size completion code will not be returned if size
-        // doesn't match as specified in IPMI specification.
-        if (password != testPassword)
+        SecureString password = ipmiUserGetPassword(userName);
+        SecureString testPassword(
+            reinterpret_cast<const char*>(req->userPassword), passwordLength);
+        // constant time string compare: always compare exactly as many bytes
+        // as the length of the input, resizing the actual password to match,
+        // maintaining a knowledge if the sizes differed originally
+        static const std::array<char, maxIpmi20PasswordSize> empty = {'\0'};
+        size_t cmpLen = testPassword.size();
+        bool pwLenDiffers = password.size() != cmpLen;
+        const char* cmpPassword = nullptr;
+        if (pwLenDiffers)
+        {
+            cmpPassword = empty.data();
+        }
+        else
+        {
+            cmpPassword = password.data();
+        }
+        bool pwBad = CRYPTO_memcmp(cmpPassword, testPassword.data(), cmpLen);
+        pwBad |= pwLenDiffers;
+        if (pwBad)
         {
             log<level::DEBUG>("Test password failed",
                               entry("USER-ID=%d", (uint8_t)req->userId));
-            // Clear sensitive data
-            OPENSSL_cleanse(testPassword.data(), testPassword.length());
-            OPENSSL_cleanse(password.data(), password.length());
-
             return static_cast<Cc>(
                 IPMISetPasswordReturnCodes::ipmiCCPasswdFailMismatch);
         }
-        // Clear sensitive data
-        OPENSSL_cleanse(testPassword.data(), testPassword.length());
-        OPENSSL_cleanse(password.data(), password.length());
-
         return ccSuccess;
     }
     return ccInvalidFieldRequest;