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