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