Add TLS client events, server probing, and srv cert matching
This allows external programs (e.g., UI) to get more information about server certificate chain used during TLS handshake. This can be used both to automatically probe the authentication server to figure out most likely network configuration and to get information about reasons for failed authentications. The follow new control interface events are used for this: CTRL-EVENT-EAP-PEER-CERT CTRL-EVENT-EAP-TLS-CERT-ERROR In addition, there is now an option for matching the server certificate instead of the full certificate chain for cases where a trusted CA is not configured or even known. This can be used, e.g., by first probing the network and learning the server certificate hash based on the new events and then adding a network configuration with the server certificate hash after user have accepted it. Future connections will then be allowed as long as the same server certificate is used. Authentication server probing can be done, e.g., with following configuration options: eap=TTLS PEAP TLS identity="" ca_cert="probe://" Example set of control events for this: CTRL-EVENT-EAP-STARTED EAP authentication started CTRL-EVENT-EAP-PROPOSED-METHOD vendor=0 method=21 CTRL-EVENT-EAP-METHOD EAP vendor 0 method 21 (TTLS) selected CTRL-EVENT-EAP-PEER-CERT depth=0 subject='/C=US/ST=California/L=San Francisco/CN=Server/emailAddress=server@kir.nu' hash=5a1bc1296205e6fdbe3979728efe3920798885c1c4590b5f90f43222d239ca6a CTRL-EVENT-EAP-TLS-CERT-ERROR reason=8 depth=0 subject='/C=US/ST=California/L=San Francisco/CN=Server/emailAddress=server@kir.nu' err='Server certificate chain probe' CTRL-EVENT-EAP-FAILURE EAP authentication failed Server certificate matching is configured with ca_cert, e.g.: ca_cert="hash://server/sha256/5a1bc1296205e6fdbe3979728efe3920798885c1c4590b5f90f43222d239ca6a" This functionality is currently available only with OpenSSL. Other TLS libraries (including internal implementation) may be added in the future.
This commit is contained in:
parent
c7d711609b
commit
00468b4650
7 changed files with 383 additions and 24 deletions
|
@ -44,6 +44,10 @@ extern "C" {
|
|||
#define WPA_EVENT_EAP_PROPOSED_METHOD "CTRL-EVENT-EAP-PROPOSED-METHOD "
|
||||
/** EAP method selected */
|
||||
#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 TLS certificate chain validation error */
|
||||
#define WPA_EVENT_EAP_TLS_CERT_ERROR "CTRL-EVENT-EAP-TLS-CERT-ERROR "
|
||||
/** EAP authentication completed successfully */
|
||||
#define WPA_EVENT_EAP_SUCCESS "CTRL-EVENT-EAP-SUCCESS "
|
||||
/** EAP authentication failed (EAP-Failure received) */
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
/*
|
||||
* SSL/TLS interface definition
|
||||
* Copyright (c) 2004-2009, Jouni Malinen <j@w1.fi>
|
||||
* Copyright (c) 2004-2010, Jouni Malinen <j@w1.fi>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
|
@ -28,11 +28,54 @@ struct tls_keys {
|
|||
size_t inner_secret_len;
|
||||
};
|
||||
|
||||
enum tls_event {
|
||||
TLS_CERT_CHAIN_FAILURE,
|
||||
TLS_PEER_CERTIFICATE
|
||||
};
|
||||
|
||||
/*
|
||||
* Note: These are used as identifier with external programs and as such, the
|
||||
* values must not be changed.
|
||||
*/
|
||||
enum tls_fail_reason {
|
||||
TLS_FAIL_UNSPECIFIED = 0,
|
||||
TLS_FAIL_UNTRUSTED = 1,
|
||||
TLS_FAIL_REVOKED = 2,
|
||||
TLS_FAIL_NOT_YET_VALID = 3,
|
||||
TLS_FAIL_EXPIRED = 4,
|
||||
TLS_FAIL_SUBJECT_MISMATCH = 5,
|
||||
TLS_FAIL_ALTSUBJECT_MISMATCH = 6,
|
||||
TLS_FAIL_BAD_CERTIFICATE = 7,
|
||||
TLS_FAIL_SERVER_CHAIN_PROBE = 8
|
||||
};
|
||||
|
||||
union tls_event_data {
|
||||
struct {
|
||||
int depth;
|
||||
const char *subject;
|
||||
enum tls_fail_reason reason;
|
||||
const char *reason_txt;
|
||||
const struct wpabuf *cert;
|
||||
} cert_fail;
|
||||
|
||||
struct {
|
||||
int depth;
|
||||
const char *subject;
|
||||
const struct wpabuf *cert;
|
||||
const u8 *hash;
|
||||
size_t hash_len;
|
||||
} peer_cert;
|
||||
};
|
||||
|
||||
struct tls_config {
|
||||
const char *opensc_engine_path;
|
||||
const char *pkcs11_engine_path;
|
||||
const char *pkcs11_module_path;
|
||||
int fips_mode;
|
||||
|
||||
void (*event_cb)(void *ctx, enum tls_event ev,
|
||||
union tls_event_data *data);
|
||||
void *cb_ctx;
|
||||
};
|
||||
|
||||
#define TLS_CONN_ALLOW_SIGN_RSA_MD5 BIT(0)
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
/*
|
||||
* SSL/TLS interface functions for OpenSSL
|
||||
* Copyright (c) 2004-2009, Jouni Malinen <j@w1.fi>
|
||||
* Copyright (c) 2004-2010, Jouni Malinen <j@w1.fi>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
|
@ -29,6 +29,7 @@
|
|||
#endif /* OPENSSL_NO_ENGINE */
|
||||
|
||||
#include "common.h"
|
||||
#include "crypto.h"
|
||||
#include "tls.h"
|
||||
|
||||
#if OPENSSL_VERSION_NUMBER >= 0x0090800fL
|
||||
|
@ -49,6 +50,15 @@
|
|||
|
||||
static int tls_openssl_ref_count = 0;
|
||||
|
||||
struct tls_global {
|
||||
void (*event_cb)(void *ctx, enum tls_event ev,
|
||||
union tls_event_data *data);
|
||||
void *cb_ctx;
|
||||
};
|
||||
|
||||
static struct tls_global *tls_global = NULL;
|
||||
|
||||
|
||||
struct tls_connection {
|
||||
SSL *ssl;
|
||||
BIO *ssl_in, *ssl_out;
|
||||
|
@ -65,6 +75,12 @@ struct tls_connection {
|
|||
/* SessionTicket received from OpenSSL hello_extension_cb (server) */
|
||||
u8 *session_ticket;
|
||||
size_t session_ticket_len;
|
||||
|
||||
int ca_cert_verify:1;
|
||||
int cert_probe:1;
|
||||
int server_cert_only:1;
|
||||
|
||||
u8 srv_cert_hash[32];
|
||||
};
|
||||
|
||||
|
||||
|
@ -665,6 +681,14 @@ void * tls_init(const struct tls_config *conf)
|
|||
SSL_CTX *ssl;
|
||||
|
||||
if (tls_openssl_ref_count == 0) {
|
||||
tls_global = os_zalloc(sizeof(*tls_global));
|
||||
if (tls_global == NULL)
|
||||
return NULL;
|
||||
if (conf) {
|
||||
tls_global->event_cb = conf->event_cb;
|
||||
tls_global->cb_ctx = conf->cb_ctx;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_FIPS
|
||||
#ifdef OPENSSL_FIPS
|
||||
if (conf && conf->fips_mode) {
|
||||
|
@ -750,6 +774,8 @@ void tls_deinit(void *ssl_ctx)
|
|||
ERR_remove_state(0);
|
||||
ERR_free_strings();
|
||||
EVP_cleanup();
|
||||
os_free(tls_global);
|
||||
tls_global = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1016,6 +1042,124 @@ static int tls_match_altsubject(X509 *cert, const char *match)
|
|||
}
|
||||
|
||||
|
||||
static enum tls_fail_reason openssl_tls_fail_reason(int err)
|
||||
{
|
||||
switch (err) {
|
||||
case X509_V_ERR_CERT_REVOKED:
|
||||
return TLS_FAIL_REVOKED;
|
||||
case X509_V_ERR_CERT_NOT_YET_VALID:
|
||||
case X509_V_ERR_CRL_NOT_YET_VALID:
|
||||
return TLS_FAIL_NOT_YET_VALID;
|
||||
case X509_V_ERR_CERT_HAS_EXPIRED:
|
||||
case X509_V_ERR_CRL_HAS_EXPIRED:
|
||||
return TLS_FAIL_EXPIRED;
|
||||
case X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT:
|
||||
case X509_V_ERR_UNABLE_TO_GET_CRL:
|
||||
case X509_V_ERR_UNABLE_TO_GET_CRL_ISSUER:
|
||||
case X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN:
|
||||
case X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY:
|
||||
case X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT:
|
||||
case X509_V_ERR_UNABLE_TO_VERIFY_LEAF_SIGNATURE:
|
||||
case X509_V_ERR_CERT_CHAIN_TOO_LONG:
|
||||
case X509_V_ERR_PATH_LENGTH_EXCEEDED:
|
||||
case X509_V_ERR_INVALID_CA:
|
||||
return TLS_FAIL_UNTRUSTED;
|
||||
case X509_V_ERR_UNABLE_TO_DECRYPT_CERT_SIGNATURE:
|
||||
case X509_V_ERR_UNABLE_TO_DECRYPT_CRL_SIGNATURE:
|
||||
case X509_V_ERR_UNABLE_TO_DECODE_ISSUER_PUBLIC_KEY:
|
||||
case X509_V_ERR_ERROR_IN_CERT_NOT_BEFORE_FIELD:
|
||||
case X509_V_ERR_ERROR_IN_CERT_NOT_AFTER_FIELD:
|
||||
case X509_V_ERR_ERROR_IN_CRL_LAST_UPDATE_FIELD:
|
||||
case X509_V_ERR_ERROR_IN_CRL_NEXT_UPDATE_FIELD:
|
||||
case X509_V_ERR_CERT_UNTRUSTED:
|
||||
case X509_V_ERR_CERT_REJECTED:
|
||||
return TLS_FAIL_BAD_CERTIFICATE;
|
||||
default:
|
||||
return TLS_FAIL_UNSPECIFIED;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static struct wpabuf * get_x509_cert(X509 *cert)
|
||||
{
|
||||
struct wpabuf *buf;
|
||||
u8 *tmp;
|
||||
|
||||
int cert_len = i2d_X509(cert, NULL);
|
||||
if (cert_len <= 0)
|
||||
return NULL;
|
||||
|
||||
buf = wpabuf_alloc(cert_len);
|
||||
if (buf == NULL)
|
||||
return NULL;
|
||||
|
||||
tmp = wpabuf_put(buf, cert_len);
|
||||
i2d_X509(cert, &tmp);
|
||||
return buf;
|
||||
}
|
||||
|
||||
|
||||
static void openssl_tls_fail_event(struct tls_connection *conn,
|
||||
X509 *err_cert, int err, int depth,
|
||||
const char *subject, const char *err_str,
|
||||
enum tls_fail_reason reason)
|
||||
{
|
||||
union tls_event_data ev;
|
||||
struct wpabuf *cert = NULL;
|
||||
|
||||
if (tls_global->event_cb == NULL)
|
||||
return;
|
||||
|
||||
cert = get_x509_cert(err_cert);
|
||||
os_memset(&ev, 0, sizeof(ev));
|
||||
ev.cert_fail.reason = reason != TLS_FAIL_UNSPECIFIED ?
|
||||
reason : openssl_tls_fail_reason(err);
|
||||
ev.cert_fail.depth = depth;
|
||||
ev.cert_fail.subject = subject;
|
||||
ev.cert_fail.reason_txt = err_str;
|
||||
ev.cert_fail.cert = cert;
|
||||
tls_global->event_cb(tls_global->cb_ctx, TLS_CERT_CHAIN_FAILURE, &ev);
|
||||
wpabuf_free(cert);
|
||||
}
|
||||
|
||||
|
||||
static void openssl_tls_cert_event(struct tls_connection *conn,
|
||||
X509 *err_cert, int depth,
|
||||
const char *subject)
|
||||
{
|
||||
struct wpabuf *cert = NULL;
|
||||
union tls_event_data ev;
|
||||
#ifdef CONFIG_SHA256
|
||||
u8 hash[32];
|
||||
#endif /* CONFIG_SHA256 */
|
||||
|
||||
if (tls_global->event_cb == NULL)
|
||||
return;
|
||||
|
||||
os_memset(&ev, 0, sizeof(ev));
|
||||
if (conn->cert_probe) {
|
||||
cert = get_x509_cert(err_cert);
|
||||
ev.peer_cert.cert = cert;
|
||||
}
|
||||
#ifdef CONFIG_SHA256
|
||||
if (cert) {
|
||||
const u8 *addr[1];
|
||||
size_t len[1];
|
||||
addr[0] = wpabuf_head(cert);
|
||||
len[0] = wpabuf_len(cert);
|
||||
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;
|
||||
ev.peer_cert.subject = subject;
|
||||
tls_global->event_cb(tls_global->cb_ctx, TLS_PEER_CERTIFICATE, &ev);
|
||||
wpabuf_free(cert);
|
||||
}
|
||||
|
||||
|
||||
static int tls_verify_cb(int preverify_ok, X509_STORE_CTX *x509_ctx)
|
||||
{
|
||||
char buf[256];
|
||||
|
@ -1024,6 +1168,7 @@ static int tls_verify_cb(int preverify_ok, X509_STORE_CTX *x509_ctx)
|
|||
SSL *ssl;
|
||||
struct tls_connection *conn;
|
||||
char *match, *altmatch;
|
||||
const char *err_str;
|
||||
|
||||
err_cert = X509_STORE_CTX_get_current_cert(x509_ctx);
|
||||
err = X509_STORE_CTX_get_error(x509_ctx);
|
||||
|
@ -1036,25 +1181,76 @@ static int tls_verify_cb(int preverify_ok, X509_STORE_CTX *x509_ctx)
|
|||
match = conn ? conn->subject_match : NULL;
|
||||
altmatch = conn ? conn->altsubject_match : NULL;
|
||||
|
||||
if (!preverify_ok && !conn->ca_cert_verify)
|
||||
preverify_ok = 1;
|
||||
if (!preverify_ok && depth > 0 && conn->server_cert_only)
|
||||
preverify_ok = 1;
|
||||
|
||||
err_str = X509_verify_cert_error_string(err);
|
||||
|
||||
#ifdef CONFIG_SHA256
|
||||
if (preverify_ok && depth == 0 && conn->server_cert_only) {
|
||||
struct wpabuf *cert;
|
||||
cert = get_x509_cert(err_cert);
|
||||
if (!cert) {
|
||||
wpa_printf(MSG_DEBUG, "OpenSSL: Could not fetch "
|
||||
"server certificate data");
|
||||
preverify_ok = 0;
|
||||
} else {
|
||||
u8 hash[32];
|
||||
const u8 *addr[1];
|
||||
size_t len[1];
|
||||
addr[0] = wpabuf_head(cert);
|
||||
len[0] = wpabuf_len(cert);
|
||||
if (sha256_vector(1, addr, len, hash) < 0 ||
|
||||
os_memcmp(conn->srv_cert_hash, hash, 32) != 0) {
|
||||
err_str = "Server certificate mismatch";
|
||||
err = X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN;
|
||||
preverify_ok = 0;
|
||||
}
|
||||
wpabuf_free(cert);
|
||||
}
|
||||
}
|
||||
#endif /* CONFIG_SHA256 */
|
||||
|
||||
if (!preverify_ok) {
|
||||
wpa_printf(MSG_WARNING, "TLS: Certificate verification failed,"
|
||||
" error %d (%s) depth %d for '%s'", err,
|
||||
X509_verify_cert_error_string(err), depth, buf);
|
||||
} else {
|
||||
wpa_printf(MSG_DEBUG, "TLS: tls_verify_cb - "
|
||||
"preverify_ok=%d err=%d (%s) depth=%d buf='%s'",
|
||||
preverify_ok, err,
|
||||
X509_verify_cert_error_string(err), depth, buf);
|
||||
if (depth == 0 && match && os_strstr(buf, match) == NULL) {
|
||||
wpa_printf(MSG_WARNING, "TLS: Subject '%s' did not "
|
||||
"match with '%s'", buf, match);
|
||||
preverify_ok = 0;
|
||||
} else if (depth == 0 && altmatch &&
|
||||
!tls_match_altsubject(err_cert, altmatch)) {
|
||||
wpa_printf(MSG_WARNING, "TLS: altSubjectName match "
|
||||
"'%s' not found", altmatch);
|
||||
preverify_ok = 0;
|
||||
}
|
||||
" error %d (%s) depth %d for '%s'", err, err_str,
|
||||
depth, buf);
|
||||
openssl_tls_fail_event(conn, err_cert, err, depth, buf,
|
||||
err_str, TLS_FAIL_UNSPECIFIED);
|
||||
return preverify_ok;
|
||||
}
|
||||
|
||||
wpa_printf(MSG_DEBUG, "TLS: tls_verify_cb - preverify_ok=%d "
|
||||
"err=%d (%s) ca_cert_verify=%d depth=%d buf='%s'",
|
||||
preverify_ok, err, err_str,
|
||||
conn->ca_cert_verify, depth, buf);
|
||||
if (depth == 0 && match && os_strstr(buf, match) == NULL) {
|
||||
wpa_printf(MSG_WARNING, "TLS: Subject '%s' did not "
|
||||
"match with '%s'", buf, match);
|
||||
preverify_ok = 0;
|
||||
openssl_tls_fail_event(conn, err_cert, err, depth, buf,
|
||||
"Subject mismatch",
|
||||
TLS_FAIL_SUBJECT_MISMATCH);
|
||||
} else if (depth == 0 && altmatch &&
|
||||
!tls_match_altsubject(err_cert, altmatch)) {
|
||||
wpa_printf(MSG_WARNING, "TLS: altSubjectName match "
|
||||
"'%s' not found", altmatch);
|
||||
preverify_ok = 0;
|
||||
openssl_tls_fail_event(conn, err_cert, err, depth, buf,
|
||||
"AltSubject mismatch",
|
||||
TLS_FAIL_ALTSUBJECT_MISMATCH);
|
||||
} else
|
||||
openssl_tls_cert_event(conn, err_cert, depth, buf);
|
||||
|
||||
if (conn->cert_probe && preverify_ok && depth == 0) {
|
||||
wpa_printf(MSG_DEBUG, "OpenSSL: Reject server certificate "
|
||||
"on probe-only run");
|
||||
preverify_ok = 0;
|
||||
openssl_tls_fail_event(conn, err_cert, err, depth, buf,
|
||||
"Server certificate chain probe",
|
||||
TLS_FAIL_SERVER_CHAIN_PROBE);
|
||||
}
|
||||
|
||||
return preverify_ok;
|
||||
|
@ -1112,6 +1308,47 @@ static int tls_connection_ca_cert(void *_ssl_ctx, struct tls_connection *conn,
|
|||
return -1;
|
||||
}
|
||||
|
||||
SSL_set_verify(conn->ssl, SSL_VERIFY_PEER, tls_verify_cb);
|
||||
conn->ca_cert_verify = 1;
|
||||
|
||||
if (ca_cert && os_strncmp(ca_cert, "probe://", 8) == 0) {
|
||||
wpa_printf(MSG_DEBUG, "OpenSSL: Probe for server certificate "
|
||||
"chain");
|
||||
conn->cert_probe = 1;
|
||||
conn->ca_cert_verify = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (ca_cert && os_strncmp(ca_cert, "hash://", 7) == 0) {
|
||||
#ifdef CONFIG_SHA256
|
||||
const char *pos = ca_cert + 7;
|
||||
if (os_strncmp(pos, "server/sha256/", 14) != 0) {
|
||||
wpa_printf(MSG_DEBUG, "OpenSSL: Unsupported ca_cert "
|
||||
"hash value '%s'", ca_cert);
|
||||
return -1;
|
||||
}
|
||||
pos += 14;
|
||||
if (os_strlen(pos) != 32 * 2) {
|
||||
wpa_printf(MSG_DEBUG, "OpenSSL: Unexpected SHA256 "
|
||||
"hash length in ca_cert '%s'", ca_cert);
|
||||
return -1;
|
||||
}
|
||||
if (hexstr2bin(pos, conn->srv_cert_hash, 32) < 0) {
|
||||
wpa_printf(MSG_DEBUG, "OpenSSL: Invalid SHA256 hash "
|
||||
"value in ca_cert '%s'", ca_cert);
|
||||
return -1;
|
||||
}
|
||||
conn->server_cert_only = 1;
|
||||
wpa_printf(MSG_DEBUG, "OpenSSL: Checking only server "
|
||||
"certificate match");
|
||||
return 0;
|
||||
#else /* CONFIG_SHA256 */
|
||||
wpa_printf(MSG_INFO, "No SHA256 included in the build - "
|
||||
"cannot validate server certificate hash");
|
||||
return -1;
|
||||
#endif /* CONFIG_SHA256 */
|
||||
}
|
||||
|
||||
if (ca_cert_blob) {
|
||||
X509 *cert = d2i_X509(NULL, (OPENSSL_d2i_TYPE) &ca_cert_blob,
|
||||
ca_cert_blob_len);
|
||||
|
@ -1140,7 +1377,6 @@ static int tls_connection_ca_cert(void *_ssl_ctx, struct tls_connection *conn,
|
|||
X509_free(cert);
|
||||
wpa_printf(MSG_DEBUG, "OpenSSL: %s - added ca_cert_blob "
|
||||
"to certificate store", __func__);
|
||||
SSL_set_verify(conn->ssl, SSL_VERIFY_PEER, tls_verify_cb);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -1149,7 +1385,6 @@ static int tls_connection_ca_cert(void *_ssl_ctx, struct tls_connection *conn,
|
|||
0) {
|
||||
wpa_printf(MSG_DEBUG, "OpenSSL: Added CA certificates from "
|
||||
"system certificate store");
|
||||
SSL_set_verify(conn->ssl, SSL_VERIFY_PEER, tls_verify_cb);
|
||||
return 0;
|
||||
}
|
||||
#endif /* CONFIG_NATIVE_WINDOWS */
|
||||
|
@ -1172,7 +1407,6 @@ static int tls_connection_ca_cert(void *_ssl_ctx, struct tls_connection *conn,
|
|||
"certificate(s) loaded");
|
||||
tls_get_errors(ssl_ctx);
|
||||
}
|
||||
SSL_set_verify(conn->ssl, SSL_VERIFY_PEER, tls_verify_cb);
|
||||
#else /* OPENSSL_NO_STDIO */
|
||||
wpa_printf(MSG_DEBUG, "OpenSSL: %s - OPENSSL_NO_STDIO",
|
||||
__func__);
|
||||
|
@ -1181,7 +1415,7 @@ static int tls_connection_ca_cert(void *_ssl_ctx, struct tls_connection *conn,
|
|||
} else {
|
||||
/* No ca_cert configured - do not try to verify server
|
||||
* certificate */
|
||||
SSL_set_verify(conn->ssl, SSL_VERIFY_NONE, NULL);
|
||||
conn->ca_cert_verify = 0;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
@ -1266,10 +1500,12 @@ int tls_connection_set_verify(void *ssl_ctx, struct tls_connection *conn,
|
|||
return -1;
|
||||
|
||||
if (verify_peer) {
|
||||
conn->ca_cert_verify = 1;
|
||||
SSL_set_verify(conn->ssl, SSL_VERIFY_PEER |
|
||||
SSL_VERIFY_FAIL_IF_NO_PEER_CERT |
|
||||
SSL_VERIFY_CLIENT_ONCE, tls_verify_cb);
|
||||
} else {
|
||||
conn->ca_cert_verify = 0;
|
||||
SSL_set_verify(conn->ssl, SSL_VERIFY_NONE, NULL);
|
||||
}
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
/*
|
||||
* EAP peer state machines (RFC 4137)
|
||||
* Copyright (c) 2004-2008, Jouni Malinen <j@w1.fi>
|
||||
* Copyright (c) 2004-2010, Jouni Malinen <j@w1.fi>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
|
@ -1160,6 +1160,60 @@ static void eap_sm_parseEapReq(struct eap_sm *sm, const struct wpabuf *req)
|
|||
}
|
||||
|
||||
|
||||
static void eap_peer_sm_tls_event(void *ctx, enum tls_event ev,
|
||||
union tls_event_data *data)
|
||||
{
|
||||
struct eap_sm *sm = ctx;
|
||||
char *hash_hex = NULL;
|
||||
char *cert_hex = NULL;
|
||||
|
||||
switch (ev) {
|
||||
case TLS_CERT_CHAIN_FAILURE:
|
||||
wpa_msg(sm->msg_ctx, MSG_INFO, WPA_EVENT_EAP_TLS_CERT_ERROR
|
||||
"reason=%d depth=%d subject='%s' err='%s'",
|
||||
data->cert_fail.reason,
|
||||
data->cert_fail.depth,
|
||||
data->cert_fail.subject,
|
||||
data->cert_fail.reason_txt);
|
||||
break;
|
||||
case TLS_PEER_CERTIFICATE:
|
||||
if (data->peer_cert.hash) {
|
||||
size_t len = data->peer_cert.hash_len * 2 + 1;
|
||||
hash_hex = os_malloc(len);
|
||||
if (hash_hex) {
|
||||
wpa_snprintf_hex(hash_hex, len,
|
||||
data->peer_cert.hash,
|
||||
data->peer_cert.hash_len);
|
||||
}
|
||||
}
|
||||
wpa_msg(sm->msg_ctx, MSG_INFO, WPA_EVENT_EAP_PEER_CERT
|
||||
"depth=%d subject='%s'%s%s",
|
||||
data->peer_cert.depth, data->peer_cert.subject,
|
||||
hash_hex ? " hash=" : "", hash_hex ? hash_hex : "");
|
||||
|
||||
if (data->peer_cert.cert) {
|
||||
size_t len = wpabuf_len(data->peer_cert.cert) * 2 + 1;
|
||||
cert_hex = os_malloc(len);
|
||||
if (cert_hex == NULL)
|
||||
break;
|
||||
wpa_snprintf_hex(cert_hex, len,
|
||||
wpabuf_head(data->peer_cert.cert),
|
||||
wpabuf_len(data->peer_cert.cert));
|
||||
wpa_msg_ctrl(sm->msg_ctx, MSG_INFO,
|
||||
WPA_EVENT_EAP_PEER_CERT
|
||||
"depth=%d subject='%s' cert=%s",
|
||||
data->peer_cert.depth,
|
||||
data->peer_cert.subject,
|
||||
cert_hex);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
os_free(hash_hex);
|
||||
os_free(cert_hex);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* eap_peer_sm_init - Allocate and initialize EAP peer state machine
|
||||
* @eapol_ctx: Context data to be used with eapol_cb calls
|
||||
|
@ -1197,6 +1251,8 @@ struct eap_sm * eap_peer_sm_init(void *eapol_ctx,
|
|||
#ifdef CONFIG_FIPS
|
||||
tlsconf.fips_mode = 1;
|
||||
#endif /* CONFIG_FIPS */
|
||||
tlsconf.event_cb = eap_peer_sm_tls_event;
|
||||
tlsconf.cb_ctx = sm;
|
||||
sm->ssl_ctx = tls_init(&tlsconf);
|
||||
if (sm->ssl_ctx == NULL) {
|
||||
wpa_printf(MSG_WARNING, "SSL: Failed to initialize TLS "
|
||||
|
|
|
@ -85,6 +85,15 @@ struct eap_peer_config {
|
|||
* Alternatively, a named configuration blob can be used by setting
|
||||
* this to blob://blob_name.
|
||||
*
|
||||
* Alternatively, this can be used to only perform matching of the
|
||||
* server certificate (SHA-256 hash of the DER encoded X.509
|
||||
* certificate). In this case, the possible CA certificates in the
|
||||
* server certificate chain are ignored and only the server certificate
|
||||
* is verified. This is configured with the following format:
|
||||
* hash:://server/sha256/cert_hash_in_hex
|
||||
* For example: "hash://server/sha256/
|
||||
* 5a1bc1296205e6fdbe3979728efe3920798885c1c4590b5f90f43222d239ca6a"
|
||||
*
|
||||
* On Windows, trusted CA certificates can be loaded from the system
|
||||
* certificate store by setting this to cert_store://name, e.g.,
|
||||
* ca_cert="cert_store://CA" or ca_cert="cert_store://ROOT".
|
||||
|
|
|
@ -999,6 +999,7 @@ endif
|
|||
|
||||
SHA256OBJS = # none by default
|
||||
ifdef NEED_SHA256
|
||||
CFLAGS += -DCONFIG_SHA256
|
||||
SHA256OBJS += ../src/crypto/sha256.o
|
||||
ifdef CONFIG_INTERNAL_SHA256
|
||||
SHA256OBJS += ../src/crypto/sha256-internal.o
|
||||
|
|
|
@ -390,6 +390,16 @@ fast_reauth=1
|
|||
# a trusted CA certificate should always be configured when using
|
||||
# EAP-TLS/TTLS/PEAP. Full path should be used since working directory may
|
||||
# change when wpa_supplicant is run in the background.
|
||||
#
|
||||
# Alternatively, this can be used to only perform matching of the server
|
||||
# certificate (SHA-256 hash of the DER encoded X.509 certificate). In
|
||||
# this case, the possible CA certificates in the server certificate chain
|
||||
# are ignored and only the server certificate is verified. This is
|
||||
# configured with the following format:
|
||||
# hash:://server/sha256/cert_hash_in_hex
|
||||
# For example: "hash://server/sha256/
|
||||
# 5a1bc1296205e6fdbe3979728efe3920798885c1c4590b5f90f43222d239ca6a"
|
||||
#
|
||||
# On Windows, trusted CA certificates can be loaded from the system
|
||||
# certificate store by setting this to cert_store://<name>, e.g.,
|
||||
# ca_cert="cert_store://CA" or ca_cert="cert_store://ROOT".
|
||||
|
|
Loading…
Reference in a new issue