EAP-MSCHAPv2 can use stored NT hashes in addition to plaintext passwords
This commit is contained in:
parent
d266e8953e
commit
a7fb418edd
|
@ -1,5 +1,6 @@
|
|||
/*
|
||||
* Copyright (C) 2009 Tobias Brunner
|
||||
* Copyright (C) 2010 Martin Willi
|
||||
* Hochschule fuer Technik Rapperswil
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
|
@ -460,37 +461,31 @@ static status_t GenerateMSK(chunk_t password_hash_hash,
|
|||
|
||||
static status_t GenerateStuff(private_eap_mschapv2_t *this,
|
||||
chunk_t server_challenge, chunk_t peer_challenge,
|
||||
chunk_t username, chunk_t password)
|
||||
chunk_t username, chunk_t nt_hash)
|
||||
{
|
||||
status_t status = FAILED;
|
||||
chunk_t password_hash = chunk_empty, password_hash_hash = chunk_empty,
|
||||
challenge_hash = chunk_empty;
|
||||
chunk_t nt_hash_hash = chunk_empty, challenge_hash = chunk_empty;
|
||||
|
||||
if (NtPasswordHash(password, &password_hash) != SUCCESS)
|
||||
{
|
||||
goto error;
|
||||
}
|
||||
if (NtPasswordHash(password_hash, &password_hash_hash) != SUCCESS)
|
||||
if (NtPasswordHash(nt_hash, &nt_hash_hash) != SUCCESS)
|
||||
{
|
||||
goto error;
|
||||
}
|
||||
if (ChallengeHash(peer_challenge, server_challenge, username,
|
||||
&challenge_hash) != SUCCESS)
|
||||
&challenge_hash) != SUCCESS)
|
||||
{
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (ChallengeResponse(challenge_hash, password_hash,
|
||||
&this->nt_response) != SUCCESS)
|
||||
if (ChallengeResponse(challenge_hash, nt_hash,
|
||||
&this->nt_response) != SUCCESS)
|
||||
{
|
||||
goto error;
|
||||
}
|
||||
if (AuthenticatorResponse(password_hash_hash, challenge_hash,
|
||||
this->nt_response, &this->auth_response) != SUCCESS)
|
||||
if (AuthenticatorResponse(nt_hash_hash, challenge_hash,
|
||||
this->nt_response, &this->auth_response) != SUCCESS)
|
||||
{
|
||||
goto error;
|
||||
}
|
||||
if (GenerateMSK(password_hash_hash, this->nt_response, &this->msk) != SUCCESS)
|
||||
if (GenerateMSK(nt_hash_hash, this->nt_response, &this->msk) != SUCCESS)
|
||||
{
|
||||
goto error;
|
||||
}
|
||||
|
@ -498,8 +493,7 @@ static status_t GenerateStuff(private_eap_mschapv2_t *this,
|
|||
status = SUCCESS;
|
||||
|
||||
error:
|
||||
chunk_free(&password_hash);
|
||||
chunk_free(&password_hash_hash);
|
||||
chunk_free(&nt_hash_hash);
|
||||
chunk_free(&challenge_hash);
|
||||
return status;
|
||||
}
|
||||
|
@ -613,6 +607,39 @@ static status_t initiate_server(private_eap_mschapv2_t *this, eap_payload_t **ou
|
|||
return NEED_MORE;
|
||||
}
|
||||
|
||||
static bool get_nt_hash(private_eap_mschapv2_t *this, identification_t *me,
|
||||
identification_t *other, chunk_t *nt_hash)
|
||||
{
|
||||
shared_key_t *shared;
|
||||
chunk_t password;
|
||||
|
||||
/* try to find a stored NT_HASH first */
|
||||
shared = charon->credentials->get_shared(charon->credentials,
|
||||
SHARED_NT_HASH, me, other);
|
||||
if (shared )
|
||||
{
|
||||
*nt_hash = chunk_clone(shared->get_key(shared));
|
||||
shared->destroy(shared);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/* fallback to plaintext password */
|
||||
shared = charon->credentials->get_shared(charon->credentials,
|
||||
SHARED_EAP, me, other);
|
||||
if (shared)
|
||||
{
|
||||
password = ascii_to_unicode(shared->get_key(shared));
|
||||
shared->destroy(shared);
|
||||
|
||||
if (NtPasswordHash(password, nt_hash) == SUCCESS)
|
||||
{
|
||||
chunk_clear(&password);
|
||||
return TRUE;
|
||||
}
|
||||
chunk_clear(&password);
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Process MS-CHAPv2 Challenge Requests
|
||||
|
@ -624,8 +651,7 @@ static status_t process_peer_challenge(private_eap_mschapv2_t *this,
|
|||
eap_mschapv2_header_t *eap;
|
||||
eap_mschapv2_challenge_t *cha;
|
||||
eap_mschapv2_response_t *res;
|
||||
shared_key_t *shared;
|
||||
chunk_t data, peer_challenge, username, password;
|
||||
chunk_t data, peer_challenge, username, nt_hash;
|
||||
u_int16_t len = RESPONSE_PAYLOAD_LEN;
|
||||
|
||||
data = in->get_data(in);
|
||||
|
@ -660,28 +686,24 @@ static status_t process_peer_challenge(private_eap_mschapv2_t *this,
|
|||
rng->get_bytes(rng, CHALLENGE_LEN, peer_challenge.ptr);
|
||||
rng->destroy(rng);
|
||||
|
||||
shared = charon->credentials->get_shared(charon->credentials,
|
||||
SHARED_EAP, this->peer, this->server);
|
||||
if (shared == NULL)
|
||||
if (!get_nt_hash(this, this->peer, this->server, &nt_hash))
|
||||
{
|
||||
DBG1(DBG_IKE, "no EAP key found for hosts '%Y' - '%Y'",
|
||||
this->server, this->peer);
|
||||
return NOT_FOUND;
|
||||
}
|
||||
|
||||
password = ascii_to_unicode(shared->get_key(shared));
|
||||
shared->destroy(shared);
|
||||
|
||||
username = extract_username(this->peer);
|
||||
len += username.len;
|
||||
|
||||
if (GenerateStuff(this, this->challenge, peer_challenge, username, password) != SUCCESS)
|
||||
if (GenerateStuff(this, this->challenge, peer_challenge,
|
||||
username, nt_hash) != SUCCESS)
|
||||
{
|
||||
DBG1(DBG_IKE, "EAP-MS-CHAPv2 generating NT-Response failed");
|
||||
chunk_clear(&password);
|
||||
chunk_clear(&nt_hash);
|
||||
return FAILED;
|
||||
}
|
||||
chunk_clear(&password);
|
||||
chunk_clear(&nt_hash);
|
||||
|
||||
eap = alloca(len);
|
||||
eap->code = EAP_RESPONSE;
|
||||
|
@ -995,9 +1017,8 @@ static status_t process_server_response(private_eap_mschapv2_t *this,
|
|||
{
|
||||
eap_mschapv2_header_t *eap;
|
||||
eap_mschapv2_response_t *res;
|
||||
chunk_t data, peer_challenge, username, password;
|
||||
chunk_t data, peer_challenge, username, nt_hash;
|
||||
identification_t *userid;
|
||||
shared_key_t *shared;
|
||||
int name_len;
|
||||
char buf[256];
|
||||
|
||||
|
@ -1019,9 +1040,7 @@ static status_t process_server_response(private_eap_mschapv2_t *this,
|
|||
DBG2(DBG_IKE, "EAP-MS-CHAPv2 username: '%Y'", userid);
|
||||
username = extract_username(userid);
|
||||
|
||||
shared = charon->credentials->get_shared(charon->credentials,
|
||||
SHARED_EAP, this->server, userid);
|
||||
if (shared == NULL)
|
||||
if (!get_nt_hash(this, this->server, userid, &nt_hash))
|
||||
{
|
||||
DBG1(DBG_IKE, "no EAP key found for hosts '%Y' - '%Y'",
|
||||
this->server, userid);
|
||||
|
@ -1035,21 +1054,19 @@ static status_t process_server_response(private_eap_mschapv2_t *this,
|
|||
return process_server_retry(this, out);
|
||||
}
|
||||
|
||||
password = ascii_to_unicode(shared->get_key(shared));
|
||||
shared->destroy(shared);
|
||||
|
||||
if (GenerateStuff(this, this->challenge, peer_challenge,
|
||||
username, password) != SUCCESS)
|
||||
username, nt_hash) != SUCCESS)
|
||||
{
|
||||
DBG1(DBG_IKE, "EAP-MS-CHAPv2 verification failed");
|
||||
userid->destroy(userid);
|
||||
chunk_clear(&password);
|
||||
chunk_clear(&nt_hash);
|
||||
return FAILED;
|
||||
}
|
||||
userid->destroy(userid);
|
||||
chunk_clear(&password);
|
||||
chunk_clear(&nt_hash);
|
||||
|
||||
if (memeq(res->response.nt_response, this->nt_response.ptr, this->nt_response.len))
|
||||
if (memeq(res->response.nt_response, this->nt_response.ptr,
|
||||
this->nt_response.len))
|
||||
{
|
||||
chunk_t hex;
|
||||
char msg[AUTH_RESPONSE_LEN + sizeof(SUCCESS_MESSAGE)];
|
||||
|
|
|
@ -41,6 +41,8 @@ enum shared_key_type_t {
|
|||
SHARED_PRIVATE_KEY_PASS,
|
||||
/** PIN to unlock a smartcard */
|
||||
SHARED_PIN,
|
||||
/** Calculated NT Hash = MD4(UTF-16LE(password)) */
|
||||
SHARED_NT_HASH,
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
Loading…
Reference in New Issue