Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1388)

Unified Diff: net/http/ntlm_buffer_reader.h

Issue 2879353002: Add a buffer reader/writer for NTLM. (Closed)
Patch Set: Rebase Created 3 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: net/http/ntlm_buffer_reader.h
diff --git a/net/http/ntlm_buffer_reader.h b/net/http/ntlm_buffer_reader.h
new file mode 100644
index 0000000000000000000000000000000000000000..76caec60c1b7a4003fdd4a82f77b6f04fe0f0f43
--- /dev/null
+++ b/net/http/ntlm_buffer_reader.h
@@ -0,0 +1,236 @@
+// 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/http/ntlm.h"
+
+namespace net {
+
+// Supports various bounds-checked low level buffer operations required by an
+// NTLM implementation.
+//
+// The class supports 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 reads leave the internal cursor at the same position as before the
+// call.
+//
+// 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]
+//
+// [1] https://msdn.microsoft.com/en-us/library/cc236621.aspx
+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(ntlm::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);
asanka 2017/06/16 03:21:29 To be pedantic, the Read*s, Skip*s, and Write*s sh
zentaro 2017/06/21 00:38:47 Done.
+
+ // 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);
+
+ // 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);
+
+ // Calls |ReadUInt32| and returns it cast as |NegotiateFlags|. No
+ // validation of the value takes place.
+ bool ReadFlags(ntlm::NegotiateFlags* flags);
+
+ // Reads |len| bytes and copies them into |buffer|.
+ bool ReadBytes(uint8_t* buffer, size_t len);
+
+ // 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(ntlm::SecurityBuffer* sec_buf);
+
+ // Reads |len| bytes into the std::string value. Technically these are
+ // actually in the OEM character set. In practice the implementation
+ // just treats any of these strings as an opaque byte sequence.
+ bool ReadUtf8String(std::string* value, size_t len);
+
+ // Reads |len| bytes as a UTF-16 string with little-endian byte order.
+ bool ReadUtf16String(base::string16* value, size_t len);
+
+ // 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(ntlm::MessageType* message_type);
+
+ // First reads a security buffer (see |ReadSecurityBuffer|), then verifies
+ // that the offset and length it states are within the message, then
+ // reads those bytes from the payload part of the message into a
+ // std::string.
+ //
+ // If the security buffer can't be read or the values in the security buffer
+ // are outside the bounds of the message then false will be returned.
+ //
+ // In the case of failure the cursor will remain as if it never read the
+ // security buffer. In the case of success the cursor will point after the
+ // security buffer.
+ //
+ // NOTE: Technically in NTLM 8-bit strings are in the OEM character set,
+ // however we never try to interpret these strings as anything other than
+ // a sequence of bytes, so the actual encoding is not relevant.
+ bool ReadUtf8Payload(std::string* value);
asanka 2017/06/16 03:21:29 Yeah, I was only referring to the Write* cases whe
zentaro 2017/06/21 00:38:47 Read*String and Read*StringPayload methods were on
+
+ // Reads a security buffer (see |ReadSecurityBuffer|), then verifies
+ // that the offset and length it states are within the message, then
+ // reads those bytes from the payload part of the message into a
+ // base::string16. The 16 bit characters within the string are read
+ // little endian.
+ //
+ // If the security buffer can't be read or the values in the security buffer
+ // are outside the bounds of the message then false will be returned.
+ //
+ // In the case of failure the cursor will remain as if it never read the
+ // security buffer. In the case of success the cursor will point after the
+ // security buffer.
+ bool ReadUtf16Payload(base::string16* value);
+
+ // First reads a security buffer (see |ReadSecurityBuffer|), then verifies
+ // that the offset and length it states are within the message, then
+ // reads those bytes from the payload and copies them into the provided
+ // |buffer|.
+ //
+ // If the security buffer can't be read or the values in the security buffer
+ // are outside the bounds of the message or |buffer_len| is less than the
+ // size of the payload then false will be returned.
+ //
+ // In the case of failure the cursor will remain as if it never read the
+ // security buffer. In the case of success the cursor will point after the
+ // security buffer.
+ bool ReadBytesPayload(uint8_t* buffer, size_t buffer_len);
+
+ // 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();
+
+ // 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();
+
+ // Skips over |count| bytes in the buffer. Returns false if there is not
+ // |count| bytes left in the buffer.
+ bool SkipBytes(size_t count);
+
+ // 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();
+
+ // Performs |ReadMessageType| and returns true if the value is
+ // |message_type|. If the read fails or the message type does not match
+ // the cursor does not move.
+ bool MatchMessageType(ntlm::MessageType message_type);
+
+ // Performs |MatchSignature| then |MatchMessageType|.
+ bool MatchMessageHeader(ntlm::MessageType message_type);
+
+ // Performs |ReadBytes(count)| and returns true if the contents is all
+ // zero.
+ bool MatchZeros(size_t count);
+
+ // Reads and returns true if the next 8 bytes contain an empty ie. all zero
+ // security buffer. If the read fails or the message type does not match
+ // the cursor does not move.
+ bool MatchEmptySecurityBuffer();
+
+ 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. This is used when reading payloads to move the
+ // cursor to the start of the payload indicated by the security buffer.
+ // 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 net
+
+#endif // NET_BASE_NTLM_BUFFER_READER_H_
« no previous file with comments | « net/http/ntlm.h ('k') | net/http/ntlm_buffer_reader.cc » ('j') | net/http/ntlm_buffer_reader.cc » ('J')

Powered by Google App Engine
This is Rietveld 408576698