diff --git a/src/eap_peer/eap.c b/src/eap_peer/eap.c index 8a9826f1b..0e8326834 100644 --- a/src/eap_peer/eap.c +++ b/src/eap_peer/eap.c @@ -1209,6 +1209,13 @@ static void eap_peer_sm_tls_event(void *ctx, enum tls_event ev, data->peer_cert.subject, cert_hex); } + if (sm->eapol_cb->notify_cert) { + sm->eapol_cb->notify_cert(sm->eapol_ctx, + data->peer_cert.depth, + data->peer_cert.subject, + hash_hex, + data->peer_cert.cert); + } break; } diff --git a/src/eap_peer/eap.h b/src/eap_peer/eap.h index 35509090c..2a80d4e74 100644 --- a/src/eap_peer/eap.h +++ b/src/eap_peer/eap.h @@ -221,6 +221,17 @@ struct eapol_callbacks { */ void (*eap_param_needed)(void *ctx, const char *field, const char *txt); + + /** + * notify_cert - Notification of a peer certificate + * @ctx: eapol_ctx from eap_peer_sm_init() call + * @depth: Depth in certificate chain (0 = server) + * @subject: Subject of the peer certificate + * @cert_hash: SHA-256 hash of the certificate + * @cert: Peer certificate + */ + void (*notify_cert)(void *ctx, int depth, const char *subject, + const char *cert_hash, const struct wpabuf *cert); }; /** diff --git a/src/eapol_supp/eapol_supp_sm.c b/src/eapol_supp/eapol_supp_sm.c index 18abb4e3c..bb6cff604 100644 --- a/src/eapol_supp/eapol_supp_sm.c +++ b/src/eapol_supp/eapol_supp_sm.c @@ -1825,6 +1825,15 @@ static void eapol_sm_eap_param_needed(void *ctx, const char *field, #define eapol_sm_eap_param_needed NULL #endif /* CONFIG_CTRL_IFACE || !CONFIG_NO_STDOUT_DEBUG */ +static void eapol_sm_notify_cert(void *ctx, int depth, const char *subject, + const char *cert_hash, + const struct wpabuf *cert) +{ + struct eapol_sm *sm = ctx; + if (sm->ctx->cert_cb) + sm->ctx->cert_cb(sm->ctx->ctx, depth, subject, + cert_hash, cert); +} static struct eapol_callbacks eapol_cb = { @@ -1837,7 +1846,8 @@ static struct eapol_callbacks eapol_cb = eapol_sm_set_config_blob, eapol_sm_get_config_blob, eapol_sm_notify_pending, - eapol_sm_eap_param_needed + eapol_sm_eap_param_needed, + eapol_sm_notify_cert }; diff --git a/src/eapol_supp/eapol_supp_sm.h b/src/eapol_supp/eapol_supp_sm.h index 1bdf8cdd4..3ea7e7993 100644 --- a/src/eapol_supp/eapol_supp_sm.h +++ b/src/eapol_supp/eapol_supp_sm.h @@ -220,6 +220,17 @@ struct eapol_ctx { * @authorized: Whether the supplicant port is now in authorized state */ void (*port_cb)(void *ctx, int authorized); + + /** + * cert_cb - Notification of a peer certificate + * @ctx: Callback context (ctx) + * @depth: Depth in certificate chain (0 = server) + * @subject: Subject of the peer certificate + * @cert_hash: SHA-256 hash of the certificate + * @cert: Peer certificate + */ + void (*cert_cb)(void *ctx, int depth, const char *subject, + const char *cert_hash, const struct wpabuf *cert); }; diff --git a/wpa_supplicant/dbus/dbus_new.c b/wpa_supplicant/dbus/dbus_new.c index d48c3d6be..533cb3210 100644 --- a/wpa_supplicant/dbus/dbus_new.c +++ b/wpa_supplicant/dbus/dbus_new.c @@ -653,6 +653,54 @@ nomem: #endif /* CONFIG_WPS */ +void wpas_dbus_signal_certification(struct wpa_supplicant *wpa_s, + int depth, const char *subject, + const char *cert_hash, + const struct wpabuf *cert) +{ + struct wpas_dbus_priv *iface; + DBusMessage *msg; + DBusMessageIter iter, dict_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, + "Certification"); + if (msg == NULL) + return; + + dbus_message_iter_init_append(msg, &iter); + if (!wpa_dbus_dict_open_write(&iter, &dict_iter)) + goto nomem; + + if (!wpa_dbus_dict_append_uint32(&dict_iter, "depth", depth) || + !wpa_dbus_dict_append_string(&dict_iter, "subject", subject)) + goto nomem; + + if (cert_hash && + !wpa_dbus_dict_append_string(&dict_iter, "cert_hash", cert_hash)) + goto nomem; + + if (cert && + !wpa_dbus_dict_append_byte_array(&dict_iter, "cert", + wpabuf_head(cert), + wpabuf_len(cert))) + goto nomem; + + if (!wpa_dbus_dict_close_write(&iter, &dict_iter)) + goto nomem; + + dbus_connection_send(iface->con, msg, NULL); + +nomem: + dbus_message_unref(msg); +} + #ifdef CONFIG_P2P /** @@ -2647,6 +2695,12 @@ static const struct wpa_dbus_signal_desc wpas_dbus_interface_signals[] = { } }, #endif /* CONFIG_P2P */ + { "Certification", WPAS_DBUS_NEW_IFACE_INTERFACE, + { + { "certification", "a{sv}", 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 3b0d50c4b..080000c07 100644 --- a/wpa_supplicant/dbus/dbus_new.h +++ b/wpa_supplicant/dbus/dbus_new.h @@ -201,6 +201,10 @@ void wpas_dbus_signal_p2p_peer_joined(struct wpa_supplicant *wpa_s, const u8 *member); void wpas_dbus_signal_p2p_wps_failed(struct wpa_supplicant *wpa_s, struct wps_event_fail *fail); +void wpas_dbus_signal_certification(struct wpa_supplicant *wpa_s, + int depth, const char *subject, + const char *cert_hash, + const struct wpabuf *cert); #else /* CONFIG_CTRL_IFACE_DBUS_NEW */ @@ -443,6 +447,14 @@ wpas_dbus_signal_p2p_wps_failed(struct wpa_supplicant *wpa_s, { } +static inline void wpas_dbus_signal_certification(struct wpa_supplicant *wpa_s, + int depth, + const char *subject, + const char *cert_hash, + const struct wpabuf *cert) +{ +} + #endif /* CONFIG_CTRL_IFACE_DBUS_NEW */ #endif /* CTRL_IFACE_DBUS_H_NEW */ diff --git a/wpa_supplicant/dbus/dbus_old.c b/wpa_supplicant/dbus/dbus_old.c index 6a00f3e57..d255e142b 100644 --- a/wpa_supplicant/dbus/dbus_old.c +++ b/wpa_supplicant/dbus/dbus_old.c @@ -549,6 +549,59 @@ void wpa_supplicant_dbus_notify_wps_cred(struct wpa_supplicant *wpa_s, } #endif /* CONFIG_WPS */ +void wpa_supplicant_dbus_notify_certification(struct wpa_supplicant *wpa_s, + int depth, const char *subject, + const char *cert_hash, + const struct wpabuf *cert) +{ + struct wpas_dbus_priv *iface; + DBusMessage *_signal = NULL; + const char *hash; + const char *cert_hex; + int cert_hex_len; + + /* Do nothing if the control interface is not turned on */ + if (wpa_s->global == NULL) + return; + iface = wpa_s->global->dbus; + if (iface == NULL) + return; + + _signal = dbus_message_new_signal(wpa_s->dbus_path, + WPAS_DBUS_IFACE_INTERFACE, + "Certification"); + if (_signal == NULL) { + wpa_printf(MSG_ERROR, + "dbus: wpa_supplicant_dbus_notify_certification: " + "Could not create dbus signal; likely out of " + "memory"); + return; + } + + hash = cert_hash ? cert_hash : ""; + cert_hex = cert ? wpabuf_head(cert) : ""; + cert_hex_len = cert ? wpabuf_len(cert) : 0; + + if (!dbus_message_append_args(_signal, + DBUS_TYPE_INT32,&depth, + DBUS_TYPE_STRING, &subject, + DBUS_TYPE_STRING, &hash, + DBUS_TYPE_ARRAY, DBUS_TYPE_BYTE, + &cert_hex, cert_hex_len, + DBUS_TYPE_INVALID)) { + wpa_printf(MSG_ERROR, + "dbus: wpa_supplicant_dbus_notify_certification: " + "Not enough memory to construct signal"); + goto out; + } + + dbus_connection_send(iface->con, _signal, NULL); + +out: + dbus_message_unref(_signal); + +} + /** * wpa_supplicant_dbus_ctrl_iface_init - Initialize dbus control interface diff --git a/wpa_supplicant/dbus/dbus_old.h b/wpa_supplicant/dbus/dbus_old.h index a9840c259..d4af86206 100644 --- a/wpa_supplicant/dbus/dbus_old.h +++ b/wpa_supplicant/dbus/dbus_old.h @@ -82,6 +82,10 @@ void wpa_supplicant_dbus_notify_state_change(struct wpa_supplicant *wpa_s, enum wpa_states old_state); void wpa_supplicant_dbus_notify_wps_cred(struct wpa_supplicant *wpa_s, const struct wps_credential *cred); +void wpa_supplicant_dbus_notify_certification(struct wpa_supplicant *wpa_s, + int depth, const char *subject, + const char *cert_hash, + const struct wpabuf *cert); char * wpas_dbus_decompose_object_path(const char *path, char **network, char **bssid); @@ -114,6 +118,14 @@ wpa_supplicant_dbus_notify_wps_cred(struct wpa_supplicant *wpa_s, { } +static inline void +void wpa_supplicant_dbus_notify_certification(struct wpa_supplicant *wpa_s, + int depth, const char *subject, + const char *cert_hash, + const struct wpabuf *cert) +{ +} + static inline int wpas_dbus_register_iface(struct wpa_supplicant *wpa_s) { diff --git a/wpa_supplicant/notify.c b/wpa_supplicant/notify.c index b03c589eb..138c22980 100644 --- a/wpa_supplicant/notify.c +++ b/wpa_supplicant/notify.c @@ -555,3 +555,15 @@ void wpas_notify_sta_authorized(struct wpa_supplicant *wpa_s, else wpas_notify_ap_sta_deauthorized(wpa_s, mac_addr); } + + +void wpas_notify_certification(struct wpa_supplicant *wpa_s, int depth, + const char *subject, const char *cert_hash, + const struct wpabuf *cert) +{ + /* notify the old DBus API */ + wpa_supplicant_dbus_notify_certification(wpa_s, depth, subject, + cert_hash, cert); + /* notify the new DBus API */ + wpas_dbus_signal_certification(wpa_s, depth, subject, cert_hash, cert); +} diff --git a/wpa_supplicant/notify.h b/wpa_supplicant/notify.h index 766668fc6..98cbcb1b3 100644 --- a/wpa_supplicant/notify.h +++ b/wpa_supplicant/notify.h @@ -119,4 +119,8 @@ void wpas_notify_persistent_group_removed(struct wpa_supplicant *wpa_s, void wpas_notify_p2p_wps_failed(struct wpa_supplicant *wpa_s, struct wps_event_fail *fail); +void wpas_notify_certification(struct wpa_supplicant *wpa_s, int depth, + const char *subject, const char *cert_hash, + const struct wpabuf *cert); + #endif /* NOTIFY_H */ diff --git a/wpa_supplicant/wpas_glue.c b/wpa_supplicant/wpas_glue.c index 2662eec46..edb947529 100644 --- a/wpa_supplicant/wpas_glue.c +++ b/wpa_supplicant/wpas_glue.c @@ -32,6 +32,7 @@ #include "wps_supplicant.h" #include "bss.h" #include "scan.h" +#include "notify.h" #ifndef CONFIG_NO_CONFIG_BLOBS @@ -611,6 +612,16 @@ static void wpa_supplicant_port_cb(void *ctx, int authorized) authorized ? "Authorized" : "Unauthorized"); wpa_drv_set_supp_port(wpa_s, authorized); } + + +static void wpa_supplicant_cert_cb(void *ctx, int depth, const char *subject, + const char *cert_hash, + const struct wpabuf *cert) +{ + struct wpa_supplicant *wpa_s = ctx; + + wpas_notify_certification(wpa_s, depth, subject, cert_hash, cert); +} #endif /* IEEE8021X_EAPOL */ @@ -641,6 +652,7 @@ int wpa_supplicant_init_eapol(struct wpa_supplicant *wpa_s) ctx->eap_param_needed = wpa_supplicant_eap_param_needed; ctx->port_cb = wpa_supplicant_port_cb; ctx->cb = wpa_supplicant_eapol_cb; + ctx->cert_cb = wpa_supplicant_cert_cb; ctx->cb_ctx = wpa_s; wpa_s->eapol = eapol_sm_init(ctx); if (wpa_s->eapol == NULL) {