FreeRDP
Loading...
Searching...
No Matches
utils/test/TestNTLM.c
1#include <winpr/wtypes.h>
2#include <winpr/ntlm.h>
3#include <winpr/string.h>
4#include <winpr/print.h>
5
6typedef struct
7{
8 const char* password;
9 const BYTE expected[16];
10 const BOOL result;
11 const BOOL shouldMatch;
12} test_case_ntowf1_t;
13
14typedef struct
15{
16 const char* password;
17 const char* user;
18 const char* domain;
19 const BYTE expected[16];
20 const BOOL result;
21 const BOOL shouldMatch;
22} test_case_ntowf2_t;
23
24typedef struct
25{
26 const char* user;
27 const char* domain;
28 const BYTE passwordhash[16];
29 const BYTE expected[16];
30 const BOOL result;
31 const BOOL shouldMatch;
32} test_case_from_hash_t;
33
34static const test_case_ntowf1_t ntofw1tests[] = {
35 { "foo1", { 0 }, TRUE, FALSE },
36 { "foo1",
37 { 0x05, 0x80, 0x83, 0x4a, 0x04, 0x89, 0xed, 0x37, 0x49, 0x6b, 0x7b, 0xfa, 0xe9, 0x90, 0x9b,
38 0x70 },
39 TRUE,
40 TRUE },
41 { "bar2",
42 { 0xee, 0xd4, 0xd3, 0xb5, 0x87, 0x11, 0x0d, 0x5c, 0x08, 0x51, 0x8c, 0xea, 0xa5, 0x69, 0x1e,
43 0xd2 },
44 TRUE,
45 TRUE },
46 { nullptr, { 0 }, FALSE, FALSE }
47};
48
49static const test_case_ntowf2_t ntofw2tests[] = {
50 { nullptr, nullptr, nullptr, { 0 }, FALSE, FALSE },
51 { nullptr, nullptr, "domain1", { 0 }, FALSE, FALSE },
52 { nullptr, "user1", "domain1", { 0 }, FALSE, FALSE },
53 { "pwd1", "user1", "domain1", { 0 }, TRUE, FALSE },
54 { "pwd1",
55 "user1",
56 "domain1",
57 { 0x9b, 0xee, 0x1e, 0x41, 0xa6, 0xd3, 0xf1, 0xf2, 0xc4, 0x00, 0xb8, 0xf9, 0x44, 0xc5, 0x44,
58 0x92 },
59 TRUE,
60 TRUE },
61 { "pwd2",
62 "user2",
63 "domain1",
64 { 0xa5, 0x82, 0xcd, 0x70, 0xce, 0xb0, 0xed, 0x99, 0xe6, 0xf5, 0x45, 0x3e, 0x96, 0x93, 0x5d,
65 0xa5 },
66 TRUE,
67 TRUE },
68 { "pwd3",
69 "user2",
70 "domain2",
71 { 0xf9, 0x4d, 0x1e, 0x10, 0x31, 0xa1, 0x96, 0x0d, 0xa9, 0xaa, 0x64, 0xb3, 0x83, 0x1a, 0x79,
72 0xf7 },
73 TRUE,
74 TRUE }
75};
76
77#define hashV1_test1 \
78 { \
79 0x47, 0x62, 0x01, 0xda, 0x81, 0xd4, 0x48, 0xac, \
80 0x69, 0x02, 0x72, 0x46, 0x3b, 0x75, 0xb3, 0xac \
81 }
82#define hashV1_test2 \
83 { \
84 0x76, 0xc2, 0x51, 0x01, 0x35, 0x27, 0x08, 0x8b, \
85 0xc6, 0x4c, 0x1b, 0xd4, 0x2c, 0x78, 0x8b, 0xac \
86 }
87#define hashV1_test1_foobar1 \
88 { \
89 0x2f, 0xb7, 0x06, 0xe3, 0xf4, 0xf2, 0x74, 0xe7, \
90 0x62, 0xfc, 0x53, 0xcb, 0x57, 0x9a, 0x28, 0x3a \
91 }
92#define hashV1_test1_foobar1_domain1 \
93 { \
94 0xa2, 0xbc, 0x65, 0x8e, 0xda, 0xfc, 0xc2, 0xef, \
95 0xaa, 0x26, 0x41, 0x07, 0xb6, 0x9f, 0x94, 0x5c \
96 }
97#define hashV1_test1_foobar1_domain2 \
98 { \
99 0xcf, 0x76, 0xd4, 0xe0, 0xe7, 0x8d, 0xc7, 0xec, \
100 0x59, 0x48, 0x9f, 0x47, 0xde, 0x52, 0xbd, 0x5c \
101 }
102#define hashV1_test2_foobar1 \
103 { \
104 0x4e, 0xe8, 0xd8, 0xe1, 0xfd, 0x7a, 0x77, 0x2b, \
105 0xe7, 0x7c, 0x06, 0xe3, 0xca, 0x6e, 0x47, 0xb6 \
106 }
107#define hashV1_test2_foobar1_domain1 \
108 { \
109 0x40, 0x74, 0xd1, 0x98, 0x32, 0x38, 0xdb, 0x3f, \
110 0x2d, 0x18, 0x1c, 0xd5, 0x0f, 0xb0, 0x70, 0xd2 \
111 }
112#define hashV1_test2_foobar1_domain2 \
113 { \
114 0x2e, 0x63, 0x11, 0x29, 0x4f, 0x47, 0x3e, 0x87, \
115 0x72, 0x07, 0x36, 0x52, 0x20, 0xb3, 0xbe, 0x46 \
116 }
117
118static const test_case_from_hash_t ntofw2fromhashtests[] = {
119 { nullptr, nullptr, { 0 }, { 0 }, FALSE, FALSE },
120 { "foobar1", nullptr, hashV1_test1, { 0 }, TRUE, FALSE },
121 { "foobar1", nullptr, hashV1_test2, hashV1_test1_foobar1, TRUE, FALSE },
122 { "foobar1", nullptr, hashV1_test1, hashV1_test1_foobar1, TRUE, TRUE },
123 { "foobar2", nullptr, hashV1_test1, hashV1_test1_foobar1, TRUE, FALSE },
124 { "foobar1", "domain1", hashV1_test1, hashV1_test1_foobar1_domain1, TRUE, TRUE },
125 { "foobar1", "domain2", hashV1_test1, hashV1_test1_foobar1_domain1, TRUE, FALSE },
126 { "foobar1", "domain2", hashV1_test1, hashV1_test1_foobar1_domain2, TRUE, TRUE },
127 { "foobar1", nullptr, hashV1_test2, { 0 }, TRUE, FALSE },
128 { "foobar1", nullptr, hashV1_test1, hashV1_test2_foobar1, TRUE, FALSE },
129 { "foobar1", nullptr, hashV1_test2, hashV1_test2_foobar1, TRUE, TRUE },
130 { "foobar2", nullptr, hashV1_test2, hashV1_test2_foobar1, TRUE, FALSE },
131 { "foobar1", "domain1", hashV1_test2, hashV1_test2_foobar1_domain1, TRUE, TRUE },
132 { "foobar1", "domain2", hashV1_test2, hashV1_test2_foobar1_domain1, TRUE, FALSE },
133 { "foobar1", "domain2", hashV1_test2, hashV1_test2_foobar1_domain2, TRUE, TRUE }
134};
135
136static BOOL testNTOWF1(size_t x, const test_case_ntowf1_t* test)
137{
138 WINPR_ASSERT(test);
139
140 BYTE hashA[sizeof(test->expected)] = WINPR_C_ARRAY_INIT;
141 BYTE hashW[sizeof(test->expected)] = WINPR_C_ARRAY_INIT;
142 size_t pwdlen = 0;
143 if (test->password)
144 pwdlen = strlen(test->password);
145
146 const BOOL rcA = NTOWFv1A(test->password, pwdlen, hashA);
147
148 WCHAR* passwordW = nullptr;
149 size_t pwdwlen = 0;
150 if (pwdlen > 0)
151 passwordW = ConvertUtf8NToWCharAlloc(test->password, pwdlen, &pwdwlen);
152 const BOOL rcW = NTOWFv1W(passwordW, pwdwlen * sizeof(WCHAR), hashW);
153 free(passwordW);
154
155 winpr_HexDump("NTOWFv1A", WLOG_INFO, hashA, sizeof(hashA));
156 winpr_HexDump("expect", WLOG_INFO, test->expected, sizeof(test->expected));
157 WLog_INFO("result", "[%" PRIuz "] got %d, expected %d", x, rcA, test->result);
158
159 winpr_HexDump("NTOWFv1W", WLOG_INFO, hashW, sizeof(hashW));
160 winpr_HexDump("expect", WLOG_INFO, test->expected, sizeof(test->expected));
161 WLog_INFO("result", "[%" PRIuz "] got %d, expected %d", x, rcW, test->result);
162
163 if (rcA != test->result)
164 return FALSE;
165
166 if (memcmp(test->expected, hashA, sizeof(test->expected)) != 0)
167 {
168 if (test->shouldMatch)
169 return FALSE;
170 }
171
172 if (rcW != test->result)
173 return FALSE;
174
175 if (memcmp(test->expected, hashW, sizeof(test->expected)) != 0)
176 {
177 if (test->shouldMatch)
178 return FALSE;
179 }
180 return TRUE;
181}
182
183static BOOL testNTOWF2(size_t x, const test_case_ntowf2_t* test)
184{
185 WINPR_ASSERT(test);
186
187 BYTE hashA[sizeof(test->expected)] = WINPR_C_ARRAY_INIT;
188 BYTE hashW[sizeof(test->expected)] = WINPR_C_ARRAY_INIT;
189
190 size_t pwdlen = 0;
191 if (test->password)
192 pwdlen = strlen(test->password);
193
194 size_t userlen = 0;
195 if (test->user)
196 userlen = strlen(test->user);
197
198 size_t domainlen = 0;
199 if (test->domain)
200 domainlen = strlen(test->domain);
201
202 const BOOL rcA =
203 NTOWFv2A(test->password, pwdlen, test->user, userlen, test->domain, domainlen, hashA);
204
205 WCHAR* passwordW = nullptr;
206 size_t pwdwlen = 0;
207 if (pwdlen > 0)
208 passwordW = ConvertUtf8NToWCharAlloc(test->password, pwdlen, &pwdwlen);
209
210 WCHAR* userW = nullptr;
211 size_t userwlen = 0;
212 if (userlen > 0)
213 userW = ConvertUtf8NToWCharAlloc(test->user, userlen, &userwlen);
214
215 WCHAR* domainW = nullptr;
216 size_t domainwlen = 0;
217 if (domainlen > 0)
218 domainW = ConvertUtf8NToWCharAlloc(test->domain, domainlen, &domainwlen);
219
220 const BOOL rcW = NTOWFv2W(passwordW, pwdwlen * sizeof(WCHAR), userW, userwlen * sizeof(WCHAR),
221 domainW, domainlen * sizeof(WCHAR), hashW);
222 free(userW);
223 free(domainW);
224 free(passwordW);
225
226 winpr_HexDump("NTOWFv2A", WLOG_INFO, hashA, sizeof(hashA));
227 winpr_HexDump("expect", WLOG_INFO, test->expected, sizeof(test->expected));
228 WLog_INFO("result", "[%" PRIuz "] got %d, expected %d", x, rcA, test->result);
229
230 winpr_HexDump("NTOWFv2W", WLOG_INFO, hashW, sizeof(hashW));
231 winpr_HexDump("expect", WLOG_INFO, test->expected, sizeof(test->expected));
232 WLog_INFO("result", "[%" PRIuz "] got %d, expected %d", x, rcW, test->result);
233
234 if (rcA != test->result)
235 return FALSE;
236 if (memcmp(test->expected, hashA, sizeof(test->expected)) != 0)
237 {
238 if (test->shouldMatch)
239 return FALSE;
240 }
241
242 if (rcW != test->result)
243 return FALSE;
244 if (memcmp(test->expected, hashW, sizeof(test->expected)) != 0)
245 {
246 if (test->shouldMatch)
247 return FALSE;
248 }
249 return TRUE;
250}
251
252static BOOL testNTOWFv2FromHash(size_t x, const test_case_from_hash_t* test)
253{
254 WINPR_ASSERT(test);
255
256 BYTE hashA[sizeof(test->expected)] = WINPR_C_ARRAY_INIT;
257 BYTE hashW[sizeof(test->expected)] = WINPR_C_ARRAY_INIT;
258
259 size_t userlen = 0;
260 if (test->user)
261 userlen = strlen(test->user);
262
263 size_t domainlen = 0;
264 if (test->domain)
265 domainlen = strlen(test->domain);
266
267 const BOOL rcA =
268 NTOWFv2FromHashA(test->passwordhash, test->user, userlen, test->domain, domainlen, hashA);
269
270 WCHAR* userW = nullptr;
271 size_t userwlen = 0;
272 if (userlen > 0)
273 userW = ConvertUtf8NToWCharAlloc(test->user, userlen, &userwlen);
274
275 WCHAR* domainW = nullptr;
276 size_t domainwlen = 0;
277 if (domainlen > 0)
278 domainW = ConvertUtf8NToWCharAlloc(test->domain, domainlen, &domainwlen);
279
280 const BOOL rcW = NTOWFv2FromHashW(test->passwordhash, userW, userwlen * sizeof(WCHAR), domainW,
281 domainwlen * sizeof(WCHAR), hashW);
282
283 free(userW);
284 free(domainW);
285
286 winpr_HexDump("NTOWFv2A", WLOG_INFO, hashA, sizeof(hashA));
287 winpr_HexDump("expect", WLOG_INFO, test->expected, sizeof(test->expected));
288 WLog_INFO("result", "[%" PRIuz "] got %d, expected %d", x, rcA, test->result);
289
290 winpr_HexDump("NTOWFv2W", WLOG_INFO, hashW, sizeof(hashW));
291 winpr_HexDump("expect", WLOG_INFO, test->expected, sizeof(test->expected));
292 WLog_INFO("result", "[%" PRIuz "] got %d, expected %d", x, rcW, test->result);
293
294 if (rcA != test->result)
295 return FALSE;
296 if (memcmp(test->expected, hashA, sizeof(test->expected)) != 0)
297 {
298 if (test->shouldMatch)
299 return FALSE;
300 }
301
302 if (rcW != test->result)
303 return FALSE;
304 if (memcmp(test->expected, hashW, sizeof(test->expected)) != 0)
305 {
306 if (test->shouldMatch)
307 return FALSE;
308 }
309 return TRUE;
310}
311
312int TestNTLM(WINPR_ATTR_UNUSED int argc, WINPR_ATTR_UNUSED char* argv[])
313{
314 for (size_t x = 0; x < ARRAYSIZE(ntofw1tests); x++)
315 {
316 const test_case_ntowf1_t* cur = &ntofw1tests[x];
317 if (!testNTOWF1(x, cur))
318 {
319 WLog_WARN("testNTOWF1", "[%" PRIuz "] test failed", x);
320 return -1;
321 }
322 }
323 for (size_t x = 0; x < ARRAYSIZE(ntofw2tests); x++)
324 {
325 const test_case_ntowf2_t* cur = &ntofw2tests[x];
326 if (!testNTOWF2(x, cur))
327 {
328 WLog_WARN("testNTOWF2", "[%" PRIuz "] test failed", x);
329 return -2;
330 }
331 }
332 for (size_t x = 0; x < ARRAYSIZE(ntofw2fromhashtests); x++)
333 {
334 const test_case_from_hash_t* cur = &ntofw2fromhashtests[x];
335 if (!testNTOWFv2FromHash(x, cur))
336 {
337 WLog_WARN("testNTOWFv2FromHash", "[%" PRIuz "] test failed", x);
338 return -2;
339 }
340 }
341 return 0;
342}