OLD | NEW |
---|---|
(Empty) | |
1 // Copyright 2017 The Chromium Authors. All rights reserved. | |
2 // Use of this source code is governed by a BSD-style license that can be | |
3 // found in the LICENSE file. | |
4 | |
5 #include "net/ntlm/ntlm_client.h" | |
6 | |
7 #include <string.h> | |
8 | |
9 #include "base/logging.h" | |
10 #include "base/strings/utf_string_conversions.h" | |
11 #include "net/ntlm/ntlm.h" | |
12 #include "net/ntlm/ntlm_buffer_reader.h" | |
13 #include "net/ntlm/ntlm_buffer_writer.h" | |
14 | |
15 namespace net { | |
16 namespace ntlm { | |
17 | |
18 namespace { | |
19 // Parses the challenge message and returns the |challenge_flags| and writes | |
20 // the |server_challenge| into the supplied buffer. | |
21 // |server_challenge| must contain at least 8 bytes. | |
22 static bool ParseChallengeMessage(const uint8_t* challenge_message, | |
asanka
2017/07/14 16:52:39
|static| is redundant within an anonymous namespac
zentaro
2017/07/19 15:20:12
Done.
| |
23 size_t challenge_message_len, | |
24 NegotiateFlags* challenge_flags, | |
25 uint8_t* server_challenge) { | |
26 NtlmBufferReader challenge_reader(challenge_message, challenge_message_len); | |
27 | |
28 return challenge_reader.MatchMessageHeader(MessageType::kChallenge) && | |
29 challenge_reader.SkipSecurityBufferWithValidation() && | |
30 challenge_reader.ReadFlags(challenge_flags) && | |
31 challenge_reader.ReadBytes(server_challenge, kChallengeLen); | |
32 } | |
33 | |
34 static bool WriteAuthenticateMessage(NtlmBufferWriter* authenticate_writer, | |
35 SecurityBuffer lm_payload, | |
36 SecurityBuffer ntlm_payload, | |
37 SecurityBuffer domain_payload, | |
38 SecurityBuffer username_payload, | |
39 SecurityBuffer hostname_payload, | |
40 NegotiateFlags authenticate_flags) { | |
41 return authenticate_writer->WriteMessageHeader(MessageType::kAuthenticate) && | |
42 authenticate_writer->WriteSecurityBuffer(lm_payload) && | |
43 authenticate_writer->WriteSecurityBuffer(ntlm_payload) && | |
44 authenticate_writer->WriteSecurityBuffer(domain_payload) && | |
45 authenticate_writer->WriteSecurityBuffer(username_payload) && | |
46 authenticate_writer->WriteSecurityBuffer(hostname_payload) && | |
47 authenticate_writer->WriteSecurityBuffer( | |
48 SecurityBuffer(kAuthenticateHeaderLenV1, 0)) && | |
49 authenticate_writer->WriteFlags(authenticate_flags); | |
50 } | |
51 | |
52 static bool WriteResponsePayloads(NtlmBufferWriter* authenticate_writer, | |
53 const uint8_t* lm_response, | |
54 size_t lm_response_len, | |
55 const uint8_t* ntlm_response, | |
56 size_t ntlm_response_len) { | |
57 return authenticate_writer->WriteBytes(lm_response, lm_response_len) && | |
58 authenticate_writer->WriteBytes(ntlm_response, ntlm_response_len); | |
59 } | |
60 | |
61 static bool WriteStringPayloads(NtlmBufferWriter* authenticate_writer, | |
62 bool is_unicode, | |
63 const base::string16& domain, | |
64 const base::string16& username, | |
65 const std::string hostname) { | |
asanka
2017/07/14 16:52:39
Use a |const std::string&| here. Otherwise you are
zentaro
2017/07/19 15:20:12
Done.
| |
66 if (is_unicode) { | |
67 return authenticate_writer->WriteUtf16String(domain) && | |
68 authenticate_writer->WriteUtf16String(username) && | |
69 authenticate_writer->WriteUtf8AsUtf16String(hostname); | |
70 } else { | |
71 return authenticate_writer->WriteUtf16AsUtf8String(domain) && | |
72 authenticate_writer->WriteUtf16AsUtf8String(username) && | |
73 authenticate_writer->WriteUtf8String(hostname); | |
74 } | |
75 } | |
76 | |
77 // Returns the size in bytes of a string16 depending whether unicode | |
78 // was negotiated. | |
79 static size_t GetStringPayloadLength(const base::string16& str, | |
80 bool is_unicode) { | |
81 if (is_unicode) | |
82 return str.length() * 2; | |
83 | |
84 // When |WriteUtf16AsUtf8String| is called with a |base::string16|, the string | |
85 // is converted to UTF8. Do the conversion to ensure that the character | |
86 // count is correct. | |
87 return base::UTF16ToUTF8(str).length(); | |
88 } | |
89 | |
90 // Returns the size in bytes of a std::string depending whether unicode | |
91 // was negotiated. | |
92 static size_t GetStringPayloadLength(const std::string& str, bool is_unicode) { | |
93 if (!is_unicode) | |
94 return str.length(); | |
95 | |
96 return base::UTF8ToUTF16(str).length() * 2; | |
97 } | |
98 | |
99 } // namespace | |
100 | |
101 NtlmClient::NtlmClient() : negotiate_flags_(kNegotiateMessageFlags) { | |
asanka
2017/07/14 16:52:39
why store negotiate_flags_ here? It's essentially
zentaro
2017/07/19 15:20:12
In the next cl for v2 - I allow it along with a fe
| |
102 // Just generate the negotiate message once and hold on to it. It never | |
103 // changes and in a NTLMv2 it's used as an input | |
104 // to the Message Integrity Check in the Authenticate message. | |
105 GenerateNegotiateMessage(); | |
106 } | |
107 | |
108 NtlmClient::~NtlmClient() {} | |
109 | |
110 void NtlmClient::GetNegotiateMessage(uint8_t** negotiate_message, | |
111 size_t* negotiate_message_len) const { | |
112 *negotiate_message_len = kNegotiateMessageLen; | |
113 *negotiate_message = static_cast<uint8_t*>(malloc(kNegotiateMessageLen)); | |
114 memcpy(*negotiate_message, negotiate_message_.get(), kNegotiateMessageLen); | |
115 } | |
116 | |
117 void NtlmClient::GenerateNegotiateMessage() { | |
118 NtlmBufferWriter writer(kNegotiateMessageLen); | |
119 bool result = | |
120 writer.WriteMessageHeader(MessageType::kNegotiate) && | |
121 writer.WriteFlags(negotiate_flags_) && | |
122 writer.WriteSecurityBuffer(SecurityBuffer(kNegotiateMessageLen, 0)) && | |
123 writer.WriteSecurityBuffer(SecurityBuffer(kNegotiateMessageLen, 0)) && | |
124 writer.IsEndOfBuffer(); | |
125 | |
126 DCHECK(result); | |
127 | |
128 negotiate_message_.reset(new uint8_t[writer.GetLength()]); | |
asanka
2017/07/14 16:52:39
Why create a new copy of the writer's buffer?
zentaro
2017/07/19 15:20:12
N/A - It's a string now.
| |
129 memcpy(negotiate_message_.get(), writer.GetBuffer().data(), | |
130 writer.GetLength()); | |
131 } | |
132 | |
133 bool NtlmClient::GenerateAuthenticateMessage( | |
134 const base::string16& domain, | |
135 const base::string16& username, | |
136 const base::string16& password, | |
137 const std::string& hostname, | |
138 const uint8_t* client_challenge, | |
139 const uint8_t* challenge_message, | |
140 size_t challenge_message_len, | |
141 uint8_t** authenticate_message, | |
142 size_t* authenticate_message_len) const { | |
143 *authenticate_message = nullptr; | |
144 *authenticate_message_len = 0; | |
145 NegotiateFlags challenge_flags; | |
146 uint8_t server_challenge[kChallengeLen]; | |
147 | |
148 if (!ParseChallengeMessage(challenge_message, challenge_message_len, | |
149 &challenge_flags, server_challenge)) { | |
150 return false; | |
151 } | |
152 | |
153 // Calculate the responses for the authenticate message. | |
154 uint8_t lm_response[kResponseLenV1]; | |
155 uint8_t ntlm_response[kResponseLenV1]; | |
156 | |
157 // Always use extended session security even if the server tries to downgrade. | |
158 NegotiateFlags authenticate_flags = (challenge_flags & negotiate_flags_) | | |
159 NegotiateFlags::kExtendedSessionSecurity; | |
160 | |
161 // Generate the LM and NTLM responses. | |
162 GenerateResponsesV1WithSessionSecurity( | |
163 password, server_challenge, client_challenge, lm_response, ntlm_response); | |
164 | |
165 // Calculate all the payload lengths and offsets. | |
166 bool is_unicode = | |
167 static_cast<bool>(authenticate_flags & NegotiateFlags::kUnicode); | |
asanka
2017/07/14 16:52:39
bool is_unicode = (authenticate_flags & NegotiateF
zentaro
2017/07/19 15:20:12
Done.
| |
168 | |
169 SecurityBuffer lm_info; | |
170 SecurityBuffer ntlm_info; | |
171 SecurityBuffer domain_info; | |
172 SecurityBuffer username_info; | |
173 SecurityBuffer hostname_info; | |
174 CalculatePayloadLayout(is_unicode, domain, username, hostname, &lm_info, | |
175 &ntlm_info, &domain_info, &username_info, | |
176 &hostname_info, authenticate_message_len); | |
177 | |
178 // Write the authenticate message header. | |
179 NtlmBufferWriter authenticate_writer(*authenticate_message_len); | |
180 bool writer_result = WriteAuthenticateMessage( | |
181 &authenticate_writer, lm_info, ntlm_info, domain_info, username_info, | |
182 hostname_info, authenticate_flags); | |
183 DCHECK(writer_result); | |
184 DCHECK(authenticate_writer.GetCursor() == GetAuthenticateHeaderLength()); | |
asanka
2017/07/14 16:52:39
DCHECK_EQ here and elsewhere.
zentaro
2017/07/19 15:20:12
Done.
| |
185 | |
186 // Write the response payloads. | |
asanka
2017/07/14 16:52:39
many of these comments seem unnecessary since the
zentaro
2017/07/19 15:20:12
Deleted.
| |
187 writer_result = | |
188 WriteResponsePayloads(&authenticate_writer, lm_response, lm_info.length, | |
189 ntlm_response, ntlm_info.length); | |
190 DCHECK(writer_result); | |
191 DCHECK(authenticate_writer.GetCursor() == domain_info.offset); | |
192 | |
193 // Write the string field payloads. | |
194 writer_result = WriteStringPayloads(&authenticate_writer, is_unicode, domain, | |
195 username, hostname); | |
196 DCHECK(writer_result); | |
197 DCHECK(authenticate_writer.IsEndOfBuffer()); | |
198 DCHECK(*authenticate_message_len == authenticate_writer.GetLength()); | |
199 | |
200 *authenticate_message = | |
201 static_cast<uint8_t*>(malloc(authenticate_writer.GetLength())); | |
asanka
2017/07/14 16:52:39
let's avoid unnecessary buffer copies.
zentaro
2017/07/19 15:20:12
N/A string now.
| |
202 memcpy(*authenticate_message, authenticate_writer.GetBuffer().data(), | |
203 authenticate_writer.GetLength()); | |
204 return true; | |
205 } | |
206 | |
207 void NtlmClient::CalculatePayloadLayout( | |
208 bool is_unicode, | |
209 const base::string16& domain, | |
210 const base::string16& username, | |
211 const std::string& hostname, | |
212 SecurityBuffer* lm_info, | |
213 SecurityBuffer* ntlm_info, | |
214 SecurityBuffer* domain_info, | |
215 SecurityBuffer* username_info, | |
216 SecurityBuffer* hostname_info, | |
217 size_t* authenticate_message_len) const { | |
218 size_t upto = GetAuthenticateHeaderLength(); | |
219 | |
220 lm_info->offset = upto; | |
221 lm_info->length = kResponseLenV1; | |
222 upto += lm_info->length; | |
223 | |
224 ntlm_info->offset = upto; | |
225 ntlm_info->length = GetNtlmResponseLength(); | |
226 upto += ntlm_info->length; | |
227 | |
228 domain_info->offset = upto; | |
229 domain_info->length = GetStringPayloadLength(domain, is_unicode); | |
230 upto += domain_info->length; | |
231 | |
232 username_info->offset = upto; | |
233 username_info->length = GetStringPayloadLength(username, is_unicode); | |
234 upto += username_info->length; | |
235 | |
236 hostname_info->offset = upto; | |
237 hostname_info->length = GetStringPayloadLength(hostname, is_unicode); | |
238 upto += hostname_info->length; | |
239 | |
240 *authenticate_message_len = upto; | |
241 } | |
242 | |
243 size_t NtlmClient::GetAuthenticateHeaderLength() const { | |
244 return kAuthenticateHeaderLenV1; | |
245 } | |
246 | |
247 size_t NtlmClient::GetNtlmResponseLength() const { | |
248 return kResponseLenV1; | |
249 } | |
250 | |
251 } // namespace ntlm | |
252 } // namespace net | |
OLD | NEW |