1*6777b538SAndroid Build Coastguard Worker // Copyright 2017 The Chromium Authors
2*6777b538SAndroid Build Coastguard Worker // Use of this source code is governed by a BSD-style license that can be
3*6777b538SAndroid Build Coastguard Worker // found in the LICENSE file.
4*6777b538SAndroid Build Coastguard Worker
5*6777b538SAndroid Build Coastguard Worker #include "net/ntlm/ntlm_client.h"
6*6777b538SAndroid Build Coastguard Worker
7*6777b538SAndroid Build Coastguard Worker #include <string>
8*6777b538SAndroid Build Coastguard Worker
9*6777b538SAndroid Build Coastguard Worker #include "base/containers/span.h"
10*6777b538SAndroid Build Coastguard Worker #include "base/strings/string_util.h"
11*6777b538SAndroid Build Coastguard Worker #include "build/build_config.h"
12*6777b538SAndroid Build Coastguard Worker #include "net/ntlm/ntlm.h"
13*6777b538SAndroid Build Coastguard Worker #include "net/ntlm/ntlm_buffer_reader.h"
14*6777b538SAndroid Build Coastguard Worker #include "net/ntlm/ntlm_buffer_writer.h"
15*6777b538SAndroid Build Coastguard Worker #include "net/ntlm/ntlm_test_data.h"
16*6777b538SAndroid Build Coastguard Worker #include "testing/gtest/include/gtest/gtest.h"
17*6777b538SAndroid Build Coastguard Worker
18*6777b538SAndroid Build Coastguard Worker namespace net::ntlm {
19*6777b538SAndroid Build Coastguard Worker
20*6777b538SAndroid Build Coastguard Worker namespace {
21*6777b538SAndroid Build Coastguard Worker
GenerateAuthMsg(const NtlmClient & client,base::span<const uint8_t> challenge_msg)22*6777b538SAndroid Build Coastguard Worker std::vector<uint8_t> GenerateAuthMsg(const NtlmClient& client,
23*6777b538SAndroid Build Coastguard Worker base::span<const uint8_t> challenge_msg) {
24*6777b538SAndroid Build Coastguard Worker return client.GenerateAuthenticateMessage(
25*6777b538SAndroid Build Coastguard Worker test::kNtlmDomain, test::kUser, test::kPassword, test::kHostnameAscii,
26*6777b538SAndroid Build Coastguard Worker reinterpret_cast<const char*>(test::kChannelBindings), test::kNtlmSpn,
27*6777b538SAndroid Build Coastguard Worker test::kClientTimestamp, test::kClientChallenge, challenge_msg);
28*6777b538SAndroid Build Coastguard Worker }
29*6777b538SAndroid Build Coastguard Worker
GenerateAuthMsg(const NtlmClient & client,const NtlmBufferWriter & challenge_writer)30*6777b538SAndroid Build Coastguard Worker std::vector<uint8_t> GenerateAuthMsg(const NtlmClient& client,
31*6777b538SAndroid Build Coastguard Worker const NtlmBufferWriter& challenge_writer) {
32*6777b538SAndroid Build Coastguard Worker return GenerateAuthMsg(client, challenge_writer.GetBuffer());
33*6777b538SAndroid Build Coastguard Worker }
34*6777b538SAndroid Build Coastguard Worker
GetAuthMsgResult(const NtlmClient & client,const NtlmBufferWriter & challenge_writer)35*6777b538SAndroid Build Coastguard Worker bool GetAuthMsgResult(const NtlmClient& client,
36*6777b538SAndroid Build Coastguard Worker const NtlmBufferWriter& challenge_writer) {
37*6777b538SAndroid Build Coastguard Worker return !GenerateAuthMsg(client, challenge_writer).empty();
38*6777b538SAndroid Build Coastguard Worker }
39*6777b538SAndroid Build Coastguard Worker
ReadBytesPayload(NtlmBufferReader * reader,base::span<uint8_t> buffer)40*6777b538SAndroid Build Coastguard Worker bool ReadBytesPayload(NtlmBufferReader* reader, base::span<uint8_t> buffer) {
41*6777b538SAndroid Build Coastguard Worker SecurityBuffer sec_buf;
42*6777b538SAndroid Build Coastguard Worker return reader->ReadSecurityBuffer(&sec_buf) &&
43*6777b538SAndroid Build Coastguard Worker (sec_buf.length == buffer.size()) &&
44*6777b538SAndroid Build Coastguard Worker reader->ReadBytesFrom(sec_buf, buffer);
45*6777b538SAndroid Build Coastguard Worker }
46*6777b538SAndroid Build Coastguard Worker
47*6777b538SAndroid Build Coastguard Worker // Reads bytes from a payload and assigns them to a string. This makes
48*6777b538SAndroid Build Coastguard Worker // no assumptions about the underlying encoding.
ReadStringPayload(NtlmBufferReader * reader,std::string * str)49*6777b538SAndroid Build Coastguard Worker bool ReadStringPayload(NtlmBufferReader* reader, std::string* str) {
50*6777b538SAndroid Build Coastguard Worker SecurityBuffer sec_buf;
51*6777b538SAndroid Build Coastguard Worker if (!reader->ReadSecurityBuffer(&sec_buf))
52*6777b538SAndroid Build Coastguard Worker return false;
53*6777b538SAndroid Build Coastguard Worker
54*6777b538SAndroid Build Coastguard Worker str->resize(sec_buf.length);
55*6777b538SAndroid Build Coastguard Worker if (!reader->ReadBytesFrom(sec_buf, base::as_writable_byte_span(*str))) {
56*6777b538SAndroid Build Coastguard Worker return false;
57*6777b538SAndroid Build Coastguard Worker }
58*6777b538SAndroid Build Coastguard Worker
59*6777b538SAndroid Build Coastguard Worker return true;
60*6777b538SAndroid Build Coastguard Worker }
61*6777b538SAndroid Build Coastguard Worker
62*6777b538SAndroid Build Coastguard Worker // Reads bytes from a payload and assigns them to a string16. This makes
63*6777b538SAndroid Build Coastguard Worker // no assumptions about the underlying encoding. This will fail if there
64*6777b538SAndroid Build Coastguard Worker // are an odd number of bytes in the payload.
ReadString16Payload(NtlmBufferReader * reader,std::u16string * str)65*6777b538SAndroid Build Coastguard Worker bool ReadString16Payload(NtlmBufferReader* reader, std::u16string* str) {
66*6777b538SAndroid Build Coastguard Worker SecurityBuffer sec_buf;
67*6777b538SAndroid Build Coastguard Worker if (!reader->ReadSecurityBuffer(&sec_buf) || (sec_buf.length % 2 != 0))
68*6777b538SAndroid Build Coastguard Worker return false;
69*6777b538SAndroid Build Coastguard Worker
70*6777b538SAndroid Build Coastguard Worker std::vector<uint8_t> raw(sec_buf.length);
71*6777b538SAndroid Build Coastguard Worker if (!reader->ReadBytesFrom(sec_buf, raw))
72*6777b538SAndroid Build Coastguard Worker return false;
73*6777b538SAndroid Build Coastguard Worker
74*6777b538SAndroid Build Coastguard Worker #if defined(ARCH_CPU_BIG_ENDIAN)
75*6777b538SAndroid Build Coastguard Worker for (size_t i = 0; i < raw.size(); i += 2) {
76*6777b538SAndroid Build Coastguard Worker std::swap(raw[i], raw[i + 1]);
77*6777b538SAndroid Build Coastguard Worker }
78*6777b538SAndroid Build Coastguard Worker #endif
79*6777b538SAndroid Build Coastguard Worker
80*6777b538SAndroid Build Coastguard Worker str->assign(reinterpret_cast<const char16_t*>(raw.data()), raw.size() / 2);
81*6777b538SAndroid Build Coastguard Worker return true;
82*6777b538SAndroid Build Coastguard Worker }
83*6777b538SAndroid Build Coastguard Worker
MakeV2ChallengeMessage(size_t target_info_len,std::vector<uint8_t> * out)84*6777b538SAndroid Build Coastguard Worker void MakeV2ChallengeMessage(size_t target_info_len, std::vector<uint8_t>* out) {
85*6777b538SAndroid Build Coastguard Worker static const size_t kChallengeV2HeaderLen = 56;
86*6777b538SAndroid Build Coastguard Worker
87*6777b538SAndroid Build Coastguard Worker // Leave room for the AV_PAIR header and the EOL pair.
88*6777b538SAndroid Build Coastguard Worker size_t server_name_len = target_info_len - kAvPairHeaderLen * 2;
89*6777b538SAndroid Build Coastguard Worker
90*6777b538SAndroid Build Coastguard Worker // See [MS-NLP] Section 2.2.1.2.
91*6777b538SAndroid Build Coastguard Worker NtlmBufferWriter challenge(kChallengeV2HeaderLen + target_info_len);
92*6777b538SAndroid Build Coastguard Worker ASSERT_TRUE(challenge.WriteMessageHeader(MessageType::kChallenge));
93*6777b538SAndroid Build Coastguard Worker ASSERT_TRUE(
94*6777b538SAndroid Build Coastguard Worker challenge.WriteSecurityBuffer(SecurityBuffer(0, 0))); // target name
95*6777b538SAndroid Build Coastguard Worker ASSERT_TRUE(challenge.WriteFlags(NegotiateFlags::kTargetInfo));
96*6777b538SAndroid Build Coastguard Worker ASSERT_TRUE(challenge.WriteZeros(kChallengeLen)); // server challenge
97*6777b538SAndroid Build Coastguard Worker ASSERT_TRUE(challenge.WriteZeros(8)); // reserved
98*6777b538SAndroid Build Coastguard Worker ASSERT_TRUE(challenge.WriteSecurityBuffer(
99*6777b538SAndroid Build Coastguard Worker SecurityBuffer(kChallengeV2HeaderLen, target_info_len))); // target info
100*6777b538SAndroid Build Coastguard Worker ASSERT_TRUE(challenge.WriteZeros(8)); // version
101*6777b538SAndroid Build Coastguard Worker ASSERT_EQ(kChallengeV2HeaderLen, challenge.GetCursor());
102*6777b538SAndroid Build Coastguard Worker ASSERT_TRUE(challenge.WriteAvPair(
103*6777b538SAndroid Build Coastguard Worker AvPair(TargetInfoAvId::kServerName,
104*6777b538SAndroid Build Coastguard Worker std::vector<uint8_t>(server_name_len, 'a'))));
105*6777b538SAndroid Build Coastguard Worker ASSERT_TRUE(challenge.WriteAvPairTerminator());
106*6777b538SAndroid Build Coastguard Worker ASSERT_TRUE(challenge.IsEndOfBuffer());
107*6777b538SAndroid Build Coastguard Worker *out = challenge.Pass();
108*6777b538SAndroid Build Coastguard Worker }
109*6777b538SAndroid Build Coastguard Worker
110*6777b538SAndroid Build Coastguard Worker } // namespace
111*6777b538SAndroid Build Coastguard Worker
TEST(NtlmClientTest,SimpleConstructionV1)112*6777b538SAndroid Build Coastguard Worker TEST(NtlmClientTest, SimpleConstructionV1) {
113*6777b538SAndroid Build Coastguard Worker NtlmClient client(NtlmFeatures(false));
114*6777b538SAndroid Build Coastguard Worker
115*6777b538SAndroid Build Coastguard Worker ASSERT_FALSE(client.IsNtlmV2());
116*6777b538SAndroid Build Coastguard Worker ASSERT_FALSE(client.IsEpaEnabled());
117*6777b538SAndroid Build Coastguard Worker ASSERT_FALSE(client.IsMicEnabled());
118*6777b538SAndroid Build Coastguard Worker }
119*6777b538SAndroid Build Coastguard Worker
TEST(NtlmClientTest,VerifyNegotiateMessageV1)120*6777b538SAndroid Build Coastguard Worker TEST(NtlmClientTest, VerifyNegotiateMessageV1) {
121*6777b538SAndroid Build Coastguard Worker NtlmClient client(NtlmFeatures(false));
122*6777b538SAndroid Build Coastguard Worker
123*6777b538SAndroid Build Coastguard Worker std::vector<uint8_t> result = client.GetNegotiateMessage();
124*6777b538SAndroid Build Coastguard Worker
125*6777b538SAndroid Build Coastguard Worker ASSERT_EQ(kNegotiateMessageLen, result.size());
126*6777b538SAndroid Build Coastguard Worker ASSERT_EQ(0, memcmp(test::kExpectedNegotiateMsg, result.data(),
127*6777b538SAndroid Build Coastguard Worker kNegotiateMessageLen));
128*6777b538SAndroid Build Coastguard Worker }
129*6777b538SAndroid Build Coastguard Worker
TEST(NtlmClientTest,MinimalStructurallyValidChallenge)130*6777b538SAndroid Build Coastguard Worker TEST(NtlmClientTest, MinimalStructurallyValidChallenge) {
131*6777b538SAndroid Build Coastguard Worker NtlmClient client(NtlmFeatures(false));
132*6777b538SAndroid Build Coastguard Worker
133*6777b538SAndroid Build Coastguard Worker NtlmBufferWriter writer(kMinChallengeHeaderLen);
134*6777b538SAndroid Build Coastguard Worker ASSERT_TRUE(writer.WriteBytes(base::make_span(test::kMinChallengeMessage)
135*6777b538SAndroid Build Coastguard Worker .subspan<0, kMinChallengeHeaderLen>()));
136*6777b538SAndroid Build Coastguard Worker
137*6777b538SAndroid Build Coastguard Worker ASSERT_TRUE(GetAuthMsgResult(client, writer));
138*6777b538SAndroid Build Coastguard Worker }
139*6777b538SAndroid Build Coastguard Worker
TEST(NtlmClientTest,MinimalStructurallyValidChallengeZeroOffset)140*6777b538SAndroid Build Coastguard Worker TEST(NtlmClientTest, MinimalStructurallyValidChallengeZeroOffset) {
141*6777b538SAndroid Build Coastguard Worker NtlmClient client(NtlmFeatures(false));
142*6777b538SAndroid Build Coastguard Worker
143*6777b538SAndroid Build Coastguard Worker // The spec (2.2.1.2) states that the length SHOULD be 0 and the offset
144*6777b538SAndroid Build Coastguard Worker // SHOULD be where the payload would be if it was present. This is the
145*6777b538SAndroid Build Coastguard Worker // expected response from a compliant server when no target name is sent.
146*6777b538SAndroid Build Coastguard Worker // In reality the offset should always be ignored if the length is zero.
147*6777b538SAndroid Build Coastguard Worker // Also implementations often just write zeros.
148*6777b538SAndroid Build Coastguard Worker uint8_t raw[kMinChallengeHeaderLen];
149*6777b538SAndroid Build Coastguard Worker memcpy(raw, test::kMinChallengeMessage, kMinChallengeHeaderLen);
150*6777b538SAndroid Build Coastguard Worker // Modify the default valid message to overwrite the offset to zero.
151*6777b538SAndroid Build Coastguard Worker ASSERT_NE(0x00, raw[16]);
152*6777b538SAndroid Build Coastguard Worker raw[16] = 0x00;
153*6777b538SAndroid Build Coastguard Worker
154*6777b538SAndroid Build Coastguard Worker NtlmBufferWriter writer(kMinChallengeHeaderLen);
155*6777b538SAndroid Build Coastguard Worker ASSERT_TRUE(writer.WriteBytes(raw));
156*6777b538SAndroid Build Coastguard Worker
157*6777b538SAndroid Build Coastguard Worker ASSERT_TRUE(GetAuthMsgResult(client, writer));
158*6777b538SAndroid Build Coastguard Worker }
159*6777b538SAndroid Build Coastguard Worker
TEST(NtlmClientTest,ChallengeMsgTooShort)160*6777b538SAndroid Build Coastguard Worker TEST(NtlmClientTest, ChallengeMsgTooShort) {
161*6777b538SAndroid Build Coastguard Worker NtlmClient client(NtlmFeatures(false));
162*6777b538SAndroid Build Coastguard Worker
163*6777b538SAndroid Build Coastguard Worker // Fail because the minimum size valid message is 32 bytes.
164*6777b538SAndroid Build Coastguard Worker NtlmBufferWriter writer(kMinChallengeHeaderLen - 1);
165*6777b538SAndroid Build Coastguard Worker ASSERT_TRUE(writer.WriteBytes(base::make_span(test::kMinChallengeMessage)
166*6777b538SAndroid Build Coastguard Worker .subspan<0, kMinChallengeHeaderLen - 1>()));
167*6777b538SAndroid Build Coastguard Worker ASSERT_FALSE(GetAuthMsgResult(client, writer));
168*6777b538SAndroid Build Coastguard Worker }
169*6777b538SAndroid Build Coastguard Worker
TEST(NtlmClientTest,ChallengeMsgNoSig)170*6777b538SAndroid Build Coastguard Worker TEST(NtlmClientTest, ChallengeMsgNoSig) {
171*6777b538SAndroid Build Coastguard Worker NtlmClient client(NtlmFeatures(false));
172*6777b538SAndroid Build Coastguard Worker
173*6777b538SAndroid Build Coastguard Worker // Fail because the first 8 bytes don't match "NTLMSSP\0"
174*6777b538SAndroid Build Coastguard Worker uint8_t raw[kMinChallengeHeaderLen];
175*6777b538SAndroid Build Coastguard Worker memcpy(raw, test::kMinChallengeMessage, kMinChallengeHeaderLen);
176*6777b538SAndroid Build Coastguard Worker // Modify the default valid message to overwrite the last byte of the
177*6777b538SAndroid Build Coastguard Worker // signature.
178*6777b538SAndroid Build Coastguard Worker ASSERT_NE(0xff, raw[7]);
179*6777b538SAndroid Build Coastguard Worker raw[7] = 0xff;
180*6777b538SAndroid Build Coastguard Worker NtlmBufferWriter writer(kMinChallengeHeaderLen);
181*6777b538SAndroid Build Coastguard Worker ASSERT_TRUE(writer.WriteBytes(raw));
182*6777b538SAndroid Build Coastguard Worker ASSERT_FALSE(GetAuthMsgResult(client, writer));
183*6777b538SAndroid Build Coastguard Worker }
184*6777b538SAndroid Build Coastguard Worker
TEST(NtlmClientTest,ChallengeMsgWrongMessageType)185*6777b538SAndroid Build Coastguard Worker TEST(NtlmClientTest, ChallengeMsgWrongMessageType) {
186*6777b538SAndroid Build Coastguard Worker NtlmClient client(NtlmFeatures(false));
187*6777b538SAndroid Build Coastguard Worker
188*6777b538SAndroid Build Coastguard Worker // Fail because the message type should be MessageType::kChallenge
189*6777b538SAndroid Build Coastguard Worker // (0x00000002)
190*6777b538SAndroid Build Coastguard Worker uint8_t raw[kMinChallengeHeaderLen];
191*6777b538SAndroid Build Coastguard Worker memcpy(raw, test::kMinChallengeMessage, kMinChallengeHeaderLen);
192*6777b538SAndroid Build Coastguard Worker // Modify the message type.
193*6777b538SAndroid Build Coastguard Worker ASSERT_NE(0x03, raw[8]);
194*6777b538SAndroid Build Coastguard Worker raw[8] = 0x03;
195*6777b538SAndroid Build Coastguard Worker
196*6777b538SAndroid Build Coastguard Worker NtlmBufferWriter writer(kMinChallengeHeaderLen);
197*6777b538SAndroid Build Coastguard Worker ASSERT_TRUE(writer.WriteBytes(raw));
198*6777b538SAndroid Build Coastguard Worker
199*6777b538SAndroid Build Coastguard Worker ASSERT_FALSE(GetAuthMsgResult(client, writer));
200*6777b538SAndroid Build Coastguard Worker }
201*6777b538SAndroid Build Coastguard Worker
TEST(NtlmClientTest,ChallengeWithNoTargetName)202*6777b538SAndroid Build Coastguard Worker TEST(NtlmClientTest, ChallengeWithNoTargetName) {
203*6777b538SAndroid Build Coastguard Worker NtlmClient client(NtlmFeatures(false));
204*6777b538SAndroid Build Coastguard Worker
205*6777b538SAndroid Build Coastguard Worker // The spec (2.2.1.2) states that the length SHOULD be 0 and the offset
206*6777b538SAndroid Build Coastguard Worker // SHOULD be where the payload would be if it was present. This is the
207*6777b538SAndroid Build Coastguard Worker // expected response from a compliant server when no target name is sent.
208*6777b538SAndroid Build Coastguard Worker // In reality the offset should always be ignored if the length is zero.
209*6777b538SAndroid Build Coastguard Worker // Also implementations often just write zeros.
210*6777b538SAndroid Build Coastguard Worker uint8_t raw[kMinChallengeHeaderLen];
211*6777b538SAndroid Build Coastguard Worker memcpy(raw, test::kMinChallengeMessage, kMinChallengeHeaderLen);
212*6777b538SAndroid Build Coastguard Worker // Modify the default valid message to overwrite the offset to zero.
213*6777b538SAndroid Build Coastguard Worker ASSERT_NE(0x00, raw[16]);
214*6777b538SAndroid Build Coastguard Worker raw[16] = 0x00;
215*6777b538SAndroid Build Coastguard Worker
216*6777b538SAndroid Build Coastguard Worker NtlmBufferWriter writer(kMinChallengeHeaderLen);
217*6777b538SAndroid Build Coastguard Worker ASSERT_TRUE(writer.WriteBytes(raw));
218*6777b538SAndroid Build Coastguard Worker
219*6777b538SAndroid Build Coastguard Worker ASSERT_TRUE(GetAuthMsgResult(client, writer));
220*6777b538SAndroid Build Coastguard Worker }
221*6777b538SAndroid Build Coastguard Worker
TEST(NtlmClientTest,Type2MessageWithTargetName)222*6777b538SAndroid Build Coastguard Worker TEST(NtlmClientTest, Type2MessageWithTargetName) {
223*6777b538SAndroid Build Coastguard Worker NtlmClient client(NtlmFeatures(false));
224*6777b538SAndroid Build Coastguard Worker
225*6777b538SAndroid Build Coastguard Worker // One extra byte is provided for target name.
226*6777b538SAndroid Build Coastguard Worker uint8_t raw[kMinChallengeHeaderLen + 1];
227*6777b538SAndroid Build Coastguard Worker memcpy(raw, test::kMinChallengeMessage, kMinChallengeHeaderLen);
228*6777b538SAndroid Build Coastguard Worker // Put something in the target name.
229*6777b538SAndroid Build Coastguard Worker raw[kMinChallengeHeaderLen] = 'Z';
230*6777b538SAndroid Build Coastguard Worker
231*6777b538SAndroid Build Coastguard Worker // Modify the default valid message to indicate 1 byte is present in the
232*6777b538SAndroid Build Coastguard Worker // target name payload.
233*6777b538SAndroid Build Coastguard Worker ASSERT_NE(0x01, raw[12]);
234*6777b538SAndroid Build Coastguard Worker ASSERT_EQ(0x00, raw[13]);
235*6777b538SAndroid Build Coastguard Worker ASSERT_NE(0x01, raw[14]);
236*6777b538SAndroid Build Coastguard Worker ASSERT_EQ(0x00, raw[15]);
237*6777b538SAndroid Build Coastguard Worker raw[12] = 0x01;
238*6777b538SAndroid Build Coastguard Worker raw[14] = 0x01;
239*6777b538SAndroid Build Coastguard Worker
240*6777b538SAndroid Build Coastguard Worker NtlmBufferWriter writer(kChallengeHeaderLen + 1);
241*6777b538SAndroid Build Coastguard Worker ASSERT_TRUE(writer.WriteBytes(raw));
242*6777b538SAndroid Build Coastguard Worker ASSERT_TRUE(GetAuthMsgResult(client, writer));
243*6777b538SAndroid Build Coastguard Worker }
244*6777b538SAndroid Build Coastguard Worker
TEST(NtlmClientTest,NoTargetNameOverflowFromOffset)245*6777b538SAndroid Build Coastguard Worker TEST(NtlmClientTest, NoTargetNameOverflowFromOffset) {
246*6777b538SAndroid Build Coastguard Worker NtlmClient client(NtlmFeatures(false));
247*6777b538SAndroid Build Coastguard Worker
248*6777b538SAndroid Build Coastguard Worker uint8_t raw[kMinChallengeHeaderLen];
249*6777b538SAndroid Build Coastguard Worker memcpy(raw, test::kMinChallengeMessage, kMinChallengeHeaderLen);
250*6777b538SAndroid Build Coastguard Worker // Modify the default valid message to claim that the target name field is 1
251*6777b538SAndroid Build Coastguard Worker // byte long overrunning the end of the message message.
252*6777b538SAndroid Build Coastguard Worker ASSERT_NE(0x01, raw[12]);
253*6777b538SAndroid Build Coastguard Worker ASSERT_EQ(0x00, raw[13]);
254*6777b538SAndroid Build Coastguard Worker ASSERT_NE(0x01, raw[14]);
255*6777b538SAndroid Build Coastguard Worker ASSERT_EQ(0x00, raw[15]);
256*6777b538SAndroid Build Coastguard Worker raw[12] = 0x01;
257*6777b538SAndroid Build Coastguard Worker raw[14] = 0x01;
258*6777b538SAndroid Build Coastguard Worker
259*6777b538SAndroid Build Coastguard Worker NtlmBufferWriter writer(kMinChallengeHeaderLen);
260*6777b538SAndroid Build Coastguard Worker ASSERT_TRUE(writer.WriteBytes(raw));
261*6777b538SAndroid Build Coastguard Worker
262*6777b538SAndroid Build Coastguard Worker // The above malformed message could cause an implementation to read outside
263*6777b538SAndroid Build Coastguard Worker // the message buffer because the offset is past the end of the message.
264*6777b538SAndroid Build Coastguard Worker // Verify it gets rejected.
265*6777b538SAndroid Build Coastguard Worker ASSERT_FALSE(GetAuthMsgResult(client, writer));
266*6777b538SAndroid Build Coastguard Worker }
267*6777b538SAndroid Build Coastguard Worker
TEST(NtlmClientTest,NoTargetNameOverflowFromLength)268*6777b538SAndroid Build Coastguard Worker TEST(NtlmClientTest, NoTargetNameOverflowFromLength) {
269*6777b538SAndroid Build Coastguard Worker NtlmClient client(NtlmFeatures(false));
270*6777b538SAndroid Build Coastguard Worker
271*6777b538SAndroid Build Coastguard Worker // Message has 1 extra byte of space after the header for the target name.
272*6777b538SAndroid Build Coastguard Worker // One extra byte is provided for target name.
273*6777b538SAndroid Build Coastguard Worker uint8_t raw[kMinChallengeHeaderLen + 1];
274*6777b538SAndroid Build Coastguard Worker memcpy(raw, test::kMinChallengeMessage, kMinChallengeHeaderLen);
275*6777b538SAndroid Build Coastguard Worker // Put something in the target name.
276*6777b538SAndroid Build Coastguard Worker raw[kMinChallengeHeaderLen] = 'Z';
277*6777b538SAndroid Build Coastguard Worker
278*6777b538SAndroid Build Coastguard Worker // Modify the default valid message to indicate 2 bytes are present in the
279*6777b538SAndroid Build Coastguard Worker // target name payload (however there is only space for 1).
280*6777b538SAndroid Build Coastguard Worker ASSERT_NE(0x02, raw[12]);
281*6777b538SAndroid Build Coastguard Worker ASSERT_EQ(0x00, raw[13]);
282*6777b538SAndroid Build Coastguard Worker ASSERT_NE(0x02, raw[14]);
283*6777b538SAndroid Build Coastguard Worker ASSERT_EQ(0x00, raw[15]);
284*6777b538SAndroid Build Coastguard Worker raw[12] = 0x02;
285*6777b538SAndroid Build Coastguard Worker raw[14] = 0x02;
286*6777b538SAndroid Build Coastguard Worker
287*6777b538SAndroid Build Coastguard Worker NtlmBufferWriter writer(kMinChallengeHeaderLen + 1);
288*6777b538SAndroid Build Coastguard Worker ASSERT_TRUE(writer.WriteBytes(raw));
289*6777b538SAndroid Build Coastguard Worker
290*6777b538SAndroid Build Coastguard Worker // The above malformed message could cause an implementation
291*6777b538SAndroid Build Coastguard Worker // to read outside the message buffer because the length is
292*6777b538SAndroid Build Coastguard Worker // longer than available space. Verify it gets rejected.
293*6777b538SAndroid Build Coastguard Worker ASSERT_FALSE(GetAuthMsgResult(client, writer));
294*6777b538SAndroid Build Coastguard Worker }
295*6777b538SAndroid Build Coastguard Worker
TEST(NtlmClientTest,Type3UnicodeWithSessionSecuritySpecTest)296*6777b538SAndroid Build Coastguard Worker TEST(NtlmClientTest, Type3UnicodeWithSessionSecuritySpecTest) {
297*6777b538SAndroid Build Coastguard Worker NtlmClient client(NtlmFeatures(false));
298*6777b538SAndroid Build Coastguard Worker
299*6777b538SAndroid Build Coastguard Worker std::vector<uint8_t> result = GenerateAuthMsg(client, test::kChallengeMsgV1);
300*6777b538SAndroid Build Coastguard Worker
301*6777b538SAndroid Build Coastguard Worker ASSERT_FALSE(result.empty());
302*6777b538SAndroid Build Coastguard Worker ASSERT_EQ(std::size(test::kExpectedAuthenticateMsgSpecResponseV1),
303*6777b538SAndroid Build Coastguard Worker result.size());
304*6777b538SAndroid Build Coastguard Worker ASSERT_EQ(0, memcmp(test::kExpectedAuthenticateMsgSpecResponseV1,
305*6777b538SAndroid Build Coastguard Worker result.data(), result.size()));
306*6777b538SAndroid Build Coastguard Worker }
307*6777b538SAndroid Build Coastguard Worker
TEST(NtlmClientTest,Type3WithoutUnicode)308*6777b538SAndroid Build Coastguard Worker TEST(NtlmClientTest, Type3WithoutUnicode) {
309*6777b538SAndroid Build Coastguard Worker NtlmClient client(NtlmFeatures(false));
310*6777b538SAndroid Build Coastguard Worker
311*6777b538SAndroid Build Coastguard Worker std::vector<uint8_t> result = GenerateAuthMsg(
312*6777b538SAndroid Build Coastguard Worker client, base::make_span(test::kMinChallengeMessageNoUnicode)
313*6777b538SAndroid Build Coastguard Worker .subspan<0, kMinChallengeHeaderLen>());
314*6777b538SAndroid Build Coastguard Worker ASSERT_FALSE(result.empty());
315*6777b538SAndroid Build Coastguard Worker
316*6777b538SAndroid Build Coastguard Worker NtlmBufferReader reader(result);
317*6777b538SAndroid Build Coastguard Worker ASSERT_TRUE(reader.MatchMessageHeader(MessageType::kAuthenticate));
318*6777b538SAndroid Build Coastguard Worker
319*6777b538SAndroid Build Coastguard Worker // Read the LM and NTLM Response Payloads.
320*6777b538SAndroid Build Coastguard Worker uint8_t actual_lm_response[kResponseLenV1];
321*6777b538SAndroid Build Coastguard Worker uint8_t actual_ntlm_response[kResponseLenV1];
322*6777b538SAndroid Build Coastguard Worker
323*6777b538SAndroid Build Coastguard Worker ASSERT_TRUE(ReadBytesPayload(&reader, actual_lm_response));
324*6777b538SAndroid Build Coastguard Worker ASSERT_TRUE(ReadBytesPayload(&reader, actual_ntlm_response));
325*6777b538SAndroid Build Coastguard Worker
326*6777b538SAndroid Build Coastguard Worker ASSERT_EQ(0, memcmp(test::kExpectedLmResponseWithV1SS, actual_lm_response,
327*6777b538SAndroid Build Coastguard Worker kResponseLenV1));
328*6777b538SAndroid Build Coastguard Worker ASSERT_EQ(0, memcmp(test::kExpectedNtlmResponseWithV1SS, actual_ntlm_response,
329*6777b538SAndroid Build Coastguard Worker kResponseLenV1));
330*6777b538SAndroid Build Coastguard Worker
331*6777b538SAndroid Build Coastguard Worker std::string domain;
332*6777b538SAndroid Build Coastguard Worker std::string username;
333*6777b538SAndroid Build Coastguard Worker std::string hostname;
334*6777b538SAndroid Build Coastguard Worker ASSERT_TRUE(ReadStringPayload(&reader, &domain));
335*6777b538SAndroid Build Coastguard Worker ASSERT_EQ(test::kNtlmDomainAscii, domain);
336*6777b538SAndroid Build Coastguard Worker ASSERT_TRUE(ReadStringPayload(&reader, &username));
337*6777b538SAndroid Build Coastguard Worker ASSERT_EQ(test::kUserAscii, username);
338*6777b538SAndroid Build Coastguard Worker ASSERT_TRUE(ReadStringPayload(&reader, &hostname));
339*6777b538SAndroid Build Coastguard Worker ASSERT_EQ(test::kHostnameAscii, hostname);
340*6777b538SAndroid Build Coastguard Worker
341*6777b538SAndroid Build Coastguard Worker // The session key is not used in HTTP. Since NTLMSSP_NEGOTIATE_KEY_EXCH
342*6777b538SAndroid Build Coastguard Worker // was not sent this is empty.
343*6777b538SAndroid Build Coastguard Worker ASSERT_TRUE(reader.MatchEmptySecurityBuffer());
344*6777b538SAndroid Build Coastguard Worker
345*6777b538SAndroid Build Coastguard Worker // Verify the unicode flag is not set and OEM flag is.
346*6777b538SAndroid Build Coastguard Worker NegotiateFlags flags;
347*6777b538SAndroid Build Coastguard Worker ASSERT_TRUE(reader.ReadFlags(&flags));
348*6777b538SAndroid Build Coastguard Worker ASSERT_EQ(NegotiateFlags::kNone, flags & NegotiateFlags::kUnicode);
349*6777b538SAndroid Build Coastguard Worker ASSERT_EQ(NegotiateFlags::kOem, flags & NegotiateFlags::kOem);
350*6777b538SAndroid Build Coastguard Worker }
351*6777b538SAndroid Build Coastguard Worker
TEST(NtlmClientTest,ClientDoesNotDowngradeSessionSecurity)352*6777b538SAndroid Build Coastguard Worker TEST(NtlmClientTest, ClientDoesNotDowngradeSessionSecurity) {
353*6777b538SAndroid Build Coastguard Worker NtlmClient client(NtlmFeatures(false));
354*6777b538SAndroid Build Coastguard Worker
355*6777b538SAndroid Build Coastguard Worker std::vector<uint8_t> result =
356*6777b538SAndroid Build Coastguard Worker GenerateAuthMsg(client, base::make_span(test::kMinChallengeMessageNoSS)
357*6777b538SAndroid Build Coastguard Worker .subspan<0, kMinChallengeHeaderLen>());
358*6777b538SAndroid Build Coastguard Worker ASSERT_FALSE(result.empty());
359*6777b538SAndroid Build Coastguard Worker
360*6777b538SAndroid Build Coastguard Worker NtlmBufferReader reader(result);
361*6777b538SAndroid Build Coastguard Worker ASSERT_TRUE(reader.MatchMessageHeader(MessageType::kAuthenticate));
362*6777b538SAndroid Build Coastguard Worker
363*6777b538SAndroid Build Coastguard Worker // Read the LM and NTLM Response Payloads.
364*6777b538SAndroid Build Coastguard Worker uint8_t actual_lm_response[kResponseLenV1];
365*6777b538SAndroid Build Coastguard Worker uint8_t actual_ntlm_response[kResponseLenV1];
366*6777b538SAndroid Build Coastguard Worker
367*6777b538SAndroid Build Coastguard Worker ASSERT_TRUE(ReadBytesPayload(&reader, actual_lm_response));
368*6777b538SAndroid Build Coastguard Worker ASSERT_TRUE(ReadBytesPayload(&reader, actual_ntlm_response));
369*6777b538SAndroid Build Coastguard Worker
370*6777b538SAndroid Build Coastguard Worker // The important part of this test is that even though the
371*6777b538SAndroid Build Coastguard Worker // server told the client to drop session security. The client
372*6777b538SAndroid Build Coastguard Worker // DID NOT drop it.
373*6777b538SAndroid Build Coastguard Worker ASSERT_EQ(0, memcmp(test::kExpectedLmResponseWithV1SS, actual_lm_response,
374*6777b538SAndroid Build Coastguard Worker kResponseLenV1));
375*6777b538SAndroid Build Coastguard Worker ASSERT_EQ(0, memcmp(test::kExpectedNtlmResponseWithV1SS, actual_ntlm_response,
376*6777b538SAndroid Build Coastguard Worker kResponseLenV1));
377*6777b538SAndroid Build Coastguard Worker
378*6777b538SAndroid Build Coastguard Worker std::u16string domain;
379*6777b538SAndroid Build Coastguard Worker std::u16string username;
380*6777b538SAndroid Build Coastguard Worker std::u16string hostname;
381*6777b538SAndroid Build Coastguard Worker ASSERT_TRUE(ReadString16Payload(&reader, &domain));
382*6777b538SAndroid Build Coastguard Worker ASSERT_EQ(test::kNtlmDomain, domain);
383*6777b538SAndroid Build Coastguard Worker ASSERT_TRUE(ReadString16Payload(&reader, &username));
384*6777b538SAndroid Build Coastguard Worker ASSERT_EQ(test::kUser, username);
385*6777b538SAndroid Build Coastguard Worker ASSERT_TRUE(ReadString16Payload(&reader, &hostname));
386*6777b538SAndroid Build Coastguard Worker ASSERT_EQ(test::kHostname, hostname);
387*6777b538SAndroid Build Coastguard Worker
388*6777b538SAndroid Build Coastguard Worker // The session key is not used in HTTP. Since NTLMSSP_NEGOTIATE_KEY_EXCH
389*6777b538SAndroid Build Coastguard Worker // was not sent this is empty.
390*6777b538SAndroid Build Coastguard Worker ASSERT_TRUE(reader.MatchEmptySecurityBuffer());
391*6777b538SAndroid Build Coastguard Worker
392*6777b538SAndroid Build Coastguard Worker // Verify the unicode and session security flag is set.
393*6777b538SAndroid Build Coastguard Worker NegotiateFlags flags;
394*6777b538SAndroid Build Coastguard Worker ASSERT_TRUE(reader.ReadFlags(&flags));
395*6777b538SAndroid Build Coastguard Worker ASSERT_EQ(NegotiateFlags::kUnicode, flags & NegotiateFlags::kUnicode);
396*6777b538SAndroid Build Coastguard Worker ASSERT_EQ(NegotiateFlags::kExtendedSessionSecurity,
397*6777b538SAndroid Build Coastguard Worker flags & NegotiateFlags::kExtendedSessionSecurity);
398*6777b538SAndroid Build Coastguard Worker }
399*6777b538SAndroid Build Coastguard Worker
400*6777b538SAndroid Build Coastguard Worker // ------------------------------------------------
401*6777b538SAndroid Build Coastguard Worker // NTLM V2 specific tests.
402*6777b538SAndroid Build Coastguard Worker // ------------------------------------------------
403*6777b538SAndroid Build Coastguard Worker
TEST(NtlmClientTest,SimpleConstructionV2)404*6777b538SAndroid Build Coastguard Worker TEST(NtlmClientTest, SimpleConstructionV2) {
405*6777b538SAndroid Build Coastguard Worker NtlmClient client(NtlmFeatures(true));
406*6777b538SAndroid Build Coastguard Worker
407*6777b538SAndroid Build Coastguard Worker ASSERT_TRUE(client.IsNtlmV2());
408*6777b538SAndroid Build Coastguard Worker ASSERT_TRUE(client.IsEpaEnabled());
409*6777b538SAndroid Build Coastguard Worker ASSERT_TRUE(client.IsMicEnabled());
410*6777b538SAndroid Build Coastguard Worker }
411*6777b538SAndroid Build Coastguard Worker
TEST(NtlmClientTest,VerifyNegotiateMessageV2)412*6777b538SAndroid Build Coastguard Worker TEST(NtlmClientTest, VerifyNegotiateMessageV2) {
413*6777b538SAndroid Build Coastguard Worker NtlmClient client(NtlmFeatures(true));
414*6777b538SAndroid Build Coastguard Worker
415*6777b538SAndroid Build Coastguard Worker std::vector<uint8_t> result = client.GetNegotiateMessage();
416*6777b538SAndroid Build Coastguard Worker ASSERT_FALSE(result.empty());
417*6777b538SAndroid Build Coastguard Worker ASSERT_EQ(std::size(test::kExpectedNegotiateMsg), result.size());
418*6777b538SAndroid Build Coastguard Worker ASSERT_EQ(0,
419*6777b538SAndroid Build Coastguard Worker memcmp(test::kExpectedNegotiateMsg, result.data(), result.size()));
420*6777b538SAndroid Build Coastguard Worker }
421*6777b538SAndroid Build Coastguard Worker
TEST(NtlmClientTest,VerifyAuthenticateMessageV2)422*6777b538SAndroid Build Coastguard Worker TEST(NtlmClientTest, VerifyAuthenticateMessageV2) {
423*6777b538SAndroid Build Coastguard Worker // Generate the auth message from the client based on the test challenge
424*6777b538SAndroid Build Coastguard Worker // message.
425*6777b538SAndroid Build Coastguard Worker NtlmClient client(NtlmFeatures(true));
426*6777b538SAndroid Build Coastguard Worker std::vector<uint8_t> result =
427*6777b538SAndroid Build Coastguard Worker GenerateAuthMsg(client, test::kChallengeMsgFromSpecV2);
428*6777b538SAndroid Build Coastguard Worker ASSERT_FALSE(result.empty());
429*6777b538SAndroid Build Coastguard Worker ASSERT_EQ(std::size(test::kExpectedAuthenticateMsgSpecResponseV2),
430*6777b538SAndroid Build Coastguard Worker result.size());
431*6777b538SAndroid Build Coastguard Worker ASSERT_EQ(0, memcmp(test::kExpectedAuthenticateMsgSpecResponseV2,
432*6777b538SAndroid Build Coastguard Worker result.data(), result.size()));
433*6777b538SAndroid Build Coastguard Worker }
434*6777b538SAndroid Build Coastguard Worker
TEST(NtlmClientTest,VerifyAuthenticateMessageInResponseToChallengeWithoutTargetInfoV2)435*6777b538SAndroid Build Coastguard Worker TEST(NtlmClientTest,
436*6777b538SAndroid Build Coastguard Worker VerifyAuthenticateMessageInResponseToChallengeWithoutTargetInfoV2) {
437*6777b538SAndroid Build Coastguard Worker // Test how the V2 client responds when the server sends a challenge that
438*6777b538SAndroid Build Coastguard Worker // does not contain target info. eg. Windows 2003 and earlier do not send
439*6777b538SAndroid Build Coastguard Worker // this. See [MS-NLMP] Appendix B Item 8. These older Windows servers
440*6777b538SAndroid Build Coastguard Worker // support NTLMv2 but don't send target info. Other implementations may
441*6777b538SAndroid Build Coastguard Worker // also be affected.
442*6777b538SAndroid Build Coastguard Worker NtlmClient client(NtlmFeatures(true));
443*6777b538SAndroid Build Coastguard Worker std::vector<uint8_t> result = GenerateAuthMsg(client, test::kChallengeMsgV1);
444*6777b538SAndroid Build Coastguard Worker ASSERT_FALSE(result.empty());
445*6777b538SAndroid Build Coastguard Worker
446*6777b538SAndroid Build Coastguard Worker ASSERT_EQ(std::size(test::kExpectedAuthenticateMsgToOldV1ChallegeV2),
447*6777b538SAndroid Build Coastguard Worker result.size());
448*6777b538SAndroid Build Coastguard Worker ASSERT_EQ(0, memcmp(test::kExpectedAuthenticateMsgToOldV1ChallegeV2,
449*6777b538SAndroid Build Coastguard Worker result.data(), result.size()));
450*6777b538SAndroid Build Coastguard Worker }
451*6777b538SAndroid Build Coastguard Worker
452*6777b538SAndroid Build Coastguard Worker // When the challenge message's target info is maximum size, adding new AV_PAIRs
453*6777b538SAndroid Build Coastguard Worker // to the response will overflow SecurityBuffer. Test that we handle this.
TEST(NtlmClientTest,AvPairsOverflow)454*6777b538SAndroid Build Coastguard Worker TEST(NtlmClientTest, AvPairsOverflow) {
455*6777b538SAndroid Build Coastguard Worker {
456*6777b538SAndroid Build Coastguard Worker NtlmClient client(NtlmFeatures(/*enable_NTLMv2=*/true));
457*6777b538SAndroid Build Coastguard Worker std::vector<uint8_t> short_challenge;
458*6777b538SAndroid Build Coastguard Worker ASSERT_NO_FATAL_FAILURE(MakeV2ChallengeMessage(0xfff, &short_challenge));
459*6777b538SAndroid Build Coastguard Worker EXPECT_FALSE(GenerateAuthMsg(client, short_challenge).empty());
460*6777b538SAndroid Build Coastguard Worker }
461*6777b538SAndroid Build Coastguard Worker {
462*6777b538SAndroid Build Coastguard Worker NtlmClient client(NtlmFeatures(/*enable_NTLMv2=*/true));
463*6777b538SAndroid Build Coastguard Worker std::vector<uint8_t> long_challenge;
464*6777b538SAndroid Build Coastguard Worker ASSERT_NO_FATAL_FAILURE(MakeV2ChallengeMessage(0xffff, &long_challenge));
465*6777b538SAndroid Build Coastguard Worker EXPECT_TRUE(GenerateAuthMsg(client, long_challenge).empty());
466*6777b538SAndroid Build Coastguard Worker }
467*6777b538SAndroid Build Coastguard Worker }
468*6777b538SAndroid Build Coastguard Worker
469*6777b538SAndroid Build Coastguard Worker } // namespace net::ntlm
470