Chromium Code Reviews| 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_ |