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>
This commit is contained in:
parent
b115eebe01
commit
f2a6ad01a9
7 changed files with 120 additions and 0 deletions
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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];
|
||||
|
|
Loading…
Reference in a new issue