eap_mschapv2.c

Go to the documentation of this file.
00001 
00016 #include "includes.h"
00017 
00018 #include "common.h"
00019 #include "eap_i.h"
00020 #include "ms_funcs.h"
00021 
00022 
00023 struct eap_mschapv2_hdr {
00024         u8 op_code; /* MSCHAPV2_OP_* */
00025         u8 mschapv2_id; /* must be changed for challenges, but not for
00026                          * success/failure */
00027         u8 ms_length[2]; /* Note: misaligned; length - 5 */
00028         /* followed by data */
00029 } STRUCT_PACKED;
00030 
00031 #define MSCHAPV2_OP_CHALLENGE 1
00032 #define MSCHAPV2_OP_RESPONSE 2
00033 #define MSCHAPV2_OP_SUCCESS 3
00034 #define MSCHAPV2_OP_FAILURE 4
00035 #define MSCHAPV2_OP_CHANGE_PASSWORD 7
00036 
00037 #define MSCHAPV2_RESP_LEN 49
00038 
00039 #define ERROR_RESTRICTED_LOGON_HOURS 646
00040 #define ERROR_ACCT_DISABLED 647
00041 #define ERROR_PASSWD_EXPIRED 648
00042 #define ERROR_NO_DIALIN_PERMISSION 649
00043 #define ERROR_AUTHENTICATION_FAILURE 691
00044 #define ERROR_CHANGING_PASSWORD 709
00045 
00046 #define PASSWD_CHANGE_CHAL_LEN 16
00047 #define MSCHAPV2_KEY_LEN 16
00048 
00049 
00050 #define CHALLENGE_LEN 16
00051 
00052 struct eap_mschapv2_data {
00053         u8 auth_challenge[CHALLENGE_LEN];
00054         int auth_challenge_from_tls;
00055         u8 *peer_challenge;
00056         u8 auth_response[20];
00057         enum { CHALLENGE, SUCCESS_REQ, FAILURE_REQ, SUCCESS, FAILURE } state;
00058         u8 resp_mschapv2_id;
00059         u8 master_key[16];
00060         int master_key_valid;
00061 };
00062 
00063 
00064 static void * eap_mschapv2_init(struct eap_sm *sm)
00065 {
00066         struct eap_mschapv2_data *data;
00067 
00068         data = os_zalloc(sizeof(*data));
00069         if (data == NULL)
00070                 return NULL;
00071         data->state = CHALLENGE;
00072 
00073         if (sm->auth_challenge) {
00074                 os_memcpy(data->auth_challenge, sm->auth_challenge,
00075                           CHALLENGE_LEN);
00076                 data->auth_challenge_from_tls = 1;
00077         }
00078 
00079         if (sm->peer_challenge) {
00080                 data->peer_challenge = os_malloc(CHALLENGE_LEN);
00081                 if (data->peer_challenge == NULL) {
00082                         os_free(data);
00083                         return NULL;
00084                 }
00085                 os_memcpy(data->peer_challenge, sm->peer_challenge,
00086                           CHALLENGE_LEN);
00087         }
00088 
00089         return data;
00090 }
00091 
00092 
00093 static void eap_mschapv2_reset(struct eap_sm *sm, void *priv)
00094 {
00095         struct eap_mschapv2_data *data = priv;
00096         if (data == NULL)
00097                 return;
00098 
00099         os_free(data->peer_challenge);
00100         os_free(data);
00101 }
00102 
00103 
00104 static struct wpabuf * eap_mschapv2_build_challenge(
00105         struct eap_sm *sm, struct eap_mschapv2_data *data, u8 id)
00106 {
00107         struct wpabuf *req;
00108         struct eap_mschapv2_hdr *ms;
00109         char *name = "hostapd"; /* TODO: make this configurable */
00110         size_t ms_len;
00111 
00112         if (!data->auth_challenge_from_tls &&
00113             os_get_random(data->auth_challenge, CHALLENGE_LEN)) {
00114                 wpa_printf(MSG_ERROR, "EAP-MSCHAPV2: Failed to get random "
00115                            "data");
00116                 data->state = FAILURE;
00117                 return NULL;
00118         }
00119 
00120         ms_len = sizeof(*ms) + 1 + CHALLENGE_LEN + os_strlen(name);
00121         req = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_MSCHAPV2, ms_len,
00122                             EAP_CODE_REQUEST, id);
00123         if (req == NULL) {
00124                 wpa_printf(MSG_ERROR, "EAP-MSCHAPV2: Failed to allocate memory"
00125                            " for request");
00126                 data->state = FAILURE;
00127                 return NULL;
00128         }
00129 
00130         ms = wpabuf_put(req, sizeof(*ms));
00131         ms->op_code = MSCHAPV2_OP_CHALLENGE;
00132         ms->mschapv2_id = id;
00133         WPA_PUT_BE16(ms->ms_length, ms_len);
00134 
00135         wpabuf_put_u8(req, CHALLENGE_LEN);
00136         if (!data->auth_challenge_from_tls)
00137                 wpabuf_put_data(req, data->auth_challenge, CHALLENGE_LEN);
00138         else
00139                 wpabuf_put(req, CHALLENGE_LEN);
00140         wpa_hexdump(MSG_MSGDUMP, "EAP-MSCHAPV2: Challenge",
00141                     data->auth_challenge, CHALLENGE_LEN);
00142         wpabuf_put_data(req, name, os_strlen(name));
00143 
00144         return req;
00145 }
00146 
00147 
00148 static struct wpabuf * eap_mschapv2_build_success_req(
00149         struct eap_sm *sm, struct eap_mschapv2_data *data, u8 id)
00150 {
00151         struct wpabuf *req;
00152         struct eap_mschapv2_hdr *ms;
00153         u8 *msg;
00154         char *message = "OK";
00155         size_t ms_len;
00156 
00157         ms_len = sizeof(*ms) + 2 + 2 * sizeof(data->auth_response) + 1 + 2 +
00158                 os_strlen(message);
00159         req = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_MSCHAPV2, ms_len,
00160                             EAP_CODE_REQUEST, id);
00161         if (req == NULL) {
00162                 wpa_printf(MSG_ERROR, "EAP-MSCHAPV2: Failed to allocate memory"
00163                            " for request");
00164                 data->state = FAILURE;
00165                 return NULL;
00166         }
00167 
00168         ms = wpabuf_put(req, sizeof(*ms));
00169         ms->op_code = MSCHAPV2_OP_SUCCESS;
00170         ms->mschapv2_id = data->resp_mschapv2_id;
00171         WPA_PUT_BE16(ms->ms_length, ms_len);
00172         msg = (u8 *) (ms + 1);
00173 
00174         wpabuf_put_u8(req, 'S');
00175         wpabuf_put_u8(req, '=');
00176         wpa_snprintf_hex_uppercase(
00177                 wpabuf_put(req, sizeof(data->auth_response) * 2),
00178                 sizeof(data->auth_response) * 2 + 1,
00179                 data->auth_response, sizeof(data->auth_response));
00180         wpabuf_put_u8(req, ' ');
00181         wpabuf_put_u8(req, 'M');
00182         wpabuf_put_u8(req, '=');
00183         wpabuf_put_data(req, message, os_strlen(message));
00184 
00185         wpa_hexdump_ascii(MSG_MSGDUMP, "EAP-MSCHAPV2: Success Request Message",
00186                           msg, ms_len - sizeof(*ms));
00187 
00188         return req;
00189 }
00190 
00191 
00192 static struct wpabuf * eap_mschapv2_build_failure_req(
00193         struct eap_sm *sm, struct eap_mschapv2_data *data, u8 id)
00194 {
00195         struct wpabuf *req;
00196         struct eap_mschapv2_hdr *ms;
00197         char *message = "E=691 R=0 C=00000000000000000000000000000000 V=3 "
00198                 "M=FAILED";
00199         size_t ms_len;
00200 
00201         ms_len = sizeof(*ms) + os_strlen(message);
00202         req = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_MSCHAPV2, ms_len,
00203                             EAP_CODE_REQUEST, id);
00204         if (req == NULL) {
00205                 wpa_printf(MSG_ERROR, "EAP-MSCHAPV2: Failed to allocate memory"
00206                            " for request");
00207                 data->state = FAILURE;
00208                 return NULL;
00209         }
00210 
00211         ms = wpabuf_put(req, sizeof(*ms));
00212         ms->op_code = MSCHAPV2_OP_FAILURE;
00213         ms->mschapv2_id = data->resp_mschapv2_id;
00214         WPA_PUT_BE16(ms->ms_length, ms_len);
00215 
00216         wpabuf_put_data(req, message, os_strlen(message));
00217 
00218         wpa_hexdump_ascii(MSG_MSGDUMP, "EAP-MSCHAPV2: Failure Request Message",
00219                           (u8 *) message, os_strlen(message));
00220 
00221         return req;
00222 }
00223 
00224 
00225 static struct wpabuf * eap_mschapv2_buildReq(struct eap_sm *sm, void *priv,
00226                                              u8 id)
00227 {
00228         struct eap_mschapv2_data *data = priv;
00229 
00230         switch (data->state) {
00231         case CHALLENGE:
00232                 return eap_mschapv2_build_challenge(sm, data, id);
00233         case SUCCESS_REQ:
00234                 return eap_mschapv2_build_success_req(sm, data, id);
00235         case FAILURE_REQ:
00236                 return eap_mschapv2_build_failure_req(sm, data, id);
00237         default:
00238                 wpa_printf(MSG_DEBUG, "EAP-MSCHAPV2: Unknown state %d in "
00239                            "buildReq", data->state);
00240                 break;
00241         }
00242         return NULL;
00243 }
00244 
00245 
00246 static Boolean eap_mschapv2_check(struct eap_sm *sm, void *priv,
00247                                   struct wpabuf *respData)
00248 {
00249         struct eap_mschapv2_data *data = priv;
00250         struct eap_mschapv2_hdr *resp;
00251         const u8 *pos;
00252         size_t len;
00253 
00254         pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_MSCHAPV2, respData,
00255                                &len);
00256         if (pos == NULL || len < 1) {
00257                 wpa_printf(MSG_INFO, "EAP-MSCHAPV2: Invalid frame");
00258                 return TRUE;
00259         }
00260 
00261         resp = (struct eap_mschapv2_hdr *) pos;
00262         if (data->state == CHALLENGE &&
00263             resp->op_code != MSCHAPV2_OP_RESPONSE) {
00264                 wpa_printf(MSG_DEBUG, "EAP-MSCHAPV2: Expected Response - "
00265                            "ignore op %d", resp->op_code);
00266                 return TRUE;
00267         }
00268 
00269         if (data->state == SUCCESS_REQ &&
00270             resp->op_code != MSCHAPV2_OP_SUCCESS &&
00271             resp->op_code != MSCHAPV2_OP_FAILURE) {
00272                 wpa_printf(MSG_DEBUG, "EAP-MSCHAPV2: Expected Success or "
00273                            "Failure - ignore op %d", resp->op_code);
00274                 return TRUE;
00275         }
00276 
00277         if (data->state == FAILURE_REQ &&
00278             resp->op_code != MSCHAPV2_OP_FAILURE) {
00279                 wpa_printf(MSG_DEBUG, "EAP-MSCHAPV2: Expected Failure "
00280                            "- ignore op %d", resp->op_code);
00281                 return TRUE;
00282         }
00283 
00284         return FALSE;
00285 }
00286 
00287 
00288 static void eap_mschapv2_process_response(struct eap_sm *sm,
00289                                           struct eap_mschapv2_data *data,
00290                                           struct wpabuf *respData)
00291 {
00292         struct eap_mschapv2_hdr *resp;
00293         const u8 *pos, *end, *peer_challenge, *nt_response, *name;
00294         u8 flags;
00295         size_t len, name_len, i;
00296         u8 expected[24];
00297         const u8 *username, *user;
00298         size_t username_len, user_len;
00299         int res;
00300 
00301         pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_MSCHAPV2, respData,
00302                                &len);
00303         if (pos == NULL || len < 1)
00304                 return; /* Should not happen - frame already validated */
00305 
00306         end = pos + len;
00307         resp = (struct eap_mschapv2_hdr *) pos;
00308         pos = (u8 *) (resp + 1);
00309 
00310         if (len < sizeof(*resp) + 1 + 49 ||
00311             resp->op_code != MSCHAPV2_OP_RESPONSE ||
00312             pos[0] != 49) {
00313                 wpa_hexdump_buf(MSG_DEBUG, "EAP-MSCHAPV2: Invalid response",
00314                                 respData);
00315                 data->state = FAILURE;
00316                 return;
00317         }
00318         data->resp_mschapv2_id = resp->mschapv2_id;
00319         pos++;
00320         peer_challenge = pos;
00321         pos += 16 + 8;
00322         nt_response = pos;
00323         pos += 24;
00324         flags = *pos++;
00325         name = pos;
00326         name_len = end - name;
00327 
00328         if (data->peer_challenge) {
00329                 wpa_printf(MSG_DEBUG, "EAP-MSCHAPV2: Using pre-configured "
00330                            "Peer-Challenge");
00331                 peer_challenge = data->peer_challenge;
00332         }
00333         wpa_hexdump(MSG_MSGDUMP, "EAP-MSCHAPV2: Peer-Challenge",
00334                     peer_challenge, 16);
00335         wpa_hexdump(MSG_MSGDUMP, "EAP-MSCHAPV2: NT-Response", nt_response, 24);
00336         wpa_printf(MSG_MSGDUMP, "EAP-MSCHAPV2: Flags 0x%x", flags);
00337         wpa_hexdump_ascii(MSG_MSGDUMP, "EAP-MSCHAPV2: Name", name, name_len);
00338 
00339         /* MSCHAPv2 does not include optional domain name in the
00340          * challenge-response calculation, so remove domain prefix
00341          * (if present). */
00342         username = sm->identity;
00343         username_len = sm->identity_len;
00344         for (i = 0; i < username_len; i++) {
00345                 if (username[i] == '\\') {
00346                         username_len -= i + 1;
00347                         username += i + 1;
00348                         break;
00349                 }
00350         }
00351 
00352         user = name;
00353         user_len = name_len;
00354         for (i = 0; i < user_len; i++) {
00355                 if (user[i] == '\\') {
00356                         user_len -= i + 1;
00357                         user += i + 1;
00358                         break;
00359                 }
00360         }
00361 
00362         if (username_len != user_len ||
00363             os_memcmp(username, user, username_len) != 0) {
00364                 wpa_printf(MSG_DEBUG, "EAP-MSCHAPV2: Mismatch in user names");
00365                 wpa_hexdump_ascii(MSG_DEBUG, "EAP-MSCHAPV2: Expected user "
00366                                   "name", username, username_len);
00367                 wpa_hexdump_ascii(MSG_DEBUG, "EAP-MSCHAPV2: Received user "
00368                                   "name", user, user_len);
00369                 data->state = FAILURE;
00370                 return;
00371         }
00372 
00373         wpa_hexdump_ascii(MSG_MSGDUMP, "EAP-MSCHAPV2: User name",
00374                           username, username_len);
00375 
00376         if (sm->user->password_hash) {
00377                 res = generate_nt_response_pwhash(data->auth_challenge,
00378                                                   peer_challenge,
00379                                                   username, username_len,
00380                                                   sm->user->password,
00381                                                   expected);
00382         } else {
00383                 res = generate_nt_response(data->auth_challenge,
00384                                            peer_challenge,
00385                                            username, username_len,
00386                                            sm->user->password,
00387                                            sm->user->password_len,
00388                                            expected);
00389         }
00390         if (res) {
00391                 data->state = FAILURE;
00392                 return;
00393         }
00394 
00395         if (os_memcmp(nt_response, expected, 24) == 0) {
00396                 const u8 *pw_hash;
00397                 u8 pw_hash_buf[16], pw_hash_hash[16];
00398 
00399                 wpa_printf(MSG_DEBUG, "EAP-MSCHAPV2: Correct NT-Response");
00400                 data->state = SUCCESS_REQ;
00401 
00402                 /* Authenticator response is not really needed yet, but
00403                  * calculate it here so that peer_challenge and username need
00404                  * not be saved. */
00405                 if (sm->user->password_hash) {
00406                         pw_hash = sm->user->password;
00407                 } else {
00408                         nt_password_hash(sm->user->password,
00409                                          sm->user->password_len,
00410                                          pw_hash_buf);
00411                         pw_hash = pw_hash_buf;
00412                 }
00413                 generate_authenticator_response_pwhash(
00414                         pw_hash, peer_challenge, data->auth_challenge,
00415                         username, username_len, nt_response,
00416                         data->auth_response);
00417 
00418                 hash_nt_password_hash(pw_hash, pw_hash_hash);
00419                 get_master_key(pw_hash_hash, nt_response, data->master_key);
00420                 data->master_key_valid = 1;
00421                 wpa_hexdump_key(MSG_DEBUG, "EAP-MSCHAPV2: Derived Master Key",
00422                                 data->master_key, MSCHAPV2_KEY_LEN);
00423         } else {
00424                 wpa_hexdump(MSG_MSGDUMP, "EAP-MSCHAPV2: Expected NT-Response",
00425                             expected, 24);
00426                 wpa_printf(MSG_DEBUG, "EAP-MSCHAPV2: Invalid NT-Response");
00427                 data->state = FAILURE_REQ;
00428         }
00429 }
00430 
00431 
00432 static void eap_mschapv2_process_success_resp(struct eap_sm *sm,
00433                                               struct eap_mschapv2_data *data,
00434                                               struct wpabuf *respData)
00435 {
00436         struct eap_mschapv2_hdr *resp;
00437         const u8 *pos;
00438         size_t len;
00439 
00440         pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_MSCHAPV2, respData,
00441                                &len);
00442         if (pos == NULL || len < 1)
00443                 return; /* Should not happen - frame already validated */
00444 
00445         resp = (struct eap_mschapv2_hdr *) pos;
00446 
00447         if (resp->op_code == MSCHAPV2_OP_SUCCESS) {
00448                 wpa_printf(MSG_DEBUG, "EAP-MSCHAPV2: Received Success Response"
00449                            " - authentication completed successfully");
00450                 data->state = SUCCESS;
00451         } else {
00452                 wpa_printf(MSG_DEBUG, "EAP-MSCHAPV2: Did not receive Success "
00453                            "Response - peer rejected authentication");
00454                 data->state = FAILURE;
00455         }
00456 }
00457 
00458 
00459 static void eap_mschapv2_process_failure_resp(struct eap_sm *sm,
00460                                               struct eap_mschapv2_data *data,
00461                                               struct wpabuf *respData)
00462 {
00463         struct eap_mschapv2_hdr *resp;
00464         const u8 *pos;
00465         size_t len;
00466 
00467         pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_MSCHAPV2, respData,
00468                                &len);
00469         if (pos == NULL || len < 1)
00470                 return; /* Should not happen - frame already validated */
00471 
00472         resp = (struct eap_mschapv2_hdr *) pos;
00473 
00474         if (resp->op_code == MSCHAPV2_OP_FAILURE) {
00475                 wpa_printf(MSG_DEBUG, "EAP-MSCHAPV2: Received Failure Response"
00476                            " - authentication failed");
00477         } else {
00478                 wpa_printf(MSG_DEBUG, "EAP-MSCHAPV2: Did not receive Failure "
00479                            "Response - authentication failed");
00480         }
00481 
00482         data->state = FAILURE;
00483 }
00484 
00485 
00486 static void eap_mschapv2_process(struct eap_sm *sm, void *priv,
00487                                  struct wpabuf *respData)
00488 {
00489         struct eap_mschapv2_data *data = priv;
00490 
00491         if (sm->user == NULL || sm->user->password == NULL) {
00492                 wpa_printf(MSG_INFO, "EAP-MSCHAPV2: Password not configured");
00493                 data->state = FAILURE;
00494                 return;
00495         }
00496 
00497         switch (data->state) {
00498         case CHALLENGE:
00499                 eap_mschapv2_process_response(sm, data, respData);
00500                 break;
00501         case SUCCESS_REQ:
00502                 eap_mschapv2_process_success_resp(sm, data, respData);
00503                 break;
00504         case FAILURE_REQ:
00505                 eap_mschapv2_process_failure_resp(sm, data, respData);
00506                 break;
00507         default:
00508                 wpa_printf(MSG_DEBUG, "EAP-MSCHAPV2: Unknown state %d in "
00509                            "process", data->state);
00510                 break;
00511         }
00512 }
00513 
00514 
00515 static Boolean eap_mschapv2_isDone(struct eap_sm *sm, void *priv)
00516 {
00517         struct eap_mschapv2_data *data = priv;
00518         return data->state == SUCCESS || data->state == FAILURE;
00519 }
00520 
00521 
00522 static u8 * eap_mschapv2_getKey(struct eap_sm *sm, void *priv, size_t *len)
00523 {
00524         struct eap_mschapv2_data *data = priv;
00525         u8 *key;
00526 
00527         if (data->state != SUCCESS || !data->master_key_valid)
00528                 return NULL;
00529 
00530         *len = 2 * MSCHAPV2_KEY_LEN;
00531         key = os_malloc(*len);
00532         if (key == NULL)
00533                 return NULL;
00534         /* MSK = server MS-MPPE-Recv-Key | MS-MPPE-Send-Key */
00535         get_asymetric_start_key(data->master_key, key, MSCHAPV2_KEY_LEN, 0, 1);
00536         get_asymetric_start_key(data->master_key, key + MSCHAPV2_KEY_LEN,
00537                                 MSCHAPV2_KEY_LEN, 1, 1);
00538         wpa_hexdump_key(MSG_DEBUG, "EAP-MSCHAPV2: Derived key", key, *len);
00539 
00540         return key;
00541 }
00542 
00543 
00544 static Boolean eap_mschapv2_isSuccess(struct eap_sm *sm, void *priv)
00545 {
00546         struct eap_mschapv2_data *data = priv;
00547         return data->state == SUCCESS;
00548 }
00549 
00550 
00551 int eap_server_mschapv2_register(void)
00552 {
00553         struct eap_method *eap;
00554         int ret;
00555 
00556         eap = eap_server_method_alloc(EAP_SERVER_METHOD_INTERFACE_VERSION,
00557                                       EAP_VENDOR_IETF, EAP_TYPE_MSCHAPV2,
00558                                       "MSCHAPV2");
00559         if (eap == NULL)
00560                 return -1;
00561 
00562         eap->init = eap_mschapv2_init;
00563         eap->reset = eap_mschapv2_reset;
00564         eap->buildReq = eap_mschapv2_buildReq;
00565         eap->check = eap_mschapv2_check;
00566         eap->process = eap_mschapv2_process;
00567         eap->isDone = eap_mschapv2_isDone;
00568         eap->getKey = eap_mschapv2_getKey;
00569         eap->isSuccess = eap_mschapv2_isSuccess;
00570 
00571         ret = eap_server_method_register(eap);
00572         if (ret)
00573                 eap_server_method_free(eap);
00574         return ret;
00575 }
00576 
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Defines

Generated on Sat Nov 21 23:16:51 2009 for hostapd by  doxygen 1.6.1