1f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)/*
2f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) * MSCHAPV2 (RFC 2759)
3f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) * Copyright (c) 2004-2008, Jouni Malinen <j@w1.fi>
4f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) *
5f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) * This software may be distributed under the terms of the BSD license.
6f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) * See README for more details.
7f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) */
803b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)
91320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#include "includes.h"
1003b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)
111320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#include "common.h"
121320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#include "crypto/ms_funcs.h"
13f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)#include "mschapv2.h"
141320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
151320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucciconst u8 * mschapv2_remove_domain(const u8 *username, size_t *len)
16f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles){
1703b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)	size_t i;
18f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
19f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)	/*
20f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)	 * MSCHAPv2 does not include optional domain name in the
21f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)	 * challenge-response calculation, so remove domain prefix
221320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci	 * (if present).
231320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci	 */
241320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
251320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci	for (i = 0; i < *len; i++) {
2603b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)		if (username[i] == '\\') {
2703b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)			*len -= i + 1;
281320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci			return username + i + 1;
291320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci		}
30f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)	}
31f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
321320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci	return username;
331320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci}
341320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
351320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
361320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucciint mschapv2_derive_response(const u8 *identity, size_t identity_len,
371320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci			     const u8 *password, size_t password_len,
38f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)			     int pwhash,
39f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)			     const u8 *auth_challenge,
40f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)			     const u8 *peer_challenge,
41f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)			     u8 *nt_response, u8 *auth_response,
42f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)			     u8 *master_key)
43f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles){
44116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch	const u8 *username;
451320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci	size_t username_len;
461320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci	u8 password_hash[16], password_hash_hash[16];
4703b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)
4803b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)	wpa_hexdump_ascii(MSG_DEBUG, "MSCHAPV2: Identity",
4903b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)			  identity, identity_len);
5003b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)	username_len = identity_len;
51116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch	username = mschapv2_remove_domain(identity, &username_len);
52116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch	wpa_hexdump_ascii(MSG_DEBUG, "MSCHAPV2: Username",
531320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci			  username, username_len);
541320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
55116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch	wpa_hexdump(MSG_DEBUG, "MSCHAPV2: auth_challenge",
561320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci		    auth_challenge, MSCHAPV2_CHAL_LEN);
571320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci	wpa_hexdump(MSG_DEBUG, "MSCHAPV2: peer_challenge",
58116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch		    peer_challenge, MSCHAPV2_CHAL_LEN);
59116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch	wpa_hexdump_ascii(MSG_DEBUG, "MSCHAPV2: username",
6003b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)			  username, username_len);
6103b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)	/* Authenticator response is not really needed yet, but calculate it
62116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch	 * here so that challenges need not be saved. */
63116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch	if (pwhash) {
64116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch		wpa_hexdump_key(MSG_DEBUG, "MSCHAPV2: password hash",
6503b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)				password, password_len);
66116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch		if (generate_nt_response_pwhash(auth_challenge, peer_challenge,
67116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch						username, username_len,
68116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch						password, nt_response) ||
6903b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)		    generate_authenticator_response_pwhash(
7003b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)			    password, peer_challenge, auth_challenge,
7103b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)			    username, username_len, nt_response,
7203b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)			    auth_response))
7303b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)			return -1;
7403b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)	} else {
75116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch		wpa_hexdump_ascii_key(MSG_DEBUG, "MSCHAPV2: password",
76116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch				      password, password_len);
77116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch		if (generate_nt_response(auth_challenge, peer_challenge,
78116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch					 username, username_len,
79116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch					 password, password_len,
801320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci					 nt_response) ||
81116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch		    generate_authenticator_response(password, password_len,
82116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch						    peer_challenge,
83116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch						    auth_challenge,
84116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch						    username, username_len,
851320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci						    nt_response,
861320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci						    auth_response))
871320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci			return -1;
88116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch	}
89116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch	wpa_hexdump(MSG_DEBUG, "MSCHAPV2: NT Response",
90116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch		    nt_response, MSCHAPV2_NT_RESPONSE_LEN);
91116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch	wpa_hexdump(MSG_DEBUG, "MSCHAPV2: Auth Response",
92116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch		    auth_response, MSCHAPV2_AUTH_RESPONSE_LEN);
93116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
94116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch	/* Generate master_key here since we have the needed data available. */
95116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch	if (pwhash) {
96116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch		if (hash_nt_password_hash(password, password_hash_hash))
9703b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)			return -1;
9803b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)	} else {
9903b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)		if (nt_password_hash(password, password_len, password_hash) ||
10003b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)		    hash_nt_password_hash(password_hash, password_hash_hash))
1011320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci			return -1;
1021320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci	}
1031320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci	if (get_master_key(password_hash_hash, nt_response, master_key))
1041320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci		return -1;
105f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)	wpa_hexdump_key(MSG_DEBUG, "MSCHAPV2: Master Key",
1061320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci			master_key, MSCHAPV2_MASTER_KEY_LEN);
1071320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
1081320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci	return 0;
1091320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci}
1101320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
1111320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
1121320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucciint mschapv2_verify_auth_response(const u8 *auth_response,
1131320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci				  const u8 *buf, size_t buf_len)
1141320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci{
1151320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci	u8 recv_response[MSCHAPV2_AUTH_RESPONSE_LEN];
1161320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci	if (buf_len < 2 + 2 * MSCHAPV2_AUTH_RESPONSE_LEN ||
1171320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci	    buf[0] != 'S' || buf[1] != '=' ||
1181320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci	    hexstr2bin((char *) (buf + 2), recv_response,
119f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)		       MSCHAPV2_AUTH_RESPONSE_LEN) ||
120f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)	    os_memcmp_const(auth_response, recv_response,
121116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch			    MSCHAPV2_AUTH_RESPONSE_LEN) != 0)
122f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)		return -1;
123f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)	return 0;
124f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)}
125f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)