summaryrefslogtreecommitdiff
path: root/src/crypto/tls_openssl.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/crypto/tls_openssl.c')
-rw-r--r--src/crypto/tls_openssl.c320
1 files changed, 300 insertions, 20 deletions
diff --git a/src/crypto/tls_openssl.c b/src/crypto/tls_openssl.c
index b0c23ae6c9b1f..07d38e47b917d 100644
--- a/src/crypto/tls_openssl.c
+++ b/src/crypto/tls_openssl.c
@@ -44,6 +44,13 @@
#define OPENSSL_NEED_EAP_FAST_PRF
#endif
+#if defined(EAP_FAST) || defined(EAP_FAST_DYNAMIC) || \
+ defined(EAP_SERVER_FAST) || defined(EAP_TEAP) || \
+ defined(EAP_SERVER_TEAP)
+#define EAP_FAST_OR_TEAP
+#endif
+
+
#if defined(OPENSSL_IS_BORINGSSL)
/* stack_index_t is the return type of OpenSSL's sk_XXX_num() functions. */
typedef size_t stack_index_t;
@@ -1071,11 +1078,8 @@ void * tls_init(const struct tls_config *conf)
}
#ifndef OPENSSL_NO_ENGINE
- wpa_printf(MSG_DEBUG, "ENGINE: Loading dynamic engine");
-#if OPENSSL_VERSION_NUMBER < 0x10100000L
- ERR_load_ENGINE_strings();
- ENGINE_load_dynamic();
-#endif /* OPENSSL_VERSION_NUMBER */
+ wpa_printf(MSG_DEBUG, "ENGINE: Loading builtin engines");
+ ENGINE_load_builtin_engines();
if (conf &&
(conf->opensc_engine_path || conf->pkcs11_engine_path ||
@@ -1331,6 +1335,8 @@ static const char * openssl_content_type(int content_type)
return "heartbeat";
case 256:
return "TLS header info"; /* pseudo content type */
+ case 257:
+ return "inner content type"; /* pseudo content type */
default:
return "?";
}
@@ -1340,6 +1346,8 @@ static const char * openssl_content_type(int content_type)
static const char * openssl_handshake_type(int content_type, const u8 *buf,
size_t len)
{
+ if (content_type == 257 && buf && len == 1)
+ return openssl_content_type(buf[0]);
if (content_type != 22 || !buf || len == 0)
return "";
switch (buf[0]) {
@@ -1570,6 +1578,11 @@ struct tls_connection * tls_connection_init(void *ssl_ctx)
options |= SSL_OP_NO_COMPRESSION;
#endif /* SSL_OP_NO_COMPRESSION */
SSL_set_options(conn->ssl, options);
+#ifdef SSL_OP_ENABLE_MIDDLEBOX_COMPAT
+ /* Hopefully there is no need for middlebox compatibility mechanisms
+ * when going through EAP authentication. */
+ SSL_clear_options(conn->ssl, SSL_OP_ENABLE_MIDDLEBOX_COMPAT);
+#endif
conn->ssl_in = BIO_new(BIO_s_mem());
if (!conn->ssl_in) {
@@ -2152,6 +2165,34 @@ static void openssl_tls_fail_event(struct tls_connection *conn,
}
+static int openssl_cert_tod(X509 *cert)
+{
+ CERTIFICATEPOLICIES *ext;
+ stack_index_t i;
+ char buf[100];
+ int res;
+ int tod = 0;
+
+ ext = X509_get_ext_d2i(cert, NID_certificate_policies, NULL, NULL);
+ if (!ext)
+ return 0;
+
+ for (i = 0; i < sk_POLICYINFO_num(ext); i++) {
+ POLICYINFO *policy;
+
+ policy = sk_POLICYINFO_value(ext, i);
+ res = OBJ_obj2txt(buf, sizeof(buf), policy->policyid, 0);
+ if (res < 0 || (size_t) res >= sizeof(buf))
+ continue;
+ wpa_printf(MSG_DEBUG, "OpenSSL: Certificate Policy %s", buf);
+ if (os_strcmp(buf, "1.3.6.1.4.1.40808.1.3.1") == 0)
+ tod = 1;
+ }
+
+ return tod;
+}
+
+
static void openssl_tls_cert_event(struct tls_connection *conn,
X509 *err_cert, int depth,
const char *subject)
@@ -2244,6 +2285,8 @@ static void openssl_tls_cert_event(struct tls_connection *conn,
ev.peer_cert.altsubject[alt] = altsubject[alt];
ev.peer_cert.num_altsubject = num_altsubject;
+ ev.peer_cert.tod = openssl_cert_tod(err_cert);
+
context->event_cb(context->cb_ctx, TLS_PEER_CERTIFICATE, &ev);
wpabuf_free(cert);
for (alt = 0; alt < num_altsubject; alt++)
@@ -2348,7 +2391,30 @@ static int tls_verify_cb(int preverify_ok, X509_STORE_CTX *x509_ctx)
}
#endif /* CONFIG_SHA256 */
+ openssl_tls_cert_event(conn, err_cert, depth, buf);
+
if (!preverify_ok) {
+ if (depth > 0) {
+ /* Send cert event for the peer certificate so that
+ * the upper layers get information about it even if
+ * validation of a CA certificate fails. */
+ STACK_OF(X509) *chain;
+
+ chain = X509_STORE_CTX_get1_chain(x509_ctx);
+ if (chain && sk_X509_num(chain) > 0) {
+ char buf2[256];
+ X509 *cert;
+
+ cert = sk_X509_value(chain, 0);
+ X509_NAME_oneline(X509_get_subject_name(cert),
+ buf2, sizeof(buf2));
+
+ openssl_tls_cert_event(conn, cert, 0, buf2);
+ }
+ if (chain)
+ sk_X509_pop_free(chain, X509_free);
+ }
+
wpa_printf(MSG_WARNING, "TLS: Certificate verification failed,"
" error %d (%s) depth %d for '%s'", err, err_str,
depth, buf);
@@ -2404,8 +2470,7 @@ static int tls_verify_cb(int preverify_ok, X509_STORE_CTX *x509_ctx)
openssl_tls_fail_event(conn, err_cert, err, depth, buf,
"Domain mismatch",
TLS_FAIL_DOMAIN_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 "
@@ -2580,9 +2645,23 @@ static int tls_connection_ca_cert(struct tls_data *data,
(const unsigned char **) &ca_cert_blob,
ca_cert_blob_len);
if (cert == NULL) {
- tls_show_errors(MSG_WARNING, __func__,
- "Failed to parse ca_cert_blob");
- return -1;
+ BIO *bio = BIO_new_mem_buf(ca_cert_blob,
+ ca_cert_blob_len);
+
+ if (bio) {
+ cert = PEM_read_bio_X509(bio, NULL, NULL, NULL);
+ BIO_free(bio);
+ }
+
+ if (!cert) {
+ tls_show_errors(MSG_WARNING, __func__,
+ "Failed to parse ca_cert_blob");
+ return -1;
+ }
+
+ while (ERR_get_error()) {
+ /* Ignore errors from DER conversion. */
+ }
}
if (!X509_STORE_add_cert(SSL_CTX_get_cert_store(ssl_ctx),
@@ -3016,6 +3095,40 @@ static int tls_set_conn_flags(struct tls_connection *conn, unsigned int flags,
}
#endif /* CONFIG_SUITEB */
+ if (flags & TLS_CONN_TEAP_ANON_DH) {
+#ifndef TEAP_DH_ANON_CS
+#define TEAP_DH_ANON_CS \
+ "ECDHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES128-GCM-SHA256:" \
+ "ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES128-SHA256:" \
+ "ECDHE-RSA-AES256-SHA:ECDHE-RSA-AES128-SHA:" \
+ "DHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:" \
+ "DHE-RSA-AES256-SHA256:DHE-RSA-AES128-SHA256:" \
+ "DHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA:" \
+ "ADH-AES256-GCM-SHA384:ADH-AES128-GCM-SHA256:" \
+ "ADH-AES256-SHA256:ADH-AES128-SHA256:ADH-AES256-SHA:ADH-AES128-SHA"
+#endif
+ static const char *cs = TEAP_DH_ANON_CS;
+
+#if OPENSSL_VERSION_NUMBER >= 0x10100000L && \
+ !defined(LIBRESSL_VERSION_NUMBER) && \
+ !defined(OPENSSL_IS_BORINGSSL)
+ /*
+ * Need to drop to security level 0 to allow anonymous
+ * cipher suites for EAP-TEAP.
+ */
+ SSL_set_security_level(conn->ssl, 0);
+#endif
+
+ wpa_printf(MSG_DEBUG,
+ "OpenSSL: Enable cipher suites for anonymous EAP-TEAP provisioning: %s",
+ cs);
+ if (SSL_set_cipher_list(conn->ssl, cs) != 1) {
+ tls_show_errors(MSG_INFO, __func__,
+ "Cipher suite configuration failed");
+ return -1;
+ }
+ }
+
return 0;
}
@@ -4002,7 +4115,7 @@ int tls_connection_get_eap_fast_key(void *tls_ctx, struct tls_connection *conn,
_out, skip + out_len) == 0) {
ret = 0;
}
- os_memset(master_key, 0, sizeof(master_key));
+ forced_memzero(master_key, sizeof(master_key));
os_free(rnd);
if (ret == 0)
os_memcpy(out, _out + skip, out_len);
@@ -4192,6 +4305,22 @@ openssl_connection_handshake(struct tls_connection *conn,
wpa_printf(MSG_DEBUG,
"OpenSSL: Handshake finished - resumed=%d",
tls_connection_resumed(conn->ssl_ctx, conn));
+ if (conn->server) {
+ char *buf;
+ size_t buflen = 2000;
+
+ buf = os_malloc(buflen);
+ if (buf) {
+ if (SSL_get_shared_ciphers(conn->ssl, buf,
+ buflen)) {
+ buf[buflen - 1] = '\0';
+ wpa_printf(MSG_DEBUG,
+ "OpenSSL: Shared ciphers: %s",
+ buf);
+ }
+ os_free(buf);
+ }
+ }
if (appl_data && in_data)
*appl_data = openssl_get_appl_data(conn,
wpabuf_len(in_data));
@@ -4374,11 +4503,15 @@ int tls_connection_set_cipher_list(void *tls_ctx, struct tls_connection *conn,
c++;
}
+ if (!buf[0]) {
+ wpa_printf(MSG_DEBUG, "OpenSSL: No ciphers listed");
+ return -1;
+ }
wpa_printf(MSG_DEBUG, "OpenSSL: cipher suites: %s", buf + 1);
#if OPENSSL_VERSION_NUMBER >= 0x10100000L && !defined(LIBRESSL_VERSION_NUMBER)
-#if defined(EAP_FAST) || defined(EAP_FAST_DYNAMIC) || defined(EAP_SERVER_FAST)
+#ifdef EAP_FAST_OR_TEAP
if (os_strstr(buf, ":ADH-")) {
/*
* Need to drop to security level 0 to allow anonymous
@@ -4389,7 +4522,7 @@ int tls_connection_set_cipher_list(void *tls_ctx, struct tls_connection *conn,
/* Force at least security level 1 */
SSL_set_security_level(conn->ssl, 1);
}
-#endif /* EAP_FAST || EAP_FAST_DYNAMIC || EAP_SERVER_FAST */
+#endif /* EAP_FAST_OR_TEAP */
#endif
if (SSL_set_cipher_list(conn->ssl, buf + 1) != 1) {
@@ -4443,7 +4576,7 @@ int tls_connection_enable_workaround(void *ssl_ctx,
}
-#if defined(EAP_FAST) || defined(EAP_FAST_DYNAMIC) || defined(EAP_SERVER_FAST)
+#ifdef EAP_FAST_OR_TEAP
/* ClientHello TLS extensions require a patch to openssl, so this function is
* commented out unless explicitly needed for EAP-FAST in order to be able to
* build this file with unmodified openssl. */
@@ -4460,7 +4593,7 @@ int tls_connection_client_hello_ext(void *ssl_ctx, struct tls_connection *conn,
return 0;
}
-#endif /* EAP_FAST || EAP_FAST_DYNAMIC || EAP_SERVER_FAST */
+#endif /* EAP_FAST_OR_TEAP */
int tls_connection_get_failed(void *ssl_ctx, struct tls_connection *conn)
@@ -4669,6 +4802,7 @@ static int ocsp_resp_cb(SSL *s, void *arg)
res = OCSP_resp_find_status(basic, id, &status, &reason, &produced_at,
&this_update, &next_update);
if (!res) {
+ OCSP_CERTID_free(id);
id = OCSP_cert_to_id(NULL, conn->peer_cert, conn->peer_issuer);
if (!id) {
wpa_printf(MSG_DEBUG,
@@ -4979,6 +5113,114 @@ int tls_connection_set_params(void *tls_ctx, struct tls_connection *conn,
}
+static void openssl_debug_dump_cipher_list(SSL_CTX *ssl_ctx)
+{
+ SSL *ssl;
+ int i;
+
+ ssl = SSL_new(ssl_ctx);
+ if (!ssl)
+ return;
+
+ wpa_printf(MSG_DEBUG,
+ "OpenSSL: Enabled cipher suites in priority order");
+ for (i = 0; ; i++) {
+ const char *cipher;
+
+ cipher = SSL_get_cipher_list(ssl, i);
+ if (!cipher)
+ break;
+ wpa_printf(MSG_DEBUG, "Cipher %d: %s", i, cipher);
+ }
+
+ SSL_free(ssl);
+}
+
+
+#if !defined(LIBRESSL_VERSION_NUMBER) && !defined(BORINGSSL_API_VERSION)
+
+static const char * openssl_pkey_type_str(const EVP_PKEY *pkey)
+{
+ if (!pkey)
+ return "NULL";
+ switch (EVP_PKEY_type(EVP_PKEY_id(pkey))) {
+ case EVP_PKEY_RSA:
+ return "RSA";
+ case EVP_PKEY_DSA:
+ return "DSA";
+ case EVP_PKEY_DH:
+ return "DH";
+ case EVP_PKEY_EC:
+ return "EC";
+ }
+ return "?";
+}
+
+
+static void openssl_debug_dump_certificate(int i, X509 *cert)
+{
+ char buf[256];
+ EVP_PKEY *pkey;
+ ASN1_INTEGER *ser;
+ char serial_num[128];
+
+ X509_NAME_oneline(X509_get_subject_name(cert), buf, sizeof(buf));
+
+ ser = X509_get_serialNumber(cert);
+ if (ser)
+ wpa_snprintf_hex_uppercase(serial_num, sizeof(serial_num),
+ ASN1_STRING_get0_data(ser),
+ ASN1_STRING_length(ser));
+ else
+ serial_num[0] = '\0';
+
+ pkey = X509_get_pubkey(cert);
+ wpa_printf(MSG_DEBUG, "%d: %s (%s) %s", i, buf,
+ openssl_pkey_type_str(pkey), serial_num);
+ EVP_PKEY_free(pkey);
+}
+
+
+static void openssl_debug_dump_certificates(SSL_CTX *ssl_ctx)
+{
+ STACK_OF(X509) *certs;
+
+ wpa_printf(MSG_DEBUG, "OpenSSL: Configured certificate chain");
+ if (SSL_CTX_get0_chain_certs(ssl_ctx, &certs) == 1) {
+ int i;
+
+ for (i = sk_X509_num(certs); i > 0; i--)
+ openssl_debug_dump_certificate(i, sk_X509_value(certs,
+ i - 1));
+ }
+ openssl_debug_dump_certificate(0, SSL_CTX_get0_certificate(ssl_ctx));
+}
+
+#endif
+
+
+static void openssl_debug_dump_certificate_chains(SSL_CTX *ssl_ctx)
+{
+#if !defined(LIBRESSL_VERSION_NUMBER) && !defined(BORINGSSL_API_VERSION)
+ int res;
+
+ for (res = SSL_CTX_set_current_cert(ssl_ctx, SSL_CERT_SET_FIRST);
+ res == 1;
+ res = SSL_CTX_set_current_cert(ssl_ctx, SSL_CERT_SET_NEXT))
+ openssl_debug_dump_certificates(ssl_ctx);
+
+ SSL_CTX_set_current_cert(ssl_ctx, SSL_CERT_SET_FIRST);
+#endif
+}
+
+
+static void openssl_debug_dump_ctx(SSL_CTX *ssl_ctx)
+{
+ openssl_debug_dump_cipher_list(ssl_ctx);
+ openssl_debug_dump_certificate_chains(ssl_ctx);
+}
+
+
int tls_global_set_params(void *tls_ctx,
const struct tls_connection_params *params)
{
@@ -5004,6 +5246,9 @@ int tls_global_set_params(void *tls_ctx,
tls_global_client_cert(data, params->client_cert) ||
tls_global_private_key(data, params->private_key,
params->private_key_passwd) ||
+ tls_global_client_cert(data, params->client_cert2) ||
+ tls_global_private_key(data, params->private_key2,
+ params->private_key_passwd2) ||
tls_global_dh(data, params->dh_file)) {
wpa_printf(MSG_INFO, "TLS: Failed to set global parameters");
return -1;
@@ -5073,11 +5318,13 @@ int tls_global_set_params(void *tls_ctx,
tls_global->ocsp_stapling_response = NULL;
#endif /* HAVE_OCSP */
+ openssl_debug_dump_ctx(ssl_ctx);
+
return 0;
}
-#if defined(EAP_FAST) || defined(EAP_FAST_DYNAMIC) || defined(EAP_SERVER_FAST)
+#ifdef EAP_FAST_OR_TEAP
/* Pre-shared secred requires a patch to openssl, so this function is
* commented out unless explicitly needed for EAP-FAST in order to be able to
* build this file with unmodified openssl. */
@@ -5158,7 +5405,7 @@ static int tls_session_ticket_ext_cb(SSL *s, const unsigned char *data,
return 1;
}
-#endif /* EAP_FAST || EAP_FAST_DYNAMIC || EAP_SERVER_FAST */
+#endif /* EAP_FAST_OR_TEAP */
int tls_connection_set_session_ticket_cb(void *tls_ctx,
@@ -5166,7 +5413,7 @@ int tls_connection_set_session_ticket_cb(void *tls_ctx,
tls_session_ticket_cb cb,
void *ctx)
{
-#if defined(EAP_FAST) || defined(EAP_FAST_DYNAMIC) || defined(EAP_SERVER_FAST)
+#ifdef EAP_FAST_OR_TEAP
conn->session_ticket_cb = cb;
conn->session_ticket_cb_ctx = ctx;
@@ -5183,9 +5430,9 @@ int tls_connection_set_session_ticket_cb(void *tls_ctx,
}
return 0;
-#else /* EAP_FAST || EAP_FAST_DYNAMIC || EAP_SERVER_FAST */
+#else /* EAP_FAST_OR_TEAP */
return -1;
-#endif /* EAP_FAST || EAP_FAST_DYNAMIC || EAP_SERVER_FAST */
+#endif /* EAP_FAST_OR_TEAP */
}
@@ -5268,3 +5515,36 @@ void tls_connection_remove_session(struct tls_connection *conn)
wpa_printf(MSG_DEBUG,
"OpenSSL: Removed cached session to disable session resumption");
}
+
+
+int tls_get_tls_unique(struct tls_connection *conn, u8 *buf, size_t max_len)
+{
+ size_t len;
+ int reused;
+
+ reused = SSL_session_reused(conn->ssl);
+ if ((conn->server && !reused) || (!conn->server && reused))
+ len = SSL_get_peer_finished(conn->ssl, buf, max_len);
+ else
+ len = SSL_get_finished(conn->ssl, buf, max_len);
+
+ if (len == 0 || len > max_len)
+ return -1;
+
+ return len;
+}
+
+
+u16 tls_connection_get_cipher_suite(struct tls_connection *conn)
+{
+ const SSL_CIPHER *cipher;
+
+ cipher = SSL_get_current_cipher(conn->ssl);
+ if (!cipher)
+ return 0;
+#if OPENSSL_VERSION_NUMBER >= 0x10101000L && !defined(LIBRESSL_VERSION_NUMBER)
+ return SSL_CIPHER_get_protocol_id(cipher);
+#else
+ return SSL_CIPHER_get_id(cipher) & 0xFFFF;
+#endif
+}