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..3c30e91e4a0724bcd767971de0441d1fa9d3ee06 |
--- /dev/null |
+++ b/net/http/ntlm_buffer_reader.h |
@@ -0,0 +1,172 @@ |
+// Copyright (c) 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_message.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 read a security buffer see |
+// |ReadSecurityBuffer| then read 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. |
+// |
+// The cursor will remain as it was before the call as if |
+// the security buffer had not been read. |
+// |
+// |
+// Skip* methods skip the cursor over that same number |
+// of bytes that the equivalent Read method would without |
+// reading or returning the values. |
+// |
+// |
+// Match* methods are used to validate fields in the |
+// buffer that should have expected values, such as |
+// signatures or message identifiers. |
Ryan Sleevi
2017/05/30 19:02:22
I can't tell - are these aligned to the maximal us
zentaro
2017/06/05 17:28:44
Done.
|
+// |
+// |
+// 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 NtlmBufferReader { |
+ public: |
+ NtlmBufferReader(const base::StringPiece buffer); |
Ryan Sleevi
2017/05/30 19:02:22
style: you can drop the const since you're passing
Ryan Sleevi
2017/05/30 19:02:22
style: "explicit" - https://google.github.io/style
zentaro
2017/06/05 17:28:44
Done. I previously was passing by const-ref then s
zentaro
2017/06/05 17:28:44
Done.
|
+ NtlmBufferReader(const uint8_t* ptr, size_t len); |
Ryan Sleevi
2017/05/30 19:02:22
Since you accept a base::StringPiece, is this over
zentaro
2017/06/05 17:28:44
I could I guess try and convert all the callers to
|
+ ~NtlmBufferReader(); |
+ |
+ size_t GetLength() const { return buffer_.length(); } |
+ size_t GetCursor() const { return cursor_; } |
+ bool IsEndOfBuffer() const { return cursor_ >= GetLength(); } |
+ |
+ 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_; } |
Ryan Sleevi
2017/05/30 19:02:22
Both this and the function on line 72 seem like th
zentaro
2017/06/05 17:28:44
I managed to refactor out all the public uses of t
|
+ |
+ // 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; |
+ |
+ bool ReadUInt16(uint16_t* value); |
Ryan Sleevi
2017/05/30 19:02:22
Document a bit more - for example, what's the endi
zentaro
2017/06/05 17:28:44
Done.
|
+ bool ReadUInt32(uint32_t* value); |
+ bool ReadUInt64(uint64_t* value); |
+ |
+ 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(uint16_t* length, uint32_t* offset); |
+ |
+ bool ReadAsciiString(std::string* value, size_t len); |
+ bool ReadUnicodeString(base::string16* value, size_t len); |
Ryan Sleevi
2017/05/30 19:02:22
I suspect you're borrowing from the NTLM language,
|
+ |
+ // 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(NtlmMessage::MessageType* message_type); |
+ |
+ bool ReadAsciiPayload(std::string* value); |
+ bool ReadUnicodePayload(base::string16* value); |
+ bool ReadBytesPayload(uint8_t* buffer, size_t buffer_len); |
Ryan Sleevi
2017/05/30 19:02:22
How are the *Payload functions different from the
zentaro
2017/06/05 17:28:44
Added some additional docs to clarify. But the 'pa
|
+ |
+ bool SkipSecurityBuffer(); |
+ |
+ // Skips over the security buffer without returning the values |
Ryan Sleevi
2017/05/30 19:02:22
grammar: "returning the values, " (add a comma)
zentaro
2017/06/05 17:28:44
Done.
|
+ // 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" |
+ bool MatchSignature(); |
+ |
+ // Reads the message type from the cursor and returns true |
+ // if it is |message_type|. |
+ bool MatchMessageType(NtlmMessage::MessageType message_type); |
+ |
+ // Performs |MatchSignature| then |MatchMessageType|. |
+ bool MatchMessageHeader(NtlmMessage::MessageType message_type); |
+ |
+ // Reads and returns true if there are |count| bytes of zeros. |
+ bool MatchZeros(size_t count); |
+ |
+ // Reads and returns true if the next 8 bytes contain an empty |
+ // ie. all zero security buffer. |
+ 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. |
+ bool SetCursor(size_t cursor); |
+ |
+ 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_ |