• 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 #ifndef NET_NTLM_NTLM_BUFFER_READER_H_
11 #define NET_NTLM_NTLM_BUFFER_READER_H_
12 
13 #include <stddef.h>
14 #include <stdint.h>
15 
16 #include <vector>
17 
18 #include "base/check.h"
19 #include "base/containers/span.h"
20 #include "base/memory/raw_span.h"
21 #include "net/base/net_export.h"
22 #include "net/ntlm/ntlm_constants.h"
23 
24 namespace net::ntlm {
25 
26 // Supports various bounds-checked low level buffer operations required by an
27 // NTLM implementation.
28 //
29 // The class supports the sequential read of a provided buffer. All reads
30 // perform bounds checking to ensure enough space is remaining in the buffer.
31 //
32 // Read* methods read from the buffer at the current cursor position and
33 // perform any necessary type conversion and provide the data in out params.
34 // After a successful read the cursor position is advanced past the read
35 // field.
36 //
37 // Failed Read*s or Match*s leave the cursor in an undefined position and the
38 // buffer MUST be discarded with no further operations performed.
39 //
40 // Read*Payload methods first reads a security buffer (see
41 // |ReadSecurityBuffer|), then reads the requested payload from the offset
42 // and length stated in the security buffer.
43 //
44 // If the length and offset in the security buffer would cause a read outside
45 // the message buffer the payload will not be read and the function will
46 // return false.
47 //
48 // Based on [MS-NLMP]: NT LAN Manager (NTLM) Authentication Protocol
49 // Specification version 28.0 [1]. Additional NTLM reference [2].
50 //
51 // [1] https://msdn.microsoft.com/en-us/library/cc236621.aspx
52 // [2] http://davenport.sourceforge.net/ntlm.html
53 class NET_EXPORT_PRIVATE NtlmBufferReader {
54  public:
55   NtlmBufferReader();
56   // |buffer| is not copied and must outlive the |NtlmBufferReader|.
57   explicit NtlmBufferReader(base::span<const uint8_t> buffer);
58 
59   ~NtlmBufferReader();
60 
GetLength()61   size_t GetLength() const { return buffer_.size(); }
GetCursor()62   size_t GetCursor() const { return cursor_; }
IsEndOfBuffer()63   bool IsEndOfBuffer() const { return cursor_ >= GetLength(); }
64 
65   // Returns true if there are |len| more bytes between the current cursor
66   // position and the end of the buffer.
67   bool CanRead(size_t len) const;
68 
69   // Returns true if there are |len| more bytes between |offset| and the end
70   // of the buffer. The cursor position is not used or modified.
71   bool CanReadFrom(size_t offset, size_t len) const;
72 
73   // Returns true if it would be possible to read the payload described by the
74   // security buffer.
CanReadFrom(SecurityBuffer sec_buf)75   bool CanReadFrom(SecurityBuffer sec_buf) const {
76     return CanReadFrom(sec_buf.offset, sec_buf.length);
77   }
78 
79   // Reads a 16 bit value (little endian) as a uint16_t. If there are not 16
80   // more bits available, it returns false.
81   [[nodiscard]] bool ReadUInt16(uint16_t* value);
82 
83   // Reads a 32 bit value (little endian) as a uint32_t. If there are not 32
84   // more bits available, it returns false.
85   [[nodiscard]] bool ReadUInt32(uint32_t* value);
86 
87   // Reads a 64 bit value (little endian) as a uint64_t. If there are not 64
88   // more bits available, it returns false.
89   [[nodiscard]] bool ReadUInt64(uint64_t* value);
90 
91   // Calls |ReadUInt32| and returns it cast as |NegotiateFlags|. No
92   // validation of the value takes place.
93   [[nodiscard]] bool ReadFlags(NegotiateFlags* flags);
94 
95   // Reads |len| bytes and copies them into |buffer|.
96   [[nodiscard]] bool ReadBytes(base::span<uint8_t> buffer);
97 
98   // Reads |sec_buf.length| bytes from offset |sec_buf.offset| and copies them
99   // into |buffer|. If the security buffer specifies a payload outside the
100   // buffer, then the call fails. Unlike the other Read* methods, this does
101   // not move the cursor.
102   [[nodiscard]] bool ReadBytesFrom(const SecurityBuffer& sec_buf,
103                                    base::span<uint8_t> buffer);
104 
105   // Reads |sec_buf.length| bytes from offset |sec_buf.offset| and assigns
106   // |reader| an |NtlmBufferReader| representing the payload. If the security
107   //  buffer specifies a payload outside the buffer, then the call fails, and
108   // the state of |reader| is undefined. Unlike the other Read* methods, this
109   // does not move the cursor.
110   [[nodiscard]] bool ReadPayloadAsBufferReader(const SecurityBuffer& sec_buf,
111                                                NtlmBufferReader* reader);
112 
113   // A security buffer is an 8 byte structure that defines the offset and
114   // length of a payload (string, struct or byte array) that appears after the
115   // fixed part of the message.
116   //
117   // The structure is (little endian fields):
118   //     uint16 - |length| Length of payload
119   //     uint16 - Allocation (this is always ignored and not returned)
120   //     uint32 - |offset| Offset from start of message
121   [[nodiscard]] bool ReadSecurityBuffer(SecurityBuffer* sec_buf);
122 
123   // Reads an AvPair header. AvPairs appear sequentially, terminated by a
124   // special EOL AvPair, in the target info payload of the Challenge message.
125   // See [MS-NLMP] Section 2.2.2.1.
126   //
127   // An AvPair contains an inline payload, and has the structure below (
128   // little endian fields):
129   //    uint16      - AvID: Identifies the type of the payload.
130   //    uint16      - AvLen: The length of the following payload.
131   //    (variable)  - Payload: Variable length payload. The content and
132   //                  format are determined by the AvId.
133   [[nodiscard]] bool ReadAvPairHeader(TargetInfoAvId* avid, uint16_t* avlen);
134 
135   // There are 3 message types Negotiate (sent by client), Challenge (sent by
136   // server), and Authenticate (sent by client).
137   //
138   // This reads the message type from the header and will return false if the
139   // value is invalid.
140   [[nodiscard]] bool ReadMessageType(MessageType* message_type);
141 
142   // Reads |target_info_len| bytes and parses them as a sequence of Av Pairs.
143   // |av_pairs| should be empty on entry to this function. If |ReadTargetInfo|
144   // returns false, the content of |av_pairs| is in an undefined state and
145   // should be discarded.
146   [[nodiscard]] bool ReadTargetInfo(size_t target_info_len,
147                                     std::vector<AvPair>* av_pairs);
148 
149   // Reads a security buffer, then parses the security buffer payload as a
150   // target info. The target info is returned as a sequence of AvPairs, with
151   // the terminating AvPair omitted. A zero length payload is valid and will
152   // result in an empty list in |av_pairs|. Any non-zero length payload must
153   // have a terminating AvPair.
154   // |av_pairs| should be empty on entry to this function. If |ReadTargetInfo|
155   // returns false, the content of |av_pairs| is in an undefined state and
156   // should be discarded.
157   [[nodiscard]] bool ReadTargetInfoPayload(std::vector<AvPair>* av_pairs);
158 
159   // Skips over a security buffer field without reading the fields. This is
160   // the equivalent of advancing the cursor 8 bytes. Returns false if there
161   // are less than 8 bytes left in the buffer.
162   [[nodiscard]] bool SkipSecurityBuffer();
163 
164   // Skips over the security buffer without returning the values, but fails if
165   // the values would cause a read outside the buffer if the payload was
166   // actually read.
167   [[nodiscard]] bool SkipSecurityBufferWithValidation();
168 
169   // Skips over |count| bytes in the buffer. Returns false if there are not
170   // |count| bytes left in the buffer.
171   [[nodiscard]] bool SkipBytes(size_t count);
172 
173   // Reads and returns true if the next 8 bytes matches the signature in an
174   // NTLM message "NTLMSSP\0". The cursor advances if the the signature
175   // is matched.
176   [[nodiscard]] bool MatchSignature();
177 
178   // Performs |ReadMessageType| and returns true if the value is
179   // |message_type|. If the read fails or the message type does not match,
180   // the buffer is invalid and MUST be discarded.
181   [[nodiscard]] bool MatchMessageType(MessageType message_type);
182 
183   // Performs |MatchSignature| then |MatchMessageType|.
184   [[nodiscard]] bool MatchMessageHeader(MessageType message_type);
185 
186   // Performs |ReadBytes(count)| and returns true if the contents is all
187   // zero.
188   [[nodiscard]] bool MatchZeros(size_t count);
189 
190   // Reads the security buffer and returns true if the length is 0 and
191   // the offset is within the message. On failure, the buffer is invalid
192   // and MUST be discarded.
193   [[nodiscard]] bool MatchEmptySecurityBuffer();
194 
195  private:
196   // Reads |sizeof(T)| bytes of an integer type from a little-endian buffer.
197   template <typename T>
198   bool ReadUInt(T* value);
199 
200   // Sets the cursor position. The caller should use |GetLength|, |CanRead|,
201   // or |CanReadFrom| to verify the bounds before calling this method.
202   void SetCursor(size_t cursor);
203 
204   // Advances the cursor by |count| bytes. The caller should use |GetLength|,
205   // |CanRead|, or |CanReadFrom| to verify the bounds before calling this
206   // method.
AdvanceCursor(size_t count)207   void AdvanceCursor(size_t count) { SetCursor(GetCursor() + count); }
208 
209   // Returns a constant pointer to the start of the buffer.
GetBufferPtr()210   const uint8_t* GetBufferPtr() const { return buffer_.data(); }
211 
212   // Returns a pointer to the underlying buffer at the current cursor
213   // position.
GetBufferAtCursor()214   const uint8_t* GetBufferAtCursor() const { return GetBufferPtr() + cursor_; }
215 
216   // Returns the byte at the current cursor position.
GetByteAtCursor()217   uint8_t GetByteAtCursor() const {
218     DCHECK(!IsEndOfBuffer());
219     return *(GetBufferAtCursor());
220   }
221 
222   base::raw_span<const uint8_t> buffer_;
223   size_t cursor_ = 0;
224 };
225 
226 }  // namespace net::ntlm
227 
228 #endif  // NET_NTLM_NTLM_BUFFER_READER_H_
229