summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSara Golemon <sara.golemon@mongodb.com>2018-01-11 14:27:11 -0500
committerSara Golemon <sara.golemon@mongodb.com>2018-01-25 16:00:56 -0500
commit298f7758a070630917fe6c67603a2951cab29322 (patch)
tree86d88f44ad23526f3b175c8defe7f93c669e7402
parentacf7bec77edde339ed6fb1bb89f7f03888144476 (diff)
downloadmongo-298f7758a070630917fe6c67603a2951cab29322.tar.gz
SERVER-32836 Refactor SCRAM mechanism to be block independent
-rw-r--r--src/mongo/client/SConscript2
-rw-r--r--src/mongo/client/sasl_scramsha1_client_conversation.cpp10
-rw-r--r--src/mongo/client/sasl_scramsha1_client_conversation.h2
-rw-r--r--src/mongo/client/scram_sha1_client_cache.cpp10
-rw-r--r--src/mongo/client/scram_sha1_client_cache.h10
-rw-r--r--src/mongo/crypto/SConscript16
-rw-r--r--src/mongo/crypto/mechanism_scram.cpp215
-rw-r--r--src/mongo/crypto/mechanism_scram.h311
-rw-r--r--src/mongo/crypto/mechanism_scram_test.cpp84
-rw-r--r--src/mongo/db/auth/SConscript3
-rw-r--r--src/mongo/db/auth/authorization_manager_test.cpp2
-rw-r--r--src/mongo/db/auth/authorization_session_test.cpp2
-rw-r--r--src/mongo/db/auth/sasl_authentication_session_test.cpp2
-rw-r--r--src/mongo/db/auth/sasl_plain_server_conversation.cpp6
-rw-r--r--src/mongo/db/auth/sasl_scramsha1_server_conversation.cpp14
-rw-r--r--src/mongo/db/auth/sasl_scramsha1_test.cpp46
-rw-r--r--src/mongo/db/auth/security_key.cpp12
-rw-r--r--src/mongo/db/auth/user_document_parser_test.cpp2
-rw-r--r--src/mongo/db/commands/user_management_commands.cpp4
-rw-r--r--src/mongo/db/logical_session_id_test.cpp4
20 files changed, 367 insertions, 390 deletions
diff --git a/src/mongo/client/SConscript b/src/mongo/client/SConscript
index c1f90812b70..8b92c437ea5 100644
--- a/src/mongo/client/SConscript
+++ b/src/mongo/client/SConscript
@@ -106,8 +106,8 @@ saslClientEnv.Library(
target='sasl_client',
source=saslClientSource,
LIBDEPS=[
+ '$BUILD_DIR/mongo/base/secure_allocator',
'$BUILD_DIR/mongo/bson/util/bson_extract',
- '$BUILD_DIR/mongo/crypto/scramauth',
'$BUILD_DIR/mongo/executor/remote_command',
'$BUILD_DIR/mongo/rpc/command_status',
'$BUILD_DIR/mongo/rpc/metadata',
diff --git a/src/mongo/client/sasl_scramsha1_client_conversation.cpp b/src/mongo/client/sasl_scramsha1_client_conversation.cpp
index 1c04d395708..0dc84fc0818 100644
--- a/src/mongo/client/sasl_scramsha1_client_conversation.cpp
+++ b/src/mongo/client/sasl_scramsha1_client_conversation.cpp
@@ -179,7 +179,7 @@ StatusWith<bool> SaslSCRAMSHA1ClientConversation::_secondStep(const std::vector<
return StatusWith<bool>(ex.toStatus());
}
- scram::SCRAMPresecrets presecrets(
+ scram::SHA1Presecrets presecrets(
_saslClientSession->getParameter(SaslClientSession::parameterPassword).toString(),
std::vector<std::uint8_t>(decodedSalt.begin(), decodedSalt.end()),
iterationCount);
@@ -191,16 +191,16 @@ StatusWith<bool> SaslSCRAMSHA1ClientConversation::_secondStep(const std::vector<
_credentials = _clientCache->getCachedSecrets(targetHost.getValue(), presecrets);
if (!_credentials) {
- _credentials = scram::generateSecrets(presecrets);
+ _credentials = presecrets;
_clientCache->setCachedSecrets(
std::move(targetHost.getValue()), std::move(presecrets), _credentials);
}
} else {
- _credentials = scram::generateSecrets(presecrets);
+ _credentials = presecrets;
}
- std::string clientProof = scram::generateClientProof(_credentials, _authMessage);
+ std::string clientProof = _credentials.generateClientProof(_authMessage);
StringBuilder sb;
sb << "c=biws,r=" << nonce << ",p=" << clientProof;
@@ -241,7 +241,7 @@ StatusWith<bool> SaslSCRAMSHA1ClientConversation::_thirdStep(const std::vector<s
}
bool validServerSignature =
- scram::verifyServerSignature(_credentials, _authMessage, input[0].substr(2));
+ _credentials.verifyServerSignature(_authMessage, base64::decode(input[0].substr(2)));
if (!validServerSignature) {
*outputData = "e=Invalid server signature";
diff --git a/src/mongo/client/sasl_scramsha1_client_conversation.h b/src/mongo/client/sasl_scramsha1_client_conversation.h
index dcf8a5686e4..fa6dbc4e6a6 100644
--- a/src/mongo/client/sasl_scramsha1_client_conversation.h
+++ b/src/mongo/client/sasl_scramsha1_client_conversation.h
@@ -82,7 +82,7 @@ private:
std::string _authMessage;
// Secrets and secrets cache
- scram::SCRAMSecrets _credentials;
+ scram::SHA1Secrets _credentials;
SCRAMSHA1ClientCache* const _clientCache;
// client and server nonce concatenated
diff --git a/src/mongo/client/scram_sha1_client_cache.cpp b/src/mongo/client/scram_sha1_client_cache.cpp
index ca3bf9eca14..87f72c011da 100644
--- a/src/mongo/client/scram_sha1_client_cache.cpp
+++ b/src/mongo/client/scram_sha1_client_cache.cpp
@@ -32,8 +32,8 @@
namespace mongo {
-scram::SCRAMSecrets SCRAMSHA1ClientCache::getCachedSecrets(
- const HostAndPort& target, const scram::SCRAMPresecrets& presecrets) const {
+scram::SHA1Secrets SCRAMSHA1ClientCache::getCachedSecrets(
+ const HostAndPort& target, const scram::SHA1Presecrets& presecrets) const {
const stdx::lock_guard<stdx::mutex> lock(_hostToSecretsMutex);
// Search the cache for a record associated with the host we're trying to connect to.
@@ -42,7 +42,7 @@ scram::SCRAMSecrets SCRAMSHA1ClientCache::getCachedSecrets(
// Presecrets contain parameters provided by the server, which may change. If the
// cached presecrets don't match the presecrets we have on hand, we must not return the
// stale cached secrets. We'll need to rerun the SCRAM computation.
- const scram::SCRAMPresecrets& foundPresecrets = foundSecret->second.first;
+ const scram::SHA1Presecrets& foundPresecrets = foundSecret->second.first;
if (foundPresecrets == presecrets) {
return foundSecret->second.second;
}
@@ -51,8 +51,8 @@ scram::SCRAMSecrets SCRAMSHA1ClientCache::getCachedSecrets(
}
void SCRAMSHA1ClientCache::setCachedSecrets(HostAndPort target,
- scram::SCRAMPresecrets presecrets,
- scram::SCRAMSecrets secrets) {
+ scram::SHA1Presecrets presecrets,
+ scram::SHA1Secrets secrets) {
const stdx::lock_guard<stdx::mutex> lock(_hostToSecretsMutex);
decltype(_hostToSecrets)::iterator it;
diff --git a/src/mongo/client/scram_sha1_client_cache.h b/src/mongo/client/scram_sha1_client_cache.h
index ac6a139af2c..84f03397cfd 100644
--- a/src/mongo/client/scram_sha1_client_cache.h
+++ b/src/mongo/client/scram_sha1_client_cache.h
@@ -68,20 +68,20 @@ public:
* match those recorded for the hostname. Otherwise, no secrets
* are returned.
*/
- scram::SCRAMSecrets getCachedSecrets(const HostAndPort& target,
- const scram::SCRAMPresecrets& presecrets) const;
+ scram::SHA1Secrets getCachedSecrets(const HostAndPort& target,
+ const scram::SHA1Presecrets& presecrets) const;
/**
* Records a set of precomputed SCRAMSecrets for the specified
* host, along with the presecrets used to generate them.
*/
void setCachedSecrets(HostAndPort target,
- scram::SCRAMPresecrets presecrets,
- scram::SCRAMSecrets secrets);
+ scram::SHA1Presecrets presecrets,
+ scram::SHA1Secrets secrets);
private:
mutable stdx::mutex _hostToSecretsMutex;
- stdx::unordered_map<HostAndPort, std::pair<scram::SCRAMPresecrets, scram::SCRAMSecrets>>
+ stdx::unordered_map<HostAndPort, std::pair<scram::SHA1Presecrets, scram::SHA1Secrets>>
_hostToSecrets;
};
diff --git a/src/mongo/crypto/SConscript b/src/mongo/crypto/SConscript
index 0846f31dd22..381405abd94 100644
--- a/src/mongo/crypto/SConscript
+++ b/src/mongo/crypto/SConscript
@@ -67,14 +67,6 @@ if env.TargetOSIs('darwin', 'macOS'):
'sha256_block',
])
-env.Library('scramauth',
- ['mechanism_scram.cpp'],
- LIBDEPS=['$BUILD_DIR/mongo/base',
- '$BUILD_DIR/mongo/base/secure_allocator',
- '$BUILD_DIR/mongo/util/secure_compare_memory',
- '$BUILD_DIR/mongo/util/secure_zero_memory',
- 'sha_block_${MONGO_CRYPTO}'])
-
env.CppUnitTest('sha1_block_test',
['sha1_block_test.cpp'],
LIBDEPS=['sha_block_${MONGO_CRYPTO}'])
@@ -82,3 +74,11 @@ env.CppUnitTest('sha1_block_test',
env.CppUnitTest('sha256_block_test',
['sha256_block_test.cpp'],
LIBDEPS=['sha_block_${MONGO_CRYPTO}'])
+
+env.CppUnitTest('mechanism_scram_test',
+ ['mechanism_scram_test.cpp'],
+ LIBDEPS_PRIVATE=[
+ '$BUILD_DIR/mongo/base',
+ '$BUILD_DIR/mongo/base/secure_allocator',
+ 'sha_block_${MONGO_CRYPTO}',
+ ])
diff --git a/src/mongo/crypto/mechanism_scram.cpp b/src/mongo/crypto/mechanism_scram.cpp
deleted file mode 100644
index d0dc5965c99..00000000000
--- a/src/mongo/crypto/mechanism_scram.cpp
+++ /dev/null
@@ -1,215 +0,0 @@
-/*
- * Copyright (C) 2014 10gen Inc.
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License, version 3,
- * as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- *
- * As a special exception, the copyright holders give permission to link the
- * code of portions of this program with the OpenSSL library under certain
- * conditions as described in each individual source file and distribute
- * linked combinations including the program with the OpenSSL library. You
- * must comply with the GNU Affero General Public License in all respects for
- * all of the code used other than as permitted herein. If you modify file(s)
- * with this exception, you may extend this exception to your version of the
- * file(s), but you are not obligated to do so. If you do not wish to do so,
- * delete this exception statement from your version. If you delete this
- * exception statement from all source files in the program, then also delete
- * it in the license file.
- */
-
-#include "mongo/platform/basic.h"
-
-#include "mongo/crypto/mechanism_scram.h"
-
-#include <vector>
-
-#include "mongo/platform/random.h"
-#include "mongo/util/base64.h"
-#include "mongo/util/secure_compare_memory.h"
-#include "mongo/util/secure_zero_memory.h"
-
-namespace mongo {
-namespace scram {
-
-using std::unique_ptr;
-
-// Compute the SCRAM step Hi() as defined in RFC5802
-static SHA1Block HMACIteration(const unsigned char input[],
- size_t inputLen,
- const unsigned char salt[],
- size_t saltLen,
- unsigned int iterationCount) {
- SHA1Block output;
- SHA1Block intermediateDigest;
- // Reserve a 20 byte block for the initial key. We use 16 byte salts, and must reserve an extra
- // 4 bytes for a suffix mandated by RFC5802.
- std::array<std::uint8_t, 20> startKey;
-
- uassert(17450, "invalid salt length provided", saltLen + 4 == startKey.size());
- std::copy(salt, salt + saltLen, startKey.begin());
-
- startKey[saltLen] = 0;
- startKey[saltLen + 1] = 0;
- startKey[saltLen + 2] = 0;
- startKey[saltLen + 3] = 1;
-
- // U1 = HMAC(input, salt + 0001)
- output = SHA1Block::computeHmac(input, inputLen, startKey.data(), startKey.size());
- intermediateDigest = output;
-
- // intermediateDigest contains Ui and output contains the accumulated XOR:ed result
- for (size_t i = 2; i <= iterationCount; i++) {
- intermediateDigest = SHA1Block::computeHmac(
- input, inputLen, intermediateDigest.data(), intermediateDigest.size());
- output.xorInline(intermediateDigest);
- }
-
- return output;
-}
-
-// Iterate the hash function to generate SaltedPassword
-SHA1Block generateSaltedPassword(const SCRAMPresecrets& presecrets) {
- // saltedPassword = Hi(hashedPassword, salt)
- SHA1Block saltedPassword =
- HMACIteration(reinterpret_cast<const unsigned char*>(presecrets.hashedPassword.c_str()),
- presecrets.hashedPassword.size(),
- presecrets.salt.data(),
- presecrets.salt.size(),
- presecrets.iterationCount);
-
- return saltedPassword;
-}
-
-SCRAMSecrets generateSecrets(const SCRAMPresecrets& presecrets) {
- SHA1Block saltedPassword = generateSaltedPassword(presecrets);
- return generateSecrets(saltedPassword);
-}
-
-SCRAMSecrets generateSecrets(const SHA1Block& saltedPassword) {
- auto generateAndStoreSecrets = [&saltedPassword](
- SHA1Block& clientKey, SHA1Block& storedKey, SHA1Block& serverKey) {
-
- // ClientKey := HMAC(saltedPassword, "Client Key")
- clientKey =
- SHA1Block::computeHmac(saltedPassword.data(),
- saltedPassword.size(),
- reinterpret_cast<const unsigned char*>(clientKeyConst.data()),
- clientKeyConst.size());
-
- // StoredKey := H(clientKey)
- storedKey = SHA1Block::computeHash(clientKey.data(), clientKey.size());
-
- // ServerKey := HMAC(SaltedPassword, "Server Key")
- serverKey =
- SHA1Block::computeHmac(saltedPassword.data(),
- saltedPassword.size(),
- reinterpret_cast<const unsigned char*>(serverKeyConst.data()),
- serverKeyConst.size());
- };
- return SCRAMSecrets(std::move(generateAndStoreSecrets));
-}
-
-
-BSONObj generateCredentials(const std::string& hashedPassword, int iterationCount) {
- const int saltLenQWords = 2;
-
- // Generate salt
- uint64_t userSalt[saltLenQWords];
-
- unique_ptr<SecureRandom> sr(SecureRandom::create());
-
- userSalt[0] = sr->nextInt64();
- userSalt[1] = sr->nextInt64();
- std::string encodedUserSalt =
- base64::encode(reinterpret_cast<char*>(userSalt), sizeof(userSalt));
-
- // Compute SCRAM secrets serverKey and storedKey
- auto secrets = generateSecrets(
- SCRAMPresecrets(hashedPassword,
- std::vector<std::uint8_t>(reinterpret_cast<std::uint8_t*>(userSalt),
- reinterpret_cast<std::uint8_t*>(userSalt) +
- saltLenQWords * sizeof(uint64_t)),
- iterationCount));
-
- std::string encodedStoredKey = secrets->storedKey.toString();
- std::string encodedServerKey = secrets->serverKey.toString();
-
- return BSON(iterationCountFieldName << iterationCount << saltFieldName << encodedUserSalt
- << storedKeyFieldName
- << encodedStoredKey
- << serverKeyFieldName
- << encodedServerKey);
-}
-
-std::string generateClientProof(const SCRAMSecrets& clientCredentials,
- const std::string& authMessage) {
- // ClientSignature := HMAC(StoredKey, AuthMessage)
- SHA1Block clientSignature =
- SHA1Block::computeHmac(clientCredentials->storedKey.data(),
- clientCredentials->storedKey.size(),
- reinterpret_cast<const unsigned char*>(authMessage.c_str()),
- authMessage.size());
-
- clientSignature.xorInline(clientCredentials->clientKey);
- return clientSignature.toString();
-}
-
-bool verifyServerSignature(const SCRAMSecrets& clientCredentials,
- const std::string& authMessage,
- const std::string& receivedServerSignature) {
- // ServerSignature := HMAC(ServerKey, AuthMessage)
- SHA1Block serverSignature =
- SHA1Block::computeHmac(clientCredentials->serverKey.data(),
- clientCredentials->serverKey.size(),
- reinterpret_cast<const unsigned char*>(authMessage.c_str()),
- authMessage.size());
-
- std::string encodedServerSignature = serverSignature.toString();
-
- if (encodedServerSignature.size() != receivedServerSignature.size()) {
- return false;
- }
-
- return consttimeMemEqual(
- reinterpret_cast<const unsigned char*>(encodedServerSignature.c_str()),
- reinterpret_cast<const unsigned char*>(receivedServerSignature.c_str()),
- encodedServerSignature.size());
-}
-
-bool verifyClientProof(StringData clientProof, StringData storedKey, StringData authMessage) {
- // ClientSignature := HMAC(StoredKey, AuthMessage)
- SHA1Block clientSignature =
- SHA1Block::computeHmac(reinterpret_cast<const unsigned char*>(storedKey.rawData()),
- storedKey.size(),
- reinterpret_cast<const unsigned char*>(authMessage.rawData()),
- authMessage.size());
-
- auto clientProofSHA1Status = SHA1Block::fromBuffer(
- reinterpret_cast<const uint8_t*>(clientProof.rawData()), clientProof.size());
- uassertStatusOK(clientProofSHA1Status);
- clientSignature.xorInline(clientProofSHA1Status.getValue());
-
- // StoredKey := H(clientSignature)
- SHA1Block computedStoredKey =
- SHA1Block::computeHash(clientSignature.data(), clientSignature.size());
-
- if (storedKey.size() != computedStoredKey.size()) {
- return false;
- }
-
- return consttimeMemEqual(reinterpret_cast<const unsigned char*>(storedKey.rawData()),
- computedStoredKey.data(),
- computedStoredKey.size());
-}
-
-} // namespace scram
-} // namespace mongo
diff --git a/src/mongo/crypto/mechanism_scram.h b/src/mongo/crypto/mechanism_scram.h
index 25afe543bbb..741566252ab 100644
--- a/src/mongo/crypto/mechanism_scram.h
+++ b/src/mongo/crypto/mechanism_scram.h
@@ -28,151 +28,264 @@
#pragma once
+#include <array>
+#include <memory>
#include <string>
+#include <vector>
#include "mongo/base/secure_allocator.h"
#include "mongo/base/status.h"
#include "mongo/crypto/sha1_block.h"
#include "mongo/db/auth/authorization_manager.h"
#include "mongo/db/jsobj.h"
+#include "mongo/platform/random.h"
+#include "mongo/util/assert_util.h"
namespace mongo {
namespace scram {
-const std::string serverKeyConst = "Server Key";
-const std::string clientKeyConst = "Client Key";
+constexpr auto kServerKeyConst = "Server Key"_sd;
+constexpr auto kClientKeyConst = "Client Key"_sd;
-const std::string iterationCountFieldName = "iterationCount";
-const std::string saltFieldName = "salt";
-const std::string storedKeyFieldName = "storedKey";
-const std::string serverKeyFieldName = "serverKey";
+constexpr auto kIterationCountFieldName = "iterationCount"_sd;
+constexpr auto kSaltFieldName = "salt"_sd;
+constexpr auto kStoredKeyFieldName = "storedKey"_sd;
+constexpr auto kServerKeyFieldName = "serverKey"_sd;
-/*
- * The precursors necessary to perform the computation which produces SCRAMSecrets.
+const int kIterationCountMinimum = 4096;
+
+/* The precursors necessary to perform the computation which produces SCRAMSecrets.
* These are the original password, its salt, and the number of times it must be
* hashed to produce the SaltedPassword used to generate the rest of the SCRAMSecrets.
*/
-struct SCRAMPresecrets {
- SCRAMPresecrets(std::string hashedPassword,
- std::vector<std::uint8_t> salt_,
- size_t iterationCount_)
- : hashedPassword(std::move(hashedPassword)),
- salt(std::move(salt_)),
- iterationCount(iterationCount_) {
- uassert(ErrorCodes::BadValue,
- "Invalid salt for SCRAM mechanism",
- salt.size() >= kSaltLengthMin);
- }
-
- std::string hashedPassword;
- std::vector<std::uint8_t> salt;
- size_t iterationCount;
+template <typename HashBlock>
+class Presecrets {
+public:
+ Presecrets(std::string password, std::vector<std::uint8_t> salt, size_t iterationCount)
+ : _password(std::move(password)), _salt(std::move(salt)), _iterationCount(iterationCount) {
+ uassert(17450, "invalid salt length provided", _salt.size() == saltLength());
+ uassert(50662, "invalid iteration count", _iterationCount >= kIterationCountMinimum);
+ }
+
+ HashBlock generateSaltedPassword() const noexcept {
+ // saltedPassword = Hi(hashedPassword, salt)
+
+ // Reserve a HashBlock::kHashLength block for the initial key.
+ // We use saltLength() salts, and reserve the extra for a suffix mandated by RFC5802.
+ std::array<std::uint8_t, HashBlock::kHashLength> startKey;
+ std::copy(_salt.cbegin(), _salt.cend(), startKey.begin());
+ startKey[_salt.size() + 0] = 0;
+ startKey[_salt.size() + 1] = 0;
+ startKey[_salt.size() + 2] = 0;
+ startKey[_salt.size() + 3] = 1;
+
+ // U1 = HMAC(input, salt + 0001)
+ auto output =
+ HashBlock::computeHmac(reinterpret_cast<const unsigned char*>(_password.c_str()),
+ _password.size(),
+ startKey.data(),
+ startKey.size());
+ auto intermediate = output;
+
+ // intermediateDigest contains Ui and output contains the accumulated XOR:ed result
+ invariant(_iterationCount >= kIterationCountMinimum);
+ for (size_t i = 1; i < _iterationCount; ++i) {
+ intermediate =
+ HashBlock::computeHmac(reinterpret_cast<const unsigned char*>(_password.c_str()),
+ _password.size(),
+ intermediate.data(),
+ intermediate.size());
+ output.xorInline(intermediate);
+ }
+
+ return output;
+ }
+
+ static std::vector<std::uint8_t> generateSecureRandomSalt() {
+ // Express salt length as a number of quad words, rounded up.
+ constexpr auto qwords = (saltLength() + sizeof(std::int64_t) - 1) / sizeof(std::int64_t);
+ std::array<std::int64_t, qwords> userSalt;
+
+ std::unique_ptr<SecureRandom> sr(SecureRandom::create());
+ std::generate(userSalt.begin(), userSalt.end(), [&sr] { return sr->nextInt64(); });
+ return std::vector<std::uint8_t>(reinterpret_cast<std::uint8_t*>(userSalt.data()),
+ reinterpret_cast<std::uint8_t*>(userSalt.data()) +
+ saltLength());
+ }
private:
- static const size_t kSaltLengthMin = 16;
+ template <typename T>
+ friend bool operator==(const Presecrets<T>&, const Presecrets<T>&);
+
+ auto equalityLens() const {
+ return std::tie(_password, _salt, _iterationCount);
+ }
+
+ static constexpr auto saltLength() {
+ return HashBlock::kHashLength - 4;
+ }
+
+ std::string _password;
+ std::vector<std::uint8_t> _salt;
+ size_t _iterationCount;
};
-inline bool operator==(const SCRAMPresecrets& lhs, const SCRAMPresecrets& rhs) {
- return lhs.hashedPassword == rhs.hashedPassword && lhs.salt == rhs.salt &&
- lhs.iterationCount == rhs.iterationCount;
+template <typename T>
+bool operator==(const Presecrets<T>& lhs, const Presecrets<T>& rhs) {
+ return lhs.equalityLens() == rhs.equalityLens();
+}
+template <typename T>
+bool operator!=(const Presecrets<T>& lhs, const Presecrets<T>& rhs) {
+ return !(lhs == rhs);
}
-/*
- * Computes the SaltedPassword from password, salt and iterationCount.
- */
-SHA1Block generateSaltedPassword(const SCRAMPresecrets& presecrets);
-
-/*
- * Stores all of the keys, generated from a password, needed for a client or server to perform a
+/* Stores all of the keys, generated from a password, needed for a client or server to perform a
* SCRAM handshake.
* These keys are reference counted, and allocated using the SecureAllocator.
* May be unpopulated. SCRAMSecrets created via the default constructor are unpopulated.
* The behavior is undefined if the accessors are called when unpopulated.
*/
-class SCRAMSecrets {
+template <typename HashBlock>
+class Secrets {
private:
- struct SCRAMSecretsHolder {
- SHA1Block clientKey;
- SHA1Block storedKey;
- SHA1Block serverKey;
+ struct SecretsHolder {
+ HashBlock clientKey;
+ HashBlock storedKey;
+ HashBlock serverKey;
};
+ using SecureSecrets = SecureAllocatorAuthDomain::SecureHandle<SecretsHolder>;
public:
- // Creates an unpopulated SCRAMSecrets object.
- SCRAMSecrets() = default;
+ Secrets() = default;
- // Creates a populated SCRAMSecrets object. First, allocates secure storage, then provides it
- // to a callback, which fills the memory.
- template <typename T>
- explicit SCRAMSecrets(T initializationFun)
- : _ptr(std::make_shared<SecureAllocatorAuthDomain::SecureHandle<SCRAMSecretsHolder>>()) {
- initializationFun((*this)->clientKey, (*this)->storedKey, (*this)->serverKey);
+ Secrets(StringData client, StringData stored, StringData server)
+ : _ptr(std::make_shared<SecureSecrets>()) {
+ if (!client.empty()) {
+ (*_ptr)->clientKey = uassertStatusOK(HashBlock::fromBuffer(
+ reinterpret_cast<const unsigned char*>(client.rawData()), client.size()));
+ }
+ (*_ptr)->storedKey = uassertStatusOK(HashBlock::fromBuffer(
+ reinterpret_cast<const unsigned char*>(stored.rawData()), stored.size()));
+ (*_ptr)->serverKey = uassertStatusOK(HashBlock::fromBuffer(
+ reinterpret_cast<const unsigned char*>(server.rawData()), stored.size()));
}
- // Returns true if the underlying shared_pointer is populated.
- explicit operator bool() const {
- return static_cast<bool>(_ptr);
- }
+ Secrets(const HashBlock& saltedPassword) : _ptr(std::make_shared<SecureSecrets>()) {
+ // ClientKey := HMAC(saltedPassword, "Client Key")
+ (*_ptr)->clientKey = HashBlock::computeHmac(
+ saltedPassword.data(),
+ saltedPassword.size(),
+ reinterpret_cast<const unsigned char*>(kClientKeyConst.rawData()),
+ kClientKeyConst.size());
+ // StoredKey := H(clientKey)
+ (*_ptr)->storedKey = HashBlock::computeHash(clientKey().data(), clientKey().size());
- const SecureAllocatorAuthDomain::SecureHandle<SCRAMSecretsHolder>& operator*() const& {
- invariant(_ptr);
- return *_ptr;
+ // ServerKey := HMAC(SaltedPassword, "Server Key")
+ (*_ptr)->serverKey = HashBlock::computeHmac(
+ saltedPassword.data(),
+ saltedPassword.size(),
+ reinterpret_cast<const unsigned char*>(kServerKeyConst.rawData()),
+ kServerKeyConst.size());
}
- void operator*() && = delete;
+ Secrets(const Presecrets<HashBlock>& presecrets)
+ : Secrets(presecrets.generateSaltedPassword()) {}
- const SecureAllocatorAuthDomain::SecureHandle<SCRAMSecretsHolder>& operator->() const& {
- invariant(_ptr);
- return *_ptr;
+ std::string generateClientProof(StringData authMessage) const {
+ // ClientProof := HMAC(StoredKey, AuthMessage) ^ ClientKey
+ auto proof =
+ HashBlock::computeHmac(storedKey().data(),
+ storedKey().size(),
+ reinterpret_cast<const unsigned char*>(authMessage.rawData()),
+ authMessage.size());
+ proof.xorInline(clientKey());
+ return proof.toString();
}
- void operator->() && = delete;
+ bool verifyClientProof(StringData authMessage, StringData proof) const {
+ // ClientKey := HMAC(StoredKey, AuthMessage) ^ ClientProof
+ auto key =
+ HashBlock::computeHmac(storedKey().data(),
+ storedKey().size(),
+ reinterpret_cast<const unsigned char*>(authMessage.rawData()),
+ authMessage.size());
+ key.xorInline(uassertStatusOK(HashBlock::fromBuffer(
+ reinterpret_cast<const uint8_t*>(proof.rawData()), proof.size())));
-private:
- std::shared_ptr<SecureAllocatorAuthDomain::SecureHandle<SCRAMSecretsHolder>> _ptr;
-};
+ // StoredKey := H(ClientKey)
+ auto exp = HashBlock::computeHash(key.data(), key.size());
-/*
- * Computes the SCRAM secrets clientKey, storedKey, and serverKey using the salt 'salt'
- * and iteration count 'iterationCount' as defined in RFC5802 (server side).
- */
-SCRAMSecrets generateSecrets(const SCRAMPresecrets& presecrets);
+ if ((exp.size() != HashBlock::kHashLength) ||
+ (storedKey().size() != HashBlock::kHashLength)) {
+ return false;
+ }
-/*
- * Computes the ClientKey and StoredKey from SaltedPassword (client side).
- */
-SCRAMSecrets generateSecrets(const SHA1Block& saltedPassword);
+ return consttimeMemEqual(reinterpret_cast<const unsigned char*>(exp.data()),
+ storedKey().data(),
+ HashBlock::kHashLength);
+ }
+ std::string generateServerSignature(StringData authMessage) const {
+ // ServerSignature := HMAC(ServerKey, AuthMessage)
+ return HashBlock::computeHmac(serverKey().data(),
+ serverKey().size(),
+ reinterpret_cast<const unsigned char*>(authMessage.rawData()),
+ authMessage.size())
+ .toString();
+ }
+ bool verifyServerSignature(StringData authMessage, StringData sig) const {
+ // ServerSignature := HMAC(ServerKey, AuthMessage)
+ const auto exp =
+ HashBlock::computeHmac(serverKey().data(),
+ serverKey().size(),
+ reinterpret_cast<const unsigned char*>(authMessage.rawData()),
+ authMessage.size());
-/*
- * Generates the user salt and the SCRAM secrets storedKey and serverKey as
- * defined in RFC5802 (server side).
- */
-BSONObj generateCredentials(const std::string& hashedPassword, int iterationCount);
+ if ((sig.size() != HashBlock::kHashLength) || (exp.size() != HashBlock::kHashLength)) {
+ return false;
+ }
+ return consttimeMemEqual(reinterpret_cast<const unsigned char*>(sig.rawData()),
+ reinterpret_cast<const unsigned char*>(exp.data()),
+ HashBlock::kHashLength);
+ }
-/*
- * Computes the ClientProof from ClientKey, StoredKey, and authMessage (client side).
- */
-std::string generateClientProof(const SCRAMSecrets& clientCredentials,
- const std::string& authMessage);
+ static BSONObj generateCredentials(std::string password, int iterationCount) {
+ auto salt = Presecrets<HashBlock>::generateSecureRandomSalt();
+ Secrets<HashBlock> secrets(Presecrets<HashBlock>(password, salt, iterationCount));
+ const auto encodedSalt = base64::encode(reinterpret_cast<char*>(salt.data()), salt.size());
+ return BSON(kIterationCountFieldName << iterationCount << kSaltFieldName << encodedSalt
+ << kStoredKeyFieldName
+ << secrets.storedKey().toString()
+ << kServerKeyFieldName
+ << secrets.serverKey().toString());
+ }
-/*
- * Validates that the provided password 'hashedPassword' generates the serverKey
- * 'serverKey' given iteration count 'iterationCount' and salt 'salt'.
- */
-bool validatePassword(const std::string& hashedPassword,
- int iterationCount,
- const std::string& salt,
- const std::string& storedKey);
+ const HashBlock& clientKey() const {
+ auto& ret = (*_ptr)->clientKey;
+ uassert(
+ ErrorCodes::BadValue, "Invalid SCRAM client key", ret.size() == HashBlock::kHashLength);
+ return ret;
+ }
+ const HashBlock& storedKey() const {
+ auto& ret = (*_ptr)->storedKey;
+ uassert(
+ ErrorCodes::BadValue, "Invalid SCRAM stored key", ret.size() == HashBlock::kHashLength);
+ return ret;
+ }
+ const HashBlock& serverKey() const {
+ auto& ret = (*_ptr)->serverKey;
+ uassert(
+ ErrorCodes::BadValue, "Invalid SCRAM server key", ret.size() == HashBlock::kHashLength);
+ return ret;
+ }
-/*
- * Verifies ServerSignature (client side).
- */
-bool verifyServerSignature(const SCRAMSecrets& clientCredentials,
- const std::string& authMessage,
- const std::string& serverSignature);
+ operator bool() const {
+ return (bool)_ptr;
+ }
-/*
- * Verifies ClientProof (server side).
- */
-bool verifyClientProof(StringData clientProof, StringData storedKey, StringData authMessage);
+private:
+ std::shared_ptr<SecureSecrets> _ptr;
+};
+
+using SHA1Presecrets = Presecrets<SHA1Block>;
+using SHA1Secrets = Secrets<SHA1Block>;
} // namespace scram
} // namespace mongo
diff --git a/src/mongo/crypto/mechanism_scram_test.cpp b/src/mongo/crypto/mechanism_scram_test.cpp
new file mode 100644
index 00000000000..5e67a1dfaa9
--- /dev/null
+++ b/src/mongo/crypto/mechanism_scram_test.cpp
@@ -0,0 +1,84 @@
+/**
+ * Copyright (C) 2018 MongoDB Inc.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License, version 3,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * As a special exception, the copyright holders give permission to link the
+ * code of portions of this program with the OpenSSL library under certain
+ * conditions as described in each individual source file and distribute
+ * linked combinations including the program with the OpenSSL library. You
+ * must comply with the GNU Affero General Public License in all respects
+ * for all of the code used other than as permitted herein. If you modify
+ * file(s) with this exception, you may extend this exception to your
+ * version of the file(s), but you are not obligated to do so. If you do not
+ * wish to do so, delete this exception statement from your version. If you
+ * delete this exception statement from all source files in the program,
+ * then also delete it in the license file.
+ */
+
+#define MONGO_LOG_DEFAULT_COMPONENT ::mongo::logger::LogComponent::kDefault
+
+#include "mongo/platform/basic.h"
+
+#include "mongo/crypto/mechanism_scram.h"
+#include "mongo/unittest/unittest.h"
+#include "mongo/util/log.h"
+
+namespace mongo {
+namespace scram {
+namespace {
+
+TEST(MechanismScram, BasicVectors) {
+ const std::vector<uint8_t> kBadSha1Salt{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15};
+
+ ASSERT_EQ(kBadSha1Salt.size(), SHA1Block::kHashLength - 4);
+
+ SHA1Presecrets presecrets("password", kBadSha1Salt, 4096);
+ ASSERT_EQ(presecrets.generateSaltedPassword().toString(), "531aYHrF581Skow4E0gCWLw/Ibo=");
+
+ SHA1Secrets secrets(presecrets);
+ ASSERT_EQ(secrets.clientKey().toString(), "wiHbIsPcvJo230S6Qf5xYCDrhb0=");
+ ASSERT_EQ(secrets.storedKey().toString(), "SjXiaB2hLRr8aMUyXMVEw7H1jSI=");
+ ASSERT_EQ(secrets.serverKey().toString(), "FilAoFIclBukd3xZxBvYMXTU3HM=");
+
+ const StringData authMessage("secret");
+ auto proof = secrets.generateClientProof(authMessage);
+ ASSERT_EQ(proof, "y+cpoAm0YlN30GuNgN4B9xghi4E=");
+ ASSERT_TRUE(secrets.verifyClientProof(authMessage, base64::decode(proof)));
+
+ auto sig = secrets.generateServerSignature(authMessage);
+ ASSERT_EQ(sig, "kiZS90Kz4/yaYZn9JieHtcRzXR0=");
+ ASSERT_TRUE(secrets.verifyServerSignature(authMessage, base64::decode(sig)));
+}
+
+TEST(MechanismScram, generateCredentials) {
+ const auto bson = SHA1Secrets::generateCredentials("password", 4096);
+
+ ASSERT_EQ(bson.nFields(), 4);
+
+ ASSERT_TRUE(bson.hasField("salt"));
+ ASSERT_EQ(base64::decode(bson.getStringField("salt")).size(), SHA1Block::kHashLength - 4);
+
+ ASSERT_TRUE(bson.hasField("storedKey"));
+ ASSERT_EQ(base64::decode(bson.getStringField("storedKey")).size(), SHA1Block::kHashLength);
+
+ ASSERT_TRUE(bson.hasField("serverKey"));
+ ASSERT_EQ(base64::decode(bson.getStringField("serverKey")).size(), SHA1Block::kHashLength);
+
+ ASSERT_TRUE(bson.hasField("iterationCount"));
+ ASSERT_EQ(bson.getIntField("iterationCount"), 4096);
+}
+
+} // namespace
+} // namespace scram
+} // namespace mongo
diff --git a/src/mongo/db/auth/SConscript b/src/mongo/db/auth/SConscript
index 5e18c13d4b1..7c29c354026 100644
--- a/src/mongo/db/auth/SConscript
+++ b/src/mongo/db/auth/SConscript
@@ -74,9 +74,9 @@ env.Library(
'sasl_options',
'user_name',
'$BUILD_DIR/mongo/base',
+ '$BUILD_DIR/mongo/base/secure_allocator',
'$BUILD_DIR/mongo/bson/mutable/mutable_bson',
'$BUILD_DIR/mongo/bson/util/bson_extract',
- '$BUILD_DIR/mongo/crypto/scramauth',
'$BUILD_DIR/mongo/db/catalog/document_validation',
'$BUILD_DIR/mongo/db/common',
'$BUILD_DIR/mongo/db/mongod_options',
@@ -179,7 +179,6 @@ env.Library('saslauth',
'authmocks', # Wat?
'sasl_options',
'$BUILD_DIR/mongo/base/secure_allocator',
- '$BUILD_DIR/mongo/crypto/scramauth',
'$BUILD_DIR/mongo/db/commands/test_commands_enabled',
'$BUILD_DIR/mongo/util/net/network',
],
diff --git a/src/mongo/db/auth/authorization_manager_test.cpp b/src/mongo/db/auth/authorization_manager_test.cpp
index ddebeafefae..7beea3ede5a 100644
--- a/src/mongo/db/auth/authorization_manager_test.cpp
+++ b/src/mongo/db/auth/authorization_manager_test.cpp
@@ -178,7 +178,7 @@ public:
externalState->setAuthorizationManager(authzManager.get());
authzManager->setAuthEnabled(true);
- credentials = BSON("SCRAM-SHA-1" << scram::generateCredentials(
+ credentials = BSON("SCRAM-SHA-1" << scram::SHA1Secrets::generateCredentials(
"password", saslGlobalParams.scramIterationCount.load()));
}
diff --git a/src/mongo/db/auth/authorization_session_test.cpp b/src/mongo/db/auth/authorization_session_test.cpp
index 42a016a83ae..16599969c7d 100644
--- a/src/mongo/db/auth/authorization_session_test.cpp
+++ b/src/mongo/db/auth/authorization_session_test.cpp
@@ -112,7 +112,7 @@ public:
authzSession = stdx::make_unique<AuthorizationSessionForTest>(std::move(localSessionState));
authzManager->setAuthEnabled(true);
- credentials = BSON("SCRAM-SHA-1" << scram::generateCredentials(
+ credentials = BSON("SCRAM-SHA-1" << scram::SHA1Secrets::generateCredentials(
"a", saslGlobalParams.scramIterationCount.load()));
}
};
diff --git a/src/mongo/db/auth/sasl_authentication_session_test.cpp b/src/mongo/db/auth/sasl_authentication_session_test.cpp
index 355ccda35fa..dbd3e117ebe 100644
--- a/src/mongo/db/auth/sasl_authentication_session_test.cpp
+++ b/src/mongo/db/auth/sasl_authentication_session_test.cpp
@@ -78,7 +78,7 @@ SaslConversation::SaslConversation(std::string mech)
BSONObj()));
const auto authHash = (mech == "SCRAM-SHA-1") ? "frim" : createPasswordDigest("andy", "frim");
- const auto creds = BSON("SCRAM-SHA-1" << scram::generateCredentials(
+ const auto creds = BSON("SCRAM-SHA-1" << scram::SHA1Secrets::generateCredentials(
authHash, saslGlobalParams.scramIterationCount.load()));
ASSERT_OK(authManagerExternalState->insert(&opCtx,
diff --git a/src/mongo/db/auth/sasl_plain_server_conversation.cpp b/src/mongo/db/auth/sasl_plain_server_conversation.cpp
index 0c574a7f7fd..8acefa7b90d 100644
--- a/src/mongo/db/auth/sasl_plain_server_conversation.cpp
+++ b/src/mongo/db/auth/sasl_plain_server_conversation.cpp
@@ -108,14 +108,14 @@ StatusWith<bool> SaslPLAINServerConversation::step(StringData inputData, std::st
// Handle schemaVersion28SCRAM (SCRAM only mode)
std::string decodedSalt = base64::decode(creds.scram.salt);
- scram::SCRAMSecrets secrets = scram::generateSecrets(scram::SCRAMPresecrets(
+ scram::SHA1Secrets secrets(scram::SHA1Presecrets(
authDigest,
std::vector<std::uint8_t>(reinterpret_cast<const std::uint8_t*>(decodedSalt.c_str()),
reinterpret_cast<const std::uint8_t*>(decodedSalt.c_str()) + 16),
creds.scram.iterationCount));
if (creds.scram.storedKey !=
- base64::encode(reinterpret_cast<const char*>(secrets->storedKey.data()),
- secrets->storedKey.size())) {
+ base64::encode(reinterpret_cast<const char*>(secrets.storedKey().data()),
+ secrets.storedKey().size())) {
return StatusWith<bool>(ErrorCodes::AuthenticationFailed,
mongoutils::str::stream() << "Incorrect user name or password");
}
diff --git a/src/mongo/db/auth/sasl_scramsha1_server_conversation.cpp b/src/mongo/db/auth/sasl_scramsha1_server_conversation.cpp
index 47a2ac4b31d..084907333a1 100644
--- a/src/mongo/db/auth/sasl_scramsha1_server_conversation.cpp
+++ b/src/mongo/db/auth/sasl_scramsha1_server_conversation.cpp
@@ -277,24 +277,20 @@ StatusWith<bool> SaslSCRAMSHA1ServerConversation::_secondStep(const std::vector<
// ClientKey := ClientSignature XOR ClientProof
// ServerSignature := HMAC(ServerKey, AuthMessage)
invariant(_creds.scram.isValid());
+ scram::SHA1Secrets secrets(
+ "", base64::decode(_creds.scram.storedKey), base64::decode(_creds.scram.serverKey));
- if (!scram::verifyClientProof(
- base64::decode(clientProof), base64::decode(_creds.scram.storedKey), _authMessage)) {
+ if (!secrets.verifyClientProof(_authMessage, base64::decode(clientProof))) {
return StatusWith<bool>(ErrorCodes::AuthenticationFailed,
mongoutils::str::stream()
<< "SCRAM-SHA-1 authentication failed, storedKey mismatch");
}
// ServerSignature := HMAC(ServerKey, AuthMessage)
- std::string decodedServerKey = base64::decode(_creds.scram.serverKey);
- SHA1Block serverSignature =
- SHA1Block::computeHmac(reinterpret_cast<const unsigned char*>(decodedServerKey.c_str()),
- decodedServerKey.size(),
- reinterpret_cast<const unsigned char*>(_authMessage.c_str()),
- _authMessage.size());
+ const auto serverSignature = secrets.generateServerSignature(_authMessage);
StringBuilder sb;
- sb << "v=" << serverSignature.toString();
+ sb << "v=" << serverSignature;
*outputData = sb.str();
return StatusWith<bool>(false);
diff --git a/src/mongo/db/auth/sasl_scramsha1_test.cpp b/src/mongo/db/auth/sasl_scramsha1_test.cpp
index eab9136575c..93466db1aa9 100644
--- a/src/mongo/db/auth/sasl_scramsha1_test.cpp
+++ b/src/mongo/db/auth/sasl_scramsha1_test.cpp
@@ -49,7 +49,7 @@ BSONObj generateSCRAMUserDocument(StringData username, StringData password) {
auto database = "test"_sd;
std::string digested = createPasswordDigest(username, password);
- BSONObj scramCred = scram::generateCredentials(digested, scramIterationCount);
+ auto scramCred = scram::SHA1Secrets::generateCredentials(digested, scramIterationCount);
return BSON("_id" << (str::stream() << database << "." << username).operator StringData()
<< AuthorizationManager::USER_NAME_FIELD_NAME
<< username
@@ -498,7 +498,7 @@ TEST(SCRAMSHA1Cache, testGetFromEmptyCache) {
std::vector<std::uint8_t> salt(saltStr.begin(), saltStr.end());
HostAndPort host("localhost:27017");
- ASSERT_FALSE(cache.getCachedSecrets(host, scram::SCRAMPresecrets("aaa", salt, 10000)));
+ ASSERT_FALSE(cache.getCachedSecrets(host, scram::SHA1Presecrets("aaa", salt, 10000)));
}
@@ -510,13 +510,13 @@ TEST(SCRAMSHA1Cache, testSetAndGet) {
std::vector<std::uint8_t> badSalt(badSaltStr.begin(), badSaltStr.end());
HostAndPort host("localhost:27017");
- auto secret = scram::generateSecrets(scram::SCRAMPresecrets("aaa", salt, 10000));
- cache.setCachedSecrets(host, scram::SCRAMPresecrets("aaa", salt, 10000), secret);
- auto cachedSecret = cache.getCachedSecrets(host, scram::SCRAMPresecrets("aaa", salt, 10000));
+ auto secret = scram::SHA1Secrets(scram::SHA1Presecrets("aaa", salt, 10000));
+ cache.setCachedSecrets(host, scram::SHA1Presecrets("aaa", salt, 10000), secret);
+ auto cachedSecret = cache.getCachedSecrets(host, scram::SHA1Presecrets("aaa", salt, 10000));
ASSERT_TRUE(cachedSecret);
- ASSERT_TRUE(secret->clientKey == cachedSecret->clientKey);
- ASSERT_TRUE(secret->serverKey == cachedSecret->serverKey);
- ASSERT_TRUE(secret->storedKey == cachedSecret->storedKey);
+ ASSERT_TRUE(secret.clientKey() == cachedSecret.clientKey());
+ ASSERT_TRUE(secret.serverKey() == cachedSecret.serverKey());
+ ASSERT_TRUE(secret.storedKey() == cachedSecret.storedKey());
}
@@ -528,14 +528,14 @@ TEST(SCRAMSHA1Cache, testSetAndGetWithDifferentParameters) {
std::vector<std::uint8_t> badSalt(badSaltStr.begin(), badSaltStr.end());
HostAndPort host("localhost:27017");
- auto secret = scram::generateSecrets(scram::SCRAMPresecrets("aaa", salt, 10000));
- cache.setCachedSecrets(host, scram::SCRAMPresecrets("aaa", salt, 10000), secret);
+ auto secret = scram::SHA1Secrets(scram::SHA1Presecrets("aaa", salt, 10000));
+ cache.setCachedSecrets(host, scram::SHA1Presecrets("aaa", salt, 10000), secret);
ASSERT_FALSE(cache.getCachedSecrets(HostAndPort("localhost:27018"),
- scram::SCRAMPresecrets("aaa", salt, 10000)));
- ASSERT_FALSE(cache.getCachedSecrets(host, scram::SCRAMPresecrets("aab", salt, 10000)));
- ASSERT_FALSE(cache.getCachedSecrets(host, scram::SCRAMPresecrets("aaa", badSalt, 10000)));
- ASSERT_FALSE(cache.getCachedSecrets(host, scram::SCRAMPresecrets("aaa", salt, 10001)));
+ scram::SHA1Presecrets("aaa", salt, 10000)));
+ ASSERT_FALSE(cache.getCachedSecrets(host, scram::SHA1Presecrets("aab", salt, 10000)));
+ ASSERT_FALSE(cache.getCachedSecrets(host, scram::SHA1Presecrets("aaa", badSalt, 10000)));
+ ASSERT_FALSE(cache.getCachedSecrets(host, scram::SHA1Presecrets("aaa", salt, 10001)));
}
@@ -545,17 +545,17 @@ TEST(SCRAMSHA1Cache, testSetAndReset) {
std::vector<std::uint8_t> salt(saltStr.begin(), saltStr.end());
HostAndPort host("localhost:27017");
- auto secret = scram::generateSecrets(scram::SCRAMPresecrets("aaa", salt, 10000));
- cache.setCachedSecrets(host, scram::SCRAMPresecrets("aaa", salt, 10000), secret);
- auto newSecret = scram::generateSecrets(scram::SCRAMPresecrets("aab", salt, 10000));
- cache.setCachedSecrets(host, scram::SCRAMPresecrets("aab", salt, 10000), newSecret);
+ scram::SHA1Secrets secret(scram::SHA1Presecrets("aaa", salt, 10000));
+ cache.setCachedSecrets(host, scram::SHA1Presecrets("aaa", salt, 10000), secret);
+ scram::SHA1Secrets newSecret(scram::SHA1Presecrets("aab", salt, 10000));
+ cache.setCachedSecrets(host, scram::SHA1Presecrets("aab", salt, 10000), newSecret);
- ASSERT_FALSE(cache.getCachedSecrets(host, scram::SCRAMPresecrets("aaa", salt, 10000)));
- auto cachedSecret = cache.getCachedSecrets(host, scram::SCRAMPresecrets("aab", salt, 10000));
+ ASSERT_FALSE(cache.getCachedSecrets(host, scram::SHA1Presecrets("aaa", salt, 10000)));
+ auto cachedSecret = cache.getCachedSecrets(host, scram::SHA1Presecrets("aab", salt, 10000));
ASSERT_TRUE(cachedSecret);
- ASSERT_TRUE(newSecret->clientKey == cachedSecret->clientKey);
- ASSERT_TRUE(newSecret->serverKey == cachedSecret->serverKey);
- ASSERT_TRUE(newSecret->storedKey == cachedSecret->storedKey);
+ ASSERT_TRUE(newSecret.clientKey() == cachedSecret.clientKey());
+ ASSERT_TRUE(newSecret.serverKey() == cachedSecret.serverKey());
+ ASSERT_TRUE(newSecret.storedKey() == cachedSecret.storedKey());
}
} // namespace mongo
diff --git a/src/mongo/db/auth/security_key.cpp b/src/mongo/db/auth/security_key.cpp
index f9d0445e65f..f146090eeca 100644
--- a/src/mongo/db/auth/security_key.cpp
+++ b/src/mongo/db/auth/security_key.cpp
@@ -76,12 +76,12 @@ bool setUpSecurityKey(const string& filename) {
const auto password =
mongo::createPasswordDigest(internalSecurity.user->getName().getUser().toString(), str);
- BSONObj creds =
- scram::generateCredentials(password, saslGlobalParams.scramIterationCount.load());
- credentials.scram.iterationCount = creds[scram::iterationCountFieldName].Int();
- credentials.scram.salt = creds[scram::saltFieldName].String();
- credentials.scram.storedKey = creds[scram::storedKeyFieldName].String();
- credentials.scram.serverKey = creds[scram::serverKeyFieldName].String();
+ auto creds = scram::SHA1Secrets::generateCredentials(
+ password, saslGlobalParams.scramIterationCount.load());
+ credentials.scram.iterationCount = creds[scram::kIterationCountFieldName].Int();
+ credentials.scram.salt = creds[scram::kSaltFieldName].String();
+ credentials.scram.storedKey = creds[scram::kStoredKeyFieldName].String();
+ credentials.scram.serverKey = creds[scram::kServerKeyFieldName].String();
internalSecurity.user->setCredentials(credentials);
diff --git a/src/mongo/db/auth/user_document_parser_test.cpp b/src/mongo/db/auth/user_document_parser_test.cpp
index decf0155fce..ddfa9f0c052 100644
--- a/src/mongo/db/auth/user_document_parser_test.cpp
+++ b/src/mongo/db/auth/user_document_parser_test.cpp
@@ -63,7 +63,7 @@ public:
user.reset(new User(UserName("spencer", "test")));
adminUser.reset(new User(UserName("admin", "admin")));
- credentials = BSON("SCRAM-SHA-1" << scram::generateCredentials(
+ credentials = BSON("SCRAM-SHA-1" << scram::SHA1Secrets::generateCredentials(
"a", saslGlobalParams.scramIterationCount.load()));
}
};
diff --git a/src/mongo/db/commands/user_management_commands.cpp b/src/mongo/db/commands/user_management_commands.cpp
index 97255194138..f2d3bcbeed2 100644
--- a/src/mongo/db/commands/user_management_commands.cpp
+++ b/src/mongo/db/commands/user_management_commands.cpp
@@ -698,7 +698,7 @@ public:
credentialsBuilder.append("external", true);
} else {
// Add SCRAM credentials.
- BSONObj scramCred = scram::generateCredentials(
+ BSONObj scramCred = scram::SHA1Secrets::generateCredentials(
args.hashedPassword, saslGlobalParams.scramIterationCount.load());
credentialsBuilder.append("SCRAM-SHA-1", scramCred);
}
@@ -808,7 +808,7 @@ public:
BSONObjBuilder credentialsBuilder(updateSetBuilder.subobjStart("credentials"));
// Add SCRAM credentials.
- BSONObj scramCred = scram::generateCredentials(
+ BSONObj scramCred = scram::SHA1Secrets::generateCredentials(
args.hashedPassword, saslGlobalParams.scramIterationCount.load());
credentialsBuilder.append("SCRAM-SHA-1", scramCred);
diff --git a/src/mongo/db/logical_session_id_test.cpp b/src/mongo/db/logical_session_id_test.cpp
index 0dd9d3c6c95..ecd86565f54 100644
--- a/src/mongo/db/logical_session_id_test.cpp
+++ b/src/mongo/db/logical_session_id_test.cpp
@@ -105,7 +105,7 @@ public:
}
User* addSimpleUser(UserName un) {
- const auto creds = BSON("SCRAM-SHA-1" << scram::generateCredentials(
+ const auto creds = BSON("SCRAM-SHA-1" << scram::SHA1Secrets::generateCredentials(
"a", saslGlobalParams.scramIterationCount.load()));
ASSERT_OK(managerState->insertPrivilegeDocument(
_opCtx.get(),
@@ -120,7 +120,7 @@ public:
}
User* addClusterUser(UserName un) {
- const auto creds = BSON("SCRAM-SHA-1" << scram::generateCredentials(
+ const auto creds = BSON("SCRAM-SHA-1" << scram::SHA1Secrets::generateCredentials(
"a", saslGlobalParams.scramIterationCount.load()));
ASSERT_OK(managerState->insertPrivilegeDocument(
_opCtx.get(),