ntlm_buffer_reader.h 9.2 KB

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