18d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt/*
28d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * MSCHAPV2 (RFC 2759)
38d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * Copyright (c) 2004-2008, Jouni Malinen <j@w1.fi>
48d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt *
5c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt * This software may be distributed under the terms of the BSD license.
6c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt * See README for more details.
78d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt */
88d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
98d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "includes.h"
108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "common.h"
128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "crypto/ms_funcs.h"
138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "mschapv2.h"
148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtconst u8 * mschapv2_remove_domain(const u8 *username, size_t *len)
168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	size_t i;
188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	/*
208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	 * MSCHAPv2 does not include optional domain name in the
218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	 * challenge-response calculation, so remove domain prefix
228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	 * (if present).
238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	 */
248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	for (i = 0; i < *len; i++) {
268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (username[i] == '\\') {
278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			*len -= i + 1;
288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			return username + i + 1;
298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		}
308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return username;
338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtint mschapv2_derive_response(const u8 *identity, size_t identity_len,
378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			     const u8 *password, size_t password_len,
388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			     int pwhash,
398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			     const u8 *auth_challenge,
408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			     const u8 *peer_challenge,
418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			     u8 *nt_response, u8 *auth_response,
428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			     u8 *master_key)
438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	const u8 *username;
458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	size_t username_len;
468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	u8 password_hash[16], password_hash_hash[16];
478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_hexdump_ascii(MSG_DEBUG, "MSCHAPV2: Identity",
498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			  identity, identity_len);
508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	username_len = identity_len;
518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	username = mschapv2_remove_domain(identity, &username_len);
528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_hexdump_ascii(MSG_DEBUG, "MSCHAPV2: Username",
538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			  username, username_len);
548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_hexdump(MSG_DEBUG, "MSCHAPV2: auth_challenge",
568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		    auth_challenge, MSCHAPV2_CHAL_LEN);
578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_hexdump(MSG_DEBUG, "MSCHAPV2: peer_challenge",
588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		    peer_challenge, MSCHAPV2_CHAL_LEN);
598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_hexdump_ascii(MSG_DEBUG, "MSCHAPV2: username",
608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			  username, username_len);
618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	/* Authenticator response is not really needed yet, but calculate it
628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	 * here so that challenges need not be saved. */
638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (pwhash) {
648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_hexdump_key(MSG_DEBUG, "MSCHAPV2: password hash",
658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				password, password_len);
6661d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt		if (generate_nt_response_pwhash(auth_challenge, peer_challenge,
6761d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt						username, username_len,
6861d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt						password, nt_response) ||
6961d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt		    generate_authenticator_response_pwhash(
7061d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt			    password, peer_challenge, auth_challenge,
7161d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt			    username, username_len, nt_response,
7261d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt			    auth_response))
7361d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt			return -1;
748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	} else {
758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_hexdump_ascii_key(MSG_DEBUG, "MSCHAPV2: password",
768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				      password, password_len);
7761d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt		if (generate_nt_response(auth_challenge, peer_challenge,
7861d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt					 username, username_len,
7961d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt					 password, password_len,
8061d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt					 nt_response) ||
8161d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt		    generate_authenticator_response(password, password_len,
8261d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt						    peer_challenge,
8361d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt						    auth_challenge,
8461d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt						    username, username_len,
8561d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt						    nt_response,
8661d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt						    auth_response))
8761d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt			return -1;
888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_hexdump(MSG_DEBUG, "MSCHAPV2: NT Response",
908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		    nt_response, MSCHAPV2_NT_RESPONSE_LEN);
918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_hexdump(MSG_DEBUG, "MSCHAPV2: Auth Response",
928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		    auth_response, MSCHAPV2_AUTH_RESPONSE_LEN);
938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	/* Generate master_key here since we have the needed data available. */
958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (pwhash) {
968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (hash_nt_password_hash(password, password_hash_hash))
978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			return -1;
988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	} else {
998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (nt_password_hash(password, password_len, password_hash) ||
1008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		    hash_nt_password_hash(password_hash, password_hash_hash))
1018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			return -1;
1028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
10361d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	if (get_master_key(password_hash_hash, nt_response, master_key))
10461d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt		return -1;
1058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_hexdump_key(MSG_DEBUG, "MSCHAPV2: Master Key",
1068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			master_key, MSCHAPV2_MASTER_KEY_LEN);
1078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return 0;
1098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
1108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtint mschapv2_verify_auth_response(const u8 *auth_response,
1138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				  const u8 *buf, size_t buf_len)
1148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
1158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	u8 recv_response[MSCHAPV2_AUTH_RESPONSE_LEN];
1168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (buf_len < 2 + 2 * MSCHAPV2_AUTH_RESPONSE_LEN ||
1178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	    buf[0] != 'S' || buf[1] != '=' ||
1188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	    hexstr2bin((char *) (buf + 2), recv_response,
1198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		       MSCHAPV2_AUTH_RESPONSE_LEN) ||
120c28170251eb54dbf64a9074a07fee377587425b2Dmitry Shmidt	    os_memcmp_const(auth_response, recv_response,
121c28170251eb54dbf64a9074a07fee377587425b2Dmitry Shmidt			    MSCHAPV2_AUTH_RESPONSE_LEN) != 0)
1228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
1238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return 0;
1248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
125