WPA_CTRL_REQ_EAP_PASSPHRASE,
WPA_CTRL_REQ_SIM,
WPA_CTRL_REQ_PSK_PASSPHRASE,
+ WPA_CTRL_REQ_EXT_CERT_CHECK,
NUM_WPA_CTRL_REQS
};
#define TLS_CONN_DISABLE_TLSv1_2 BIT(6)
#define TLS_CONN_EAP_FAST BIT(7)
#define TLS_CONN_DISABLE_TLSv1_0 BIT(8)
+#define TLS_CONN_EXT_CERT_CHECK BIT(9)
/**
* struct tls_connection_params - Parameters for TLS connection
if (conn == NULL || params == NULL)
return -1;
+ if (params->flags & TLS_CONN_EXT_CERT_CHECK) {
+ wpa_printf(MSG_INFO,
+ "GnuTLS: tls_ext_cert_check=1 not supported");
+ return -1;
+ }
+
if (params->subject_match) {
wpa_printf(MSG_INFO, "GnuTLS: subject_match not supported");
return -1;
if (conn->client == NULL)
return -1;
+ if (params->flags & TLS_CONN_EXT_CERT_CHECK) {
+ wpa_printf(MSG_INFO,
+ "TLS: tls_ext_cert_check=1 not supported");
+ return -1;
+ }
+
cred = tlsv1_cred_alloc();
if (cred == NULL)
return -1;
return;
os_memset(&ev, 0, sizeof(ev));
- if (conn->cert_probe || context->cert_in_cb) {
+ if (conn->cert_probe || (conn->flags & TLS_CONN_EXT_CERT_CHECK) ||
+ context->cert_in_cb) {
cert = get_x509_cert(err_cert);
ev.peer_cert.cert = cert;
}
}
#endif /* OPENSSL_IS_BORINGSSL */
- if (preverify_ok && context->event_cb != NULL)
+ if (depth == 0 && preverify_ok && context->event_cb != NULL)
context->event_cb(context->cb_ctx,
TLS_CERT_CHAIN_SUCCESS, NULL);
static const char * eap_sm_method_state_txt(EapMethodState state);
static const char * eap_sm_decision_txt(EapDecision decision);
#endif /* CONFIG_CTRL_IFACE || !CONFIG_NO_STDOUT_DEBUG */
+static void eap_sm_request(struct eap_sm *sm, enum wpa_ctrl_req_type field,
+ const char *msg, size_t msglen);
wpa_printf(MSG_DEBUG, "EAP: Initialize selected EAP method: "
"vendor %u method %u (%s)",
sm->reqVendor, method, sm->m->name);
- if (reinit)
+ if (reinit) {
sm->eap_method_priv = sm->m->init_for_reauth(
sm, sm->eap_method_priv);
- else
+ } else {
+ sm->waiting_ext_cert_check = 0;
+ sm->ext_cert_check = 0;
sm->eap_method_priv = sm->m->init(sm);
+ }
if (sm->eap_method_priv == NULL) {
struct eap_peer_config *config = eap_get_config(sm);
case TLS_CERT_CHAIN_SUCCESS:
eap_notify_status(sm, "remote certificate verification",
"success");
+ if (sm->ext_cert_check) {
+ sm->waiting_ext_cert_check = 1;
+ eap_sm_request(sm, WPA_CTRL_REQ_EXT_CERT_CHECK,
+ NULL, 0);
+ }
break;
case TLS_CERT_CHAIN_FAILURE:
wpa_msg(sm->msg_ctx, MSG_INFO, WPA_EVENT_EAP_TLS_CERT_ERROR
#endif /* CONFIG_CTRL_IFACE */
-#if defined(CONFIG_CTRL_IFACE) || !defined(CONFIG_NO_STDOUT_DEBUG)
static void eap_sm_request(struct eap_sm *sm, enum wpa_ctrl_req_type field,
const char *msg, size_t msglen)
{
+#if defined(CONFIG_CTRL_IFACE) || !defined(CONFIG_NO_STDOUT_DEBUG)
struct eap_peer_config *config;
const char *txt = NULL;
char *tmp;
case WPA_CTRL_REQ_SIM:
txt = msg;
break;
+ case WPA_CTRL_REQ_EXT_CERT_CHECK:
+ break;
default:
return;
}
if (sm->eapol_cb->eap_param_needed)
sm->eapol_cb->eap_param_needed(sm->eapol_ctx, field, txt);
-}
-#else /* CONFIG_CTRL_IFACE || !CONFIG_NO_STDOUT_DEBUG */
-#define eap_sm_request(sm, type, msg, msglen) do { } while (0)
#endif /* CONFIG_CTRL_IFACE || !CONFIG_NO_STDOUT_DEBUG */
+}
+
const char * eap_sm_get_method_name(struct eap_sm *sm)
{
* erp - Whether EAP Re-authentication Protocol (ERP) is enabled
*/
int erp;
+
+ /**
+ * pending_ext_cert_check - External server certificate check status
+ *
+ * This field should not be set in configuration step. It is only used
+ * internally when control interface is used to request external
+ * validation of server certificate chain.
+ */
+ enum {
+ NO_CHECK = 0,
+ PENDING_CHECK,
+ EXT_CERT_CHECK_GOOD,
+ EXT_CERT_CHECK_BAD,
+ } pending_ext_cert_check;
};
/*
* EAP peer method: EAP-FAST (RFC 4851)
- * Copyright (c) 2004-2008, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2004-2015, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
int simck_idx;
struct wpabuf *pending_phase2_req;
+ struct wpabuf *pending_resp;
};
os_memset(data->emsk, 0, EAP_EMSK_LEN);
os_free(data->session_id);
wpabuf_free(data->pending_phase2_req);
+ wpabuf_free(data->pending_resp);
os_free(data);
}
res = 1;
}
} else {
+ if (sm->waiting_ext_cert_check && data->pending_resp) {
+ struct eap_peer_config *config = eap_get_config(sm);
+
+ if (config->pending_ext_cert_check ==
+ EXT_CERT_CHECK_GOOD) {
+ wpa_printf(MSG_DEBUG,
+ "EAP-FAST: External certificate check succeeded - continue handshake");
+ resp = data->pending_resp;
+ data->pending_resp = NULL;
+ sm->waiting_ext_cert_check = 0;
+ return resp;
+ }
+
+ if (config->pending_ext_cert_check ==
+ EXT_CERT_CHECK_BAD) {
+ wpa_printf(MSG_DEBUG,
+ "EAP-FAST: External certificate check failed - force authentication failure");
+ ret->methodState = METHOD_DONE;
+ ret->decision = DECISION_FAIL;
+ sm->waiting_ext_cert_check = 0;
+ return NULL;
+ }
+
+ wpa_printf(MSG_DEBUG,
+ "EAP-FAST: Continuing to wait external server certificate validation");
+ return NULL;
+ }
+
/* Continue processing TLS handshake (phase 1). */
res = eap_peer_tls_process_helper(sm, &data->ssl,
EAP_TYPE_FAST,
return resp;
}
+ if (sm->waiting_ext_cert_check) {
+ wpa_printf(MSG_DEBUG,
+ "EAP-FAST: Waiting external server certificate validation");
+ wpabuf_free(data->pending_resp);
+ data->pending_resp = resp;
+ return NULL;
+ }
+
if (tls_connection_established(sm->ssl_ctx, data->ssl.conn)) {
char cipher[80];
wpa_printf(MSG_DEBUG,
data->key_block_p = NULL;
wpabuf_free(data->pending_phase2_req);
data->pending_phase2_req = NULL;
+ wpabuf_free(data->pending_resp);
+ data->pending_resp = NULL;
}
int external_sim;
unsigned int expected_failure:1;
+ unsigned int ext_cert_check:1;
+ unsigned int waiting_ext_cert_check:1;
struct dl_list erp_keys; /* struct eap_erp_key */
};
/*
* EAP peer method: EAP-PEAP (draft-josefsson-pppext-eap-tls-eap-10.txt)
- * Copyright (c) 2004-2008, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2004-2015, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
size_t id_len;
struct wpabuf *pending_phase2_req;
+ struct wpabuf *pending_resp;
enum { NO_BINDING, OPTIONAL_BINDING, REQUIRE_BINDING } crypto_binding;
int crypto_binding_used;
u8 binding_nonce[32];
eap_peap_free_key(data);
os_free(data->session_id);
wpabuf_free(data->pending_phase2_req);
+ wpabuf_free(data->pending_resp);
os_free(data);
}
!data->resuming) {
res = eap_peap_decrypt(sm, data, ret, req, &msg, &resp);
} else {
+ if (sm->waiting_ext_cert_check && data->pending_resp) {
+ struct eap_peer_config *config = eap_get_config(sm);
+
+ if (config->pending_ext_cert_check ==
+ EXT_CERT_CHECK_GOOD) {
+ wpa_printf(MSG_DEBUG,
+ "EAP-PEAP: External certificate check succeeded - continue handshake");
+ resp = data->pending_resp;
+ data->pending_resp = NULL;
+ sm->waiting_ext_cert_check = 0;
+ return resp;
+ }
+
+ if (config->pending_ext_cert_check ==
+ EXT_CERT_CHECK_BAD) {
+ wpa_printf(MSG_DEBUG,
+ "EAP-PEAP: External certificate check failed - force authentication failure");
+ ret->methodState = METHOD_DONE;
+ ret->decision = DECISION_FAIL;
+ sm->waiting_ext_cert_check = 0;
+ return NULL;
+ }
+
+ wpa_printf(MSG_DEBUG,
+ "EAP-PEAP: Continuing to wait external server certificate validation");
+ return NULL;
+ }
+
res = eap_peer_tls_process_helper(sm, &data->ssl,
EAP_TYPE_PEAP,
data->peap_version, id, &msg,
ret->decision = DECISION_FAIL;
return resp;
}
+
+
+ if (sm->waiting_ext_cert_check) {
+ wpa_printf(MSG_DEBUG,
+ "EAP-PEAP: Waiting external server certificate validation");
+ wpabuf_free(data->pending_resp);
+ data->pending_resp = resp;
+ return NULL;
+ }
+
if (tls_connection_established(sm->ssl_ctx, data->ssl.conn)) {
char *label;
wpa_printf(MSG_DEBUG,
struct eap_peap_data *data = priv;
wpabuf_free(data->pending_phase2_req);
data->pending_phase2_req = NULL;
+ wpabuf_free(data->pending_resp);
+ data->pending_resp = NULL;
data->crypto_binding_used = 0;
}
/*
* EAP peer method: EAP-TLS (RFC 2716)
- * Copyright (c) 2004-2008, 2012, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2004-2008, 2012-2015, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
size_t id_len;
void *ssl_ctx;
u8 eap_type;
+ struct wpabuf *pending_resp;
};
eap_peer_tls_ssl_deinit(sm, &data->ssl);
eap_tls_free_key(data);
os_free(data->session_id);
+ wpabuf_free(data->pending_resp);
os_free(data);
}
struct eap_tls_data *data = priv;
struct wpabuf msg;
+ if (sm->waiting_ext_cert_check && data->pending_resp) {
+ struct eap_peer_config *config = eap_get_config(sm);
+
+ if (config->pending_ext_cert_check == EXT_CERT_CHECK_GOOD) {
+ wpa_printf(MSG_DEBUG,
+ "EAP-TLS: External certificate check succeeded - continue handshake");
+ resp = data->pending_resp;
+ data->pending_resp = NULL;
+ sm->waiting_ext_cert_check = 0;
+ return resp;
+ }
+
+ if (config->pending_ext_cert_check == EXT_CERT_CHECK_BAD) {
+ wpa_printf(MSG_DEBUG,
+ "EAP-TLS: External certificate check failed - force authentication failure");
+ ret->methodState = METHOD_DONE;
+ ret->decision = DECISION_FAIL;
+ sm->waiting_ext_cert_check = 0;
+ return NULL;
+ }
+
+ wpa_printf(MSG_DEBUG,
+ "EAP-TLS: Continuing to wait external server certificate validation");
+ return NULL;
+ }
+
pos = eap_peer_tls_process_init(sm, &data->ssl, data->eap_type, ret,
reqData, &left, &flags);
if (pos == NULL)
return eap_tls_failure(sm, data, ret, res, resp, id);
}
+ if (sm->waiting_ext_cert_check) {
+ wpa_printf(MSG_DEBUG,
+ "EAP-TLS: Waiting external server certificate validation");
+ wpabuf_free(data->pending_resp);
+ data->pending_resp = resp;
+ return NULL;
+ }
+
if (tls_connection_established(data->ssl_ctx, data->ssl.conn))
eap_tls_success(sm, data, ret);
static void eap_tls_deinit_for_reauth(struct eap_sm *sm, void *priv)
{
+ struct eap_tls_data *data = priv;
+
+ wpabuf_free(data->pending_resp);
+ data->pending_resp = NULL;
}
params->flags |= TLS_CONN_DISABLE_TLSv1_2;
if (os_strstr(txt, "tls_disable_tlsv1_2=0"))
params->flags &= ~TLS_CONN_DISABLE_TLSv1_2;
+ if (os_strstr(txt, "tls_ext_cert_check=1"))
+ params->flags |= TLS_CONN_EXT_CERT_CHECK;
+ if (os_strstr(txt, "tls_ext_cert_check=0"))
+ params->flags &= ~TLS_CONN_EXT_CERT_CHECK;
}
params->openssl_ciphers = config->openssl_ciphers;
+ sm->ext_cert_check = !!(params->flags & TLS_CONN_EXT_CERT_CHECK);
+
return 0;
}
/*
* EAP peer method: EAP-TTLS (RFC 5281)
- * Copyright (c) 2004-2011, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2004-2015, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
size_t id_len;
struct wpabuf *pending_phase2_req;
+ struct wpabuf *pending_resp;
#ifdef EAP_TNC
int ready_for_tnc;
eap_ttls_free_key(data);
os_free(data->session_id);
wpabuf_free(data->pending_phase2_req);
+ wpabuf_free(data->pending_resp);
os_free(data);
}
{
int res;
+ if (sm->waiting_ext_cert_check && data->pending_resp) {
+ struct eap_peer_config *config = eap_get_config(sm);
+
+ if (config->pending_ext_cert_check == EXT_CERT_CHECK_GOOD) {
+ wpa_printf(MSG_DEBUG,
+ "EAP-TTLS: External certificate check succeeded - continue handshake");
+ *out_data = data->pending_resp;
+ data->pending_resp = NULL;
+ sm->waiting_ext_cert_check = 0;
+ return 0;
+ }
+
+ if (config->pending_ext_cert_check == EXT_CERT_CHECK_BAD) {
+ wpa_printf(MSG_DEBUG,
+ "EAP-TTLS: External certificate check failed - force authentication failure");
+ ret->methodState = METHOD_DONE;
+ ret->decision = DECISION_FAIL;
+ sm->waiting_ext_cert_check = 0;
+ return 0;
+ }
+
+ wpa_printf(MSG_DEBUG,
+ "EAP-TTLS: Continuing to wait external server certificate validation");
+ return 0;
+ }
+
res = eap_peer_tls_process_helper(sm, &data->ssl, EAP_TYPE_TTLS,
data->ttls_version, identifier,
in_data, out_data);
return -1;
}
+ if (sm->waiting_ext_cert_check) {
+ wpa_printf(MSG_DEBUG,
+ "EAP-TTLS: Waiting external server certificate validation");
+ wpabuf_free(data->pending_resp);
+ data->pending_resp = *out_data;
+ *out_data = NULL;
+ return 0;
+ }
+
if (tls_connection_established(sm->ssl_ctx, data->ssl.conn)) {
wpa_printf(MSG_DEBUG, "EAP-TTLS: TLS done, proceed to "
"Phase 2");
struct eap_ttls_data *data = priv;
wpabuf_free(data->pending_phase2_req);
data->pending_phase2_req = NULL;
+ wpabuf_free(data->pending_resp);
+ data->pending_resp = NULL;
#ifdef EAP_TNC
data->ready_for_tnc = 0;
data->tnc_started = 0;
if (wpa_s->wpa_state == WPA_SCANNING && !wpa_s->scanning)
wpa_supplicant_req_scan(wpa_s, 0, 0);
break;
+ case WPA_CTRL_REQ_EXT_CERT_CHECK:
+ if (eap->pending_ext_cert_check != PENDING_CHECK)
+ return -1;
+ if (os_strcmp(value, "good") == 0)
+ eap->pending_ext_cert_check = EXT_CERT_CHECK_GOOD;
+ else if (os_strcmp(value, "bad") == 0)
+ eap->pending_ext_cert_check = EXT_CERT_CHECK_BAD;
+ else
+ return -1;
+ break;
default:
wpa_printf(MSG_DEBUG, "CTRL_IFACE: Unknown field '%s'", field);
return -1;
# that have issues interoperating with updated TLS version)
# tls_disable_tlsv1_2=1 - disable use of TLSv1.2 (a workaround for AAA servers
# that have issues interoperating with updated TLS version)
+# tls_ext_cert_check=0 - No external server certificate validation (default)
+# tls_ext_cert_check=1 - External server certificate validation enabled; this
+# requires an external program doing validation of server certificate
+# chain when receiving CTRL-RSP-EXT_CERT_CHECK event from the control
+# interface and report the result of the validation with
+# CTRL-RSP_EXT_CERT_CHECK.
#
# Following certificate/private key fields are used in inner Phase2
# authentication when using EAP-TTLS or EAP-PEAP.
return WPA_CTRL_REQ_SIM;
else if (os_strcmp(field, "PSK_PASSPHRASE") == 0)
return WPA_CTRL_REQ_PSK_PASSPHRASE;
+ else if (os_strcmp(field, "EXT_CERT_CHECK") == 0)
+ return WPA_CTRL_REQ_EXT_CERT_CHECK;
return WPA_CTRL_REQ_UNKNOWN;
}
*txt = "PSK or passphrase";
ret = "PSK_PASSPHRASE";
break;
+ case WPA_CTRL_REQ_EXT_CERT_CHECK:
+ *txt = "External server certificate validation";
+ ret = "EXT_CERT_CHECK";
+ break;
default:
break;
}
if (ssid == NULL)
return;
+ if (field == WPA_CTRL_REQ_EXT_CERT_CHECK)
+ ssid->eap.pending_ext_cert_check = PENDING_CHECK;
wpas_notify_network_request(wpa_s, ssid, field, default_txt);
field_name = wpa_supplicant_ctrl_req_to_string(field, default_txt,