1 //
2 // NTLMCredentialsTest.cpp
3 //
4 // Copyright (c) 2014, Applied Informatics Software Engineering GmbH.
5 // and Contributors.
6 //
7 // SPDX-License-Identifier:	BSL-1.0
8 //
9 
10 
11 #include "NTLMCredentialsTest.h"
12 #include "CppUnit/TestCaller.h"
13 #include "CppUnit/TestSuite.h"
14 #include "Poco/Net/NTLMCredentials.h"
15 #include "Poco/DigestEngine.h"
16 
17 
18 using Poco::Net::NTLMCredentials;
19 
20 
NTLMCredentialsTest(const std::string & name)21 NTLMCredentialsTest::NTLMCredentialsTest(const std::string& name): CppUnit::TestCase(name)
22 {
23 }
24 
25 
~NTLMCredentialsTest()26 NTLMCredentialsTest::~NTLMCredentialsTest()
27 {
28 }
29 
30 
testNonce()31 void NTLMCredentialsTest::testNonce()
32 {
33 	std::vector<unsigned char> nonce1 = NTLMCredentials::createNonce();
34 	assertTrue (nonce1.size() == 8);
35 
36 	std::vector<unsigned char> nonce2 = NTLMCredentials::createNonce();
37 	assertTrue (nonce2.size() == 8);
38 
39 	assertTrue (nonce1 != nonce2);
40 }
41 
42 
testPasswordHash()43 void NTLMCredentialsTest::testPasswordHash()
44 {
45 	std::vector<unsigned char> passHash = NTLMCredentials::createPasswordHash("SecREt01");
46 	std::string passHashHex = Poco::DigestEngine::digestToHex(passHash);
47 	assertTrue (passHashHex == "cd06ca7c7e10c99b1d33b7485a2ed808");
48 }
49 
50 
testNTLMv2Hash()51 void NTLMCredentialsTest::testNTLMv2Hash()
52 {
53 	std::vector<unsigned char> ntlm2Hash = NTLMCredentials::createNTLMv2Hash("user", "DOMAIN", "SecREt01");
54 	std::string ntlm2HashHex = Poco::DigestEngine::digestToHex(ntlm2Hash);
55 	assertTrue (ntlm2HashHex == "04b8e0ba74289cc540826bab1dee63ae");
56 }
57 
58 
testLMv2Response()59 void NTLMCredentialsTest::testLMv2Response()
60 {
61 	static const unsigned char CHALLENGE[] = {0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef};
62 	static const unsigned char NONCE[] = {0xff, 0xff, 0xff, 0x00, 0x11, 0x22, 0x33, 0x44};
63 
64 	std::vector<unsigned char> challenge(CHALLENGE, CHALLENGE + 8);
65 	std::vector<unsigned char> nonce(NONCE, NONCE + 8);
66 
67 	std::vector<unsigned char> ntlm2Hash = NTLMCredentials::createNTLMv2Hash("user", "DOMAIN", "SecREt01");
68 	std::vector<unsigned char> lm2Response = NTLMCredentials::createLMv2Response(ntlm2Hash, challenge, nonce);
69 
70 	std::string lm2ResponseHex = Poco::DigestEngine::digestToHex(lm2Response);
71 	assertTrue (lm2ResponseHex == "d6e6152ea25d03b7c6ba6629c2d6aaf0ffffff0011223344");
72 }
73 
74 
testNTLMv2Response()75 void NTLMCredentialsTest::testNTLMv2Response()
76 {
77 	static const unsigned char CHALLENGE[] = {0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef};
78 	static const unsigned char NONCE[] = {0xff, 0xff, 0xff, 0x00, 0x11, 0x22, 0x33, 0x44};
79 	static const unsigned char TARGET_INFO[] = {
80 		0x02, 0x00, 0x0c, 0x00, 0x44, 0x00, 0x4f, 0x00,
81 		0x4d, 0x00, 0x41, 0x00, 0x49, 0x00, 0x4e, 0x00,
82 		0x01, 0x00, 0x0c, 0x00, 0x53, 0x00, 0x45, 0x00,
83 		0x52, 0x00, 0x56, 0x00, 0x45, 0x00, 0x52, 0x00,
84 		0x04, 0x00, 0x14, 0x00, 0x64, 0x00, 0x6f, 0x00,
85 		0x6d, 0x00, 0x61, 0x00, 0x69, 0x00, 0x6e, 0x00,
86 		0x2e, 0x00, 0x63, 0x00, 0x6f, 0x00, 0x6d, 0x00,
87 		0x03, 0x00, 0x22, 0x00, 0x73, 0x00, 0x65, 0x00,
88 		0x72, 0x00, 0x76, 0x00, 0x65, 0x00, 0x72, 0x00,
89 		0x2e, 0x00, 0x64, 0x00, 0x6f, 0x00, 0x6d, 0x00,
90 		0x61, 0x00, 0x69, 0x00, 0x6e, 0x00, 0x2e, 0x00,
91 		0x63, 0x00, 0x6f, 0x00, 0x6d, 0x00, 0x00, 0x00,
92 		0x00, 0x00
93 	};
94 
95 	std::vector<unsigned char> challenge(CHALLENGE, CHALLENGE + 8);
96 	std::vector<unsigned char> nonce(NONCE, NONCE + 8);
97 	std::vector<unsigned char> targetInfo(TARGET_INFO, TARGET_INFO + sizeof(TARGET_INFO));
98 
99 	std::vector<unsigned char> ntlm2Hash = NTLMCredentials::createNTLMv2Hash("user", "DOMAIN", "SecREt01");
100 	Poco::UInt64 timestamp = Poco::UInt64(12700317600)*10000000;
101 
102 	std::vector<unsigned char> ntlm2Response = NTLMCredentials::createNTLMv2Response(
103 		ntlm2Hash,
104 		challenge,
105 		nonce,
106 		targetInfo,
107 		timestamp);
108 
109 	std::string ntlm2ResponseHex = Poco::DigestEngine::digestToHex(ntlm2Response);
110 
111 	assertTrue (ntlm2ResponseHex ==
112 		"cbabbca713eb795d04c97abc01ee4983"
113 		"01010000000000000090d336b734c301"
114 		"ffffff00112233440000000002000c00"
115 		"44004f004d00410049004e0001000c00"
116 		"53004500520056004500520004001400"
117 		"64006f006d00610069006e002e006300"
118 		"6f006d00030022007300650072007600"
119 		"650072002e0064006f006d0061006900"
120 		"6e002e0063006f006d00000000000000"
121 		"0000"
122 	);
123 }
124 
125 
testFormatNegotiateMessage()126 void NTLMCredentialsTest::testFormatNegotiateMessage()
127 {
128 	NTLMCredentials::NegotiateMessage msg1;
129 	msg1.flags = 0;
130 
131 	std::vector<unsigned char> msg1Buffer = NTLMCredentials::formatNegotiateMessage(msg1);
132 	std::string msg1BufferHex = Poco::DigestEngine::digestToHex(msg1Buffer);
133 
134 	assertTrue (msg1BufferHex == "4e544c4d53535000010000000582080000000000180000000000000018000000");
135 
136 	msg1.domain = "DOMAIN";
137 	msg1Buffer = NTLMCredentials::formatNegotiateMessage(msg1);
138 	msg1BufferHex = Poco::DigestEngine::digestToHex(msg1Buffer);
139 
140 	assertTrue (msg1BufferHex == "4e544c4d5353500001000000059208000c000c0018000000000000002400000044004f004d00410049004e00");
141 
142 	msg1.workstation = "WORKST";
143 	msg1Buffer = NTLMCredentials::formatNegotiateMessage(msg1);
144 	msg1BufferHex = Poco::DigestEngine::digestToHex(msg1Buffer);
145 
146 	assertTrue (msg1BufferHex == "4e544c4d535350000100000005b208000c000c00180000000c000c002400000044004f004d00410049004e0057004f0052004b0053005400");
147 }
148 
149 
testParseChallengeMessage()150 void  NTLMCredentialsTest::testParseChallengeMessage()
151 {
152 	const unsigned char BUFFER[] = {
153 		0x4e, 0x54, 0x4c, 0x4d, 0x53, 0x53, 0x50, 0x00,
154 		0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
155 		0x00, 0x00, 0x00, 0x00, 0x02, 0x02, 0x00, 0x00,
156 		0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef
157 	};
158 
159 	NTLMCredentials::ChallengeMessage msg2;
160 	bool ok = NTLMCredentials::parseChallengeMessage(BUFFER, sizeof(BUFFER), msg2);
161 
162 	assertTrue (ok);
163 	assertTrue (msg2.flags == (NTLMCredentials::NTLM_FLAG_NEGOTIATE_OEM | NTLMCredentials::NTLM_FLAG_NEGOTIATE_NTLM));
164 	assertTrue (msg2.challenge.size() == 8);
165 	assertTrue (msg2.targetInfo.empty());
166 
167 	assertTrue (msg2.challenge[0] == 0x01);
168 	assertTrue (msg2.challenge[1] == 0x23);
169 	assertTrue (msg2.challenge[7] == 0xef);
170 }
171 
172 
testParseChallengeMessageWithTargetInfo()173 void  NTLMCredentialsTest::testParseChallengeMessageWithTargetInfo()
174 {
175 	const unsigned char BUFFER[] = {
176 		0x4e, 0x54, 0x4c, 0x4d, 0x53, 0x53, 0x50, 0x00,
177 		0x02, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x0c, 0x00,
178 		0x30, 0x00, 0x00, 0x00, 0x01, 0x02, 0x81, 0x00,
179 		0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef,
180 		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
181 		0x62, 0x00, 0x62, 0x00, 0x3c, 0x00, 0x00, 0x00,
182 		0x44, 0x00, 0x4f, 0x00, 0x4d, 0x00, 0x41, 0x00,
183 		0x49, 0x00, 0x4e, 0x00, 0x02, 0x00, 0x0c, 0x00,
184 		0x44, 0x00, 0x4f, 0x00, 0x4d, 0x00, 0x41, 0x00,
185 		0x49, 0x00, 0x4e, 0x00, 0x01, 0x00, 0x0c, 0x00,
186 		0x53, 0x00, 0x45, 0x00, 0x52, 0x00, 0x56, 0x00,
187 		0x45, 0x00, 0x52, 0x00, 0x04, 0x00, 0x14, 0x00,
188 		0x64, 0x00, 0x6f, 0x00, 0x6d, 0x00, 0x61, 0x00,
189 		0x69, 0x00, 0x6e, 0x00, 0x2e, 0x00, 0x63, 0x00,
190 		0x6f, 0x00, 0x6d, 0x00, 0x03, 0x00, 0x22, 0x00,
191 		0x73, 0x00, 0x65, 0x00, 0x72, 0x00, 0x76, 0x00,
192 		0x65, 0x00, 0x72, 0x00, 0x2e, 0x00, 0x64, 0x00,
193 		0x6f, 0x00, 0x6d, 0x00, 0x61, 0x00, 0x69, 0x00,
194 		0x6e, 0x00, 0x2e, 0x00, 0x63, 0x00, 0x6f, 0x00,
195 		0x6d, 0x00, 0x00, 0x00, 0x00, 0x00
196 	};
197 
198 	NTLMCredentials::ChallengeMessage msg2;
199 	bool ok = NTLMCredentials::parseChallengeMessage(BUFFER, sizeof(BUFFER), msg2);
200 
201 	assertTrue (ok);
202 	assertTrue (msg2.flags == (NTLMCredentials::NTLM_FLAG_NEGOTIATE_UNICODE | NTLMCredentials::NTLM_FLAG_NEGOTIATE_NTLM | NTLMCredentials::NTLM_FLAG_NEGOTIATE_TARGET | NTLMCredentials::NTLM_FLAG_TARGET_DOMAIN));
203 	assertTrue (msg2.challenge.size() == 8);
204 	assertTrue (msg2.target == "DOMAIN");
205 
206 	assertTrue (msg2.targetInfo.size() == 98);
207 
208 	assertTrue (msg2.challenge[0] == 0x01);
209 	assertTrue (msg2.challenge[1] == 0x23);
210 	assertTrue (msg2.challenge[7] == 0xef);
211 
212 	assertTrue (msg2.targetInfo[0] == 0x02);
213 	assertTrue (msg2.targetInfo[1] == 0x00);
214 	assertTrue (msg2.targetInfo[97] == 0x00);
215 }
216 
217 
testFormatAuthenticateMessage()218 void NTLMCredentialsTest::testFormatAuthenticateMessage()
219 {
220 	const unsigned char LM[] = {
221 		0xc3, 0x37, 0xcd, 0x5c, 0xbd, 0x44, 0xfc, 0x97,
222 		0x82, 0xa6, 0x67, 0xaf, 0x6d, 0x42, 0x7c, 0x6d,
223 		0xe6, 0x7c, 0x20, 0xc2, 0xd3, 0xe7, 0x7c, 0x56
224 	};
225 	const unsigned char NTLM[] = {
226 		0x25, 0xa9, 0x8c, 0x1c, 0x31, 0xe8, 0x18, 0x47,
227 		0x46, 0x6b, 0x29, 0xb2, 0xdf, 0x46, 0x80, 0xf3,
228 		0x99, 0x58, 0xfb, 0x8c, 0x21, 0x3a, 0x9c, 0xc6
229 	};
230 
231 	NTLMCredentials::AuthenticateMessage msg3;
232 	msg3.flags = NTLMCredentials::NTLM_FLAG_NEGOTIATE_UNICODE | NTLMCredentials::NTLM_FLAG_NEGOTIATE_NTLM;
233 	msg3.target = "DOMAIN";
234 	msg3.username = "user";
235 	msg3.workstation = "WORKSTATION";
236 	msg3.lmResponse.assign(LM, LM + sizeof(LM));
237 	msg3.ntlmResponse.assign(NTLM, NTLM + sizeof(NTLM));
238 
239 	std::vector<unsigned char> msg3Buffer = NTLMCredentials::formatAuthenticateMessage(msg3);
240 	std::string msg3BufferHex = Poco::DigestEngine::digestToHex(msg3Buffer);
241 
242 	assertTrue (msg3BufferHex ==
243 		"4e544c4d5353500003000000180018004000000018001800"
244 		"580000000c000c0070000000080008007c00000016001600"
245 		"84000000000000009a00000001020000c337cd5cbd44fc97"
246 		"82a667af6d427c6de67c20c2d3e77c5625a98c1c31e81847"
247 		"466b29b2df4680f39958fb8c213a9cc644004f004d004100"
248 		"49004e00750073006500720057004f0052004b0053005400"
249 		"4100540049004f004e00"
250 	);
251 }
252 
253 
setUp()254 void NTLMCredentialsTest::setUp()
255 {
256 }
257 
258 
tearDown()259 void NTLMCredentialsTest::tearDown()
260 {
261 }
262 
263 
suite()264 CppUnit::Test* NTLMCredentialsTest::suite()
265 {
266 	CppUnit::TestSuite* pSuite = new CppUnit::TestSuite("NTLMCredentialsTest");
267 
268 	CppUnit_addTest(pSuite, NTLMCredentialsTest, testNonce);
269 	CppUnit_addTest(pSuite, NTLMCredentialsTest, testPasswordHash);
270 	CppUnit_addTest(pSuite, NTLMCredentialsTest, testNTLMv2Hash);
271 	CppUnit_addTest(pSuite, NTLMCredentialsTest, testLMv2Response);
272 	CppUnit_addTest(pSuite, NTLMCredentialsTest, testNTLMv2Response);
273 	CppUnit_addTest(pSuite, NTLMCredentialsTest, testFormatNegotiateMessage);
274 	CppUnit_addTest(pSuite, NTLMCredentialsTest, testParseChallengeMessage);
275 	CppUnit_addTest(pSuite, NTLMCredentialsTest, testParseChallengeMessageWithTargetInfo);
276 	CppUnit_addTest(pSuite, NTLMCredentialsTest, testFormatAuthenticateMessage);
277 
278 	return pSuite;
279 }
280