aboutsummaryrefslogtreecommitdiff
path: root/contrib/wpa_supplicant/eap_mschapv2.c
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/wpa_supplicant/eap_mschapv2.c')
-rw-r--r--contrib/wpa_supplicant/eap_mschapv2.c567
1 files changed, 0 insertions, 567 deletions
diff --git a/contrib/wpa_supplicant/eap_mschapv2.c b/contrib/wpa_supplicant/eap_mschapv2.c
deleted file mode 100644
index 35c391c63c48..000000000000
--- a/contrib/wpa_supplicant/eap_mschapv2.c
+++ /dev/null
@@ -1,567 +0,0 @@
-/*
- * WPA Supplicant / EAP-MSCHAPV2 (draft-kamath-pppext-eap-mschapv2-00.txt)
- * Copyright (c) 2004-2005, Jouni Malinen <jkmaline@cc.hut.fi>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
- */
-
-#include <stdlib.h>
-#include <stdio.h>
-#include <string.h>
-
-#include "common.h"
-#include "eap_i.h"
-#include "wpa_supplicant.h"
-#include "config_ssid.h"
-#include "ms_funcs.h"
-
-
-struct eap_mschapv2_hdr {
- u8 code;
- u8 identifier;
- u16 length; /* including code, identifier, and length */
- u8 type; /* EAP_TYPE_MSCHAPV2 */
- u8 op_code; /* MSCHAPV2_OP_* */
- u8 mschapv2_id; /* usually same as identifier */
- u8 ms_length[2]; /* Note: misaligned; length - 5 */
- /* followed by data */
-} __attribute__ ((packed));
-
-#define MSCHAPV2_OP_CHALLENGE 1
-#define MSCHAPV2_OP_RESPONSE 2
-#define MSCHAPV2_OP_SUCCESS 3
-#define MSCHAPV2_OP_FAILURE 4
-#define MSCHAPV2_OP_CHANGE_PASSWORD 7
-
-#define MSCHAPV2_RESP_LEN 49
-
-#define ERROR_RESTRICTED_LOGON_HOURS 646
-#define ERROR_ACCT_DISABLED 647
-#define ERROR_PASSWD_EXPIRED 648
-#define ERROR_NO_DIALIN_PERMISSION 649
-#define ERROR_AUTHENTICATION_FAILURE 691
-#define ERROR_CHANGING_PASSWORD 709
-
-#define PASSWD_CHANGE_CHAL_LEN 16
-#define MSCHAPV2_KEY_LEN 16
-
-
-struct eap_mschapv2_data {
- u8 auth_response[20];
- int auth_response_valid;
-
- int prev_error;
- u8 passwd_change_challenge[PASSWD_CHANGE_CHAL_LEN];
- int passwd_change_challenge_valid;
- int passwd_change_version;
-
- /* Optional challenge values generated in EAP-FAST Phase 1 negotiation
- */
- u8 *peer_challenge;
- u8 *auth_challenge;
-
- int phase2;
- u8 master_key[16];
- int master_key_valid;
- int success;
-};
-
-
-static void eap_mschapv2_deinit(struct eap_sm *sm, void *priv);
-
-
-static void * eap_mschapv2_init(struct eap_sm *sm)
-{
- struct eap_mschapv2_data *data;
- data = malloc(sizeof(*data));
- if (data == NULL)
- return NULL;
- memset(data, 0, sizeof(*data));
-
- if (sm->peer_challenge) {
- data->peer_challenge = malloc(16);
- if (data->peer_challenge == NULL) {
- eap_mschapv2_deinit(sm, data);
- return NULL;
- }
- memcpy(data->peer_challenge, sm->peer_challenge, 16);
- }
-
- if (sm->auth_challenge) {
- data->auth_challenge = malloc(16);
- if (data->auth_challenge == NULL) {
- eap_mschapv2_deinit(sm, data);
- return NULL;
- }
- memcpy(data->auth_challenge, sm->auth_challenge, 16);
- }
-
- data->phase2 = sm->init_phase2;
-
- return data;
-}
-
-
-static void eap_mschapv2_deinit(struct eap_sm *sm, void *priv)
-{
- struct eap_mschapv2_data *data = priv;
- free(data->peer_challenge);
- free(data->auth_challenge);
- free(data);
-}
-
-
-static u8 * eap_mschapv2_challenge(struct eap_sm *sm,
- struct eap_mschapv2_data *data,
- struct eap_method_ret *ret,
- struct eap_mschapv2_hdr *req,
- size_t *respDataLen)
-{
- struct wpa_ssid *config = eap_get_config(sm);
- u8 *challenge, *peer_challenge, *username, *pos;
- int i, ms_len;
- size_t len, challenge_len, username_len;
- struct eap_mschapv2_hdr *resp;
- u8 password_hash[16], password_hash_hash[16];
-
- /* MSCHAPv2 does not include optional domain name in the
- * challenge-response calculation, so remove domain prefix
- * (if present). */
- username = config->identity;
- username_len = config->identity_len;
- for (i = 0; i < username_len; i++) {
- if (username[i] == '\\') {
- username_len -= i + 1;
- username += i + 1;
- break;
- }
- }
-
- wpa_printf(MSG_DEBUG, "EAP-MSCHAPV2: Received challenge");
- len = be_to_host16(req->length);
- pos = (u8 *) (req + 1);
- challenge_len = *pos++;
- if (challenge_len != 16) {
- wpa_printf(MSG_INFO, "EAP-MSCHAPV2: Invalid challenge length "
- "%d", challenge_len);
- ret->ignore = TRUE;
- return NULL;
- }
-
- if (len < 10 || len - 10 < challenge_len) {
- wpa_printf(MSG_INFO, "EAP-MSCHAPV2: Too short challenge"
- " packet: len=%lu challenge_len=%d",
- (unsigned long) len, challenge_len);
- ret->ignore = TRUE;
- return NULL;
- }
-
- challenge = pos;
- pos += challenge_len;
- wpa_hexdump_ascii(MSG_DEBUG, "EAP-MSCHAPV2: Authentication Servername",
- pos, len - challenge_len - 10);
-
- ret->ignore = FALSE;
- ret->methodState = METHOD_CONT;
- ret->decision = DECISION_FAIL;
- ret->allowNotifications = TRUE;
-
- wpa_printf(MSG_DEBUG, "EAP-MSCHAPV2: Generating Challenge Response");
-
- *respDataLen = sizeof(*resp) + 1 + MSCHAPV2_RESP_LEN +
- config->identity_len;
- resp = malloc(*respDataLen);
- if (resp == NULL)
- return NULL;
- memset(resp, 0, *respDataLen);
- resp->code = EAP_CODE_RESPONSE;
- resp->identifier = req->identifier;
- resp->length = host_to_be16(*respDataLen);
- resp->type = EAP_TYPE_MSCHAPV2;
- resp->op_code = MSCHAPV2_OP_RESPONSE;
- resp->mschapv2_id = req->mschapv2_id;
- ms_len = *respDataLen - 5;
- resp->ms_length[0] = ms_len >> 8;
- resp->ms_length[1] = ms_len & 0xff;
- pos = (u8 *) (resp + 1);
- *pos++ = MSCHAPV2_RESP_LEN; /* Value-Size */
-
- /* Response */
- peer_challenge = pos;
- if (data->peer_challenge) {
- wpa_printf(MSG_DEBUG, "EAP-MSCHAPV2: peer_challenge generated "
- "in Phase 1");
- peer_challenge = data->peer_challenge;
- } else if (hostapd_get_rand(peer_challenge, 16)) {
- free(resp);
- return NULL;
- }
- pos += 16;
- pos += 8; /* Reserved, must be zero */
- if (data->auth_challenge) {
- wpa_printf(MSG_DEBUG, "EAP-MSCHAPV2: auth_challenge generated "
- "in Phase 1");
- challenge = data->auth_challenge;
- }
- wpa_hexdump(MSG_DEBUG, "EAP-MSCHAPV2: auth_challenge", challenge, 16);
- wpa_hexdump(MSG_DEBUG, "EAP-MSCHAPV2: peer_challenge",
- peer_challenge, 16);
- wpa_hexdump_ascii(MSG_DEBUG, "EAP-MSCHAPV2: username",
- username, username_len);
- wpa_hexdump_ascii_key(MSG_DEBUG, "EAP-MSCHAPV2: password",
- config->password, config->password_len);
- generate_nt_response(challenge, peer_challenge,
- username, username_len,
- config->password, config->password_len,
- pos);
- wpa_hexdump(MSG_DEBUG, "EAP-MSCHAPV2: response", pos, 24);
- /* Authenticator response is not really needed yet, but calculate it
- * here so that challenges need not be saved. */
- generate_authenticator_response(config->password, config->password_len,
- peer_challenge, challenge,
- username, username_len, pos,
- data->auth_response);
- data->auth_response_valid = 1;
-
- /* Likewise, generate master_key here since we have the needed data
- * available. */
- nt_password_hash(config->password, config->password_len,
- password_hash);
- hash_nt_password_hash(password_hash, password_hash_hash);
- get_master_key(password_hash_hash, pos /* nt_response */,
- data->master_key);
- data->master_key_valid = 1;
-
- pos += 24;
- pos++; /* Flag / reserved, must be zero */
-
- memcpy(pos, config->identity, config->identity_len);
- return (u8 *) resp;
-}
-
-
-static u8 * eap_mschapv2_success(struct eap_sm *sm,
- struct eap_mschapv2_data *data,
- struct eap_method_ret *ret,
- struct eap_mschapv2_hdr *req,
- size_t *respDataLen)
-{
- struct eap_mschapv2_hdr *resp;
- u8 *pos, recv_response[20];
- int len, left;
-
- wpa_printf(MSG_DEBUG, "EAP-MSCHAPV2: Received success");
- len = be_to_host16(req->length);
- pos = (u8 *) (req + 1);
- if (!data->auth_response_valid || len < sizeof(*req) + 42 ||
- pos[0] != 'S' || pos[1] != '=' ||
- hexstr2bin((char *) (pos + 2), recv_response, 20) ||
- memcmp(data->auth_response, recv_response, 20) != 0) {
- wpa_printf(MSG_WARNING, "EAP-MSCHAPV2: Invalid authenticator "
- "response in success request");
- ret->methodState = METHOD_DONE;
- ret->decision = DECISION_FAIL;
- return NULL;
- }
- pos += 42;
- left = len - sizeof(*req) - 42;
- while (left > 0 && *pos == ' ') {
- pos++;
- left--;
- }
- wpa_hexdump_ascii(MSG_DEBUG, "EAP-MSCHAPV2: Success message",
- pos, left);
- wpa_printf(MSG_INFO, "EAP-MSCHAPV2: Authentication succeeded");
- *respDataLen = 6;
- resp = malloc(6);
- if (resp == NULL) {
- wpa_printf(MSG_DEBUG, "EAP-MSCHAPV2: Failed to allocate "
- "buffer for success response");
- ret->ignore = TRUE;
- return NULL;
- }
-
- resp->code = EAP_CODE_RESPONSE;
- resp->identifier = req->identifier;
- resp->length = host_to_be16(6);
- resp->type = EAP_TYPE_MSCHAPV2;
- resp->op_code = MSCHAPV2_OP_SUCCESS;
-
- ret->methodState = METHOD_DONE;
- ret->decision = DECISION_UNCOND_SUCC;
- ret->allowNotifications = FALSE;
- data->success = 1;
-
- return (u8 *) resp;
-}
-
-
-static int eap_mschapv2_failure_txt(struct eap_sm *sm,
- struct eap_mschapv2_data *data, char *txt)
-{
- char *pos, *msg = "";
- int retry = 1;
- struct wpa_ssid *config = eap_get_config(sm);
-
- /* For example:
- * E=691 R=1 C=<32 octets hex challenge> V=3 M=Authentication Failure
- */
-
- pos = txt;
-
- if (pos && strncmp(pos, "E=", 2) == 0) {
- pos += 2;
- data->prev_error = atoi(pos);
- wpa_printf(MSG_DEBUG, "EAP-MSCHAPV2: error %d",
- data->prev_error);
- pos = strchr(pos, ' ');
- if (pos)
- pos++;
- }
-
- if (pos && strncmp(pos, "R=", 2) == 0) {
- pos += 2;
- retry = atoi(pos);
- wpa_printf(MSG_DEBUG, "EAP-MSCHAPV2: retry is %sallowed",
- retry == 1 ? "" : "not ");
- pos = strchr(pos, ' ');
- if (pos)
- pos++;
- }
-
- if (pos && strncmp(pos, "C=", 2) == 0) {
- int hex_len;
- pos += 2;
- hex_len = strchr(pos, ' ') - (char *) pos;
- if (hex_len == PASSWD_CHANGE_CHAL_LEN * 2) {
- if (hexstr2bin(pos, data->passwd_change_challenge,
- PASSWD_CHANGE_CHAL_LEN)) {
- wpa_printf(MSG_DEBUG, "EAP-MSCHAPV2: invalid "
- "failure challenge");
- } else {
- wpa_hexdump(MSG_DEBUG, "EAP-MSCHAPV2: failure "
- "challenge",
- data->passwd_change_challenge,
- PASSWD_CHANGE_CHAL_LEN);
- data->passwd_change_challenge_valid = 1;
- }
- } else {
- wpa_printf(MSG_DEBUG, "EAP-MSCHAPV2: invalid failure "
- "challenge len %d", hex_len);
- }
- pos = strchr(pos, ' ');
- if (pos)
- pos++;
- } else {
- wpa_printf(MSG_DEBUG, "EAP-MSCHAPV2: required challenge field "
- "was not present in failure message");
- }
-
- if (pos && strncmp(pos, "V=", 2) == 0) {
- pos += 2;
- data->passwd_change_version = atoi(pos);
- wpa_printf(MSG_DEBUG, "EAP-MSCHAPV2: password changing "
- "protocol version %d", data->passwd_change_version);
- pos = strchr(pos, ' ');
- if (pos)
- pos++;
- }
-
- if (pos && strncmp(pos, "M=", 2) == 0) {
- pos += 2;
- msg = pos;
- }
- wpa_msg(sm->msg_ctx, MSG_WARNING,
- "EAP-MSCHAPV2: failure message: '%s' (retry %sallowed, error "
- "%d)",
- msg, retry == 1 ? "" : "not ", data->prev_error);
- if (retry == 1 && config) {
- /* TODO: could prevent the current password from being used
- * again at least for some period of time */
- eap_sm_request_identity(sm, config);
- eap_sm_request_password(sm, config);
- } else if (config) {
- /* TODO: prevent retries using same username/password */
- }
-
- return retry == 1;
-}
-
-
-static u8 * eap_mschapv2_failure(struct eap_sm *sm,
- struct eap_mschapv2_data *data,
- struct eap_method_ret *ret,
- struct eap_mschapv2_hdr *req,
- size_t *respDataLen)
-{
- struct eap_mschapv2_hdr *resp;
- u8 *msdata = (u8 *) (req + 1);
- char *buf;
- int len = be_to_host16(req->length) - sizeof(*req);
- int retry = 0;
-
- wpa_printf(MSG_DEBUG, "EAP-MSCHAPV2: Received failure");
- wpa_hexdump_ascii(MSG_DEBUG, "EAP-MSCHAPV2: Failure data",
- msdata, len);
- buf = malloc(len + 1);
- if (buf) {
- memcpy(buf, msdata, len);
- buf[len] = '\0';
- retry = eap_mschapv2_failure_txt(sm, data, buf);
- free(buf);
- }
-
- ret->ignore = FALSE;
- ret->methodState = METHOD_DONE;
- ret->decision = DECISION_FAIL;
- ret->allowNotifications = FALSE;
-
- if (retry) {
- /* TODO: could try to retry authentication, e.g, after having
- * changed the username/password. In this case, EAP MS-CHAP-v2
- * Failure Response would not be sent here. */
- }
-
- *respDataLen = 6;
- resp = malloc(6);
- if (resp == NULL) {
- return NULL;
- }
-
- resp->code = EAP_CODE_RESPONSE;
- resp->identifier = req->identifier;
- resp->length = host_to_be16(6);
- resp->type = EAP_TYPE_MSCHAPV2;
- resp->op_code = MSCHAPV2_OP_FAILURE;
-
- return (u8 *) resp;
-}
-
-
-static u8 * eap_mschapv2_process(struct eap_sm *sm, void *priv,
- struct eap_method_ret *ret,
- u8 *reqData, size_t reqDataLen,
- size_t *respDataLen)
-{
- struct eap_mschapv2_data *data = priv;
- struct wpa_ssid *config = eap_get_config(sm);
- struct eap_mschapv2_hdr *req;
- int ms_len, len;
-
- if (config == NULL || config->identity == NULL) {
- wpa_printf(MSG_INFO, "EAP-MSCHAPV2: Identity not configured");
- eap_sm_request_identity(sm, config);
- ret->ignore = TRUE;
- return NULL;
- }
-
- if (config->password == NULL) {
- wpa_printf(MSG_INFO, "EAP-MSCHAPV2: Password not configured");
- eap_sm_request_password(sm, config);
- ret->ignore = TRUE;
- return NULL;
- }
-
- req = (struct eap_mschapv2_hdr *) reqData;
- len = be_to_host16(req->length);
- if (len < sizeof(*req) + 2 || req->type != EAP_TYPE_MSCHAPV2 ||
- len > reqDataLen) {
- wpa_printf(MSG_INFO, "EAP-MSCHAPV2: Invalid frame");
- ret->ignore = TRUE;
- return NULL;
- }
-
- ms_len = ((int) req->ms_length[0] << 8) | req->ms_length[1];
- if (ms_len != len - 5) {
- wpa_printf(MSG_INFO, "EAP-MSCHAPV2: Invalid header: len=%d "
- "ms_len=%d", len, ms_len);
- if (sm->workaround) {
- /* Some authentication servers use invalid ms_len,
- * ignore it for interoperability. */
- wpa_printf(MSG_INFO, "EAP-MSCHAPV2: workaround, ignore"
- " invalid ms_len");
- } else {
- ret->ignore = TRUE;
- return NULL;
- }
- }
-
- switch (req->op_code) {
- case MSCHAPV2_OP_CHALLENGE:
- return eap_mschapv2_challenge(sm, data, ret, req, respDataLen);
- case MSCHAPV2_OP_SUCCESS:
- return eap_mschapv2_success(sm, data, ret, req, respDataLen);
- case MSCHAPV2_OP_FAILURE:
- return eap_mschapv2_failure(sm, data, ret, req, respDataLen);
- default:
- wpa_printf(MSG_INFO, "EAP-MSCHAPV2: Unknown op %d - ignored",
- req->op_code);
- ret->ignore = TRUE;
- return NULL;
- }
-}
-
-
-static Boolean eap_mschapv2_isKeyAvailable(struct eap_sm *sm, void *priv)
-{
- struct eap_mschapv2_data *data = priv;
- return data->success && data->master_key_valid;
-}
-
-
-static u8 * eap_mschapv2_getKey(struct eap_sm *sm, void *priv, size_t *len)
-{
- struct eap_mschapv2_data *data = priv;
- u8 *key;
- int key_len;
-
- if (!data->master_key_valid || !data->success)
- return NULL;
-
- if (data->peer_challenge) {
- /* EAP-FAST needs both send and receive keys */
- key_len = 2 * MSCHAPV2_KEY_LEN;
- } else {
- key_len = MSCHAPV2_KEY_LEN;
- }
-
- key = malloc(key_len);
- if (key == NULL)
- return NULL;
-
- if (data->peer_challenge) {
- get_asymetric_start_key(data->master_key, key,
- MSCHAPV2_KEY_LEN, 0, 0);
- get_asymetric_start_key(data->master_key,
- key + MSCHAPV2_KEY_LEN,
- MSCHAPV2_KEY_LEN, 1, 0);
- } else {
- get_asymetric_start_key(data->master_key, key,
- MSCHAPV2_KEY_LEN, 1, 0);
- }
-
- wpa_hexdump_key(MSG_DEBUG, "EAP-MSCHAPV2: Derived key",
- key, key_len);
-
- *len = key_len;
- return key;
-}
-
-
-const struct eap_method eap_method_mschapv2 =
-{
- .method = EAP_TYPE_MSCHAPV2,
- .name = "MSCHAPV2",
- .init = eap_mschapv2_init,
- .deinit = eap_mschapv2_deinit,
- .process = eap_mschapv2_process,
- .isKeyAvailable = eap_mschapv2_isKeyAvailable,
- .getKey = eap_mschapv2_getKey,
-};