From dd7fec1f2969c377ac895246edd34c13986ebb08 Mon Sep 17 00:00:00 2001 From: Paul Stewart Date: Mon, 4 Jun 2012 21:10:01 +0300 Subject: [PATCH] wpa_supplicant: Report EAP connection progress to DBus Send an "EAP" signal via the new DBus interface under various conditions during EAP authentication: - During method selection (ACK and NAK) - During certificate verification - While sending and receiving TLS alert messages - EAP success and failure messages This provides DBus callers a number of new tools: - The ability to probe an AP for available EAP methods (given an identity). - The ability to identify why the remote certificate was not verified. - The ability to identify why the remote peer refused a TLS connection. Signed-hostap: Paul Stewart --- src/crypto/tls.h | 10 +++++++- src/crypto/tls_openssl.c | 13 +++++++++++ src/eap_peer/eap.c | 35 +++++++++++++++++++++++++++- src/eap_peer/eap.h | 9 ++++++++ src/eapol_supp/eapol_supp_sm.c | 14 +++++++++++- src/eapol_supp/eapol_supp_sm.h | 9 ++++++++ wpa_supplicant/dbus/dbus_new.c | 42 ++++++++++++++++++++++++++++++++++ wpa_supplicant/dbus/dbus_new.h | 8 +++++++ wpa_supplicant/notify.c | 7 ++++++ wpa_supplicant/notify.h | 2 ++ wpa_supplicant/wpas_glue.c | 10 ++++++++ 11 files changed, 156 insertions(+), 3 deletions(-) diff --git a/src/crypto/tls.h b/src/crypto/tls.h index 2bd3bbbb0..990f6e6ed 100644 --- a/src/crypto/tls.h +++ b/src/crypto/tls.h @@ -21,8 +21,10 @@ struct tls_keys { }; enum tls_event { + TLS_CERT_CHAIN_SUCCESS, TLS_CERT_CHAIN_FAILURE, - TLS_PEER_CERTIFICATE + TLS_PEER_CERTIFICATE, + TLS_ALERT }; /* @@ -57,6 +59,12 @@ union tls_event_data { const u8 *hash; size_t hash_len; } peer_cert; + + struct { + int is_local; + const char *type; + const char *description; + } alert; }; struct tls_config { diff --git a/src/crypto/tls_openssl.c b/src/crypto/tls_openssl.c index 772f0b2f1..3bbd45706 100644 --- a/src/crypto/tls_openssl.c +++ b/src/crypto/tls_openssl.c @@ -525,6 +525,15 @@ static void ssl_info_cb(const SSL *ssl, int where, int ret) else conn->write_alerts++; } + if (tls_global->event_cb != NULL) { + union tls_event_data ev; + os_memset(&ev, 0, sizeof(ev)); + ev.alert.is_local = !(where & SSL_CB_READ); + ev.alert.type = SSL_alert_type_string_long(ret); + ev.alert.description = SSL_alert_desc_string_long(ret); + tls_global->event_cb(tls_global->cb_ctx, TLS_ALERT, + &ev); + } } else if (where & SSL_CB_EXIT && ret <= 0) { wpa_printf(MSG_DEBUG, "SSL: %s:%s in %s", str, ret == 0 ? "failed" : "error", @@ -1265,6 +1274,10 @@ static int tls_verify_cb(int preverify_ok, X509_STORE_CTX *x509_ctx) TLS_FAIL_SERVER_CHAIN_PROBE); } + if (preverify_ok && tls_global->event_cb != NULL) + tls_global->event_cb(tls_global->cb_ctx, + TLS_CERT_CHAIN_SUCCESS, NULL); + return preverify_ok; } diff --git a/src/eap_peer/eap.c b/src/eap_peer/eap.c index 50a779786..8b43be438 100644 --- a/src/eap_peer/eap.c +++ b/src/eap_peer/eap.c @@ -81,6 +81,16 @@ static struct wpabuf * eapol_get_eapReqData(struct eap_sm *sm) } +static void eap_notify_status(struct eap_sm *sm, const char *status, + const char *parameter) +{ + wpa_printf(MSG_DEBUG, "EAP: Status notification: %s (param=%s)", + status, parameter); + if (sm->eapol_cb->notify_status) + sm->eapol_cb->notify_status(sm->eapol_ctx, status, parameter); +} + + static void eap_deinit_prev_method(struct eap_sm *sm, const char *txt) { if (sm->m == NULL || sm->eap_method_priv == NULL) @@ -213,6 +223,7 @@ SM_STATE(EAP, GET_METHOD) { int reinit; EapType method; + const struct eap_method *eap_method; SM_ENTRY(EAP, GET_METHOD); @@ -221,18 +232,24 @@ SM_STATE(EAP, GET_METHOD) else method = sm->reqMethod; + eap_method = eap_peer_get_eap_method(sm->reqVendor, method); + if (!eap_sm_allowMethod(sm, sm->reqVendor, method)) { wpa_printf(MSG_DEBUG, "EAP: vendor %u method %u not allowed", sm->reqVendor, method); wpa_msg(sm->msg_ctx, MSG_INFO, WPA_EVENT_EAP_PROPOSED_METHOD "vendor=%u method=%u -> NAK", sm->reqVendor, method); + eap_notify_status(sm, "refuse proposed method", + eap_method ? eap_method->name : "unknown"); goto nak; } wpa_msg(sm->msg_ctx, MSG_INFO, WPA_EVENT_EAP_PROPOSED_METHOD "vendor=%u method=%u", sm->reqVendor, method); + eap_notify_status(sm, "accept proposed method", + eap_method ? eap_method->name : "unknown"); /* * RFC 4137 does not define specific operation for fast * re-authentication (session resumption). The design here is to allow @@ -256,7 +273,7 @@ SM_STATE(EAP, GET_METHOD) sm->selectedMethod = sm->reqMethod; if (sm->m == NULL) - sm->m = eap_peer_get_eap_method(sm->reqVendor, method); + sm->m = eap_method; if (!sm->m) { wpa_printf(MSG_DEBUG, "EAP: Could not find selected method: " "vendor %d method %d", @@ -1235,10 +1252,12 @@ static void eap_sm_parseEapReq(struct eap_sm *sm, const struct wpabuf *req) break; case EAP_CODE_SUCCESS: wpa_printf(MSG_DEBUG, "EAP: Received EAP-Success"); + eap_notify_status(sm, "completion", "success"); sm->rxSuccess = TRUE; break; case EAP_CODE_FAILURE: wpa_printf(MSG_DEBUG, "EAP: Received EAP-Failure"); + eap_notify_status(sm, "completion", "failure"); sm->rxFailure = TRUE; break; default: @@ -1256,6 +1275,10 @@ static void eap_peer_sm_tls_event(void *ctx, enum tls_event ev, char *hash_hex = NULL; switch (ev) { + case TLS_CERT_CHAIN_SUCCESS: + eap_notify_status(sm, "remote certificate verification", + "success"); + break; case TLS_CERT_CHAIN_FAILURE: wpa_msg(sm->msg_ctx, MSG_INFO, WPA_EVENT_EAP_TLS_CERT_ERROR "reason=%d depth=%d subject='%s' err='%s'", @@ -1263,6 +1286,8 @@ static void eap_peer_sm_tls_event(void *ctx, enum tls_event ev, data->cert_fail.depth, data->cert_fail.subject, data->cert_fail.reason_txt); + eap_notify_status(sm, "remote certificate verification", + data->cert_fail.reason_txt); break; case TLS_PEER_CERTIFICATE: if (!sm->eapol_cb->notify_cert) @@ -1283,6 +1308,14 @@ static void eap_peer_sm_tls_event(void *ctx, enum tls_event ev, data->peer_cert.subject, hash_hex, data->peer_cert.cert); break; + case TLS_ALERT: + if (data->alert.is_local) + eap_notify_status(sm, "local TLS alert", + data->alert.description); + else + eap_notify_status(sm, "remote TLS alert", + data->alert.description); + break; } os_free(hash_hex); diff --git a/src/eap_peer/eap.h b/src/eap_peer/eap.h index b95a285e5..6e87475d3 100644 --- a/src/eap_peer/eap.h +++ b/src/eap_peer/eap.h @@ -226,6 +226,15 @@ struct eapol_callbacks { */ void (*notify_cert)(void *ctx, int depth, const char *subject, const char *cert_hash, const struct wpabuf *cert); + + /** + * notify_status - Notification of the current EAP state + * @ctx: eapol_ctx from eap_peer_sm_init() call + * @status: Step in the process of EAP authentication + * @parameter: Step-specific parameter, e.g., EAP method name + */ + void (*notify_status)(void *ctx, const char *status, + const char *parameter); }; /** diff --git a/src/eapol_supp/eapol_supp_sm.c b/src/eapol_supp/eapol_supp_sm.c index c83709f86..f0cae700d 100644 --- a/src/eapol_supp/eapol_supp_sm.c +++ b/src/eapol_supp/eapol_supp_sm.c @@ -1847,6 +1847,17 @@ static void eapol_sm_notify_cert(void *ctx, int depth, const char *subject, cert_hash, cert); } + +static void eapol_sm_notify_status(void *ctx, const char *status, + const char *parameter) +{ + struct eapol_sm *sm = ctx; + + if (sm->ctx->status_cb) + sm->ctx->status_cb(sm->ctx->ctx, status, parameter); +} + + static struct eapol_callbacks eapol_cb = { eapol_sm_get_config, @@ -1859,7 +1870,8 @@ static struct eapol_callbacks eapol_cb = eapol_sm_get_config_blob, eapol_sm_notify_pending, eapol_sm_eap_param_needed, - eapol_sm_notify_cert + eapol_sm_notify_cert, + eapol_sm_notify_status }; diff --git a/src/eapol_supp/eapol_supp_sm.h b/src/eapol_supp/eapol_supp_sm.h index 3260c6148..1a20e4b98 100644 --- a/src/eapol_supp/eapol_supp_sm.h +++ b/src/eapol_supp/eapol_supp_sm.h @@ -230,6 +230,15 @@ struct eapol_ctx { * cert_in_cb - Include server certificates in callback */ int cert_in_cb; + + /** + * status_cb - Notification of a change in EAP status + * @ctx: Callback context (ctx) + * @status: Step in the process of EAP authentication + * @parameter: Step-specific parameter, e.g., EAP method name + */ + void (*status_cb)(void *ctx, const char *status, + const char *parameter); }; diff --git a/wpa_supplicant/dbus/dbus_new.c b/wpa_supplicant/dbus/dbus_new.c index 1760dd2e3..f7393d934 100644 --- a/wpa_supplicant/dbus/dbus_new.c +++ b/wpa_supplicant/dbus/dbus_new.c @@ -840,6 +840,41 @@ nomem: dbus_message_unref(msg); } + +void wpas_dbus_signal_eap_status(struct wpa_supplicant *wpa_s, + const char *status, const char *parameter) +{ + struct wpas_dbus_priv *iface; + DBusMessage *msg; + DBusMessageIter iter; + + iface = wpa_s->global->dbus; + + /* Do nothing if the control interface is not turned on */ + if (iface == NULL) + return; + + msg = dbus_message_new_signal(wpa_s->dbus_new_path, + WPAS_DBUS_NEW_IFACE_INTERFACE, + "EAP"); + if (msg == NULL) + return; + + dbus_message_iter_init_append(msg, &iter); + + if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &status) + || + !dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, + ¶meter)) + goto nomem; + + dbus_connection_send(iface->con, msg, NULL); + +nomem: + dbus_message_unref(msg); +} + + #ifdef CONFIG_P2P /** @@ -2934,6 +2969,13 @@ static const struct wpa_dbus_signal_desc wpas_dbus_interface_signals[] = { END_ARGS } }, + { "EAP", WPAS_DBUS_NEW_IFACE_INTERFACE, + { + { "status", "s", ARG_OUT }, + { "parameter", "s", ARG_OUT }, + END_ARGS + } + }, { NULL, NULL, { END_ARGS } } }; diff --git a/wpa_supplicant/dbus/dbus_new.h b/wpa_supplicant/dbus/dbus_new.h index a2d701139..4d322a1e8 100644 --- a/wpa_supplicant/dbus/dbus_new.h +++ b/wpa_supplicant/dbus/dbus_new.h @@ -224,6 +224,8 @@ void wpas_dbus_signal_certification(struct wpa_supplicant *wpa_s, void wpas_dbus_signal_preq(struct wpa_supplicant *wpa_s, const u8 *addr, const u8 *dst, const u8 *bssid, const u8 *ie, size_t ie_len, u32 ssi_signal); +void wpas_dbus_signal_eap_status(struct wpa_supplicant *wpa_s, + const char *status, const char *parameter); #else /* CONFIG_CTRL_IFACE_DBUS_NEW */ @@ -489,6 +491,12 @@ static inline void wpas_dbus_signal_preq(struct wpa_supplicant *wpa_s, { } +static inline void wpas_dbus_signal_eap_status(struct wpa_supplicant *wpa_s, + const char *status, + const char *parameter) +{ +} + #endif /* CONFIG_CTRL_IFACE_DBUS_NEW */ #endif /* CTRL_IFACE_DBUS_H_NEW */ diff --git a/wpa_supplicant/notify.c b/wpa_supplicant/notify.c index d471dfb16..c4d7e939f 100644 --- a/wpa_supplicant/notify.c +++ b/wpa_supplicant/notify.c @@ -612,3 +612,10 @@ void wpas_notify_preq(struct wpa_supplicant *wpa_s, wpas_dbus_signal_preq(wpa_s, addr, dst, bssid, ie, ie_len, ssi_signal); #endif /* CONFIG_AP */ } + + +void wpas_notify_eap_status(struct wpa_supplicant *wpa_s, const char *status, + const char *parameter) +{ + wpas_dbus_signal_eap_status(wpa_s, status, parameter); +} diff --git a/wpa_supplicant/notify.h b/wpa_supplicant/notify.h index 0c483bc13..e2bf78842 100644 --- a/wpa_supplicant/notify.h +++ b/wpa_supplicant/notify.h @@ -124,5 +124,7 @@ void wpas_notify_certification(struct wpa_supplicant *wpa_s, int depth, void wpas_notify_preq(struct wpa_supplicant *wpa_s, const u8 *addr, const u8 *dst, const u8 *bssid, const u8 *ie, size_t ie_len, u32 ssi_signal); +void wpas_notify_eap_status(struct wpa_supplicant *wpa_s, const char *status, + const char *parameter); #endif /* NOTIFY_H */ diff --git a/wpa_supplicant/wpas_glue.c b/wpa_supplicant/wpas_glue.c index 5b9dc9ee5..fb4fa2244 100644 --- a/wpa_supplicant/wpas_glue.c +++ b/wpa_supplicant/wpas_glue.c @@ -720,6 +720,15 @@ static void wpa_supplicant_cert_cb(void *ctx, int depth, const char *subject, wpas_notify_certification(wpa_s, depth, subject, cert_hash, cert); } + + +static void wpa_supplicant_status_cb(void *ctx, const char *status, + const char *parameter) +{ + struct wpa_supplicant *wpa_s = ctx; + + wpas_notify_eap_status(wpa_s, status, parameter); +} #endif /* IEEE8021X_EAPOL */ @@ -751,6 +760,7 @@ int wpa_supplicant_init_eapol(struct wpa_supplicant *wpa_s) ctx->port_cb = wpa_supplicant_port_cb; ctx->cb = wpa_supplicant_eapol_cb; ctx->cert_cb = wpa_supplicant_cert_cb; + ctx->status_cb = wpa_supplicant_status_cb; ctx->cb_ctx = wpa_s; wpa_s->eapol = eapol_sm_init(ctx); if (wpa_s->eapol == NULL) {