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