From ac611b47d4f9edc7a576e52735a0edf0bde9f989 Mon Sep 17 00:00:00 2001 From: Andreas Nilsson Date: Tue, 9 Sep 2014 16:28:26 -0400 Subject: SERVER-7596 Native SCRAM-SHA-1 client/shell implementation --- src/mongo/client/native_sasl_client_session.cpp | 33 ++- src/mongo/client/native_sasl_client_session.h | 7 + src/mongo/client/sasl_client_conversation.cpp | 35 +++ src/mongo/client/sasl_client_conversation.h | 78 +++++++ .../client/sasl_plain_client_conversation.cpp | 64 ++++++ src/mongo/client/sasl_plain_client_conversation.h | 56 +++++ .../client/sasl_scramsha1_client_conversation.cpp | 252 +++++++++++++++++++++ .../client/sasl_scramsha1_client_conversation.h | 88 +++++++ 8 files changed, 608 insertions(+), 5 deletions(-) create mode 100644 src/mongo/client/sasl_client_conversation.cpp create mode 100644 src/mongo/client/sasl_client_conversation.h create mode 100644 src/mongo/client/sasl_plain_client_conversation.cpp create mode 100644 src/mongo/client/sasl_plain_client_conversation.h create mode 100644 src/mongo/client/sasl_scramsha1_client_conversation.cpp create mode 100644 src/mongo/client/sasl_scramsha1_client_conversation.h (limited to 'src/mongo/client') diff --git a/src/mongo/client/native_sasl_client_session.cpp b/src/mongo/client/native_sasl_client_session.cpp index 705626dc106..57e33eb9639 100644 --- a/src/mongo/client/native_sasl_client_session.cpp +++ b/src/mongo/client/native_sasl_client_session.cpp @@ -30,6 +30,9 @@ #include "mongo/client/native_sasl_client_session.h" #include "mongo/base/init.h" +#include "mongo/client/sasl_client_conversation.h" +#include "mongo/client/sasl_plain_client_conversation.h" +#include "mongo/client/sasl_scramsha1_client_conversation.h" #include "mongo/util/mongoutils/str.h" namespace mongo { @@ -49,18 +52,38 @@ namespace { NativeSaslClientSession::NativeSaslClientSession() : SaslClientSession(), _step(0), - _done(false) { + _done(false), + _saslConversation(NULL) { } NativeSaslClientSession::~NativeSaslClientSession() {} Status NativeSaslClientSession::initialize() { - return Status(ErrorCodes::BadValue, - mongoutils::str::stream() << "SASL authentication not supported in client"); + if (_saslConversation) + return Status(ErrorCodes::AlreadyInitialized, + "Cannot reinitialize NativeSaslClientSession."); + + std::string mechanism = getParameter(parameterMechanism).toString(); + if (mechanism == "PLAIN") { + _saslConversation.reset(new SaslPLAINClientConversation(this)); + } + else if (mechanism == "SCRAM-SHA-1") { + _saslConversation.reset(new SaslSCRAMSHA1ClientConversation(this)); + } + else { + return Status(ErrorCodes::BadValue, + mongoutils::str::stream() << "SASL mechanism " << mechanism << + "is not supported"); + } + + return Status::OK(); } Status NativeSaslClientSession::step(const StringData& inputData, std::string* outputData) { - return Status(ErrorCodes::BadValue, - mongoutils::str::stream() << "SASL authentication not supported in client"); + StatusWith status = _saslConversation->step(inputData, outputData); + if (status.isOK()) { + _done = status.getValue(); + } + return status.getStatus(); } } // namespace diff --git a/src/mongo/client/native_sasl_client_session.h b/src/mongo/client/native_sasl_client_session.h index d80b9cc57ed..3bb83230025 100644 --- a/src/mongo/client/native_sasl_client_session.h +++ b/src/mongo/client/native_sasl_client_session.h @@ -25,10 +25,14 @@ * then also delete it in the license file. */ +#include + #include "mongo/client/sasl_client_session.h" namespace mongo { + class SaslClientConversation; + /** * Implementation of the client side of a SASL authentication conversation using the * native SASL implementation. @@ -52,6 +56,9 @@ namespace mongo { /// See isDone(). bool _done; + + /// The client side of a SASL authentication conversation. + boost::scoped_ptr _saslConversation; }; } // namespace mongo diff --git a/src/mongo/client/sasl_client_conversation.cpp b/src/mongo/client/sasl_client_conversation.cpp new file mode 100644 index 00000000000..637d6b14f5f --- /dev/null +++ b/src/mongo/client/sasl_client_conversation.cpp @@ -0,0 +1,35 @@ +/* + * Copyright (C) 2014 MongoDB Inc. All Rights Reserved. + * + * 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 . + * + * 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/client/sasl_client_conversation.h" + +namespace mongo { + + SaslClientConversation::~SaslClientConversation() {}; + +} // namespace mongo diff --git a/src/mongo/client/sasl_client_conversation.h b/src/mongo/client/sasl_client_conversation.h new file mode 100644 index 00000000000..f71e7ea0ad0 --- /dev/null +++ b/src/mongo/client/sasl_client_conversation.h @@ -0,0 +1,78 @@ +/* + * Copyright (C) 2014 MongoDB Inc. All Rights Reserved. + * + * 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 . + * + * 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. + */ + +#pragma once + +#include + +#include "mongo/base/disallow_copying.h" +#include "mongo/base/string_data.h" + +namespace mongo { + + class SaslClientSession; + template class StatusWith; + + /** + * Abstract class for implementing the clent-side + * of a SASL mechanism conversation. + */ + class SaslClientConversation { + MONGO_DISALLOW_COPYING(SaslClientConversation); + public: + /** + * Implements the client side of a SASL authentication mechanism. + * + * "saslClientSession" is the corresponding SASLClientSession. + * "saslClientSession" must stay in scope until the SaslClientConversation's + * destructor completes. + * + **/ + explicit SaslClientConversation(SaslClientSession* saslClientSession) : + _saslClientSession(saslClientSession) {} + + virtual ~SaslClientConversation(); + + /** + * Performs one step of the client side of the authentication session, + * consuming "inputData" and producing "*outputData". + * + * A return of Status::OK() indicates successful progress towards authentication. + * A return of !Status::OK() indicates failed authentication + * + * A return of true means that the authentication process has finished. + * A return of false means that the authentication process has more steps. + * + */ + virtual StatusWith step(const StringData& inputData, std::string* outputData) = 0; + + protected: + SaslClientSession* _saslClientSession; + }; + +} // namespace mongo diff --git a/src/mongo/client/sasl_plain_client_conversation.cpp b/src/mongo/client/sasl_plain_client_conversation.cpp new file mode 100644 index 00000000000..b3436cc836e --- /dev/null +++ b/src/mongo/client/sasl_plain_client_conversation.cpp @@ -0,0 +1,64 @@ +/* + * Copyright (C) 2014 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 . + * + * 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/client/sasl_plain_client_conversation.h" + +#include "mongo/base/status_with.h" +#include "mongo/client/sasl_client_session.h" +#include "mongo/util/log.h" +#include "mongo/util/password_digest.h" +#include "mongo/util/text.h" + +namespace mongo { + + SaslPLAINClientConversation::SaslPLAINClientConversation( + SaslClientSession* saslClientSession) : + SaslClientConversation(saslClientSession) { + } + + SaslPLAINClientConversation::~SaslPLAINClientConversation() {}; + + StatusWith SaslPLAINClientConversation::step(const StringData& inputData, + std::string* outputData) { + // Create PLAIN message on the form: user\0user\0pwd + + StringBuilder sb; + sb << _saslClientSession->getParameter(SaslClientSession::parameterUser).toString() << + '\0' << + _saslClientSession->getParameter(SaslClientSession::parameterUser).toString() << + '\0' << + _saslClientSession->getParameter(SaslClientSession::parameterPassword).toString(); + + *outputData = sb.str(); + + return StatusWith(true); + } + +} // namespace mongo diff --git a/src/mongo/client/sasl_plain_client_conversation.h b/src/mongo/client/sasl_plain_client_conversation.h new file mode 100644 index 00000000000..ffd3f46b810 --- /dev/null +++ b/src/mongo/client/sasl_plain_client_conversation.h @@ -0,0 +1,56 @@ +/* + * Copyright (C) 2014 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 . + * + * 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. + */ + +#pragma once + +#include + +#include "mongo/base/disallow_copying.h" +#include "mongo/base/status.h" +#include "mongo/base/string_data.h" +#include "mongo/client/sasl_client_conversation.h" + +namespace mongo { + /** + * Client side authentication session for SASL PLAIN. + */ + class SaslPLAINClientConversation : public SaslClientConversation { + MONGO_DISALLOW_COPYING(SaslPLAINClientConversation); + public: + /** + * Implements the client side of a SASL PLAIN mechanism session. + * + **/ + explicit SaslPLAINClientConversation(SaslClientSession* saslClientSession); + + virtual ~SaslPLAINClientConversation(); + + virtual StatusWith step(const StringData& inputData, std::string* outputData); + }; + +} // namespace mongo diff --git a/src/mongo/client/sasl_scramsha1_client_conversation.cpp b/src/mongo/client/sasl_scramsha1_client_conversation.cpp new file mode 100644 index 00000000000..1fdb171b52f --- /dev/null +++ b/src/mongo/client/sasl_scramsha1_client_conversation.cpp @@ -0,0 +1,252 @@ +/* + * Copyright (C) 2014 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 . + * + * 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/client/sasl_scramsha1_client_conversation.h" + +#include +#ifdef MONGO_SSL +#include +#include +#include +#endif + +#include "mongo/base/parse_number.h" +#include "mongo/client/sasl_client_session.h" +#include "mongo/platform/random.h" +#include "mongo/util/base64.h" +#include "mongo/util/mongoutils/str.h" +#include "mongo/util/password_digest.h" +#include "mongo/util/text.h" + +namespace mongo { + SaslSCRAMSHA1ClientConversation::SaslSCRAMSHA1ClientConversation( + SaslClientSession* saslClientSession) : + SaslClientConversation(saslClientSession), + _step(0), + _authMessage(""), + _clientNonce("") { + } + + SaslSCRAMSHA1ClientConversation::~SaslSCRAMSHA1ClientConversation(){ + // clear the _saltedPassword memory + memset(_saltedPassword, 0, scram::hashSize); + } + + StatusWith SaslSCRAMSHA1ClientConversation::step(const StringData& inputData, + std::string* outputData) { + std::vector input = StringSplitter::split(inputData.toString(), ","); + _step++; + + switch (_step) { + case 1: + return _firstStep(outputData); + case 2: + // Append server-first-message to _authMessage + _authMessage += inputData.toString() + ","; + return _secondStep(input, outputData); + case 3: + return _thirdStep(input, outputData); + default: + return StatusWith(ErrorCodes::AuthenticationFailed, + mongoutils::str::stream() << + "Invalid SCRAM-SHA-1 authentication step: " << _step); + } + } + + /* + * RFC 5802 specifies that in SCRAM user names characters ',' and '=' are encoded as + * =2C and =3D respectively. + */ + static void encodeSCRAMUsername(std::string& user) { + boost::replace_all(user, ",", "=2C"); + boost::replace_all(user, "=", "=3D"); + } + + /* + * Generate client-first-message of the form: + * n,a=authzid,n=encoded-username,r=client-nonce + */ + StatusWith SaslSCRAMSHA1ClientConversation::_firstStep(std::string* outputData) { +#ifndef MONGO_SSL + return StatusWith(ErrorCodes::InternalError, + "The server is not compiled with SSL support"); +#else + // Create text-based nonce as base64 encoding of a binary blob of length multiple of 3 + const int nonceLenQWords = 3; + uint64_t binaryNonce[nonceLenQWords]; + + scoped_ptr sr(SecureRandom::create()); + + binaryNonce[0] = sr->nextInt64(); + binaryNonce[1] = sr->nextInt64(); + binaryNonce[2] = sr->nextInt64(); + + std::string user = + _saslClientSession->getParameter(SaslClientSession::parameterUser).toString(); + encodeSCRAMUsername(user); + std::string clientNonce = base64::encode(reinterpret_cast(binaryNonce), + sizeof(binaryNonce)); + + // Append client-first-message-bare to authMessage + _authMessage = "n=" + user + ",r=" + clientNonce + ","; + + StringBuilder sb; + sb << "n,,n=" << user << + ",r=" << clientNonce; + *outputData = sb.str(); + + return StatusWith(false); + +#endif // MONGO_SSL + } + + /** + * Parse server-first-message on the form: + * r=client-nonce|server-nonce,s=user-salt,i=iteration-count + * + * Generate client-final-message of the form: + * c=channel-binding(base64),r=client-nonce|server-nonce,p=ClientProof + * + **/ + StatusWith SaslSCRAMSHA1ClientConversation::_secondStep(const std::vector& input, + std::string* outputData) { +#ifndef MONGO_SSL + return StatusWith(ErrorCodes::InternalError, + "The server is not compiled with SSL support"); +#else + if (input.size() != 3) { + return StatusWith(ErrorCodes::BadValue, mongoutils::str::stream() << + "Incorrect number of arguments for first SCRAM-SHA-1 server message, got " << + input.size() << " expected 3"); + } + else if (!str::startsWith(input[0], "r=") || input[0].size() < 2) { + return StatusWith(ErrorCodes::BadValue, mongoutils::str::stream() << + "Incorrect SCRAM-SHA-1 client|server nonce: " << input[0]); + } + else if (!str::startsWith(input[1], "s=") || input[1].size() < 6) { + return StatusWith(ErrorCodes::BadValue, mongoutils::str::stream() << + "Incorrect SCRAM-SHA-1 salt: " << input[1]); + } + else if(!str::startsWith(input[2], "i=") || input[2].size() < 3) { + return StatusWith(ErrorCodes::BadValue, mongoutils::str::stream() << + "Incorrect SCRAM-SHA-1 iteration count: " << input[2]); + } + + std::string nonce = input[0].substr(2); + if(!str::startsWith(nonce, _clientNonce)) { + return StatusWith(ErrorCodes::BadValue, mongoutils::str::stream() << + "Server SCRAM-SHA-1 nonce does not match client nonce" << input[2]); + } + + std::string salt = input[1].substr(2); + int iterationCount; + + Status status = parseNumberFromStringWithBase(input[2].substr(2), 10, &iterationCount); + if (status != Status::OK()) { + return StatusWith(ErrorCodes::BadValue, mongoutils::str::stream() << + "Failed to parse SCRAM-SHA-1 iteration count: " << input[2]); + } + + // Append client-final-message-without-proof to _authMessage + _authMessage += "c=biws,r=" + nonce; + + std::string decodedSalt; + try { + decodedSalt = base64::decode(salt); + } + catch (const DBException& ex) { + return StatusWith(ex.toStatus()); + } + + scram::generateSaltedPassword( + _saslClientSession->getParameter(SaslClientSession::parameterPassword), + reinterpret_cast(decodedSalt.c_str()), + decodedSalt.size(), + iterationCount, + _saltedPassword); + + std::string clientProof = scram::generateClientProof(_saltedPassword, _authMessage); + + StringBuilder sb; + sb << "c=biws,r=" << nonce << ",p=" << clientProof; + *outputData = sb.str(); + + return StatusWith(false); +#endif // MONGO_SSL + } + + /** + * Verify server-final-message on the form: + * v=ServerSignature + * + * or failed authentication server-final-message on the form: + * e=message + **/ + StatusWith SaslSCRAMSHA1ClientConversation::_thirdStep(const std::vector& input, + std::string* outputData) { +#ifndef MONGO_SSL + return StatusWith(ErrorCodes::InternalError, + "The server is not compiled with SSL support"); +#else + + if (input.size() != 1) { + return StatusWith(ErrorCodes::BadValue, mongoutils::str::stream() << + "Incorrect number of arguments for final SCRAM-SHA-1 server message, got " << + input.size() << " expected 1"); + } + else if (input[0].size() < 3) { + return StatusWith(ErrorCodes::BadValue, mongoutils::str::stream() << + "Incorrect SCRAM-SHA-1 server message length: " << input[0]); + } + else if (str::startsWith(input[0], "e=")) { + return StatusWith(ErrorCodes::AuthenticationFailed, mongoutils::str::stream() << + "SCRAM-SHA-1 authentication failure: " << input[0].substr(2)); + } + else if (!str::startsWith(input[0], "v=")) { + return StatusWith(ErrorCodes::BadValue, mongoutils::str::stream() << + "Incorrect SCRAM-SHA-1 ServerSignature: " << input[0]); + } + + bool validServerSignature = + scram::verifyServerSignature(_saltedPassword, _authMessage, input[0].substr(2)); + + if (!validServerSignature) { + *outputData = "e=Invalid server signature"; + return StatusWith(ErrorCodes::BadValue, mongoutils::str::stream() << + "Client failed to verify SCRAM-SHA-1 ServerSignature, received " << + input[0].substr(2)); + } + + *outputData = ""; + + return StatusWith(true); +#endif // MONGO_SSL + } +} // namespace mongo diff --git a/src/mongo/client/sasl_scramsha1_client_conversation.h b/src/mongo/client/sasl_scramsha1_client_conversation.h new file mode 100644 index 00000000000..668588bc03f --- /dev/null +++ b/src/mongo/client/sasl_scramsha1_client_conversation.h @@ -0,0 +1,88 @@ +/* + * Copyright (C) 2014 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 . + * + * 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. + */ + +#pragma once + +#include +#include + +#include "mongo/base/disallow_copying.h" +#include "mongo/base/status.h" +#include "mongo/base/string_data.h" +#include "mongo/client/sasl_client_conversation.h" +#include "mongo/db/auth/mechanism_scram.h" +#include "mongo/db/auth/user.h" + +namespace mongo { + /** + * Client side authentication session for SASL PLAIN. + */ + class SaslSCRAMSHA1ClientConversation : public SaslClientConversation { + MONGO_DISALLOW_COPYING(SaslSCRAMSHA1ClientConversation); + public: + /** + * Implements the client side of a SASL PLAIN mechanism session. + **/ + explicit SaslSCRAMSHA1ClientConversation(SaslClientSession* saslClientSession); + + virtual ~SaslSCRAMSHA1ClientConversation(); + + /** + * Takes one step in a SCRAM-SHA-1 conversation. + * + * @return !Status::OK() for failure. The boolean part indicates if the + * authentication conversation is finished or not. + * + **/ + virtual StatusWith step(const StringData& inputData, std::string* outputData); + + private: + /** + * Generates client-first-message. + **/ + StatusWith _firstStep(std::string* outputData); + + /** + * Parses server-first-message and generate client-final-message. + **/ + StatusWith _secondStep(const std::vector& input, std::string* outputData); + + /** + * Generates client-first-message. + **/ + StatusWith _thirdStep(const std::vector& input, std::string* outputData); + + int _step; + std::string _authMessage; + unsigned char _saltedPassword[scram::hashSize]; + + // client and server nonce concatenated + std::string _clientNonce; + }; + +} // namespace mongo -- cgit v1.2.1