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