diff options
author | Patrick Freed <patrick.freed@mongodb.com> | 2018-11-30 16:40:02 -0500 |
---|---|---|
committer | Patrick Freed <patrick.freed@mongodb.com> | 2018-12-20 17:11:29 -0500 |
commit | 916a5553a2db8ae7553fea7c3703ef8fef75b055 (patch) | |
tree | d1cb1af190d93a2f010e2c8a11663366b4979bf7 /src/mongo/crypto | |
parent | cf30414301d665e151b3d75eab7de59023514871 (diff) | |
download | mongo-916a5553a2db8ae7553fea7c3703ef8fef75b055.tar.gz |
SERVER-37565 Unlock memory held during SCRAM authentication
This fixes a bug where the server would crash if a large number of parallel connections occurred at once
Diffstat (limited to 'src/mongo/crypto')
-rw-r--r-- | src/mongo/crypto/mechanism_scram.h | 64 |
1 files changed, 49 insertions, 15 deletions
diff --git a/src/mongo/crypto/mechanism_scram.h b/src/mongo/crypto/mechanism_scram.h index 37614357f73..2a8cd79e72f 100644 --- a/src/mongo/crypto/mechanism_scram.h +++ b/src/mongo/crypto/mechanism_scram.h @@ -139,6 +139,47 @@ template <typename T> bool operator!=(const Presecrets<T>& lhs, const Presecrets<T>& rhs) { return !(lhs == rhs); } +template <typename HashBlock> +struct SecretsHolder { + HashBlock clientKey; + HashBlock storedKey; + HashBlock serverKey; +}; + +template <typename HashBlock> +class LockedSecretsPolicy { +public: + LockedSecretsPolicy() = default; + + const SecretsHolder<HashBlock>* operator->() const { + return &(*_holder); + } + SecretsHolder<HashBlock>* operator->() { + return &(*_holder); + } + +private: + using SecureSecrets = SecureAllocatorAuthDomain::SecureHandle<SecretsHolder<HashBlock>>; + + SecureSecrets _holder; +}; + +template <typename HashBlock> +class UnlockedSecretsPolicy { +public: + UnlockedSecretsPolicy() = default; + + const SecretsHolder<HashBlock>* operator->() const { + return &_holder; + } + + SecretsHolder<HashBlock>* operator->() { + return &_holder; + } + +private: + SecretsHolder<HashBlock> _holder; +}; /* Stores all of the keys, generated from a password, needed for a client or server to perform a * SCRAM handshake. @@ -146,21 +187,13 @@ bool operator!=(const Presecrets<T>& lhs, const Presecrets<T>& rhs) { * May be unpopulated. SCRAMSecrets created via the default constructor are unpopulated. * The behavior is undefined if the accessors are called when unpopulated. */ -template <typename HashBlock> +template <typename HashBlock, template <typename> class MemoryPolicy = LockedSecretsPolicy> class Secrets { -private: - struct SecretsHolder { - HashBlock clientKey; - HashBlock storedKey; - HashBlock serverKey; - }; - using SecureSecrets = SecureAllocatorAuthDomain::SecureHandle<SecretsHolder>; - public: Secrets() = default; Secrets(StringData client, StringData stored, StringData server) - : _ptr(std::make_shared<SecureSecrets>()) { + : _ptr(std::make_shared<MemoryPolicy<HashBlock>>()) { if (!client.empty()) { (*_ptr)->clientKey = uassertStatusOK(HashBlock::fromBuffer( reinterpret_cast<const unsigned char*>(client.rawData()), client.size())); @@ -171,13 +204,13 @@ public: reinterpret_cast<const unsigned char*>(server.rawData()), stored.size())); } - Secrets(const HashBlock& saltedPassword) : _ptr(std::make_shared<SecureSecrets>()) { + Secrets(const HashBlock& saltedPassword) : _ptr(std::make_shared<MemoryPolicy<HashBlock>>()) { // ClientKey := HMAC(saltedPassword, "Client Key") - (*_ptr)->clientKey = HashBlock::computeHmac( + (*_ptr)->clientKey = (HashBlock::computeHmac( saltedPassword.data(), saltedPassword.size(), reinterpret_cast<const unsigned char*>(kClientKeyConst.rawData()), - kClientKeyConst.size()); + kClientKeyConst.size())); // StoredKey := H(clientKey) (*_ptr)->storedKey = HashBlock::computeHash(clientKey().data(), clientKey().size()); @@ -255,7 +288,8 @@ public: static BSONObj generateCredentials(const std::vector<uint8_t>& salt, const std::string& password, int iterationCount) { - Secrets<HashBlock> secrets(Presecrets<HashBlock>(password, salt, iterationCount)); + Secrets<HashBlock, MemoryPolicy> secrets( + Presecrets<HashBlock>(password, salt, iterationCount)); const auto encodedSalt = base64::encode(reinterpret_cast<const char*>(salt.data()), salt.size()); return BSON(kIterationCountFieldName << iterationCount << kSaltFieldName << encodedSalt @@ -289,7 +323,7 @@ public: } private: - std::shared_ptr<SecureSecrets> _ptr; + std::shared_ptr<MemoryPolicy<HashBlock>> _ptr; }; } // namespace scram |