Add peer certificate alt subject name information to EAP events
A new "CTRL-EVENT-EAP-PEER-ALT depth=<i> <alt name>" event is now used to provide information about server certificate chain alternative subject names for upper layers, e.g., to make it easier to configure constraints on the server certificate. For example: CTRL-EVENT-EAP-PEER-ALT depth=0 DNS:server.example.com Currently, this includes DNS, EMAIL, and URI components from the certificates. Similar information is priovided to D-Bus Certification signal in the new altsubject argument which is a string array of these items. Signed-off-by: Jouni Malinen <j@w1.fi>
This commit is contained in:
parent
98a4cd447e
commit
d07d3fbda2
13 changed files with 96 additions and 10 deletions
|
@ -792,7 +792,7 @@ fi.w1.wpa_supplicant1.CreateInterface.
|
||||||
<h4>Arguments</h4>
|
<h4>Arguments</h4>
|
||||||
<dl>
|
<dl>
|
||||||
<dt>a{sv} : parameters</dt>
|
<dt>a{sv} : parameters</dt>
|
||||||
<dd>A dictionary with pairs of field names and their values. Possible dictionary keys are: "depth", "subject", "cert_hash", "cert".</dd>
|
<dd>A dictionary with pairs of field names and their values. Possible dictionary keys are: "depth", "subject", "altsubject", "cert_hash", "cert".</dd>
|
||||||
</dl>
|
</dl>
|
||||||
</li>
|
</li>
|
||||||
|
|
||||||
|
|
|
@ -42,6 +42,8 @@ extern "C" {
|
||||||
#define WPA_EVENT_EAP_METHOD "CTRL-EVENT-EAP-METHOD "
|
#define WPA_EVENT_EAP_METHOD "CTRL-EVENT-EAP-METHOD "
|
||||||
/** EAP peer certificate from TLS */
|
/** EAP peer certificate from TLS */
|
||||||
#define WPA_EVENT_EAP_PEER_CERT "CTRL-EVENT-EAP-PEER-CERT "
|
#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 */
|
/** EAP TLS certificate chain validation error */
|
||||||
#define WPA_EVENT_EAP_TLS_CERT_ERROR "CTRL-EVENT-EAP-TLS-CERT-ERROR "
|
#define WPA_EVENT_EAP_TLS_CERT_ERROR "CTRL-EVENT-EAP-TLS-CERT-ERROR "
|
||||||
/** EAP status */
|
/** EAP status */
|
||||||
|
|
|
@ -44,6 +44,9 @@ enum tls_fail_reason {
|
||||||
TLS_FAIL_DOMAIN_SUFFIX_MISMATCH = 9
|
TLS_FAIL_DOMAIN_SUFFIX_MISMATCH = 9
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#define TLS_MAX_ALT_SUBJECT 10
|
||||||
|
|
||||||
union tls_event_data {
|
union tls_event_data {
|
||||||
struct {
|
struct {
|
||||||
int depth;
|
int depth;
|
||||||
|
@ -59,6 +62,8 @@ union tls_event_data {
|
||||||
const struct wpabuf *cert;
|
const struct wpabuf *cert;
|
||||||
const u8 *hash;
|
const u8 *hash;
|
||||||
size_t hash_len;
|
size_t hash_len;
|
||||||
|
const char *altsubject[TLS_MAX_ALT_SUBJECT];
|
||||||
|
int num_altsubject;
|
||||||
} peer_cert;
|
} peer_cert;
|
||||||
|
|
||||||
struct {
|
struct {
|
||||||
|
|
|
@ -1377,6 +1377,11 @@ static void openssl_tls_cert_event(struct tls_connection *conn,
|
||||||
struct wpabuf *cert = NULL;
|
struct wpabuf *cert = NULL;
|
||||||
union tls_event_data ev;
|
union tls_event_data ev;
|
||||||
struct tls_context *context = conn->context;
|
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
|
#ifdef CONFIG_SHA256
|
||||||
u8 hash[32];
|
u8 hash[32];
|
||||||
#endif /* CONFIG_SHA256 */
|
#endif /* CONFIG_SHA256 */
|
||||||
|
@ -1403,8 +1408,52 @@ static void openssl_tls_cert_event(struct tls_connection *conn,
|
||||||
#endif /* CONFIG_SHA256 */
|
#endif /* CONFIG_SHA256 */
|
||||||
ev.peer_cert.depth = depth;
|
ev.peer_cert.depth = depth;
|
||||||
ev.peer_cert.subject = subject;
|
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);
|
context->event_cb(context->cb_ctx, TLS_PEER_CERTIFICATE, &ev);
|
||||||
wpabuf_free(cert);
|
wpabuf_free(cert);
|
||||||
|
for (alt = 0; alt < num_altsubject; alt++)
|
||||||
|
os_free(altsubject[alt]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -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,
|
sm->eapol_cb->notify_cert(sm->eapol_ctx,
|
||||||
data->peer_cert.depth,
|
data->peer_cert.depth,
|
||||||
data->peer_cert.subject,
|
data->peer_cert.subject,
|
||||||
|
data->peer_cert.altsubject,
|
||||||
|
data->peer_cert.num_altsubject,
|
||||||
hash_hex, data->peer_cert.cert);
|
hash_hex, data->peer_cert.cert);
|
||||||
break;
|
break;
|
||||||
case TLS_ALERT:
|
case TLS_ALERT:
|
||||||
|
|
|
@ -228,10 +228,13 @@ struct eapol_callbacks {
|
||||||
* @ctx: eapol_ctx from eap_peer_sm_init() call
|
* @ctx: eapol_ctx from eap_peer_sm_init() call
|
||||||
* @depth: Depth in certificate chain (0 = server)
|
* @depth: Depth in certificate chain (0 = server)
|
||||||
* @subject: Subject of the peer certificate
|
* @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_hash: SHA-256 hash of the certificate
|
||||||
* @cert: Peer certificate
|
* @cert: Peer certificate
|
||||||
*/
|
*/
|
||||||
void (*notify_cert)(void *ctx, int depth, const char *subject,
|
void (*notify_cert)(void *ctx, int depth, const char *subject,
|
||||||
|
const char *altsubject[], int num_altsubject,
|
||||||
const char *cert_hash, const struct wpabuf *cert);
|
const char *cert_hash, const struct wpabuf *cert);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -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 */
|
#endif /* CONFIG_CTRL_IFACE || !CONFIG_NO_STDOUT_DEBUG */
|
||||||
|
|
||||||
static void eapol_sm_notify_cert(void *ctx, int depth, const char *subject,
|
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)
|
const struct wpabuf *cert)
|
||||||
{
|
{
|
||||||
struct eapol_sm *sm = ctx;
|
struct eapol_sm *sm = ctx;
|
||||||
if (sm->ctx->cert_cb)
|
if (sm->ctx->cert_cb)
|
||||||
sm->ctx->cert_cb(sm->ctx->ctx, depth, subject,
|
sm->ctx->cert_cb(sm->ctx->ctx, depth, subject, altsubject,
|
||||||
cert_hash, cert);
|
num_altsubject, cert_hash, cert);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -248,10 +248,13 @@ struct eapol_ctx {
|
||||||
* @ctx: Callback context (ctx)
|
* @ctx: Callback context (ctx)
|
||||||
* @depth: Depth in certificate chain (0 = server)
|
* @depth: Depth in certificate chain (0 = server)
|
||||||
* @subject: Subject of the peer certificate
|
* @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_hash: SHA-256 hash of the certificate
|
||||||
* @cert: Peer certificate
|
* @cert: Peer certificate
|
||||||
*/
|
*/
|
||||||
void (*cert_cb)(void *ctx, int depth, const char *subject,
|
void (*cert_cb)(void *ctx, int depth, const char *subject,
|
||||||
|
const char *altsubject[], int num_altsubject,
|
||||||
const char *cert_hash, const struct wpabuf *cert);
|
const char *cert_hash, const struct wpabuf *cert);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -748,6 +748,8 @@ nomem:
|
||||||
|
|
||||||
void wpas_dbus_signal_certification(struct wpa_supplicant *wpa_s,
|
void wpas_dbus_signal_certification(struct wpa_supplicant *wpa_s,
|
||||||
int depth, const char *subject,
|
int depth, const char *subject,
|
||||||
|
const char *altsubject[],
|
||||||
|
int num_altsubject,
|
||||||
const char *cert_hash,
|
const char *cert_hash,
|
||||||
const struct wpabuf *cert)
|
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) ||
|
if (!wpa_dbus_dict_open_write(&iter, &dict_iter) ||
|
||||||
!wpa_dbus_dict_append_uint32(&dict_iter, "depth", depth) ||
|
!wpa_dbus_dict_append_uint32(&dict_iter, "depth", depth) ||
|
||||||
!wpa_dbus_dict_append_string(&dict_iter, "subject", subject) ||
|
!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 &&
|
(cert_hash &&
|
||||||
!wpa_dbus_dict_append_string(&dict_iter, "cert_hash",
|
!wpa_dbus_dict_append_string(&dict_iter, "cert_hash",
|
||||||
cert_hash)) ||
|
cert_hash)) ||
|
||||||
|
|
|
@ -215,6 +215,8 @@ void wpas_dbus_signal_p2p_wps_failed(struct wpa_supplicant *wpa_s,
|
||||||
struct wps_event_fail *fail);
|
struct wps_event_fail *fail);
|
||||||
void wpas_dbus_signal_certification(struct wpa_supplicant *wpa_s,
|
void wpas_dbus_signal_certification(struct wpa_supplicant *wpa_s,
|
||||||
int depth, const char *subject,
|
int depth, const char *subject,
|
||||||
|
const char *altsubject[],
|
||||||
|
int num_altsubject,
|
||||||
const char *cert_hash,
|
const char *cert_hash,
|
||||||
const struct wpabuf *cert);
|
const struct wpabuf *cert);
|
||||||
void wpas_dbus_signal_preq(struct wpa_supplicant *wpa_s,
|
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,
|
static inline void wpas_dbus_signal_certification(struct wpa_supplicant *wpa_s,
|
||||||
int depth,
|
int depth,
|
||||||
const char *subject,
|
const char *subject,
|
||||||
|
const char *altsubject[],
|
||||||
|
int num_altsubject,
|
||||||
const char *cert_hash,
|
const char *cert_hash,
|
||||||
const struct wpabuf *cert)
|
const struct wpabuf *cert)
|
||||||
{
|
{
|
||||||
|
|
|
@ -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,
|
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)
|
const struct wpabuf *cert)
|
||||||
{
|
{
|
||||||
wpa_msg(wpa_s, MSG_INFO, WPA_EVENT_EAP_PEER_CERT
|
wpa_msg(wpa_s, MSG_INFO, WPA_EVENT_EAP_PEER_CERT
|
||||||
"depth=%d subject='%s'%s%s",
|
"depth=%d subject='%s'%s%s",
|
||||||
depth, subject,
|
depth, subject, cert_hash ? " hash=" : "",
|
||||||
cert_hash ? " hash=" : "",
|
|
||||||
cert_hash ? cert_hash : "");
|
cert_hash ? cert_hash : "");
|
||||||
|
|
||||||
if (cert) {
|
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 */
|
/* notify the old DBus API */
|
||||||
wpa_supplicant_dbus_notify_certification(wpa_s, depth, subject,
|
wpa_supplicant_dbus_notify_certification(wpa_s, depth, subject,
|
||||||
cert_hash, cert);
|
cert_hash, cert);
|
||||||
/* notify the new DBus API */
|
/* 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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -121,7 +121,8 @@ void wpas_notify_p2p_wps_failed(struct wpa_supplicant *wpa_s,
|
||||||
struct wps_event_fail *fail);
|
struct wps_event_fail *fail);
|
||||||
|
|
||||||
void wpas_notify_certification(struct wpa_supplicant *wpa_s, int depth,
|
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);
|
const struct wpabuf *cert);
|
||||||
void wpas_notify_preq(struct wpa_supplicant *wpa_s,
|
void wpas_notify_preq(struct wpa_supplicant *wpa_s,
|
||||||
const u8 *addr, const u8 *dst, const u8 *bssid,
|
const u8 *addr, const u8 *dst, const u8 *bssid,
|
||||||
|
|
|
@ -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,
|
static void wpa_supplicant_cert_cb(void *ctx, int depth, const char *subject,
|
||||||
|
const char *altsubject[], int num_altsubject,
|
||||||
const char *cert_hash,
|
const char *cert_hash,
|
||||||
const struct wpabuf *cert)
|
const struct wpabuf *cert)
|
||||||
{
|
{
|
||||||
struct wpa_supplicant *wpa_s = ctx;
|
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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue