Chromium Code Reviews| 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/http/ntlm.h" | |
| 16 | |
| 17 namespace net { | |
| 18 | |
| 19 // Supports various bounds-checked low level buffer operations required by an | |
| 20 // NTLM implementation. | |
| 21 // | |
| 22 // The class supports sequential read of a provided buffer. All reads perform | |
| 23 // bounds checking to ensure enough space is remaining in the buffer. | |
| 24 // | |
| 25 // Read* methods read from the buffer at the current cursor position and | |
| 26 // perform any necessary type conversion and provide the data in out params. | |
| 27 // After a successful read the cursor position is advanced past the read | |
| 28 // field. | |
| 29 // | |
| 30 // Failed reads leave the internal cursor at the same position as before the | |
| 31 // call. | |
| 32 // | |
| 33 // Read*Payload methods first reads a security buffer (see | |
| 34 // |ReadSecurityBuffer|), then reads the requested payload from the offset | |
| 35 // and length stated in the security buffer. | |
| 36 // | |
| 37 // If the length and offset in the security buffer would cause a read outside | |
| 38 // the message buffer the payload will not be read and the function will | |
| 39 // return false. | |
| 40 // | |
| 41 // Based on [MS-NLMP]: NT LAN Manager (NTLM) Authentication Protocol | |
| 42 // Specification version 28.0 [1] | |
| 43 // | |
| 44 // [1] https://msdn.microsoft.com/en-us/library/cc236621.aspx | |
| 45 class NET_EXPORT_PRIVATE NtlmBufferReader { | |
| 46 public: | |
| 47 explicit NtlmBufferReader(base::StringPiece buffer); | |
| 48 | |
| 49 // This class does not take ownership of |ptr| so the caller must ensure | |
| 50 // that the buffer outlives the |NtlmBufferReader|. | |
| 51 NtlmBufferReader(const uint8_t* ptr, size_t len); | |
| 52 ~NtlmBufferReader(); | |
| 53 | |
| 54 size_t GetLength() const { return buffer_.length(); } | |
| 55 size_t GetCursor() const { return cursor_; } | |
| 56 bool IsEndOfBuffer() const { return cursor_ >= GetLength(); } | |
| 57 | |
| 58 // Returns true if there are |len| more bytes between the current cursor | |
| 59 // position and the end of the buffer. | |
| 60 bool CanRead(size_t len) const; | |
| 61 | |
| 62 // Returns true if there are |len| more bytes between |offset| and the end | |
| 63 // of the buffer. The cursor position is not used or modified. | |
| 64 bool CanReadFrom(size_t offset, size_t len) const; | |
| 65 | |
| 66 // Returns true if it would be possible to read the payload described by the | |
| 67 // security buffer. | |
| 68 bool CanReadFrom(ntlm::SecurityBuffer sec_buf) const { | |
| 69 return CanReadFrom(sec_buf.offset, sec_buf.length); | |
| 70 } | |
| 71 | |
| 72 // Reads a 16 bit value (little endian) as a uint16_t. If there are not 16 | |
| 73 // more bits available it returns false. | |
| 74 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.
| |
| 75 | |
| 76 // Reads a 32 bit value (little endian) as a uint32_t. If there are not 32 | |
| 77 // more bits available it returns false. | |
| 78 bool ReadUInt32(uint32_t* value); | |
| 79 | |
| 80 // Reads a 64 bit value (little endian) as a uint64_t. If there are not 64 | |
| 81 // more bits available it returns false. | |
| 82 bool ReadUInt64(uint64_t* value); | |
| 83 | |
| 84 // Calls |ReadUInt32| and returns it cast as |NegotiateFlags|. No | |
| 85 // validation of the value takes place. | |
| 86 bool ReadFlags(ntlm::NegotiateFlags* flags); | |
| 87 | |
| 88 // Reads |len| bytes and copies them into |buffer|. | |
| 89 bool ReadBytes(uint8_t* buffer, size_t len); | |
| 90 | |
| 91 // A security buffer is an 8 byte structure that defines the offset and | |
| 92 // length of a payload (string, struct or byte array) that appears after the | |
| 93 // fixed part of the message. | |
| 94 // | |
| 95 // The structure is (little endian fields): | |
| 96 // uint16 - |length| Length of payload | |
| 97 // uint16 - Allocation (this is always ignored and not returned) | |
| 98 // uint32 - |offset| Offset from start of message | |
| 99 bool ReadSecurityBuffer(ntlm::SecurityBuffer* sec_buf); | |
| 100 | |
| 101 // Reads |len| bytes into the std::string value. Technically these are | |
| 102 // actually in the OEM character set. In practice the implementation | |
| 103 // just treats any of these strings as an opaque byte sequence. | |
| 104 bool ReadUtf8String(std::string* value, size_t len); | |
| 105 | |
| 106 // Reads |len| bytes as a UTF-16 string with little-endian byte order. | |
| 107 bool ReadUtf16String(base::string16* value, size_t len); | |
| 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(ntlm::MessageType* message_type); | |
| 115 | |
| 116 // First reads a security buffer (see |ReadSecurityBuffer|), then verifies | |
| 117 // that the offset and length it states are within the message, then | |
| 118 // reads those bytes from the payload part of the message into a | |
| 119 // std::string. | |
| 120 // | |
| 121 // If the security buffer can't be read or the values in the security buffer | |
| 122 // are outside the bounds of the message then false will be returned. | |
| 123 // | |
| 124 // In the case of failure the cursor will remain as if it never read the | |
| 125 // security buffer. In the case of success the cursor will point after the | |
| 126 // security buffer. | |
| 127 // | |
| 128 // NOTE: Technically in NTLM 8-bit strings are in the OEM character set, | |
| 129 // however we never try to interpret these strings as anything other than | |
| 130 // a sequence of bytes, so the actual encoding is not relevant. | |
| 131 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
| |
| 132 | |
| 133 // Reads a security buffer (see |ReadSecurityBuffer|), then verifies | |
| 134 // that the offset and length it states are within the message, then | |
| 135 // reads those bytes from the payload part of the message into a | |
| 136 // base::string16. The 16 bit characters within the string are read | |
| 137 // little endian. | |
| 138 // | |
| 139 // If the security buffer can't be read or the values in the security buffer | |
| 140 // are outside the bounds of the message then false will be returned. | |
| 141 // | |
| 142 // In the case of failure the cursor will remain as if it never read the | |
| 143 // security buffer. In the case of success the cursor will point after the | |
| 144 // security buffer. | |
| 145 bool ReadUtf16Payload(base::string16* value); | |
| 146 | |
| 147 // First reads a security buffer (see |ReadSecurityBuffer|), then verifies | |
| 148 // that the offset and length it states are within the message, then | |
| 149 // reads those bytes from the payload and copies them into the provided | |
| 150 // |buffer|. | |
| 151 // | |
| 152 // If the security buffer can't be read or the values in the security buffer | |
| 153 // are outside the bounds of the message or |buffer_len| is less than the | |
| 154 // size of the payload then false will be returned. | |
| 155 // | |
| 156 // In the case of failure the cursor will remain as if it never read the | |
| 157 // security buffer. In the case of success the cursor will point after the | |
| 158 // security buffer. | |
| 159 bool ReadBytesPayload(uint8_t* buffer, size_t buffer_len); | |
| 160 | |
| 161 // Skips over a security buffer field without reading the fields. This is | |
| 162 // the equivalent of advancing the cursor 8 bytes. Returns false if there | |
| 163 // are less than 8 bytes left in the buffer. | |
| 164 bool SkipSecurityBuffer(); | |
| 165 | |
| 166 // Skips over the security buffer without returning the values, but fails if | |
| 167 // the values would cause a read outside the buffer if the payload was | |
| 168 // actually read. | |
| 169 bool SkipSecurityBufferWithValidation(); | |
| 170 | |
| 171 // Skips over |count| bytes in the buffer. Returns false if there is not | |
| 172 // |count| bytes left in the buffer. | |
| 173 bool SkipBytes(size_t count); | |
| 174 | |
| 175 // Reads and returns true if the next 8 bytes matches the signature in an | |
| 176 // NTLM message "NTLMSSP\0". The cursor advances if the the signature | |
| 177 // is matched. | |
| 178 bool MatchSignature(); | |
| 179 | |
| 180 // Performs |ReadMessageType| and returns true if the value is | |
| 181 // |message_type|. If the read fails or the message type does not match | |
| 182 // the cursor does not move. | |
| 183 bool MatchMessageType(ntlm::MessageType message_type); | |
| 184 | |
| 185 // Performs |MatchSignature| then |MatchMessageType|. | |
| 186 bool MatchMessageHeader(ntlm::MessageType message_type); | |
| 187 | |
| 188 // Performs |ReadBytes(count)| and returns true if the contents is all | |
| 189 // zero. | |
| 190 bool MatchZeros(size_t count); | |
| 191 | |
| 192 // Reads and returns true if the next 8 bytes contain an empty ie. all zero | |
| 193 // security buffer. If the read fails or the message type does not match | |
| 194 // the cursor does not move. | |
| 195 bool MatchEmptySecurityBuffer(); | |
| 196 | |
| 197 private: | |
| 198 // Reads |sizeof(T)| bytes of an integer type from a little-endian buffer. | |
| 199 template <typename T> | |
| 200 bool ReadUInt(T* value); | |
| 201 | |
| 202 // Sets the cursor position. This is used when reading payloads to move the | |
| 203 // cursor to the start of the payload indicated by the security buffer. | |
| 204 // The caller should use |GetLength|, |CanRead|, or |CanReadFrom| to verify | |
| 205 // the bounds before calling this method. | |
| 206 void SetCursor(size_t cursor); | |
| 207 | |
| 208 // Advances the cursor by |count| bytes. The caller should use|GetLength|, | |
| 209 // |CanRead|, or |CanReadFrom| to verify the bounds before calling this | |
| 210 // method. | |
| 211 void AdvanceCursor(size_t count) { SetCursor(GetCursor() + count); } | |
| 212 | |
| 213 // Returns a constant pointer to the start of the buffer. | |
| 214 const uint8_t* GetBufferPtr() const { | |
| 215 return reinterpret_cast<const uint8_t*>(buffer_.data()); | |
| 216 } | |
| 217 | |
| 218 // Returns a pointer to the underlying buffer at the current cursor | |
| 219 // position. | |
| 220 const uint8_t* GetBufferAtCursor() const { return GetBufferPtr() + cursor_; } | |
| 221 | |
| 222 // Returns the byte at the current cursor position. | |
| 223 uint8_t GetByteAtCursor() const { | |
| 224 DCHECK(!IsEndOfBuffer()); | |
| 225 return *(GetBufferAtCursor()); | |
| 226 } | |
| 227 | |
| 228 const base::StringPiece buffer_; | |
| 229 size_t cursor_; | |
| 230 | |
| 231 DISALLOW_COPY_AND_ASSIGN(NtlmBufferReader); | |
| 232 }; | |
| 233 | |
| 234 } // namespace net | |
| 235 | |
| 236 #endif // NET_BASE_NTLM_BUFFER_READER_H_ | |
| OLD | NEW |