From e8de229223cb48dde46c2a63a615524d01e77f29 Mon Sep 17 00:00:00 2001 From: Tim Kourt Date: Tue, 23 Oct 2018 16:33:52 -0700 Subject: [PATCH] ttls: add support for tunneled MS-CHAP --- src/eap-ttls.c | 94 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 94 insertions(+) diff --git a/src/eap-ttls.c b/src/eap-ttls.c index 1adf3658..33bd06e8 100644 --- a/src/eap-ttls.c +++ b/src/eap-ttls.c @@ -30,6 +30,7 @@ #include #include "util.h" +#include "mschaputil.h" #include "eap.h" #include "eap-private.h" #include "eap-tls-common.h" @@ -47,6 +48,7 @@ enum radius_attr { RADIUS_ATTR_USER_NAME = 1, RADIUS_ATTR_USER_PASSWORD = 2, RADIUS_ATTR_CHAP_PASSWORD = 3, + RADIUS_ATTR_MS_CHAP_CHALLENGE = 11, RADIUS_ATTR_CHAP_CHALLENGE = 60, RADIUS_ATTR_EAP_MESSAGE = 79, }; @@ -222,6 +224,58 @@ static void build_avp_chap_password(struct avp_builder *builder, avp_builder_finalize_avp(builder); } +#define RADIUS_VENDOR_ID_MICROSOFT 311 +#define RADIUS_ATTR_MS_CHAP_RESPONSE 1 + +#define MS_CHAP_CHALLENGE_LEN 8 +#define MS_CHAP_LM_RESPONSE_LEN 24 +#define MS_CHAP_NT_RESPONSE_LEN 24 + +static void build_avp_ms_chap_challenge(struct avp_builder *builder, + const uint8_t *challenge) +{ + avp_builder_start_avp(builder, RADIUS_ATTR_MS_CHAP_CHALLENGE, true, + RADIUS_VENDOR_ID_MICROSOFT); + memcpy(avp_builder_reserve(builder, 1, MS_CHAP_CHALLENGE_LEN), + challenge, MS_CHAP_CHALLENGE_LEN); + avp_builder_finalize_avp(builder); +} + +static void build_avp_ms_chap_response(struct avp_builder *builder, + const uint8_t *ident, + const uint8_t *challenge, + const uint8_t *password_hash) +{ + uint8_t *flags; + uint8_t nt_challenge_response[NT_CHALLENGE_RESPONSE_LEN]; + + avp_builder_start_avp(builder, RADIUS_ATTR_MS_CHAP_RESPONSE, true, + RADIUS_VENDOR_ID_MICROSOFT); + + memcpy(avp_builder_reserve(builder, 1, CHAP_IDENT_LEN), + ident, CHAP_IDENT_LEN); + + /* + * RFC 2548: Section 2.1.3 + * + * The Flags field is set to one (0x01), the NT-Response field is to + * be used in preference to the LM-Response field for authentication. + */ + flags = avp_builder_reserve(builder, 1, 1); + *flags = 1; + + /* The LM-Response field is left empty */ + avp_builder_reserve(builder, 1, MS_CHAP_LM_RESPONSE_LEN); + + mschap_challenge_response(challenge, password_hash, + nt_challenge_response); + + memcpy(avp_builder_reserve(builder, 1, NT_CHALLENGE_RESPONSE_LEN), + nt_challenge_response, NT_CHALLENGE_RESPONSE_LEN); + + avp_builder_finalize_avp(builder); +} + struct avp_iter { enum radius_attr type; uint8_t flags; @@ -508,6 +562,45 @@ static struct phase2_method phase2_chap = { .destroy = eap_ttls_phase2_credentials_destroy, }; +static bool eap_ttls_phase2_ms_chap_init(struct eap_state *eap) +{ + struct eap_ttls_state *ttls = eap_get_data(eap); + struct phase2_credentials *credentials = ttls->phase2->state; + struct avp_builder *builder; + uint8_t challenge[MS_CHAP_CHALLENGE_LEN + CHAP_IDENT_LEN]; + uint8_t password_hash[16]; + uint8_t ident; + uint8_t *data; + size_t data_len; + + eap_ttls_phase2_chap_generate_challenge(ttls->tls, challenge, + MS_CHAP_CHALLENGE_LEN + + CHAP_IDENT_LEN); + + ident = challenge[MS_CHAP_CHALLENGE_LEN]; + + builder = avp_builder_new(512); + + build_avp_user_name(builder, credentials->username); + build_avp_ms_chap_challenge(builder, challenge); + + mschap_nt_password_hash(credentials->password, password_hash); + + build_avp_ms_chap_response(builder, &ident, challenge, password_hash); + + data = avp_builder_free(builder, false, &data_len); + + l_tls_write(ttls->tls, data, data_len); + l_free(data); + + return true; +} + +static struct phase2_method phase2_ms_chap = { + .init = eap_ttls_phase2_ms_chap_init, + .destroy = eap_ttls_phase2_credentials_destroy, +}; + static bool eap_ttls_phase2_pap_init(struct eap_state *eap) { struct eap_ttls_state *ttls = eap_get_data(eap); @@ -996,6 +1089,7 @@ static const struct { struct phase2_method *method; } tunneled_non_eap_methods[] = { { "Tunneled-CHAP", &phase2_chap }, + { "Tunneled-MSCHAP", &phase2_ms_chap }, { "Tunneled-PAP", &phase2_pap }, { } };