ntlm_buffer_writer.h 7.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195
  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_WRITER_H_
  5. #define NET_NTLM_NTLM_BUFFER_WRITER_H_
  6. #include <stddef.h>
  7. #include <stdint.h>
  8. #include <memory>
  9. #include <string>
  10. #include "base/containers/span.h"
  11. #include "base/strings/string_piece.h"
  12. #include "net/base/net_export.h"
  13. #include "net/ntlm/ntlm_constants.h"
  14. namespace net::ntlm {
  15. // Supports various bounds checked low level buffer operations required by an
  16. // NTLM implementation.
  17. //
  18. // The class supports sequential write to an internally managed buffer. All
  19. // writes perform bounds checking to ensure enough space is remaining in the
  20. // buffer.
  21. //
  22. // The internal buffer is allocated in the constructor with size |buffer_len|
  23. // and owned by the class.
  24. //
  25. // Write* methods write the buffer at the current cursor position and perform
  26. // any necessary type conversion and provide the data in out params. After a
  27. // successful write the cursor position is advanced past the written field.
  28. //
  29. // Failed writes leave the internal cursor at the same position as before the
  30. // call.
  31. //
  32. // Based on [MS-NLMP]: NT LAN Manager (NTLM) Authentication Protocol
  33. // Specification version 28.0 [1]. Additional NTLM reference [2].
  34. //
  35. // [1] https://msdn.microsoft.com/en-us/library/cc236621.aspx
  36. // [2] http://davenport.sourceforge.net/ntlm.html
  37. class NET_EXPORT_PRIVATE NtlmBufferWriter {
  38. public:
  39. explicit NtlmBufferWriter(size_t buffer_len);
  40. NtlmBufferWriter(const NtlmBufferWriter&) = delete;
  41. NtlmBufferWriter& operator=(const NtlmBufferWriter&) = delete;
  42. ~NtlmBufferWriter();
  43. size_t GetLength() const { return buffer_.size(); }
  44. size_t GetCursor() const { return cursor_; }
  45. bool IsEndOfBuffer() const { return cursor_ >= GetLength(); }
  46. base::span<const uint8_t> GetBuffer() const { return buffer_; }
  47. std::vector<uint8_t> Pass() const { return std::move(buffer_); }
  48. // Returns true if there are |len| more bytes between the current cursor
  49. // position and the end of the buffer.
  50. bool CanWrite(size_t len) const;
  51. // Writes a 16 bit unsigned value (little endian). If there are not 16
  52. // more bits available in the buffer, it returns false.
  53. [[nodiscard]] bool WriteUInt16(uint16_t value);
  54. // Writes a 32 bit unsigned value (little endian). If there are not 32
  55. // more bits available in the buffer, it returns false.
  56. [[nodiscard]] bool WriteUInt32(uint32_t value);
  57. // Writes a 64 bit unsigned value (little endian). If there are not 64
  58. // more bits available in the buffer, it returns false.
  59. [[nodiscard]] bool WriteUInt64(uint64_t value);
  60. // Writes flags as a 32 bit unsigned value (little endian).
  61. [[nodiscard]] bool WriteFlags(NegotiateFlags flags);
  62. // Writes the bytes from the |buffer|. If there are not enough
  63. // bytes in the buffer, it returns false.
  64. [[nodiscard]] bool WriteBytes(base::span<const uint8_t> buffer);
  65. // Writes |count| bytes of zeros to the buffer. If there are not |count|
  66. // more bytes in available in the buffer, it returns false.
  67. [[nodiscard]] bool WriteZeros(size_t count);
  68. // A security buffer is an 8 byte structure that defines the offset and
  69. // length of a payload (string, struct, or byte array) that appears after
  70. // the fixed part of the message.
  71. //
  72. // The structure in the NTLM message is (little endian fields):
  73. // uint16 - |length| Length of payload
  74. // uint16 - Allocation (ignored and always set to |length|)
  75. // uint32 - |offset| Offset from start of message
  76. [[nodiscard]] bool WriteSecurityBuffer(SecurityBuffer sec_buf);
  77. // Writes an AvPair header. See [MS-NLMP] Section 2.2.2.1.
  78. //
  79. // The header has the following structure:
  80. // uint16 - |avid| The identifier of the following payload.
  81. // uint16 - |avlen| The length of the following payload.
  82. [[nodiscard]] bool WriteAvPairHeader(TargetInfoAvId avid, uint16_t avlen);
  83. // Writes an AvPair header for an |AvPair|. See [MS-NLMP] Section 2.2.2.1.
  84. [[nodiscard]] bool WriteAvPairHeader(const AvPair& pair) {
  85. return WriteAvPairHeader(pair.avid, pair.avlen);
  86. }
  87. // Writes a special AvPair header with both fields equal to 0. This zero
  88. // length AvPair signals the end of the AvPair list.
  89. [[nodiscard]] bool WriteAvPairTerminator();
  90. // Writes an |AvPair| header and its payload to the buffer. If the |avid|
  91. // is of type |TargetInfoAvId::kFlags| the |flags| field of |pair| will be
  92. // used as the payload and the |buffer| field is ignored. In all other cases
  93. // |buffer| is used as the payload. See also
  94. // |NtlmBufferReader::ReadTargetInfo|.
  95. [[nodiscard]] bool WriteAvPair(const AvPair& pair);
  96. // Writes a string of 8 bit characters to the buffer.
  97. //
  98. // When Unicode was not negotiated only the hostname string will go through
  99. // this code path. The 8 bit bytes of the hostname are written to the buffer.
  100. // The encoding is not relevant.
  101. [[nodiscard]] bool WriteUtf8String(const std::string& str);
  102. // Converts the 16 bit characters to UTF8 and writes the resulting 8 bit
  103. // characters.
  104. //
  105. // If Unicode was not negotiated, the username and domain get converted to
  106. // UTF8 in the message. Since they are just treated as additional bytes
  107. // input to hash the encoding doesn't matter. In practice, only a very old or
  108. // non-Windows server might trigger this code path since we always attempt
  109. // to negotiate Unicode and servers are supposed to honor that request.
  110. [[nodiscard]] bool WriteUtf16AsUtf8String(const std::u16string& str);
  111. // Treats |str| as UTF8, converts to UTF-16 and writes it with little-endian
  112. // byte order to the buffer.
  113. //
  114. // Two specific strings go through this code path.
  115. //
  116. // One case is the hostname. When the the Unicode flag has been set during
  117. // negotiation, the hostname needs to appear in the message with 16-bit
  118. // characters.
  119. //
  120. // The other case is the Service Principal Name (SPN). With Extended
  121. // Protection for Authentication (EPA) enabled, it appears in the target info
  122. // inside an AV Pair, where strings always have 16-bit characters.
  123. [[nodiscard]] bool WriteUtf8AsUtf16String(const std::string& str);
  124. // Writes UTF-16 LE characters to the buffer. For these strings, such as
  125. // username and the domain the actual encoding isn't important; they are just
  126. // treated as additional bytes of input to the hash.
  127. [[nodiscard]] bool WriteUtf16String(const std::u16string& str);
  128. // Writes the 8 byte NTLM signature "NTLMSSP\0" into the buffer.
  129. [[nodiscard]] bool WriteSignature();
  130. // There are 3 message types Negotiate (sent by client), Challenge (sent by
  131. // server), and Authenticate (sent by client).
  132. //
  133. // This writes |message_type| as a uint32_t into the buffer.
  134. [[nodiscard]] bool WriteMessageType(MessageType message_type);
  135. // Performs |WriteSignature| then |WriteMessageType|.
  136. [[nodiscard]] bool WriteMessageHeader(MessageType message_type);
  137. private:
  138. // Writes |sizeof(T)| bytes little-endian of an integer type to the buffer.
  139. template <typename T>
  140. bool WriteUInt(T value);
  141. // Sets the cursor position. The caller should use |GetLength| or
  142. // |CanWrite| to verify the bounds before calling this method.
  143. void SetCursor(size_t cursor);
  144. // Advances the cursor by |count|. The caller should use |GetLength| or
  145. // |CanWrite| to verify the bounds before calling this method.
  146. void AdvanceCursor(size_t count) { SetCursor(GetCursor() + count); }
  147. // Returns a pointer to the start of the buffer.
  148. const uint8_t* GetBufferPtr() const { return buffer_.data(); }
  149. uint8_t* GetBufferPtr() { return buffer_.data(); }
  150. // Returns pointer into the buffer at the current cursor location.
  151. const uint8_t* GetBufferPtrAtCursor() const {
  152. return GetBufferPtr() + GetCursor();
  153. }
  154. uint8_t* GetBufferPtrAtCursor() { return GetBufferPtr() + GetCursor(); }
  155. std::vector<uint8_t> buffer_;
  156. size_t cursor_ = 0;
  157. };
  158. } // namespace net::ntlm
  159. #endif // NET_NTLM_NTLM_BUFFER_WRITER_H_