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 |