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/http/ntlm_buffer_reader.h" | |
6 | |
7 #include <string.h> | |
8 | |
9 #include "base/logging.h" | |
10 | |
11 namespace net { | |
asanka
2017/06/16 03:21:29
Curious. Why aren't these in namespace ntlm {} ?
zentaro
2017/06/21 00:38:46
Oversight. Done.
| |
12 | |
13 #if defined(ARCH_CPU_LITTLE_ENDIAN) | |
14 #define IS_LITTLE_ENDIAN 1 | |
15 #undef IS_BIG_ENDIAN | |
16 #elif defined(ARCH_CPU_BIG_ENDIAN) | |
17 #define IS_BIG_ENDIAN 1 | |
18 #undef IS_LITTLE_ENDIAN | |
19 #else | |
20 #error "Unknown endianness" | |
21 #endif | |
22 | |
23 NtlmBufferReader::NtlmBufferReader(base::StringPiece buffer) | |
24 : buffer_(buffer), cursor_(0) { | |
25 DCHECK(buffer.data()); | |
26 } | |
27 | |
28 NtlmBufferReader::NtlmBufferReader(const uint8_t* ptr, size_t len) | |
29 : NtlmBufferReader( | |
30 base::StringPiece(reinterpret_cast<const char*>(ptr), len)) {} | |
31 | |
32 NtlmBufferReader::~NtlmBufferReader() {} | |
33 | |
34 bool NtlmBufferReader::CanRead(size_t len) const { | |
35 return CanReadFrom(GetCursor(), len); | |
36 } | |
37 | |
38 bool NtlmBufferReader::CanReadFrom(size_t offset, size_t len) const { | |
39 if (len == 0) | |
40 return true; | |
41 | |
42 return (len <= GetLength() && offset <= GetLength() - len); | |
43 } | |
44 | |
45 void NtlmBufferReader::SetCursor(size_t cursor) { | |
46 DCHECK(cursor <= GetLength()); | |
asanka
2017/06/16 03:21:28
DCHECK_LE
zentaro
2017/06/21 00:38:46
Done.
| |
47 | |
48 cursor_ = cursor; | |
49 } | |
50 | |
51 bool NtlmBufferReader::ReadUInt16(uint16_t* value) { | |
52 return ReadUInt<uint16_t>(value); | |
53 } | |
54 | |
55 bool NtlmBufferReader::ReadUInt32(uint32_t* value) { | |
56 return ReadUInt<uint32_t>(value); | |
57 } | |
58 | |
59 bool NtlmBufferReader::ReadUInt64(uint64_t* value) { | |
60 return ReadUInt<uint64_t>(value); | |
61 } | |
62 | |
63 bool NtlmBufferReader::ReadFlags(ntlm::NegotiateFlags* flags) { | |
64 uint32_t raw; | |
65 if (!ReadUInt32(&raw)) | |
66 return false; | |
67 | |
68 *flags = static_cast<ntlm::NegotiateFlags>(raw); | |
69 return true; | |
70 } | |
71 | |
72 template <typename T> | |
73 bool NtlmBufferReader::ReadUInt(T* value) { | |
74 size_t int_size = sizeof(T); | |
75 if (!CanRead(int_size)) | |
76 return false; | |
77 | |
78 *value = 0; | |
79 for (size_t i = 0; i < int_size; i++) { | |
80 *value += static_cast<T>(GetByteAtCursor()) << (i * 8); | |
81 AdvanceCursor(1); | |
82 } | |
83 | |
84 return true; | |
85 } | |
86 | |
87 bool NtlmBufferReader::ReadBytes(uint8_t* buffer, size_t len) { | |
88 if (!CanRead(len)) | |
89 return false; | |
90 | |
91 memcpy(reinterpret_cast<void*>(buffer), | |
92 reinterpret_cast<const void*>(GetBufferAtCursor()), len); | |
93 | |
94 AdvanceCursor(len); | |
95 return true; | |
96 } | |
97 | |
98 bool NtlmBufferReader::ReadSecurityBuffer(ntlm::SecurityBuffer* sec_buf) { | |
99 if (!CanRead(ntlm::SECURITY_BUFFER_LEN)) | |
100 return false; | |
101 | |
102 bool result = ReadUInt16(&sec_buf->length) && SkipBytes(sizeof(uint16_t)) && | |
103 ReadUInt32(&sec_buf->offset); | |
104 | |
105 DCHECK(result); | |
106 return result; | |
107 } | |
108 | |
109 bool NtlmBufferReader::ReadUtf8String(std::string* value, size_t num_bytes) { | |
110 if (!CanRead(num_bytes)) | |
111 return false; | |
112 | |
113 value->assign(reinterpret_cast<const char*>(GetBufferAtCursor()), num_bytes); | |
114 AdvanceCursor(num_bytes); | |
115 return true; | |
116 } | |
117 | |
118 bool NtlmBufferReader::ReadUtf16String(base::string16* value, | |
119 size_t num_bytes) { | |
120 if (!CanRead(num_bytes) || (num_bytes % 2 != 0)) | |
121 return false; | |
122 | |
123 value->assign(reinterpret_cast<const base::char16*>(GetBufferAtCursor()), | |
124 num_bytes / 2); | |
125 #if IS_BIG_ENDIAN | |
126 // The NTLM buffer is always little-endian. So when it was assigned to the | |
127 // string above all the chars will be in little-endian order. | |
128 // Now swap them all so that the resulting string |value| is big-endian. | |
129 uint8_t* ptr = reinterpret_cast<uint8_t*>(value->c_str()); | |
130 for (int i = 0; i < num_bytes; i += 2) { | |
131 std::swap(ptr[i], ptr[i + 1]); | |
132 } | |
133 #endif | |
134 AdvanceCursor(num_bytes); | |
135 return true; | |
136 } | |
137 | |
138 bool NtlmBufferReader::ReadUtf16Payload(base::string16* value) { | |
139 size_t old_cursor = GetCursor(); | |
140 | |
141 // First read the security buffer. | |
142 ntlm::SecurityBuffer sec_buf; | |
143 if (!ReadSecurityBuffer(&sec_buf)) | |
144 return false; | |
145 | |
146 if (!CanReadFrom(sec_buf)) { | |
147 SetCursor(old_cursor); | |
148 return false; | |
149 } | |
150 | |
151 old_cursor = GetCursor(); | |
152 SetCursor(sec_buf.offset); | |
153 bool result = ReadUtf16String(value, sec_buf.length); | |
154 DCHECK(result); | |
155 SetCursor(old_cursor); | |
156 | |
157 return result; | |
158 } | |
159 | |
160 bool NtlmBufferReader::ReadBytesPayload(uint8_t* buffer, size_t buffer_len) { | |
161 size_t old_cursor = GetCursor(); | |
162 | |
163 // First read the security buffer. | |
164 ntlm::SecurityBuffer sec_buf; | |
165 if (!ReadSecurityBuffer(&sec_buf)) | |
166 return false; | |
167 | |
168 if (!CanReadFrom(sec_buf) || sec_buf.length > buffer_len) { | |
169 SetCursor(old_cursor); | |
170 return false; | |
171 } | |
172 | |
173 old_cursor = GetCursor(); | |
174 SetCursor(sec_buf.offset); | |
175 bool result = ReadBytes(buffer, sec_buf.length); | |
asanka
2017/06/16 03:21:28
Seems unnecessary to invoke ReadBytes() since we a
zentaro
2017/06/21 00:38:47
Done. Was just trying to keep it consistent with t
| |
176 DCHECK(result); | |
177 SetCursor(old_cursor); | |
178 | |
179 return result; | |
180 } | |
181 | |
182 bool NtlmBufferReader::ReadUtf8Payload(std::string* value) { | |
183 size_t old_cursor = GetCursor(); | |
184 | |
185 // First read the security buffer. | |
186 ntlm::SecurityBuffer sec_buf; | |
187 if (!ReadSecurityBuffer(&sec_buf)) | |
188 return false; | |
189 | |
190 if (!CanReadFrom(sec_buf)) { | |
191 SetCursor(old_cursor); | |
192 return false; | |
193 } | |
194 | |
195 old_cursor = GetCursor(); | |
196 SetCursor(sec_buf.offset); | |
197 bool result = ReadUtf8String(value, sec_buf.length); | |
198 DCHECK(result); | |
199 SetCursor(old_cursor); | |
200 | |
201 return result; | |
202 } | |
203 | |
204 bool NtlmBufferReader::ReadMessageType(ntlm::MessageType* message_type) { | |
205 size_t old_cursor = GetCursor(); | |
206 | |
207 uint32_t raw_message_type; | |
208 if (!ReadUInt32(&raw_message_type)) | |
209 return false; | |
210 | |
211 *message_type = static_cast<ntlm::MessageType>(raw_message_type); | |
212 | |
213 if (*message_type != ntlm::MessageType::NEGOTIATE && | |
214 *message_type != ntlm::MessageType::CHALLENGE && | |
215 *message_type != ntlm::MessageType::AUTHENTICATE) { | |
216 SetCursor(old_cursor); | |
217 return false; | |
218 } | |
219 | |
220 return true; | |
221 } | |
222 | |
223 bool NtlmBufferReader::SkipSecurityBuffer() { | |
224 return SkipBytes(ntlm::SECURITY_BUFFER_LEN); | |
225 } | |
226 | |
227 bool NtlmBufferReader::SkipSecurityBufferWithValidation() { | |
228 size_t old_cursor = GetCursor(); | |
229 | |
230 ntlm::SecurityBuffer sec_buf; | |
231 if (!ReadSecurityBuffer(&sec_buf)) { | |
232 return false; | |
233 } | |
234 | |
235 // If the security buffer indicates to read outside | |
236 // the message buffer then fail. | |
237 if (!CanReadFrom(sec_buf)) { | |
238 SetCursor(old_cursor); | |
239 return false; | |
240 } | |
241 | |
242 return true; | |
243 } | |
244 | |
245 bool NtlmBufferReader::SkipBytes(size_t count) { | |
246 if (!CanRead(count)) | |
247 return false; | |
248 | |
249 AdvanceCursor(count); | |
250 return true; | |
251 } | |
252 | |
253 bool NtlmBufferReader::MatchSignature() { | |
254 if (!CanRead(ntlm::SIGNATURE_LEN)) | |
255 return false; | |
256 | |
257 if (memcmp(ntlm::SIGNATURE, GetBufferAtCursor(), ntlm::SIGNATURE_LEN) != 0) | |
258 return false; | |
259 | |
260 AdvanceCursor(ntlm::SIGNATURE_LEN); | |
261 return true; | |
262 } | |
263 | |
264 bool NtlmBufferReader::MatchMessageType(ntlm::MessageType message_type) { | |
265 size_t old_cursor = GetCursor(); | |
266 ntlm::MessageType actual_message_type; | |
267 if (!ReadMessageType(&actual_message_type)) | |
268 return false; | |
269 | |
270 if (actual_message_type != message_type) { | |
271 SetCursor(old_cursor); | |
asanka
2017/06/16 03:21:28
I'm guessing that in practice all of these failure
zentaro
2017/06/21 00:38:46
I was just trying to leave things in a predictable
| |
272 return false; | |
273 } | |
274 | |
275 return true; | |
276 } | |
277 | |
278 bool NtlmBufferReader::MatchMessageHeader(ntlm::MessageType message_type) { | |
279 size_t old_cursor = GetCursor(); | |
280 if (MatchSignature() && MatchMessageType(message_type)) | |
281 return true; | |
282 | |
283 SetCursor(old_cursor); | |
284 return false; | |
285 } | |
286 | |
287 bool NtlmBufferReader::MatchZeros(size_t count) { | |
288 if (!CanRead(count)) | |
289 return false; | |
290 | |
291 for (size_t i = 0; i < count; i++) { | |
292 if (GetBufferAtCursor()[i] != 0) | |
293 return false; | |
294 } | |
295 | |
296 AdvanceCursor(count); | |
297 return true; | |
298 } | |
299 | |
300 bool NtlmBufferReader::MatchEmptySecurityBuffer() { | |
301 return MatchZeros(ntlm::SECURITY_BUFFER_LEN); | |
302 } | |
303 | |
304 } // namespace net | |
OLD | NEW |