xref: /aosp_15_r20/external/cronet/net/ntlm/ntlm_client.cc (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
1*6777b538SAndroid Build Coastguard Worker // Copyright 2017 The Chromium Authors
2*6777b538SAndroid Build Coastguard Worker // Use of this source code is governed by a BSD-style license that can be
3*6777b538SAndroid Build Coastguard Worker // found in the LICENSE file.
4*6777b538SAndroid Build Coastguard Worker 
5*6777b538SAndroid Build Coastguard Worker #include "net/ntlm/ntlm_client.h"
6*6777b538SAndroid Build Coastguard Worker 
7*6777b538SAndroid Build Coastguard Worker #include <string.h>
8*6777b538SAndroid Build Coastguard Worker 
9*6777b538SAndroid Build Coastguard Worker #include "base/check_op.h"
10*6777b538SAndroid Build Coastguard Worker #include "base/containers/span.h"
11*6777b538SAndroid Build Coastguard Worker #include "base/logging.h"
12*6777b538SAndroid Build Coastguard Worker #include "base/numerics/safe_math.h"
13*6777b538SAndroid Build Coastguard Worker #include "base/strings/utf_string_conversions.h"
14*6777b538SAndroid Build Coastguard Worker #include "net/ntlm/ntlm.h"
15*6777b538SAndroid Build Coastguard Worker #include "net/ntlm/ntlm_buffer_reader.h"
16*6777b538SAndroid Build Coastguard Worker #include "net/ntlm/ntlm_buffer_writer.h"
17*6777b538SAndroid Build Coastguard Worker #include "net/ntlm/ntlm_constants.h"
18*6777b538SAndroid Build Coastguard Worker 
19*6777b538SAndroid Build Coastguard Worker namespace net::ntlm {
20*6777b538SAndroid Build Coastguard Worker 
21*6777b538SAndroid Build Coastguard Worker namespace {
22*6777b538SAndroid Build Coastguard Worker // Parses the challenge message and returns the |challenge_flags| and
23*6777b538SAndroid Build Coastguard Worker // |server_challenge| into the supplied buffer.
ParseChallengeMessage(base::span<const uint8_t> challenge_message,NegotiateFlags * challenge_flags,base::span<uint8_t,kChallengeLen> server_challenge)24*6777b538SAndroid Build Coastguard Worker bool ParseChallengeMessage(
25*6777b538SAndroid Build Coastguard Worker     base::span<const uint8_t> challenge_message,
26*6777b538SAndroid Build Coastguard Worker     NegotiateFlags* challenge_flags,
27*6777b538SAndroid Build Coastguard Worker     base::span<uint8_t, kChallengeLen> server_challenge) {
28*6777b538SAndroid Build Coastguard Worker   NtlmBufferReader challenge_reader(challenge_message);
29*6777b538SAndroid Build Coastguard Worker 
30*6777b538SAndroid Build Coastguard Worker   return challenge_reader.MatchMessageHeader(MessageType::kChallenge) &&
31*6777b538SAndroid Build Coastguard Worker          challenge_reader.SkipSecurityBufferWithValidation() &&
32*6777b538SAndroid Build Coastguard Worker          challenge_reader.ReadFlags(challenge_flags) &&
33*6777b538SAndroid Build Coastguard Worker          challenge_reader.ReadBytes(server_challenge);
34*6777b538SAndroid Build Coastguard Worker }
35*6777b538SAndroid Build Coastguard Worker 
36*6777b538SAndroid Build Coastguard Worker // Parses the challenge message and extracts the information necessary to
37*6777b538SAndroid Build Coastguard Worker // make an NTLMv2 response.
ParseChallengeMessageV2(base::span<const uint8_t> challenge_message,NegotiateFlags * challenge_flags,base::span<uint8_t,kChallengeLen> server_challenge,std::vector<AvPair> * av_pairs)38*6777b538SAndroid Build Coastguard Worker bool ParseChallengeMessageV2(
39*6777b538SAndroid Build Coastguard Worker     base::span<const uint8_t> challenge_message,
40*6777b538SAndroid Build Coastguard Worker     NegotiateFlags* challenge_flags,
41*6777b538SAndroid Build Coastguard Worker     base::span<uint8_t, kChallengeLen> server_challenge,
42*6777b538SAndroid Build Coastguard Worker     std::vector<AvPair>* av_pairs) {
43*6777b538SAndroid Build Coastguard Worker   NtlmBufferReader challenge_reader(challenge_message);
44*6777b538SAndroid Build Coastguard Worker 
45*6777b538SAndroid Build Coastguard Worker   return challenge_reader.MatchMessageHeader(MessageType::kChallenge) &&
46*6777b538SAndroid Build Coastguard Worker          challenge_reader.SkipSecurityBufferWithValidation() &&
47*6777b538SAndroid Build Coastguard Worker          challenge_reader.ReadFlags(challenge_flags) &&
48*6777b538SAndroid Build Coastguard Worker          challenge_reader.ReadBytes(server_challenge) &&
49*6777b538SAndroid Build Coastguard Worker          challenge_reader.SkipBytes(8) &&
50*6777b538SAndroid Build Coastguard Worker          // challenge_reader.ReadTargetInfoPayload(av_pairs);
51*6777b538SAndroid Build Coastguard Worker          (((*challenge_flags & NegotiateFlags::kTargetInfo) ==
52*6777b538SAndroid Build Coastguard Worker            NegotiateFlags::kTargetInfo)
53*6777b538SAndroid Build Coastguard Worker               ? challenge_reader.ReadTargetInfoPayload(av_pairs)
54*6777b538SAndroid Build Coastguard Worker               : true);
55*6777b538SAndroid Build Coastguard Worker }
56*6777b538SAndroid Build Coastguard Worker 
WriteAuthenticateMessage(NtlmBufferWriter * authenticate_writer,SecurityBuffer lm_payload,SecurityBuffer ntlm_payload,SecurityBuffer domain_payload,SecurityBuffer username_payload,SecurityBuffer hostname_payload,SecurityBuffer session_key_payload,NegotiateFlags authenticate_flags)57*6777b538SAndroid Build Coastguard Worker bool WriteAuthenticateMessage(NtlmBufferWriter* authenticate_writer,
58*6777b538SAndroid Build Coastguard Worker                               SecurityBuffer lm_payload,
59*6777b538SAndroid Build Coastguard Worker                               SecurityBuffer ntlm_payload,
60*6777b538SAndroid Build Coastguard Worker                               SecurityBuffer domain_payload,
61*6777b538SAndroid Build Coastguard Worker                               SecurityBuffer username_payload,
62*6777b538SAndroid Build Coastguard Worker                               SecurityBuffer hostname_payload,
63*6777b538SAndroid Build Coastguard Worker                               SecurityBuffer session_key_payload,
64*6777b538SAndroid Build Coastguard Worker                               NegotiateFlags authenticate_flags) {
65*6777b538SAndroid Build Coastguard Worker   return authenticate_writer->WriteMessageHeader(MessageType::kAuthenticate) &&
66*6777b538SAndroid Build Coastguard Worker          authenticate_writer->WriteSecurityBuffer(lm_payload) &&
67*6777b538SAndroid Build Coastguard Worker          authenticate_writer->WriteSecurityBuffer(ntlm_payload) &&
68*6777b538SAndroid Build Coastguard Worker          authenticate_writer->WriteSecurityBuffer(domain_payload) &&
69*6777b538SAndroid Build Coastguard Worker          authenticate_writer->WriteSecurityBuffer(username_payload) &&
70*6777b538SAndroid Build Coastguard Worker          authenticate_writer->WriteSecurityBuffer(hostname_payload) &&
71*6777b538SAndroid Build Coastguard Worker          authenticate_writer->WriteSecurityBuffer(session_key_payload) &&
72*6777b538SAndroid Build Coastguard Worker          authenticate_writer->WriteFlags(authenticate_flags);
73*6777b538SAndroid Build Coastguard Worker }
74*6777b538SAndroid Build Coastguard Worker 
75*6777b538SAndroid Build Coastguard Worker // Writes the NTLMv1 LM Response and NTLM Response.
WriteResponsePayloads(NtlmBufferWriter * authenticate_writer,base::span<const uint8_t,kResponseLenV1> lm_response,base::span<const uint8_t,kResponseLenV1> ntlm_response)76*6777b538SAndroid Build Coastguard Worker bool WriteResponsePayloads(
77*6777b538SAndroid Build Coastguard Worker     NtlmBufferWriter* authenticate_writer,
78*6777b538SAndroid Build Coastguard Worker     base::span<const uint8_t, kResponseLenV1> lm_response,
79*6777b538SAndroid Build Coastguard Worker     base::span<const uint8_t, kResponseLenV1> ntlm_response) {
80*6777b538SAndroid Build Coastguard Worker   return authenticate_writer->WriteBytes(lm_response) &&
81*6777b538SAndroid Build Coastguard Worker          authenticate_writer->WriteBytes(ntlm_response);
82*6777b538SAndroid Build Coastguard Worker }
83*6777b538SAndroid Build Coastguard Worker 
84*6777b538SAndroid Build Coastguard Worker // Writes the |lm_response| and writes the NTLMv2 response by concatenating
85*6777b538SAndroid Build Coastguard Worker // |v2_proof|, |v2_proof_input|, |updated_target_info| and 4 zero bytes.
WriteResponsePayloadsV2(NtlmBufferWriter * authenticate_writer,base::span<const uint8_t,kResponseLenV1> lm_response,base::span<const uint8_t,kNtlmProofLenV2> v2_proof,base::span<const uint8_t> v2_proof_input,base::span<const uint8_t> updated_target_info)86*6777b538SAndroid Build Coastguard Worker bool WriteResponsePayloadsV2(
87*6777b538SAndroid Build Coastguard Worker     NtlmBufferWriter* authenticate_writer,
88*6777b538SAndroid Build Coastguard Worker     base::span<const uint8_t, kResponseLenV1> lm_response,
89*6777b538SAndroid Build Coastguard Worker     base::span<const uint8_t, kNtlmProofLenV2> v2_proof,
90*6777b538SAndroid Build Coastguard Worker     base::span<const uint8_t> v2_proof_input,
91*6777b538SAndroid Build Coastguard Worker     base::span<const uint8_t> updated_target_info) {
92*6777b538SAndroid Build Coastguard Worker   return authenticate_writer->WriteBytes(lm_response) &&
93*6777b538SAndroid Build Coastguard Worker          authenticate_writer->WriteBytes(v2_proof) &&
94*6777b538SAndroid Build Coastguard Worker          authenticate_writer->WriteBytes(v2_proof_input) &&
95*6777b538SAndroid Build Coastguard Worker          authenticate_writer->WriteBytes(updated_target_info) &&
96*6777b538SAndroid Build Coastguard Worker          authenticate_writer->WriteUInt32(0);
97*6777b538SAndroid Build Coastguard Worker }
98*6777b538SAndroid Build Coastguard Worker 
WriteStringPayloads(NtlmBufferWriter * authenticate_writer,bool is_unicode,const std::u16string & domain,const std::u16string & username,const std::string & hostname)99*6777b538SAndroid Build Coastguard Worker bool WriteStringPayloads(NtlmBufferWriter* authenticate_writer,
100*6777b538SAndroid Build Coastguard Worker                          bool is_unicode,
101*6777b538SAndroid Build Coastguard Worker                          const std::u16string& domain,
102*6777b538SAndroid Build Coastguard Worker                          const std::u16string& username,
103*6777b538SAndroid Build Coastguard Worker                          const std::string& hostname) {
104*6777b538SAndroid Build Coastguard Worker   if (is_unicode) {
105*6777b538SAndroid Build Coastguard Worker     return authenticate_writer->WriteUtf16String(domain) &&
106*6777b538SAndroid Build Coastguard Worker            authenticate_writer->WriteUtf16String(username) &&
107*6777b538SAndroid Build Coastguard Worker            authenticate_writer->WriteUtf8AsUtf16String(hostname);
108*6777b538SAndroid Build Coastguard Worker   } else {
109*6777b538SAndroid Build Coastguard Worker     return authenticate_writer->WriteUtf16AsUtf8String(domain) &&
110*6777b538SAndroid Build Coastguard Worker            authenticate_writer->WriteUtf16AsUtf8String(username) &&
111*6777b538SAndroid Build Coastguard Worker            authenticate_writer->WriteUtf8String(hostname);
112*6777b538SAndroid Build Coastguard Worker   }
113*6777b538SAndroid Build Coastguard Worker }
114*6777b538SAndroid Build Coastguard Worker 
115*6777b538SAndroid Build Coastguard Worker // Returns the size in bytes of a string16 depending whether unicode
116*6777b538SAndroid Build Coastguard Worker // was negotiated.
GetStringPayloadLength(const std::u16string & str,bool is_unicode)117*6777b538SAndroid Build Coastguard Worker size_t GetStringPayloadLength(const std::u16string& str, bool is_unicode) {
118*6777b538SAndroid Build Coastguard Worker   if (is_unicode)
119*6777b538SAndroid Build Coastguard Worker     return str.length() * 2;
120*6777b538SAndroid Build Coastguard Worker 
121*6777b538SAndroid Build Coastguard Worker   // When |WriteUtf16AsUtf8String| is called with a |std::u16string|, the string
122*6777b538SAndroid Build Coastguard Worker   // is converted to UTF8. Do the conversion to ensure that the character
123*6777b538SAndroid Build Coastguard Worker   // count is correct.
124*6777b538SAndroid Build Coastguard Worker   return base::UTF16ToUTF8(str).length();
125*6777b538SAndroid Build Coastguard Worker }
126*6777b538SAndroid Build Coastguard Worker 
127*6777b538SAndroid Build Coastguard Worker // Returns the size in bytes of a std::string depending whether unicode
128*6777b538SAndroid Build Coastguard Worker // was negotiated.
GetStringPayloadLength(const std::string & str,bool is_unicode)129*6777b538SAndroid Build Coastguard Worker size_t GetStringPayloadLength(const std::string& str, bool is_unicode) {
130*6777b538SAndroid Build Coastguard Worker   if (!is_unicode)
131*6777b538SAndroid Build Coastguard Worker     return str.length();
132*6777b538SAndroid Build Coastguard Worker 
133*6777b538SAndroid Build Coastguard Worker   return base::UTF8ToUTF16(str).length() * 2;
134*6777b538SAndroid Build Coastguard Worker }
135*6777b538SAndroid Build Coastguard Worker 
136*6777b538SAndroid Build Coastguard Worker // Sets |buffer| to point to |length| bytes from |offset| and updates |offset|
137*6777b538SAndroid Build Coastguard Worker // past those bytes. In case of overflow, returns false.
ComputeSecurityBuffer(uint32_t * offset,size_t length,SecurityBuffer * buffer)138*6777b538SAndroid Build Coastguard Worker bool ComputeSecurityBuffer(uint32_t* offset,
139*6777b538SAndroid Build Coastguard Worker                            size_t length,
140*6777b538SAndroid Build Coastguard Worker                            SecurityBuffer* buffer) {
141*6777b538SAndroid Build Coastguard Worker   base::CheckedNumeric<uint16_t> length_checked = length;
142*6777b538SAndroid Build Coastguard Worker   if (!length_checked.IsValid()) {
143*6777b538SAndroid Build Coastguard Worker     return false;
144*6777b538SAndroid Build Coastguard Worker   }
145*6777b538SAndroid Build Coastguard Worker   base::CheckedNumeric<uint32_t> new_offset = *offset + length_checked;
146*6777b538SAndroid Build Coastguard Worker   if (!new_offset.IsValid()) {
147*6777b538SAndroid Build Coastguard Worker     return false;
148*6777b538SAndroid Build Coastguard Worker   }
149*6777b538SAndroid Build Coastguard Worker   buffer->offset = *offset;
150*6777b538SAndroid Build Coastguard Worker   buffer->length = length_checked.ValueOrDie();
151*6777b538SAndroid Build Coastguard Worker   *offset = new_offset.ValueOrDie();
152*6777b538SAndroid Build Coastguard Worker   return true;
153*6777b538SAndroid Build Coastguard Worker }
154*6777b538SAndroid Build Coastguard Worker 
155*6777b538SAndroid Build Coastguard Worker }  // namespace
156*6777b538SAndroid Build Coastguard Worker 
NtlmClient(NtlmFeatures features)157*6777b538SAndroid Build Coastguard Worker NtlmClient::NtlmClient(NtlmFeatures features)
158*6777b538SAndroid Build Coastguard Worker     : features_(features), negotiate_flags_(kNegotiateMessageFlags) {
159*6777b538SAndroid Build Coastguard Worker   // Just generate the negotiate message once and hold on to it. It never
160*6777b538SAndroid Build Coastguard Worker   // changes and in NTLMv2 it's used as an input to the Message Integrity
161*6777b538SAndroid Build Coastguard Worker   // Check (MIC) in the Authenticate message.
162*6777b538SAndroid Build Coastguard Worker   GenerateNegotiateMessage();
163*6777b538SAndroid Build Coastguard Worker }
164*6777b538SAndroid Build Coastguard Worker 
165*6777b538SAndroid Build Coastguard Worker NtlmClient::~NtlmClient() = default;
166*6777b538SAndroid Build Coastguard Worker 
GetNegotiateMessage() const167*6777b538SAndroid Build Coastguard Worker std::vector<uint8_t> NtlmClient::GetNegotiateMessage() const {
168*6777b538SAndroid Build Coastguard Worker   return negotiate_message_;
169*6777b538SAndroid Build Coastguard Worker }
170*6777b538SAndroid Build Coastguard Worker 
GenerateNegotiateMessage()171*6777b538SAndroid Build Coastguard Worker void NtlmClient::GenerateNegotiateMessage() {
172*6777b538SAndroid Build Coastguard Worker   NtlmBufferWriter writer(kNegotiateMessageLen);
173*6777b538SAndroid Build Coastguard Worker   bool result =
174*6777b538SAndroid Build Coastguard Worker       writer.WriteMessageHeader(MessageType::kNegotiate) &&
175*6777b538SAndroid Build Coastguard Worker       writer.WriteFlags(negotiate_flags_) &&
176*6777b538SAndroid Build Coastguard Worker       writer.WriteSecurityBuffer(SecurityBuffer(kNegotiateMessageLen, 0)) &&
177*6777b538SAndroid Build Coastguard Worker       writer.WriteSecurityBuffer(SecurityBuffer(kNegotiateMessageLen, 0)) &&
178*6777b538SAndroid Build Coastguard Worker       writer.IsEndOfBuffer();
179*6777b538SAndroid Build Coastguard Worker 
180*6777b538SAndroid Build Coastguard Worker   DCHECK(result);
181*6777b538SAndroid Build Coastguard Worker 
182*6777b538SAndroid Build Coastguard Worker   negotiate_message_ = writer.Pass();
183*6777b538SAndroid Build Coastguard Worker }
184*6777b538SAndroid Build Coastguard Worker 
GenerateAuthenticateMessage(const std::u16string & domain,const std::u16string & username,const std::u16string & password,const std::string & hostname,const std::string & channel_bindings,const std::string & spn,uint64_t client_time,base::span<const uint8_t,kChallengeLen> client_challenge,base::span<const uint8_t> server_challenge_message) const185*6777b538SAndroid Build Coastguard Worker std::vector<uint8_t> NtlmClient::GenerateAuthenticateMessage(
186*6777b538SAndroid Build Coastguard Worker     const std::u16string& domain,
187*6777b538SAndroid Build Coastguard Worker     const std::u16string& username,
188*6777b538SAndroid Build Coastguard Worker     const std::u16string& password,
189*6777b538SAndroid Build Coastguard Worker     const std::string& hostname,
190*6777b538SAndroid Build Coastguard Worker     const std::string& channel_bindings,
191*6777b538SAndroid Build Coastguard Worker     const std::string& spn,
192*6777b538SAndroid Build Coastguard Worker     uint64_t client_time,
193*6777b538SAndroid Build Coastguard Worker     base::span<const uint8_t, kChallengeLen> client_challenge,
194*6777b538SAndroid Build Coastguard Worker     base::span<const uint8_t> server_challenge_message) const {
195*6777b538SAndroid Build Coastguard Worker   // Limit the size of strings that are accepted. As an absolute limit any
196*6777b538SAndroid Build Coastguard Worker   // field represented by a |SecurityBuffer| or |AvPair| must be less than
197*6777b538SAndroid Build Coastguard Worker   // UINT16_MAX bytes long. The strings are restricted to the maximum sizes
198*6777b538SAndroid Build Coastguard Worker   // without regard to encoding. As such this isn't intended to restrict all
199*6777b538SAndroid Build Coastguard Worker   // invalid inputs, only to allow all possible valid inputs.
200*6777b538SAndroid Build Coastguard Worker   //
201*6777b538SAndroid Build Coastguard Worker   // |domain| and |hostname| can be no longer than 255 characters.
202*6777b538SAndroid Build Coastguard Worker   // |username| can be no longer than 104 characters. See [1].
203*6777b538SAndroid Build Coastguard Worker   // |password| can be no longer than 256 characters. See [2].
204*6777b538SAndroid Build Coastguard Worker   //
205*6777b538SAndroid Build Coastguard Worker   // [1] - https://technet.microsoft.com/en-us/library/bb726984.aspx
206*6777b538SAndroid Build Coastguard Worker   // [2] - https://technet.microsoft.com/en-us/library/cc512606.aspx
207*6777b538SAndroid Build Coastguard Worker   if (hostname.length() > kMaxFqdnLen || domain.length() > kMaxFqdnLen ||
208*6777b538SAndroid Build Coastguard Worker       username.length() > kMaxUsernameLen ||
209*6777b538SAndroid Build Coastguard Worker       password.length() > kMaxPasswordLen) {
210*6777b538SAndroid Build Coastguard Worker     return {};
211*6777b538SAndroid Build Coastguard Worker   }
212*6777b538SAndroid Build Coastguard Worker 
213*6777b538SAndroid Build Coastguard Worker   NegotiateFlags challenge_flags;
214*6777b538SAndroid Build Coastguard Worker   uint8_t server_challenge[kChallengeLen];
215*6777b538SAndroid Build Coastguard Worker   uint8_t lm_response[kResponseLenV1];
216*6777b538SAndroid Build Coastguard Worker   uint8_t ntlm_response[kResponseLenV1];
217*6777b538SAndroid Build Coastguard Worker 
218*6777b538SAndroid Build Coastguard Worker   // Response fields only for NTLMv2
219*6777b538SAndroid Build Coastguard Worker   std::vector<uint8_t> updated_target_info;
220*6777b538SAndroid Build Coastguard Worker   std::vector<uint8_t> v2_proof_input;
221*6777b538SAndroid Build Coastguard Worker   uint8_t v2_proof[kNtlmProofLenV2];
222*6777b538SAndroid Build Coastguard Worker   uint8_t v2_session_key[kSessionKeyLenV2];
223*6777b538SAndroid Build Coastguard Worker 
224*6777b538SAndroid Build Coastguard Worker   if (IsNtlmV2()) {
225*6777b538SAndroid Build Coastguard Worker     std::vector<AvPair> av_pairs;
226*6777b538SAndroid Build Coastguard Worker     if (!ParseChallengeMessageV2(server_challenge_message, &challenge_flags,
227*6777b538SAndroid Build Coastguard Worker                                  server_challenge, &av_pairs)) {
228*6777b538SAndroid Build Coastguard Worker       return {};
229*6777b538SAndroid Build Coastguard Worker     }
230*6777b538SAndroid Build Coastguard Worker 
231*6777b538SAndroid Build Coastguard Worker     uint64_t timestamp;
232*6777b538SAndroid Build Coastguard Worker     updated_target_info =
233*6777b538SAndroid Build Coastguard Worker         GenerateUpdatedTargetInfo(IsMicEnabled(), IsEpaEnabled(),
234*6777b538SAndroid Build Coastguard Worker                                   channel_bindings, spn, av_pairs, &timestamp);
235*6777b538SAndroid Build Coastguard Worker 
236*6777b538SAndroid Build Coastguard Worker     memset(lm_response, 0, kResponseLenV1);
237*6777b538SAndroid Build Coastguard Worker     if (timestamp == UINT64_MAX) {
238*6777b538SAndroid Build Coastguard Worker       // If the server didn't send a time, then use the clients time.
239*6777b538SAndroid Build Coastguard Worker       timestamp = client_time;
240*6777b538SAndroid Build Coastguard Worker     }
241*6777b538SAndroid Build Coastguard Worker 
242*6777b538SAndroid Build Coastguard Worker     uint8_t v2_hash[kNtlmHashLen];
243*6777b538SAndroid Build Coastguard Worker     GenerateNtlmHashV2(domain, username, password, v2_hash);
244*6777b538SAndroid Build Coastguard Worker     v2_proof_input = GenerateProofInputV2(timestamp, client_challenge);
245*6777b538SAndroid Build Coastguard Worker     GenerateNtlmProofV2(v2_hash, server_challenge,
246*6777b538SAndroid Build Coastguard Worker                         base::make_span<kProofInputLenV2>(v2_proof_input),
247*6777b538SAndroid Build Coastguard Worker                         updated_target_info, v2_proof);
248*6777b538SAndroid Build Coastguard Worker     GenerateSessionBaseKeyV2(v2_hash, v2_proof, v2_session_key);
249*6777b538SAndroid Build Coastguard Worker   } else {
250*6777b538SAndroid Build Coastguard Worker     if (!ParseChallengeMessage(server_challenge_message, &challenge_flags,
251*6777b538SAndroid Build Coastguard Worker                                server_challenge)) {
252*6777b538SAndroid Build Coastguard Worker       return {};
253*6777b538SAndroid Build Coastguard Worker     }
254*6777b538SAndroid Build Coastguard Worker 
255*6777b538SAndroid Build Coastguard Worker     // Calculate the responses for the authenticate message.
256*6777b538SAndroid Build Coastguard Worker     GenerateResponsesV1WithSessionSecurity(password, server_challenge,
257*6777b538SAndroid Build Coastguard Worker                                            client_challenge, lm_response,
258*6777b538SAndroid Build Coastguard Worker                                            ntlm_response);
259*6777b538SAndroid Build Coastguard Worker   }
260*6777b538SAndroid Build Coastguard Worker 
261*6777b538SAndroid Build Coastguard Worker   // Always use extended session security even if the server tries to downgrade.
262*6777b538SAndroid Build Coastguard Worker   NegotiateFlags authenticate_flags = (challenge_flags & negotiate_flags_) |
263*6777b538SAndroid Build Coastguard Worker                                       NegotiateFlags::kExtendedSessionSecurity;
264*6777b538SAndroid Build Coastguard Worker 
265*6777b538SAndroid Build Coastguard Worker   // Calculate all the payload lengths and offsets.
266*6777b538SAndroid Build Coastguard Worker   bool is_unicode = (authenticate_flags & NegotiateFlags::kUnicode) ==
267*6777b538SAndroid Build Coastguard Worker                     NegotiateFlags::kUnicode;
268*6777b538SAndroid Build Coastguard Worker 
269*6777b538SAndroid Build Coastguard Worker   SecurityBuffer lm_info;
270*6777b538SAndroid Build Coastguard Worker   SecurityBuffer ntlm_info;
271*6777b538SAndroid Build Coastguard Worker   SecurityBuffer domain_info;
272*6777b538SAndroid Build Coastguard Worker   SecurityBuffer username_info;
273*6777b538SAndroid Build Coastguard Worker   SecurityBuffer hostname_info;
274*6777b538SAndroid Build Coastguard Worker   SecurityBuffer session_key_info;
275*6777b538SAndroid Build Coastguard Worker   size_t authenticate_message_len;
276*6777b538SAndroid Build Coastguard Worker 
277*6777b538SAndroid Build Coastguard Worker   if (!CalculatePayloadLayout(is_unicode, domain, username, hostname,
278*6777b538SAndroid Build Coastguard Worker                               updated_target_info.size(), &lm_info, &ntlm_info,
279*6777b538SAndroid Build Coastguard Worker                               &domain_info, &username_info, &hostname_info,
280*6777b538SAndroid Build Coastguard Worker                               &session_key_info, &authenticate_message_len)) {
281*6777b538SAndroid Build Coastguard Worker     return {};
282*6777b538SAndroid Build Coastguard Worker   }
283*6777b538SAndroid Build Coastguard Worker 
284*6777b538SAndroid Build Coastguard Worker   NtlmBufferWriter authenticate_writer(authenticate_message_len);
285*6777b538SAndroid Build Coastguard Worker   bool writer_result = WriteAuthenticateMessage(
286*6777b538SAndroid Build Coastguard Worker       &authenticate_writer, lm_info, ntlm_info, domain_info, username_info,
287*6777b538SAndroid Build Coastguard Worker       hostname_info, session_key_info, authenticate_flags);
288*6777b538SAndroid Build Coastguard Worker   DCHECK(writer_result);
289*6777b538SAndroid Build Coastguard Worker 
290*6777b538SAndroid Build Coastguard Worker   if (IsNtlmV2()) {
291*6777b538SAndroid Build Coastguard Worker     // Write the optional (for V1) Version and MIC fields. Note that they
292*6777b538SAndroid Build Coastguard Worker     // could also safely be sent in V1. However, the server should never try to
293*6777b538SAndroid Build Coastguard Worker     // read them, because neither the version negotiate flag nor the
294*6777b538SAndroid Build Coastguard Worker     // |TargetInfoAvFlags::kMicPresent| in the target info are set.
295*6777b538SAndroid Build Coastguard Worker     //
296*6777b538SAndroid Build Coastguard Worker     // Version is never supported so it is filled with zeros. MIC is a hash
297*6777b538SAndroid Build Coastguard Worker     // calculated over all 3 messages while the MIC is set to zeros then
298*6777b538SAndroid Build Coastguard Worker     // backfilled at the end if the MIC feature is enabled.
299*6777b538SAndroid Build Coastguard Worker     writer_result = authenticate_writer.WriteZeros(kVersionFieldLen) &&
300*6777b538SAndroid Build Coastguard Worker                     authenticate_writer.WriteZeros(kMicLenV2);
301*6777b538SAndroid Build Coastguard Worker 
302*6777b538SAndroid Build Coastguard Worker     DCHECK(writer_result);
303*6777b538SAndroid Build Coastguard Worker   }
304*6777b538SAndroid Build Coastguard Worker 
305*6777b538SAndroid Build Coastguard Worker   // Verify the location in the payload buffer.
306*6777b538SAndroid Build Coastguard Worker   DCHECK(authenticate_writer.GetCursor() == GetAuthenticateHeaderLength());
307*6777b538SAndroid Build Coastguard Worker   DCHECK(GetAuthenticateHeaderLength() == lm_info.offset);
308*6777b538SAndroid Build Coastguard Worker 
309*6777b538SAndroid Build Coastguard Worker   if (IsNtlmV2()) {
310*6777b538SAndroid Build Coastguard Worker     // Write the response payloads for V2.
311*6777b538SAndroid Build Coastguard Worker     writer_result =
312*6777b538SAndroid Build Coastguard Worker         WriteResponsePayloadsV2(&authenticate_writer, lm_response, v2_proof,
313*6777b538SAndroid Build Coastguard Worker                                 v2_proof_input, updated_target_info);
314*6777b538SAndroid Build Coastguard Worker   } else {
315*6777b538SAndroid Build Coastguard Worker     // Write the response payloads.
316*6777b538SAndroid Build Coastguard Worker     DCHECK_EQ(kResponseLenV1, lm_info.length);
317*6777b538SAndroid Build Coastguard Worker     DCHECK_EQ(kResponseLenV1, ntlm_info.length);
318*6777b538SAndroid Build Coastguard Worker     writer_result =
319*6777b538SAndroid Build Coastguard Worker         WriteResponsePayloads(&authenticate_writer, lm_response, ntlm_response);
320*6777b538SAndroid Build Coastguard Worker   }
321*6777b538SAndroid Build Coastguard Worker 
322*6777b538SAndroid Build Coastguard Worker   DCHECK(writer_result);
323*6777b538SAndroid Build Coastguard Worker   DCHECK_EQ(authenticate_writer.GetCursor(), domain_info.offset);
324*6777b538SAndroid Build Coastguard Worker 
325*6777b538SAndroid Build Coastguard Worker   writer_result = WriteStringPayloads(&authenticate_writer, is_unicode, domain,
326*6777b538SAndroid Build Coastguard Worker                                       username, hostname);
327*6777b538SAndroid Build Coastguard Worker   DCHECK(writer_result);
328*6777b538SAndroid Build Coastguard Worker   DCHECK(authenticate_writer.IsEndOfBuffer());
329*6777b538SAndroid Build Coastguard Worker   DCHECK_EQ(authenticate_message_len, authenticate_writer.GetLength());
330*6777b538SAndroid Build Coastguard Worker 
331*6777b538SAndroid Build Coastguard Worker   std::vector<uint8_t> auth_msg = authenticate_writer.Pass();
332*6777b538SAndroid Build Coastguard Worker 
333*6777b538SAndroid Build Coastguard Worker   // Backfill the MIC if enabled.
334*6777b538SAndroid Build Coastguard Worker   if (IsMicEnabled()) {
335*6777b538SAndroid Build Coastguard Worker     // The MIC has to be generated over all 3 completed messages with the MIC
336*6777b538SAndroid Build Coastguard Worker     // set to zeros.
337*6777b538SAndroid Build Coastguard Worker     DCHECK_LT(kMicOffsetV2 + kMicLenV2, authenticate_message_len);
338*6777b538SAndroid Build Coastguard Worker 
339*6777b538SAndroid Build Coastguard Worker     base::span<uint8_t, kMicLenV2> mic(
340*6777b538SAndroid Build Coastguard Worker         const_cast<uint8_t*>(auth_msg.data()) + kMicOffsetV2, kMicLenV2);
341*6777b538SAndroid Build Coastguard Worker     GenerateMicV2(v2_session_key, negotiate_message_, server_challenge_message,
342*6777b538SAndroid Build Coastguard Worker                   auth_msg, mic);
343*6777b538SAndroid Build Coastguard Worker   }
344*6777b538SAndroid Build Coastguard Worker 
345*6777b538SAndroid Build Coastguard Worker   return auth_msg;
346*6777b538SAndroid Build Coastguard Worker }
347*6777b538SAndroid Build Coastguard Worker 
CalculatePayloadLayout(bool is_unicode,const std::u16string & domain,const std::u16string & username,const std::string & hostname,size_t updated_target_info_len,SecurityBuffer * lm_info,SecurityBuffer * ntlm_info,SecurityBuffer * domain_info,SecurityBuffer * username_info,SecurityBuffer * hostname_info,SecurityBuffer * session_key_info,size_t * authenticate_message_len) const348*6777b538SAndroid Build Coastguard Worker bool NtlmClient::CalculatePayloadLayout(
349*6777b538SAndroid Build Coastguard Worker     bool is_unicode,
350*6777b538SAndroid Build Coastguard Worker     const std::u16string& domain,
351*6777b538SAndroid Build Coastguard Worker     const std::u16string& username,
352*6777b538SAndroid Build Coastguard Worker     const std::string& hostname,
353*6777b538SAndroid Build Coastguard Worker     size_t updated_target_info_len,
354*6777b538SAndroid Build Coastguard Worker     SecurityBuffer* lm_info,
355*6777b538SAndroid Build Coastguard Worker     SecurityBuffer* ntlm_info,
356*6777b538SAndroid Build Coastguard Worker     SecurityBuffer* domain_info,
357*6777b538SAndroid Build Coastguard Worker     SecurityBuffer* username_info,
358*6777b538SAndroid Build Coastguard Worker     SecurityBuffer* hostname_info,
359*6777b538SAndroid Build Coastguard Worker     SecurityBuffer* session_key_info,
360*6777b538SAndroid Build Coastguard Worker     size_t* authenticate_message_len) const {
361*6777b538SAndroid Build Coastguard Worker   uint32_t offset = GetAuthenticateHeaderLength();
362*6777b538SAndroid Build Coastguard Worker   if (!ComputeSecurityBuffer(&offset, 0, session_key_info) ||
363*6777b538SAndroid Build Coastguard Worker       !ComputeSecurityBuffer(&offset, kResponseLenV1, lm_info) ||
364*6777b538SAndroid Build Coastguard Worker       !ComputeSecurityBuffer(
365*6777b538SAndroid Build Coastguard Worker           &offset, GetNtlmResponseLength(updated_target_info_len), ntlm_info) ||
366*6777b538SAndroid Build Coastguard Worker       !ComputeSecurityBuffer(
367*6777b538SAndroid Build Coastguard Worker           &offset, GetStringPayloadLength(domain, is_unicode), domain_info) ||
368*6777b538SAndroid Build Coastguard Worker       !ComputeSecurityBuffer(&offset,
369*6777b538SAndroid Build Coastguard Worker                              GetStringPayloadLength(username, is_unicode),
370*6777b538SAndroid Build Coastguard Worker                              username_info) ||
371*6777b538SAndroid Build Coastguard Worker       !ComputeSecurityBuffer(&offset,
372*6777b538SAndroid Build Coastguard Worker                              GetStringPayloadLength(hostname, is_unicode),
373*6777b538SAndroid Build Coastguard Worker                              hostname_info)) {
374*6777b538SAndroid Build Coastguard Worker     return false;
375*6777b538SAndroid Build Coastguard Worker   }
376*6777b538SAndroid Build Coastguard Worker 
377*6777b538SAndroid Build Coastguard Worker   *authenticate_message_len = offset;
378*6777b538SAndroid Build Coastguard Worker   return true;
379*6777b538SAndroid Build Coastguard Worker }
380*6777b538SAndroid Build Coastguard Worker 
GetAuthenticateHeaderLength() const381*6777b538SAndroid Build Coastguard Worker size_t NtlmClient::GetAuthenticateHeaderLength() const {
382*6777b538SAndroid Build Coastguard Worker   if (IsNtlmV2()) {
383*6777b538SAndroid Build Coastguard Worker     return kAuthenticateHeaderLenV2;
384*6777b538SAndroid Build Coastguard Worker   }
385*6777b538SAndroid Build Coastguard Worker 
386*6777b538SAndroid Build Coastguard Worker   return kAuthenticateHeaderLenV1;
387*6777b538SAndroid Build Coastguard Worker }
388*6777b538SAndroid Build Coastguard Worker 
GetNtlmResponseLength(size_t updated_target_info_len) const389*6777b538SAndroid Build Coastguard Worker size_t NtlmClient::GetNtlmResponseLength(size_t updated_target_info_len) const {
390*6777b538SAndroid Build Coastguard Worker   if (IsNtlmV2()) {
391*6777b538SAndroid Build Coastguard Worker     return kNtlmResponseHeaderLenV2 + updated_target_info_len + 4;
392*6777b538SAndroid Build Coastguard Worker   }
393*6777b538SAndroid Build Coastguard Worker 
394*6777b538SAndroid Build Coastguard Worker   return kResponseLenV1;
395*6777b538SAndroid Build Coastguard Worker }
396*6777b538SAndroid Build Coastguard Worker 
397*6777b538SAndroid Build Coastguard Worker }  // namespace net::ntlm
398