aboutsummaryrefslogtreecommitdiffstats
path: root/src/tls
diff options
context:
space:
mode:
authorJouni Malinen <j@w1.fi>2015-11-29 16:59:27 (GMT)
committerJouni Malinen <j@w1.fi>2015-11-29 16:59:27 (GMT)
commitf2a6ad01a943103c658de5721c2d7f7e91ee7fa4 (patch)
tree73d1fbdd538d39173755a854b428c728894be2ec /src/tls
parentb115eebe01ca23848d3af786a6b22803a1b2fafc (diff)
downloadhostap-f2a6ad01a943103c658de5721c2d7f7e91ee7fa4.zip
hostap-f2a6ad01a943103c658de5721c2d7f7e91ee7fa4.tar.gz
hostap-f2a6ad01a943103c658de5721c2d7f7e91ee7fa4.tar.bz2
TLS client: Add support for server certificate probing
The internal TLS client implementation can now be used with ca_cert="probe://" to probe the server certificate chain. This is also adding the related CTRL-EVENT-EAP-TLS-CERT-ERROR and CTRL-EVENT-EAP-PEER-CERT events. Signed-off-by: Jouni Malinen <j@w1.fi>
Diffstat (limited to 'src/tls')
-rw-r--r--src/tls/tlsv1_client.c12
-rw-r--r--src/tls/tlsv1_client.h6
-rw-r--r--src/tls/tlsv1_client_i.h5
-rw-r--r--src/tls/tlsv1_client_read.c77
-rw-r--r--src/tls/tlsv1_cred.c7
-rw-r--r--src/tls/tlsv1_cred.h1
6 files changed, 108 insertions, 0 deletions
diff --git a/src/tls/tlsv1_client.c b/src/tls/tlsv1_client.c
index 2fa43ad..49ebf2f 100644
--- a/src/tls/tlsv1_client.c
+++ b/src/tls/tlsv1_client.c
@@ -826,3 +826,15 @@ void tlsv1_client_set_session_ticket_cb(struct tlsv1_client *conn,
conn->session_ticket_cb = cb;
conn->session_ticket_cb_ctx = ctx;
}
+
+
+void tlsv1_client_set_cb(struct tlsv1_client *conn,
+ void (*event_cb)(void *ctx, enum tls_event ev,
+ union tls_event_data *data),
+ void *cb_ctx,
+ int cert_in_cb)
+{
+ conn->event_cb = event_cb;
+ conn->cb_ctx = cb_ctx;
+ conn->cert_in_cb = !!cert_in_cb;
+}
diff --git a/src/tls/tlsv1_client.h b/src/tls/tlsv1_client.h
index a4e25e9..bbfb8bd 100644
--- a/src/tls/tlsv1_client.h
+++ b/src/tls/tlsv1_client.h
@@ -51,4 +51,10 @@ void tlsv1_client_set_session_ticket_cb(struct tlsv1_client *conn,
tlsv1_client_session_ticket_cb cb,
void *ctx);
+void tlsv1_client_set_cb(struct tlsv1_client *conn,
+ void (*event_cb)(void *ctx, enum tls_event ev,
+ union tls_event_data *data),
+ void *cb_ctx,
+ int cert_in_cb);
+
#endif /* TLSV1_CLIENT_H */
diff --git a/src/tls/tlsv1_client_i.h b/src/tls/tlsv1_client_i.h
index 55fdcf8..1c517a8 100644
--- a/src/tls/tlsv1_client_i.h
+++ b/src/tls/tlsv1_client_i.h
@@ -34,6 +34,7 @@ struct tlsv1_client {
unsigned int session_ticket_included:1;
unsigned int use_session_ticket:1;
unsigned int disable_time_checks:1;
+ unsigned int cert_in_cb:1;
struct crypto_public_key *server_rsa_key;
@@ -64,6 +65,10 @@ struct tlsv1_client {
void *session_ticket_cb_ctx;
struct wpabuf *partial_input;
+
+ void (*event_cb)(void *ctx, enum tls_event ev,
+ union tls_event_data *data);
+ void *cb_ctx;
};
diff --git a/src/tls/tlsv1_client_read.c b/src/tls/tlsv1_client_read.c
index 294ae00..a2cd478 100644
--- a/src/tls/tlsv1_client_read.c
+++ b/src/tls/tlsv1_client_read.c
@@ -211,6 +211,47 @@ decode_error:
}
+static void tls_peer_cert_event(struct tlsv1_client *conn, int depth,
+ struct x509_certificate *cert)
+{
+ union tls_event_data ev;
+ struct wpabuf *cert_buf = NULL;
+#ifdef CONFIG_SHA256
+ u8 hash[32];
+#endif /* CONFIG_SHA256 */
+ char subject[128];
+
+ if (!conn->event_cb)
+ return;
+
+ os_memset(&ev, 0, sizeof(ev));
+ if (conn->cred->cert_probe || conn->cert_in_cb) {
+ cert_buf = wpabuf_alloc_copy(cert->cert_start,
+ cert->cert_len);
+ ev.peer_cert.cert = cert_buf;
+ }
+#ifdef CONFIG_SHA256
+ if (cert_buf) {
+ const u8 *addr[1];
+ size_t len[1];
+ addr[0] = wpabuf_head(cert_buf);
+ len[0] = wpabuf_len(cert_buf);
+ if (sha256_vector(1, addr, len, hash) == 0) {
+ ev.peer_cert.hash = hash;
+ ev.peer_cert.hash_len = sizeof(hash);
+ }
+ }
+#endif /* CONFIG_SHA256 */
+
+ ev.peer_cert.depth = depth;
+ x509_name_string(&cert->subject, subject, sizeof(subject));
+ ev.peer_cert.subject = subject;
+
+ conn->event_cb(conn->cb_ctx, TLS_PEER_CERTIFICATE, &ev);
+ wpabuf_free(cert_buf);
+}
+
+
static int tls_process_certificate(struct tlsv1_client *conn, u8 ct,
const u8 *in_data, size_t *in_len)
{
@@ -354,6 +395,8 @@ static int tls_process_certificate(struct tlsv1_client *conn, u8 ct,
return -1;
}
+ tls_peer_cert_event(conn, idx, cert);
+
if (last == NULL)
chain = cert;
else
@@ -380,11 +423,45 @@ static int tls_process_certificate(struct tlsv1_client *conn, u8 ct,
"TLSv1: Server certificate hash mismatch");
wpa_hexdump(MSG_MSGDUMP, "TLSv1: SHA256 hash",
hash, SHA256_MAC_LEN);
+ if (conn->event_cb) {
+ union tls_event_data ev;
+
+ os_memset(&ev, 0, sizeof(ev));
+ ev.cert_fail.reason = TLS_FAIL_UNSPECIFIED;
+ ev.cert_fail.reason_txt =
+ "Server certificate mismatch";
+ ev.cert_fail.subject = buf;
+ conn->event_cb(conn->cb_ctx,
+ TLS_CERT_CHAIN_FAILURE, &ev);
+ }
tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
TLS_ALERT_BAD_CERTIFICATE);
x509_certificate_chain_free(chain);
return -1;
}
+ } else if (conn->cred && conn->cred->cert_probe) {
+ wpa_printf(MSG_DEBUG,
+ "TLSv1: Reject server certificate on probe-only rune");
+ if (conn->event_cb) {
+ union tls_event_data ev;
+ char buf[128];
+
+ os_memset(&ev, 0, sizeof(ev));
+ ev.cert_fail.reason = TLS_FAIL_SERVER_CHAIN_PROBE;
+ ev.cert_fail.reason_txt =
+ "Server certificate chain probe";
+ if (chain) {
+ x509_name_string(&chain->subject, buf,
+ sizeof(buf));
+ ev.cert_fail.subject = buf;
+ }
+ conn->event_cb(conn->cb_ctx, TLS_CERT_CHAIN_FAILURE,
+ &ev);
+ }
+ tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
+ TLS_ALERT_BAD_CERTIFICATE);
+ x509_certificate_chain_free(chain);
+ return -1;
} else if (conn->cred && conn->cred->ca_cert_verify &&
x509_certificate_chain_validate(conn->cred->trusted_certs,
chain, &reason,
diff --git a/src/tls/tlsv1_cred.c b/src/tls/tlsv1_cred.c
index 3ed21ec..067562b 100644
--- a/src/tls/tlsv1_cred.c
+++ b/src/tls/tlsv1_cred.c
@@ -218,6 +218,13 @@ int tlsv1_set_ca_cert(struct tlsv1_credentials *cred, const char *cert,
return 0;
}
+ if (cert && os_strncmp(cert, "probe://", 8) == 0) {
+ cred->cert_probe = 1;
+ cred->ca_cert_verify = 0;
+ wpa_printf(MSG_DEBUG, "TLSv1: Only probe server certificate");
+ return 0;
+ }
+
cred->ca_cert_verify = cert || cert_blob || path;
if (tlsv1_set_cert_chain(&cred->trusted_certs, cert,
diff --git a/src/tls/tlsv1_cred.h b/src/tls/tlsv1_cred.h
index ac72b8c..b4bfe38 100644
--- a/src/tls/tlsv1_cred.h
+++ b/src/tls/tlsv1_cred.h
@@ -14,6 +14,7 @@ struct tlsv1_credentials {
struct x509_certificate *cert;
struct crypto_private_key *key;
+ unsigned int cert_probe:1;
unsigned int ca_cert_verify:1;
unsigned int server_cert_only:1;
u8 srv_cert_hash[32];