diff --git a/src/crypto/tls_internal.c b/src/crypto/tls_internal.c index 1b82245e0..b91f181e2 100644 --- a/src/crypto/tls_internal.c +++ b/src/crypto/tls_internal.c @@ -23,6 +23,11 @@ struct tls_global { int server; struct tlsv1_credentials *server_cred; int check_crl; + + void (*event_cb)(void *ctx, enum tls_event ev, + union tls_event_data *data); + void *cb_ctx; + int cert_in_cb; }; struct tls_connection { @@ -51,6 +56,11 @@ void * tls_init(const struct tls_config *conf) global = os_zalloc(sizeof(*global)); if (global == NULL) return NULL; + if (conf) { + global->event_cb = conf->event_cb; + global->cb_ctx = conf->cb_ctx; + global->cert_in_cb = conf->cert_in_cb; + } return global; } @@ -97,6 +107,8 @@ struct tls_connection * tls_connection_init(void *tls_ctx) os_free(conn); return NULL; } + tlsv1_client_set_cb(conn->client, global->event_cb, + global->cb_ctx, global->cert_in_cb); } #endif /* CONFIG_TLS_INTERNAL_CLIENT */ #ifdef CONFIG_TLS_INTERNAL_SERVER diff --git a/src/tls/tlsv1_client.c b/src/tls/tlsv1_client.c index 2fa43add7..49ebf2ff3 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 a4e25e969..bbfb8bdd9 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 55fdcf8d0..1c517a8f3 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 294ae0081..a2cd478e8 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 3ed21ec1c..067562b6b 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 ac72b8c22..b4bfe38d5 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];