diff options
author | Mark Benvenuto <mark.benvenuto@mongodb.com> | 2015-11-10 14:55:20 -0500 |
---|---|---|
committer | Mark Benvenuto <mark.benvenuto@mongodb.com> | 2015-11-13 11:40:46 -0500 |
commit | 618a5ef908ac5787eb80166ada3914f4db7d3c37 (patch) | |
tree | e4174420d436d3c0ee72b40d38d11fc083120da7 | |
parent | caf1dfe036900fdf134a7b448cd0dbb38592f08e (diff) | |
download | mongo-618a5ef908ac5787eb80166ada3914f4db7d3c37.tar.gz |
SERVER-21016 Use constant time comparison for SCRAM1 signature comparisons
-rw-r--r-- | src/mongo/crypto/mechanism_scram.cpp | 30 |
1 files changed, 29 insertions, 1 deletions
diff --git a/src/mongo/crypto/mechanism_scram.cpp b/src/mongo/crypto/mechanism_scram.cpp index 8ec28b3e2c6..086e9943c4c 100644 --- a/src/mongo/crypto/mechanism_scram.cpp +++ b/src/mongo/crypto/mechanism_scram.cpp @@ -196,6 +196,27 @@ std::string generateClientProof(const unsigned char saltedPassword[hashSize], return base64::encode(reinterpret_cast<char*>(clientProof), hashSize); } +/** + * Compare two arrays of bytes for equality in constant time. + * + * This means that the function runs for the same amount of time even if they differ. Unlike memcmp, + * this function does not exit on the first difference. + * + * Returns true if the two arrays are equal. + * + * TODO: evaluate if LTO inlines or changes the code flow of this function. + */ +NOINLINE_DECL +bool memequal(volatile const unsigned char* s1, volatile const unsigned char* s2, size_t length) { + unsigned char ret = 0; + + for (size_t i = 0; i < length; ++i) { + ret |= s1[i] ^ s2[i]; + } + + return ret == 0; +} + bool verifyServerSignature(const unsigned char saltedPassword[hashSize], const std::string& authMessage, const std::string& receivedServerSignature) { @@ -222,7 +243,14 @@ bool verifyServerSignature(const unsigned char saltedPassword[hashSize], std::string encodedServerSignature = base64::encode(reinterpret_cast<char*>(serverSignature), sizeof(serverSignature)); - return (receivedServerSignature == encodedServerSignature); + + if (encodedServerSignature.size() != receivedServerSignature.size()) { + return false; + } + + return memequal(reinterpret_cast<const unsigned char*>(encodedServerSignature.c_str()), + reinterpret_cast<const unsigned char*>(receivedServerSignature.c_str()), + encodedServerSignature.size()); } } // namespace scram |