#include <openssl/ssl.h>
#include <openssl/err.h>
+#include <openssl/opensslv.h>
#include <openssl/pkcs12.h>
#include <openssl/x509v3.h>
#ifndef OPENSSL_NO_ENGINE
#include "sha1.h"
#include "sha256.h"
#include "tls.h"
+#include "tls_openssl.h"
-#if OPENSSL_VERSION_NUMBER < 0x10000000L
-/* ERR_remove_thread_state replaces ERR_remove_state and the latter is
- * deprecated. However, OpenSSL 0.9.8 doesn't include
- * ERR_remove_thread_state. */
-#define ERR_remove_thread_state(tid) ERR_remove_state(0)
+#if !defined(CONFIG_FIPS) && \
+ (defined(EAP_FAST) || defined(EAP_FAST_DYNAMIC) || \
+ defined(EAP_SERVER_FAST))
+#define OPENSSL_NEED_EAP_FAST_PRF
#endif
#if defined(OPENSSL_IS_BORINGSSL)
#endif /* OPENSSL_NO_TLSEXT */
#endif /* SSL_set_tlsext_status_type */
+#if (OPENSSL_VERSION_NUMBER < 0x10100000L || \
+ defined(LIBRESSL_VERSION_NUMBER)) && \
+ !defined(BORINGSSL_API_VERSION)
+/*
+ * SSL_get_client_random() and SSL_get_server_random() were added in OpenSSL
+ * 1.1.0 and newer BoringSSL revisions. Provide compatibility wrappers for
+ * older versions.
+ */
+
+static size_t SSL_get_client_random(const SSL *ssl, unsigned char *out,
+ size_t outlen)
+{
+ if (!ssl->s3 || outlen < SSL3_RANDOM_SIZE)
+ return 0;
+ os_memcpy(out, ssl->s3->client_random, SSL3_RANDOM_SIZE);
+ return SSL3_RANDOM_SIZE;
+}
+
+
+static size_t SSL_get_server_random(const SSL *ssl, unsigned char *out,
+ size_t outlen)
+{
+ if (!ssl->s3 || outlen < SSL3_RANDOM_SIZE)
+ return 0;
+ os_memcpy(out, ssl->s3->server_random, SSL3_RANDOM_SIZE);
+ return SSL3_RANDOM_SIZE;
+}
+
+
+#ifdef OPENSSL_NEED_EAP_FAST_PRF
+static size_t SSL_SESSION_get_master_key(const SSL_SESSION *session,
+ unsigned char *out, size_t outlen)
+{
+ if (!session || session->master_key_length < 0 ||
+ (size_t) session->master_key_length > outlen)
+ return 0;
+ if ((size_t) session->master_key_length < outlen)
+ outlen = session->master_key_length;
+ os_memcpy(out, session->master_key, outlen);
+ return outlen;
+}
+#endif /* OPENSSL_NEED_EAP_FAST_PRF */
+
+#endif
+
#ifdef ANDROID
#include <openssl/pem.h>
#include <keystore/keystore_get.h>
free(value);
return bio;
}
+
+
+static int tls_add_ca_from_keystore(X509_STORE *ctx, const char *key_alias)
+{
+ BIO *bio = BIO_from_keystore(key_alias);
+ STACK_OF(X509_INFO) *stack = NULL;
+ stack_index_t i;
+
+ if (bio) {
+ stack = PEM_X509_INFO_read_bio(bio, NULL, NULL, NULL);
+ BIO_free(bio);
+ }
+
+ if (!stack) {
+ wpa_printf(MSG_WARNING, "TLS: Failed to parse certificate: %s",
+ key_alias);
+ return -1;
+ }
+
+ for (i = 0; i < sk_X509_INFO_num(stack); ++i) {
+ X509_INFO *info = sk_X509_INFO_value(stack, i);
+
+ if (info->x509)
+ X509_STORE_add_cert(ctx, info->x509);
+ if (info->crl)
+ X509_STORE_add_crl(ctx, info->crl);
+ }
+
+ sk_X509_INFO_pop_free(stack, X509_INFO_free);
+
+ return 0;
+}
+
+
+static int tls_add_ca_from_keystore_encoded(X509_STORE *ctx,
+ const char *encoded_key_alias)
+{
+ int rc = -1;
+ int len = os_strlen(encoded_key_alias);
+ unsigned char *decoded_alias;
+
+ if (len & 1) {
+ wpa_printf(MSG_WARNING, "Invalid hex-encoded alias: %s",
+ encoded_key_alias);
+ return rc;
+ }
+
+ decoded_alias = os_malloc(len / 2 + 1);
+ if (decoded_alias) {
+ if (!hexstr2bin(encoded_key_alias, decoded_alias, len / 2)) {
+ decoded_alias[len / 2] = '\0';
+ rc = tls_add_ca_from_keystore(
+ ctx, (const char *) decoded_alias);
+ }
+ os_free(decoded_alias);
+ }
+
+ return rc;
+}
+
#endif /* ANDROID */
static int tls_openssl_ref_count = 0;
+static int tls_ex_idx_session = -1;
struct tls_context {
void (*event_cb)(void *ctx, enum tls_event ev,
static struct tls_context *tls_global = NULL;
+struct tls_data {
+ SSL_CTX *ssl;
+ unsigned int tls_session_lifetime;
+};
+
struct tls_connection {
struct tls_context *context;
SSL_CTX *ssl_ctx;
SSL *ssl;
BIO *ssl_in, *ssl_out;
-#ifndef OPENSSL_NO_ENGINE
+#if defined(ANDROID) || !defined(OPENSSL_NO_ENGINE)
ENGINE *engine; /* functional reference to the engine */
EVP_PKEY *private_key; /* the private key if using engine */
#endif /* OPENSSL_NO_ENGINE */
unsigned int cert_probe:1;
unsigned int server_cert_only:1;
unsigned int invalid_hb_used:1;
+ unsigned int success_data:1;
u8 srv_cert_hash[32];
X509 *peer_issuer;
X509 *peer_issuer_issuer;
-#if OPENSSL_VERSION_NUMBER >= 0x10100000L
unsigned char client_random[SSL3_RANDOM_SIZE];
unsigned char server_random[SSL3_RANDOM_SIZE];
-#endif
};
wpa_printf(MSG_DEBUG, "OpenSSL: Loaded CA certificate for "
"system certificate store: subject='%s'", buf);
- if (!X509_STORE_add_cert(ssl_ctx->cert_store, cert)) {
+ if (!X509_STORE_add_cert(SSL_CTX_get_cert_store(ssl_ctx),
+ cert)) {
tls_show_errors(MSG_WARNING, __func__,
"Failed to add ca_cert to OpenSSL "
"certificate store");
engine = ENGINE_by_id(id);
if (engine) {
- ENGINE_free(engine);
wpa_printf(MSG_DEBUG, "ENGINE: engine '%s' is already "
"available", id);
- return 0;
+ /*
+ * If it was auto-loaded by ENGINE_by_id() we might still
+ * need to tell it which PKCS#11 module to use in legacy
+ * (non-p11-kit) environments. Do so now; even if it was
+ * properly initialised before, setting it again will be
+ * harmless.
+ */
+ goto found;
}
ERR_clear_error();
id, ERR_error_string(ERR_get_error(), NULL));
return -1;
}
-
+ found:
while (post && post[0]) {
wpa_printf(MSG_DEBUG, "ENGINE: '%s' '%s'", post[0], post[1]);
if (ENGINE_ctrl_cmd_string(engine, post[0], post[1], 0) == 0) {
#endif /* OPENSSL_NO_ENGINE */
+static void remove_session_cb(SSL_CTX *ctx, SSL_SESSION *sess)
+{
+ struct wpabuf *buf;
+
+ if (tls_ex_idx_session < 0)
+ return;
+ buf = SSL_SESSION_get_ex_data(sess, tls_ex_idx_session);
+ if (!buf)
+ return;
+ wpa_printf(MSG_DEBUG,
+ "OpenSSL: Free application session data %p (sess %p)",
+ buf, sess);
+ wpabuf_free(buf);
+
+ SSL_SESSION_set_ex_data(sess, tls_ex_idx_session, NULL);
+}
+
+
void * tls_init(const struct tls_config *conf)
{
+ struct tls_data *data;
SSL_CTX *ssl;
struct tls_context *context;
const char *ciphers;
}
#endif /* OPENSSL_FIPS */
#endif /* CONFIG_FIPS */
+#if OPENSSL_VERSION_NUMBER < 0x10100000L || defined(LIBRESSL_VERSION_NUMBER)
SSL_load_error_strings();
SSL_library_init();
#ifndef OPENSSL_NO_SHA256
#endif /* OPENSSL_NO_RC2 */
PKCS12_PBE_add();
#endif /* PKCS12_FUNCS */
+#endif /* < 1.1.0 */
} else {
context = tls_context_new(conf);
if (context == NULL)
}
tls_openssl_ref_count++;
- ssl = SSL_CTX_new(SSLv23_method());
+ data = os_zalloc(sizeof(*data));
+ if (data)
+ ssl = SSL_CTX_new(SSLv23_method());
+ else
+ ssl = NULL;
if (ssl == NULL) {
tls_openssl_ref_count--;
if (context != tls_global)
os_free(tls_global);
tls_global = NULL;
}
+ os_free(data);
return NULL;
}
+ data->ssl = ssl;
+ if (conf)
+ data->tls_session_lifetime = conf->tls_session_lifetime;
SSL_CTX_set_options(ssl, SSL_OP_NO_SSLv2);
SSL_CTX_set_options(ssl, SSL_OP_NO_SSLv3);
+#ifdef SSL_MODE_NO_AUTO_CHAIN
+ /* Number of deployed use cases assume the default OpenSSL behavior of
+ * auto chaining the local certificate is in use. BoringSSL removed this
+ * functionality by default, so we need to restore it here to avoid
+ * breaking existing use cases. */
+ SSL_CTX_clear_mode(ssl, SSL_MODE_NO_AUTO_CHAIN);
+#endif /* SSL_MODE_NO_AUTO_CHAIN */
+
SSL_CTX_set_info_callback(ssl, ssl_info_cb);
SSL_CTX_set_app_data(ssl, context);
+ if (data->tls_session_lifetime > 0) {
+ SSL_CTX_set_quiet_shutdown(ssl, 1);
+ /*
+ * Set default context here. In practice, this will be replaced
+ * by the per-EAP method context in tls_connection_set_verify().
+ */
+ SSL_CTX_set_session_id_context(ssl, (u8 *) "hostapd", 7);
+ SSL_CTX_set_session_cache_mode(ssl, SSL_SESS_CACHE_SERVER);
+ SSL_CTX_set_timeout(ssl, data->tls_session_lifetime);
+ SSL_CTX_sess_set_remove_cb(ssl, remove_session_cb);
+ } else {
+ SSL_CTX_set_session_cache_mode(ssl, SSL_SESS_CACHE_OFF);
+ }
+
+ if (tls_ex_idx_session < 0) {
+ tls_ex_idx_session = SSL_SESSION_get_ex_new_index(
+ 0, NULL, NULL, NULL, NULL);
+ if (tls_ex_idx_session < 0) {
+ tls_deinit(data);
+ return NULL;
+ }
+ }
#ifndef OPENSSL_NO_ENGINE
wpa_printf(MSG_DEBUG, "ENGINE: Loading dynamic engine");
if (tls_engine_load_dynamic_opensc(conf->opensc_engine_path) ||
tls_engine_load_dynamic_pkcs11(conf->pkcs11_engine_path,
conf->pkcs11_module_path)) {
- tls_deinit(ssl);
+ tls_deinit(data);
return NULL;
}
}
wpa_printf(MSG_ERROR,
"OpenSSL: Failed to set cipher string '%s'",
ciphers);
- tls_deinit(ssl);
+ tls_deinit(data);
return NULL;
}
- return ssl;
+ return data;
}
void tls_deinit(void *ssl_ctx)
{
- SSL_CTX *ssl = ssl_ctx;
+ struct tls_data *data = ssl_ctx;
+ SSL_CTX *ssl = data->ssl;
struct tls_context *context = SSL_CTX_get_app_data(ssl);
if (context != tls_global)
os_free(context);
+ if (data->tls_session_lifetime > 0)
+ SSL_CTX_flush_sessions(ssl, 0);
SSL_CTX_free(ssl);
tls_openssl_ref_count--;
if (tls_openssl_ref_count == 0) {
+#if OPENSSL_VERSION_NUMBER < 0x10100000L || defined(LIBRESSL_VERSION_NUMBER)
#ifndef OPENSSL_NO_ENGINE
ENGINE_cleanup();
#endif /* OPENSSL_NO_ENGINE */
ERR_remove_thread_state(NULL);
ERR_free_strings();
EVP_cleanup();
+#endif /* < 1.1.0 */
os_free(tls_global->ocsp_stapling_response);
tls_global->ocsp_stapling_response = NULL;
os_free(tls_global);
tls_global = NULL;
}
+
+ os_free(data);
}
#endif /* OPENSSL_NO_ENGINE */
+#ifdef ANDROID
+/* EVP_PKEY_from_keystore comes from system/security/keystore-engine. */
+EVP_PKEY * EVP_PKEY_from_keystore(const char *key_id);
+#endif /* ANDROID */
+
static int tls_engine_init(struct tls_connection *conn, const char *engine_id,
const char *pin, const char *key_id,
const char *cert_id, const char *ca_cert_id)
{
+#if defined(ANDROID) && defined(OPENSSL_IS_BORINGSSL)
+#if !defined(OPENSSL_NO_ENGINE)
+#error "This code depends on OPENSSL_NO_ENGINE being defined by BoringSSL."
+#endif
+ if (!key_id)
+ return TLS_SET_PARAMS_ENGINE_PRV_INIT_FAILED;
+ conn->engine = NULL;
+ conn->private_key = EVP_PKEY_from_keystore(key_id);
+ if (!conn->private_key) {
+ wpa_printf(MSG_ERROR,
+ "ENGINE: cannot load private key with id '%s' [%s]",
+ key_id,
+ ERR_error_string(ERR_get_error(), NULL));
+ return TLS_SET_PARAMS_ENGINE_PRV_INIT_FAILED;
+ }
+#endif /* ANDROID && OPENSSL_IS_BORINGSSL */
+
#ifndef OPENSSL_NO_ENGINE
int ret = -1;
if (engine_id == NULL) {
static void tls_engine_deinit(struct tls_connection *conn)
{
-#ifndef OPENSSL_NO_ENGINE
+#if defined(ANDROID) || !defined(OPENSSL_NO_ENGINE)
wpa_printf(MSG_DEBUG, "ENGINE: engine deinit");
if (conn->private_key) {
EVP_PKEY_free(conn->private_key);
conn->private_key = NULL;
}
if (conn->engine) {
+#if !defined(OPENSSL_IS_BORINGSSL)
ENGINE_finish(conn->engine);
+#endif /* !OPENSSL_IS_BORINGSSL */
conn->engine = NULL;
}
-#endif /* OPENSSL_NO_ENGINE */
+#endif /* ANDROID || !OPENSSL_NO_ENGINE */
}
}
+static const char * openssl_content_type(int content_type)
+{
+ switch (content_type) {
+ case 20:
+ return "change cipher spec";
+ case 21:
+ return "alert";
+ case 22:
+ return "handshake";
+ case 23:
+ return "application data";
+ case 24:
+ return "heartbeat";
+ case 256:
+ return "TLS header info"; /* pseudo content type */
+ default:
+ return "?";
+ }
+}
+
+
+static const char * openssl_handshake_type(int content_type, const u8 *buf,
+ size_t len)
+{
+ if (content_type != 22 || !buf || len == 0)
+ return "";
+ switch (buf[0]) {
+ case 0:
+ return "hello request";
+ case 1:
+ return "client hello";
+ case 2:
+ return "server hello";
+ case 4:
+ return "new session ticket";
+ case 11:
+ return "certificate";
+ case 12:
+ return "server key exchange";
+ case 13:
+ return "certificate request";
+ case 14:
+ return "server hello done";
+ case 15:
+ return "certificate verify";
+ case 16:
+ return "client key exchange";
+ case 20:
+ return "finished";
+ case 21:
+ return "certificate url";
+ case 22:
+ return "certificate status";
+ default:
+ return "?";
+ }
+}
+
+
static void tls_msg_cb(int write_p, int version, int content_type,
const void *buf, size_t len, SSL *ssl, void *arg)
{
struct tls_connection *conn = arg;
const u8 *pos = buf;
- wpa_printf(MSG_DEBUG, "OpenSSL: %s ver=0x%x content_type=%d",
- write_p ? "TX" : "RX", version, content_type);
+ if (write_p == 2) {
+ wpa_printf(MSG_DEBUG,
+ "OpenSSL: session ver=0x%x content_type=%d",
+ version, content_type);
+ wpa_hexdump_key(MSG_MSGDUMP, "OpenSSL: Data", buf, len);
+ return;
+ }
+
+ wpa_printf(MSG_DEBUG, "OpenSSL: %s ver=0x%x content_type=%d (%s/%s)",
+ write_p ? "TX" : "RX", version, content_type,
+ openssl_content_type(content_type),
+ openssl_handshake_type(content_type, buf, len));
wpa_hexdump_key(MSG_MSGDUMP, "OpenSSL: Message", buf, len);
if (content_type == 24 && len >= 3 && pos[0] == 1) {
size_t payload_len = WPA_GET_BE16(pos + 1);
struct tls_connection * tls_connection_init(void *ssl_ctx)
{
- SSL_CTX *ssl = ssl_ctx;
+ struct tls_data *data = ssl_ctx;
+ SSL_CTX *ssl = data->ssl;
struct tls_connection *conn;
long options;
struct tls_context *context = SSL_CTX_get_app_data(ssl);
conn = os_zalloc(sizeof(*conn));
if (conn == NULL)
return NULL;
- conn->ssl_ctx = ssl_ctx;
+ conn->ssl_ctx = ssl;
conn->ssl = SSL_new(ssl);
if (conn->ssl == NULL) {
tls_show_errors(MSG_INFO, __func__,
{
if (conn == NULL)
return;
+ if (conn->success_data) {
+ /*
+ * Make sure ssl_clear_bad_session() does not remove this
+ * session.
+ */
+ SSL_set_quiet_shutdown(conn->ssl, 1);
+ SSL_shutdown(conn->ssl);
+ }
SSL_free(conn->ssl);
tls_engine_deinit(conn);
os_free(conn->subject_match);
found++;
}
+ sk_GENERAL_NAME_pop_free(ext, GENERAL_NAME_free);
+
return found;
}
1) {
wpa_printf(MSG_DEBUG, "TLS: %s in dNSName found",
full ? "Match" : "Suffix match");
+ sk_GENERAL_NAME_pop_free(ext, GENERAL_NAME_free);
return 1;
}
}
+ sk_GENERAL_NAME_pop_free(ext, GENERAL_NAME_free);
if (dns_name) {
wpa_printf(MSG_DEBUG, "TLS: None of the dNSName(s) matched");
return;
os_memset(&ev, 0, sizeof(ev));
- if (conn->cert_probe || context->cert_in_cb) {
+ if (conn->cert_probe || (conn->flags & TLS_CONN_EXT_CERT_CHECK) ||
+ context->cert_in_cb) {
cert = get_x509_cert(err_cert);
ev.peer_cert.cert = cert;
}
pos += gen->d.ia5->length;
*pos = '\0';
}
+ sk_GENERAL_NAME_pop_free(ext, GENERAL_NAME_free);
for (alt = 0; alt < num_altsubject; alt++)
ev.peer_cert.altsubject[alt] = altsubject[alt];
TLS_FAIL_SERVER_CHAIN_PROBE);
}
- if (preverify_ok && context->event_cb != NULL)
+#ifdef OPENSSL_IS_BORINGSSL
+ if (depth == 0 && (conn->flags & TLS_CONN_REQUEST_OCSP) &&
+ preverify_ok) {
+ enum ocsp_result res;
+
+ res = check_ocsp_resp(conn->ssl_ctx, conn->ssl, err_cert,
+ conn->peer_issuer,
+ conn->peer_issuer_issuer);
+ if (res == OCSP_REVOKED) {
+ preverify_ok = 0;
+ openssl_tls_fail_event(conn, err_cert, err, depth, buf,
+ "certificate revoked",
+ TLS_FAIL_REVOKED);
+ if (err == X509_V_OK)
+ X509_STORE_CTX_set_error(
+ x509_ctx, X509_V_ERR_CERT_REVOKED);
+ } else if (res != OCSP_GOOD &&
+ (conn->flags & TLS_CONN_REQUIRE_OCSP)) {
+ preverify_ok = 0;
+ openssl_tls_fail_event(conn, err_cert, err, depth, buf,
+ "bad certificate status response",
+ TLS_FAIL_UNSPECIFIED);
+ }
+ }
+#endif /* OPENSSL_IS_BORINGSSL */
+
+ if (depth == 0 && preverify_ok && context->event_cb != NULL)
context->event_cb(context->cb_ctx,
TLS_CERT_CHAIN_SUCCESS, NULL);
#ifndef OPENSSL_NO_STDIO
-static int tls_load_ca_der(void *_ssl_ctx, const char *ca_cert)
+static int tls_load_ca_der(struct tls_data *data, const char *ca_cert)
{
- SSL_CTX *ssl_ctx = _ssl_ctx;
+ SSL_CTX *ssl_ctx = data->ssl;
X509_LOOKUP *lookup;
int ret = 0;
#endif /* OPENSSL_NO_STDIO */
-static int tls_connection_ca_cert(void *_ssl_ctx, struct tls_connection *conn,
+static int tls_connection_ca_cert(struct tls_data *data,
+ struct tls_connection *conn,
const char *ca_cert, const u8 *ca_cert_blob,
size_t ca_cert_blob_len, const char *ca_path)
{
- SSL_CTX *ssl_ctx = _ssl_ctx;
+ SSL_CTX *ssl_ctx = data->ssl;
X509_STORE *store;
/*
}
#ifdef ANDROID
+ /* Single alias */
if (ca_cert && os_strncmp("keystore://", ca_cert, 11) == 0) {
- BIO *bio = BIO_from_keystore(&ca_cert[11]);
- STACK_OF(X509_INFO) *stack = NULL;
- stack_index_t i;
-
- if (bio) {
- stack = PEM_X509_INFO_read_bio(bio, NULL, NULL, NULL);
- BIO_free(bio);
- }
- if (!stack)
+ if (tls_add_ca_from_keystore(SSL_CTX_get_cert_store(ssl_ctx),
+ &ca_cert[11]) < 0)
return -1;
+ SSL_set_verify(conn->ssl, SSL_VERIFY_PEER, tls_verify_cb);
+ return 0;
+ }
- for (i = 0; i < sk_X509_INFO_num(stack); ++i) {
- X509_INFO *info = sk_X509_INFO_value(stack, i);
- if (info->x509) {
- X509_STORE_add_cert(ssl_ctx->cert_store,
- info->x509);
- }
- if (info->crl) {
- X509_STORE_add_crl(ssl_ctx->cert_store,
- info->crl);
+ /* Multiple aliases separated by space */
+ if (ca_cert && os_strncmp("keystores://", ca_cert, 12) == 0) {
+ char *aliases = os_strdup(&ca_cert[12]);
+ const char *delim = " ";
+ int rc = 0;
+ char *savedptr;
+ char *alias;
+
+ if (!aliases)
+ return -1;
+ alias = strtok_r(aliases, delim, &savedptr);
+ for (; alias; alias = strtok_r(NULL, delim, &savedptr)) {
+ if (tls_add_ca_from_keystore_encoded(
+ SSL_CTX_get_cert_store(ssl_ctx), alias)) {
+ wpa_printf(MSG_WARNING,
+ "OpenSSL: %s - Failed to add ca_cert %s from keystore",
+ __func__, alias);
+ rc = -1;
+ break;
}
}
- sk_X509_INFO_pop_free(stack, X509_INFO_free);
+ os_free(aliases);
+ if (rc)
+ return rc;
+
SSL_set_verify(conn->ssl, SSL_VERIFY_PEER, tls_verify_cb);
return 0;
}
tls_show_errors(MSG_WARNING, __func__,
"Failed to load root certificates");
if (ca_cert &&
- tls_load_ca_der(ssl_ctx, ca_cert) == 0) {
+ tls_load_ca_der(data, ca_cert) == 0) {
wpa_printf(MSG_DEBUG, "OpenSSL: %s - loaded "
"DER format CA certificate",
__func__);
} else {
wpa_printf(MSG_DEBUG, "TLS: Trusted root "
"certificate(s) loaded");
- tls_get_errors(ssl_ctx);
+ tls_get_errors(data);
}
#else /* OPENSSL_NO_STDIO */
wpa_printf(MSG_DEBUG, "OpenSSL: %s - OPENSSL_NO_STDIO",
}
-static int tls_global_ca_cert(SSL_CTX *ssl_ctx, const char *ca_cert)
+static int tls_global_ca_cert(struct tls_data *data, const char *ca_cert)
{
+ SSL_CTX *ssl_ctx = data->ssl;
+
if (ca_cert) {
if (SSL_CTX_load_verify_locations(ssl_ctx, ca_cert, NULL) != 1)
{
int flags;
if (check_crl) {
- X509_STORE *cs = SSL_CTX_get_cert_store(ssl_ctx);
+ struct tls_data *data = ssl_ctx;
+ X509_STORE *cs = SSL_CTX_get_cert_store(data->ssl);
if (cs == NULL) {
tls_show_errors(MSG_INFO, __func__, "Failed to get "
"certificate store when enabling "
}
+static void tls_set_conn_flags(SSL *ssl, unsigned int flags)
+{
+#ifdef SSL_OP_NO_TICKET
+ if (flags & TLS_CONN_DISABLE_SESSION_TICKET)
+ SSL_set_options(ssl, SSL_OP_NO_TICKET);
+ else
+ SSL_clear_options(ssl, SSL_OP_NO_TICKET);
+#endif /* SSL_OP_NO_TICKET */
+
+#ifdef SSL_OP_NO_TLSv1
+ if (flags & TLS_CONN_DISABLE_TLSv1_0)
+ SSL_set_options(ssl, SSL_OP_NO_TLSv1);
+ else
+ SSL_clear_options(ssl, SSL_OP_NO_TLSv1);
+#endif /* SSL_OP_NO_TLSv1 */
+#ifdef SSL_OP_NO_TLSv1_1
+ if (flags & TLS_CONN_DISABLE_TLSv1_1)
+ SSL_set_options(ssl, SSL_OP_NO_TLSv1_1);
+ else
+ SSL_clear_options(ssl, SSL_OP_NO_TLSv1_1);
+#endif /* SSL_OP_NO_TLSv1_1 */
+#ifdef SSL_OP_NO_TLSv1_2
+ if (flags & TLS_CONN_DISABLE_TLSv1_2)
+ SSL_set_options(ssl, SSL_OP_NO_TLSv1_2);
+ else
+ SSL_clear_options(ssl, SSL_OP_NO_TLSv1_2);
+#endif /* SSL_OP_NO_TLSv1_2 */
+}
+
+
int tls_connection_set_verify(void *ssl_ctx, struct tls_connection *conn,
- int verify_peer)
+ int verify_peer, unsigned int flags,
+ const u8 *session_ctx, size_t session_ctx_len)
{
static int counter = 0;
+ struct tls_data *data = ssl_ctx;
if (conn == NULL)
return -1;
SSL_set_verify(conn->ssl, SSL_VERIFY_NONE, NULL);
}
+ tls_set_conn_flags(conn->ssl, flags);
+ conn->flags = flags;
+
SSL_set_accept_state(conn->ssl);
- /*
- * Set session id context in order to avoid fatal errors when client
- * tries to resume a session. However, set the context to a unique
- * value in order to effectively disable session resumption for now
- * since not all areas of the server code are ready for it (e.g.,
- * EAP-TTLS needs special handling for Phase 2 after abbreviated TLS
- * handshake).
- */
- counter++;
- SSL_set_session_id_context(conn->ssl,
- (const unsigned char *) &counter,
- sizeof(counter));
+ if (data->tls_session_lifetime == 0) {
+ /*
+ * Set session id context to a unique value to make sure
+ * session resumption cannot be used either through session
+ * caching or TLS ticket extension.
+ */
+ counter++;
+ SSL_set_session_id_context(conn->ssl,
+ (const unsigned char *) &counter,
+ sizeof(counter));
+ } else if (session_ctx) {
+ SSL_set_session_id_context(conn->ssl, session_ctx,
+ session_ctx_len);
+ }
return 0;
}
if (client_cert == NULL && client_cert_blob == NULL)
return 0;
+#ifdef PKCS12_FUNCS
+#if OPENSSL_VERSION_NUMBER < 0x10002000L || defined(LIBRESSL_VERSION_NUMBER)
+ /*
+ * Clear previously set extra chain certificates, if any, from PKCS#12
+ * processing in tls_parse_pkcs12() to allow OpenSSL to build a new
+ * chain properly.
+ */
+ SSL_CTX_clear_extra_chain_certs(conn->ssl_ctx);
+#endif /* OPENSSL_VERSION_NUMBER < 0x10002000L */
+#endif /* PKCS12_FUNCS */
+
if (client_cert_blob &&
SSL_use_certificate_ASN1(conn->ssl, (u8 *) client_cert_blob,
client_cert_blob_len) == 1) {
int ret = -1;
if (bio) {
x509 = PEM_read_bio_X509(bio, NULL, NULL, NULL);
- BIO_free(bio);
}
if (x509) {
if (SSL_use_certificate(conn->ssl, x509) == 1)
ret = 0;
X509_free(x509);
}
+
+ /* Read additional certificates into the chain. */
+ while (bio) {
+ x509 = PEM_read_bio_X509(bio, NULL, NULL, NULL);
+ if (x509) {
+ /* Takes ownership of x509 */
+ SSL_add0_chain_cert(conn->ssl, x509);
+ } else {
+ BIO_free(bio);
+ bio = NULL;
+ }
+ }
return ret;
}
#endif /* ANDROID */
}
-static int tls_global_client_cert(SSL_CTX *ssl_ctx, const char *client_cert)
+static int tls_global_client_cert(struct tls_data *data,
+ const char *client_cert)
{
#ifndef OPENSSL_NO_STDIO
+ SSL_CTX *ssl_ctx = data->ssl;
+
if (client_cert == NULL)
return 0;
#ifdef PKCS12_FUNCS
-static int tls_parse_pkcs12(SSL_CTX *ssl_ctx, SSL *ssl, PKCS12 *p12,
+static int tls_parse_pkcs12(struct tls_data *data, SSL *ssl, PKCS12 *p12,
const char *passwd)
{
EVP_PKEY *pkey;
if (SSL_use_certificate(ssl, cert) != 1)
res = -1;
} else {
- if (SSL_CTX_use_certificate(ssl_ctx, cert) != 1)
+ if (SSL_CTX_use_certificate(data->ssl, cert) != 1)
res = -1;
}
X509_free(cert);
if (SSL_use_PrivateKey(ssl, pkey) != 1)
res = -1;
} else {
- if (SSL_CTX_use_PrivateKey(ssl_ctx, pkey) != 1)
+ if (SSL_CTX_use_PrivateKey(data->ssl, pkey) != 1)
res = -1;
}
EVP_PKEY_free(pkey);
}
if (certs) {
-#if OPENSSL_VERSION_NUMBER >= 0x10002000L
- SSL_clear_chain_certs(ssl);
+#if OPENSSL_VERSION_NUMBER >= 0x10002000L && !defined(LIBRESSL_VERSION_NUMBER)
+ if (ssl)
+ SSL_clear_chain_certs(ssl);
+ else
+ SSL_CTX_clear_chain_certs(data->ssl);
while ((cert = sk_X509_pop(certs)) != NULL) {
X509_NAME_oneline(X509_get_subject_name(cert), buf,
sizeof(buf));
wpa_printf(MSG_DEBUG, "TLS: additional certificate"
" from PKCS12: subject='%s'", buf);
- if (SSL_add1_chain_cert(ssl, cert) != 1) {
+ if ((ssl && SSL_add1_chain_cert(ssl, cert) != 1) ||
+ (!ssl && SSL_CTX_add1_chain_cert(data->ssl,
+ cert) != 1)) {
+ tls_show_errors(MSG_DEBUG, __func__,
+ "Failed to add additional certificate");
res = -1;
+ X509_free(cert);
break;
}
+ X509_free(cert);
+ }
+ if (!res) {
+ /* Try to continue anyway */
}
- sk_X509_free(certs);
+ sk_X509_pop_free(certs, X509_free);
#ifndef OPENSSL_IS_BORINGSSL
- res = SSL_build_cert_chain(ssl,
- SSL_BUILD_CHAIN_FLAG_CHECK |
- SSL_BUILD_CHAIN_FLAG_IGNORE_ERROR);
+ if (ssl)
+ res = SSL_build_cert_chain(
+ ssl,
+ SSL_BUILD_CHAIN_FLAG_CHECK |
+ SSL_BUILD_CHAIN_FLAG_IGNORE_ERROR);
+ else
+ res = SSL_CTX_build_cert_chain(
+ data->ssl,
+ SSL_BUILD_CHAIN_FLAG_CHECK |
+ SSL_BUILD_CHAIN_FLAG_IGNORE_ERROR);
if (!res) {
tls_show_errors(MSG_DEBUG, __func__,
"Failed to build certificate chain");
*/
res = 0;
#else /* OPENSSL_VERSION_NUMBER >= 0x10002000L */
-#if OPENSSL_VERSION_NUMBER >= 0x10001000L
- SSL_CTX_clear_extra_chain_certs(ssl_ctx);
-#endif /* OPENSSL_VERSION_NUMBER >= 0x10001000L */
+ SSL_CTX_clear_extra_chain_certs(data->ssl);
while ((cert = sk_X509_pop(certs)) != NULL) {
X509_NAME_oneline(X509_get_subject_name(cert), buf,
sizeof(buf));
* There is no SSL equivalent for the chain cert - so
* always add it to the context...
*/
- if (SSL_CTX_add_extra_chain_cert(ssl_ctx, cert) != 1) {
+ if (SSL_CTX_add_extra_chain_cert(data->ssl, cert) != 1)
+ {
+ X509_free(cert);
res = -1;
break;
}
}
- sk_X509_free(certs);
+ sk_X509_pop_free(certs, X509_free);
#endif /* OPENSSL_VERSION_NUMBER >= 0x10002000L */
}
PKCS12_free(p12);
if (res < 0)
- tls_get_errors(ssl_ctx);
+ tls_get_errors(data);
return res;
}
#endif /* PKCS12_FUNCS */
-static int tls_read_pkcs12(SSL_CTX *ssl_ctx, SSL *ssl, const char *private_key,
- const char *passwd)
+static int tls_read_pkcs12(struct tls_data *data, SSL *ssl,
+ const char *private_key, const char *passwd)
{
#ifdef PKCS12_FUNCS
FILE *f;
return -1;
}
- return tls_parse_pkcs12(ssl_ctx, ssl, p12, passwd);
+ return tls_parse_pkcs12(data, ssl, p12, passwd);
#else /* PKCS12_FUNCS */
wpa_printf(MSG_INFO, "TLS: PKCS12 support disabled - cannot read "
}
-static int tls_read_pkcs12_blob(SSL_CTX *ssl_ctx, SSL *ssl,
+static int tls_read_pkcs12_blob(struct tls_data *data, SSL *ssl,
const u8 *blob, size_t len, const char *passwd)
{
#ifdef PKCS12_FUNCS
return -1;
}
- return tls_parse_pkcs12(ssl_ctx, ssl, p12, passwd);
+ return tls_parse_pkcs12(data, ssl, p12, passwd);
#else /* PKCS12_FUNCS */
wpa_printf(MSG_INFO, "TLS: PKCS12 support disabled - cannot parse "
}
-static int tls_connection_engine_ca_cert(void *_ssl_ctx,
+static int tls_connection_engine_ca_cert(struct tls_data *data,
struct tls_connection *conn,
const char *ca_cert_id)
{
#ifndef OPENSSL_NO_ENGINE
X509 *cert;
- SSL_CTX *ssl_ctx = _ssl_ctx;
+ SSL_CTX *ssl_ctx = data->ssl;
X509_STORE *store;
if (tls_engine_get_cert(conn, ca_cert_id, &cert))
static int tls_connection_engine_private_key(struct tls_connection *conn)
{
-#ifndef OPENSSL_NO_ENGINE
+#if defined(ANDROID) || !defined(OPENSSL_NO_ENGINE)
if (SSL_use_PrivateKey(conn->ssl, conn->private_key) != 1) {
tls_show_errors(MSG_ERROR, __func__,
"ENGINE: cannot use private key for TLS");
}
-static int tls_connection_private_key(void *_ssl_ctx,
+static int tls_connection_private_key(struct tls_data *data,
struct tls_connection *conn,
const char *private_key,
const char *private_key_passwd,
const u8 *private_key_blob,
size_t private_key_blob_len)
{
- SSL_CTX *ssl_ctx = _ssl_ctx;
+ SSL_CTX *ssl_ctx = data->ssl;
char *passwd;
int ok;
break;
}
- if (tls_read_pkcs12_blob(ssl_ctx, conn->ssl, private_key_blob,
+ if (tls_read_pkcs12_blob(data, conn->ssl, private_key_blob,
private_key_blob_len, passwd) == 0) {
wpa_printf(MSG_DEBUG, "OpenSSL: PKCS#12 as blob --> "
"OK");
__func__);
#endif /* OPENSSL_NO_STDIO */
- if (tls_read_pkcs12(ssl_ctx, conn->ssl, private_key, passwd)
+ if (tls_read_pkcs12(data, conn->ssl, private_key, passwd)
== 0) {
wpa_printf(MSG_DEBUG, "OpenSSL: Reading PKCS#12 file "
"--> OK");
}
-static int tls_global_private_key(SSL_CTX *ssl_ctx, const char *private_key,
+static int tls_global_private_key(struct tls_data *data,
+ const char *private_key,
const char *private_key_passwd)
{
+ SSL_CTX *ssl_ctx = data->ssl;
char *passwd;
if (private_key == NULL)
SSL_CTX_use_PrivateKey_file(ssl_ctx, private_key,
SSL_FILETYPE_PEM) != 1 &&
#endif /* OPENSSL_NO_STDIO */
- tls_read_pkcs12(ssl_ctx, NULL, private_key, passwd)) {
+ tls_read_pkcs12(data, NULL, private_key, passwd)) {
tls_show_errors(MSG_INFO, __func__,
"Failed to load private key");
os_free(passwd);
}
-static int tls_global_dh(SSL_CTX *ssl_ctx, const char *dh_file)
+static int tls_global_dh(struct tls_data *data, const char *dh_file)
{
#ifdef OPENSSL_NO_DH
if (dh_file == NULL)
"dh_file specified");
return -1;
#else /* OPENSSL_NO_DH */
+ SSL_CTX *ssl_ctx = data->ssl;
DH *dh;
BIO *bio;
if (conn == NULL || keys == NULL)
return -1;
ssl = conn->ssl;
-#if OPENSSL_VERSION_NUMBER < 0x10100000L
- if (ssl == NULL || ssl->s3 == NULL || ssl->session == NULL)
- return -1;
-
- os_memset(keys, 0, sizeof(*keys));
- keys->client_random = ssl->s3->client_random;
- keys->client_random_len = SSL3_RANDOM_SIZE;
- keys->server_random = ssl->s3->server_random;
- keys->server_random_len = SSL3_RANDOM_SIZE;
-#else
if (ssl == NULL)
return -1;
keys->server_random = conn->server_random;
keys->server_random_len = SSL_get_server_random(
ssl, conn->server_random, sizeof(conn->server_random));
-#endif
return 0;
}
-#ifndef CONFIG_FIPS
+#ifdef OPENSSL_NEED_EAP_FAST_PRF
static int openssl_get_keyblock_size(SSL *ssl)
{
-#if OPENSSL_VERSION_NUMBER < 0x10100000L
+#if OPENSSL_VERSION_NUMBER < 0x10100000L || defined(LIBRESSL_VERSION_NUMBER)
const EVP_CIPHER *c;
const EVP_MD *h;
int md_size;
return -1;
c = ssl->enc_read_ctx->cipher;
-#if OPENSSL_VERSION_NUMBER >= 0x00909000L
h = EVP_MD_CTX_md(ssl->read_hash);
-#else
- h = ssl->read_hash;
-#endif
if (h)
md_size = EVP_MD_size(h);
-#if OPENSSL_VERSION_NUMBER >= 0x10000000L
else if (ssl->s3)
md_size = ssl->s3->tmp.new_mac_secret_size;
-#endif
else
return -1;
EVP_CIPHER_iv_length(c));
#endif
}
-#endif /* CONFIG_FIPS */
+#endif /* OPENSSL_NEED_EAP_FAST_PRF */
-static int openssl_tls_prf(void *tls_ctx, struct tls_connection *conn,
- const char *label, int server_random_first,
- int skip_keyblock, u8 *out, size_t out_len)
+int tls_connection_export_key(void *tls_ctx, struct tls_connection *conn,
+ const char *label, u8 *out, size_t out_len)
{
-#ifdef CONFIG_FIPS
- wpa_printf(MSG_ERROR, "OpenSSL: TLS keys cannot be exported in FIPS "
- "mode");
- return -1;
-#else /* CONFIG_FIPS */
-#if OPENSSL_VERSION_NUMBER < 0x10100000L
- SSL *ssl;
- u8 *rnd;
- int ret = -1;
- int skip = 0;
- u8 *tmp_out = NULL;
- u8 *_out = out;
- const char *ver;
-
- /*
- * TLS library did not support key generation, so get the needed TLS
- * session parameters and use an internal implementation of TLS PRF to
- * derive the key.
- */
-
- if (conn == NULL)
- return -1;
- ssl = conn->ssl;
- if (ssl == NULL || ssl->s3 == NULL || ssl->session == NULL ||
- ssl->session->master_key_length <= 0)
+ if (!conn ||
+ SSL_export_keying_material(conn->ssl, out, out_len, label,
+ os_strlen(label), NULL, 0, 0) != 1)
return -1;
- ver = SSL_get_version(ssl);
-
- if (skip_keyblock) {
- skip = openssl_get_keyblock_size(ssl);
- if (skip < 0)
- return -1;
- tmp_out = os_malloc(skip + out_len);
- if (!tmp_out)
- return -1;
- _out = tmp_out;
- }
-
- rnd = os_malloc(2 * SSL3_RANDOM_SIZE);
- if (!rnd) {
- os_free(tmp_out);
- return -1;
- }
+ return 0;
+}
- if (server_random_first) {
- os_memcpy(rnd, ssl->s3->server_random, SSL3_RANDOM_SIZE);
- os_memcpy(rnd + SSL3_RANDOM_SIZE, ssl->s3->client_random,
- SSL3_RANDOM_SIZE);
- } else {
- os_memcpy(rnd, ssl->s3->client_random, SSL3_RANDOM_SIZE);
- os_memcpy(rnd + SSL3_RANDOM_SIZE, ssl->s3->server_random,
- SSL3_RANDOM_SIZE);
- }
- if (os_strcmp(ver, "TLSv1.2") == 0) {
- tls_prf_sha256(ssl->session->master_key,
- ssl->session->master_key_length,
- label, rnd, 2 * SSL3_RANDOM_SIZE,
- _out, skip + out_len);
- ret = 0;
- } else if (tls_prf_sha1_md5(ssl->session->master_key,
- ssl->session->master_key_length,
- label, rnd, 2 * SSL3_RANDOM_SIZE,
- _out, skip + out_len) == 0) {
- ret = 0;
- }
- os_free(rnd);
- if (ret == 0 && skip_keyblock)
- os_memcpy(out, _out + skip, out_len);
- bin_clear_free(tmp_out, skip);
-
- return ret;
-#else
+int tls_connection_get_eap_fast_key(void *tls_ctx, struct tls_connection *conn,
+ u8 *out, size_t out_len)
+{
+#ifdef OPENSSL_NEED_EAP_FAST_PRF
SSL *ssl;
SSL_SESSION *sess;
u8 *rnd;
const char *ver;
/*
- * TLS library did not support key generation, so get the needed TLS
- * session parameters and use an internal implementation of TLS PRF to
- * derive the key.
+ * TLS library did not support EAP-FAST key generation, so get the
+ * needed TLS session parameters and use an internal implementation of
+ * TLS PRF to derive the key.
*/
if (conn == NULL)
if (!ver || !sess)
return -1;
- if (skip_keyblock) {
- skip = openssl_get_keyblock_size(ssl);
- if (skip < 0)
- return -1;
- tmp_out = os_malloc(skip + out_len);
- if (!tmp_out)
- return -1;
- _out = tmp_out;
- }
+ skip = openssl_get_keyblock_size(ssl);
+ if (skip < 0)
+ return -1;
+ tmp_out = os_malloc(skip + out_len);
+ if (!tmp_out)
+ return -1;
+ _out = tmp_out;
rnd = os_malloc(2 * SSL3_RANDOM_SIZE);
if (!rnd) {
master_key_len = SSL_SESSION_get_master_key(sess, master_key,
sizeof(master_key));
- if (server_random_first) {
- os_memcpy(rnd, server_random, SSL3_RANDOM_SIZE);
- os_memcpy(rnd + SSL3_RANDOM_SIZE, client_random,
- SSL3_RANDOM_SIZE);
- } else {
- os_memcpy(rnd, client_random, SSL3_RANDOM_SIZE);
- os_memcpy(rnd + SSL3_RANDOM_SIZE, server_random,
- SSL3_RANDOM_SIZE);
- }
+ os_memcpy(rnd, server_random, SSL3_RANDOM_SIZE);
+ os_memcpy(rnd + SSL3_RANDOM_SIZE, client_random, SSL3_RANDOM_SIZE);
if (os_strcmp(ver, "TLSv1.2") == 0) {
tls_prf_sha256(master_key, master_key_len,
- label, rnd, 2 * SSL3_RANDOM_SIZE,
+ "key expansion", rnd, 2 * SSL3_RANDOM_SIZE,
_out, skip + out_len);
ret = 0;
} else if (tls_prf_sha1_md5(master_key, master_key_len,
- label, rnd, 2 * SSL3_RANDOM_SIZE,
+ "key expansion", rnd, 2 * SSL3_RANDOM_SIZE,
_out, skip + out_len) == 0) {
ret = 0;
}
os_memset(master_key, 0, sizeof(master_key));
os_free(rnd);
- if (ret == 0 && skip_keyblock)
+ if (ret == 0)
os_memcpy(out, _out + skip, out_len);
bin_clear_free(tmp_out, skip);
return ret;
-#endif
-#endif /* CONFIG_FIPS */
-}
-
-
-int tls_connection_prf(void *tls_ctx, struct tls_connection *conn,
- const char *label, int server_random_first,
- int skip_keyblock, u8 *out, size_t out_len)
-{
-#if OPENSSL_VERSION_NUMBER >= 0x10001000L
- SSL *ssl;
- if (conn == NULL)
- return -1;
- if (server_random_first || skip_keyblock)
- return openssl_tls_prf(tls_ctx, conn, label,
- server_random_first, skip_keyblock,
- out, out_len);
- ssl = conn->ssl;
- if (SSL_export_keying_material(ssl, out, out_len, label,
- os_strlen(label), NULL, 0, 0) == 1) {
- wpa_printf(MSG_DEBUG, "OpenSSL: Using internal PRF");
- return 0;
- }
-#endif
- return openssl_tls_prf(tls_ctx, conn, label, server_random_first,
- skip_keyblock, out, out_len);
+#else /* OPENSSL_NEED_EAP_FAST_PRF */
+ wpa_printf(MSG_ERROR,
+ "OpenSSL: EAP-FAST keys cannot be exported in FIPS mode");
+ return -1;
+#endif /* OPENSSL_NEED_EAP_FAST_PRF */
}
int tls_connection_resumed(void *ssl_ctx, struct tls_connection *conn)
{
-#if OPENSSL_VERSION_NUMBER >= 0x10001000L
return conn ? SSL_cache_hit(conn->ssl) : 0;
-#else
- return conn ? conn->ssl->hit : 0;
-#endif
}
int tls_connection_set_cipher_list(void *tls_ctx, struct tls_connection *conn,
u8 *ciphers)
{
- char buf[100], *pos, *end;
+ char buf[500], *pos, *end;
u8 *c;
int ret;
case TLS_CIPHER_ANON_DH_AES128_SHA:
suite = "ADH-AES128-SHA";
break;
+ case TLS_CIPHER_RSA_DHE_AES256_SHA:
+ suite = "DHE-RSA-AES256-SHA";
+ break;
+ case TLS_CIPHER_AES256_SHA:
+ suite = "AES256-SHA";
+ break;
default:
wpa_printf(MSG_DEBUG, "TLS: Unsupported "
"cipher selection: %d", *c);
wpa_printf(MSG_DEBUG, "OpenSSL: cipher suites: %s", buf + 1);
-#if OPENSSL_VERSION_NUMBER >= 0x10100000L
+#if OPENSSL_VERSION_NUMBER >= 0x10100000L && !defined(LIBRESSL_VERSION_NUMBER)
#if defined(EAP_FAST) || defined(EAP_FAST_DYNAMIC) || defined(EAP_SERVER_FAST)
if (os_strstr(buf, ":ADH-")) {
/*
wpa_printf(MSG_INFO, "OpenSSL: Could not find current server certificate from OCSP response%s",
(conn->flags & TLS_CONN_REQUIRE_OCSP) ? "" :
" (OCSP not required)");
+ OCSP_CERTID_free(id);
OCSP_BASICRESP_free(basic);
OCSP_RESPONSE_free(rsp);
return (conn->flags & TLS_CONN_REQUIRE_OCSP) ? 0 : 1;
}
+ OCSP_CERTID_free(id);
if (!OCSP_check_validity(this_update, next_update, 5 * 60, -1)) {
tls_show_errors(MSG_INFO, __func__,
int tls_connection_set_params(void *tls_ctx, struct tls_connection *conn,
const struct tls_connection_params *params)
{
+ struct tls_data *data = tls_ctx;
int ret;
unsigned long err;
int can_pkcs11 = 0;
if (conn == NULL)
return -1;
+ if (params->flags & TLS_CONN_REQUIRE_OCSP_ALL) {
+ wpa_printf(MSG_INFO,
+ "OpenSSL: ocsp=3 not supported");
+ return -1;
+ }
+
/*
* If the engine isn't explicitly configured, and any of the
* cert/key fields are actually PKCS#11 URIs, then automatically
engine_id = "pkcs11";
#if defined(EAP_FAST) || defined(EAP_FAST_DYNAMIC) || defined(EAP_SERVER_FAST)
-#if OPENSSL_VERSION_NUMBER < 0x10100000L
+#if OPENSSL_VERSION_NUMBER < 0x10100000L || defined(LIBRESSL_VERSION_NUMBER)
if (params->flags & TLS_CONN_EAP_FAST) {
wpa_printf(MSG_DEBUG,
"OpenSSL: Use TLSv1_method() for EAP-FAST");
return -1;
if (engine_id && ca_cert_id) {
- if (tls_connection_engine_ca_cert(tls_ctx, conn,
- ca_cert_id))
+ if (tls_connection_engine_ca_cert(data, conn, ca_cert_id))
return TLS_SET_PARAMS_ENGINE_PRV_VERIFY_FAILED;
- } else if (tls_connection_ca_cert(tls_ctx, conn, params->ca_cert,
+ } else if (tls_connection_ca_cert(data, conn, params->ca_cert,
params->ca_cert_blob,
params->ca_cert_blob_len,
params->ca_path))
wpa_printf(MSG_DEBUG, "TLS: Using private key from engine");
if (tls_connection_engine_private_key(conn))
return TLS_SET_PARAMS_ENGINE_PRV_VERIFY_FAILED;
- } else if (tls_connection_private_key(tls_ctx, conn,
+ } else if (tls_connection_private_key(data, conn,
params->private_key,
params->private_key_passwd,
params->private_key_blob,
return -1;
}
-#ifdef SSL_OP_NO_TICKET
- if (params->flags & TLS_CONN_DISABLE_SESSION_TICKET)
- SSL_set_options(conn->ssl, SSL_OP_NO_TICKET);
-#ifdef SSL_clear_options
- else
- SSL_clear_options(conn->ssl, SSL_OP_NO_TICKET);
-#endif /* SSL_clear_options */
-#endif /* SSL_OP_NO_TICKET */
-
-#ifdef SSL_OP_NO_TLSv1
- if (params->flags & TLS_CONN_DISABLE_TLSv1_0)
- SSL_set_options(conn->ssl, SSL_OP_NO_TLSv1);
- else
- SSL_clear_options(conn->ssl, SSL_OP_NO_TLSv1);
-#endif /* SSL_OP_NO_TLSv1 */
-#ifdef SSL_OP_NO_TLSv1_1
- if (params->flags & TLS_CONN_DISABLE_TLSv1_1)
- SSL_set_options(conn->ssl, SSL_OP_NO_TLSv1_1);
- else
- SSL_clear_options(conn->ssl, SSL_OP_NO_TLSv1_1);
-#endif /* SSL_OP_NO_TLSv1_1 */
-#ifdef SSL_OP_NO_TLSv1_2
- if (params->flags & TLS_CONN_DISABLE_TLSv1_2)
- SSL_set_options(conn->ssl, SSL_OP_NO_TLSv1_2);
- else
- SSL_clear_options(conn->ssl, SSL_OP_NO_TLSv1_2);
-#endif /* SSL_OP_NO_TLSv1_2 */
+ tls_set_conn_flags(conn->ssl, params->flags);
+#ifdef OPENSSL_IS_BORINGSSL
+ if (params->flags & TLS_CONN_REQUEST_OCSP) {
+ SSL_enable_ocsp_stapling(conn->ssl);
+ }
+#else /* OPENSSL_IS_BORINGSSL */
#ifdef HAVE_OCSP
if (params->flags & TLS_CONN_REQUEST_OCSP) {
- SSL_CTX *ssl_ctx = tls_ctx;
+ SSL_CTX *ssl_ctx = data->ssl;
SSL_set_tlsext_status_type(conn->ssl, TLSEXT_STATUSTYPE_ocsp);
SSL_CTX_set_tlsext_status_cb(ssl_ctx, ocsp_resp_cb);
SSL_CTX_set_tlsext_status_arg(ssl_ctx, conn);
"OpenSSL: No OCSP support included - allow optional OCSP case to continue");
}
#endif /* HAVE_OCSP */
+#endif /* OPENSSL_IS_BORINGSSL */
conn->flags = params->flags;
- tls_get_errors(tls_ctx);
+ tls_get_errors(data);
return 0;
}
int tls_global_set_params(void *tls_ctx,
const struct tls_connection_params *params)
{
- SSL_CTX *ssl_ctx = tls_ctx;
+ struct tls_data *data = tls_ctx;
+ SSL_CTX *ssl_ctx = data->ssl;
unsigned long err;
while ((err = ERR_get_error())) {
__func__, ERR_error_string(err, NULL));
}
- if (tls_global_ca_cert(ssl_ctx, params->ca_cert) ||
- tls_global_client_cert(ssl_ctx, params->client_cert) ||
- tls_global_private_key(ssl_ctx, params->private_key,
+ if (tls_global_ca_cert(data, params->ca_cert) ||
+ tls_global_client_cert(data, params->client_cert) ||
+ tls_global_private_key(data, params->private_key,
params->private_key_passwd) ||
- tls_global_dh(ssl_ctx, params->dh_file)) {
+ tls_global_dh(data, params->dh_file)) {
wpa_printf(MSG_INFO, "TLS: Failed to set global parameters");
return -1;
}
#ifdef SSL_OP_NO_TICKET
if (params->flags & TLS_CONN_DISABLE_SESSION_TICKET)
SSL_CTX_set_options(ssl_ctx, SSL_OP_NO_TICKET);
-#ifdef SSL_CTX_clear_options
else
SSL_CTX_clear_options(ssl_ctx, SSL_OP_NO_TICKET);
-#endif /* SSL_clear_options */
#endif /* SSL_OP_NO_TICKET */
#ifdef HAVE_OCSP
* commented out unless explicitly needed for EAP-FAST in order to be able to
* build this file with unmodified openssl. */
-#ifdef OPENSSL_IS_BORINGSSL
+#if (defined(OPENSSL_IS_BORINGSSL) || OPENSSL_VERSION_NUMBER >= 0x10100000L) && !defined(LIBRESSL_VERSION_NUMBER)
static int tls_sess_sec_cb(SSL *s, void *secret, int *secret_len,
STACK_OF(SSL_CIPHER) *peer_ciphers,
const SSL_CIPHER **cipher, void *arg)
struct tls_connection *conn = arg;
int ret;
-#if OPENSSL_VERSION_NUMBER < 0x10100000L
+#if OPENSSL_VERSION_NUMBER < 0x10100000L || defined(LIBRESSL_VERSION_NUMBER)
if (conn == NULL || conn->session_ticket_cb == NULL)
return 0;
wpa_hexdump(MSG_DEBUG, "OpenSSL: ClientHello SessionTicket "
"extension", data, len);
- conn->session_ticket = os_malloc(len);
+ conn->session_ticket = os_memdup(data, len);
if (conn->session_ticket == NULL)
return 0;
- os_memcpy(conn->session_ticket, data, len);
conn->session_ticket_len = len;
return 1;
int tls_get_library_version(char *buf, size_t buf_len)
{
+#if OPENSSL_VERSION_NUMBER >= 0x10100000L && !defined(LIBRESSL_VERSION_NUMBER)
+ return os_snprintf(buf, buf_len, "OpenSSL build=%s run=%s",
+ OPENSSL_VERSION_TEXT,
+ OpenSSL_version(OPENSSL_VERSION));
+#else
return os_snprintf(buf, buf_len, "OpenSSL build=%s run=%s",
OPENSSL_VERSION_TEXT,
SSLeay_version(SSLEAY_VERSION));
+#endif
+}
+
+
+void tls_connection_set_success_data(struct tls_connection *conn,
+ struct wpabuf *data)
+{
+ SSL_SESSION *sess;
+ struct wpabuf *old;
+
+ if (tls_ex_idx_session < 0)
+ goto fail;
+ sess = SSL_get_session(conn->ssl);
+ if (!sess)
+ goto fail;
+ old = SSL_SESSION_get_ex_data(sess, tls_ex_idx_session);
+ if (old) {
+ wpa_printf(MSG_DEBUG, "OpenSSL: Replacing old success data %p",
+ old);
+ wpabuf_free(old);
+ }
+ if (SSL_SESSION_set_ex_data(sess, tls_ex_idx_session, data) != 1)
+ goto fail;
+
+ wpa_printf(MSG_DEBUG, "OpenSSL: Stored success data %p", data);
+ conn->success_data = 1;
+ return;
+
+fail:
+ wpa_printf(MSG_INFO, "OpenSSL: Failed to store success data");
+ wpabuf_free(data);
+}
+
+
+void tls_connection_set_success_data_resumed(struct tls_connection *conn)
+{
+ wpa_printf(MSG_DEBUG,
+ "OpenSSL: Success data accepted for resumed session");
+ conn->success_data = 1;
+}
+
+
+const struct wpabuf *
+tls_connection_get_success_data(struct tls_connection *conn)
+{
+ SSL_SESSION *sess;
+
+ if (tls_ex_idx_session < 0 ||
+ !(sess = SSL_get_session(conn->ssl)))
+ return NULL;
+ return SSL_SESSION_get_ex_data(sess, tls_ex_idx_session);
+}
+
+
+void tls_connection_remove_session(struct tls_connection *conn)
+{
+ SSL_SESSION *sess;
+
+ sess = SSL_get_session(conn->ssl);
+ if (!sess)
+ return;
+
+ if (SSL_CTX_remove_session(conn->ssl_ctx, sess) != 1)
+ wpa_printf(MSG_DEBUG,
+ "OpenSSL: Session was not cached");
+ else
+ wpa_printf(MSG_DEBUG,
+ "OpenSSL: Removed cached session to disable session resumption");
}