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

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

Issue 2879353002: Add a buffer reader/writer for NTLM. (Closed)
Patch Set: Add a buffer reader/writer for NTLM. 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 (c) 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 {
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() != nullptr);
Ryan Sleevi 2017/06/08 18:36:33 DCHECK(buffer.data()) ?
zentaro 2017/06/12 23:12:05 Done.
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(cursor_, len);
36 }
37
38 bool NtlmBufferReader::CanReadFrom(size_t offset, size_t len) const {
39 if (len == 0)
40 return true;
41
42 return (offset + len > offset) && (offset + len <= GetLength());
Ryan Sleevi 2017/06/08 18:36:33 This usually triggers a pattern matching warning (
zentaro 2017/06/12 23:12:05 Done.
43 }
44
45 bool NtlmBufferReader::SetCursor(size_t cursor) {
46 if (cursor > GetLength())
47 return false;
48
49 cursor_ = cursor;
50 return true;
51 }
52
53 bool NtlmBufferReader::ReadUInt16(uint16_t* value) {
54 return ReadUInt<uint16_t>(value);
55 }
56
57 bool NtlmBufferReader::ReadUInt32(uint32_t* value) {
58 return ReadUInt<uint32_t>(value);
59 }
60
61 bool NtlmBufferReader::ReadUInt64(uint64_t* value) {
62 return ReadUInt<uint64_t>(value);
63 }
64
65 template <typename T>
66 bool NtlmBufferReader::ReadUInt(T* value) {
67 size_t int_size = sizeof(T);
68 if (!CanRead(int_size))
69 return false;
70
71 *value = 0;
72 for (size_t i = 0; i < int_size; i++) {
73 *value += static_cast<T>(GetByteAtCursor()) << (i * 8);
74 cursor_++;
75 }
76
77 return true;
78 }
79
80 bool NtlmBufferReader::ReadBytes(uint8_t* buffer, size_t len) {
81 if (!CanRead(len))
82 return false;
83
84 memcpy(reinterpret_cast<void*>(buffer),
85 reinterpret_cast<const void*>(GetBufferAtCursor()), len);
86
87 cursor_ += len;
88 return true;
89 }
90
91 bool NtlmBufferReader::ReadSecurityBuffer(ntlm::SecurityBuffer* sec_buf) {
92 if (!CanRead(ntlm::SECURITY_BUFFER_LEN))
93 return false;
94
95 if (ReadUInt16(&sec_buf->length) && SkipBytes(sizeof(uint16_t)) &&
Ryan Sleevi 2017/06/08 18:36:33 heh, I'm torn on whether sizeof(uint16_t) is reall
asanka 2017/06/08 18:44:58 nit: if (X) return true; return false; ---> retur
zentaro 2017/06/12 23:12:05 Seemed more natural here because it makes it more
96 ReadUInt32(&sec_buf->offset))
97 return true;
98
99 NOTREACHED();
100 return false;
101 }
102
103 bool NtlmBufferReader::ReadAsciiString(std::string* value, size_t num_bytes) {
104 if (!CanRead(num_bytes))
105 return false;
106
107 value->assign(reinterpret_cast<const char*>(GetBufferAtCursor()), num_bytes);
108 cursor_ += num_bytes;
109 return true;
110 }
111
112 bool NtlmBufferReader::ReadUnicodeString(base::string16* value,
113 size_t num_bytes) {
114 if (!CanRead(num_bytes) || (num_bytes % 2 != 0))
115 return false;
116
117 value->assign(reinterpret_cast<const base::char16*>(GetBufferAtCursor()),
118 num_bytes / 2);
119 #if IS_BIG_ENDIAN
asanka 2017/06/08 18:44:58 Do we build and test on BIG_ENDIAN?
zentaro 2017/06/12 23:12:05 No idea! If the rest of chrome doesn't support it,
120 // The NTLM buffer is always little-endian. So when it was assigned to the
121 // string above all the chars will be in little-endian order.
122 // Now swap them all so that the resulting string |value| is big-endian.
123 uint8_t* ptr = reinterpret_cast<uint8_t*>(value->c_str());
124 for (int i = 0; i < num_bytes; i += 2) {
125 std::swap(ptr[i], ptr[i + 1]);
126 }
127 #endif
128 cursor_ += num_bytes;
129 return true;
130 }
131
132 bool NtlmBufferReader::ReadUnicodePayload(base::string16* value) {
133 // First read the security buffer.
134 ntlm::SecurityBuffer sec_buf;
135 if (!ReadSecurityBuffer(&sec_buf))
136 return false;
137
138 if (!CanReadFrom(sec_buf)) {
139 cursor_ -= ntlm::SECURITY_BUFFER_LEN;
asanka 2017/06/08 18:44:58 nit: store and restore the original cursor instead
zentaro 2017/06/12 23:12:05 Done.
140 return false;
141 }
142
143 size_t old_cursor = GetCursor();
144
145 bool result = SetCursor(sec_buf.offset) &&
146 ReadUnicodeString(value, sec_buf.length) &&
147 SetCursor(old_cursor);
148
149 DCHECK(result);
150 return result;
151 }
152
153 bool NtlmBufferReader::ReadBytesPayload(uint8_t* buffer, size_t buffer_len) {
154 // First read the security buffer.
155 ntlm::SecurityBuffer sec_buf;
156 if (!ReadSecurityBuffer(&sec_buf))
157 return false;
158
159 if (!CanReadFrom(sec_buf) || sec_buf.length > buffer_len) {
160 cursor_ -= ntlm::SECURITY_BUFFER_LEN;
161 return false;
162 }
163
164 size_t old_cursor = GetCursor();
165 bool result = SetCursor(sec_buf.offset) &&
166 ReadBytes(buffer, sec_buf.length) && SetCursor(old_cursor);
Ryan Sleevi 2017/06/08 18:36:33 Note: if ReadBytes() fails, SetCursor(old_cursor)
zentaro 2017/06/12 23:12:05 Set cursor should never fail. Because we already c
167 DCHECK(result);
168 return result;
169 }
170
171 bool NtlmBufferReader::ReadAsciiPayload(std::string* value) {
172 // First read the security buffer.
173 ntlm::SecurityBuffer sec_buf;
174 if (!ReadSecurityBuffer(&sec_buf))
175 return false;
176
177 if (!CanReadFrom(sec_buf)) {
178 cursor_ -= ntlm::SECURITY_BUFFER_LEN;
179 return false;
180 }
181
182 size_t old_cursor = GetCursor();
183 bool result = SetCursor(sec_buf.offset) &&
184 ReadAsciiString(value, sec_buf.length) && SetCursor(old_cursor);
185
186 DCHECK(result);
187 return result;
188 }
189
190 bool NtlmBufferReader::ReadMessageType(ntlm::MessageType* message_type) {
191 uint32_t temp;
asanka 2017/06/08 18:44:58 everything is temporary :-) . This is the raw mess
zentaro 2017/06/12 23:12:05 Done.
192 if (!ReadUInt32(&temp))
193 return false;
194
195 if (temp != ntlm::MESSAGE_NEGOTIATE && temp != ntlm::MESSAGE_CHALLENGE &&
196 temp != ntlm::MESSAGE_AUTHENTICATE) {
197 cursor_ -= sizeof(uint32_t);
198 return false;
199 }
200
201 *message_type = static_cast<ntlm::MessageType>(temp);
202 return true;
203 }
204
205 bool NtlmBufferReader::SkipSecurityBuffer() {
206 return SkipBytes(ntlm::SECURITY_BUFFER_LEN);
207 }
208
209 bool NtlmBufferReader::SkipSecurityBufferWithValidation() {
210 ntlm::SecurityBuffer sec_buf;
211 if (!ReadSecurityBuffer(&sec_buf)) {
212 return false;
213 }
214
215 // If the security buffer indicates to read outside
216 // the message buffer then fail.
217 if (!CanReadFrom(sec_buf)) {
218 cursor_ -= ntlm::SECURITY_BUFFER_LEN;
219 return false;
220 }
221
222 return true;
223 }
224
225 bool NtlmBufferReader::SkipBytes(size_t count) {
226 if (!CanRead(count))
227 return false;
228
229 cursor_ += count;
230 return true;
231 }
232
233 bool NtlmBufferReader::MatchSignature() {
234 if (!CanRead(ntlm::SIGNATURE_LEN))
235 return false;
236
237 if (memcmp(ntlm::SIGNATURE, GetBufferAtCursor(), ntlm::SIGNATURE_LEN) != 0)
238 return false;
239
240 cursor_ += ntlm::SIGNATURE_LEN;
241 return true;
242 }
243
244 bool NtlmBufferReader::MatchMessageType(ntlm::MessageType message_type) {
245 size_t old_cursor = cursor_;
246 ntlm::MessageType actual_message_type;
247 if (!ReadMessageType(&actual_message_type))
248 return false;
249
250 if (actual_message_type != message_type) {
251 cursor_ = old_cursor;
252 return false;
253 }
254
255 return true;
256 }
257
258 bool NtlmBufferReader::MatchMessageHeader(ntlm::MessageType message_type) {
259 size_t old_cursor = cursor_;
asanka 2017/06/08 18:44:58 Nit: let's be consistent about GetCursor()/SetCurs
zentaro 2017/06/12 23:12:05 Yep. SetCursor() it is. It was added in a refactor
260 if (MatchSignature() && MatchMessageType(message_type))
261 return true;
262
263 cursor_ = old_cursor;
264 return false;
265 }
266
267 bool NtlmBufferReader::MatchZeros(size_t count) {
268 if (!CanRead(count))
269 return false;
270
271 for (size_t i = 0; i < count; i++) {
272 if (GetBufferAtCursor()[i] != 0)
273 return false;
274 }
275
276 cursor_ += count;
277 return true;
278 }
279
280 bool NtlmBufferReader::MatchEmptySecurityBuffer() {
281 return MatchZeros(ntlm::SECURITY_BUFFER_LEN);
282 }
283
284 } // namespace net
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698