EAP-TEAP server: Add support for requiring user and machine credentials

The new eap_teap_id=5 hostapd configuration parameter value can be used
to configure EAP-TEAP server to request and require user and machine
credentials within the tunnel. This can be done either with Basic
Password Authentication or with inner EAP authentication methods.

Signed-off-by: Jouni Malinen <j@w1.fi>
This commit is contained in:
Jouni Malinen 2019-08-24 16:48:34 +03:00
parent f380464257
commit 93cd29d2b8
3 changed files with 49 additions and 9 deletions

View file

@ -1212,6 +1212,7 @@ eap_server=0
# 2 = require machine identity # 2 = require machine identity
# 3 = request user identity; accept either user or machine identity # 3 = request user identity; accept either user or machine identity
# 4 = request machine identity; accept either user or machine identity # 4 = request machine identity; accept either user or machine identity
# 5 = require both user and machine identity
#eap_teap_id=0 #eap_teap_id=0
# EAP-SIM and EAP-AKA protected success/failure indication using AT_RESULT_IND # EAP-SIM and EAP-AKA protected success/failure indication using AT_RESULT_IND

View file

@ -204,6 +204,7 @@ struct eap_config {
EAP_TEAP_ID_REQUIRE_MACHINE = 2, EAP_TEAP_ID_REQUIRE_MACHINE = 2,
EAP_TEAP_ID_REQUEST_USER_ACCEPT_MACHINE = 3, EAP_TEAP_ID_REQUEST_USER_ACCEPT_MACHINE = 3,
EAP_TEAP_ID_REQUEST_MACHINE_ACCEPT_USER = 4, EAP_TEAP_ID_REQUEST_MACHINE_ACCEPT_USER = 4,
EAP_TEAP_ID_REQUIRE_USER_AND_MACHINE = 5,
} eap_teap_id; } eap_teap_id;
/** /**

View file

@ -56,6 +56,8 @@ struct eap_teap_data {
size_t srv_id_len; size_t srv_id_len;
char *srv_id_info; char *srv_id_info;
unsigned int basic_auth_not_done:1;
unsigned int inner_eap_not_done:1;
int anon_provisioning; int anon_provisioning;
int skipped_inner_auth; int skipped_inner_auth;
int send_new_pac; /* server triggered re-keying of Tunnel PAC */ int send_new_pac; /* server triggered re-keying of Tunnel PAC */
@ -71,6 +73,7 @@ struct eap_teap_data {
int pac_key_refresh_time; int pac_key_refresh_time;
enum teap_error_codes error_code; enum teap_error_codes error_code;
enum teap_identity_types cur_id_type;
}; };
@ -541,19 +544,27 @@ static struct wpabuf * eap_teap_build_phase2_req(struct eap_sm *sm,
break; break;
case EAP_TEAP_ID_REQUIRE_USER: case EAP_TEAP_ID_REQUIRE_USER:
case EAP_TEAP_ID_REQUEST_USER_ACCEPT_MACHINE: case EAP_TEAP_ID_REQUEST_USER_ACCEPT_MACHINE:
id_tlv = eap_teap_tlv_identity_type( data->cur_id_type = TEAP_IDENTITY_TYPE_USER;
TEAP_IDENTITY_TYPE_USER); id_tlv = eap_teap_tlv_identity_type(data->cur_id_type);
break; break;
case EAP_TEAP_ID_REQUIRE_MACHINE: case EAP_TEAP_ID_REQUIRE_MACHINE:
case EAP_TEAP_ID_REQUEST_MACHINE_ACCEPT_USER: case EAP_TEAP_ID_REQUEST_MACHINE_ACCEPT_USER:
id_tlv = eap_teap_tlv_identity_type( data->cur_id_type = TEAP_IDENTITY_TYPE_MACHINE;
TEAP_IDENTITY_TYPE_MACHINE); id_tlv = eap_teap_tlv_identity_type(data->cur_id_type);
break;
case EAP_TEAP_ID_REQUIRE_USER_AND_MACHINE:
if (data->cur_id_type == TEAP_IDENTITY_TYPE_USER)
data->cur_id_type = TEAP_IDENTITY_TYPE_MACHINE;
else
data->cur_id_type = TEAP_IDENTITY_TYPE_USER;
id_tlv = eap_teap_tlv_identity_type(data->cur_id_type);
break; break;
} }
} }
if (sm->cfg->eap_teap_auth == 1) { if (sm->cfg->eap_teap_auth == 1) {
wpa_printf(MSG_DEBUG, "EAP-TEAP: Initiate Basic-Password-Auth"); wpa_printf(MSG_DEBUG, "EAP-TEAP: Initiate Basic-Password-Auth");
data->basic_auth_not_done = 1;
req = wpabuf_alloc(sizeof(struct teap_tlv_hdr)); req = wpabuf_alloc(sizeof(struct teap_tlv_hdr));
if (!req) { if (!req) {
wpabuf_free(id_tlv); wpabuf_free(id_tlv);
@ -564,6 +575,7 @@ static struct wpabuf * eap_teap_build_phase2_req(struct eap_sm *sm,
} }
wpa_printf(MSG_DEBUG, "EAP-TEAP: Initiate inner EAP method"); wpa_printf(MSG_DEBUG, "EAP-TEAP: Initiate inner EAP method");
data->inner_eap_not_done = 1;
if (!data->phase2_priv) { if (!data->phase2_priv) {
wpa_printf(MSG_DEBUG, wpa_printf(MSG_DEBUG,
"EAP-TEAP: Phase 2 method not initialized"); "EAP-TEAP: Phase 2 method not initialized");
@ -596,12 +608,14 @@ static struct wpabuf * eap_teap_build_crypto_binding(
return NULL; return NULL;
if (data->send_new_pac || data->anon_provisioning || if (data->send_new_pac || data->anon_provisioning ||
data->basic_auth_not_done || data->inner_eap_not_done ||
data->phase2_method || sm->cfg->eap_teap_separate_result) data->phase2_method || sm->cfg->eap_teap_separate_result)
data->final_result = 0; data->final_result = 0;
else else
data->final_result = 1; data->final_result = 1;
if (!data->final_result || data->eap_seq > 0) { if (!data->final_result || data->eap_seq > 0 ||
sm->cfg->eap_teap_auth == 1) {
/* Intermediate-Result */ /* Intermediate-Result */
wpa_printf(MSG_DEBUG, wpa_printf(MSG_DEBUG,
"EAP-TEAP: Add Intermediate-Result TLV (status=SUCCESS)"); "EAP-TEAP: Add Intermediate-Result TLV (status=SUCCESS)");
@ -987,7 +1001,7 @@ static int eap_teap_phase2_init(struct eap_sm *sm, struct eap_teap_data *data,
} }
static int eap_teap_valid_id_type(struct eap_sm *sm, static int eap_teap_valid_id_type(struct eap_sm *sm, struct eap_teap_data *data,
enum teap_identity_types id_type) enum teap_identity_types id_type)
{ {
if (sm->cfg->eap_teap_id == EAP_TEAP_ID_REQUIRE_USER && if (sm->cfg->eap_teap_id == EAP_TEAP_ID_REQUIRE_USER &&
@ -996,6 +1010,9 @@ static int eap_teap_valid_id_type(struct eap_sm *sm,
if (sm->cfg->eap_teap_id == EAP_TEAP_ID_REQUIRE_MACHINE && if (sm->cfg->eap_teap_id == EAP_TEAP_ID_REQUIRE_MACHINE &&
id_type != TEAP_IDENTITY_TYPE_MACHINE) id_type != TEAP_IDENTITY_TYPE_MACHINE)
return 0; return 0;
if (sm->cfg->eap_teap_id == EAP_TEAP_ID_REQUIRE_USER_AND_MACHINE &&
id_type != data->cur_id_type)
return 0;
if (sm->cfg->eap_teap_id != EAP_TEAP_ID_ALLOW_ANY && if (sm->cfg->eap_teap_id != EAP_TEAP_ID_ALLOW_ANY &&
id_type != TEAP_IDENTITY_TYPE_USER && id_type != TEAP_IDENTITY_TYPE_USER &&
id_type != TEAP_IDENTITY_TYPE_MACHINE) id_type != TEAP_IDENTITY_TYPE_MACHINE)
@ -1086,7 +1103,7 @@ static void eap_teap_process_phase2_response(struct eap_sm *sm,
switch (data->state) { switch (data->state) {
case PHASE2_ID: case PHASE2_ID:
if (!eap_teap_valid_id_type(sm, id_type)) { if (!eap_teap_valid_id_type(sm, data, id_type)) {
wpa_printf(MSG_DEBUG, wpa_printf(MSG_DEBUG,
"EAP-TEAP: Provided Identity-Type %u not allowed", "EAP-TEAP: Provided Identity-Type %u not allowed",
id_type); id_type);
@ -1122,6 +1139,11 @@ static void eap_teap_process_phase2_response(struct eap_sm *sm,
case PHASE2_METHOD: case PHASE2_METHOD:
case CRYPTO_BINDING: case CRYPTO_BINDING:
eap_teap_update_icmk(sm, data); eap_teap_update_icmk(sm, data);
if (data->state == PHASE2_METHOD &&
(sm->cfg->eap_teap_id !=
EAP_TEAP_ID_REQUIRE_USER_AND_MACHINE ||
data->cur_id_type == TEAP_IDENTITY_TYPE_MACHINE))
data->inner_eap_not_done = 0;
eap_teap_state(data, CRYPTO_BINDING); eap_teap_state(data, CRYPTO_BINDING);
data->eap_seq++; data->eap_seq++;
next_vendor = EAP_VENDOR_IETF; next_vendor = EAP_VENDOR_IETF;
@ -1197,7 +1219,7 @@ static void eap_teap_process_basic_auth_resp(struct eap_sm *sm,
u8 *pos, *end, *username, *password, *new_id; u8 *pos, *end, *username, *password, *new_id;
u8 userlen, passlen; u8 userlen, passlen;
if (!eap_teap_valid_id_type(sm, id_type)) { if (!eap_teap_valid_id_type(sm, data, id_type)) {
wpa_printf(MSG_DEBUG, wpa_printf(MSG_DEBUG,
"EAP-TEAP: Provided Identity-Type %u not allowed", "EAP-TEAP: Provided Identity-Type %u not allowed",
id_type); id_type);
@ -1282,6 +1304,9 @@ static void eap_teap_process_basic_auth_resp(struct eap_sm *sm,
sm->identity = new_id; sm->identity = new_id;
sm->identity_len = userlen; sm->identity_len = userlen;
} }
if (sm->cfg->eap_teap_id != EAP_TEAP_ID_REQUIRE_USER_AND_MACHINE ||
data->cur_id_type == TEAP_IDENTITY_TYPE_MACHINE)
data->basic_auth_not_done = 0;
eap_teap_state(data, CRYPTO_BINDING); eap_teap_state(data, CRYPTO_BINDING);
eap_teap_update_icmk(sm, data); eap_teap_update_icmk(sm, data);
} }
@ -1618,6 +1643,19 @@ static void eap_teap_process_phase2_tlvs(struct eap_sm *sm,
wpa_printf(MSG_DEBUG, wpa_printf(MSG_DEBUG,
"EAP-TEAP: Peer agreed with final success - authentication completed"); "EAP-TEAP: Peer agreed with final success - authentication completed");
eap_teap_state(data, SUCCESS); eap_teap_state(data, SUCCESS);
} else if (check_crypto_binding && data->state == CRYPTO_BINDING &&
sm->cfg->eap_teap_auth == 1 && data->basic_auth_not_done) {
wpa_printf(MSG_DEBUG,
"EAP-TEAP: Continue with basic password authentication for second credential");
eap_teap_state(data, PHASE2_BASIC_AUTH);
} else if (check_crypto_binding && data->state == CRYPTO_BINDING &&
sm->cfg->eap_teap_auth == 0 && data->inner_eap_not_done) {
wpa_printf(MSG_DEBUG,
"EAP-TEAP: Continue with inner EAP authentication for second credential");
eap_teap_state(data, PHASE2_ID);
if (eap_teap_phase2_init(sm, data, EAP_VENDOR_IETF,
EAP_TYPE_IDENTITY) < 0)
eap_teap_state(data, FAILURE);
} }
} }