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 | |
20 // |server_challenge| into the supplied buffer. | |
21 // |server_challenge| must contain at least 8 bytes. | |
22 bool ParseChallengeMessage(const Buffer& challenge_message, | |
23 NegotiateFlags* challenge_flags, | |
24 uint8_t* server_challenge) { | |
25 NtlmBufferReader challenge_reader(challenge_message); | |
26 | |
27 return challenge_reader.MatchMessageHeader(MessageType::kChallenge) && | |
28 challenge_reader.SkipSecurityBufferWithValidation() && | |
29 challenge_reader.ReadFlags(challenge_flags) && | |
30 challenge_reader.ReadBytes(server_challenge, kChallengeLen); | |
31 } | |
32 | |
33 bool WriteAuthenticateMessage(NtlmBufferWriter* authenticate_writer, | |
34 SecurityBuffer lm_payload, | |
35 SecurityBuffer ntlm_payload, | |
36 SecurityBuffer domain_payload, | |
37 SecurityBuffer username_payload, | |
38 SecurityBuffer hostname_payload, | |
39 NegotiateFlags authenticate_flags) { | |
40 return authenticate_writer->WriteMessageHeader(MessageType::kAuthenticate) && | |
41 authenticate_writer->WriteSecurityBuffer(lm_payload) && | |
42 authenticate_writer->WriteSecurityBuffer(ntlm_payload) && | |
43 authenticate_writer->WriteSecurityBuffer(domain_payload) && | |
44 authenticate_writer->WriteSecurityBuffer(username_payload) && | |
45 authenticate_writer->WriteSecurityBuffer(hostname_payload) && | |
46 authenticate_writer->WriteSecurityBuffer( | |
47 SecurityBuffer(kAuthenticateHeaderLenV1, 0)) && | |
48 authenticate_writer->WriteFlags(authenticate_flags); | |
49 } | |
50 | |
51 bool WriteResponsePayloads(NtlmBufferWriter* authenticate_writer, | |
52 const uint8_t* lm_response, | |
53 size_t lm_response_len, | |
54 const uint8_t* ntlm_response, | |
55 size_t ntlm_response_len) { | |
56 return authenticate_writer->WriteBytes(lm_response, lm_response_len) && | |
57 authenticate_writer->WriteBytes(ntlm_response, ntlm_response_len); | |
58 } | |
59 | |
60 bool WriteStringPayloads(NtlmBufferWriter* authenticate_writer, | |
61 bool is_unicode, | |
62 const base::string16& domain, | |
63 const base::string16& username, | |
64 const std::string& hostname) { | |
65 if (is_unicode) { | |
66 return authenticate_writer->WriteUtf16String(domain) && | |
67 authenticate_writer->WriteUtf16String(username) && | |
68 authenticate_writer->WriteUtf8AsUtf16String(hostname); | |
69 } else { | |
70 return authenticate_writer->WriteUtf16AsUtf8String(domain) && | |
71 authenticate_writer->WriteUtf16AsUtf8String(username) && | |
72 authenticate_writer->WriteUtf8String(hostname); | |
73 } | |
74 } | |
75 | |
76 // Returns the size in bytes of a string16 depending whether unicode | |
77 // was negotiated. | |
78 size_t GetStringPayloadLength(const base::string16& str, bool is_unicode) { | |
79 if (is_unicode) | |
80 return str.length() * 2; | |
81 | |
82 // When |WriteUtf16AsUtf8String| is called with a |base::string16|, the string | |
83 // is converted to UTF8. Do the conversion to ensure that the character | |
84 // count is correct. | |
85 return base::UTF16ToUTF8(str).length(); | |
86 } | |
87 | |
88 // Returns the size in bytes of a std::string depending whether unicode | |
89 // was negotiated. | |
90 size_t GetStringPayloadLength(const std::string& str, bool is_unicode) { | |
91 if (!is_unicode) | |
92 return str.length(); | |
93 | |
94 return base::UTF8ToUTF16(str).length() * 2; | |
95 } | |
96 | |
97 } // namespace | |
98 | |
99 NtlmClient::NtlmClient() : negotiate_flags_(kNegotiateMessageFlags) { | |
100 // Just generate the negotiate message once and hold on to it. It never | |
101 // changes and in a NTLMv2 it's used as an input | |
102 // to the Message Integrity Check in the Authenticate message. | |
103 GenerateNegotiateMessage(); | |
104 } | |
105 | |
106 NtlmClient::~NtlmClient() {} | |
107 | |
108 Buffer NtlmClient::GetNegotiateMessage() const { | |
109 return negotiate_message_; | |
110 } | |
111 | |
112 void NtlmClient::GenerateNegotiateMessage() { | |
113 NtlmBufferWriter writer(kNegotiateMessageLen); | |
114 bool result = | |
115 writer.WriteMessageHeader(MessageType::kNegotiate) && | |
116 writer.WriteFlags(negotiate_flags_) && | |
117 writer.WriteSecurityBuffer(SecurityBuffer(kNegotiateMessageLen, 0)) && | |
118 writer.WriteSecurityBuffer(SecurityBuffer(kNegotiateMessageLen, 0)) && | |
119 writer.IsEndOfBuffer(); | |
120 | |
121 DCHECK(result); | |
122 | |
123 negotiate_message_ = writer.Pass(); | |
124 } | |
125 | |
126 Buffer NtlmClient::GenerateAuthenticateMessage( | |
127 const base::string16& domain, | |
128 const base::string16& username, | |
129 const base::string16& password, | |
130 const std::string& hostname, | |
131 const uint8_t* client_challenge, | |
132 const Buffer& server_challenge_message) const { | |
133 NegotiateFlags challenge_flags; | |
134 uint8_t server_challenge[kChallengeLen]; | |
135 | |
136 // Read the flags and the servers random challenge from the challenge | |
mmenke
2017/07/20 19:44:50
nit: server's
zentaro
2017/08/01 18:21:36
Done.
| |
137 // message. | |
138 if (!ParseChallengeMessage(server_challenge_message, &challenge_flags, | |
139 server_challenge)) { | |
140 return Buffer(); | |
141 } | |
142 | |
143 // Calculate the responses for the authenticate message. | |
144 uint8_t lm_response[kResponseLenV1]; | |
145 uint8_t ntlm_response[kResponseLenV1]; | |
146 | |
147 // Always use extended session security even if the server tries to downgrade. | |
148 NegotiateFlags authenticate_flags = (challenge_flags & negotiate_flags_) | | |
149 NegotiateFlags::kExtendedSessionSecurity; | |
150 | |
151 // Generate the LM and NTLM responses. | |
152 GenerateResponsesV1WithSessionSecurity( | |
153 password, server_challenge, client_challenge, lm_response, ntlm_response); | |
154 | |
155 // Calculate all the payload lengths and offsets. | |
156 bool is_unicode = (authenticate_flags & NegotiateFlags::kUnicode) == | |
157 NegotiateFlags::kUnicode; | |
158 | |
159 SecurityBuffer lm_info; | |
160 SecurityBuffer ntlm_info; | |
161 SecurityBuffer domain_info; | |
162 SecurityBuffer username_info; | |
163 SecurityBuffer hostname_info; | |
164 size_t authenticate_message_len; | |
165 CalculatePayloadLayout(is_unicode, domain, username, hostname, &lm_info, | |
166 &ntlm_info, &domain_info, &username_info, | |
167 &hostname_info, &authenticate_message_len); | |
168 | |
169 NtlmBufferWriter authenticate_writer(authenticate_message_len); | |
170 bool writer_result = WriteAuthenticateMessage( | |
171 &authenticate_writer, lm_info, ntlm_info, domain_info, username_info, | |
172 hostname_info, authenticate_flags); | |
173 DCHECK(writer_result); | |
174 DCHECK_EQ(authenticate_writer.GetCursor(), GetAuthenticateHeaderLength()); | |
175 | |
176 writer_result = | |
177 WriteResponsePayloads(&authenticate_writer, lm_response, lm_info.length, | |
178 ntlm_response, ntlm_info.length); | |
179 DCHECK(writer_result); | |
180 DCHECK_EQ(authenticate_writer.GetCursor(), domain_info.offset); | |
181 | |
182 writer_result = WriteStringPayloads(&authenticate_writer, is_unicode, domain, | |
183 username, hostname); | |
184 DCHECK(writer_result); | |
185 DCHECK(authenticate_writer.IsEndOfBuffer()); | |
186 DCHECK_EQ(authenticate_message_len, authenticate_writer.GetLength()); | |
187 | |
188 return authenticate_writer.Pass(); | |
189 } | |
190 | |
191 void NtlmClient::CalculatePayloadLayout( | |
192 bool is_unicode, | |
193 const base::string16& domain, | |
194 const base::string16& username, | |
195 const std::string& hostname, | |
196 SecurityBuffer* lm_info, | |
197 SecurityBuffer* ntlm_info, | |
198 SecurityBuffer* domain_info, | |
199 SecurityBuffer* username_info, | |
200 SecurityBuffer* hostname_info, | |
201 size_t* authenticate_message_len) const { | |
202 size_t upto = GetAuthenticateHeaderLength(); | |
203 | |
204 lm_info->offset = upto; | |
205 lm_info->length = kResponseLenV1; | |
206 upto += lm_info->length; | |
207 | |
208 ntlm_info->offset = upto; | |
209 ntlm_info->length = GetNtlmResponseLength(); | |
210 upto += ntlm_info->length; | |
211 | |
212 domain_info->offset = upto; | |
213 domain_info->length = GetStringPayloadLength(domain, is_unicode); | |
214 upto += domain_info->length; | |
215 | |
216 username_info->offset = upto; | |
217 username_info->length = GetStringPayloadLength(username, is_unicode); | |
218 upto += username_info->length; | |
219 | |
220 hostname_info->offset = upto; | |
221 hostname_info->length = GetStringPayloadLength(hostname, is_unicode); | |
222 upto += hostname_info->length; | |
223 | |
224 *authenticate_message_len = upto; | |
225 } | |
226 | |
227 size_t NtlmClient::GetAuthenticateHeaderLength() const { | |
228 return kAuthenticateHeaderLenV1; | |
229 } | |
230 | |
231 size_t NtlmClient::GetNtlmResponseLength() const { | |
232 return kResponseLenV1; | |
233 } | |
234 | |
235 } // namespace ntlm | |
236 } // namespace net | |
OLD | NEW |