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