OLD | NEW |
(Empty) | |
| 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 |
| 5 #ifndef NET_BASE_NTLM_BUFFER_READER_H_ |
| 6 #define NET_BASE_NTLM_BUFFER_READER_H_ |
| 7 |
| 8 #include <stddef.h> |
| 9 #include <stdint.h> |
| 10 |
| 11 #include <string> |
| 12 |
| 13 #include "base/strings/string_piece.h" |
| 14 #include "net/base/net_export.h" |
| 15 #include "net/ntlm/ntlm.h" |
| 16 |
| 17 namespace net { |
| 18 namespace ntlm { |
| 19 |
| 20 // Supports various bounds-checked low level buffer operations required by an |
| 21 // NTLM implementation. |
| 22 // |
| 23 // The class supports sequential read of a provided buffer. All reads perform |
| 24 // 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 explicit NtlmBufferReader(base::StringPiece buffer); |
| 50 |
| 51 // This class does not take ownership of |ptr| so the caller must ensure |
| 52 // that the buffer outlives the |NtlmBufferReader|. |
| 53 NtlmBufferReader(const uint8_t* ptr, size_t len); |
| 54 ~NtlmBufferReader(); |
| 55 |
| 56 size_t GetLength() const { return buffer_.length(); } |
| 57 size_t GetCursor() const { return cursor_; } |
| 58 bool IsEndOfBuffer() const { return cursor_ >= GetLength(); } |
| 59 |
| 60 // Returns true if there are |len| more bytes between the current cursor |
| 61 // position and the end of the buffer. |
| 62 bool CanRead(size_t len) const; |
| 63 |
| 64 // Returns true if there are |len| more bytes between |offset| and the end |
| 65 // of the buffer. The cursor position is not used or modified. |
| 66 bool CanReadFrom(size_t offset, size_t len) const; |
| 67 |
| 68 // Returns true if it would be possible to read the payload described by the |
| 69 // security buffer. |
| 70 bool CanReadFrom(SecurityBuffer sec_buf) const { |
| 71 return CanReadFrom(sec_buf.offset, sec_buf.length); |
| 72 } |
| 73 |
| 74 // Reads a 16 bit value (little endian) as a uint16_t. If there are not 16 |
| 75 // more bits available it returns false. |
| 76 bool ReadUInt16(uint16_t* value) WARN_UNUSED_RESULT; |
| 77 |
| 78 // Reads a 32 bit value (little endian) as a uint32_t. If there are not 32 |
| 79 // more bits available it returns false. |
| 80 bool ReadUInt32(uint32_t* value) WARN_UNUSED_RESULT; |
| 81 |
| 82 // Reads a 64 bit value (little endian) as a uint64_t. If there are not 64 |
| 83 // more bits available it returns false. |
| 84 bool ReadUInt64(uint64_t* value) WARN_UNUSED_RESULT; |
| 85 |
| 86 // Calls |ReadUInt32| and returns it cast as |NegotiateFlags|. No |
| 87 // validation of the value takes place. |
| 88 bool ReadFlags(NegotiateFlags* flags) WARN_UNUSED_RESULT; |
| 89 |
| 90 // Reads |len| bytes and copies them into |buffer|. |
| 91 bool ReadBytes(uint8_t* buffer, size_t len) WARN_UNUSED_RESULT; |
| 92 |
| 93 // Reads |sec_buf.length| bytes from offset |sec_buf.offset| and copies them |
| 94 // into |buffer|. If the security buffer specifies a payload outside the |
| 95 // buffer then the call fails. |
| 96 bool ReadBytesFrom(const SecurityBuffer& sec_buf, |
| 97 uint8_t* buffer) WARN_UNUSED_RESULT; |
| 98 |
| 99 // A security buffer is an 8 byte structure that defines the offset and |
| 100 // length of a payload (string, struct or byte array) that appears after the |
| 101 // fixed part of the message. |
| 102 // |
| 103 // The structure is (little endian fields): |
| 104 // uint16 - |length| Length of payload |
| 105 // uint16 - Allocation (this is always ignored and not returned) |
| 106 // uint32 - |offset| Offset from start of message |
| 107 bool ReadSecurityBuffer(SecurityBuffer* sec_buf) WARN_UNUSED_RESULT; |
| 108 |
| 109 // There are 3 message types Negotiate (sent by client), Challenge (sent by |
| 110 // server), and Authenticate (sent by client). |
| 111 // |
| 112 // This reads the message type from the header and will return false if the |
| 113 // value is invalid. |
| 114 bool ReadMessageType(MessageType* message_type) WARN_UNUSED_RESULT; |
| 115 |
| 116 // Skips over a security buffer field without reading the fields. This is |
| 117 // the equivalent of advancing the cursor 8 bytes. Returns false if there |
| 118 // are less than 8 bytes left in the buffer. |
| 119 bool SkipSecurityBuffer() WARN_UNUSED_RESULT; |
| 120 |
| 121 // Skips over the security buffer without returning the values, but fails if |
| 122 // the values would cause a read outside the buffer if the payload was |
| 123 // actually read. |
| 124 bool SkipSecurityBufferWithValidation() WARN_UNUSED_RESULT; |
| 125 |
| 126 // Skips over |count| bytes in the buffer. Returns false if there is not |
| 127 // |count| bytes left in the buffer. |
| 128 bool SkipBytes(size_t count) WARN_UNUSED_RESULT; |
| 129 |
| 130 // Reads and returns true if the next 8 bytes matches the signature in an |
| 131 // NTLM message "NTLMSSP\0". The cursor advances if the the signature |
| 132 // is matched. |
| 133 bool MatchSignature() WARN_UNUSED_RESULT; |
| 134 |
| 135 // Performs |ReadMessageType| and returns true if the value is |
| 136 // |message_type|. If the read fails or the message type does not match, |
| 137 // the buffer is invalid and MUST be discarded. |
| 138 bool MatchMessageType(MessageType message_type) WARN_UNUSED_RESULT; |
| 139 |
| 140 // Performs |MatchSignature| then |MatchMessageType|. |
| 141 bool MatchMessageHeader(MessageType message_type) WARN_UNUSED_RESULT; |
| 142 |
| 143 // Performs |ReadBytes(count)| and returns true if the contents is all |
| 144 // zero. |
| 145 bool MatchZeros(size_t count) WARN_UNUSED_RESULT; |
| 146 |
| 147 // Reads the security buffer and returns true if the length is 0 and |
| 148 // the offset is within the message. On failure the buffer is invalid |
| 149 // and MUST be discarded. |
| 150 bool MatchEmptySecurityBuffer() WARN_UNUSED_RESULT; |
| 151 |
| 152 private: |
| 153 // Reads |sizeof(T)| bytes of an integer type from a little-endian buffer. |
| 154 template <typename T> |
| 155 bool ReadUInt(T* value); |
| 156 |
| 157 // Sets the cursor position. This is used when reading payloads to move the |
| 158 // cursor to the start of the payload indicated by the security buffer. |
| 159 // The caller should use |GetLength|, |CanRead|, or |CanReadFrom| to verify |
| 160 // the bounds before calling this method. |
| 161 void SetCursor(size_t cursor); |
| 162 |
| 163 // Advances the cursor by |count| bytes. The caller should use |GetLength|, |
| 164 // |CanRead|, or |CanReadFrom| to verify the bounds before calling this |
| 165 // method. |
| 166 void AdvanceCursor(size_t count) { SetCursor(GetCursor() + count); } |
| 167 |
| 168 // Returns a constant pointer to the start of the buffer. |
| 169 const uint8_t* GetBufferPtr() const { |
| 170 return reinterpret_cast<const uint8_t*>(buffer_.data()); |
| 171 } |
| 172 |
| 173 // Returns a pointer to the underlying buffer at the current cursor |
| 174 // position. |
| 175 const uint8_t* GetBufferAtCursor() const { return GetBufferPtr() + cursor_; } |
| 176 |
| 177 // Returns the byte at the current cursor position. |
| 178 uint8_t GetByteAtCursor() const { |
| 179 DCHECK(!IsEndOfBuffer()); |
| 180 return *(GetBufferAtCursor()); |
| 181 } |
| 182 |
| 183 const base::StringPiece buffer_; |
| 184 size_t cursor_; |
| 185 |
| 186 DISALLOW_COPY_AND_ASSIGN(NtlmBufferReader); |
| 187 }; |
| 188 |
| 189 } // namespce ntlm |
| 190 } // namespace net |
| 191 |
| 192 #endif // NET_BASE_NTLM_BUFFER_READER_H_ |
OLD | NEW |