diff --git a/doc/dbus.doxygen b/doc/dbus.doxygen index 2e5d9c732..329e5d03b 100644 --- a/doc/dbus.doxygen +++ b/doc/dbus.doxygen @@ -792,7 +792,7 @@ fi.w1.wpa_supplicant1.CreateInterface.

Arguments

a{sv} : parameters
-
A dictionary with pairs of field names and their values. Possible dictionary keys are: "depth", "subject", "cert_hash", "cert".
+
A dictionary with pairs of field names and their values. Possible dictionary keys are: "depth", "subject", "altsubject", "cert_hash", "cert".
diff --git a/src/common/wpa_ctrl.h b/src/common/wpa_ctrl.h index 82fad4b44..bc5dd7c35 100644 --- a/src/common/wpa_ctrl.h +++ b/src/common/wpa_ctrl.h @@ -42,6 +42,8 @@ extern "C" { #define WPA_EVENT_EAP_METHOD "CTRL-EVENT-EAP-METHOD " /** EAP peer certificate from TLS */ #define WPA_EVENT_EAP_PEER_CERT "CTRL-EVENT-EAP-PEER-CERT " +/** EAP peer certificate alternative subject name component from TLS */ +#define WPA_EVENT_EAP_PEER_ALT "CTRL-EVENT-EAP-PEER-ALT " /** EAP TLS certificate chain validation error */ #define WPA_EVENT_EAP_TLS_CERT_ERROR "CTRL-EVENT-EAP-TLS-CERT-ERROR " /** EAP status */ diff --git a/src/crypto/tls.h b/src/crypto/tls.h index a4f954c7a..202ada8b2 100644 --- a/src/crypto/tls.h +++ b/src/crypto/tls.h @@ -44,6 +44,9 @@ enum tls_fail_reason { TLS_FAIL_DOMAIN_SUFFIX_MISMATCH = 9 }; + +#define TLS_MAX_ALT_SUBJECT 10 + union tls_event_data { struct { int depth; @@ -59,6 +62,8 @@ union tls_event_data { const struct wpabuf *cert; const u8 *hash; size_t hash_len; + const char *altsubject[TLS_MAX_ALT_SUBJECT]; + int num_altsubject; } peer_cert; struct { diff --git a/src/crypto/tls_openssl.c b/src/crypto/tls_openssl.c index 5433ebb2d..e52fd3976 100644 --- a/src/crypto/tls_openssl.c +++ b/src/crypto/tls_openssl.c @@ -1377,6 +1377,11 @@ static void openssl_tls_cert_event(struct tls_connection *conn, struct wpabuf *cert = NULL; union tls_event_data ev; struct tls_context *context = conn->context; + char *altsubject[TLS_MAX_ALT_SUBJECT]; + int alt, num_altsubject = 0; + GENERAL_NAME *gen; + void *ext; + stack_index_t i; #ifdef CONFIG_SHA256 u8 hash[32]; #endif /* CONFIG_SHA256 */ @@ -1403,8 +1408,52 @@ static void openssl_tls_cert_event(struct tls_connection *conn, #endif /* CONFIG_SHA256 */ ev.peer_cert.depth = depth; ev.peer_cert.subject = subject; + + ext = X509_get_ext_d2i(err_cert, NID_subject_alt_name, NULL, NULL); + for (i = 0; ext && i < sk_GENERAL_NAME_num(ext); i++) { + char *pos; + + if (num_altsubject == TLS_MAX_ALT_SUBJECT) + break; + gen = sk_GENERAL_NAME_value(ext, i); + if (gen->type != GEN_EMAIL && + gen->type != GEN_DNS && + gen->type != GEN_URI) + continue; + + pos = os_malloc(10 + gen->d.ia5->length + 1); + if (pos == NULL) + break; + altsubject[num_altsubject++] = pos; + + switch (gen->type) { + case GEN_EMAIL: + os_memcpy(pos, "EMAIL:", 6); + pos += 6; + break; + case GEN_DNS: + os_memcpy(pos, "DNS:", 4); + pos += 4; + break; + case GEN_URI: + os_memcpy(pos, "URI:", 4); + pos += 4; + break; + } + + os_memcpy(pos, gen->d.ia5->data, gen->d.ia5->length); + pos += gen->d.ia5->length; + *pos = '\0'; + } + + for (alt = 0; alt < num_altsubject; alt++) + ev.peer_cert.altsubject[alt] = altsubject[alt]; + ev.peer_cert.num_altsubject = num_altsubject; + context->event_cb(context->cb_ctx, TLS_PEER_CERTIFICATE, &ev); wpabuf_free(cert); + for (alt = 0; alt < num_altsubject; alt++) + os_free(altsubject[alt]); } diff --git a/src/eap_peer/eap.c b/src/eap_peer/eap.c index 31c1a29c6..62cd4a18c 100644 --- a/src/eap_peer/eap.c +++ b/src/eap_peer/eap.c @@ -1858,6 +1858,8 @@ static void eap_peer_sm_tls_event(void *ctx, enum tls_event ev, sm->eapol_cb->notify_cert(sm->eapol_ctx, data->peer_cert.depth, data->peer_cert.subject, + data->peer_cert.altsubject, + data->peer_cert.num_altsubject, hash_hex, data->peer_cert.cert); break; case TLS_ALERT: diff --git a/src/eap_peer/eap.h b/src/eap_peer/eap.h index bc207e74f..8c4a42f63 100644 --- a/src/eap_peer/eap.h +++ b/src/eap_peer/eap.h @@ -228,10 +228,13 @@ struct eapol_callbacks { * @ctx: eapol_ctx from eap_peer_sm_init() call * @depth: Depth in certificate chain (0 = server) * @subject: Subject of the peer certificate + * @altsubject: Select fields from AltSubject of the peer certificate + * @num_altsubject: Number of altsubject values * @cert_hash: SHA-256 hash of the certificate * @cert: Peer certificate */ void (*notify_cert)(void *ctx, int depth, const char *subject, + const char *altsubject[], int num_altsubject, 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 941a26945..621318ee1 100644 --- a/src/eapol_supp/eapol_supp_sm.c +++ b/src/eapol_supp/eapol_supp_sm.c @@ -1962,13 +1962,14 @@ static void eapol_sm_eap_param_needed(void *ctx, enum wpa_ctrl_req_type field, #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 char *altsubject[], + int num_altsubject, 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); + sm->ctx->cert_cb(sm->ctx->ctx, depth, subject, altsubject, + num_altsubject, cert_hash, cert); } diff --git a/src/eapol_supp/eapol_supp_sm.h b/src/eapol_supp/eapol_supp_sm.h index e089e88b5..d8ae9d4ec 100644 --- a/src/eapol_supp/eapol_supp_sm.h +++ b/src/eapol_supp/eapol_supp_sm.h @@ -248,10 +248,13 @@ struct eapol_ctx { * @ctx: Callback context (ctx) * @depth: Depth in certificate chain (0 = server) * @subject: Subject of the peer certificate + * @altsubject: Select fields from AltSubject of the peer certificate + * @num_altsubject: Number of altsubject values * @cert_hash: SHA-256 hash of the certificate * @cert: Peer certificate */ void (*cert_cb)(void *ctx, int depth, const char *subject, + const char *altsubject[], int num_altsubject, 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 b30cc389f..30ef03a74 100644 --- a/wpa_supplicant/dbus/dbus_new.c +++ b/wpa_supplicant/dbus/dbus_new.c @@ -748,6 +748,8 @@ nomem: void wpas_dbus_signal_certification(struct wpa_supplicant *wpa_s, int depth, const char *subject, + const char *altsubject[], + int num_altsubject, const char *cert_hash, const struct wpabuf *cert) { @@ -771,6 +773,9 @@ void wpas_dbus_signal_certification(struct wpa_supplicant *wpa_s, if (!wpa_dbus_dict_open_write(&iter, &dict_iter) || !wpa_dbus_dict_append_uint32(&dict_iter, "depth", depth) || !wpa_dbus_dict_append_string(&dict_iter, "subject", subject) || + (altsubject && num_altsubject && + !wpa_dbus_dict_append_string_array(&dict_iter, "altsubject", + altsubject, num_altsubject)) || (cert_hash && !wpa_dbus_dict_append_string(&dict_iter, "cert_hash", cert_hash)) || diff --git a/wpa_supplicant/dbus/dbus_new.h b/wpa_supplicant/dbus/dbus_new.h index 5f32bbf6b..d162d2b66 100644 --- a/wpa_supplicant/dbus/dbus_new.h +++ b/wpa_supplicant/dbus/dbus_new.h @@ -215,6 +215,8 @@ 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 *altsubject[], + int num_altsubject, const char *cert_hash, const struct wpabuf *cert); void wpas_dbus_signal_preq(struct wpa_supplicant *wpa_s, @@ -484,6 +486,8 @@ 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 *altsubject[], + int num_altsubject, const char *cert_hash, const struct wpabuf *cert) { diff --git a/wpa_supplicant/notify.c b/wpa_supplicant/notify.c index df1ce9e0c..bf1836a5c 100644 --- a/wpa_supplicant/notify.c +++ b/wpa_supplicant/notify.c @@ -690,13 +690,13 @@ void wpas_notify_sta_authorized(struct wpa_supplicant *wpa_s, void wpas_notify_certification(struct wpa_supplicant *wpa_s, int depth, - const char *subject, const char *cert_hash, + const char *subject, const char *altsubject[], + int num_altsubject, const char *cert_hash, const struct wpabuf *cert) { wpa_msg(wpa_s, MSG_INFO, WPA_EVENT_EAP_PEER_CERT "depth=%d subject='%s'%s%s", - depth, subject, - cert_hash ? " hash=" : "", + depth, subject, cert_hash ? " hash=" : "", cert_hash ? cert_hash : ""); if (cert) { @@ -714,11 +714,20 @@ void wpas_notify_certification(struct wpa_supplicant *wpa_s, int depth, } } + if (altsubject) { + int i; + + for (i = 0; i < num_altsubject; i++) + wpa_msg(wpa_s, MSG_INFO, WPA_EVENT_EAP_PEER_ALT + "depth=%d %s", depth, altsubject[i]); + } + /* 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); + wpas_dbus_signal_certification(wpa_s, depth, subject, altsubject, + num_altsubject, cert_hash, cert); } diff --git a/wpa_supplicant/notify.h b/wpa_supplicant/notify.h index 7feb53044..7fb1f58ef 100644 --- a/wpa_supplicant/notify.h +++ b/wpa_supplicant/notify.h @@ -121,7 +121,8 @@ 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 char *subject, const char *altsubject[], + int num_altsubject, const char *cert_hash, const struct wpabuf *cert); void wpas_notify_preq(struct wpa_supplicant *wpa_s, const u8 *addr, const u8 *dst, const u8 *bssid, diff --git a/wpa_supplicant/wpas_glue.c b/wpa_supplicant/wpas_glue.c index 8029ae53e..838704335 100644 --- a/wpa_supplicant/wpas_glue.c +++ b/wpa_supplicant/wpas_glue.c @@ -860,12 +860,14 @@ static void wpa_supplicant_port_cb(void *ctx, int authorized) static void wpa_supplicant_cert_cb(void *ctx, int depth, const char *subject, + const char *altsubject[], int num_altsubject, const char *cert_hash, const struct wpabuf *cert) { struct wpa_supplicant *wpa_s = ctx; - wpas_notify_certification(wpa_s, depth, subject, cert_hash, cert); + wpas_notify_certification(wpa_s, depth, subject, altsubject, + num_altsubject, cert_hash, cert); }