Add support for MS-CHAP v2.
git-svn-id: svn://svn.h5l.se/heimdal/trunk/heimdal@20114 ec53bebd-3082-4978-b11e-865c3cabbd6b
This commit is contained in:
152
kdc/digest.c
152
kdc/digest.c
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2006 Kungliga Tekniska H<>gskolan
|
||||
* Copyright (c) 2006 - 2007 Kungliga Tekniska H<>gskolan
|
||||
* (Royal Institute of Technology, Stockholm, Sweden).
|
||||
* All rights reserved.
|
||||
*
|
||||
@@ -36,6 +36,7 @@
|
||||
|
||||
RCSID("$Id$");
|
||||
|
||||
#define MS_CHAP_V2 0x20
|
||||
#define CHAP_MD5 0x10
|
||||
#define DIGEST_MD5 0x08
|
||||
#define NTLM_V2 0x04
|
||||
@@ -43,6 +44,7 @@ RCSID("$Id$");
|
||||
#define NTLM_V1 0x01
|
||||
|
||||
const struct units _kdc_digestunits[] = {
|
||||
{"ms-chap-v2", 1U << 5},
|
||||
{"chap-md5", 1U << 4},
|
||||
{"digest-md5", 1U << 3},
|
||||
{"ntlm-v2", 1U << 2},
|
||||
@@ -135,6 +137,23 @@ fill_targetinfo(krb5_context context,
|
||||
}
|
||||
|
||||
|
||||
static const unsigned char ms_chap_v1_magic1[39] = {
|
||||
0x4D, 0x61, 0x67, 0x69, 0x63, 0x20, 0x73, 0x65, 0x72, 0x76,
|
||||
0x65, 0x72, 0x20, 0x74, 0x6F, 0x20, 0x63, 0x6C, 0x69, 0x65,
|
||||
0x6E, 0x74, 0x20, 0x73, 0x69, 0x67, 0x6E, 0x69, 0x6E, 0x67,
|
||||
0x20, 0x63, 0x6F, 0x6E, 0x73, 0x74, 0x61, 0x6E, 0x74
|
||||
};
|
||||
static const unsigned char ms_chap_v1_magic2[41] = {
|
||||
0x50, 0x61, 0x64, 0x20, 0x74, 0x6F, 0x20, 0x6D, 0x61, 0x6B,
|
||||
0x65, 0x20, 0x69, 0x74, 0x20, 0x64, 0x6F, 0x20, 0x6D, 0x6F,
|
||||
0x72, 0x65, 0x20, 0x74, 0x68, 0x61, 0x6E, 0x20, 0x6F, 0x6E,
|
||||
0x65, 0x20, 0x69, 0x74, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6F,
|
||||
0x6E
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
/*
|
||||
*
|
||||
*/
|
||||
@@ -710,6 +729,137 @@ _kdc_do_digest(krb5_context context,
|
||||
goto out;
|
||||
}
|
||||
|
||||
} else if (strcasecmp(ireq.u.digestRequest.type, "MS-CHAP-V2") == 0) {
|
||||
unsigned char md[SHA_DIGEST_LENGTH], challange[SHA_DIGEST_LENGTH];
|
||||
const char *username;
|
||||
struct ntlm_buf answer;
|
||||
Key *key = NULL;
|
||||
SHA_CTX ctx;
|
||||
|
||||
if ((config->digests_allowed & MS_CHAP_V2) == 0) {
|
||||
kdc_log(context, config, 0, "MS-CHAP-V2 not allowed");
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (ireq.u.digestRequest.clientNonce == NULL) {
|
||||
krb5_set_error_string(context,
|
||||
"MS-CHAP-V2 clientNonce missing");
|
||||
ret = EINVAL;
|
||||
goto out;
|
||||
}
|
||||
if (serverNonce.length != 16) {
|
||||
krb5_set_error_string(context,
|
||||
"MS-CHAP-V2 serverNonce wrong length");
|
||||
ret = EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* strip of the domain component */
|
||||
username = strchr(ireq.u.digestRequest.username, '\\');
|
||||
if (username == NULL)
|
||||
username = ireq.u.digestRequest.username;
|
||||
else
|
||||
username++;
|
||||
|
||||
/* ChallangeHash */
|
||||
SHA1_Init(&ctx);
|
||||
{
|
||||
ssize_t ssize;
|
||||
krb5_data clientNonce;
|
||||
|
||||
clientNonce.length = strlen(*ireq.u.digestRequest.clientNonce);
|
||||
clientNonce.data = malloc(clientNonce.length);
|
||||
if (clientNonce.data == NULL) {
|
||||
ret = ENOMEM;
|
||||
krb5_set_error_string(context, "out of memory");
|
||||
goto out;
|
||||
}
|
||||
|
||||
ssize = hex_decode(*ireq.u.digestRequest.clientNonce,
|
||||
clientNonce.data, clientNonce.length);
|
||||
if (ssize != 16) {
|
||||
krb5_set_error_string(context,
|
||||
"Failed to decode clientNonce");
|
||||
ret = ENOMEM;
|
||||
goto out;
|
||||
}
|
||||
SHA1_Update(&ctx, clientNonce.data, clientNonce.length);
|
||||
free(clientNonce.data);
|
||||
}
|
||||
SHA1_Update(&ctx, serverNonce.data, serverNonce.length);
|
||||
SHA1_Update(&ctx, username, strlen(username));
|
||||
SHA1_Final(challange, &ctx);
|
||||
|
||||
/* NtPasswordHash */
|
||||
ret = krb5_parse_name(context, username, &clientprincipal);
|
||||
if (ret)
|
||||
goto out;
|
||||
|
||||
ret = _kdc_db_fetch(context, config, clientprincipal,
|
||||
HDB_F_GET_CLIENT, NULL, &user);
|
||||
krb5_free_principal(context, clientprincipal);
|
||||
if (ret) {
|
||||
krb5_set_error_string(context,
|
||||
"MS-CHAP-V2 user %s not in database",
|
||||
username);
|
||||
goto out;
|
||||
}
|
||||
|
||||
ret = hdb_enctype2key(context, &user->entry,
|
||||
ETYPE_ARCFOUR_HMAC_MD5, &key);
|
||||
if (ret) {
|
||||
krb5_set_error_string(context,
|
||||
"MS-CHAP-V2 missing arcfour key %s",
|
||||
username);
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* ChallengeResponse */
|
||||
ret = heim_ntlm_calculate_ntlm1(key->key.keyvalue.data,
|
||||
key->key.keyvalue.length,
|
||||
challange, &answer);
|
||||
if (ret) {
|
||||
krb5_set_error_string(context, "NTLM missing arcfour key");
|
||||
goto out;
|
||||
}
|
||||
|
||||
r.element = choice_DigestRepInner_response;
|
||||
hex_encode(answer.data, answer.length, &r.u.response.responseData);
|
||||
if (r.u.response.responseData == NULL) {
|
||||
free(answer.data);
|
||||
krb5_clear_error_string(context);
|
||||
ret = ENOMEM;
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* GenerateAuthenticatorResponse */
|
||||
SHA1_Init(&ctx);
|
||||
SHA1_Update(&ctx, key->key.keyvalue.data, key->key.keyvalue.length);
|
||||
SHA1_Update(&ctx, answer.data, answer.length);
|
||||
SHA1_Update(&ctx, ms_chap_v1_magic1, sizeof(ms_chap_v1_magic1));
|
||||
SHA1_Final(md, &ctx);
|
||||
free(answer.data);
|
||||
|
||||
SHA1_Init(&ctx);
|
||||
SHA1_Update(&ctx, md, sizeof(md));
|
||||
SHA1_Update(&ctx, challange, 8);
|
||||
SHA1_Update(&ctx, ms_chap_v1_magic2, sizeof(ms_chap_v1_magic2));
|
||||
SHA1_Final(md, &ctx);
|
||||
|
||||
r.u.response.rsp = calloc(1, sizeof(*r.u.response.rsp));
|
||||
if (r.u.response.rsp == NULL) {
|
||||
krb5_clear_error_string(context);
|
||||
ret = ENOMEM;
|
||||
goto out;
|
||||
}
|
||||
|
||||
hex_encode(md, sizeof(md), r.u.response.rsp);
|
||||
if (r.u.response.responseData == NULL) {
|
||||
krb5_clear_error_string(context);
|
||||
ret = ENOMEM;
|
||||
goto out;
|
||||
}
|
||||
|
||||
} else {
|
||||
r.element = choice_DigestRepInner_error;
|
||||
asprintf(&r.u.error.reason, "unsupported digest type %s",
|
||||
|
Reference in New Issue
Block a user