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