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