Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(172)

Side by Side Diff: net/ntlm/ntlm_client.cc

Issue 2904633002: Replace NTLMv1 implementation with a functionally equivalent one.
Patch Set: Only return malloc memory from NtlmClient Created 3 years, 5 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(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
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698