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 		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, auth_response);
     72 	} else {
     73 		wpa_hexdump_ascii_key(MSG_DEBUG, "MSCHAPV2: password",
     74 				      password, password_len);
     75 		generate_nt_response(auth_challenge, peer_challenge,
     76 				     username, username_len,
     77 				     password, password_len, nt_response);
     78 		generate_authenticator_response(password, password_len,
     79 						peer_challenge, auth_challenge,
     80 						username, username_len,
     81 						nt_response, auth_response);
     82 	}
     83 	wpa_hexdump(MSG_DEBUG, "MSCHAPV2: NT Response",
     84 		    nt_response, MSCHAPV2_NT_RESPONSE_LEN);
     85 	wpa_hexdump(MSG_DEBUG, "MSCHAPV2: Auth Response",
     86 		    auth_response, MSCHAPV2_AUTH_RESPONSE_LEN);
     87 
     88 	/* Generate master_key here since we have the needed data available. */
     89 	if (pwhash) {
     90 		if (hash_nt_password_hash(password, password_hash_hash))
     91 			return -1;
     92 	} else {
     93 		if (nt_password_hash(password, password_len, password_hash) ||
     94 		    hash_nt_password_hash(password_hash, password_hash_hash))
     95 			return -1;
     96 	}
     97 	get_master_key(password_hash_hash, nt_response, master_key);
     98 	wpa_hexdump_key(MSG_DEBUG, "MSCHAPV2: Master Key",
     99 			master_key, MSCHAPV2_MASTER_KEY_LEN);
    100 
    101 	return 0;
    102 }
    103 
    104 
    105 int mschapv2_verify_auth_response(const u8 *auth_response,
    106 				  const u8 *buf, size_t buf_len)
    107 {
    108 	u8 recv_response[MSCHAPV2_AUTH_RESPONSE_LEN];
    109 	if (buf_len < 2 + 2 * MSCHAPV2_AUTH_RESPONSE_LEN ||
    110 	    buf[0] != 'S' || buf[1] != '=' ||
    111 	    hexstr2bin((char *) (buf + 2), recv_response,
    112 		       MSCHAPV2_AUTH_RESPONSE_LEN) ||
    113 	    os_memcmp(auth_response, recv_response,
    114 		      MSCHAPV2_AUTH_RESPONSE_LEN) != 0)
    115 		return -1;
    116 	return 0;
    117 }
    118