1189251Ssam/* 2189251Ssam * MSCHAPV2 (RFC 2759) 3189251Ssam * Copyright (c) 2004-2008, Jouni Malinen <j@w1.fi> 4189251Ssam * 5252726Srpaulo * This software may be distributed under the terms of the BSD license. 6252726Srpaulo * See README for more details. 7189251Ssam */ 8189251Ssam 9189251Ssam#include "includes.h" 10189251Ssam 11189251Ssam#include "common.h" 12214734Srpaulo#include "crypto/ms_funcs.h" 13189251Ssam#include "mschapv2.h" 14189251Ssam 15189251Ssamconst u8 * mschapv2_remove_domain(const u8 *username, size_t *len) 16189251Ssam{ 17189251Ssam size_t i; 18189251Ssam 19189251Ssam /* 20189251Ssam * MSCHAPv2 does not include optional domain name in the 21189251Ssam * challenge-response calculation, so remove domain prefix 22189251Ssam * (if present). 23189251Ssam */ 24189251Ssam 25189251Ssam for (i = 0; i < *len; i++) { 26189251Ssam if (username[i] == '\\') { 27189251Ssam *len -= i + 1; 28189251Ssam return username + i + 1; 29189251Ssam } 30189251Ssam } 31189251Ssam 32189251Ssam return username; 33189251Ssam} 34189251Ssam 35189251Ssam 36214734Srpauloint mschapv2_derive_response(const u8 *identity, size_t identity_len, 37214734Srpaulo const u8 *password, size_t password_len, 38214734Srpaulo int pwhash, 39214734Srpaulo const u8 *auth_challenge, 40214734Srpaulo const u8 *peer_challenge, 41214734Srpaulo u8 *nt_response, u8 *auth_response, 42214734Srpaulo u8 *master_key) 43189251Ssam{ 44189251Ssam const u8 *username; 45189251Ssam size_t username_len; 46189251Ssam u8 password_hash[16], password_hash_hash[16]; 47189251Ssam 48189251Ssam wpa_hexdump_ascii(MSG_DEBUG, "MSCHAPV2: Identity", 49189251Ssam identity, identity_len); 50189251Ssam username_len = identity_len; 51189251Ssam username = mschapv2_remove_domain(identity, &username_len); 52189251Ssam wpa_hexdump_ascii(MSG_DEBUG, "MSCHAPV2: Username", 53189251Ssam username, username_len); 54189251Ssam 55189251Ssam wpa_hexdump(MSG_DEBUG, "MSCHAPV2: auth_challenge", 56189251Ssam auth_challenge, MSCHAPV2_CHAL_LEN); 57189251Ssam wpa_hexdump(MSG_DEBUG, "MSCHAPV2: peer_challenge", 58189251Ssam peer_challenge, MSCHAPV2_CHAL_LEN); 59189251Ssam wpa_hexdump_ascii(MSG_DEBUG, "MSCHAPV2: username", 60189251Ssam username, username_len); 61189251Ssam /* Authenticator response is not really needed yet, but calculate it 62189251Ssam * here so that challenges need not be saved. */ 63189251Ssam if (pwhash) { 64189251Ssam wpa_hexdump_key(MSG_DEBUG, "MSCHAPV2: password hash", 65189251Ssam password, password_len); 66252726Srpaulo if (generate_nt_response_pwhash(auth_challenge, peer_challenge, 67252726Srpaulo username, username_len, 68252726Srpaulo password, nt_response) || 69252726Srpaulo generate_authenticator_response_pwhash( 70252726Srpaulo password, peer_challenge, auth_challenge, 71252726Srpaulo username, username_len, nt_response, 72252726Srpaulo auth_response)) 73252726Srpaulo return -1; 74189251Ssam } else { 75189251Ssam wpa_hexdump_ascii_key(MSG_DEBUG, "MSCHAPV2: password", 76189251Ssam password, password_len); 77252726Srpaulo if (generate_nt_response(auth_challenge, peer_challenge, 78252726Srpaulo username, username_len, 79252726Srpaulo password, password_len, 80252726Srpaulo nt_response) || 81252726Srpaulo generate_authenticator_response(password, password_len, 82252726Srpaulo peer_challenge, 83252726Srpaulo auth_challenge, 84252726Srpaulo username, username_len, 85252726Srpaulo nt_response, 86252726Srpaulo auth_response)) 87252726Srpaulo return -1; 88189251Ssam } 89189251Ssam wpa_hexdump(MSG_DEBUG, "MSCHAPV2: NT Response", 90189251Ssam nt_response, MSCHAPV2_NT_RESPONSE_LEN); 91189251Ssam wpa_hexdump(MSG_DEBUG, "MSCHAPV2: Auth Response", 92189251Ssam auth_response, MSCHAPV2_AUTH_RESPONSE_LEN); 93189251Ssam 94189251Ssam /* Generate master_key here since we have the needed data available. */ 95189251Ssam if (pwhash) { 96214734Srpaulo if (hash_nt_password_hash(password, password_hash_hash)) 97214734Srpaulo return -1; 98189251Ssam } else { 99214734Srpaulo if (nt_password_hash(password, password_len, password_hash) || 100214734Srpaulo hash_nt_password_hash(password_hash, password_hash_hash)) 101214734Srpaulo return -1; 102189251Ssam } 103252726Srpaulo if (get_master_key(password_hash_hash, nt_response, master_key)) 104252726Srpaulo return -1; 105189251Ssam wpa_hexdump_key(MSG_DEBUG, "MSCHAPV2: Master Key", 106189251Ssam master_key, MSCHAPV2_MASTER_KEY_LEN); 107214734Srpaulo 108214734Srpaulo return 0; 109189251Ssam} 110189251Ssam 111189251Ssam 112189251Ssamint mschapv2_verify_auth_response(const u8 *auth_response, 113189251Ssam const u8 *buf, size_t buf_len) 114189251Ssam{ 115189251Ssam u8 recv_response[MSCHAPV2_AUTH_RESPONSE_LEN]; 116189251Ssam if (buf_len < 2 + 2 * MSCHAPV2_AUTH_RESPONSE_LEN || 117189251Ssam buf[0] != 'S' || buf[1] != '=' || 118189251Ssam hexstr2bin((char *) (buf + 2), recv_response, 119189251Ssam MSCHAPV2_AUTH_RESPONSE_LEN) || 120189251Ssam os_memcmp(auth_response, recv_response, 121189251Ssam MSCHAPV2_AUTH_RESPONSE_LEN) != 0) 122189251Ssam return -1; 123189251Ssam return 0; 124189251Ssam} 125