159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta/*
259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * MSCHAPV2 (RFC 2759)
359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * Copyright (c) 2004-2008, Jouni Malinen <j@w1.fi>
459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta *
559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * This program is free software; you can redistribute it and/or modify
659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * it under the terms of the GNU General Public License version 2 as
759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * published by the Free Software Foundation.
859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta *
959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * Alternatively, this software may be distributed under the terms of BSD
1059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * license.
1159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta *
1259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * See README and COPYING for more details.
1359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta */
1459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta
1559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta#include "includes.h"
1659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta
1759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta#include "common.h"
1859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta#include "crypto/ms_funcs.h"
1959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta#include "mschapv2.h"
2059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta
2159b2e6871c65f58fdad78cd7229c292f6a177578Scott Bartaconst u8 * mschapv2_remove_domain(const u8 *username, size_t *len)
2259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta{
2359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta	size_t i;
2459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta
2559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta	/*
2659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta	 * MSCHAPv2 does not include optional domain name in the
2759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta	 * challenge-response calculation, so remove domain prefix
2859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta	 * (if present).
2959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta	 */
3059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta
3159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta	for (i = 0; i < *len; i++) {
3259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta		if (username[i] == '\\') {
3359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta			*len -= i + 1;
3459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta			return username + i + 1;
3559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta		}
3659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta	}
3759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta
3859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta	return username;
3959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta}
4059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta
4159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta
4259b2e6871c65f58fdad78cd7229c292f6a177578Scott Bartavoid mschapv2_derive_response(const u8 *identity, size_t identity_len,
4359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta			      const u8 *password, size_t password_len,
4459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta			      int pwhash,
4559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta			      const u8 *auth_challenge,
4659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta			      const u8 *peer_challenge,
4759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta			      u8 *nt_response, u8 *auth_response,
4859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta			      u8 *master_key)
4959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta{
5059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta	const u8 *username;
5159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta	size_t username_len;
5259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta	u8 password_hash[16], password_hash_hash[16];
5359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta
5459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta	wpa_hexdump_ascii(MSG_DEBUG, "MSCHAPV2: Identity",
5559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta			  identity, identity_len);
5659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta	username_len = identity_len;
5759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta	username = mschapv2_remove_domain(identity, &username_len);
5859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta	wpa_hexdump_ascii(MSG_DEBUG, "MSCHAPV2: Username",
5959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta			  username, username_len);
6059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta
6159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta	wpa_hexdump(MSG_DEBUG, "MSCHAPV2: auth_challenge",
6259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta		    auth_challenge, MSCHAPV2_CHAL_LEN);
6359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta	wpa_hexdump(MSG_DEBUG, "MSCHAPV2: peer_challenge",
6459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta		    peer_challenge, MSCHAPV2_CHAL_LEN);
6559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta	wpa_hexdump_ascii(MSG_DEBUG, "MSCHAPV2: username",
6659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta			  username, username_len);
6759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta	/* Authenticator response is not really needed yet, but calculate it
6859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta	 * here so that challenges need not be saved. */
6959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta	if (pwhash) {
7059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta		wpa_hexdump_key(MSG_DEBUG, "MSCHAPV2: password hash",
7159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta				password, password_len);
7259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta		generate_nt_response_pwhash(auth_challenge, peer_challenge,
7359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta					    username, username_len,
7459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta					    password, nt_response);
7559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta		generate_authenticator_response_pwhash(
7659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta			password, peer_challenge, auth_challenge,
7759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta			username, username_len, nt_response, auth_response);
7859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta	} else {
7959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta		wpa_hexdump_ascii_key(MSG_DEBUG, "MSCHAPV2: password",
8059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta				      password, password_len);
8159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta		generate_nt_response(auth_challenge, peer_challenge,
8259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta				     username, username_len,
8359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta				     password, password_len, nt_response);
8459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta		generate_authenticator_response(password, password_len,
8559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta						peer_challenge, auth_challenge,
8659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta						username, username_len,
8759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta						nt_response, auth_response);
8859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta	}
8959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta	wpa_hexdump(MSG_DEBUG, "MSCHAPV2: NT Response",
9059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta		    nt_response, MSCHAPV2_NT_RESPONSE_LEN);
9159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta	wpa_hexdump(MSG_DEBUG, "MSCHAPV2: Auth Response",
9259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta		    auth_response, MSCHAPV2_AUTH_RESPONSE_LEN);
9359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta
9459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta	/* Generate master_key here since we have the needed data available. */
9559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta	if (pwhash) {
9659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta		hash_nt_password_hash(password, password_hash_hash);
9759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta	} else {
9859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta		nt_password_hash(password, password_len, password_hash);
9959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta		hash_nt_password_hash(password_hash, password_hash_hash);
10059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta	}
10159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta	get_master_key(password_hash_hash, nt_response, master_key);
10259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta	wpa_hexdump_key(MSG_DEBUG, "MSCHAPV2: Master Key",
10359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta			master_key, MSCHAPV2_MASTER_KEY_LEN);
10459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta}
10559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta
10659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta
10759b2e6871c65f58fdad78cd7229c292f6a177578Scott Bartaint mschapv2_verify_auth_response(const u8 *auth_response,
10859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta				  const u8 *buf, size_t buf_len)
10959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta{
11059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta	u8 recv_response[MSCHAPV2_AUTH_RESPONSE_LEN];
11159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta	if (buf_len < 2 + 2 * MSCHAPV2_AUTH_RESPONSE_LEN ||
11259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta	    buf[0] != 'S' || buf[1] != '=' ||
11359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta	    hexstr2bin((char *) (buf + 2), recv_response,
11459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta		       MSCHAPV2_AUTH_RESPONSE_LEN) ||
11559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta	    os_memcmp(auth_response, recv_response,
11659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta		      MSCHAPV2_AUTH_RESPONSE_LEN) != 0)
11759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta		return -1;
11859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta	return 0;
11959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta}
12059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta