Status HostAndPort::initialize(const StringData& s) { const size_t colonPos = s.rfind(':'); const StringData hostPart = s.substr(0, colonPos); if (hostPart.empty()) { return Status(ErrorCodes::FailedToParse, str::stream() << "Empty host component parsing HostAndPort from \"" << escape(s.toString()) << "\""); } int port; if (colonPos != std::string::npos) { const StringData portPart = s.substr(colonPos + 1); Status status = parseNumberFromStringWithBase(portPart, 10, &port); if (!status.isOK()) { return status; } if (port <= 0) { return Status(ErrorCodes::FailedToParse, str::stream() << "Port number " << port << " out of range parsing HostAndPort from \"" << escape(s.toString()) << "\""); } } else { port = -1; } _host = hostPart.toString(); _port = port; return Status::OK(); }
Status HostAndPort::initialize(const StringData& s) { size_t colonPos = s.rfind(':'); StringData hostPart = s.substr(0, colonPos); // handle ipv6 hostPart (which we require to be wrapped in []s) const size_t openBracketPos = s.find('['); const size_t closeBracketPos = s.find(']'); if (openBracketPos != std::string::npos) { if (openBracketPos != 0) { return Status(ErrorCodes::FailedToParse, str::stream() << "'[' present, but not first character in " << s.toString()); } if (closeBracketPos == std::string::npos) { return Status(ErrorCodes::FailedToParse, str::stream() << "ipv6 address is missing closing ']' in hostname in " << s.toString()); } hostPart = s.substr(openBracketPos+1, closeBracketPos-openBracketPos-1); // prevent accidental assignment of port to the value of the final portion of hostPart if (colonPos < closeBracketPos) { colonPos = std::string::npos; } else if (colonPos != closeBracketPos+1) { return Status(ErrorCodes::FailedToParse, str::stream() << "Extraneous characters between ']' and pre-port ':'" << " in " << s.toString()); } } else if (closeBracketPos != std::string::npos) { return Status(ErrorCodes::FailedToParse, str::stream() << "']' present without '[' in " << s.toString()); } if (hostPart.empty()) { return Status(ErrorCodes::FailedToParse, str::stream() << "Empty host component parsing HostAndPort from \"" << escape(s.toString()) << "\""); } int port; if (colonPos != std::string::npos) { const StringData portPart = s.substr(colonPos + 1); Status status = parseNumberFromStringWithBase(portPart, 10, &port); if (!status.isOK()) { return status; } if (port <= 0) { return Status(ErrorCodes::FailedToParse, str::stream() << "Port number " << port << " out of range parsing HostAndPort from \"" << escape(s.toString()) << "\""); } } else { port = -1; } _host = hostPart.toString(); _port = port; return Status::OK(); }
StatusWith<std::tuple<bool, std::string>> SaslSCRAMServerMechanism<Policy>::_secondStep( OperationContext* opCtx, StringData inputData) { const auto badCount = [](int got) { return Status(ErrorCodes::BadValue, str::stream() << "Incorrect number of arguments for second SCRAM client message, got " << got << " expected at least 3"); }; /** * client-final-message-without-proof := cbind ',' nonce ',' [ ',' extensions ] * client-final-message := client-final-message-without-proof ',' proof */ const auto last_comma = inputData.rfind(','); if (last_comma == std::string::npos) { return badCount(1); } // add client-final-message-without-proof to authMessage const auto client_final_message_without_proof = inputData.substr(0, last_comma); _authMessage += "," + client_final_message_without_proof.toString(); const auto last_field = inputData.substr(last_comma + 1); if ((last_field.size() < 3) || !last_field.startsWith("p=")) { return Status(ErrorCodes::BadValue, str::stream() << "Incorrect SCRAM ClientProof: " << last_field); } const auto proof = last_field.substr(2); const auto input = StringSplitter::split(client_final_message_without_proof.toString(), ","); if (input.size() < 2) { // Add count for proof back on. return badCount(input.size() + 1); } if (!str::startsWith(input[0], "c=") || input[0].size() < 3) { return Status(ErrorCodes::BadValue, str::stream() << "Incorrect SCRAM channel binding: " << input[0]); } const auto cbind = input[0].substr(2); if (!str::startsWith(input[1], "r=") || input[1].size() < 6) { return Status(ErrorCodes::BadValue, str::stream() << "Incorrect SCRAM client|server nonce: " << input[1]); } const auto nonce = input[1].substr(2); // Concatenated nonce sent by client should equal the one in server-first-message if (nonce != _nonce) { return Status(ErrorCodes::BadValue, str::stream() << "Unmatched SCRAM nonce received from client in second step, expected " << _nonce << " but received " << nonce); } // Do server side computations, compare storedKeys and generate client-final-message // AuthMessage := client-first-message-bare + "," + // server-first-message + "," + // client-final-message-without-proof // ClientSignature := HMAC(StoredKey, AuthMessage) // ClientKey := ClientSignature XOR ClientProof // ServerSignature := HMAC(ServerKey, AuthMessage) if (!_secrets.verifyClientProof(_authMessage, base64::decode(proof.toString()))) { return Status(ErrorCodes::AuthenticationFailed, "SCRAM authentication failed, storedKey mismatch"); } StringBuilder sb; // ServerSignature := HMAC(ServerKey, AuthMessage) sb << "v=" << _secrets.generateServerSignature(_authMessage); return std::make_tuple(false, sb.str()); }