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);
}