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

Side by Side Diff: net/http/ntlm_buffer_reader.cc

Issue 2879353002: Add a buffer reader/writer for NTLM. (Closed)
Patch Set: Rebase Created 3 years, 6 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/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
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698