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