1 /*
2  * MSCHAPV2
3  */
4 
5 #ifdef EAP_MSCHAPv2
6 
7 #include "utils/includes.h"
8 #include "utils/common.h"
9 #include "crypto/ms_funcs.h"
10 #include "eap_peer/mschapv2.h"
11 
mschapv2_remove_domain(const u8 * username,size_t * len)12 const u8 * mschapv2_remove_domain(const u8 *username, size_t *len)
13 {
14 	size_t i;
15 
16 	/*
17 	 * MSCHAPv2 does not include optional domain name in the
18 	 * challenge-response calculation, so remove domain prefix
19 	 * (if present).
20 	 */
21 
22 	for (i = 0; i < *len; i++) {
23 		if (username[i] == '\\') {
24 			*len -= i + 1;
25 			return username + i + 1;
26 		}
27 	}
28 
29 	return username;
30 }
31 
32 
mschapv2_derive_response(const u8 * identity,size_t identity_len,const u8 * password,size_t password_len,int pwhash,const u8 * auth_challenge,const u8 * peer_challenge,u8 * nt_response,u8 * auth_response,u8 * master_key)33 int mschapv2_derive_response(const u8 *identity, size_t identity_len,
34 			     const u8 *password, size_t password_len,
35 			     int pwhash,
36 			     const u8 *auth_challenge,
37 			     const u8 *peer_challenge,
38 			     u8 *nt_response, u8 *auth_response,
39 			     u8 *master_key)
40 {
41 	const u8 *username;
42 	size_t username_len;
43 	u8 password_hash[16], password_hash_hash[16];
44 
45 	wpa_hexdump_ascii(MSG_DEBUG, "MSCHAPV2: Identity",
46 			  identity, identity_len);
47 	username_len = identity_len;
48 	username = mschapv2_remove_domain(identity, &username_len);
49 	wpa_hexdump_ascii(MSG_DEBUG, "MSCHAPV2: Username",
50 			  username, username_len);
51 
52 	wpa_hexdump(MSG_DEBUG, "MSCHAPV2: auth_challenge",
53 		    auth_challenge, MSCHAPV2_CHAL_LEN);
54 	wpa_hexdump(MSG_DEBUG, "MSCHAPV2: peer_challenge",
55 		    peer_challenge, MSCHAPV2_CHAL_LEN);
56 	wpa_hexdump_ascii(MSG_DEBUG, "MSCHAPV2: username",
57 			  username, username_len);
58 	/* Authenticator response is not really needed yet, but calculate it
59 	 * here so that challenges need not be saved. */
60 	if (pwhash) {
61 		wpa_hexdump_key(MSG_DEBUG, "MSCHAPV2: password hash",
62 				password, password_len);
63 		if (generate_nt_response_pwhash(auth_challenge, peer_challenge,
64 						username, username_len,
65 						password, nt_response) ||
66 		    generate_authenticator_response_pwhash(
67 			    password, peer_challenge, auth_challenge,
68 			    username, username_len, nt_response,
69 			    auth_response))
70 			return -1;
71 	} else {
72 		wpa_hexdump_ascii_key(MSG_DEBUG, "MSCHAPV2: password",
73 				      password, password_len);
74 		if (generate_nt_response(auth_challenge, peer_challenge,
75 					 username, username_len,
76 					 password, password_len,
77 					 nt_response) ||
78 		    generate_authenticator_response(password, password_len,
79 						    peer_challenge,
80 						    auth_challenge,
81 						    username, username_len,
82 						    nt_response,
83 						    auth_response))
84 			return -1;
85 	}
86 	wpa_hexdump(MSG_DEBUG, "MSCHAPV2: NT Response",
87 		    nt_response, MSCHAPV2_NT_RESPONSE_LEN);
88 	wpa_hexdump(MSG_DEBUG, "MSCHAPV2: Auth Response",
89 		    auth_response, MSCHAPV2_AUTH_RESPONSE_LEN);
90 
91 	/* Generate master_key here since we have the needed data available. */
92 	if (pwhash) {
93 		if (hash_nt_password_hash(password, password_hash_hash))
94 			return -1;
95 	} else {
96 		if (nt_password_hash(password, password_len, password_hash) ||
97 		    hash_nt_password_hash(password_hash, password_hash_hash))
98 			return -1;
99 	}
100 	if (get_master_key(password_hash_hash, nt_response, master_key))
101 		return -1;
102 	wpa_hexdump_key(MSG_DEBUG, "MSCHAPV2: Master Key",
103 			master_key, MSCHAPV2_MASTER_KEY_LEN);
104 
105 	return 0;
106 }
107 
108 
mschapv2_verify_auth_response(const u8 * auth_response,const u8 * buf,size_t buf_len)109 int mschapv2_verify_auth_response(const u8 *auth_response,
110 				  const u8 *buf, size_t buf_len)
111 {
112 	u8 recv_response[MSCHAPV2_AUTH_RESPONSE_LEN];
113 	if (buf_len < 2 + 2 * MSCHAPV2_AUTH_RESPONSE_LEN ||
114 	    buf[0] != 'S' || buf[1] != '=' ||
115 	    hexstr2bin((char *) (buf + 2), recv_response,
116 		       MSCHAPV2_AUTH_RESPONSE_LEN) ||
117 	    os_memcmp(auth_response, recv_response,
118 		      MSCHAPV2_AUTH_RESPONSE_LEN) != 0)
119 		return -1;
120 	return 0;
121 }
122 
123 #endif /* EAP_MSCHAPv2 */
124