• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2017 The Chromium Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #ifdef UNSAFE_BUFFERS_BUILD
6 // TODO(crbug.com/40284755): Remove this and spanify to fix the errors.
7 #pragma allow_unsafe_buffers
8 #endif
9 
10 #include "net/ntlm/ntlm_buffer_reader.h"
11 
12 #include <string.h>
13 
14 #include "base/check_op.h"
15 
16 namespace net::ntlm {
17 
18 NtlmBufferReader::NtlmBufferReader() = default;
19 
NtlmBufferReader(base::span<const uint8_t> buffer)20 NtlmBufferReader::NtlmBufferReader(base::span<const uint8_t> buffer)
21     : buffer_(buffer) {}
22 
23 NtlmBufferReader::~NtlmBufferReader() = default;
24 
CanRead(size_t len) const25 bool NtlmBufferReader::CanRead(size_t len) const {
26   return CanReadFrom(GetCursor(), len);
27 }
28 
CanReadFrom(size_t offset,size_t len) const29 bool NtlmBufferReader::CanReadFrom(size_t offset, size_t len) const {
30   if (len == 0)
31     return true;
32 
33   return (len <= GetLength() && offset <= GetLength() - len);
34 }
35 
ReadUInt16(uint16_t * value)36 bool NtlmBufferReader::ReadUInt16(uint16_t* value) {
37   return ReadUInt<uint16_t>(value);
38 }
39 
ReadUInt32(uint32_t * value)40 bool NtlmBufferReader::ReadUInt32(uint32_t* value) {
41   return ReadUInt<uint32_t>(value);
42 }
43 
ReadUInt64(uint64_t * value)44 bool NtlmBufferReader::ReadUInt64(uint64_t* value) {
45   return ReadUInt<uint64_t>(value);
46 }
47 
ReadFlags(NegotiateFlags * flags)48 bool NtlmBufferReader::ReadFlags(NegotiateFlags* flags) {
49   uint32_t raw;
50   if (!ReadUInt32(&raw))
51     return false;
52 
53   *flags = static_cast<NegotiateFlags>(raw);
54   return true;
55 }
56 
ReadBytes(base::span<uint8_t> buffer)57 bool NtlmBufferReader::ReadBytes(base::span<uint8_t> buffer) {
58   if (!CanRead(buffer.size()))
59     return false;
60 
61   if (buffer.empty())
62     return true;
63 
64   memcpy(buffer.data(), GetBufferAtCursor(), buffer.size());
65 
66   AdvanceCursor(buffer.size());
67   return true;
68 }
69 
ReadBytesFrom(const SecurityBuffer & sec_buf,base::span<uint8_t> buffer)70 bool NtlmBufferReader::ReadBytesFrom(const SecurityBuffer& sec_buf,
71                                      base::span<uint8_t> buffer) {
72   if (!CanReadFrom(sec_buf) || buffer.size() < sec_buf.length)
73     return false;
74 
75   if (buffer.empty())
76     return true;
77 
78   memcpy(buffer.data(), GetBufferPtr() + sec_buf.offset, sec_buf.length);
79 
80   return true;
81 }
82 
ReadPayloadAsBufferReader(const SecurityBuffer & sec_buf,NtlmBufferReader * reader)83 bool NtlmBufferReader::ReadPayloadAsBufferReader(const SecurityBuffer& sec_buf,
84                                                  NtlmBufferReader* reader) {
85   if (!CanReadFrom(sec_buf))
86     return false;
87 
88   *reader = NtlmBufferReader(
89       base::span(GetBufferPtr() + sec_buf.offset, sec_buf.length));
90   return true;
91 }
92 
ReadSecurityBuffer(SecurityBuffer * sec_buf)93 bool NtlmBufferReader::ReadSecurityBuffer(SecurityBuffer* sec_buf) {
94   return ReadUInt16(&sec_buf->length) && SkipBytes(sizeof(uint16_t)) &&
95          ReadUInt32(&sec_buf->offset);
96 }
97 
ReadAvPairHeader(TargetInfoAvId * avid,uint16_t * avlen)98 bool NtlmBufferReader::ReadAvPairHeader(TargetInfoAvId* avid, uint16_t* avlen) {
99   if (!CanRead(kAvPairHeaderLen))
100     return false;
101 
102   uint16_t raw_avid;
103   bool result = ReadUInt16(&raw_avid) && ReadUInt16(avlen);
104   DCHECK(result);
105 
106   // Don't try and validate the avid because the code only cares about a few
107   // specific ones and it is likely a future version might extend this field.
108   // The implementation can ignore and skip over AV Pairs it doesn't
109   // understand.
110   *avid = static_cast<TargetInfoAvId>(raw_avid);
111 
112   return true;
113 }
114 
ReadTargetInfo(size_t target_info_len,std::vector<AvPair> * av_pairs)115 bool NtlmBufferReader::ReadTargetInfo(size_t target_info_len,
116                                       std::vector<AvPair>* av_pairs) {
117   DCHECK(av_pairs->empty());
118 
119   // A completely empty target info is allowed.
120   if (target_info_len == 0)
121     return true;
122 
123   // If there is any content there has to be at least one terminating header.
124   if (!CanRead(target_info_len) || target_info_len < kAvPairHeaderLen) {
125     return false;
126   }
127 
128   size_t target_info_end = GetCursor() + target_info_len;
129   bool saw_eol = false;
130 
131   while ((GetCursor() < target_info_end)) {
132     AvPair pair;
133     if (!ReadAvPairHeader(&pair.avid, &pair.avlen))
134       break;
135 
136     // Make sure the length wouldn't read outside the buffer.
137     if (!CanRead(pair.avlen))
138       return false;
139 
140     // Take a copy of the payload in the AVPair.
141     pair.buffer.assign(GetBufferAtCursor(), GetBufferAtCursor() + pair.avlen);
142     if (pair.avid == TargetInfoAvId::kEol) {
143       // Terminator must have zero length.
144       if (pair.avlen != 0)
145         return false;
146 
147       // Break out of the loop once a valid terminator is found. After the
148       // loop it will be validated that the whole target info was consumed.
149       saw_eol = true;
150       break;
151     }
152 
153     switch (pair.avid) {
154       case TargetInfoAvId::kFlags:
155         // For flags also populate the flags field so it doesn't
156         // have to be modified through the raw buffer later.
157         if (pair.avlen != sizeof(uint32_t) ||
158             !ReadUInt32(reinterpret_cast<uint32_t*>(&pair.flags)))
159           return false;
160         break;
161       case TargetInfoAvId::kTimestamp:
162         // Populate timestamp so it doesn't need to be read through the
163         // raw buffer later.
164         if (pair.avlen != sizeof(uint64_t) || !ReadUInt64(&pair.timestamp))
165           return false;
166         break;
167       case TargetInfoAvId::kChannelBindings:
168       case TargetInfoAvId::kTargetName:
169         // The server should never send these, and with EPA enabled the client
170         // will add these to the authenticate message. To avoid issues with
171         // duplicates or only one being read, just don't allow them.
172         return false;
173       default:
174         // For all other types, just jump over the payload to the next pair.
175         // If there aren't enough bytes left, then fail.
176         if (!SkipBytes(pair.avlen))
177           return false;
178         break;
179     }
180 
181     av_pairs->push_back(std::move(pair));
182   }
183 
184   // Fail if the buffer wasn't properly formed. The entire payload should have
185   // been consumed and a terminator found.
186   if ((GetCursor() != target_info_end) || !saw_eol)
187     return false;
188 
189   return true;
190 }
191 
ReadTargetInfoPayload(std::vector<AvPair> * av_pairs)192 bool NtlmBufferReader::ReadTargetInfoPayload(std::vector<AvPair>* av_pairs) {
193   DCHECK(av_pairs->empty());
194 
195   SecurityBuffer sec_buf;
196 
197   // First read the security buffer.
198   if (!ReadSecurityBuffer(&sec_buf))
199     return false;
200 
201   NtlmBufferReader payload_reader;
202   if (!ReadPayloadAsBufferReader(sec_buf, &payload_reader))
203     return false;
204 
205   if (!payload_reader.ReadTargetInfo(sec_buf.length, av_pairs))
206     return false;
207 
208   // |ReadTargetInfo| should have consumed the entire contents.
209   return payload_reader.IsEndOfBuffer();
210 }
211 
ReadMessageType(MessageType * message_type)212 bool NtlmBufferReader::ReadMessageType(MessageType* message_type) {
213   uint32_t raw_message_type;
214   if (!ReadUInt32(&raw_message_type))
215     return false;
216 
217   *message_type = static_cast<MessageType>(raw_message_type);
218 
219   if (*message_type != MessageType::kNegotiate &&
220       *message_type != MessageType::kChallenge &&
221       *message_type != MessageType::kAuthenticate)
222     return false;
223 
224   return true;
225 }
226 
SkipSecurityBuffer()227 bool NtlmBufferReader::SkipSecurityBuffer() {
228   return SkipBytes(kSecurityBufferLen);
229 }
230 
SkipSecurityBufferWithValidation()231 bool NtlmBufferReader::SkipSecurityBufferWithValidation() {
232   SecurityBuffer sec_buf;
233   return ReadSecurityBuffer(&sec_buf) && CanReadFrom(sec_buf);
234 }
235 
SkipBytes(size_t count)236 bool NtlmBufferReader::SkipBytes(size_t count) {
237   if (!CanRead(count))
238     return false;
239 
240   AdvanceCursor(count);
241   return true;
242 }
243 
MatchSignature()244 bool NtlmBufferReader::MatchSignature() {
245   if (!CanRead(kSignatureLen))
246     return false;
247 
248   if (memcmp(kSignature, GetBufferAtCursor(), kSignatureLen) != 0)
249     return false;
250 
251   AdvanceCursor(kSignatureLen);
252   return true;
253 }
254 
MatchMessageType(MessageType message_type)255 bool NtlmBufferReader::MatchMessageType(MessageType message_type) {
256   MessageType actual_message_type;
257   return ReadMessageType(&actual_message_type) &&
258          (actual_message_type == message_type);
259 }
260 
MatchMessageHeader(MessageType message_type)261 bool NtlmBufferReader::MatchMessageHeader(MessageType message_type) {
262   return MatchSignature() && MatchMessageType(message_type);
263 }
264 
MatchZeros(size_t count)265 bool NtlmBufferReader::MatchZeros(size_t count) {
266   if (!CanRead(count))
267     return false;
268 
269   for (size_t i = 0; i < count; i++) {
270     if (GetBufferAtCursor()[i] != 0)
271       return false;
272   }
273 
274   AdvanceCursor(count);
275   return true;
276 }
277 
MatchEmptySecurityBuffer()278 bool NtlmBufferReader::MatchEmptySecurityBuffer() {
279   SecurityBuffer sec_buf;
280   return ReadSecurityBuffer(&sec_buf) && (sec_buf.offset <= GetLength()) &&
281          (sec_buf.length == 0);
282 }
283 
284 template <typename T>
ReadUInt(T * value)285 bool NtlmBufferReader::ReadUInt(T* value) {
286   size_t int_size = sizeof(T);
287   if (!CanRead(int_size))
288     return false;
289 
290   *value = 0;
291   for (size_t i = 0; i < int_size; i++) {
292     *value += static_cast<T>(GetByteAtCursor()) << (i * 8);
293     AdvanceCursor(1);
294   }
295 
296   return true;
297 }
298 
SetCursor(size_t cursor)299 void NtlmBufferReader::SetCursor(size_t cursor) {
300   DCHECK_LE(cursor, GetLength());
301 
302   cursor_ = cursor;
303 }
304 
305 }  // namespace net::ntlm
306