Index: net/ntlm/ntlm_buffer_reader.h |
diff --git a/net/ntlm/ntlm_buffer_reader.h b/net/ntlm/ntlm_buffer_reader.h |
new file mode 100644 |
index 0000000000000000000000000000000000000000..d31429f4b71ea8530d24d36d386907119f9072da |
--- /dev/null |
+++ b/net/ntlm/ntlm_buffer_reader.h |
@@ -0,0 +1,191 @@ |
+// Copyright 2017 The Chromium Authors. All rights reserved. |
+// Use of this source code is governed by a BSD-style license that can be |
+// found in the LICENSE file. |
+ |
+#ifndef NET_BASE_NTLM_BUFFER_READER_H_ |
+#define NET_BASE_NTLM_BUFFER_READER_H_ |
+ |
+#include <stddef.h> |
+#include <stdint.h> |
+ |
+#include <string> |
+ |
+#include "base/strings/string_piece.h" |
+#include "net/base/net_export.h" |
+#include "net/ntlm/ntlm_constants.h" |
+ |
+namespace net { |
+namespace ntlm { |
+ |
+// Supports various bounds-checked low level buffer operations required by an |
+// NTLM implementation. |
+// |
+// The class supports the sequential read of a provided buffer. All reads |
+// perform bounds checking to ensure enough space is remaining in the buffer. |
+// |
+// Read* methods read from the buffer at the current cursor position and |
+// perform any necessary type conversion and provide the data in out params. |
+// After a successful read the cursor position is advanced past the read |
+// field. |
+// |
+// Failed Read*s or Match*s leave the cursor in an undefined position and the |
+// buffer MUST be discarded with no further operations performed. |
+// |
+// Read*Payload methods first reads a security buffer (see |
+// |ReadSecurityBuffer|), then reads the requested payload from the offset |
+// and length stated in the security buffer. |
+// |
+// If the length and offset in the security buffer would cause a read outside |
+// the message buffer the payload will not be read and the function will |
+// return false. |
+// |
+// Based on [MS-NLMP]: NT LAN Manager (NTLM) Authentication Protocol |
+// Specification version 28.0 [1]. Additional NTLM reference [2]. |
+// |
+// [1] https://msdn.microsoft.com/en-us/library/cc236621.aspx |
+// [2] http://davenport.sourceforge.net/ntlm.html |
+class NET_EXPORT_PRIVATE NtlmBufferReader { |
+ public: |
+ explicit NtlmBufferReader(base::StringPiece buffer); |
+ |
+ // This class does not take ownership of |ptr|, so the caller must ensure |
+ // that the buffer outlives the |NtlmBufferReader|. |
+ NtlmBufferReader(const uint8_t* ptr, size_t len); |
+ ~NtlmBufferReader(); |
+ |
+ size_t GetLength() const { return buffer_.length(); } |
+ size_t GetCursor() const { return cursor_; } |
+ bool IsEndOfBuffer() const { return cursor_ >= GetLength(); } |
+ |
+ // Returns true if there are |len| more bytes between the current cursor |
+ // position and the end of the buffer. |
+ bool CanRead(size_t len) const; |
+ |
+ // Returns true if there are |len| more bytes between |offset| and the end |
+ // of the buffer. The cursor position is not used or modified. |
+ bool CanReadFrom(size_t offset, size_t len) const; |
+ |
+ // Returns true if it would be possible to read the payload described by the |
+ // security buffer. |
+ bool CanReadFrom(SecurityBuffer sec_buf) const { |
+ return CanReadFrom(sec_buf.offset, sec_buf.length); |
+ } |
+ |
+ // Reads a 16 bit value (little endian) as a uint16_t. If there are not 16 |
+ // more bits available, it returns false. |
+ bool ReadUInt16(uint16_t* value) WARN_UNUSED_RESULT; |
+ |
+ // Reads a 32 bit value (little endian) as a uint32_t. If there are not 32 |
+ // more bits available, it returns false. |
+ bool ReadUInt32(uint32_t* value) WARN_UNUSED_RESULT; |
+ |
+ // Reads a 64 bit value (little endian) as a uint64_t. If there are not 64 |
+ // more bits available, it returns false. |
+ bool ReadUInt64(uint64_t* value) WARN_UNUSED_RESULT; |
+ |
+ // Calls |ReadUInt32| and returns it cast as |NegotiateFlags|. No |
+ // validation of the value takes place. |
+ bool ReadFlags(NegotiateFlags* flags) WARN_UNUSED_RESULT; |
+ |
+ // Reads |len| bytes and copies them into |buffer|. |
+ bool ReadBytes(uint8_t* buffer, size_t len) WARN_UNUSED_RESULT; |
+ |
+ // Reads |sec_buf.length| bytes from offset |sec_buf.offset| and copies them |
+ // into |buffer|. If the security buffer specifies a payload outside the |
+ // buffer, then the call fails. Unlike the other Read* methods, this does |
+ // not move the cursor. |
+ bool ReadBytesFrom(const SecurityBuffer& sec_buf, |
+ uint8_t* buffer) WARN_UNUSED_RESULT; |
+ |
+ // A security buffer is an 8 byte structure that defines the offset and |
+ // length of a payload (string, struct or byte array) that appears after the |
+ // fixed part of the message. |
+ // |
+ // The structure is (little endian fields): |
+ // uint16 - |length| Length of payload |
+ // uint16 - Allocation (this is always ignored and not returned) |
+ // uint32 - |offset| Offset from start of message |
+ bool ReadSecurityBuffer(SecurityBuffer* sec_buf) WARN_UNUSED_RESULT; |
+ |
+ // There are 3 message types Negotiate (sent by client), Challenge (sent by |
+ // server), and Authenticate (sent by client). |
+ // |
+ // This reads the message type from the header and will return false if the |
+ // value is invalid. |
+ bool ReadMessageType(MessageType* message_type) WARN_UNUSED_RESULT; |
+ |
+ // Skips over a security buffer field without reading the fields. This is |
+ // the equivalent of advancing the cursor 8 bytes. Returns false if there |
+ // are less than 8 bytes left in the buffer. |
+ bool SkipSecurityBuffer() WARN_UNUSED_RESULT; |
+ |
+ // Skips over the security buffer without returning the values, but fails if |
+ // the values would cause a read outside the buffer if the payload was |
+ // actually read. |
+ bool SkipSecurityBufferWithValidation() WARN_UNUSED_RESULT; |
+ |
+ // Skips over |count| bytes in the buffer. Returns false if there are not |
+ // |count| bytes left in the buffer. |
+ bool SkipBytes(size_t count) WARN_UNUSED_RESULT; |
+ |
+ // Reads and returns true if the next 8 bytes matches the signature in an |
+ // NTLM message "NTLMSSP\0". The cursor advances if the the signature |
+ // is matched. |
+ bool MatchSignature() WARN_UNUSED_RESULT; |
+ |
+ // Performs |ReadMessageType| and returns true if the value is |
+ // |message_type|. If the read fails or the message type does not match, |
+ // the buffer is invalid and MUST be discarded. |
+ bool MatchMessageType(MessageType message_type) WARN_UNUSED_RESULT; |
+ |
+ // Performs |MatchSignature| then |MatchMessageType|. |
+ bool MatchMessageHeader(MessageType message_type) WARN_UNUSED_RESULT; |
+ |
+ // Performs |ReadBytes(count)| and returns true if the contents is all |
+ // zero. |
+ bool MatchZeros(size_t count) WARN_UNUSED_RESULT; |
+ |
+ // Reads the security buffer and returns true if the length is 0 and |
+ // the offset is within the message. On failure, the buffer is invalid |
+ // and MUST be discarded. |
+ bool MatchEmptySecurityBuffer() WARN_UNUSED_RESULT; |
+ |
+ private: |
+ // Reads |sizeof(T)| bytes of an integer type from a little-endian buffer. |
+ template <typename T> |
+ bool ReadUInt(T* value); |
+ |
+ // Sets the cursor position. The caller should use |GetLength|, |CanRead|, |
+ // or |CanReadFrom| to verify the bounds before calling this method. |
+ void SetCursor(size_t cursor); |
+ |
+ // Advances the cursor by |count| bytes. The caller should use |GetLength|, |
+ // |CanRead|, or |CanReadFrom| to verify the bounds before calling this |
+ // method. |
+ void AdvanceCursor(size_t count) { SetCursor(GetCursor() + count); } |
+ |
+ // Returns a constant pointer to the start of the buffer. |
+ const uint8_t* GetBufferPtr() const { |
+ return reinterpret_cast<const uint8_t*>(buffer_.data()); |
+ } |
+ |
+ // Returns a pointer to the underlying buffer at the current cursor |
+ // position. |
+ const uint8_t* GetBufferAtCursor() const { return GetBufferPtr() + cursor_; } |
+ |
+ // Returns the byte at the current cursor position. |
+ uint8_t GetByteAtCursor() const { |
+ DCHECK(!IsEndOfBuffer()); |
+ return *(GetBufferAtCursor()); |
+ } |
+ |
+ const base::StringPiece buffer_; |
+ size_t cursor_; |
+ |
+ DISALLOW_COPY_AND_ASSIGN(NtlmBufferReader); |
+}; |
+ |
+} // namespace ntlm |
+} // namespace net |
+ |
+#endif // NET_BASE_NTLM_BUFFER_READER_H_ |