iPXE
ntlm_test.c
Go to the documentation of this file.
00001 /*
00002  * Copyright (C) 2017 Michael Brown <mbrown@fensystems.co.uk>.
00003  *
00004  * This program is free software; you can redistribute it and/or
00005  * modify it under the terms of the GNU General Public License as
00006  * published by the Free Software Foundation; either version 2 of the
00007  * License, or any later version.
00008  *
00009  * This program is distributed in the hope that it will be useful, but
00010  * WITHOUT ANY WARRANTY; without even the implied warranty of
00011  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00012  * General Public License for more details.
00013  *
00014  * You should have received a copy of the GNU General Public License
00015  * along with this program; if not, write to the Free Software
00016  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
00017  * 02110-1301, USA.
00018  *
00019  * You can also choose to distribute this program under the terms of
00020  * the Unmodified Binary Distribution Licence (as given in the file
00021  * COPYING.UBDL), provided that you have satisfied its requirements.
00022  */
00023 
00024 FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
00025 
00026 /** @file
00027  *
00028  * NTLM authentication self-tests
00029  *
00030  * The test vectors are taken from the MS-NLMP specification document.
00031  *
00032  */
00033 
00034 /* Forcibly enable assertions */
00035 #undef NDEBUG
00036 
00037 #include <stdlib.h>
00038 #include <string.h>
00039 #include <byteswap.h>
00040 #include <ipxe/ntlm.h>
00041 #include <ipxe/test.h>
00042 
00043 /** A key generation test */
00044 struct ntlm_key_test {
00045         /** Domain name (or NULL) */
00046         const char *domain;
00047         /** User name (or NULL) */
00048         const char *username;
00049         /** Password (or NULL) */
00050         const char *password;
00051         /** Expected key */
00052         struct ntlm_key expected;
00053 };
00054 
00055 /** An authentication test */
00056 struct ntlm_authenticate_test {
00057         /** Domain name (or NULL) */
00058         const char *domain;
00059         /** User name (or NULL) */
00060         const char *username;
00061         /** Password (or NULL) */
00062         const char *password;
00063         /** Workstation (or NULL) */
00064         const char *workstation;
00065         /** Nonce */
00066         struct ntlm_nonce nonce;
00067         /** Challenge message */
00068         struct ntlm_challenge *challenge;
00069         /** Length of Challenge message */
00070         size_t challenge_len;
00071         /** Expected Authenticate message */
00072         struct ntlm_authenticate *expected;
00073         /** Expected length of Authenticate message */
00074         size_t expected_len;
00075 };
00076 
00077 /** Define inline message data */
00078 #define DATA(...) { __VA_ARGS__ }
00079 
00080 /** Define a key generation digest test */
00081 #define KEY_TEST( name, DOMAIN, USERNAME, PASSWORD, EXPECTED )          \
00082         static struct ntlm_key_test name = {                            \
00083                 .domain = DOMAIN,                                       \
00084                 .username = USERNAME,                                   \
00085                 .password = PASSWORD,                                   \
00086                 .expected = {                                           \
00087                         .raw = EXPECTED,                                \
00088                 },                                                      \
00089         };
00090 
00091 /** Define an authentication test */
00092 #define AUTHENTICATE_TEST( name, DOMAIN, USERNAME, PASSWORD,            \
00093                            WORKSTATION, NONCE, CHALLENGE, EXPECTED )    \
00094         static const uint8_t name ## _challenge[] = CHALLENGE;          \
00095         static const uint8_t name ## _expected[] = EXPECTED;            \
00096         static struct ntlm_authenticate_test name = {                   \
00097                 .domain = DOMAIN,                                       \
00098                 .username = USERNAME,                                   \
00099                 .password = PASSWORD,                                   \
00100                 .workstation = WORKSTATION,                             \
00101                 .nonce = {                                              \
00102                         .raw = NONCE,                                   \
00103                 },                                                      \
00104                 .challenge = ( ( void * ) name ## _challenge ),         \
00105                 .challenge_len = sizeof ( name ## _challenge ),         \
00106                 .expected = ( ( void * ) name ## _expected ),           \
00107                 .expected_len = sizeof ( name ## _expected ),           \
00108         };
00109 
00110 /** NTOWFv2() test from MS-NLMP specification */
00111 KEY_TEST ( msnlmp_ntowfv2, "Domain", "User", "Password",
00112         DATA ( 0x0c, 0x86, 0x8a, 0x40, 0x3b, 0xfd, 0x7a, 0x93, 0xa3, 0x00,
00113                0x1e, 0xf2, 0x2e, 0xf0, 0x2e, 0x3f ) );
00114 
00115 /** Authentication test from MS-NLMP specification */
00116 AUTHENTICATE_TEST ( msnlmp_authenticate,
00117         "Domain", "User", "Password", "COMPUTER",
00118         DATA ( 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa ),
00119         DATA ( 0x4e, 0x54, 0x4c, 0x4d, 0x53, 0x53, 0x50, 0x00, 0x02, 0x00,
00120                0x00, 0x00, 0x0c, 0x00, 0x0c, 0x00, 0x38, 0x00, 0x00, 0x00,
00121                0x33, 0x82, 0x8a, 0xe2, 0x01, 0x23, 0x45, 0x67, 0x89, 0xab,
00122                0xcd, 0xef, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
00123                0x24, 0x00, 0x24, 0x00, 0x44, 0x00, 0x00, 0x00, 0x06, 0x00,
00124                0x70, 0x17, 0x00, 0x00, 0x00, 0x0f, 0x53, 0x00, 0x65, 0x00,
00125                0x72, 0x00, 0x76, 0x00, 0x65, 0x00, 0x72, 0x00, 0x02, 0x00,
00126                0x0c, 0x00, 0x44, 0x00, 0x6f, 0x00, 0x6d, 0x00, 0x61, 0x00,
00127                0x69, 0x00, 0x6e, 0x00, 0x01, 0x00, 0x0c, 0x00, 0x53, 0x00,
00128                0x65, 0x00, 0x72, 0x00, 0x76, 0x00, 0x65, 0x00, 0x72, 0x00,
00129                0x00, 0x00, 0x00, 0x00 ),
00130         DATA ( 0x4e, 0x54, 0x4c, 0x4d, 0x53, 0x53, 0x50, 0x00, 0x03, 0x00,
00131                0x00, 0x00, 0x18, 0x00, 0x18, 0x00, 0x6c, 0x00, 0x00, 0x00,
00132                0x54, 0x00, 0x54, 0x00, 0x84, 0x00, 0x00, 0x00, 0x0c, 0x00,
00133                0x0c, 0x00, 0x48, 0x00, 0x00, 0x00, 0x08, 0x00, 0x08, 0x00,
00134                0x54, 0x00, 0x00, 0x00, 0x10, 0x00, 0x10, 0x00, 0x5c, 0x00,
00135                0x00, 0x00, 0x10, 0x00, 0x10, 0x00, 0xd8, 0x00, 0x00, 0x00,
00136                0x35, 0x82, 0x88, 0xe2, 0x05, 0x01, 0x28, 0x0a, 0x00, 0x00,
00137                0x00, 0x0f, 0x44, 0x00, 0x6f, 0x00, 0x6d, 0x00, 0x61, 0x00,
00138                0x69, 0x00, 0x6e, 0x00, 0x55, 0x00, 0x73, 0x00, 0x65, 0x00,
00139                0x72, 0x00, 0x43, 0x00, 0x4f, 0x00, 0x4d, 0x00, 0x50, 0x00,
00140                0x55, 0x00, 0x54, 0x00, 0x45, 0x00, 0x52, 0x00, 0x86, 0xc3,
00141                0x50, 0x97, 0xac, 0x9c, 0xec, 0x10, 0x25, 0x54, 0x76, 0x4a,
00142                0x57, 0xcc, 0xcc, 0x19, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
00143                0xaa, 0xaa, 0x68, 0xcd, 0x0a, 0xb8, 0x51, 0xe5, 0x1c, 0x96,
00144                0xaa, 0xbc, 0x92, 0x7b, 0xeb, 0xef, 0x6a, 0x1c, 0x01, 0x01,
00145                0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
00146                0x00, 0x00, 0x00, 0x00, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
00147                0xaa, 0xaa, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x0c, 0x00,
00148                0x44, 0x00, 0x6f, 0x00, 0x6d, 0x00, 0x61, 0x00, 0x69, 0x00,
00149                0x6e, 0x00, 0x01, 0x00, 0x0c, 0x00, 0x53, 0x00, 0x65, 0x00,
00150                0x72, 0x00, 0x76, 0x00, 0x65, 0x00, 0x72, 0x00, 0x00, 0x00,
00151                0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc5, 0xda, 0xd2, 0x54,
00152                0x4f, 0xc9, 0x79, 0x90, 0x94, 0xce, 0x1c, 0xe9, 0x0b, 0xc9,
00153                0xd0, 0x3e ) );
00154 
00155 /**
00156  * Report key generation test result
00157  *
00158  * @v test              Key generation test
00159  * @v file              Test code file
00160  * @v line              Test code line
00161  */
00162 static void ntlm_key_okx ( struct ntlm_key_test *test,
00163                            const char *file, unsigned int line ) {
00164         struct ntlm_key key;
00165 
00166         ntlm_key ( test->domain, test->username, test->password, &key );
00167         okx ( memcmp ( &key, &test->expected, sizeof ( key ) ) == 0,
00168               file, line );
00169 }
00170 #define ntlm_key_ok( test )                                             \
00171         ntlm_key_okx ( test, __FILE__, __LINE__ )
00172 
00173 /**
00174  * Report NTLM variable-length data test result
00175  *
00176  * @v msg               Message header
00177  * @v msg_len           Length of message
00178  * @v data              Variable-length data descriptor
00179  * @v expected          Expected message header
00180  * @v expected_data     Expected variable-length data descriptor
00181  * @v field             Field name
00182  * @v file              Test code file
00183  * @v line              Test code line
00184  */
00185 static void ntlm_data_okx ( struct ntlm_header *msg, size_t msg_len,
00186                             struct ntlm_data *data,
00187                             struct ntlm_header *expected,
00188                             struct ntlm_data *expected_data,
00189                             const char *field, const char *file,
00190                             unsigned int line ) {
00191         size_t offset;
00192         size_t len;
00193         void *raw;
00194         void *expected_raw;
00195 
00196         /* Verify data lies within message */
00197         okx ( data->len == data->max_len, file, line );
00198         offset = le32_to_cpu ( data->offset );
00199         len = le16_to_cpu ( data->len );
00200         okx ( offset <= msg_len, file, line );
00201         okx ( len <= ( msg_len - offset ), file, line );
00202 
00203         /* Verify content matches expected content */
00204         raw = ( ( ( void * ) msg ) + offset );
00205         expected_raw = ( ( ( void * ) expected ) +
00206                          le32_to_cpu ( expected_data->offset ) );
00207         DBGC ( msg, "NTLM %s expected:\n", field );
00208         DBGC_HDA ( msg, 0, expected_raw, le16_to_cpu ( expected_data->len ) );
00209         DBGC ( msg, "NTLM %s actual:\n", field );
00210         DBGC_HDA ( msg, 0, raw, len );
00211         okx ( data->len == expected_data->len, file, line );
00212         okx ( memcmp ( raw, expected_raw, len ) == 0, file, line );
00213 }
00214 #define ntlm_data_ok( msg, msg_len, data, expected, expected_data )     \
00215         ntlm_data_okx ( msg, msg_len, data, expected, expected_data,    \
00216                         __FILE__, __LINE__ )
00217 
00218 /**
00219  * Report NTLM authentication test result
00220  *
00221  * @v test              Authentication test
00222  * @v file              Test code file
00223  * @v line              Test code line
00224  */
00225 static void ntlm_authenticate_okx ( struct ntlm_authenticate_test *test,
00226                                     const char *file, unsigned int line ) {
00227         struct ntlm_authenticate *expected = test->expected;
00228         struct ntlm_challenge_info info;
00229         struct ntlm_authenticate *auth;
00230         struct ntlm_key key;
00231         struct ntlm_lm_response lm;
00232         struct ntlm_nt_response nt;
00233         size_t len;
00234 
00235         /* Parse Challenge message */
00236         okx ( ntlm_challenge ( test->challenge, test->challenge_len,
00237                                &info ) == 0, file, line );
00238 
00239         /* Generate key */
00240         ntlm_key ( test->domain, test->username, test->password, &key );
00241 
00242         /* Generate responses */
00243         ntlm_response ( &info, &key, &test->nonce, &lm, &nt );
00244 
00245         /* Allocate buffer for Authenticate message */
00246         len = ntlm_authenticate_len ( &info, test->domain, test->username,
00247                                       test->workstation );
00248         okx ( len >= sizeof ( *auth ), file, line );
00249         auth = malloc ( len );
00250         okx ( auth != NULL, file, line );
00251 
00252         /* Construct Authenticate message */
00253         okx ( ntlm_authenticate ( &info, test->domain, test->username,
00254                                   test->workstation, &lm, &nt, auth ) == len,
00255               file, line );
00256 
00257         /* Verify header */
00258         okx ( memcmp ( &auth->header, &expected->header,
00259                        sizeof ( auth->header ) ) == 0, file, line );
00260 
00261         /* Verify LAN Manager response */
00262         ntlm_data_okx ( &auth->header, len, &auth->lm, &expected->header,
00263                         &expected->lm, "LM", file, line );
00264 
00265         /* Verify NT response */
00266         ntlm_data_okx ( &auth->header, len, &auth->nt, &expected->header,
00267                         &expected->nt, "NT", file, line );
00268 
00269         /* Verify domain name */
00270         ntlm_data_okx ( &auth->header, len, &auth->domain, &expected->header,
00271                         &expected->domain, "domain", file, line );
00272 
00273         /* Verify user name */
00274         ntlm_data_okx ( &auth->header, len, &auth->user, &expected->header,
00275                         &expected->user, "user", file, line );
00276 
00277         /* Verify workstation name */
00278         ntlm_data_okx ( &auth->header, len, &auth->workstation,
00279                         &expected->header, &expected->workstation,
00280                         "workstation",file, line );
00281 
00282         /* Verify session key */
00283         if ( auth->flags & NTLM_NEGOTIATE_KEY_EXCH ) {
00284                 ntlm_data_okx ( &auth->header, len, &auth->session,
00285                                 &expected->header, &expected->session,
00286                                 "session", file, line );
00287         }
00288 
00289         /* Free Authenticate message */
00290         free ( auth );
00291 }
00292 #define ntlm_authenticate_ok( test )                                    \
00293         ntlm_authenticate_okx ( test, __FILE__, __LINE__ )
00294 
00295 /**
00296  * Perform NTLM self-test
00297  *
00298  */
00299 static void ntlm_test_exec ( void ) {
00300 
00301         /* Verify key generation */
00302         ntlm_key_ok ( &msnlmp_ntowfv2 );
00303 
00304         /* Verify authentication response */
00305         ntlm_authenticate_ok ( &msnlmp_authenticate );
00306 }
00307 
00308 /** NTLM self-test */
00309 struct self_test ntlm_test __self_test = {
00310         .name = "ntlm",
00311         .exec = ntlm_test_exec,
00312 };