1 /*
2 * Copyright (C) 2017 Michael Brown <mbrown@fensystems.co.uk>.
3 *
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License as
6 * published by the Free Software Foundation; either version 2 of the
7 * License, or any later version.
8 *
9 * This program is distributed in the hope that it will be useful, but
10 * WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
17 * 02110-1301, USA.
18 *
19 * You can also choose to distribute this program under the terms of
20 * the Unmodified Binary Distribution Licence (as given in the file
21 * COPYING.UBDL), provided that you have satisfied its requirements.
22 */
23
24 FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
25
26 /** @file
27 *
28 * NTLM authentication self-tests
29 *
30 * The test vectors are taken from the MS-NLMP specification document.
31 *
32 */
33
34 /* Forcibly enable assertions */
35 #undef NDEBUG
36
37 #include <stdlib.h>
38 #include <string.h>
39 #include <byteswap.h>
40 #include <ipxe/ntlm.h>
41 #include <ipxe/test.h>
42
43 /** A key generation test */
44 struct ntlm_key_test {
45 /** Domain name (or NULL) */
46 const char *domain;
47 /** User name (or NULL) */
48 const char *username;
49 /** Password (or NULL) */
50 const char *password;
51 /** Expected key */
52 struct ntlm_key expected;
53 };
54
55 /** An authentication test */
56 struct ntlm_authenticate_test {
57 /** Domain name (or NULL) */
58 const char *domain;
59 /** User name (or NULL) */
60 const char *username;
61 /** Password (or NULL) */
62 const char *password;
63 /** Workstation (or NULL) */
64 const char *workstation;
65 /** Nonce */
66 struct ntlm_nonce nonce;
67 /** Challenge message */
68 struct ntlm_challenge *challenge;
69 /** Length of Challenge message */
70 size_t challenge_len;
71 /** Expected Authenticate message */
72 struct ntlm_authenticate *expected;
73 /** Expected length of Authenticate message */
74 size_t expected_len;
75 };
76
77 /** Define inline message data */
78 #define DATA(...) { __VA_ARGS__ }
79
80 /** Define a key generation digest test */
81 #define KEY_TEST( name, DOMAIN, USERNAME, PASSWORD, EXPECTED ) \
82 static struct ntlm_key_test name = { \
83 .domain = DOMAIN, \
84 .username = USERNAME, \
85 .password = PASSWORD, \
86 .expected = { \
87 .raw = EXPECTED, \
88 }, \
89 };
90
91 /** Define an authentication test */
92 #define AUTHENTICATE_TEST( name, DOMAIN, USERNAME, PASSWORD, \
93 WORKSTATION, NONCE, CHALLENGE, EXPECTED ) \
94 static const uint8_t name ## _challenge[] = CHALLENGE; \
95 static const uint8_t name ## _expected[] = EXPECTED; \
96 static struct ntlm_authenticate_test name = { \
97 .domain = DOMAIN, \
98 .username = USERNAME, \
99 .password = PASSWORD, \
100 .workstation = WORKSTATION, \
101 .nonce = { \
102 .raw = NONCE, \
103 }, \
104 .challenge = ( ( void * ) name ## _challenge ), \
105 .challenge_len = sizeof ( name ## _challenge ), \
106 .expected = ( ( void * ) name ## _expected ), \
107 .expected_len = sizeof ( name ## _expected ), \
108 };
109
110 /** NTOWFv2() test from MS-NLMP specification */
111 KEY_TEST ( msnlmp_ntowfv2, "Domain", "User", "Password",
112 DATA ( 0x0c, 0x86, 0x8a, 0x40, 0x3b, 0xfd, 0x7a, 0x93, 0xa3, 0x00,
113 0x1e, 0xf2, 0x2e, 0xf0, 0x2e, 0x3f ) );
114
115 /** Authentication test from MS-NLMP specification */
116 AUTHENTICATE_TEST ( msnlmp_authenticate,
117 "Domain", "User", "Password", "COMPUTER",
118 DATA ( 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa ),
119 DATA ( 0x4e, 0x54, 0x4c, 0x4d, 0x53, 0x53, 0x50, 0x00, 0x02, 0x00,
120 0x00, 0x00, 0x0c, 0x00, 0x0c, 0x00, 0x38, 0x00, 0x00, 0x00,
121 0x33, 0x82, 0x8a, 0xe2, 0x01, 0x23, 0x45, 0x67, 0x89, 0xab,
122 0xcd, 0xef, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
123 0x24, 0x00, 0x24, 0x00, 0x44, 0x00, 0x00, 0x00, 0x06, 0x00,
124 0x70, 0x17, 0x00, 0x00, 0x00, 0x0f, 0x53, 0x00, 0x65, 0x00,
125 0x72, 0x00, 0x76, 0x00, 0x65, 0x00, 0x72, 0x00, 0x02, 0x00,
126 0x0c, 0x00, 0x44, 0x00, 0x6f, 0x00, 0x6d, 0x00, 0x61, 0x00,
127 0x69, 0x00, 0x6e, 0x00, 0x01, 0x00, 0x0c, 0x00, 0x53, 0x00,
128 0x65, 0x00, 0x72, 0x00, 0x76, 0x00, 0x65, 0x00, 0x72, 0x00,
129 0x00, 0x00, 0x00, 0x00 ),
130 DATA ( 0x4e, 0x54, 0x4c, 0x4d, 0x53, 0x53, 0x50, 0x00, 0x03, 0x00,
131 0x00, 0x00, 0x18, 0x00, 0x18, 0x00, 0x6c, 0x00, 0x00, 0x00,
132 0x54, 0x00, 0x54, 0x00, 0x84, 0x00, 0x00, 0x00, 0x0c, 0x00,
133 0x0c, 0x00, 0x48, 0x00, 0x00, 0x00, 0x08, 0x00, 0x08, 0x00,
134 0x54, 0x00, 0x00, 0x00, 0x10, 0x00, 0x10, 0x00, 0x5c, 0x00,
135 0x00, 0x00, 0x10, 0x00, 0x10, 0x00, 0xd8, 0x00, 0x00, 0x00,
136 0x35, 0x82, 0x88, 0xe2, 0x05, 0x01, 0x28, 0x0a, 0x00, 0x00,
137 0x00, 0x0f, 0x44, 0x00, 0x6f, 0x00, 0x6d, 0x00, 0x61, 0x00,
138 0x69, 0x00, 0x6e, 0x00, 0x55, 0x00, 0x73, 0x00, 0x65, 0x00,
139 0x72, 0x00, 0x43, 0x00, 0x4f, 0x00, 0x4d, 0x00, 0x50, 0x00,
140 0x55, 0x00, 0x54, 0x00, 0x45, 0x00, 0x52, 0x00, 0x86, 0xc3,
141 0x50, 0x97, 0xac, 0x9c, 0xec, 0x10, 0x25, 0x54, 0x76, 0x4a,
142 0x57, 0xcc, 0xcc, 0x19, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
143 0xaa, 0xaa, 0x68, 0xcd, 0x0a, 0xb8, 0x51, 0xe5, 0x1c, 0x96,
144 0xaa, 0xbc, 0x92, 0x7b, 0xeb, 0xef, 0x6a, 0x1c, 0x01, 0x01,
145 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
146 0x00, 0x00, 0x00, 0x00, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
147 0xaa, 0xaa, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x0c, 0x00,
148 0x44, 0x00, 0x6f, 0x00, 0x6d, 0x00, 0x61, 0x00, 0x69, 0x00,
149 0x6e, 0x00, 0x01, 0x00, 0x0c, 0x00, 0x53, 0x00, 0x65, 0x00,
150 0x72, 0x00, 0x76, 0x00, 0x65, 0x00, 0x72, 0x00, 0x00, 0x00,
151 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc5, 0xda, 0xd2, 0x54,
152 0x4f, 0xc9, 0x79, 0x90, 0x94, 0xce, 0x1c, 0xe9, 0x0b, 0xc9,
153 0xd0, 0x3e ) );
154
155 /**
156 * Report key generation test result
157 *
158 * @v test Key generation test
159 * @v file Test code file
160 * @v line Test code line
161 */
ntlm_key_okx(struct ntlm_key_test * test,const char * file,unsigned int line)162 static void ntlm_key_okx ( struct ntlm_key_test *test,
163 const char *file, unsigned int line ) {
164 struct ntlm_key key;
165
166 ntlm_key ( test->domain, test->username, test->password, &key );
167 okx ( memcmp ( &key, &test->expected, sizeof ( key ) ) == 0,
168 file, line );
169 }
170 #define ntlm_key_ok( test ) \
171 ntlm_key_okx ( test, __FILE__, __LINE__ )
172
173 /**
174 * Report NTLM variable-length data test result
175 *
176 * @v msg Message header
177 * @v msg_len Length of message
178 * @v data Variable-length data descriptor
179 * @v expected Expected message header
180 * @v expected_data Expected variable-length data descriptor
181 * @v field Field name
182 * @v file Test code file
183 * @v line Test code line
184 */
ntlm_data_okx(struct ntlm_header * msg,size_t msg_len,struct ntlm_data * data,struct ntlm_header * expected,struct ntlm_data * expected_data,const char * field,const char * file,unsigned int line)185 static void ntlm_data_okx ( struct ntlm_header *msg, size_t msg_len,
186 struct ntlm_data *data,
187 struct ntlm_header *expected,
188 struct ntlm_data *expected_data,
189 const char *field, const char *file,
190 unsigned int line ) {
191 size_t offset;
192 size_t len;
193 void *raw;
194 void *expected_raw;
195
196 /* Verify data lies within message */
197 okx ( data->len == data->max_len, file, line );
198 offset = le32_to_cpu ( data->offset );
199 len = le16_to_cpu ( data->len );
200 okx ( offset <= msg_len, file, line );
201 okx ( len <= ( msg_len - offset ), file, line );
202
203 /* Verify content matches expected content */
204 raw = ( ( ( void * ) msg ) + offset );
205 expected_raw = ( ( ( void * ) expected ) +
206 le32_to_cpu ( expected_data->offset ) );
207 DBGC ( msg, "NTLM %s expected:\n", field );
208 DBGC_HDA ( msg, 0, expected_raw, le16_to_cpu ( expected_data->len ) );
209 DBGC ( msg, "NTLM %s actual:\n", field );
210 DBGC_HDA ( msg, 0, raw, len );
211 okx ( data->len == expected_data->len, file, line );
212 okx ( memcmp ( raw, expected_raw, len ) == 0, file, line );
213 }
214 #define ntlm_data_ok( msg, msg_len, data, expected, expected_data ) \
215 ntlm_data_okx ( msg, msg_len, data, expected, expected_data, \
216 __FILE__, __LINE__ )
217
218 /**
219 * Report NTLM authentication test result
220 *
221 * @v test Authentication test
222 * @v file Test code file
223 * @v line Test code line
224 */
ntlm_authenticate_okx(struct ntlm_authenticate_test * test,const char * file,unsigned int line)225 static void ntlm_authenticate_okx ( struct ntlm_authenticate_test *test,
226 const char *file, unsigned int line ) {
227 struct ntlm_authenticate *expected = test->expected;
228 struct ntlm_challenge_info info;
229 struct ntlm_authenticate *auth;
230 struct ntlm_key key;
231 struct ntlm_lm_response lm;
232 struct ntlm_nt_response nt;
233 size_t len;
234
235 /* Parse Challenge message */
236 okx ( ntlm_challenge ( test->challenge, test->challenge_len,
237 &info ) == 0, file, line );
238
239 /* Generate key */
240 ntlm_key ( test->domain, test->username, test->password, &key );
241
242 /* Generate responses */
243 ntlm_response ( &info, &key, &test->nonce, &lm, &nt );
244
245 /* Allocate buffer for Authenticate message */
246 len = ntlm_authenticate_len ( &info, test->domain, test->username,
247 test->workstation );
248 okx ( len >= sizeof ( *auth ), file, line );
249 auth = malloc ( len );
250 okx ( auth != NULL, file, line );
251
252 /* Construct Authenticate message */
253 okx ( ntlm_authenticate ( &info, test->domain, test->username,
254 test->workstation, &lm, &nt, auth ) == len,
255 file, line );
256
257 /* Verify header */
258 okx ( memcmp ( &auth->header, &expected->header,
259 sizeof ( auth->header ) ) == 0, file, line );
260
261 /* Verify LAN Manager response */
262 ntlm_data_okx ( &auth->header, len, &auth->lm, &expected->header,
263 &expected->lm, "LM", file, line );
264
265 /* Verify NT response */
266 ntlm_data_okx ( &auth->header, len, &auth->nt, &expected->header,
267 &expected->nt, "NT", file, line );
268
269 /* Verify domain name */
270 ntlm_data_okx ( &auth->header, len, &auth->domain, &expected->header,
271 &expected->domain, "domain", file, line );
272
273 /* Verify user name */
274 ntlm_data_okx ( &auth->header, len, &auth->user, &expected->header,
275 &expected->user, "user", file, line );
276
277 /* Verify workstation name */
278 ntlm_data_okx ( &auth->header, len, &auth->workstation,
279 &expected->header, &expected->workstation,
280 "workstation",file, line );
281
282 /* Verify session key */
283 if ( auth->flags & NTLM_NEGOTIATE_KEY_EXCH ) {
284 ntlm_data_okx ( &auth->header, len, &auth->session,
285 &expected->header, &expected->session,
286 "session", file, line );
287 }
288
289 /* Free Authenticate message */
290 free ( auth );
291 }
292 #define ntlm_authenticate_ok( test ) \
293 ntlm_authenticate_okx ( test, __FILE__, __LINE__ )
294
295 /**
296 * Perform NTLM self-test
297 *
298 */
ntlm_test_exec(void)299 static void ntlm_test_exec ( void ) {
300
301 /* Verify key generation */
302 ntlm_key_ok ( &msnlmp_ntowfv2 );
303
304 /* Verify authentication response */
305 ntlm_authenticate_ok ( &msnlmp_authenticate );
306 }
307
308 /** NTLM self-test */
309 struct self_test ntlm_test __self_test = {
310 .name = "ntlm",
311 .exec = ntlm_test_exec,
312 };
313