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