xref: /freebsd/contrib/wpa/src/crypto/tls_openssl.c (revision a90b9d0159070121c221b966469c3e36d912bf82)
139beb93cSSam Leffler /*
2e28a4053SRui Paulo  * SSL/TLS interface functions for OpenSSL
3325151a3SRui Paulo  * Copyright (c) 2004-2015, Jouni Malinen <j@w1.fi>
439beb93cSSam Leffler  *
5f05cddf9SRui Paulo  * This software may be distributed under the terms of the BSD license.
6f05cddf9SRui Paulo  * See README for more details.
739beb93cSSam Leffler  */
839beb93cSSam Leffler 
939beb93cSSam Leffler #include "includes.h"
10*a90b9d01SCy Schubert #ifdef CONFIG_TESTING_OPTIONS
11*a90b9d01SCy Schubert #include <fcntl.h>
12*a90b9d01SCy Schubert #endif /* CONFIG_TESTING_OPTIONS */
1339beb93cSSam Leffler 
1439beb93cSSam Leffler #ifndef CONFIG_SMARTCARD
1539beb93cSSam Leffler #ifndef OPENSSL_NO_ENGINE
165b9c547cSRui Paulo #ifndef ANDROID
1739beb93cSSam Leffler #define OPENSSL_NO_ENGINE
1839beb93cSSam Leffler #endif
1939beb93cSSam Leffler #endif
205b9c547cSRui Paulo #endif
2139beb93cSSam Leffler 
22*a90b9d01SCy Schubert #ifndef OPENSSL_NO_ENGINE
23*a90b9d01SCy Schubert /* OpenSSL 3.0 has moved away from the engine API */
24*a90b9d01SCy Schubert #define OPENSSL_SUPPRESS_DEPRECATED
25*a90b9d01SCy Schubert #include <openssl/engine.h>
26*a90b9d01SCy Schubert #endif /* OPENSSL_NO_ENGINE */
2739beb93cSSam Leffler #include <openssl/ssl.h>
2839beb93cSSam Leffler #include <openssl/err.h>
29780fb4a2SCy Schubert #include <openssl/opensslv.h>
3039beb93cSSam Leffler #include <openssl/pkcs12.h>
3139beb93cSSam Leffler #include <openssl/x509v3.h>
32*a90b9d01SCy Schubert #if OPENSSL_VERSION_NUMBER >= 0x30000000L
33*a90b9d01SCy Schubert #include <openssl/core_names.h>
34*a90b9d01SCy Schubert #include <openssl/decoder.h>
35*a90b9d01SCy Schubert #include <openssl/param_build.h>
36*a90b9d01SCy Schubert #else /* OpenSSL version >= 3.0 */
37325151a3SRui Paulo #ifndef OPENSSL_NO_DSA
38325151a3SRui Paulo #include <openssl/dsa.h>
39325151a3SRui Paulo #endif
40325151a3SRui Paulo #ifndef OPENSSL_NO_DH
41325151a3SRui Paulo #include <openssl/dh.h>
42325151a3SRui Paulo #endif
43*a90b9d01SCy Schubert #endif /* OpenSSL version >= 3.0 */
4439beb93cSSam Leffler 
4539beb93cSSam Leffler #include "common.h"
46*a90b9d01SCy Schubert #include "utils/list.h"
47e28a4053SRui Paulo #include "crypto.h"
48325151a3SRui Paulo #include "sha1.h"
49325151a3SRui Paulo #include "sha256.h"
5039beb93cSSam Leffler #include "tls.h"
51780fb4a2SCy Schubert #include "tls_openssl.h"
5239beb93cSSam Leffler 
53780fb4a2SCy Schubert #if !defined(CONFIG_FIPS) &&                             \
54780fb4a2SCy Schubert     (defined(EAP_FAST) || defined(EAP_FAST_DYNAMIC) ||   \
55780fb4a2SCy Schubert      defined(EAP_SERVER_FAST))
56780fb4a2SCy Schubert #define OPENSSL_NEED_EAP_FAST_PRF
5739beb93cSSam Leffler #endif
585b9c547cSRui Paulo 
59206b73d0SCy Schubert #if defined(EAP_FAST) || defined(EAP_FAST_DYNAMIC) || \
60206b73d0SCy Schubert 	defined(EAP_SERVER_FAST) || defined(EAP_TEAP) || \
61206b73d0SCy Schubert 	defined(EAP_SERVER_TEAP)
62206b73d0SCy Schubert #define EAP_FAST_OR_TEAP
63206b73d0SCy Schubert #endif
64206b73d0SCy Schubert 
65206b73d0SCy Schubert 
665b9c547cSRui Paulo #if defined(OPENSSL_IS_BORINGSSL)
675b9c547cSRui Paulo /* stack_index_t is the return type of OpenSSL's sk_XXX_num() functions. */
685b9c547cSRui Paulo typedef size_t stack_index_t;
695b9c547cSRui Paulo #else
705b9c547cSRui Paulo typedef int stack_index_t;
7139beb93cSSam Leffler #endif
7239beb93cSSam Leffler 
735b9c547cSRui Paulo #ifdef SSL_set_tlsext_status_type
745b9c547cSRui Paulo #ifndef OPENSSL_NO_TLSEXT
755b9c547cSRui Paulo #define HAVE_OCSP
765b9c547cSRui Paulo #include <openssl/ocsp.h>
775b9c547cSRui Paulo #endif /* OPENSSL_NO_TLSEXT */
785b9c547cSRui Paulo #endif /* SSL_set_tlsext_status_type */
795b9c547cSRui Paulo 
80*a90b9d01SCy Schubert #if OPENSSL_VERSION_NUMBER < 0x10100000L && \
81780fb4a2SCy Schubert     !defined(BORINGSSL_API_VERSION)
82780fb4a2SCy Schubert /*
83780fb4a2SCy Schubert  * SSL_get_client_random() and SSL_get_server_random() were added in OpenSSL
84780fb4a2SCy Schubert  * 1.1.0 and newer BoringSSL revisions. Provide compatibility wrappers for
85780fb4a2SCy Schubert  * older versions.
86780fb4a2SCy Schubert  */
87780fb4a2SCy Schubert 
SSL_get_client_random(const SSL * ssl,unsigned char * out,size_t outlen)88780fb4a2SCy Schubert static size_t SSL_get_client_random(const SSL *ssl, unsigned char *out,
89780fb4a2SCy Schubert 				    size_t outlen)
90780fb4a2SCy Schubert {
91780fb4a2SCy Schubert 	if (!ssl->s3 || outlen < SSL3_RANDOM_SIZE)
92780fb4a2SCy Schubert 		return 0;
93780fb4a2SCy Schubert 	os_memcpy(out, ssl->s3->client_random, SSL3_RANDOM_SIZE);
94780fb4a2SCy Schubert 	return SSL3_RANDOM_SIZE;
95780fb4a2SCy Schubert }
96780fb4a2SCy Schubert 
97780fb4a2SCy Schubert 
SSL_get_server_random(const SSL * ssl,unsigned char * out,size_t outlen)98780fb4a2SCy Schubert static size_t SSL_get_server_random(const SSL *ssl, unsigned char *out,
99780fb4a2SCy Schubert 				    size_t outlen)
100780fb4a2SCy Schubert {
101780fb4a2SCy Schubert 	if (!ssl->s3 || outlen < SSL3_RANDOM_SIZE)
102780fb4a2SCy Schubert 		return 0;
103780fb4a2SCy Schubert 	os_memcpy(out, ssl->s3->server_random, SSL3_RANDOM_SIZE);
104780fb4a2SCy Schubert 	return SSL3_RANDOM_SIZE;
105780fb4a2SCy Schubert }
106780fb4a2SCy Schubert 
107780fb4a2SCy Schubert 
108780fb4a2SCy Schubert #ifdef OPENSSL_NEED_EAP_FAST_PRF
SSL_SESSION_get_master_key(const SSL_SESSION * session,unsigned char * out,size_t outlen)109780fb4a2SCy Schubert static size_t SSL_SESSION_get_master_key(const SSL_SESSION *session,
110780fb4a2SCy Schubert 					 unsigned char *out, size_t outlen)
111780fb4a2SCy Schubert {
112780fb4a2SCy Schubert 	if (!session || session->master_key_length < 0 ||
113780fb4a2SCy Schubert 	    (size_t) session->master_key_length > outlen)
114780fb4a2SCy Schubert 		return 0;
115780fb4a2SCy Schubert 	if ((size_t) session->master_key_length < outlen)
116780fb4a2SCy Schubert 		outlen = session->master_key_length;
117780fb4a2SCy Schubert 	os_memcpy(out, session->master_key, outlen);
118780fb4a2SCy Schubert 	return outlen;
119780fb4a2SCy Schubert }
120780fb4a2SCy Schubert #endif /* OPENSSL_NEED_EAP_FAST_PRF */
121780fb4a2SCy Schubert 
122780fb4a2SCy Schubert #endif
123780fb4a2SCy Schubert 
124*a90b9d01SCy Schubert #if OPENSSL_VERSION_NUMBER < 0x10100000L
ASN1_STRING_get0_data(const ASN1_STRING * x)12585732ac8SCy Schubert static const unsigned char * ASN1_STRING_get0_data(const ASN1_STRING *x)
12685732ac8SCy Schubert {
12785732ac8SCy Schubert 	return ASN1_STRING_data((ASN1_STRING *) x);
12885732ac8SCy Schubert }
12985732ac8SCy Schubert #endif
13085732ac8SCy Schubert 
1315b9c547cSRui Paulo #ifdef ANDROID
1325b9c547cSRui Paulo #include <openssl/pem.h>
1335b9c547cSRui Paulo #include <keystore/keystore_get.h>
1345b9c547cSRui Paulo 
BIO_from_keystore(const char * key)1355b9c547cSRui Paulo static BIO * BIO_from_keystore(const char *key)
1365b9c547cSRui Paulo {
1375b9c547cSRui Paulo 	BIO *bio = NULL;
1385b9c547cSRui Paulo 	uint8_t *value = NULL;
1395b9c547cSRui Paulo 	int length = keystore_get(key, strlen(key), &value);
1405b9c547cSRui Paulo 	if (length != -1 && (bio = BIO_new(BIO_s_mem())) != NULL)
1415b9c547cSRui Paulo 		BIO_write(bio, value, length);
1425b9c547cSRui Paulo 	free(value);
1435b9c547cSRui Paulo 	return bio;
1445b9c547cSRui Paulo }
145780fb4a2SCy Schubert 
146780fb4a2SCy Schubert 
tls_add_ca_from_keystore(X509_STORE * ctx,const char * key_alias)147780fb4a2SCy Schubert static int tls_add_ca_from_keystore(X509_STORE *ctx, const char *key_alias)
148780fb4a2SCy Schubert {
149780fb4a2SCy Schubert 	BIO *bio = BIO_from_keystore(key_alias);
150780fb4a2SCy Schubert 	STACK_OF(X509_INFO) *stack = NULL;
151780fb4a2SCy Schubert 	stack_index_t i;
152780fb4a2SCy Schubert 
153780fb4a2SCy Schubert 	if (bio) {
154780fb4a2SCy Schubert 		stack = PEM_X509_INFO_read_bio(bio, NULL, NULL, NULL);
155780fb4a2SCy Schubert 		BIO_free(bio);
156780fb4a2SCy Schubert 	}
157780fb4a2SCy Schubert 
158780fb4a2SCy Schubert 	if (!stack) {
159780fb4a2SCy Schubert 		wpa_printf(MSG_WARNING, "TLS: Failed to parse certificate: %s",
160780fb4a2SCy Schubert 			   key_alias);
161780fb4a2SCy Schubert 		return -1;
162780fb4a2SCy Schubert 	}
163780fb4a2SCy Schubert 
164780fb4a2SCy Schubert 	for (i = 0; i < sk_X509_INFO_num(stack); ++i) {
165780fb4a2SCy Schubert 		X509_INFO *info = sk_X509_INFO_value(stack, i);
166780fb4a2SCy Schubert 
167780fb4a2SCy Schubert 		if (info->x509)
168780fb4a2SCy Schubert 			X509_STORE_add_cert(ctx, info->x509);
169780fb4a2SCy Schubert 		if (info->crl)
170780fb4a2SCy Schubert 			X509_STORE_add_crl(ctx, info->crl);
171780fb4a2SCy Schubert 	}
172780fb4a2SCy Schubert 
173780fb4a2SCy Schubert 	sk_X509_INFO_pop_free(stack, X509_INFO_free);
174780fb4a2SCy Schubert 
175780fb4a2SCy Schubert 	return 0;
176780fb4a2SCy Schubert }
177780fb4a2SCy Schubert 
178780fb4a2SCy Schubert 
tls_add_ca_from_keystore_encoded(X509_STORE * ctx,const char * encoded_key_alias)179780fb4a2SCy Schubert static int tls_add_ca_from_keystore_encoded(X509_STORE *ctx,
180780fb4a2SCy Schubert 					    const char *encoded_key_alias)
181780fb4a2SCy Schubert {
182780fb4a2SCy Schubert 	int rc = -1;
183780fb4a2SCy Schubert 	int len = os_strlen(encoded_key_alias);
184780fb4a2SCy Schubert 	unsigned char *decoded_alias;
185780fb4a2SCy Schubert 
186780fb4a2SCy Schubert 	if (len & 1) {
187780fb4a2SCy Schubert 		wpa_printf(MSG_WARNING, "Invalid hex-encoded alias: %s",
188780fb4a2SCy Schubert 			   encoded_key_alias);
189780fb4a2SCy Schubert 		return rc;
190780fb4a2SCy Schubert 	}
191780fb4a2SCy Schubert 
192780fb4a2SCy Schubert 	decoded_alias = os_malloc(len / 2 + 1);
193780fb4a2SCy Schubert 	if (decoded_alias) {
194780fb4a2SCy Schubert 		if (!hexstr2bin(encoded_key_alias, decoded_alias, len / 2)) {
195780fb4a2SCy Schubert 			decoded_alias[len / 2] = '\0';
196780fb4a2SCy Schubert 			rc = tls_add_ca_from_keystore(
197780fb4a2SCy Schubert 				ctx, (const char *) decoded_alias);
198780fb4a2SCy Schubert 		}
199780fb4a2SCy Schubert 		os_free(decoded_alias);
200780fb4a2SCy Schubert 	}
201780fb4a2SCy Schubert 
202780fb4a2SCy Schubert 	return rc;
203780fb4a2SCy Schubert }
204780fb4a2SCy Schubert 
2055b9c547cSRui Paulo #endif /* ANDROID */
2065b9c547cSRui Paulo 
20739beb93cSSam Leffler static int tls_openssl_ref_count = 0;
208325151a3SRui Paulo static int tls_ex_idx_session = -1;
20939beb93cSSam Leffler 
210*a90b9d01SCy Schubert struct tls_session_data {
211*a90b9d01SCy Schubert 	struct dl_list list;
212*a90b9d01SCy Schubert 	struct wpabuf *buf;
213*a90b9d01SCy Schubert };
214*a90b9d01SCy Schubert 
2155b9c547cSRui Paulo struct tls_context {
216e28a4053SRui Paulo 	void (*event_cb)(void *ctx, enum tls_event ev,
217e28a4053SRui Paulo 			 union tls_event_data *data);
218e28a4053SRui Paulo 	void *cb_ctx;
219f05cddf9SRui Paulo 	int cert_in_cb;
2205b9c547cSRui Paulo 	char *ocsp_stapling_response;
221*a90b9d01SCy Schubert 	struct dl_list sessions; /* struct tls_session_data */
222e28a4053SRui Paulo };
223e28a4053SRui Paulo 
2245b9c547cSRui Paulo static struct tls_context *tls_global = NULL;
225e28a4053SRui Paulo 
226e28a4053SRui Paulo 
227325151a3SRui Paulo struct tls_data {
228325151a3SRui Paulo 	SSL_CTX *ssl;
229325151a3SRui Paulo 	unsigned int tls_session_lifetime;
2304bc52338SCy Schubert 	int check_crl;
2314bc52338SCy Schubert 	int check_crl_strict;
2324bc52338SCy Schubert 	char *ca_cert;
2334bc52338SCy Schubert 	unsigned int crl_reload_interval;
2344bc52338SCy Schubert 	struct os_reltime crl_last_reload;
2354bc52338SCy Schubert 	char *check_cert_subject;
236*a90b9d01SCy Schubert 	char *openssl_ciphers;
237325151a3SRui Paulo };
238325151a3SRui Paulo 
23939beb93cSSam Leffler struct tls_connection {
2405b9c547cSRui Paulo 	struct tls_context *context;
2414bc52338SCy Schubert 	struct tls_data *data;
2425b9c547cSRui Paulo 	SSL_CTX *ssl_ctx;
24339beb93cSSam Leffler 	SSL *ssl;
24439beb93cSSam Leffler 	BIO *ssl_in, *ssl_out;
245780fb4a2SCy Schubert #if defined(ANDROID) || !defined(OPENSSL_NO_ENGINE)
24639beb93cSSam Leffler 	ENGINE *engine;        /* functional reference to the engine */
24739beb93cSSam Leffler 	EVP_PKEY *private_key; /* the private key if using engine */
24839beb93cSSam Leffler #endif /* OPENSSL_NO_ENGINE */
2495b9c547cSRui Paulo 	char *subject_match, *altsubject_match, *suffix_match, *domain_match;
2504bc52338SCy Schubert 	char *check_cert_subject;
25139beb93cSSam Leffler 	int read_alerts, write_alerts, failed;
25239beb93cSSam Leffler 
25339beb93cSSam Leffler 	tls_session_ticket_cb session_ticket_cb;
25439beb93cSSam Leffler 	void *session_ticket_cb_ctx;
25539beb93cSSam Leffler 
25639beb93cSSam Leffler 	/* SessionTicket received from OpenSSL hello_extension_cb (server) */
25739beb93cSSam Leffler 	u8 *session_ticket;
25839beb93cSSam Leffler 	size_t session_ticket_len;
259e28a4053SRui Paulo 
260e28a4053SRui Paulo 	unsigned int ca_cert_verify:1;
261e28a4053SRui Paulo 	unsigned int cert_probe:1;
262e28a4053SRui Paulo 	unsigned int server_cert_only:1;
2635b9c547cSRui Paulo 	unsigned int invalid_hb_used:1;
264325151a3SRui Paulo 	unsigned int success_data:1;
26585732ac8SCy Schubert 	unsigned int client_hello_generated:1;
26685732ac8SCy Schubert 	unsigned int server:1;
267e28a4053SRui Paulo 
268e28a4053SRui Paulo 	u8 srv_cert_hash[32];
269f05cddf9SRui Paulo 
270f05cddf9SRui Paulo 	unsigned int flags;
2715b9c547cSRui Paulo 
2725b9c547cSRui Paulo 	X509 *peer_cert;
2735b9c547cSRui Paulo 	X509 *peer_issuer;
2745b9c547cSRui Paulo 	X509 *peer_issuer_issuer;
275c1d255d3SCy Schubert 	char *peer_subject; /* peer subject info for authenticated peer */
276325151a3SRui Paulo 
277325151a3SRui Paulo 	unsigned char client_random[SSL3_RANDOM_SIZE];
278325151a3SRui Paulo 	unsigned char server_random[SSL3_RANDOM_SIZE];
27985732ac8SCy Schubert 
28085732ac8SCy Schubert 	u16 cipher_suite;
28185732ac8SCy Schubert 	int server_dh_prime_len;
28239beb93cSSam Leffler };
28339beb93cSSam Leffler 
28439beb93cSSam Leffler 
tls_context_new(const struct tls_config * conf)2855b9c547cSRui Paulo static struct tls_context * tls_context_new(const struct tls_config *conf)
2865b9c547cSRui Paulo {
2875b9c547cSRui Paulo 	struct tls_context *context = os_zalloc(sizeof(*context));
2885b9c547cSRui Paulo 	if (context == NULL)
2895b9c547cSRui Paulo 		return NULL;
290*a90b9d01SCy Schubert 	dl_list_init(&context->sessions);
2915b9c547cSRui Paulo 	if (conf) {
2925b9c547cSRui Paulo 		context->event_cb = conf->event_cb;
2935b9c547cSRui Paulo 		context->cb_ctx = conf->cb_ctx;
2945b9c547cSRui Paulo 		context->cert_in_cb = conf->cert_in_cb;
2955b9c547cSRui Paulo 	}
2965b9c547cSRui Paulo 	return context;
2975b9c547cSRui Paulo }
2985b9c547cSRui Paulo 
2995b9c547cSRui Paulo 
30039beb93cSSam Leffler #ifdef CONFIG_NO_STDOUT_DEBUG
30139beb93cSSam Leffler 
_tls_show_errors(void)30239beb93cSSam Leffler static void _tls_show_errors(void)
30339beb93cSSam Leffler {
30439beb93cSSam Leffler 	unsigned long err;
30539beb93cSSam Leffler 
30639beb93cSSam Leffler 	while ((err = ERR_get_error())) {
30739beb93cSSam Leffler 		/* Just ignore the errors, since stdout is disabled */
30839beb93cSSam Leffler 	}
30939beb93cSSam Leffler }
31039beb93cSSam Leffler #define tls_show_errors(l, f, t) _tls_show_errors()
31139beb93cSSam Leffler 
31239beb93cSSam Leffler #else /* CONFIG_NO_STDOUT_DEBUG */
31339beb93cSSam Leffler 
tls_show_errors(int level,const char * func,const char * txt)31439beb93cSSam Leffler static void tls_show_errors(int level, const char *func, const char *txt)
31539beb93cSSam Leffler {
31639beb93cSSam Leffler 	unsigned long err;
31739beb93cSSam Leffler 
31839beb93cSSam Leffler 	wpa_printf(level, "OpenSSL: %s - %s %s",
31939beb93cSSam Leffler 		   func, txt, ERR_error_string(ERR_get_error(), NULL));
32039beb93cSSam Leffler 
32139beb93cSSam Leffler 	while ((err = ERR_get_error())) {
32239beb93cSSam Leffler 		wpa_printf(MSG_INFO, "OpenSSL: pending error: %s",
32339beb93cSSam Leffler 			   ERR_error_string(err, NULL));
32439beb93cSSam Leffler 	}
32539beb93cSSam Leffler }
32639beb93cSSam Leffler 
32739beb93cSSam Leffler #endif /* CONFIG_NO_STDOUT_DEBUG */
32839beb93cSSam Leffler 
32939beb93cSSam Leffler 
tls_crl_cert_reload(const char * ca_cert,int check_crl)3304bc52338SCy Schubert static X509_STORE * tls_crl_cert_reload(const char *ca_cert, int check_crl)
3314bc52338SCy Schubert {
3324bc52338SCy Schubert 	int flags;
3334bc52338SCy Schubert 	X509_STORE *store;
3344bc52338SCy Schubert 
3354bc52338SCy Schubert 	store = X509_STORE_new();
3364bc52338SCy Schubert 	if (!store) {
3374bc52338SCy Schubert 		wpa_printf(MSG_DEBUG,
3384bc52338SCy Schubert 			   "OpenSSL: %s - failed to allocate new certificate store",
3394bc52338SCy Schubert 			   __func__);
3404bc52338SCy Schubert 		return NULL;
3414bc52338SCy Schubert 	}
3424bc52338SCy Schubert 
3434bc52338SCy Schubert 	if (ca_cert && X509_STORE_load_locations(store, ca_cert, NULL) != 1) {
3444bc52338SCy Schubert 		tls_show_errors(MSG_WARNING, __func__,
3454bc52338SCy Schubert 				"Failed to load root certificates");
3464bc52338SCy Schubert 		X509_STORE_free(store);
3474bc52338SCy Schubert 		return NULL;
3484bc52338SCy Schubert 	}
3494bc52338SCy Schubert 
3504bc52338SCy Schubert 	flags = check_crl ? X509_V_FLAG_CRL_CHECK : 0;
3514bc52338SCy Schubert 	if (check_crl == 2)
3524bc52338SCy Schubert 		flags |= X509_V_FLAG_CRL_CHECK_ALL;
3534bc52338SCy Schubert 
3544bc52338SCy Schubert 	X509_STORE_set_flags(store, flags);
3554bc52338SCy Schubert 
3564bc52338SCy Schubert 	return store;
3574bc52338SCy Schubert }
3584bc52338SCy Schubert 
3594bc52338SCy Schubert 
36039beb93cSSam Leffler #ifdef CONFIG_NATIVE_WINDOWS
36139beb93cSSam Leffler 
36239beb93cSSam Leffler /* Windows CryptoAPI and access to certificate stores */
36339beb93cSSam Leffler #include <wincrypt.h>
36439beb93cSSam Leffler 
36539beb93cSSam Leffler #ifdef __MINGW32_VERSION
36639beb93cSSam Leffler /*
36739beb93cSSam Leffler  * MinGW does not yet include all the needed definitions for CryptoAPI, so
36839beb93cSSam Leffler  * define here whatever extra is needed.
36939beb93cSSam Leffler  */
37039beb93cSSam Leffler #define CERT_SYSTEM_STORE_CURRENT_USER (1 << 16)
37139beb93cSSam Leffler #define CERT_STORE_READONLY_FLAG 0x00008000
37239beb93cSSam Leffler #define CERT_STORE_OPEN_EXISTING_FLAG 0x00004000
37339beb93cSSam Leffler 
37439beb93cSSam Leffler #endif /* __MINGW32_VERSION */
37539beb93cSSam Leffler 
37639beb93cSSam Leffler 
37739beb93cSSam Leffler struct cryptoapi_rsa_data {
37839beb93cSSam Leffler 	const CERT_CONTEXT *cert;
37939beb93cSSam Leffler 	HCRYPTPROV crypt_prov;
38039beb93cSSam Leffler 	DWORD key_spec;
38139beb93cSSam Leffler 	BOOL free_crypt_prov;
38239beb93cSSam Leffler };
38339beb93cSSam Leffler 
38439beb93cSSam Leffler 
cryptoapi_error(const char * msg)38539beb93cSSam Leffler static void cryptoapi_error(const char *msg)
38639beb93cSSam Leffler {
38739beb93cSSam Leffler 	wpa_printf(MSG_INFO, "CryptoAPI: %s; err=%u",
38839beb93cSSam Leffler 		   msg, (unsigned int) GetLastError());
38939beb93cSSam Leffler }
39039beb93cSSam Leffler 
39139beb93cSSam Leffler 
cryptoapi_rsa_pub_enc(int flen,const unsigned char * from,unsigned char * to,RSA * rsa,int padding)39239beb93cSSam Leffler static int cryptoapi_rsa_pub_enc(int flen, const unsigned char *from,
39339beb93cSSam Leffler 				 unsigned char *to, RSA *rsa, int padding)
39439beb93cSSam Leffler {
39539beb93cSSam Leffler 	wpa_printf(MSG_DEBUG, "%s - not implemented", __func__);
39639beb93cSSam Leffler 	return 0;
39739beb93cSSam Leffler }
39839beb93cSSam Leffler 
39939beb93cSSam Leffler 
cryptoapi_rsa_pub_dec(int flen,const unsigned char * from,unsigned char * to,RSA * rsa,int padding)40039beb93cSSam Leffler static int cryptoapi_rsa_pub_dec(int flen, const unsigned char *from,
40139beb93cSSam Leffler 				 unsigned char *to, RSA *rsa, int padding)
40239beb93cSSam Leffler {
40339beb93cSSam Leffler 	wpa_printf(MSG_DEBUG, "%s - not implemented", __func__);
40439beb93cSSam Leffler 	return 0;
40539beb93cSSam Leffler }
40639beb93cSSam Leffler 
40739beb93cSSam Leffler 
cryptoapi_rsa_priv_enc(int flen,const unsigned char * from,unsigned char * to,RSA * rsa,int padding)40839beb93cSSam Leffler static int cryptoapi_rsa_priv_enc(int flen, const unsigned char *from,
40939beb93cSSam Leffler 				  unsigned char *to, RSA *rsa, int padding)
41039beb93cSSam Leffler {
41139beb93cSSam Leffler 	struct cryptoapi_rsa_data *priv =
41239beb93cSSam Leffler 		(struct cryptoapi_rsa_data *) rsa->meth->app_data;
41339beb93cSSam Leffler 	HCRYPTHASH hash;
41439beb93cSSam Leffler 	DWORD hash_size, len, i;
41539beb93cSSam Leffler 	unsigned char *buf = NULL;
41639beb93cSSam Leffler 	int ret = 0;
41739beb93cSSam Leffler 
41839beb93cSSam Leffler 	if (priv == NULL) {
41939beb93cSSam Leffler 		RSAerr(RSA_F_RSA_EAY_PRIVATE_ENCRYPT,
42039beb93cSSam Leffler 		       ERR_R_PASSED_NULL_PARAMETER);
42139beb93cSSam Leffler 		return 0;
42239beb93cSSam Leffler 	}
42339beb93cSSam Leffler 
42439beb93cSSam Leffler 	if (padding != RSA_PKCS1_PADDING) {
42539beb93cSSam Leffler 		RSAerr(RSA_F_RSA_EAY_PRIVATE_ENCRYPT,
42639beb93cSSam Leffler 		       RSA_R_UNKNOWN_PADDING_TYPE);
42739beb93cSSam Leffler 		return 0;
42839beb93cSSam Leffler 	}
42939beb93cSSam Leffler 
43039beb93cSSam Leffler 	if (flen != 16 /* MD5 */ + 20 /* SHA-1 */) {
43139beb93cSSam Leffler 		wpa_printf(MSG_INFO, "%s - only MD5-SHA1 hash supported",
43239beb93cSSam Leffler 			   __func__);
43339beb93cSSam Leffler 		RSAerr(RSA_F_RSA_EAY_PRIVATE_ENCRYPT,
43439beb93cSSam Leffler 		       RSA_R_INVALID_MESSAGE_LENGTH);
43539beb93cSSam Leffler 		return 0;
43639beb93cSSam Leffler 	}
43739beb93cSSam Leffler 
43839beb93cSSam Leffler 	if (!CryptCreateHash(priv->crypt_prov, CALG_SSL3_SHAMD5, 0, 0, &hash))
43939beb93cSSam Leffler 	{
44039beb93cSSam Leffler 		cryptoapi_error("CryptCreateHash failed");
44139beb93cSSam Leffler 		return 0;
44239beb93cSSam Leffler 	}
44339beb93cSSam Leffler 
44439beb93cSSam Leffler 	len = sizeof(hash_size);
44539beb93cSSam Leffler 	if (!CryptGetHashParam(hash, HP_HASHSIZE, (BYTE *) &hash_size, &len,
44639beb93cSSam Leffler 			       0)) {
44739beb93cSSam Leffler 		cryptoapi_error("CryptGetHashParam failed");
44839beb93cSSam Leffler 		goto err;
44939beb93cSSam Leffler 	}
45039beb93cSSam Leffler 
45139beb93cSSam Leffler 	if ((int) hash_size != flen) {
45239beb93cSSam Leffler 		wpa_printf(MSG_INFO, "CryptoAPI: Invalid hash size (%u != %d)",
45339beb93cSSam Leffler 			   (unsigned) hash_size, flen);
45439beb93cSSam Leffler 		RSAerr(RSA_F_RSA_EAY_PRIVATE_ENCRYPT,
45539beb93cSSam Leffler 		       RSA_R_INVALID_MESSAGE_LENGTH);
45639beb93cSSam Leffler 		goto err;
45739beb93cSSam Leffler 	}
45839beb93cSSam Leffler 	if (!CryptSetHashParam(hash, HP_HASHVAL, (BYTE * ) from, 0)) {
45939beb93cSSam Leffler 		cryptoapi_error("CryptSetHashParam failed");
46039beb93cSSam Leffler 		goto err;
46139beb93cSSam Leffler 	}
46239beb93cSSam Leffler 
46339beb93cSSam Leffler 	len = RSA_size(rsa);
46439beb93cSSam Leffler 	buf = os_malloc(len);
46539beb93cSSam Leffler 	if (buf == NULL) {
46639beb93cSSam Leffler 		RSAerr(RSA_F_RSA_EAY_PRIVATE_ENCRYPT, ERR_R_MALLOC_FAILURE);
46739beb93cSSam Leffler 		goto err;
46839beb93cSSam Leffler 	}
46939beb93cSSam Leffler 
47039beb93cSSam Leffler 	if (!CryptSignHash(hash, priv->key_spec, NULL, 0, buf, &len)) {
47139beb93cSSam Leffler 		cryptoapi_error("CryptSignHash failed");
47239beb93cSSam Leffler 		goto err;
47339beb93cSSam Leffler 	}
47439beb93cSSam Leffler 
47539beb93cSSam Leffler 	for (i = 0; i < len; i++)
47639beb93cSSam Leffler 		to[i] = buf[len - i - 1];
47739beb93cSSam Leffler 	ret = len;
47839beb93cSSam Leffler 
47939beb93cSSam Leffler err:
48039beb93cSSam Leffler 	os_free(buf);
48139beb93cSSam Leffler 	CryptDestroyHash(hash);
48239beb93cSSam Leffler 
48339beb93cSSam Leffler 	return ret;
48439beb93cSSam Leffler }
48539beb93cSSam Leffler 
48639beb93cSSam Leffler 
cryptoapi_rsa_priv_dec(int flen,const unsigned char * from,unsigned char * to,RSA * rsa,int padding)48739beb93cSSam Leffler static int cryptoapi_rsa_priv_dec(int flen, const unsigned char *from,
48839beb93cSSam Leffler 				  unsigned char *to, RSA *rsa, int padding)
48939beb93cSSam Leffler {
49039beb93cSSam Leffler 	wpa_printf(MSG_DEBUG, "%s - not implemented", __func__);
49139beb93cSSam Leffler 	return 0;
49239beb93cSSam Leffler }
49339beb93cSSam Leffler 
49439beb93cSSam Leffler 
cryptoapi_free_data(struct cryptoapi_rsa_data * priv)49539beb93cSSam Leffler static void cryptoapi_free_data(struct cryptoapi_rsa_data *priv)
49639beb93cSSam Leffler {
49739beb93cSSam Leffler 	if (priv == NULL)
49839beb93cSSam Leffler 		return;
49939beb93cSSam Leffler 	if (priv->crypt_prov && priv->free_crypt_prov)
50039beb93cSSam Leffler 		CryptReleaseContext(priv->crypt_prov, 0);
50139beb93cSSam Leffler 	if (priv->cert)
50239beb93cSSam Leffler 		CertFreeCertificateContext(priv->cert);
50339beb93cSSam Leffler 	os_free(priv);
50439beb93cSSam Leffler }
50539beb93cSSam Leffler 
50639beb93cSSam Leffler 
cryptoapi_finish(RSA * rsa)50739beb93cSSam Leffler static int cryptoapi_finish(RSA *rsa)
50839beb93cSSam Leffler {
50939beb93cSSam Leffler 	cryptoapi_free_data((struct cryptoapi_rsa_data *) rsa->meth->app_data);
51039beb93cSSam Leffler 	os_free((void *) rsa->meth);
51139beb93cSSam Leffler 	rsa->meth = NULL;
51239beb93cSSam Leffler 	return 1;
51339beb93cSSam Leffler }
51439beb93cSSam Leffler 
51539beb93cSSam Leffler 
cryptoapi_find_cert(const char * name,DWORD store)51639beb93cSSam Leffler static const CERT_CONTEXT * cryptoapi_find_cert(const char *name, DWORD store)
51739beb93cSSam Leffler {
51839beb93cSSam Leffler 	HCERTSTORE cs;
51939beb93cSSam Leffler 	const CERT_CONTEXT *ret = NULL;
52039beb93cSSam Leffler 
52139beb93cSSam Leffler 	cs = CertOpenStore((LPCSTR) CERT_STORE_PROV_SYSTEM, 0, 0,
52239beb93cSSam Leffler 			   store | CERT_STORE_OPEN_EXISTING_FLAG |
52339beb93cSSam Leffler 			   CERT_STORE_READONLY_FLAG, L"MY");
52439beb93cSSam Leffler 	if (cs == NULL) {
52539beb93cSSam Leffler 		cryptoapi_error("Failed to open 'My system store'");
52639beb93cSSam Leffler 		return NULL;
52739beb93cSSam Leffler 	}
52839beb93cSSam Leffler 
52939beb93cSSam Leffler 	if (strncmp(name, "cert://", 7) == 0) {
53039beb93cSSam Leffler 		unsigned short wbuf[255];
53139beb93cSSam Leffler 		MultiByteToWideChar(CP_ACP, 0, name + 7, -1, wbuf, 255);
53239beb93cSSam Leffler 		ret = CertFindCertificateInStore(cs, X509_ASN_ENCODING |
53339beb93cSSam Leffler 						 PKCS_7_ASN_ENCODING,
53439beb93cSSam Leffler 						 0, CERT_FIND_SUBJECT_STR,
53539beb93cSSam Leffler 						 wbuf, NULL);
53639beb93cSSam Leffler 	} else if (strncmp(name, "hash://", 7) == 0) {
53739beb93cSSam Leffler 		CRYPT_HASH_BLOB blob;
53839beb93cSSam Leffler 		int len;
53939beb93cSSam Leffler 		const char *hash = name + 7;
54039beb93cSSam Leffler 		unsigned char *buf;
54139beb93cSSam Leffler 
54239beb93cSSam Leffler 		len = os_strlen(hash) / 2;
54339beb93cSSam Leffler 		buf = os_malloc(len);
54439beb93cSSam Leffler 		if (buf && hexstr2bin(hash, buf, len) == 0) {
54539beb93cSSam Leffler 			blob.cbData = len;
54639beb93cSSam Leffler 			blob.pbData = buf;
54739beb93cSSam Leffler 			ret = CertFindCertificateInStore(cs,
54839beb93cSSam Leffler 							 X509_ASN_ENCODING |
54939beb93cSSam Leffler 							 PKCS_7_ASN_ENCODING,
55039beb93cSSam Leffler 							 0, CERT_FIND_HASH,
55139beb93cSSam Leffler 							 &blob, NULL);
55239beb93cSSam Leffler 		}
55339beb93cSSam Leffler 		os_free(buf);
55439beb93cSSam Leffler 	}
55539beb93cSSam Leffler 
55639beb93cSSam Leffler 	CertCloseStore(cs, 0);
55739beb93cSSam Leffler 
55839beb93cSSam Leffler 	return ret;
55939beb93cSSam Leffler }
56039beb93cSSam Leffler 
56139beb93cSSam Leffler 
tls_cryptoapi_cert(SSL * ssl,const char * name)56239beb93cSSam Leffler static int tls_cryptoapi_cert(SSL *ssl, const char *name)
56339beb93cSSam Leffler {
56439beb93cSSam Leffler 	X509 *cert = NULL;
56539beb93cSSam Leffler 	RSA *rsa = NULL, *pub_rsa;
56639beb93cSSam Leffler 	struct cryptoapi_rsa_data *priv;
56739beb93cSSam Leffler 	RSA_METHOD *rsa_meth;
56839beb93cSSam Leffler 
56939beb93cSSam Leffler 	if (name == NULL ||
57039beb93cSSam Leffler 	    (strncmp(name, "cert://", 7) != 0 &&
57139beb93cSSam Leffler 	     strncmp(name, "hash://", 7) != 0))
57239beb93cSSam Leffler 		return -1;
57339beb93cSSam Leffler 
57439beb93cSSam Leffler 	priv = os_zalloc(sizeof(*priv));
57539beb93cSSam Leffler 	rsa_meth = os_zalloc(sizeof(*rsa_meth));
57639beb93cSSam Leffler 	if (priv == NULL || rsa_meth == NULL) {
57739beb93cSSam Leffler 		wpa_printf(MSG_WARNING, "CryptoAPI: Failed to allocate memory "
57839beb93cSSam Leffler 			   "for CryptoAPI RSA method");
57939beb93cSSam Leffler 		os_free(priv);
58039beb93cSSam Leffler 		os_free(rsa_meth);
58139beb93cSSam Leffler 		return -1;
58239beb93cSSam Leffler 	}
58339beb93cSSam Leffler 
58439beb93cSSam Leffler 	priv->cert = cryptoapi_find_cert(name, CERT_SYSTEM_STORE_CURRENT_USER);
58539beb93cSSam Leffler 	if (priv->cert == NULL) {
58639beb93cSSam Leffler 		priv->cert = cryptoapi_find_cert(
58739beb93cSSam Leffler 			name, CERT_SYSTEM_STORE_LOCAL_MACHINE);
58839beb93cSSam Leffler 	}
58939beb93cSSam Leffler 	if (priv->cert == NULL) {
59039beb93cSSam Leffler 		wpa_printf(MSG_INFO, "CryptoAPI: Could not find certificate "
59139beb93cSSam Leffler 			   "'%s'", name);
59239beb93cSSam Leffler 		goto err;
59339beb93cSSam Leffler 	}
59439beb93cSSam Leffler 
5955b9c547cSRui Paulo 	cert = d2i_X509(NULL,
5965b9c547cSRui Paulo 			(const unsigned char **) &priv->cert->pbCertEncoded,
59739beb93cSSam Leffler 			priv->cert->cbCertEncoded);
59839beb93cSSam Leffler 	if (cert == NULL) {
59939beb93cSSam Leffler 		wpa_printf(MSG_INFO, "CryptoAPI: Could not process X509 DER "
60039beb93cSSam Leffler 			   "encoding");
60139beb93cSSam Leffler 		goto err;
60239beb93cSSam Leffler 	}
60339beb93cSSam Leffler 
60439beb93cSSam Leffler 	if (!CryptAcquireCertificatePrivateKey(priv->cert,
60539beb93cSSam Leffler 					       CRYPT_ACQUIRE_COMPARE_KEY_FLAG,
60639beb93cSSam Leffler 					       NULL, &priv->crypt_prov,
60739beb93cSSam Leffler 					       &priv->key_spec,
60839beb93cSSam Leffler 					       &priv->free_crypt_prov)) {
60939beb93cSSam Leffler 		cryptoapi_error("Failed to acquire a private key for the "
61039beb93cSSam Leffler 				"certificate");
61139beb93cSSam Leffler 		goto err;
61239beb93cSSam Leffler 	}
61339beb93cSSam Leffler 
61439beb93cSSam Leffler 	rsa_meth->name = "Microsoft CryptoAPI RSA Method";
61539beb93cSSam Leffler 	rsa_meth->rsa_pub_enc = cryptoapi_rsa_pub_enc;
61639beb93cSSam Leffler 	rsa_meth->rsa_pub_dec = cryptoapi_rsa_pub_dec;
61739beb93cSSam Leffler 	rsa_meth->rsa_priv_enc = cryptoapi_rsa_priv_enc;
61839beb93cSSam Leffler 	rsa_meth->rsa_priv_dec = cryptoapi_rsa_priv_dec;
61939beb93cSSam Leffler 	rsa_meth->finish = cryptoapi_finish;
62039beb93cSSam Leffler 	rsa_meth->flags = RSA_METHOD_FLAG_NO_CHECK;
62139beb93cSSam Leffler 	rsa_meth->app_data = (char *) priv;
62239beb93cSSam Leffler 
62339beb93cSSam Leffler 	rsa = RSA_new();
62439beb93cSSam Leffler 	if (rsa == NULL) {
62539beb93cSSam Leffler 		SSLerr(SSL_F_SSL_CTX_USE_CERTIFICATE_FILE,
62639beb93cSSam Leffler 		       ERR_R_MALLOC_FAILURE);
62739beb93cSSam Leffler 		goto err;
62839beb93cSSam Leffler 	}
62939beb93cSSam Leffler 
63039beb93cSSam Leffler 	if (!SSL_use_certificate(ssl, cert)) {
63139beb93cSSam Leffler 		RSA_free(rsa);
63239beb93cSSam Leffler 		rsa = NULL;
63339beb93cSSam Leffler 		goto err;
63439beb93cSSam Leffler 	}
63539beb93cSSam Leffler 	pub_rsa = cert->cert_info->key->pkey->pkey.rsa;
63639beb93cSSam Leffler 	X509_free(cert);
63739beb93cSSam Leffler 	cert = NULL;
63839beb93cSSam Leffler 
63939beb93cSSam Leffler 	rsa->n = BN_dup(pub_rsa->n);
64039beb93cSSam Leffler 	rsa->e = BN_dup(pub_rsa->e);
64139beb93cSSam Leffler 	if (!RSA_set_method(rsa, rsa_meth))
64239beb93cSSam Leffler 		goto err;
64339beb93cSSam Leffler 
64439beb93cSSam Leffler 	if (!SSL_use_RSAPrivateKey(ssl, rsa))
64539beb93cSSam Leffler 		goto err;
64639beb93cSSam Leffler 	RSA_free(rsa);
64739beb93cSSam Leffler 
64839beb93cSSam Leffler 	return 0;
64939beb93cSSam Leffler 
65039beb93cSSam Leffler err:
65139beb93cSSam Leffler 	if (cert)
65239beb93cSSam Leffler 		X509_free(cert);
65339beb93cSSam Leffler 	if (rsa)
65439beb93cSSam Leffler 		RSA_free(rsa);
65539beb93cSSam Leffler 	else {
65639beb93cSSam Leffler 		os_free(rsa_meth);
65739beb93cSSam Leffler 		cryptoapi_free_data(priv);
65839beb93cSSam Leffler 	}
65939beb93cSSam Leffler 	return -1;
66039beb93cSSam Leffler }
66139beb93cSSam Leffler 
66239beb93cSSam Leffler 
tls_cryptoapi_ca_cert(SSL_CTX * ssl_ctx,SSL * ssl,const char * name)66339beb93cSSam Leffler static int tls_cryptoapi_ca_cert(SSL_CTX *ssl_ctx, SSL *ssl, const char *name)
66439beb93cSSam Leffler {
66539beb93cSSam Leffler 	HCERTSTORE cs;
66639beb93cSSam Leffler 	PCCERT_CONTEXT ctx = NULL;
66739beb93cSSam Leffler 	X509 *cert;
66839beb93cSSam Leffler 	char buf[128];
66939beb93cSSam Leffler 	const char *store;
67039beb93cSSam Leffler #ifdef UNICODE
67139beb93cSSam Leffler 	WCHAR *wstore;
67239beb93cSSam Leffler #endif /* UNICODE */
67339beb93cSSam Leffler 
67439beb93cSSam Leffler 	if (name == NULL || strncmp(name, "cert_store://", 13) != 0)
67539beb93cSSam Leffler 		return -1;
67639beb93cSSam Leffler 
67739beb93cSSam Leffler 	store = name + 13;
67839beb93cSSam Leffler #ifdef UNICODE
67939beb93cSSam Leffler 	wstore = os_malloc((os_strlen(store) + 1) * sizeof(WCHAR));
68039beb93cSSam Leffler 	if (wstore == NULL)
68139beb93cSSam Leffler 		return -1;
68239beb93cSSam Leffler 	wsprintf(wstore, L"%S", store);
68339beb93cSSam Leffler 	cs = CertOpenSystemStore(0, wstore);
68439beb93cSSam Leffler 	os_free(wstore);
68539beb93cSSam Leffler #else /* UNICODE */
68639beb93cSSam Leffler 	cs = CertOpenSystemStore(0, store);
68739beb93cSSam Leffler #endif /* UNICODE */
68839beb93cSSam Leffler 	if (cs == NULL) {
68939beb93cSSam Leffler 		wpa_printf(MSG_DEBUG, "%s: failed to open system cert store "
69039beb93cSSam Leffler 			   "'%s': error=%d", __func__, store,
69139beb93cSSam Leffler 			   (int) GetLastError());
69239beb93cSSam Leffler 		return -1;
69339beb93cSSam Leffler 	}
69439beb93cSSam Leffler 
69539beb93cSSam Leffler 	while ((ctx = CertEnumCertificatesInStore(cs, ctx))) {
6965b9c547cSRui Paulo 		cert = d2i_X509(NULL,
6975b9c547cSRui Paulo 				(const unsigned char **) &ctx->pbCertEncoded,
69839beb93cSSam Leffler 				ctx->cbCertEncoded);
69939beb93cSSam Leffler 		if (cert == NULL) {
70039beb93cSSam Leffler 			wpa_printf(MSG_INFO, "CryptoAPI: Could not process "
70139beb93cSSam Leffler 				   "X509 DER encoding for CA cert");
70239beb93cSSam Leffler 			continue;
70339beb93cSSam Leffler 		}
70439beb93cSSam Leffler 
70539beb93cSSam Leffler 		X509_NAME_oneline(X509_get_subject_name(cert), buf,
70639beb93cSSam Leffler 				  sizeof(buf));
70739beb93cSSam Leffler 		wpa_printf(MSG_DEBUG, "OpenSSL: Loaded CA certificate for "
70839beb93cSSam Leffler 			   "system certificate store: subject='%s'", buf);
70939beb93cSSam Leffler 
710780fb4a2SCy Schubert 		if (!X509_STORE_add_cert(SSL_CTX_get_cert_store(ssl_ctx),
711780fb4a2SCy Schubert 					 cert)) {
71239beb93cSSam Leffler 			tls_show_errors(MSG_WARNING, __func__,
71339beb93cSSam Leffler 					"Failed to add ca_cert to OpenSSL "
71439beb93cSSam Leffler 					"certificate store");
71539beb93cSSam Leffler 		}
71639beb93cSSam Leffler 
71739beb93cSSam Leffler 		X509_free(cert);
71839beb93cSSam Leffler 	}
71939beb93cSSam Leffler 
72039beb93cSSam Leffler 	if (!CertCloseStore(cs, 0)) {
72139beb93cSSam Leffler 		wpa_printf(MSG_DEBUG, "%s: failed to close system cert store "
72239beb93cSSam Leffler 			   "'%s': error=%d", __func__, name + 13,
72339beb93cSSam Leffler 			   (int) GetLastError());
72439beb93cSSam Leffler 	}
72539beb93cSSam Leffler 
72639beb93cSSam Leffler 	return 0;
72739beb93cSSam Leffler }
72839beb93cSSam Leffler 
72939beb93cSSam Leffler 
73039beb93cSSam Leffler #else /* CONFIG_NATIVE_WINDOWS */
73139beb93cSSam Leffler 
tls_cryptoapi_cert(SSL * ssl,const char * name)73239beb93cSSam Leffler static int tls_cryptoapi_cert(SSL *ssl, const char *name)
73339beb93cSSam Leffler {
73439beb93cSSam Leffler 	return -1;
73539beb93cSSam Leffler }
73639beb93cSSam Leffler 
73739beb93cSSam Leffler #endif /* CONFIG_NATIVE_WINDOWS */
73839beb93cSSam Leffler 
73939beb93cSSam Leffler 
ssl_info_cb(const SSL * ssl,int where,int ret)74039beb93cSSam Leffler static void ssl_info_cb(const SSL *ssl, int where, int ret)
74139beb93cSSam Leffler {
74239beb93cSSam Leffler 	const char *str;
74339beb93cSSam Leffler 	int w;
74439beb93cSSam Leffler 
74539beb93cSSam Leffler 	wpa_printf(MSG_DEBUG, "SSL: (where=0x%x ret=0x%x)", where, ret);
74639beb93cSSam Leffler 	w = where & ~SSL_ST_MASK;
74739beb93cSSam Leffler 	if (w & SSL_ST_CONNECT)
74839beb93cSSam Leffler 		str = "SSL_connect";
74939beb93cSSam Leffler 	else if (w & SSL_ST_ACCEPT)
75039beb93cSSam Leffler 		str = "SSL_accept";
75139beb93cSSam Leffler 	else
75239beb93cSSam Leffler 		str = "undefined";
75339beb93cSSam Leffler 
75439beb93cSSam Leffler 	if (where & SSL_CB_LOOP) {
75539beb93cSSam Leffler 		wpa_printf(MSG_DEBUG, "SSL: %s:%s",
75639beb93cSSam Leffler 			   str, SSL_state_string_long(ssl));
75739beb93cSSam Leffler 	} else if (where & SSL_CB_ALERT) {
7585b9c547cSRui Paulo 		struct tls_connection *conn = SSL_get_app_data((SSL *) ssl);
75939beb93cSSam Leffler 		wpa_printf(MSG_INFO, "SSL: SSL3 alert: %s:%s:%s",
76039beb93cSSam Leffler 			   where & SSL_CB_READ ?
76139beb93cSSam Leffler 			   "read (remote end reported an error)" :
76239beb93cSSam Leffler 			   "write (local SSL3 detected an error)",
76339beb93cSSam Leffler 			   SSL_alert_type_string_long(ret),
76439beb93cSSam Leffler 			   SSL_alert_desc_string_long(ret));
76539beb93cSSam Leffler 		if ((ret >> 8) == SSL3_AL_FATAL) {
76639beb93cSSam Leffler 			if (where & SSL_CB_READ)
76739beb93cSSam Leffler 				conn->read_alerts++;
76839beb93cSSam Leffler 			else
76939beb93cSSam Leffler 				conn->write_alerts++;
77039beb93cSSam Leffler 		}
7715b9c547cSRui Paulo 		if (conn->context->event_cb != NULL) {
772f05cddf9SRui Paulo 			union tls_event_data ev;
7735b9c547cSRui Paulo 			struct tls_context *context = conn->context;
774f05cddf9SRui Paulo 			os_memset(&ev, 0, sizeof(ev));
775f05cddf9SRui Paulo 			ev.alert.is_local = !(where & SSL_CB_READ);
776f05cddf9SRui Paulo 			ev.alert.type = SSL_alert_type_string_long(ret);
777f05cddf9SRui Paulo 			ev.alert.description = SSL_alert_desc_string_long(ret);
7785b9c547cSRui Paulo 			context->event_cb(context->cb_ctx, TLS_ALERT, &ev);
779f05cddf9SRui Paulo 		}
78039beb93cSSam Leffler 	} else if (where & SSL_CB_EXIT && ret <= 0) {
78139beb93cSSam Leffler 		wpa_printf(MSG_DEBUG, "SSL: %s:%s in %s",
78239beb93cSSam Leffler 			   str, ret == 0 ? "failed" : "error",
78339beb93cSSam Leffler 			   SSL_state_string_long(ssl));
78439beb93cSSam Leffler 	}
78539beb93cSSam Leffler }
78639beb93cSSam Leffler 
78739beb93cSSam Leffler 
78839beb93cSSam Leffler #ifndef OPENSSL_NO_ENGINE
78939beb93cSSam Leffler /**
79039beb93cSSam Leffler  * tls_engine_load_dynamic_generic - load any openssl engine
79139beb93cSSam Leffler  * @pre: an array of commands and values that load an engine initialized
79239beb93cSSam Leffler  *       in the engine specific function
79339beb93cSSam Leffler  * @post: an array of commands and values that initialize an already loaded
79439beb93cSSam Leffler  *        engine (or %NULL if not required)
79539beb93cSSam Leffler  * @id: the engine id of the engine to load (only required if post is not %NULL
79639beb93cSSam Leffler  *
79739beb93cSSam Leffler  * This function is a generic function that loads any openssl engine.
79839beb93cSSam Leffler  *
79939beb93cSSam Leffler  * Returns: 0 on success, -1 on failure
80039beb93cSSam Leffler  */
tls_engine_load_dynamic_generic(const char * pre[],const char * post[],const char * id)80139beb93cSSam Leffler static int tls_engine_load_dynamic_generic(const char *pre[],
80239beb93cSSam Leffler 					   const char *post[], const char *id)
80339beb93cSSam Leffler {
80439beb93cSSam Leffler 	ENGINE *engine;
80539beb93cSSam Leffler 	const char *dynamic_id = "dynamic";
80639beb93cSSam Leffler 
80739beb93cSSam Leffler 	engine = ENGINE_by_id(id);
80839beb93cSSam Leffler 	if (engine) {
80939beb93cSSam Leffler 		wpa_printf(MSG_DEBUG, "ENGINE: engine '%s' is already "
81039beb93cSSam Leffler 			   "available", id);
811780fb4a2SCy Schubert 		/*
812780fb4a2SCy Schubert 		 * If it was auto-loaded by ENGINE_by_id() we might still
813780fb4a2SCy Schubert 		 * need to tell it which PKCS#11 module to use in legacy
814780fb4a2SCy Schubert 		 * (non-p11-kit) environments. Do so now; even if it was
815780fb4a2SCy Schubert 		 * properly initialised before, setting it again will be
816780fb4a2SCy Schubert 		 * harmless.
817780fb4a2SCy Schubert 		 */
818780fb4a2SCy Schubert 		goto found;
81939beb93cSSam Leffler 	}
82039beb93cSSam Leffler 	ERR_clear_error();
82139beb93cSSam Leffler 
82239beb93cSSam Leffler 	engine = ENGINE_by_id(dynamic_id);
82339beb93cSSam Leffler 	if (engine == NULL) {
82439beb93cSSam Leffler 		wpa_printf(MSG_INFO, "ENGINE: Can't find engine %s [%s]",
82539beb93cSSam Leffler 			   dynamic_id,
82639beb93cSSam Leffler 			   ERR_error_string(ERR_get_error(), NULL));
82739beb93cSSam Leffler 		return -1;
82839beb93cSSam Leffler 	}
82939beb93cSSam Leffler 
83039beb93cSSam Leffler 	/* Perform the pre commands. This will load the engine. */
83139beb93cSSam Leffler 	while (pre && pre[0]) {
83239beb93cSSam Leffler 		wpa_printf(MSG_DEBUG, "ENGINE: '%s' '%s'", pre[0], pre[1]);
83339beb93cSSam Leffler 		if (ENGINE_ctrl_cmd_string(engine, pre[0], pre[1], 0) == 0) {
83439beb93cSSam Leffler 			wpa_printf(MSG_INFO, "ENGINE: ctrl cmd_string failed: "
83539beb93cSSam Leffler 				   "%s %s [%s]", pre[0], pre[1],
83639beb93cSSam Leffler 				   ERR_error_string(ERR_get_error(), NULL));
83739beb93cSSam Leffler 			ENGINE_free(engine);
83839beb93cSSam Leffler 			return -1;
83939beb93cSSam Leffler 		}
84039beb93cSSam Leffler 		pre += 2;
84139beb93cSSam Leffler 	}
84239beb93cSSam Leffler 
84339beb93cSSam Leffler 	/*
84439beb93cSSam Leffler 	 * Free the reference to the "dynamic" engine. The loaded engine can
84539beb93cSSam Leffler 	 * now be looked up using ENGINE_by_id().
84639beb93cSSam Leffler 	 */
84739beb93cSSam Leffler 	ENGINE_free(engine);
84839beb93cSSam Leffler 
84939beb93cSSam Leffler 	engine = ENGINE_by_id(id);
85039beb93cSSam Leffler 	if (engine == NULL) {
85139beb93cSSam Leffler 		wpa_printf(MSG_INFO, "ENGINE: Can't find engine %s [%s]",
85239beb93cSSam Leffler 			   id, ERR_error_string(ERR_get_error(), NULL));
85339beb93cSSam Leffler 		return -1;
85439beb93cSSam Leffler 	}
855780fb4a2SCy Schubert  found:
85639beb93cSSam Leffler 	while (post && post[0]) {
85739beb93cSSam Leffler 		wpa_printf(MSG_DEBUG, "ENGINE: '%s' '%s'", post[0], post[1]);
85839beb93cSSam Leffler 		if (ENGINE_ctrl_cmd_string(engine, post[0], post[1], 0) == 0) {
85939beb93cSSam Leffler 			wpa_printf(MSG_DEBUG, "ENGINE: ctrl cmd_string failed:"
86039beb93cSSam Leffler 				" %s %s [%s]", post[0], post[1],
86139beb93cSSam Leffler 				   ERR_error_string(ERR_get_error(), NULL));
86239beb93cSSam Leffler 			ENGINE_remove(engine);
86339beb93cSSam Leffler 			ENGINE_free(engine);
86439beb93cSSam Leffler 			return -1;
86539beb93cSSam Leffler 		}
86639beb93cSSam Leffler 		post += 2;
86739beb93cSSam Leffler 	}
86839beb93cSSam Leffler 	ENGINE_free(engine);
86939beb93cSSam Leffler 
87039beb93cSSam Leffler 	return 0;
87139beb93cSSam Leffler }
87239beb93cSSam Leffler 
87339beb93cSSam Leffler 
87439beb93cSSam Leffler /**
87539beb93cSSam Leffler  * tls_engine_load_dynamic_pkcs11 - load the pkcs11 engine provided by opensc
87639beb93cSSam Leffler  * @pkcs11_so_path: pksc11_so_path from the configuration
87739beb93cSSam Leffler  * @pcks11_module_path: pkcs11_module_path from the configuration
87839beb93cSSam Leffler  */
tls_engine_load_dynamic_pkcs11(const char * pkcs11_so_path,const char * pkcs11_module_path)87939beb93cSSam Leffler static int tls_engine_load_dynamic_pkcs11(const char *pkcs11_so_path,
88039beb93cSSam Leffler 					  const char *pkcs11_module_path)
88139beb93cSSam Leffler {
88239beb93cSSam Leffler 	char *engine_id = "pkcs11";
88339beb93cSSam Leffler 	const char *pre_cmd[] = {
88439beb93cSSam Leffler 		"SO_PATH", NULL /* pkcs11_so_path */,
88539beb93cSSam Leffler 		"ID", NULL /* engine_id */,
88639beb93cSSam Leffler 		"LIST_ADD", "1",
88739beb93cSSam Leffler 		/* "NO_VCHECK", "1", */
88839beb93cSSam Leffler 		"LOAD", NULL,
88939beb93cSSam Leffler 		NULL, NULL
89039beb93cSSam Leffler 	};
89139beb93cSSam Leffler 	const char *post_cmd[] = {
89239beb93cSSam Leffler 		"MODULE_PATH", NULL /* pkcs11_module_path */,
89339beb93cSSam Leffler 		NULL, NULL
89439beb93cSSam Leffler 	};
89539beb93cSSam Leffler 
8965b9c547cSRui Paulo 	if (!pkcs11_so_path)
89739beb93cSSam Leffler 		return 0;
89839beb93cSSam Leffler 
89939beb93cSSam Leffler 	pre_cmd[1] = pkcs11_so_path;
90039beb93cSSam Leffler 	pre_cmd[3] = engine_id;
9015b9c547cSRui Paulo 	if (pkcs11_module_path)
90239beb93cSSam Leffler 		post_cmd[1] = pkcs11_module_path;
9035b9c547cSRui Paulo 	else
9045b9c547cSRui Paulo 		post_cmd[0] = NULL;
90539beb93cSSam Leffler 
90639beb93cSSam Leffler 	wpa_printf(MSG_DEBUG, "ENGINE: Loading pkcs11 Engine from %s",
90739beb93cSSam Leffler 		   pkcs11_so_path);
90839beb93cSSam Leffler 
90939beb93cSSam Leffler 	return tls_engine_load_dynamic_generic(pre_cmd, post_cmd, engine_id);
91039beb93cSSam Leffler }
91139beb93cSSam Leffler 
91239beb93cSSam Leffler 
91339beb93cSSam Leffler /**
91439beb93cSSam Leffler  * tls_engine_load_dynamic_opensc - load the opensc engine provided by opensc
91539beb93cSSam Leffler  * @opensc_so_path: opensc_so_path from the configuration
91639beb93cSSam Leffler  */
tls_engine_load_dynamic_opensc(const char * opensc_so_path)91739beb93cSSam Leffler static int tls_engine_load_dynamic_opensc(const char *opensc_so_path)
91839beb93cSSam Leffler {
91939beb93cSSam Leffler 	char *engine_id = "opensc";
92039beb93cSSam Leffler 	const char *pre_cmd[] = {
92139beb93cSSam Leffler 		"SO_PATH", NULL /* opensc_so_path */,
92239beb93cSSam Leffler 		"ID", NULL /* engine_id */,
92339beb93cSSam Leffler 		"LIST_ADD", "1",
92439beb93cSSam Leffler 		"LOAD", NULL,
92539beb93cSSam Leffler 		NULL, NULL
92639beb93cSSam Leffler 	};
92739beb93cSSam Leffler 
92839beb93cSSam Leffler 	if (!opensc_so_path)
92939beb93cSSam Leffler 		return 0;
93039beb93cSSam Leffler 
93139beb93cSSam Leffler 	pre_cmd[1] = opensc_so_path;
93239beb93cSSam Leffler 	pre_cmd[3] = engine_id;
93339beb93cSSam Leffler 
93439beb93cSSam Leffler 	wpa_printf(MSG_DEBUG, "ENGINE: Loading OpenSC Engine from %s",
93539beb93cSSam Leffler 		   opensc_so_path);
93639beb93cSSam Leffler 
93739beb93cSSam Leffler 	return tls_engine_load_dynamic_generic(pre_cmd, NULL, engine_id);
93839beb93cSSam Leffler }
93939beb93cSSam Leffler #endif /* OPENSSL_NO_ENGINE */
94039beb93cSSam Leffler 
94139beb93cSSam Leffler 
get_session_data(struct tls_context * context,const struct wpabuf * buf)942*a90b9d01SCy Schubert static struct tls_session_data * get_session_data(struct tls_context *context,
943*a90b9d01SCy Schubert 						  const struct wpabuf *buf)
944*a90b9d01SCy Schubert {
945*a90b9d01SCy Schubert 	struct tls_session_data *data;
946*a90b9d01SCy Schubert 
947*a90b9d01SCy Schubert 	dl_list_for_each(data, &context->sessions, struct tls_session_data,
948*a90b9d01SCy Schubert 			 list) {
949*a90b9d01SCy Schubert 		if (data->buf == buf)
950*a90b9d01SCy Schubert 			return data;
951*a90b9d01SCy Schubert 	}
952*a90b9d01SCy Schubert 
953*a90b9d01SCy Schubert 	return NULL;
954*a90b9d01SCy Schubert }
955*a90b9d01SCy Schubert 
956*a90b9d01SCy Schubert 
remove_session_cb(SSL_CTX * ctx,SSL_SESSION * sess)957325151a3SRui Paulo static void remove_session_cb(SSL_CTX *ctx, SSL_SESSION *sess)
958325151a3SRui Paulo {
959325151a3SRui Paulo 	struct wpabuf *buf;
960*a90b9d01SCy Schubert 	struct tls_context *context;
961*a90b9d01SCy Schubert 	struct tls_session_data *found;
962*a90b9d01SCy Schubert 
963*a90b9d01SCy Schubert 	wpa_printf(MSG_DEBUG,
964*a90b9d01SCy Schubert 		   "OpenSSL: Remove session %p (tls_ex_idx_session=%d)", sess,
965*a90b9d01SCy Schubert 		   tls_ex_idx_session);
966325151a3SRui Paulo 
967325151a3SRui Paulo 	if (tls_ex_idx_session < 0)
968325151a3SRui Paulo 		return;
969325151a3SRui Paulo 	buf = SSL_SESSION_get_ex_data(sess, tls_ex_idx_session);
970325151a3SRui Paulo 	if (!buf)
971325151a3SRui Paulo 		return;
972*a90b9d01SCy Schubert 
973*a90b9d01SCy Schubert 	context = SSL_CTX_get_app_data(ctx);
974*a90b9d01SCy Schubert 	SSL_SESSION_set_ex_data(sess, tls_ex_idx_session, NULL);
975*a90b9d01SCy Schubert 	found = get_session_data(context, buf);
976*a90b9d01SCy Schubert 	if (!found) {
977*a90b9d01SCy Schubert 		wpa_printf(MSG_DEBUG,
978*a90b9d01SCy Schubert 			   "OpenSSL: Do not free application session data %p (sess %p)",
979*a90b9d01SCy Schubert 			   buf, sess);
980*a90b9d01SCy Schubert 		return;
981*a90b9d01SCy Schubert 	}
982*a90b9d01SCy Schubert 
983*a90b9d01SCy Schubert 	dl_list_del(&found->list);
984*a90b9d01SCy Schubert 	os_free(found);
985325151a3SRui Paulo 	wpa_printf(MSG_DEBUG,
986325151a3SRui Paulo 		   "OpenSSL: Free application session data %p (sess %p)",
987325151a3SRui Paulo 		   buf, sess);
988325151a3SRui Paulo 	wpabuf_free(buf);
989325151a3SRui Paulo }
990325151a3SRui Paulo 
991325151a3SRui Paulo 
tls_init(const struct tls_config * conf)99239beb93cSSam Leffler void * tls_init(const struct tls_config *conf)
99339beb93cSSam Leffler {
994325151a3SRui Paulo 	struct tls_data *data;
99539beb93cSSam Leffler 	SSL_CTX *ssl;
9965b9c547cSRui Paulo 	struct tls_context *context;
9975b9c547cSRui Paulo 	const char *ciphers;
998*a90b9d01SCy Schubert #ifndef OPENSSL_NO_ENGINE
999*a90b9d01SCy Schubert #ifdef CONFIG_OPENSC_ENGINE_PATH
1000*a90b9d01SCy Schubert 	char const * const opensc_engine_path = CONFIG_OPENSC_ENGINE_PATH;
1001*a90b9d01SCy Schubert #else /* CONFIG_OPENSC_ENGINE_PATH */
1002*a90b9d01SCy Schubert 	char const * const opensc_engine_path =
1003*a90b9d01SCy Schubert 		conf ? conf->opensc_engine_path : NULL;
1004*a90b9d01SCy Schubert #endif /* CONFIG_OPENSC_ENGINE_PATH */
1005*a90b9d01SCy Schubert #ifdef CONFIG_PKCS11_ENGINE_PATH
1006*a90b9d01SCy Schubert 	char const * const pkcs11_engine_path = CONFIG_PKCS11_ENGINE_PATH;
1007*a90b9d01SCy Schubert #else /* CONFIG_PKCS11_ENGINE_PATH */
1008*a90b9d01SCy Schubert 	char const * const pkcs11_engine_path =
1009*a90b9d01SCy Schubert 		conf ? conf->pkcs11_engine_path : NULL;
1010*a90b9d01SCy Schubert #endif /* CONFIG_PKCS11_ENGINE_PATH */
1011*a90b9d01SCy Schubert #ifdef CONFIG_PKCS11_MODULE_PATH
1012*a90b9d01SCy Schubert 	char const * const pkcs11_module_path = CONFIG_PKCS11_MODULE_PATH;
1013*a90b9d01SCy Schubert #else /* CONFIG_PKCS11_MODULE_PATH */
1014*a90b9d01SCy Schubert 	char const * const pkcs11_module_path =
1015*a90b9d01SCy Schubert 		conf ? conf->pkcs11_module_path : NULL;
1016*a90b9d01SCy Schubert #endif /* CONFIG_PKCS11_MODULE_PATH */
1017*a90b9d01SCy Schubert #endif /* OPENSSL_NO_ENGINE */
101839beb93cSSam Leffler 
101939beb93cSSam Leffler 	if (tls_openssl_ref_count == 0) {
1020ec080394SCy Schubert 		void openssl_load_legacy_provider(void);
1021ec080394SCy Schubert 
1022ec080394SCy Schubert 		openssl_load_legacy_provider();
1023ec080394SCy Schubert 
10245b9c547cSRui Paulo 		tls_global = context = tls_context_new(conf);
10255b9c547cSRui Paulo 		if (context == NULL)
1026e28a4053SRui Paulo 			return NULL;
1027e28a4053SRui Paulo #ifdef CONFIG_FIPS
1028e28a4053SRui Paulo #ifdef OPENSSL_FIPS
1029e28a4053SRui Paulo 		if (conf && conf->fips_mode) {
1030325151a3SRui Paulo 			static int fips_enabled = 0;
1031325151a3SRui Paulo 
1032325151a3SRui Paulo 			if (!fips_enabled && !FIPS_mode_set(1)) {
1033e28a4053SRui Paulo 				wpa_printf(MSG_ERROR, "Failed to enable FIPS "
1034e28a4053SRui Paulo 					   "mode");
1035e28a4053SRui Paulo 				ERR_load_crypto_strings();
1036e28a4053SRui Paulo 				ERR_print_errors_fp(stderr);
1037f05cddf9SRui Paulo 				os_free(tls_global);
1038f05cddf9SRui Paulo 				tls_global = NULL;
1039e28a4053SRui Paulo 				return NULL;
1040325151a3SRui Paulo 			} else {
1041e28a4053SRui Paulo 				wpa_printf(MSG_INFO, "Running in FIPS mode");
1042325151a3SRui Paulo 				fips_enabled = 1;
1043325151a3SRui Paulo 			}
1044e28a4053SRui Paulo 		}
1045e28a4053SRui Paulo #else /* OPENSSL_FIPS */
1046e28a4053SRui Paulo 		if (conf && conf->fips_mode) {
1047e28a4053SRui Paulo 			wpa_printf(MSG_ERROR, "FIPS mode requested, but not "
1048e28a4053SRui Paulo 				   "supported");
1049f05cddf9SRui Paulo 			os_free(tls_global);
1050f05cddf9SRui Paulo 			tls_global = NULL;
1051e28a4053SRui Paulo 			return NULL;
1052e28a4053SRui Paulo 		}
1053e28a4053SRui Paulo #endif /* OPENSSL_FIPS */
1054e28a4053SRui Paulo #endif /* CONFIG_FIPS */
1055*a90b9d01SCy Schubert #if OPENSSL_VERSION_NUMBER < 0x10100000L
105639beb93cSSam Leffler 		SSL_load_error_strings();
105739beb93cSSam Leffler 		SSL_library_init();
10585b9c547cSRui Paulo #ifndef OPENSSL_NO_SHA256
10593157ba21SRui Paulo 		EVP_add_digest(EVP_sha256());
10603157ba21SRui Paulo #endif /* OPENSSL_NO_SHA256 */
106139beb93cSSam Leffler 		/* TODO: if /dev/urandom is available, PRNG is seeded
106239beb93cSSam Leffler 		 * automatically. If this is not the case, random data should
106339beb93cSSam Leffler 		 * be added here. */
106439beb93cSSam Leffler 
106539beb93cSSam Leffler #ifdef PKCS12_FUNCS
10663157ba21SRui Paulo #ifndef OPENSSL_NO_RC2
10673157ba21SRui Paulo 		/*
10683157ba21SRui Paulo 		 * 40-bit RC2 is commonly used in PKCS#12 files, so enable it.
10693157ba21SRui Paulo 		 * This is enabled by PKCS12_PBE_add() in OpenSSL 0.9.8
10703157ba21SRui Paulo 		 * versions, but it looks like OpenSSL 1.0.0 does not do that
10713157ba21SRui Paulo 		 * anymore.
10723157ba21SRui Paulo 		 */
10733157ba21SRui Paulo 		EVP_add_cipher(EVP_rc2_40_cbc());
10743157ba21SRui Paulo #endif /* OPENSSL_NO_RC2 */
107539beb93cSSam Leffler 		PKCS12_PBE_add();
107639beb93cSSam Leffler #endif  /* PKCS12_FUNCS */
1077780fb4a2SCy Schubert #endif /* < 1.1.0 */
10785b9c547cSRui Paulo 	} else {
10795b9c547cSRui Paulo 		context = tls_context_new(conf);
10805b9c547cSRui Paulo 		if (context == NULL)
10815b9c547cSRui Paulo 			return NULL;
108239beb93cSSam Leffler 	}
108339beb93cSSam Leffler 	tls_openssl_ref_count++;
108439beb93cSSam Leffler 
1085325151a3SRui Paulo 	data = os_zalloc(sizeof(*data));
1086325151a3SRui Paulo 	if (data)
10875b9c547cSRui Paulo 		ssl = SSL_CTX_new(SSLv23_method());
1088325151a3SRui Paulo 	else
1089325151a3SRui Paulo 		ssl = NULL;
10905b9c547cSRui Paulo 	if (ssl == NULL) {
10915b9c547cSRui Paulo 		tls_openssl_ref_count--;
10925b9c547cSRui Paulo 		if (context != tls_global)
10935b9c547cSRui Paulo 			os_free(context);
10945b9c547cSRui Paulo 		if (tls_openssl_ref_count == 0) {
10955b9c547cSRui Paulo 			os_free(tls_global);
10965b9c547cSRui Paulo 			tls_global = NULL;
10975b9c547cSRui Paulo 		}
1098780fb4a2SCy Schubert 		os_free(data);
109939beb93cSSam Leffler 		return NULL;
11005b9c547cSRui Paulo 	}
1101325151a3SRui Paulo 	data->ssl = ssl;
11024bc52338SCy Schubert 	if (conf) {
1103325151a3SRui Paulo 		data->tls_session_lifetime = conf->tls_session_lifetime;
11044bc52338SCy Schubert 		data->crl_reload_interval = conf->crl_reload_interval;
11054bc52338SCy Schubert 	}
11065b9c547cSRui Paulo 
11075b9c547cSRui Paulo 	SSL_CTX_set_options(ssl, SSL_OP_NO_SSLv2);
11085b9c547cSRui Paulo 	SSL_CTX_set_options(ssl, SSL_OP_NO_SSLv3);
110939beb93cSSam Leffler 
1110c1d255d3SCy Schubert 	SSL_CTX_set_mode(ssl, SSL_MODE_AUTO_RETRY);
1111c1d255d3SCy Schubert 
111285732ac8SCy Schubert #ifdef SSL_MODE_NO_AUTO_CHAIN
111385732ac8SCy Schubert 	/* Number of deployed use cases assume the default OpenSSL behavior of
111485732ac8SCy Schubert 	 * auto chaining the local certificate is in use. BoringSSL removed this
111585732ac8SCy Schubert 	 * functionality by default, so we need to restore it here to avoid
111685732ac8SCy Schubert 	 * breaking existing use cases. */
111785732ac8SCy Schubert 	SSL_CTX_clear_mode(ssl, SSL_MODE_NO_AUTO_CHAIN);
111885732ac8SCy Schubert #endif /* SSL_MODE_NO_AUTO_CHAIN */
111985732ac8SCy Schubert 
112039beb93cSSam Leffler 	SSL_CTX_set_info_callback(ssl, ssl_info_cb);
11215b9c547cSRui Paulo 	SSL_CTX_set_app_data(ssl, context);
1122325151a3SRui Paulo 	if (data->tls_session_lifetime > 0) {
1123325151a3SRui Paulo 		SSL_CTX_set_quiet_shutdown(ssl, 1);
1124325151a3SRui Paulo 		/*
1125325151a3SRui Paulo 		 * Set default context here. In practice, this will be replaced
1126325151a3SRui Paulo 		 * by the per-EAP method context in tls_connection_set_verify().
1127325151a3SRui Paulo 		 */
1128325151a3SRui Paulo 		SSL_CTX_set_session_id_context(ssl, (u8 *) "hostapd", 7);
1129325151a3SRui Paulo 		SSL_CTX_set_session_cache_mode(ssl, SSL_SESS_CACHE_SERVER);
1130325151a3SRui Paulo 		SSL_CTX_set_timeout(ssl, data->tls_session_lifetime);
1131325151a3SRui Paulo 		SSL_CTX_sess_set_remove_cb(ssl, remove_session_cb);
1132*a90b9d01SCy Schubert #if OPENSSL_VERSION_NUMBER >= 0x10101000L && \
1133*a90b9d01SCy Schubert 	!defined(LIBRESSL_VERSION_NUMBER) && \
1134*a90b9d01SCy Schubert 	!defined(OPENSSL_IS_BORINGSSL)
1135*a90b9d01SCy Schubert 		/* One session ticket is sufficient for EAP-TLS */
1136*a90b9d01SCy Schubert 		SSL_CTX_set_num_tickets(ssl, 1);
1137*a90b9d01SCy Schubert #endif
1138325151a3SRui Paulo 	} else {
1139325151a3SRui Paulo 		SSL_CTX_set_session_cache_mode(ssl, SSL_SESS_CACHE_OFF);
1140*a90b9d01SCy Schubert #if OPENSSL_VERSION_NUMBER >= 0x10101000L && \
1141*a90b9d01SCy Schubert 	!defined(LIBRESSL_VERSION_NUMBER) && \
1142*a90b9d01SCy Schubert 	!defined(OPENSSL_IS_BORINGSSL)
1143*a90b9d01SCy Schubert 		SSL_CTX_set_num_tickets(ssl, 0);
1144*a90b9d01SCy Schubert #endif
1145325151a3SRui Paulo 	}
1146325151a3SRui Paulo 
1147325151a3SRui Paulo 	if (tls_ex_idx_session < 0) {
1148325151a3SRui Paulo 		tls_ex_idx_session = SSL_SESSION_get_ex_new_index(
1149325151a3SRui Paulo 			0, NULL, NULL, NULL, NULL);
1150325151a3SRui Paulo 		if (tls_ex_idx_session < 0) {
1151325151a3SRui Paulo 			tls_deinit(data);
1152325151a3SRui Paulo 			return NULL;
1153325151a3SRui Paulo 		}
1154325151a3SRui Paulo 	}
115539beb93cSSam Leffler 
115639beb93cSSam Leffler #ifndef OPENSSL_NO_ENGINE
1157206b73d0SCy Schubert 	wpa_printf(MSG_DEBUG, "ENGINE: Loading builtin engines");
1158206b73d0SCy Schubert 	ENGINE_load_builtin_engines();
115939beb93cSSam Leffler 
1160*a90b9d01SCy Schubert 	if (opensc_engine_path || pkcs11_engine_path || pkcs11_module_path) {
1161*a90b9d01SCy Schubert 		if (tls_engine_load_dynamic_opensc(opensc_engine_path) ||
1162*a90b9d01SCy Schubert 		    tls_engine_load_dynamic_pkcs11(pkcs11_engine_path,
1163*a90b9d01SCy Schubert 						   pkcs11_module_path)) {
1164325151a3SRui Paulo 			tls_deinit(data);
116539beb93cSSam Leffler 			return NULL;
116639beb93cSSam Leffler 		}
116739beb93cSSam Leffler 	}
116839beb93cSSam Leffler #endif /* OPENSSL_NO_ENGINE */
116939beb93cSSam Leffler 
11705b9c547cSRui Paulo 	if (conf && conf->openssl_ciphers)
11715b9c547cSRui Paulo 		ciphers = conf->openssl_ciphers;
11725b9c547cSRui Paulo 	else
117385732ac8SCy Schubert 		ciphers = TLS_DEFAULT_CIPHERS;
11745b9c547cSRui Paulo 	if (SSL_CTX_set_cipher_list(ssl, ciphers) != 1) {
11755b9c547cSRui Paulo 		wpa_printf(MSG_ERROR,
11765b9c547cSRui Paulo 			   "OpenSSL: Failed to set cipher string '%s'",
11775b9c547cSRui Paulo 			   ciphers);
1178325151a3SRui Paulo 		tls_deinit(data);
11795b9c547cSRui Paulo 		return NULL;
11805b9c547cSRui Paulo 	}
11815b9c547cSRui Paulo 
1182325151a3SRui Paulo 	return data;
118339beb93cSSam Leffler }
118439beb93cSSam Leffler 
118539beb93cSSam Leffler 
tls_deinit(void * ssl_ctx)118639beb93cSSam Leffler void tls_deinit(void *ssl_ctx)
118739beb93cSSam Leffler {
1188325151a3SRui Paulo 	struct tls_data *data = ssl_ctx;
1189325151a3SRui Paulo 	SSL_CTX *ssl = data->ssl;
11905b9c547cSRui Paulo 	struct tls_context *context = SSL_CTX_get_app_data(ssl);
1191*a90b9d01SCy Schubert 	struct tls_session_data *sess_data;
1192*a90b9d01SCy Schubert 
1193*a90b9d01SCy Schubert 	if (data->tls_session_lifetime > 0) {
1194*a90b9d01SCy Schubert 		wpa_printf(MSG_DEBUG, "OpenSSL: Flush sessions");
1195*a90b9d01SCy Schubert 		SSL_CTX_flush_sessions(ssl, 0);
1196*a90b9d01SCy Schubert 		wpa_printf(MSG_DEBUG, "OpenSSL: Flush sessions - done");
1197*a90b9d01SCy Schubert 	}
1198*a90b9d01SCy Schubert 	while ((sess_data = dl_list_first(&context->sessions,
1199*a90b9d01SCy Schubert 					  struct tls_session_data, list))) {
1200*a90b9d01SCy Schubert 		wpa_printf(MSG_DEBUG,
1201*a90b9d01SCy Schubert 			   "OpenSSL: Freeing not-flushed session data %p",
1202*a90b9d01SCy Schubert 			   sess_data->buf);
1203*a90b9d01SCy Schubert 		wpabuf_free(sess_data->buf);
1204*a90b9d01SCy Schubert 		dl_list_del(&sess_data->list);
1205*a90b9d01SCy Schubert 		os_free(sess_data);
1206*a90b9d01SCy Schubert 	}
12075b9c547cSRui Paulo 	if (context != tls_global)
12085b9c547cSRui Paulo 		os_free(context);
12094bc52338SCy Schubert 	os_free(data->ca_cert);
121039beb93cSSam Leffler 	SSL_CTX_free(ssl);
121139beb93cSSam Leffler 
121239beb93cSSam Leffler 	tls_openssl_ref_count--;
121339beb93cSSam Leffler 	if (tls_openssl_ref_count == 0) {
1214*a90b9d01SCy Schubert #if OPENSSL_VERSION_NUMBER < 0x10100000L
121539beb93cSSam Leffler #ifndef OPENSSL_NO_ENGINE
121639beb93cSSam Leffler 		ENGINE_cleanup();
121739beb93cSSam Leffler #endif /* OPENSSL_NO_ENGINE */
121839beb93cSSam Leffler 		CRYPTO_cleanup_all_ex_data();
12195b9c547cSRui Paulo 		ERR_remove_thread_state(NULL);
122039beb93cSSam Leffler 		ERR_free_strings();
122139beb93cSSam Leffler 		EVP_cleanup();
1222780fb4a2SCy Schubert #endif /* < 1.1.0 */
12235b9c547cSRui Paulo 		os_free(tls_global->ocsp_stapling_response);
12245b9c547cSRui Paulo 		tls_global->ocsp_stapling_response = NULL;
1225e28a4053SRui Paulo 		os_free(tls_global);
1226e28a4053SRui Paulo 		tls_global = NULL;
122739beb93cSSam Leffler 	}
1228325151a3SRui Paulo 
12294bc52338SCy Schubert 	os_free(data->check_cert_subject);
1230*a90b9d01SCy Schubert 	os_free(data->openssl_ciphers);
1231325151a3SRui Paulo 	os_free(data);
123239beb93cSSam Leffler }
123339beb93cSSam Leffler 
123439beb93cSSam Leffler 
1235325151a3SRui Paulo #ifndef OPENSSL_NO_ENGINE
1236325151a3SRui Paulo 
1237325151a3SRui Paulo /* Cryptoki return values */
1238325151a3SRui Paulo #define CKR_PIN_INCORRECT 0x000000a0
1239325151a3SRui Paulo #define CKR_PIN_INVALID 0x000000a1
1240325151a3SRui Paulo #define CKR_PIN_LEN_RANGE 0x000000a2
1241325151a3SRui Paulo 
1242325151a3SRui Paulo /* libp11 */
1243325151a3SRui Paulo #define ERR_LIB_PKCS11	ERR_LIB_USER
1244325151a3SRui Paulo 
tls_is_pin_error(unsigned int err)1245325151a3SRui Paulo static int tls_is_pin_error(unsigned int err)
1246325151a3SRui Paulo {
1247325151a3SRui Paulo 	return ERR_GET_LIB(err) == ERR_LIB_PKCS11 &&
1248325151a3SRui Paulo 		(ERR_GET_REASON(err) == CKR_PIN_INCORRECT ||
1249325151a3SRui Paulo 		 ERR_GET_REASON(err) == CKR_PIN_INVALID ||
1250325151a3SRui Paulo 		 ERR_GET_REASON(err) == CKR_PIN_LEN_RANGE);
1251325151a3SRui Paulo }
1252325151a3SRui Paulo 
1253325151a3SRui Paulo #endif /* OPENSSL_NO_ENGINE */
1254325151a3SRui Paulo 
1255325151a3SRui Paulo 
1256780fb4a2SCy Schubert #ifdef ANDROID
1257780fb4a2SCy Schubert /* EVP_PKEY_from_keystore comes from system/security/keystore-engine. */
1258780fb4a2SCy Schubert EVP_PKEY * EVP_PKEY_from_keystore(const char *key_id);
1259780fb4a2SCy Schubert #endif /* ANDROID */
1260780fb4a2SCy Schubert 
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)126139beb93cSSam Leffler static int tls_engine_init(struct tls_connection *conn, const char *engine_id,
126239beb93cSSam Leffler 			   const char *pin, const char *key_id,
126339beb93cSSam Leffler 			   const char *cert_id, const char *ca_cert_id)
126439beb93cSSam Leffler {
1265780fb4a2SCy Schubert #if defined(ANDROID) && defined(OPENSSL_IS_BORINGSSL)
1266780fb4a2SCy Schubert #if !defined(OPENSSL_NO_ENGINE)
1267780fb4a2SCy Schubert #error "This code depends on OPENSSL_NO_ENGINE being defined by BoringSSL."
1268780fb4a2SCy Schubert #endif
1269780fb4a2SCy Schubert 	if (!key_id)
1270780fb4a2SCy Schubert 		return TLS_SET_PARAMS_ENGINE_PRV_INIT_FAILED;
1271780fb4a2SCy Schubert 	conn->engine = NULL;
1272780fb4a2SCy Schubert 	conn->private_key = EVP_PKEY_from_keystore(key_id);
1273780fb4a2SCy Schubert 	if (!conn->private_key) {
1274780fb4a2SCy Schubert 		wpa_printf(MSG_ERROR,
1275780fb4a2SCy Schubert 			   "ENGINE: cannot load private key with id '%s' [%s]",
1276780fb4a2SCy Schubert 			   key_id,
1277780fb4a2SCy Schubert 			   ERR_error_string(ERR_get_error(), NULL));
1278780fb4a2SCy Schubert 		return TLS_SET_PARAMS_ENGINE_PRV_INIT_FAILED;
1279780fb4a2SCy Schubert 	}
1280780fb4a2SCy Schubert #endif /* ANDROID && OPENSSL_IS_BORINGSSL */
1281780fb4a2SCy Schubert 
128239beb93cSSam Leffler #ifndef OPENSSL_NO_ENGINE
128339beb93cSSam Leffler 	int ret = -1;
128439beb93cSSam Leffler 	if (engine_id == NULL) {
128539beb93cSSam Leffler 		wpa_printf(MSG_ERROR, "ENGINE: Engine ID not set");
128639beb93cSSam Leffler 		return -1;
128739beb93cSSam Leffler 	}
128839beb93cSSam Leffler 
128939beb93cSSam Leffler 	ERR_clear_error();
12905b9c547cSRui Paulo #ifdef ANDROID
12915b9c547cSRui Paulo 	ENGINE_load_dynamic();
12925b9c547cSRui Paulo #endif
129339beb93cSSam Leffler 	conn->engine = ENGINE_by_id(engine_id);
129439beb93cSSam Leffler 	if (!conn->engine) {
129539beb93cSSam Leffler 		wpa_printf(MSG_ERROR, "ENGINE: engine %s not available [%s]",
129639beb93cSSam Leffler 			   engine_id, ERR_error_string(ERR_get_error(), NULL));
129739beb93cSSam Leffler 		goto err;
129839beb93cSSam Leffler 	}
129939beb93cSSam Leffler 	if (ENGINE_init(conn->engine) != 1) {
130039beb93cSSam Leffler 		wpa_printf(MSG_ERROR, "ENGINE: engine init failed "
130139beb93cSSam Leffler 			   "(engine: %s) [%s]", engine_id,
130239beb93cSSam Leffler 			   ERR_error_string(ERR_get_error(), NULL));
130339beb93cSSam Leffler 		goto err;
130439beb93cSSam Leffler 	}
130539beb93cSSam Leffler 	wpa_printf(MSG_DEBUG, "ENGINE: engine initialized");
130639beb93cSSam Leffler 
13075b9c547cSRui Paulo #ifndef ANDROID
13085b9c547cSRui Paulo 	if (pin && ENGINE_ctrl_cmd_string(conn->engine, "PIN", pin, 0) == 0) {
130939beb93cSSam Leffler 		wpa_printf(MSG_ERROR, "ENGINE: cannot set pin [%s]",
131039beb93cSSam Leffler 			   ERR_error_string(ERR_get_error(), NULL));
131139beb93cSSam Leffler 		goto err;
131239beb93cSSam Leffler 	}
13135b9c547cSRui Paulo #endif
13145b9c547cSRui Paulo 	if (key_id) {
13155b9c547cSRui Paulo 		/*
13165b9c547cSRui Paulo 		 * Ensure that the ENGINE does not attempt to use the OpenSSL
13175b9c547cSRui Paulo 		 * UI system to obtain a PIN, if we didn't provide one.
13185b9c547cSRui Paulo 		 */
13195b9c547cSRui Paulo 		struct {
13205b9c547cSRui Paulo 			const void *password;
13215b9c547cSRui Paulo 			const char *prompt_info;
13225b9c547cSRui Paulo 		} key_cb = { "", NULL };
13235b9c547cSRui Paulo 
132439beb93cSSam Leffler 		/* load private key first in-case PIN is required for cert */
132539beb93cSSam Leffler 		conn->private_key = ENGINE_load_private_key(conn->engine,
13265b9c547cSRui Paulo 							    key_id, NULL,
13275b9c547cSRui Paulo 							    &key_cb);
132839beb93cSSam Leffler 		if (!conn->private_key) {
1329325151a3SRui Paulo 			unsigned long err = ERR_get_error();
1330325151a3SRui Paulo 
13315b9c547cSRui Paulo 			wpa_printf(MSG_ERROR,
13325b9c547cSRui Paulo 				   "ENGINE: cannot load private key with id '%s' [%s]",
13335b9c547cSRui Paulo 				   key_id,
1334325151a3SRui Paulo 				   ERR_error_string(err, NULL));
1335325151a3SRui Paulo 			if (tls_is_pin_error(err))
1336325151a3SRui Paulo 				ret = TLS_SET_PARAMS_ENGINE_PRV_BAD_PIN;
1337325151a3SRui Paulo 			else
133839beb93cSSam Leffler 				ret = TLS_SET_PARAMS_ENGINE_PRV_INIT_FAILED;
133939beb93cSSam Leffler 			goto err;
134039beb93cSSam Leffler 		}
13415b9c547cSRui Paulo 	}
134239beb93cSSam Leffler 
134339beb93cSSam Leffler 	/* handle a certificate and/or CA certificate */
134439beb93cSSam Leffler 	if (cert_id || ca_cert_id) {
134539beb93cSSam Leffler 		const char *cmd_name = "LOAD_CERT_CTRL";
134639beb93cSSam Leffler 
134739beb93cSSam Leffler 		/* test if the engine supports a LOAD_CERT_CTRL */
134839beb93cSSam Leffler 		if (!ENGINE_ctrl(conn->engine, ENGINE_CTRL_GET_CMD_FROM_NAME,
134939beb93cSSam Leffler 				 0, (void *)cmd_name, NULL)) {
135039beb93cSSam Leffler 			wpa_printf(MSG_ERROR, "ENGINE: engine does not support"
135139beb93cSSam Leffler 				   " loading certificates");
135239beb93cSSam Leffler 			ret = TLS_SET_PARAMS_ENGINE_PRV_INIT_FAILED;
135339beb93cSSam Leffler 			goto err;
135439beb93cSSam Leffler 		}
135539beb93cSSam Leffler 	}
135639beb93cSSam Leffler 
135739beb93cSSam Leffler 	return 0;
135839beb93cSSam Leffler 
135939beb93cSSam Leffler err:
136039beb93cSSam Leffler 	if (conn->engine) {
136139beb93cSSam Leffler 		ENGINE_free(conn->engine);
136239beb93cSSam Leffler 		conn->engine = NULL;
136339beb93cSSam Leffler 	}
136439beb93cSSam Leffler 
136539beb93cSSam Leffler 	if (conn->private_key) {
136639beb93cSSam Leffler 		EVP_PKEY_free(conn->private_key);
136739beb93cSSam Leffler 		conn->private_key = NULL;
136839beb93cSSam Leffler 	}
136939beb93cSSam Leffler 
137039beb93cSSam Leffler 	return ret;
137139beb93cSSam Leffler #else /* OPENSSL_NO_ENGINE */
137239beb93cSSam Leffler 	return 0;
137339beb93cSSam Leffler #endif /* OPENSSL_NO_ENGINE */
137439beb93cSSam Leffler }
137539beb93cSSam Leffler 
137639beb93cSSam Leffler 
tls_engine_deinit(struct tls_connection * conn)137739beb93cSSam Leffler static void tls_engine_deinit(struct tls_connection *conn)
137839beb93cSSam Leffler {
1379780fb4a2SCy Schubert #if defined(ANDROID) || !defined(OPENSSL_NO_ENGINE)
138039beb93cSSam Leffler 	wpa_printf(MSG_DEBUG, "ENGINE: engine deinit");
138139beb93cSSam Leffler 	if (conn->private_key) {
138239beb93cSSam Leffler 		EVP_PKEY_free(conn->private_key);
138339beb93cSSam Leffler 		conn->private_key = NULL;
138439beb93cSSam Leffler 	}
138539beb93cSSam Leffler 	if (conn->engine) {
1386780fb4a2SCy Schubert #if !defined(OPENSSL_IS_BORINGSSL)
138739beb93cSSam Leffler 		ENGINE_finish(conn->engine);
1388780fb4a2SCy Schubert #endif /* !OPENSSL_IS_BORINGSSL */
138939beb93cSSam Leffler 		conn->engine = NULL;
139039beb93cSSam Leffler 	}
1391780fb4a2SCy Schubert #endif /* ANDROID || !OPENSSL_NO_ENGINE */
139239beb93cSSam Leffler }
139339beb93cSSam Leffler 
139439beb93cSSam Leffler 
tls_get_errors(void * ssl_ctx)139539beb93cSSam Leffler int tls_get_errors(void *ssl_ctx)
139639beb93cSSam Leffler {
139739beb93cSSam Leffler 	int count = 0;
139839beb93cSSam Leffler 	unsigned long err;
139939beb93cSSam Leffler 
140039beb93cSSam Leffler 	while ((err = ERR_get_error())) {
140139beb93cSSam Leffler 		wpa_printf(MSG_INFO, "TLS - SSL error: %s",
140239beb93cSSam Leffler 			   ERR_error_string(err, NULL));
140339beb93cSSam Leffler 		count++;
140439beb93cSSam Leffler 	}
140539beb93cSSam Leffler 
140639beb93cSSam Leffler 	return count;
140739beb93cSSam Leffler }
140839beb93cSSam Leffler 
14095b9c547cSRui Paulo 
openssl_content_type(int content_type)1410780fb4a2SCy Schubert static const char * openssl_content_type(int content_type)
1411780fb4a2SCy Schubert {
1412780fb4a2SCy Schubert 	switch (content_type) {
1413780fb4a2SCy Schubert 	case 20:
1414780fb4a2SCy Schubert 		return "change cipher spec";
1415780fb4a2SCy Schubert 	case 21:
1416780fb4a2SCy Schubert 		return "alert";
1417780fb4a2SCy Schubert 	case 22:
1418780fb4a2SCy Schubert 		return "handshake";
1419780fb4a2SCy Schubert 	case 23:
1420780fb4a2SCy Schubert 		return "application data";
1421780fb4a2SCy Schubert 	case 24:
1422780fb4a2SCy Schubert 		return "heartbeat";
1423780fb4a2SCy Schubert 	case 256:
1424780fb4a2SCy Schubert 		return "TLS header info"; /* pseudo content type */
1425206b73d0SCy Schubert 	case 257:
1426206b73d0SCy Schubert 		return "inner content type"; /* pseudo content type */
1427780fb4a2SCy Schubert 	default:
1428780fb4a2SCy Schubert 		return "?";
1429780fb4a2SCy Schubert 	}
1430780fb4a2SCy Schubert }
1431780fb4a2SCy Schubert 
1432780fb4a2SCy Schubert 
openssl_handshake_type(int content_type,const u8 * buf,size_t len)1433780fb4a2SCy Schubert static const char * openssl_handshake_type(int content_type, const u8 *buf,
1434780fb4a2SCy Schubert 					   size_t len)
1435780fb4a2SCy Schubert {
1436206b73d0SCy Schubert 	if (content_type == 257 && buf && len == 1)
1437206b73d0SCy Schubert 		return openssl_content_type(buf[0]);
1438780fb4a2SCy Schubert 	if (content_type != 22 || !buf || len == 0)
1439780fb4a2SCy Schubert 		return "";
1440780fb4a2SCy Schubert 	switch (buf[0]) {
1441780fb4a2SCy Schubert 	case 0:
1442780fb4a2SCy Schubert 		return "hello request";
1443780fb4a2SCy Schubert 	case 1:
1444780fb4a2SCy Schubert 		return "client hello";
1445780fb4a2SCy Schubert 	case 2:
1446780fb4a2SCy Schubert 		return "server hello";
14474bc52338SCy Schubert 	case 3:
14484bc52338SCy Schubert 		return "hello verify request";
1449780fb4a2SCy Schubert 	case 4:
1450780fb4a2SCy Schubert 		return "new session ticket";
14514bc52338SCy Schubert 	case 5:
14524bc52338SCy Schubert 		return "end of early data";
14534bc52338SCy Schubert 	case 6:
14544bc52338SCy Schubert 		return "hello retry request";
14554bc52338SCy Schubert 	case 8:
14564bc52338SCy Schubert 		return "encrypted extensions";
1457780fb4a2SCy Schubert 	case 11:
1458780fb4a2SCy Schubert 		return "certificate";
1459780fb4a2SCy Schubert 	case 12:
1460780fb4a2SCy Schubert 		return "server key exchange";
1461780fb4a2SCy Schubert 	case 13:
1462780fb4a2SCy Schubert 		return "certificate request";
1463780fb4a2SCy Schubert 	case 14:
1464780fb4a2SCy Schubert 		return "server hello done";
1465780fb4a2SCy Schubert 	case 15:
1466780fb4a2SCy Schubert 		return "certificate verify";
1467780fb4a2SCy Schubert 	case 16:
1468780fb4a2SCy Schubert 		return "client key exchange";
1469780fb4a2SCy Schubert 	case 20:
1470780fb4a2SCy Schubert 		return "finished";
1471780fb4a2SCy Schubert 	case 21:
1472780fb4a2SCy Schubert 		return "certificate url";
1473780fb4a2SCy Schubert 	case 22:
1474780fb4a2SCy Schubert 		return "certificate status";
14754bc52338SCy Schubert 	case 23:
14764bc52338SCy Schubert 		return "supplemental data";
14774bc52338SCy Schubert 	case 24:
14784bc52338SCy Schubert 		return "key update";
14794bc52338SCy Schubert 	case 254:
14804bc52338SCy Schubert 		return "message hash";
1481780fb4a2SCy Schubert 	default:
1482780fb4a2SCy Schubert 		return "?";
1483780fb4a2SCy Schubert 	}
1484780fb4a2SCy Schubert }
1485780fb4a2SCy Schubert 
1486780fb4a2SCy Schubert 
148785732ac8SCy Schubert #ifdef CONFIG_SUITEB
148885732ac8SCy Schubert 
check_server_hello(struct tls_connection * conn,const u8 * pos,const u8 * end)148985732ac8SCy Schubert static void check_server_hello(struct tls_connection *conn,
149085732ac8SCy Schubert 			       const u8 *pos, const u8 *end)
149185732ac8SCy Schubert {
149285732ac8SCy Schubert 	size_t payload_len, id_len;
149385732ac8SCy Schubert 
149485732ac8SCy Schubert 	/*
149585732ac8SCy Schubert 	 * Parse ServerHello to get the selected cipher suite since OpenSSL does
149685732ac8SCy Schubert 	 * not make it cleanly available during handshake and we need to know
149785732ac8SCy Schubert 	 * whether DHE was selected.
149885732ac8SCy Schubert 	 */
149985732ac8SCy Schubert 
150085732ac8SCy Schubert 	if (end - pos < 3)
150185732ac8SCy Schubert 		return;
150285732ac8SCy Schubert 	payload_len = WPA_GET_BE24(pos);
150385732ac8SCy Schubert 	pos += 3;
150485732ac8SCy Schubert 
150585732ac8SCy Schubert 	if ((size_t) (end - pos) < payload_len)
150685732ac8SCy Schubert 		return;
150785732ac8SCy Schubert 	end = pos + payload_len;
150885732ac8SCy Schubert 
150985732ac8SCy Schubert 	/* Skip Version and Random */
151085732ac8SCy Schubert 	if (end - pos < 2 + SSL3_RANDOM_SIZE)
151185732ac8SCy Schubert 		return;
151285732ac8SCy Schubert 	pos += 2 + SSL3_RANDOM_SIZE;
151385732ac8SCy Schubert 
151485732ac8SCy Schubert 	/* Skip Session ID */
151585732ac8SCy Schubert 	if (end - pos < 1)
151685732ac8SCy Schubert 		return;
151785732ac8SCy Schubert 	id_len = *pos++;
151885732ac8SCy Schubert 	if ((size_t) (end - pos) < id_len)
151985732ac8SCy Schubert 		return;
152085732ac8SCy Schubert 	pos += id_len;
152185732ac8SCy Schubert 
152285732ac8SCy Schubert 	if (end - pos < 2)
152385732ac8SCy Schubert 		return;
152485732ac8SCy Schubert 	conn->cipher_suite = WPA_GET_BE16(pos);
152585732ac8SCy Schubert 	wpa_printf(MSG_DEBUG, "OpenSSL: Server selected cipher suite 0x%x",
152685732ac8SCy Schubert 		   conn->cipher_suite);
152785732ac8SCy Schubert }
152885732ac8SCy Schubert 
152985732ac8SCy Schubert 
check_server_key_exchange(SSL * ssl,struct tls_connection * conn,const u8 * pos,const u8 * end)153085732ac8SCy Schubert static void check_server_key_exchange(SSL *ssl, struct tls_connection *conn,
153185732ac8SCy Schubert 				      const u8 *pos, const u8 *end)
153285732ac8SCy Schubert {
153385732ac8SCy Schubert 	size_t payload_len;
153485732ac8SCy Schubert 	u16 dh_len;
153585732ac8SCy Schubert 	BIGNUM *p;
153685732ac8SCy Schubert 	int bits;
153785732ac8SCy Schubert 
153885732ac8SCy Schubert 	if (!(conn->flags & TLS_CONN_SUITEB))
153985732ac8SCy Schubert 		return;
154085732ac8SCy Schubert 
154185732ac8SCy Schubert 	/* DHE is enabled only with DHE-RSA-AES256-GCM-SHA384 */
154285732ac8SCy Schubert 	if (conn->cipher_suite != 0x9f)
154385732ac8SCy Schubert 		return;
154485732ac8SCy Schubert 
154585732ac8SCy Schubert 	if (end - pos < 3)
154685732ac8SCy Schubert 		return;
154785732ac8SCy Schubert 	payload_len = WPA_GET_BE24(pos);
154885732ac8SCy Schubert 	pos += 3;
154985732ac8SCy Schubert 
155085732ac8SCy Schubert 	if ((size_t) (end - pos) < payload_len)
155185732ac8SCy Schubert 		return;
155285732ac8SCy Schubert 	end = pos + payload_len;
155385732ac8SCy Schubert 
155485732ac8SCy Schubert 	if (end - pos < 2)
155585732ac8SCy Schubert 		return;
155685732ac8SCy Schubert 	dh_len = WPA_GET_BE16(pos);
155785732ac8SCy Schubert 	pos += 2;
155885732ac8SCy Schubert 
155985732ac8SCy Schubert 	if ((size_t) (end - pos) < dh_len)
156085732ac8SCy Schubert 		return;
156185732ac8SCy Schubert 	p = BN_bin2bn(pos, dh_len, NULL);
156285732ac8SCy Schubert 	if (!p)
156385732ac8SCy Schubert 		return;
156485732ac8SCy Schubert 
156585732ac8SCy Schubert 	bits = BN_num_bits(p);
156685732ac8SCy Schubert 	BN_free(p);
156785732ac8SCy Schubert 
156885732ac8SCy Schubert 	conn->server_dh_prime_len = bits;
156985732ac8SCy Schubert 	wpa_printf(MSG_DEBUG, "OpenSSL: Server DH prime length: %d bits",
157085732ac8SCy Schubert 		   conn->server_dh_prime_len);
157185732ac8SCy Schubert }
157285732ac8SCy Schubert 
157385732ac8SCy Schubert #endif /* CONFIG_SUITEB */
157485732ac8SCy Schubert 
157585732ac8SCy Schubert 
tls_msg_cb(int write_p,int version,int content_type,const void * buf,size_t len,SSL * ssl,void * arg)15765b9c547cSRui Paulo static void tls_msg_cb(int write_p, int version, int content_type,
15775b9c547cSRui Paulo 		       const void *buf, size_t len, SSL *ssl, void *arg)
15785b9c547cSRui Paulo {
15795b9c547cSRui Paulo 	struct tls_connection *conn = arg;
15805b9c547cSRui Paulo 	const u8 *pos = buf;
15815b9c547cSRui Paulo 
1582*a90b9d01SCy Schubert #if OPENSSL_VERSION_NUMBER >= 0x30000000L
1583*a90b9d01SCy Schubert 	if ((SSL_version(ssl) == TLS1_VERSION ||
1584*a90b9d01SCy Schubert 	     SSL_version(ssl) == TLS1_1_VERSION) &&
1585*a90b9d01SCy Schubert 	    SSL_get_security_level(ssl) > 0) {
1586*a90b9d01SCy Schubert 		wpa_printf(MSG_DEBUG,
1587*a90b9d01SCy Schubert 			   "OpenSSL: Drop security level to 0 to allow TLS 1.0/1.1 use of MD5-SHA1 signature algorithm");
1588*a90b9d01SCy Schubert 		SSL_set_security_level(ssl, 0);
1589*a90b9d01SCy Schubert 	}
1590*a90b9d01SCy Schubert #endif /* OpenSSL version >= 3.0 */
1591780fb4a2SCy Schubert 	if (write_p == 2) {
1592780fb4a2SCy Schubert 		wpa_printf(MSG_DEBUG,
1593780fb4a2SCy Schubert 			   "OpenSSL: session ver=0x%x content_type=%d",
1594780fb4a2SCy Schubert 			   version, content_type);
1595780fb4a2SCy Schubert 		wpa_hexdump_key(MSG_MSGDUMP, "OpenSSL: Data", buf, len);
1596780fb4a2SCy Schubert 		return;
1597780fb4a2SCy Schubert 	}
1598780fb4a2SCy Schubert 
1599780fb4a2SCy Schubert 	wpa_printf(MSG_DEBUG, "OpenSSL: %s ver=0x%x content_type=%d (%s/%s)",
1600780fb4a2SCy Schubert 		   write_p ? "TX" : "RX", version, content_type,
1601780fb4a2SCy Schubert 		   openssl_content_type(content_type),
1602780fb4a2SCy Schubert 		   openssl_handshake_type(content_type, buf, len));
16035b9c547cSRui Paulo 	wpa_hexdump_key(MSG_MSGDUMP, "OpenSSL: Message", buf, len);
16045b9c547cSRui Paulo 	if (content_type == 24 && len >= 3 && pos[0] == 1) {
16055b9c547cSRui Paulo 		size_t payload_len = WPA_GET_BE16(pos + 1);
16065b9c547cSRui Paulo 		if (payload_len + 3 > len) {
16075b9c547cSRui Paulo 			wpa_printf(MSG_ERROR, "OpenSSL: Heartbeat attack detected");
16085b9c547cSRui Paulo 			conn->invalid_hb_used = 1;
16095b9c547cSRui Paulo 		}
16105b9c547cSRui Paulo 	}
161185732ac8SCy Schubert 
161285732ac8SCy Schubert #ifdef CONFIG_SUITEB
161385732ac8SCy Schubert 	/*
161485732ac8SCy Schubert 	 * Need to parse these handshake messages to be able to check DH prime
161585732ac8SCy Schubert 	 * length since OpenSSL does not expose the new cipher suite and DH
161685732ac8SCy Schubert 	 * parameters during handshake (e.g., for cert_cb() callback).
161785732ac8SCy Schubert 	 */
161885732ac8SCy Schubert 	if (content_type == 22 && pos && len > 0 && pos[0] == 2)
161985732ac8SCy Schubert 		check_server_hello(conn, pos + 1, pos + len);
162085732ac8SCy Schubert 	if (content_type == 22 && pos && len > 0 && pos[0] == 12)
162185732ac8SCy Schubert 		check_server_key_exchange(ssl, conn, pos + 1, pos + len);
162285732ac8SCy Schubert #endif /* CONFIG_SUITEB */
16235b9c547cSRui Paulo }
16245b9c547cSRui Paulo 
16255b9c547cSRui Paulo 
1626*a90b9d01SCy Schubert #ifdef CONFIG_TESTING_OPTIONS
1627*a90b9d01SCy Schubert #if OPENSSL_VERSION_NUMBER >= 0x10101000L && !defined(LIBRESSL_VERSION_NUMBER)
1628*a90b9d01SCy Schubert /*
1629*a90b9d01SCy Schubert  * By setting the environment variable SSLKEYLOGFILE to a filename keying
1630*a90b9d01SCy Schubert  * material will be exported that you may use with Wireshark to decode any
1631*a90b9d01SCy Schubert  * TLS flows. Please see the following for more details:
1632*a90b9d01SCy Schubert  *
1633*a90b9d01SCy Schubert  *	https://gitlab.com/wireshark/wireshark/-/wikis/TLS#tls-decryption
1634*a90b9d01SCy Schubert  *
1635*a90b9d01SCy Schubert  * Example logging sessions are (you should delete the file on each run):
1636*a90b9d01SCy Schubert  *
1637*a90b9d01SCy Schubert  *	rm -f /tmp/sslkey.log
1638*a90b9d01SCy Schubert  *	env SSLKEYLOGFILE=/tmp/sslkey.log hostapd ...
1639*a90b9d01SCy Schubert  *
1640*a90b9d01SCy Schubert  *	rm -f /tmp/sslkey.log
1641*a90b9d01SCy Schubert  *	env SSLKEYLOGFILE=/tmp/sslkey.log wpa_supplicant ...
1642*a90b9d01SCy Schubert  *
1643*a90b9d01SCy Schubert  *	rm -f /tmp/sslkey.log
1644*a90b9d01SCy Schubert  *	env SSLKEYLOGFILE=/tmp/sslkey.log eapol_test ...
1645*a90b9d01SCy Schubert  */
tls_keylog_cb(const SSL * ssl,const char * line)1646*a90b9d01SCy Schubert static void tls_keylog_cb(const SSL *ssl, const char *line)
1647*a90b9d01SCy Schubert {
1648*a90b9d01SCy Schubert 	int fd;
1649*a90b9d01SCy Schubert 	const char *filename;
1650*a90b9d01SCy Schubert 	struct iovec iov[2];
1651*a90b9d01SCy Schubert 
1652*a90b9d01SCy Schubert 	filename = getenv("SSLKEYLOGFILE");
1653*a90b9d01SCy Schubert 	if (!filename)
1654*a90b9d01SCy Schubert 		return;
1655*a90b9d01SCy Schubert 
1656*a90b9d01SCy Schubert 	fd = open(filename, O_WRONLY | O_CREAT | O_APPEND, S_IRUSR | S_IWUSR);
1657*a90b9d01SCy Schubert 	if (fd < 0) {
1658*a90b9d01SCy Schubert 		wpa_printf(MSG_ERROR,
1659*a90b9d01SCy Schubert 			   "OpenSSL: Failed to open keylog file %s: %s",
1660*a90b9d01SCy Schubert 			   filename, strerror(errno));
1661*a90b9d01SCy Schubert 		return;
1662*a90b9d01SCy Schubert 	}
1663*a90b9d01SCy Schubert 
1664*a90b9d01SCy Schubert 	/* Assume less than _POSIX_PIPE_BUF (512) where writes are guaranteed
1665*a90b9d01SCy Schubert 	 * to be atomic for O_APPEND. */
1666*a90b9d01SCy Schubert 	iov[0].iov_base = (void *) line;
1667*a90b9d01SCy Schubert 	iov[0].iov_len = os_strlen(line);
1668*a90b9d01SCy Schubert 	iov[1].iov_base = "\n";
1669*a90b9d01SCy Schubert 	iov[1].iov_len = 1;
1670*a90b9d01SCy Schubert 
1671*a90b9d01SCy Schubert 	if (writev(fd, iov, ARRAY_SIZE(iov)) < 01) {
1672*a90b9d01SCy Schubert 		wpa_printf(MSG_DEBUG,
1673*a90b9d01SCy Schubert 			   "OpenSSL: Failed to write to keylog file %s: %s",
1674*a90b9d01SCy Schubert 			   filename, strerror(errno));
1675*a90b9d01SCy Schubert 	}
1676*a90b9d01SCy Schubert 
1677*a90b9d01SCy Schubert 	close(fd);
1678*a90b9d01SCy Schubert }
1679*a90b9d01SCy Schubert #endif
1680*a90b9d01SCy Schubert #endif /* CONFIG_TESTING_OPTIONS */
1681*a90b9d01SCy Schubert 
1682*a90b9d01SCy Schubert 
tls_connection_init(void * ssl_ctx)168339beb93cSSam Leffler struct tls_connection * tls_connection_init(void *ssl_ctx)
168439beb93cSSam Leffler {
1685325151a3SRui Paulo 	struct tls_data *data = ssl_ctx;
1686325151a3SRui Paulo 	SSL_CTX *ssl = data->ssl;
168739beb93cSSam Leffler 	struct tls_connection *conn;
168839beb93cSSam Leffler 	long options;
16894bc52338SCy Schubert 	X509_STORE *new_cert_store;
16904bc52338SCy Schubert 	struct os_reltime now;
16915b9c547cSRui Paulo 	struct tls_context *context = SSL_CTX_get_app_data(ssl);
169239beb93cSSam Leffler 
16934bc52338SCy Schubert 	/* Replace X509 store if it is time to update CRL. */
16944bc52338SCy Schubert 	if (data->crl_reload_interval > 0 && os_get_reltime(&now) == 0 &&
16954bc52338SCy Schubert 	    os_reltime_expired(&now, &data->crl_last_reload,
16964bc52338SCy Schubert 			       data->crl_reload_interval)) {
16974bc52338SCy Schubert 		wpa_printf(MSG_INFO,
16984bc52338SCy Schubert 			   "OpenSSL: Flushing X509 store with ca_cert file");
16994bc52338SCy Schubert 		new_cert_store = tls_crl_cert_reload(data->ca_cert,
17004bc52338SCy Schubert 						     data->check_crl);
17014bc52338SCy Schubert 		if (!new_cert_store) {
17024bc52338SCy Schubert 			wpa_printf(MSG_ERROR,
17034bc52338SCy Schubert 				   "OpenSSL: Error replacing X509 store with ca_cert file");
17044bc52338SCy Schubert 		} else {
17054bc52338SCy Schubert 			/* Replace old store */
17064bc52338SCy Schubert 			SSL_CTX_set_cert_store(ssl, new_cert_store);
17074bc52338SCy Schubert 			data->crl_last_reload = now;
17084bc52338SCy Schubert 		}
17094bc52338SCy Schubert 	}
17104bc52338SCy Schubert 
171139beb93cSSam Leffler 	conn = os_zalloc(sizeof(*conn));
171239beb93cSSam Leffler 	if (conn == NULL)
171339beb93cSSam Leffler 		return NULL;
17144bc52338SCy Schubert 	conn->data = data;
1715325151a3SRui Paulo 	conn->ssl_ctx = ssl;
171639beb93cSSam Leffler 	conn->ssl = SSL_new(ssl);
171739beb93cSSam Leffler 	if (conn->ssl == NULL) {
171839beb93cSSam Leffler 		tls_show_errors(MSG_INFO, __func__,
171939beb93cSSam Leffler 				"Failed to initialize new SSL connection");
172039beb93cSSam Leffler 		os_free(conn);
172139beb93cSSam Leffler 		return NULL;
172239beb93cSSam Leffler 	}
172339beb93cSSam Leffler 
17245b9c547cSRui Paulo 	conn->context = context;
172539beb93cSSam Leffler 	SSL_set_app_data(conn->ssl, conn);
17265b9c547cSRui Paulo 	SSL_set_msg_callback(conn->ssl, tls_msg_cb);
17275b9c547cSRui Paulo 	SSL_set_msg_callback_arg(conn->ssl, conn);
172839beb93cSSam Leffler 	options = SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3 |
172939beb93cSSam Leffler 		SSL_OP_SINGLE_DH_USE;
173039beb93cSSam Leffler #ifdef SSL_OP_NO_COMPRESSION
173139beb93cSSam Leffler 	options |= SSL_OP_NO_COMPRESSION;
173239beb93cSSam Leffler #endif /* SSL_OP_NO_COMPRESSION */
173339beb93cSSam Leffler 	SSL_set_options(conn->ssl, options);
1734206b73d0SCy Schubert #ifdef SSL_OP_ENABLE_MIDDLEBOX_COMPAT
1735206b73d0SCy Schubert 	/* Hopefully there is no need for middlebox compatibility mechanisms
1736206b73d0SCy Schubert 	 * when going through EAP authentication. */
1737206b73d0SCy Schubert 	SSL_clear_options(conn->ssl, SSL_OP_ENABLE_MIDDLEBOX_COMPAT);
1738206b73d0SCy Schubert #endif
173939beb93cSSam Leffler 
1740*a90b9d01SCy Schubert #ifdef CONFIG_TESTING_OPTIONS
1741*a90b9d01SCy Schubert #if OPENSSL_VERSION_NUMBER >= 0x10101000L && !defined(LIBRESSL_VERSION_NUMBER)
1742*a90b9d01SCy Schubert 	/* Set the keylog file if the admin requested it. */
1743*a90b9d01SCy Schubert 	if (getenv("SSLKEYLOGFILE"))
1744*a90b9d01SCy Schubert 		SSL_CTX_set_keylog_callback(conn->ssl_ctx, tls_keylog_cb);
1745*a90b9d01SCy Schubert #endif
1746*a90b9d01SCy Schubert #endif /* CONFIG_TESTING_OPTIONS */
1747*a90b9d01SCy Schubert 
174839beb93cSSam Leffler 	conn->ssl_in = BIO_new(BIO_s_mem());
174939beb93cSSam Leffler 	if (!conn->ssl_in) {
175039beb93cSSam Leffler 		tls_show_errors(MSG_INFO, __func__,
175139beb93cSSam Leffler 				"Failed to create a new BIO for ssl_in");
175239beb93cSSam Leffler 		SSL_free(conn->ssl);
175339beb93cSSam Leffler 		os_free(conn);
175439beb93cSSam Leffler 		return NULL;
175539beb93cSSam Leffler 	}
175639beb93cSSam Leffler 
175739beb93cSSam Leffler 	conn->ssl_out = BIO_new(BIO_s_mem());
175839beb93cSSam Leffler 	if (!conn->ssl_out) {
175939beb93cSSam Leffler 		tls_show_errors(MSG_INFO, __func__,
176039beb93cSSam Leffler 				"Failed to create a new BIO for ssl_out");
176139beb93cSSam Leffler 		SSL_free(conn->ssl);
176239beb93cSSam Leffler 		BIO_free(conn->ssl_in);
176339beb93cSSam Leffler 		os_free(conn);
176439beb93cSSam Leffler 		return NULL;
176539beb93cSSam Leffler 	}
176639beb93cSSam Leffler 
176739beb93cSSam Leffler 	SSL_set_bio(conn->ssl, conn->ssl_in, conn->ssl_out);
176839beb93cSSam Leffler 
176939beb93cSSam Leffler 	return conn;
177039beb93cSSam Leffler }
177139beb93cSSam Leffler 
177239beb93cSSam Leffler 
tls_connection_deinit(void * ssl_ctx,struct tls_connection * conn)177339beb93cSSam Leffler void tls_connection_deinit(void *ssl_ctx, struct tls_connection *conn)
177439beb93cSSam Leffler {
177539beb93cSSam Leffler 	if (conn == NULL)
177639beb93cSSam Leffler 		return;
1777325151a3SRui Paulo 	if (conn->success_data) {
1778325151a3SRui Paulo 		/*
1779325151a3SRui Paulo 		 * Make sure ssl_clear_bad_session() does not remove this
1780325151a3SRui Paulo 		 * session.
1781325151a3SRui Paulo 		 */
1782325151a3SRui Paulo 		SSL_set_quiet_shutdown(conn->ssl, 1);
1783325151a3SRui Paulo 		SSL_shutdown(conn->ssl);
1784325151a3SRui Paulo 	}
178539beb93cSSam Leffler 	SSL_free(conn->ssl);
178639beb93cSSam Leffler 	tls_engine_deinit(conn);
178739beb93cSSam Leffler 	os_free(conn->subject_match);
178839beb93cSSam Leffler 	os_free(conn->altsubject_match);
17895b9c547cSRui Paulo 	os_free(conn->suffix_match);
17905b9c547cSRui Paulo 	os_free(conn->domain_match);
17914bc52338SCy Schubert 	os_free(conn->check_cert_subject);
179239beb93cSSam Leffler 	os_free(conn->session_ticket);
1793c1d255d3SCy Schubert 	os_free(conn->peer_subject);
179439beb93cSSam Leffler 	os_free(conn);
179539beb93cSSam Leffler }
179639beb93cSSam Leffler 
179739beb93cSSam Leffler 
tls_connection_established(void * ssl_ctx,struct tls_connection * conn)179839beb93cSSam Leffler int tls_connection_established(void *ssl_ctx, struct tls_connection *conn)
179939beb93cSSam Leffler {
180039beb93cSSam Leffler 	return conn ? SSL_is_init_finished(conn->ssl) : 0;
180139beb93cSSam Leffler }
180239beb93cSSam Leffler 
180339beb93cSSam Leffler 
tls_connection_peer_serial_num(void * tls_ctx,struct tls_connection * conn)180485732ac8SCy Schubert char * tls_connection_peer_serial_num(void *tls_ctx,
180585732ac8SCy Schubert 				      struct tls_connection *conn)
180685732ac8SCy Schubert {
180785732ac8SCy Schubert 	ASN1_INTEGER *ser;
180885732ac8SCy Schubert 	char *serial_num;
180985732ac8SCy Schubert 	size_t len;
181085732ac8SCy Schubert 
181185732ac8SCy Schubert 	if (!conn->peer_cert)
181285732ac8SCy Schubert 		return NULL;
181385732ac8SCy Schubert 
181485732ac8SCy Schubert 	ser = X509_get_serialNumber(conn->peer_cert);
181585732ac8SCy Schubert 	if (!ser)
181685732ac8SCy Schubert 		return NULL;
181785732ac8SCy Schubert 
181885732ac8SCy Schubert 	len = ASN1_STRING_length(ser) * 2 + 1;
181985732ac8SCy Schubert 	serial_num = os_malloc(len);
182085732ac8SCy Schubert 	if (!serial_num)
182185732ac8SCy Schubert 		return NULL;
182285732ac8SCy Schubert 	wpa_snprintf_hex_uppercase(serial_num, len,
182385732ac8SCy Schubert 				   ASN1_STRING_get0_data(ser),
182485732ac8SCy Schubert 				   ASN1_STRING_length(ser));
182585732ac8SCy Schubert 	return serial_num;
182685732ac8SCy Schubert }
182785732ac8SCy Schubert 
182885732ac8SCy Schubert 
tls_connection_shutdown(void * ssl_ctx,struct tls_connection * conn)182939beb93cSSam Leffler int tls_connection_shutdown(void *ssl_ctx, struct tls_connection *conn)
183039beb93cSSam Leffler {
183139beb93cSSam Leffler 	if (conn == NULL)
183239beb93cSSam Leffler 		return -1;
183339beb93cSSam Leffler 
183439beb93cSSam Leffler 	/* Shutdown previous TLS connection without notifying the peer
183539beb93cSSam Leffler 	 * because the connection was already terminated in practice
183639beb93cSSam Leffler 	 * and "close notify" shutdown alert would confuse AS. */
183739beb93cSSam Leffler 	SSL_set_quiet_shutdown(conn->ssl, 1);
183839beb93cSSam Leffler 	SSL_shutdown(conn->ssl);
1839325151a3SRui Paulo 	return SSL_clear(conn->ssl) == 1 ? 0 : -1;
184039beb93cSSam Leffler }
184139beb93cSSam Leffler 
184239beb93cSSam Leffler 
tls_match_altsubject_component(X509 * cert,int type,const char * value,size_t len)184339beb93cSSam Leffler static int tls_match_altsubject_component(X509 *cert, int type,
184439beb93cSSam Leffler 					  const char *value, size_t len)
184539beb93cSSam Leffler {
184639beb93cSSam Leffler 	GENERAL_NAME *gen;
184739beb93cSSam Leffler 	void *ext;
18485b9c547cSRui Paulo 	int found = 0;
18495b9c547cSRui Paulo 	stack_index_t i;
185039beb93cSSam Leffler 
185139beb93cSSam Leffler 	ext = X509_get_ext_d2i(cert, NID_subject_alt_name, NULL, NULL);
185239beb93cSSam Leffler 
185339beb93cSSam Leffler 	for (i = 0; ext && i < sk_GENERAL_NAME_num(ext); i++) {
185439beb93cSSam Leffler 		gen = sk_GENERAL_NAME_value(ext, i);
185539beb93cSSam Leffler 		if (gen->type != type)
185639beb93cSSam Leffler 			continue;
185739beb93cSSam Leffler 		if (os_strlen((char *) gen->d.ia5->data) == len &&
185839beb93cSSam Leffler 		    os_memcmp(value, gen->d.ia5->data, len) == 0)
185939beb93cSSam Leffler 			found++;
186039beb93cSSam Leffler 	}
186139beb93cSSam Leffler 
1862780fb4a2SCy Schubert 	sk_GENERAL_NAME_pop_free(ext, GENERAL_NAME_free);
1863780fb4a2SCy Schubert 
186439beb93cSSam Leffler 	return found;
186539beb93cSSam Leffler }
186639beb93cSSam Leffler 
186739beb93cSSam Leffler 
tls_match_altsubject(X509 * cert,const char * match)186839beb93cSSam Leffler static int tls_match_altsubject(X509 *cert, const char *match)
186939beb93cSSam Leffler {
187039beb93cSSam Leffler 	int type;
187139beb93cSSam Leffler 	const char *pos, *end;
187239beb93cSSam Leffler 	size_t len;
187339beb93cSSam Leffler 
187439beb93cSSam Leffler 	pos = match;
187539beb93cSSam Leffler 	do {
187639beb93cSSam Leffler 		if (os_strncmp(pos, "EMAIL:", 6) == 0) {
187739beb93cSSam Leffler 			type = GEN_EMAIL;
187839beb93cSSam Leffler 			pos += 6;
187939beb93cSSam Leffler 		} else if (os_strncmp(pos, "DNS:", 4) == 0) {
188039beb93cSSam Leffler 			type = GEN_DNS;
188139beb93cSSam Leffler 			pos += 4;
188239beb93cSSam Leffler 		} else if (os_strncmp(pos, "URI:", 4) == 0) {
188339beb93cSSam Leffler 			type = GEN_URI;
188439beb93cSSam Leffler 			pos += 4;
188539beb93cSSam Leffler 		} else {
188639beb93cSSam Leffler 			wpa_printf(MSG_INFO, "TLS: Invalid altSubjectName "
188739beb93cSSam Leffler 				   "match '%s'", pos);
188839beb93cSSam Leffler 			return 0;
188939beb93cSSam Leffler 		}
189039beb93cSSam Leffler 		end = os_strchr(pos, ';');
189139beb93cSSam Leffler 		while (end) {
189239beb93cSSam Leffler 			if (os_strncmp(end + 1, "EMAIL:", 6) == 0 ||
189339beb93cSSam Leffler 			    os_strncmp(end + 1, "DNS:", 4) == 0 ||
189439beb93cSSam Leffler 			    os_strncmp(end + 1, "URI:", 4) == 0)
189539beb93cSSam Leffler 				break;
189639beb93cSSam Leffler 			end = os_strchr(end + 1, ';');
189739beb93cSSam Leffler 		}
189839beb93cSSam Leffler 		if (end)
189939beb93cSSam Leffler 			len = end - pos;
190039beb93cSSam Leffler 		else
190139beb93cSSam Leffler 			len = os_strlen(pos);
190239beb93cSSam Leffler 		if (tls_match_altsubject_component(cert, type, pos, len) > 0)
190339beb93cSSam Leffler 			return 1;
190439beb93cSSam Leffler 		pos = end + 1;
190539beb93cSSam Leffler 	} while (end);
190639beb93cSSam Leffler 
190739beb93cSSam Leffler 	return 0;
190839beb93cSSam Leffler }
190939beb93cSSam Leffler 
191039beb93cSSam Leffler 
19115b9c547cSRui Paulo #ifndef CONFIG_NATIVE_WINDOWS
domain_suffix_match(const u8 * val,size_t len,const char * match,size_t match_len,int full)19125b9c547cSRui Paulo static int domain_suffix_match(const u8 *val, size_t len, const char *match,
19134bc52338SCy Schubert 			       size_t match_len, int full)
19145b9c547cSRui Paulo {
19154bc52338SCy Schubert 	size_t i;
19165b9c547cSRui Paulo 
19175b9c547cSRui Paulo 	/* Check for embedded nuls that could mess up suffix matching */
19185b9c547cSRui Paulo 	for (i = 0; i < len; i++) {
19195b9c547cSRui Paulo 		if (val[i] == '\0') {
19205b9c547cSRui Paulo 			wpa_printf(MSG_DEBUG, "TLS: Embedded null in a string - reject");
19215b9c547cSRui Paulo 			return 0;
19225b9c547cSRui Paulo 		}
19235b9c547cSRui Paulo 	}
19245b9c547cSRui Paulo 
19255b9c547cSRui Paulo 	if (match_len > len || (full && match_len != len))
19265b9c547cSRui Paulo 		return 0;
19275b9c547cSRui Paulo 
19285b9c547cSRui Paulo 	if (os_strncasecmp((const char *) val + len - match_len, match,
19295b9c547cSRui Paulo 			   match_len) != 0)
19305b9c547cSRui Paulo 		return 0; /* no match */
19315b9c547cSRui Paulo 
19325b9c547cSRui Paulo 	if (match_len == len)
19335b9c547cSRui Paulo 		return 1; /* exact match */
19345b9c547cSRui Paulo 
19355b9c547cSRui Paulo 	if (val[len - match_len - 1] == '.')
19365b9c547cSRui Paulo 		return 1; /* full label match completes suffix match */
19375b9c547cSRui Paulo 
19385b9c547cSRui Paulo 	wpa_printf(MSG_DEBUG, "TLS: Reject due to incomplete label match");
19395b9c547cSRui Paulo 	return 0;
19405b9c547cSRui Paulo }
19415b9c547cSRui Paulo #endif /* CONFIG_NATIVE_WINDOWS */
19425b9c547cSRui Paulo 
19435b9c547cSRui Paulo 
19444bc52338SCy Schubert struct tls_dn_field_order_cnt {
19454bc52338SCy Schubert 	u8 cn;
19464bc52338SCy Schubert 	u8 c;
19474bc52338SCy Schubert 	u8 l;
19484bc52338SCy Schubert 	u8 st;
19494bc52338SCy Schubert 	u8 o;
19504bc52338SCy Schubert 	u8 ou;
19514bc52338SCy Schubert 	u8 email;
19524bc52338SCy Schubert };
19534bc52338SCy Schubert 
19544bc52338SCy Schubert 
get_dn_field_index(const struct tls_dn_field_order_cnt * dn_cnt,int nid)19554bc52338SCy Schubert static int get_dn_field_index(const struct tls_dn_field_order_cnt *dn_cnt,
19564bc52338SCy Schubert 			      int nid)
19575b9c547cSRui Paulo {
19584bc52338SCy Schubert 	switch (nid) {
19594bc52338SCy Schubert 	case NID_commonName:
19604bc52338SCy Schubert 		return dn_cnt->cn;
19614bc52338SCy Schubert 	case NID_countryName:
19624bc52338SCy Schubert 		return dn_cnt->c;
19634bc52338SCy Schubert 	case NID_localityName:
19644bc52338SCy Schubert 		return dn_cnt->l;
19654bc52338SCy Schubert 	case NID_stateOrProvinceName:
19664bc52338SCy Schubert 		return dn_cnt->st;
19674bc52338SCy Schubert 	case NID_organizationName:
19684bc52338SCy Schubert 		return dn_cnt->o;
19694bc52338SCy Schubert 	case NID_organizationalUnitName:
19704bc52338SCy Schubert 		return dn_cnt->ou;
19714bc52338SCy Schubert 	case NID_pkcs9_emailAddress:
19724bc52338SCy Schubert 		return dn_cnt->email;
19734bc52338SCy Schubert 	default:
19744bc52338SCy Schubert 		wpa_printf(MSG_ERROR,
19754bc52338SCy Schubert 			   "TLS: Unknown NID '%d' in check_cert_subject",
19764bc52338SCy Schubert 			   nid);
19775b9c547cSRui Paulo 		return -1;
19784bc52338SCy Schubert 	}
19794bc52338SCy Schubert }
19804bc52338SCy Schubert 
19814bc52338SCy Schubert 
19824bc52338SCy Schubert /**
19834bc52338SCy Schubert  * match_dn_field - Match configuration DN field against Certificate DN field
19844bc52338SCy Schubert  * @cert: Certificate
19854bc52338SCy Schubert  * @nid: NID of DN field
19864bc52338SCy Schubert  * @field: Field name
19874bc52338SCy Schubert  * @value DN field value which is passed from configuration
19884bc52338SCy Schubert  *	e.g., if configuration have C=US and this argument will point to US.
19894bc52338SCy Schubert  * @dn_cnt: DN matching context
19904bc52338SCy Schubert  * Returns: 1 on success and 0 on failure
19914bc52338SCy Schubert  */
match_dn_field(const X509 * cert,int nid,const char * field,const char * value,const struct tls_dn_field_order_cnt * dn_cnt)19924bc52338SCy Schubert static int match_dn_field(const X509 *cert, int nid, const char *field,
19934bc52338SCy Schubert 			  const char *value,
19944bc52338SCy Schubert 			  const struct tls_dn_field_order_cnt *dn_cnt)
19954bc52338SCy Schubert {
19964bc52338SCy Schubert 	int i, ret = 0, len, config_dn_field_index, match_index = 0;
19974bc52338SCy Schubert 	X509_NAME *name;
19984bc52338SCy Schubert 
19994bc52338SCy Schubert 	len = os_strlen(value);
20004bc52338SCy Schubert 	name = X509_get_subject_name((X509 *) cert);
20014bc52338SCy Schubert 
20024bc52338SCy Schubert 	/* Assign incremented cnt for every field of DN to check DN field in
20034bc52338SCy Schubert 	 * right order */
20044bc52338SCy Schubert 	config_dn_field_index = get_dn_field_index(dn_cnt, nid);
20054bc52338SCy Schubert 	if (config_dn_field_index < 0)
20064bc52338SCy Schubert 		return 0;
20074bc52338SCy Schubert 
20084bc52338SCy Schubert 	/* Fetch value based on NID */
20094bc52338SCy Schubert 	for (i = -1; (i = X509_NAME_get_index_by_NID(name, nid, i)) > -1;) {
20104bc52338SCy Schubert 		X509_NAME_ENTRY *e;
20114bc52338SCy Schubert 		ASN1_STRING *cn;
20124bc52338SCy Schubert 
20134bc52338SCy Schubert 		e = X509_NAME_get_entry(name, i);
20144bc52338SCy Schubert 		if (!e)
20154bc52338SCy Schubert 			continue;
20164bc52338SCy Schubert 
20174bc52338SCy Schubert 		cn = X509_NAME_ENTRY_get_data(e);
20184bc52338SCy Schubert 		if (!cn)
20194bc52338SCy Schubert 			continue;
20204bc52338SCy Schubert 
20214bc52338SCy Schubert 		match_index++;
20224bc52338SCy Schubert 
20234bc52338SCy Schubert 		/* check for more than one DN field with same name */
20244bc52338SCy Schubert 		if (match_index != config_dn_field_index)
20254bc52338SCy Schubert 			continue;
20264bc52338SCy Schubert 
20274bc52338SCy Schubert 		/* Check wildcard at the right end side */
20284bc52338SCy Schubert 		/* E.g., if OU=develop* mentioned in configuration, allow 'OU'
20294bc52338SCy Schubert 		 * of the subject in the client certificate to start with
20304bc52338SCy Schubert 		 * 'develop' */
20314bc52338SCy Schubert 		if (len > 0 && value[len - 1] == '*') {
20324bc52338SCy Schubert 			/* Compare actual certificate DN field value with
20334bc52338SCy Schubert 			 * configuration DN field value up to the specified
20344bc52338SCy Schubert 			 * length. */
20354bc52338SCy Schubert 			ret = ASN1_STRING_length(cn) >= len - 1 &&
20364bc52338SCy Schubert 				os_memcmp(ASN1_STRING_get0_data(cn), value,
20374bc52338SCy Schubert 					  len - 1) == 0;
20384bc52338SCy Schubert 		} else {
20394bc52338SCy Schubert 			/* Compare actual certificate DN field value with
20404bc52338SCy Schubert 			 * configuration DN field value */
20414bc52338SCy Schubert 			ret = ASN1_STRING_length(cn) == len &&
20424bc52338SCy Schubert 				os_memcmp(ASN1_STRING_get0_data(cn), value,
20434bc52338SCy Schubert 					  len) == 0;
20444bc52338SCy Schubert 		}
20454bc52338SCy Schubert 		if (!ret) {
20464bc52338SCy Schubert 			wpa_printf(MSG_ERROR,
20474bc52338SCy Schubert 				   "OpenSSL: Failed to match %s '%s' with certificate DN field value '%s'",
20484bc52338SCy Schubert 				   field, value, ASN1_STRING_get0_data(cn));
20494bc52338SCy Schubert 		}
20504bc52338SCy Schubert 		break;
20514bc52338SCy Schubert 	}
20524bc52338SCy Schubert 
20534bc52338SCy Schubert 	return ret;
20544bc52338SCy Schubert }
20554bc52338SCy Schubert 
20564bc52338SCy Schubert 
20574bc52338SCy Schubert /**
20584bc52338SCy Schubert  * get_value_from_field - Get value from DN field
20594bc52338SCy Schubert  * @cert: Certificate
20604bc52338SCy Schubert  * @field_str: DN field string which is passed from configuration file (e.g.,
20614bc52338SCy Schubert  *	 C=US)
20624bc52338SCy Schubert  * @dn_cnt: DN matching context
20634bc52338SCy Schubert  * Returns: 1 on success and 0 on failure
20644bc52338SCy Schubert  */
get_value_from_field(const X509 * cert,char * field_str,struct tls_dn_field_order_cnt * dn_cnt)20654bc52338SCy Schubert static int get_value_from_field(const X509 *cert, char *field_str,
20664bc52338SCy Schubert 				struct tls_dn_field_order_cnt *dn_cnt)
20674bc52338SCy Schubert {
20684bc52338SCy Schubert 	int nid;
20694bc52338SCy Schubert 	char *context = NULL, *name, *value;
20704bc52338SCy Schubert 
20714bc52338SCy Schubert 	if (os_strcmp(field_str, "*") == 0)
20724bc52338SCy Schubert 		return 1; /* wildcard matches everything */
20734bc52338SCy Schubert 
20744bc52338SCy Schubert 	name = str_token(field_str, "=", &context);
20754bc52338SCy Schubert 	if (!name)
20764bc52338SCy Schubert 		return 0;
20774bc52338SCy Schubert 
20784bc52338SCy Schubert 	/* Compare all configured DN fields and assign nid based on that to
20794bc52338SCy Schubert 	 * fetch correct value from certificate subject */
20804bc52338SCy Schubert 	if (os_strcmp(name, "CN") == 0) {
20814bc52338SCy Schubert 		nid = NID_commonName;
20824bc52338SCy Schubert 		dn_cnt->cn++;
20834bc52338SCy Schubert 	} else if(os_strcmp(name, "C") == 0) {
20844bc52338SCy Schubert 		nid = NID_countryName;
20854bc52338SCy Schubert 		dn_cnt->c++;
20864bc52338SCy Schubert 	} else if (os_strcmp(name, "L") == 0) {
20874bc52338SCy Schubert 		nid = NID_localityName;
20884bc52338SCy Schubert 		dn_cnt->l++;
20894bc52338SCy Schubert 	} else if (os_strcmp(name, "ST") == 0) {
20904bc52338SCy Schubert 		nid = NID_stateOrProvinceName;
20914bc52338SCy Schubert 		dn_cnt->st++;
20924bc52338SCy Schubert 	} else if (os_strcmp(name, "O") == 0) {
20934bc52338SCy Schubert 		nid = NID_organizationName;
20944bc52338SCy Schubert 		dn_cnt->o++;
20954bc52338SCy Schubert 	} else if (os_strcmp(name, "OU") == 0) {
20964bc52338SCy Schubert 		nid = NID_organizationalUnitName;
20974bc52338SCy Schubert 		dn_cnt->ou++;
20984bc52338SCy Schubert 	} else if (os_strcmp(name, "emailAddress") == 0) {
20994bc52338SCy Schubert 		nid = NID_pkcs9_emailAddress;
21004bc52338SCy Schubert 		dn_cnt->email++;
21014bc52338SCy Schubert 	} else {
21024bc52338SCy Schubert 		wpa_printf(MSG_ERROR,
21034bc52338SCy Schubert 			"TLS: Unknown field '%s' in check_cert_subject", name);
21044bc52338SCy Schubert 		return 0;
21054bc52338SCy Schubert 	}
21064bc52338SCy Schubert 
21074bc52338SCy Schubert 	value = str_token(field_str, "=", &context);
21084bc52338SCy Schubert 	if (!value) {
21094bc52338SCy Schubert 		wpa_printf(MSG_ERROR,
21104bc52338SCy Schubert 			   "TLS: Distinguished Name field '%s' value is not defined in check_cert_subject",
21114bc52338SCy Schubert 			   name);
21124bc52338SCy Schubert 		return 0;
21134bc52338SCy Schubert 	}
21144bc52338SCy Schubert 
21154bc52338SCy Schubert 	return match_dn_field(cert, nid, name, value, dn_cnt);
21164bc52338SCy Schubert }
21174bc52338SCy Schubert 
21184bc52338SCy Schubert 
21194bc52338SCy Schubert /**
21204bc52338SCy Schubert  * tls_match_dn_field - Match subject DN field with check_cert_subject
21214bc52338SCy Schubert  * @cert: Certificate
21224bc52338SCy Schubert  * @match: check_cert_subject string
21234bc52338SCy Schubert  * Returns: Return 1 on success and 0 on failure
21244bc52338SCy Schubert */
tls_match_dn_field(X509 * cert,const char * match)21254bc52338SCy Schubert static int tls_match_dn_field(X509 *cert, const char *match)
21264bc52338SCy Schubert {
21274bc52338SCy Schubert 	const char *token, *last = NULL;
21284bc52338SCy Schubert 	char field[256];
21294bc52338SCy Schubert 	struct tls_dn_field_order_cnt dn_cnt;
21304bc52338SCy Schubert 
21314bc52338SCy Schubert 	os_memset(&dn_cnt, 0, sizeof(dn_cnt));
21324bc52338SCy Schubert 
21334bc52338SCy Schubert 	/* Maximum length of each DN field is 255 characters */
21344bc52338SCy Schubert 
21354bc52338SCy Schubert 	/* Process each '/' delimited field */
21364bc52338SCy Schubert 	while ((token = cstr_token(match, "/", &last))) {
21374bc52338SCy Schubert 		if (last - token >= (int) sizeof(field)) {
21384bc52338SCy Schubert 			wpa_printf(MSG_ERROR,
21394bc52338SCy Schubert 				   "OpenSSL: Too long DN matching field value in '%s'",
21404bc52338SCy Schubert 				   match);
21414bc52338SCy Schubert 			return 0;
21424bc52338SCy Schubert 		}
21434bc52338SCy Schubert 		os_memcpy(field, token, last - token);
21444bc52338SCy Schubert 		field[last - token] = '\0';
21454bc52338SCy Schubert 
21464bc52338SCy Schubert 		if (!get_value_from_field(cert, field, &dn_cnt)) {
21474bc52338SCy Schubert 			wpa_printf(MSG_DEBUG, "OpenSSL: No match for DN '%s'",
21484bc52338SCy Schubert 				   field);
21494bc52338SCy Schubert 			return 0;
21504bc52338SCy Schubert 		}
21514bc52338SCy Schubert 	}
21524bc52338SCy Schubert 
21534bc52338SCy Schubert 	return 1;
21544bc52338SCy Schubert }
21554bc52338SCy Schubert 
21564bc52338SCy Schubert 
21574bc52338SCy Schubert #ifndef CONFIG_NATIVE_WINDOWS
tls_match_suffix_helper(X509 * cert,const char * match,size_t match_len,int full)21584bc52338SCy Schubert static int tls_match_suffix_helper(X509 *cert, const char *match,
21594bc52338SCy Schubert 				   size_t match_len, int full)
21604bc52338SCy Schubert {
21615b9c547cSRui Paulo 	GENERAL_NAME *gen;
21625b9c547cSRui Paulo 	void *ext;
21635b9c547cSRui Paulo 	int i;
21645b9c547cSRui Paulo 	stack_index_t j;
21655b9c547cSRui Paulo 	int dns_name = 0;
21665b9c547cSRui Paulo 	X509_NAME *name;
21675b9c547cSRui Paulo 
21685b9c547cSRui Paulo 	wpa_printf(MSG_DEBUG, "TLS: Match domain against %s%s",
21695b9c547cSRui Paulo 		   full ? "": "suffix ", match);
21705b9c547cSRui Paulo 
21715b9c547cSRui Paulo 	ext = X509_get_ext_d2i(cert, NID_subject_alt_name, NULL, NULL);
21725b9c547cSRui Paulo 
21735b9c547cSRui Paulo 	for (j = 0; ext && j < sk_GENERAL_NAME_num(ext); j++) {
21745b9c547cSRui Paulo 		gen = sk_GENERAL_NAME_value(ext, j);
21755b9c547cSRui Paulo 		if (gen->type != GEN_DNS)
21765b9c547cSRui Paulo 			continue;
21775b9c547cSRui Paulo 		dns_name++;
21785b9c547cSRui Paulo 		wpa_hexdump_ascii(MSG_DEBUG, "TLS: Certificate dNSName",
21795b9c547cSRui Paulo 				  gen->d.dNSName->data,
21805b9c547cSRui Paulo 				  gen->d.dNSName->length);
21815b9c547cSRui Paulo 		if (domain_suffix_match(gen->d.dNSName->data,
21824bc52338SCy Schubert 					gen->d.dNSName->length,
21834bc52338SCy Schubert 					match, match_len, full) == 1) {
21845b9c547cSRui Paulo 			wpa_printf(MSG_DEBUG, "TLS: %s in dNSName found",
21855b9c547cSRui Paulo 				   full ? "Match" : "Suffix match");
2186780fb4a2SCy Schubert 			sk_GENERAL_NAME_pop_free(ext, GENERAL_NAME_free);
21875b9c547cSRui Paulo 			return 1;
21885b9c547cSRui Paulo 		}
21895b9c547cSRui Paulo 	}
2190780fb4a2SCy Schubert 	sk_GENERAL_NAME_pop_free(ext, GENERAL_NAME_free);
21915b9c547cSRui Paulo 
21925b9c547cSRui Paulo 	if (dns_name) {
21935b9c547cSRui Paulo 		wpa_printf(MSG_DEBUG, "TLS: None of the dNSName(s) matched");
21945b9c547cSRui Paulo 		return 0;
21955b9c547cSRui Paulo 	}
21965b9c547cSRui Paulo 
21975b9c547cSRui Paulo 	name = X509_get_subject_name(cert);
21985b9c547cSRui Paulo 	i = -1;
21995b9c547cSRui Paulo 	for (;;) {
22005b9c547cSRui Paulo 		X509_NAME_ENTRY *e;
22015b9c547cSRui Paulo 		ASN1_STRING *cn;
22025b9c547cSRui Paulo 
22035b9c547cSRui Paulo 		i = X509_NAME_get_index_by_NID(name, NID_commonName, i);
22045b9c547cSRui Paulo 		if (i == -1)
22055b9c547cSRui Paulo 			break;
22065b9c547cSRui Paulo 		e = X509_NAME_get_entry(name, i);
22075b9c547cSRui Paulo 		if (e == NULL)
22085b9c547cSRui Paulo 			continue;
22095b9c547cSRui Paulo 		cn = X509_NAME_ENTRY_get_data(e);
22105b9c547cSRui Paulo 		if (cn == NULL)
22115b9c547cSRui Paulo 			continue;
22125b9c547cSRui Paulo 		wpa_hexdump_ascii(MSG_DEBUG, "TLS: Certificate commonName",
22135b9c547cSRui Paulo 				  cn->data, cn->length);
22144bc52338SCy Schubert 		if (domain_suffix_match(cn->data, cn->length,
22154bc52338SCy Schubert 					match, match_len, full) == 1) {
22165b9c547cSRui Paulo 			wpa_printf(MSG_DEBUG, "TLS: %s in commonName found",
22175b9c547cSRui Paulo 				   full ? "Match" : "Suffix match");
22185b9c547cSRui Paulo 			return 1;
22195b9c547cSRui Paulo 		}
22205b9c547cSRui Paulo 	}
22215b9c547cSRui Paulo 
22225b9c547cSRui Paulo 	wpa_printf(MSG_DEBUG, "TLS: No CommonName %smatch found",
22235b9c547cSRui Paulo 		   full ? "": "suffix ");
22245b9c547cSRui Paulo 	return 0;
22254bc52338SCy Schubert }
22264bc52338SCy Schubert #endif /* CONFIG_NATIVE_WINDOWS */
22274bc52338SCy Schubert 
22284bc52338SCy Schubert 
tls_match_suffix(X509 * cert,const char * match,int full)22294bc52338SCy Schubert static int tls_match_suffix(X509 *cert, const char *match, int full)
22304bc52338SCy Schubert {
22314bc52338SCy Schubert #ifdef CONFIG_NATIVE_WINDOWS
22324bc52338SCy Schubert 	/* wincrypt.h has conflicting X509_NAME definition */
22334bc52338SCy Schubert 	return -1;
22344bc52338SCy Schubert #else /* CONFIG_NATIVE_WINDOWS */
22354bc52338SCy Schubert 	const char *token, *last = NULL;
22364bc52338SCy Schubert 
22374bc52338SCy Schubert 	/* Process each match alternative separately until a match is found */
22384bc52338SCy Schubert 	while ((token = cstr_token(match, ";", &last))) {
22394bc52338SCy Schubert 		if (tls_match_suffix_helper(cert, token, last - token, full))
22404bc52338SCy Schubert 			return 1;
22414bc52338SCy Schubert 	}
22424bc52338SCy Schubert 
22434bc52338SCy Schubert 	return 0;
22445b9c547cSRui Paulo #endif /* CONFIG_NATIVE_WINDOWS */
22455b9c547cSRui Paulo }
22465b9c547cSRui Paulo 
22475b9c547cSRui Paulo 
openssl_tls_fail_reason(int err)2248e28a4053SRui Paulo static enum tls_fail_reason openssl_tls_fail_reason(int err)
2249e28a4053SRui Paulo {
2250e28a4053SRui Paulo 	switch (err) {
2251e28a4053SRui Paulo 	case X509_V_ERR_CERT_REVOKED:
2252e28a4053SRui Paulo 		return TLS_FAIL_REVOKED;
2253e28a4053SRui Paulo 	case X509_V_ERR_CERT_NOT_YET_VALID:
2254e28a4053SRui Paulo 	case X509_V_ERR_CRL_NOT_YET_VALID:
2255e28a4053SRui Paulo 		return TLS_FAIL_NOT_YET_VALID;
2256e28a4053SRui Paulo 	case X509_V_ERR_CERT_HAS_EXPIRED:
2257e28a4053SRui Paulo 	case X509_V_ERR_CRL_HAS_EXPIRED:
2258e28a4053SRui Paulo 		return TLS_FAIL_EXPIRED;
2259e28a4053SRui Paulo 	case X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT:
2260e28a4053SRui Paulo 	case X509_V_ERR_UNABLE_TO_GET_CRL:
2261e28a4053SRui Paulo 	case X509_V_ERR_UNABLE_TO_GET_CRL_ISSUER:
2262e28a4053SRui Paulo 	case X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN:
2263e28a4053SRui Paulo 	case X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY:
2264e28a4053SRui Paulo 	case X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT:
2265e28a4053SRui Paulo 	case X509_V_ERR_UNABLE_TO_VERIFY_LEAF_SIGNATURE:
2266e28a4053SRui Paulo 	case X509_V_ERR_CERT_CHAIN_TOO_LONG:
2267e28a4053SRui Paulo 	case X509_V_ERR_PATH_LENGTH_EXCEEDED:
2268e28a4053SRui Paulo 	case X509_V_ERR_INVALID_CA:
2269e28a4053SRui Paulo 		return TLS_FAIL_UNTRUSTED;
2270e28a4053SRui Paulo 	case X509_V_ERR_UNABLE_TO_DECRYPT_CERT_SIGNATURE:
2271e28a4053SRui Paulo 	case X509_V_ERR_UNABLE_TO_DECRYPT_CRL_SIGNATURE:
2272e28a4053SRui Paulo 	case X509_V_ERR_UNABLE_TO_DECODE_ISSUER_PUBLIC_KEY:
2273e28a4053SRui Paulo 	case X509_V_ERR_ERROR_IN_CERT_NOT_BEFORE_FIELD:
2274e28a4053SRui Paulo 	case X509_V_ERR_ERROR_IN_CERT_NOT_AFTER_FIELD:
2275e28a4053SRui Paulo 	case X509_V_ERR_ERROR_IN_CRL_LAST_UPDATE_FIELD:
2276e28a4053SRui Paulo 	case X509_V_ERR_ERROR_IN_CRL_NEXT_UPDATE_FIELD:
2277e28a4053SRui Paulo 	case X509_V_ERR_CERT_UNTRUSTED:
2278e28a4053SRui Paulo 	case X509_V_ERR_CERT_REJECTED:
2279e28a4053SRui Paulo 		return TLS_FAIL_BAD_CERTIFICATE;
2280e28a4053SRui Paulo 	default:
2281e28a4053SRui Paulo 		return TLS_FAIL_UNSPECIFIED;
2282e28a4053SRui Paulo 	}
2283e28a4053SRui Paulo }
2284e28a4053SRui Paulo 
2285e28a4053SRui Paulo 
get_x509_cert(X509 * cert)2286e28a4053SRui Paulo static struct wpabuf * get_x509_cert(X509 *cert)
2287e28a4053SRui Paulo {
2288e28a4053SRui Paulo 	struct wpabuf *buf;
2289e28a4053SRui Paulo 	u8 *tmp;
2290e28a4053SRui Paulo 
2291e28a4053SRui Paulo 	int cert_len = i2d_X509(cert, NULL);
2292e28a4053SRui Paulo 	if (cert_len <= 0)
2293e28a4053SRui Paulo 		return NULL;
2294e28a4053SRui Paulo 
2295e28a4053SRui Paulo 	buf = wpabuf_alloc(cert_len);
2296e28a4053SRui Paulo 	if (buf == NULL)
2297e28a4053SRui Paulo 		return NULL;
2298e28a4053SRui Paulo 
2299e28a4053SRui Paulo 	tmp = wpabuf_put(buf, cert_len);
2300e28a4053SRui Paulo 	i2d_X509(cert, &tmp);
2301e28a4053SRui Paulo 	return buf;
2302e28a4053SRui Paulo }
2303e28a4053SRui Paulo 
2304e28a4053SRui Paulo 
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)2305e28a4053SRui Paulo static void openssl_tls_fail_event(struct tls_connection *conn,
2306e28a4053SRui Paulo 				   X509 *err_cert, int err, int depth,
2307e28a4053SRui Paulo 				   const char *subject, const char *err_str,
2308e28a4053SRui Paulo 				   enum tls_fail_reason reason)
2309e28a4053SRui Paulo {
2310e28a4053SRui Paulo 	union tls_event_data ev;
2311e28a4053SRui Paulo 	struct wpabuf *cert = NULL;
23125b9c547cSRui Paulo 	struct tls_context *context = conn->context;
2313e28a4053SRui Paulo 
23145b9c547cSRui Paulo 	if (context->event_cb == NULL)
2315e28a4053SRui Paulo 		return;
2316e28a4053SRui Paulo 
2317e28a4053SRui Paulo 	cert = get_x509_cert(err_cert);
2318e28a4053SRui Paulo 	os_memset(&ev, 0, sizeof(ev));
2319e28a4053SRui Paulo 	ev.cert_fail.reason = reason != TLS_FAIL_UNSPECIFIED ?
2320e28a4053SRui Paulo 		reason : openssl_tls_fail_reason(err);
2321e28a4053SRui Paulo 	ev.cert_fail.depth = depth;
2322e28a4053SRui Paulo 	ev.cert_fail.subject = subject;
2323e28a4053SRui Paulo 	ev.cert_fail.reason_txt = err_str;
2324e28a4053SRui Paulo 	ev.cert_fail.cert = cert;
23255b9c547cSRui Paulo 	context->event_cb(context->cb_ctx, TLS_CERT_CHAIN_FAILURE, &ev);
2326e28a4053SRui Paulo 	wpabuf_free(cert);
2327e28a4053SRui Paulo }
2328e28a4053SRui Paulo 
2329e28a4053SRui Paulo 
openssl_cert_tod(X509 * cert)2330206b73d0SCy Schubert static int openssl_cert_tod(X509 *cert)
2331206b73d0SCy Schubert {
2332206b73d0SCy Schubert 	CERTIFICATEPOLICIES *ext;
2333206b73d0SCy Schubert 	stack_index_t i;
2334206b73d0SCy Schubert 	char buf[100];
2335206b73d0SCy Schubert 	int res;
2336206b73d0SCy Schubert 	int tod = 0;
2337206b73d0SCy Schubert 
2338206b73d0SCy Schubert 	ext = X509_get_ext_d2i(cert, NID_certificate_policies, NULL, NULL);
2339206b73d0SCy Schubert 	if (!ext)
2340206b73d0SCy Schubert 		return 0;
2341206b73d0SCy Schubert 
2342206b73d0SCy Schubert 	for (i = 0; i < sk_POLICYINFO_num(ext); i++) {
2343206b73d0SCy Schubert 		POLICYINFO *policy;
2344206b73d0SCy Schubert 
2345206b73d0SCy Schubert 		policy = sk_POLICYINFO_value(ext, i);
2346206b73d0SCy Schubert 		res = OBJ_obj2txt(buf, sizeof(buf), policy->policyid, 0);
2347206b73d0SCy Schubert 		if (res < 0 || (size_t) res >= sizeof(buf))
2348206b73d0SCy Schubert 			continue;
2349206b73d0SCy Schubert 		wpa_printf(MSG_DEBUG, "OpenSSL: Certificate Policy %s", buf);
2350206b73d0SCy Schubert 		if (os_strcmp(buf, "1.3.6.1.4.1.40808.1.3.1") == 0)
2351c1d255d3SCy Schubert 			tod = 1; /* TOD-STRICT */
2352c1d255d3SCy Schubert 		else if (os_strcmp(buf, "1.3.6.1.4.1.40808.1.3.2") == 0 && !tod)
2353c1d255d3SCy Schubert 			tod = 2; /* TOD-TOFU */
2354206b73d0SCy Schubert 	}
2355c1d255d3SCy Schubert 	sk_POLICYINFO_pop_free(ext, POLICYINFO_free);
2356206b73d0SCy Schubert 
2357206b73d0SCy Schubert 	return tod;
2358206b73d0SCy Schubert }
2359206b73d0SCy Schubert 
2360206b73d0SCy Schubert 
openssl_tls_cert_event(struct tls_connection * conn,X509 * err_cert,int depth,const char * subject)2361e28a4053SRui Paulo static void openssl_tls_cert_event(struct tls_connection *conn,
2362e28a4053SRui Paulo 				   X509 *err_cert, int depth,
2363e28a4053SRui Paulo 				   const char *subject)
2364e28a4053SRui Paulo {
2365e28a4053SRui Paulo 	struct wpabuf *cert = NULL;
2366e28a4053SRui Paulo 	union tls_event_data ev;
23675b9c547cSRui Paulo 	struct tls_context *context = conn->context;
23685b9c547cSRui Paulo 	char *altsubject[TLS_MAX_ALT_SUBJECT];
23695b9c547cSRui Paulo 	int alt, num_altsubject = 0;
23705b9c547cSRui Paulo 	GENERAL_NAME *gen;
23715b9c547cSRui Paulo 	void *ext;
23725b9c547cSRui Paulo 	stack_index_t i;
237385732ac8SCy Schubert 	ASN1_INTEGER *ser;
237485732ac8SCy Schubert 	char serial_num[128];
2375e28a4053SRui Paulo #ifdef CONFIG_SHA256
2376e28a4053SRui Paulo 	u8 hash[32];
2377e28a4053SRui Paulo #endif /* CONFIG_SHA256 */
2378e28a4053SRui Paulo 
23795b9c547cSRui Paulo 	if (context->event_cb == NULL)
2380e28a4053SRui Paulo 		return;
2381e28a4053SRui Paulo 
2382e28a4053SRui Paulo 	os_memset(&ev, 0, sizeof(ev));
2383780fb4a2SCy Schubert 	if (conn->cert_probe || (conn->flags & TLS_CONN_EXT_CERT_CHECK) ||
2384780fb4a2SCy Schubert 	    context->cert_in_cb) {
2385e28a4053SRui Paulo 		cert = get_x509_cert(err_cert);
2386e28a4053SRui Paulo 		ev.peer_cert.cert = cert;
2387e28a4053SRui Paulo 	}
2388e28a4053SRui Paulo #ifdef CONFIG_SHA256
2389e28a4053SRui Paulo 	if (cert) {
2390e28a4053SRui Paulo 		const u8 *addr[1];
2391e28a4053SRui Paulo 		size_t len[1];
2392e28a4053SRui Paulo 		addr[0] = wpabuf_head(cert);
2393e28a4053SRui Paulo 		len[0] = wpabuf_len(cert);
2394e28a4053SRui Paulo 		if (sha256_vector(1, addr, len, hash) == 0) {
2395e28a4053SRui Paulo 			ev.peer_cert.hash = hash;
2396e28a4053SRui Paulo 			ev.peer_cert.hash_len = sizeof(hash);
2397e28a4053SRui Paulo 		}
2398e28a4053SRui Paulo 	}
2399e28a4053SRui Paulo #endif /* CONFIG_SHA256 */
2400e28a4053SRui Paulo 	ev.peer_cert.depth = depth;
2401e28a4053SRui Paulo 	ev.peer_cert.subject = subject;
24025b9c547cSRui Paulo 
240385732ac8SCy Schubert 	ser = X509_get_serialNumber(err_cert);
240485732ac8SCy Schubert 	if (ser) {
240585732ac8SCy Schubert 		wpa_snprintf_hex_uppercase(serial_num, sizeof(serial_num),
240685732ac8SCy Schubert 					   ASN1_STRING_get0_data(ser),
240785732ac8SCy Schubert 					   ASN1_STRING_length(ser));
240885732ac8SCy Schubert 		ev.peer_cert.serial_num = serial_num;
240985732ac8SCy Schubert 	}
241085732ac8SCy Schubert 
24115b9c547cSRui Paulo 	ext = X509_get_ext_d2i(err_cert, NID_subject_alt_name, NULL, NULL);
24125b9c547cSRui Paulo 	for (i = 0; ext && i < sk_GENERAL_NAME_num(ext); i++) {
24135b9c547cSRui Paulo 		char *pos;
24145b9c547cSRui Paulo 
24155b9c547cSRui Paulo 		if (num_altsubject == TLS_MAX_ALT_SUBJECT)
24165b9c547cSRui Paulo 			break;
24175b9c547cSRui Paulo 		gen = sk_GENERAL_NAME_value(ext, i);
24185b9c547cSRui Paulo 		if (gen->type != GEN_EMAIL &&
24195b9c547cSRui Paulo 		    gen->type != GEN_DNS &&
24205b9c547cSRui Paulo 		    gen->type != GEN_URI)
24215b9c547cSRui Paulo 			continue;
24225b9c547cSRui Paulo 
24235b9c547cSRui Paulo 		pos = os_malloc(10 + gen->d.ia5->length + 1);
24245b9c547cSRui Paulo 		if (pos == NULL)
24255b9c547cSRui Paulo 			break;
24265b9c547cSRui Paulo 		altsubject[num_altsubject++] = pos;
24275b9c547cSRui Paulo 
24285b9c547cSRui Paulo 		switch (gen->type) {
24295b9c547cSRui Paulo 		case GEN_EMAIL:
24305b9c547cSRui Paulo 			os_memcpy(pos, "EMAIL:", 6);
24315b9c547cSRui Paulo 			pos += 6;
24325b9c547cSRui Paulo 			break;
24335b9c547cSRui Paulo 		case GEN_DNS:
24345b9c547cSRui Paulo 			os_memcpy(pos, "DNS:", 4);
24355b9c547cSRui Paulo 			pos += 4;
24365b9c547cSRui Paulo 			break;
24375b9c547cSRui Paulo 		case GEN_URI:
24385b9c547cSRui Paulo 			os_memcpy(pos, "URI:", 4);
24395b9c547cSRui Paulo 			pos += 4;
24405b9c547cSRui Paulo 			break;
24415b9c547cSRui Paulo 		}
24425b9c547cSRui Paulo 
24435b9c547cSRui Paulo 		os_memcpy(pos, gen->d.ia5->data, gen->d.ia5->length);
24445b9c547cSRui Paulo 		pos += gen->d.ia5->length;
24455b9c547cSRui Paulo 		*pos = '\0';
24465b9c547cSRui Paulo 	}
2447780fb4a2SCy Schubert 	sk_GENERAL_NAME_pop_free(ext, GENERAL_NAME_free);
24485b9c547cSRui Paulo 
24495b9c547cSRui Paulo 	for (alt = 0; alt < num_altsubject; alt++)
24505b9c547cSRui Paulo 		ev.peer_cert.altsubject[alt] = altsubject[alt];
24515b9c547cSRui Paulo 	ev.peer_cert.num_altsubject = num_altsubject;
24525b9c547cSRui Paulo 
2453206b73d0SCy Schubert 	ev.peer_cert.tod = openssl_cert_tod(err_cert);
2454206b73d0SCy Schubert 
24555b9c547cSRui Paulo 	context->event_cb(context->cb_ctx, TLS_PEER_CERTIFICATE, &ev);
2456e28a4053SRui Paulo 	wpabuf_free(cert);
24575b9c547cSRui Paulo 	for (alt = 0; alt < num_altsubject; alt++)
24585b9c547cSRui Paulo 		os_free(altsubject[alt]);
2459e28a4053SRui Paulo }
2460e28a4053SRui Paulo 
2461e28a4053SRui Paulo 
debug_print_cert(X509 * cert,const char * title)2462c1d255d3SCy Schubert static void debug_print_cert(X509 *cert, const char *title)
2463c1d255d3SCy Schubert {
2464c1d255d3SCy Schubert #ifndef CONFIG_NO_STDOUT_DEBUG
2465c1d255d3SCy Schubert 	BIO *out;
2466c1d255d3SCy Schubert 	size_t rlen;
2467c1d255d3SCy Schubert 	char *txt;
2468c1d255d3SCy Schubert 	int res;
2469c1d255d3SCy Schubert 
2470c1d255d3SCy Schubert 	if (wpa_debug_level > MSG_DEBUG)
2471c1d255d3SCy Schubert 		return;
2472c1d255d3SCy Schubert 
2473c1d255d3SCy Schubert 	out = BIO_new(BIO_s_mem());
2474c1d255d3SCy Schubert 	if (!out)
2475c1d255d3SCy Schubert 		return;
2476c1d255d3SCy Schubert 
2477c1d255d3SCy Schubert 	X509_print(out, cert);
2478c1d255d3SCy Schubert 	rlen = BIO_ctrl_pending(out);
2479c1d255d3SCy Schubert 	txt = os_malloc(rlen + 1);
2480c1d255d3SCy Schubert 	if (txt) {
2481c1d255d3SCy Schubert 		res = BIO_read(out, txt, rlen);
2482c1d255d3SCy Schubert 		if (res > 0) {
2483c1d255d3SCy Schubert 			txt[res] = '\0';
2484c1d255d3SCy Schubert 			wpa_printf(MSG_DEBUG, "OpenSSL: %s\n%s", title, txt);
2485c1d255d3SCy Schubert 		}
2486c1d255d3SCy Schubert 		os_free(txt);
2487c1d255d3SCy Schubert 	}
2488c1d255d3SCy Schubert 
2489c1d255d3SCy Schubert 	BIO_free(out);
2490c1d255d3SCy Schubert #endif /* CONFIG_NO_STDOUT_DEBUG */
2491c1d255d3SCy Schubert }
2492c1d255d3SCy Schubert 
2493c1d255d3SCy Schubert 
tls_verify_cb(int preverify_ok,X509_STORE_CTX * x509_ctx)249439beb93cSSam Leffler static int tls_verify_cb(int preverify_ok, X509_STORE_CTX *x509_ctx)
249539beb93cSSam Leffler {
249639beb93cSSam Leffler 	char buf[256];
249739beb93cSSam Leffler 	X509 *err_cert;
249839beb93cSSam Leffler 	int err, depth;
249939beb93cSSam Leffler 	SSL *ssl;
250039beb93cSSam Leffler 	struct tls_connection *conn;
25015b9c547cSRui Paulo 	struct tls_context *context;
25025b9c547cSRui Paulo 	char *match, *altmatch, *suffix_match, *domain_match;
25034bc52338SCy Schubert 	const char *check_cert_subject;
2504e28a4053SRui Paulo 	const char *err_str;
250539beb93cSSam Leffler 
250639beb93cSSam Leffler 	err_cert = X509_STORE_CTX_get_current_cert(x509_ctx);
25075b9c547cSRui Paulo 	if (!err_cert)
25085b9c547cSRui Paulo 		return 0;
25095b9c547cSRui Paulo 
251039beb93cSSam Leffler 	err = X509_STORE_CTX_get_error(x509_ctx);
251139beb93cSSam Leffler 	depth = X509_STORE_CTX_get_error_depth(x509_ctx);
251239beb93cSSam Leffler 	ssl = X509_STORE_CTX_get_ex_data(x509_ctx,
251339beb93cSSam Leffler 					 SSL_get_ex_data_X509_STORE_CTX_idx());
2514c1d255d3SCy Schubert 	os_snprintf(buf, sizeof(buf), "Peer certificate - depth %d", depth);
2515c1d255d3SCy Schubert 	debug_print_cert(err_cert, buf);
251639beb93cSSam Leffler 	X509_NAME_oneline(X509_get_subject_name(err_cert), buf, sizeof(buf));
251739beb93cSSam Leffler 
251839beb93cSSam Leffler 	conn = SSL_get_app_data(ssl);
2519f05cddf9SRui Paulo 	if (conn == NULL)
2520f05cddf9SRui Paulo 		return 0;
25215b9c547cSRui Paulo 
25225b9c547cSRui Paulo 	if (depth == 0)
25235b9c547cSRui Paulo 		conn->peer_cert = err_cert;
25245b9c547cSRui Paulo 	else if (depth == 1)
25255b9c547cSRui Paulo 		conn->peer_issuer = err_cert;
25265b9c547cSRui Paulo 	else if (depth == 2)
25275b9c547cSRui Paulo 		conn->peer_issuer_issuer = err_cert;
25285b9c547cSRui Paulo 
25295b9c547cSRui Paulo 	context = conn->context;
2530f05cddf9SRui Paulo 	match = conn->subject_match;
2531f05cddf9SRui Paulo 	altmatch = conn->altsubject_match;
25325b9c547cSRui Paulo 	suffix_match = conn->suffix_match;
25335b9c547cSRui Paulo 	domain_match = conn->domain_match;
253439beb93cSSam Leffler 
2535e28a4053SRui Paulo 	if (!preverify_ok && !conn->ca_cert_verify)
2536e28a4053SRui Paulo 		preverify_ok = 1;
2537e28a4053SRui Paulo 	if (!preverify_ok && depth > 0 && conn->server_cert_only)
2538e28a4053SRui Paulo 		preverify_ok = 1;
2539f05cddf9SRui Paulo 	if (!preverify_ok && (conn->flags & TLS_CONN_DISABLE_TIME_CHECKS) &&
2540f05cddf9SRui Paulo 	    (err == X509_V_ERR_CERT_HAS_EXPIRED ||
2541f05cddf9SRui Paulo 	     err == X509_V_ERR_CERT_NOT_YET_VALID)) {
2542f05cddf9SRui Paulo 		wpa_printf(MSG_DEBUG, "OpenSSL: Ignore certificate validity "
2543f05cddf9SRui Paulo 			   "time mismatch");
2544f05cddf9SRui Paulo 		preverify_ok = 1;
2545f05cddf9SRui Paulo 	}
25464bc52338SCy Schubert 	if (!preverify_ok && !conn->data->check_crl_strict &&
25474bc52338SCy Schubert 	    (err == X509_V_ERR_CRL_HAS_EXPIRED ||
25484bc52338SCy Schubert 	     err == X509_V_ERR_CRL_NOT_YET_VALID)) {
25494bc52338SCy Schubert 		wpa_printf(MSG_DEBUG,
25504bc52338SCy Schubert 			   "OpenSSL: Ignore certificate validity CRL time mismatch");
25514bc52338SCy Schubert 		preverify_ok = 1;
25524bc52338SCy Schubert 	}
2553e28a4053SRui Paulo 
2554e28a4053SRui Paulo 	err_str = X509_verify_cert_error_string(err);
2555e28a4053SRui Paulo 
2556e28a4053SRui Paulo #ifdef CONFIG_SHA256
25575b9c547cSRui Paulo 	/*
25585b9c547cSRui Paulo 	 * Do not require preverify_ok so we can explicity allow otherwise
25595b9c547cSRui Paulo 	 * invalid pinned server certificates.
25605b9c547cSRui Paulo 	 */
25615b9c547cSRui Paulo 	if (depth == 0 && conn->server_cert_only) {
2562e28a4053SRui Paulo 		struct wpabuf *cert;
2563e28a4053SRui Paulo 		cert = get_x509_cert(err_cert);
2564e28a4053SRui Paulo 		if (!cert) {
2565e28a4053SRui Paulo 			wpa_printf(MSG_DEBUG, "OpenSSL: Could not fetch "
2566e28a4053SRui Paulo 				   "server certificate data");
2567e28a4053SRui Paulo 			preverify_ok = 0;
2568e28a4053SRui Paulo 		} else {
2569e28a4053SRui Paulo 			u8 hash[32];
2570e28a4053SRui Paulo 			const u8 *addr[1];
2571e28a4053SRui Paulo 			size_t len[1];
2572e28a4053SRui Paulo 			addr[0] = wpabuf_head(cert);
2573e28a4053SRui Paulo 			len[0] = wpabuf_len(cert);
2574e28a4053SRui Paulo 			if (sha256_vector(1, addr, len, hash) < 0 ||
2575e28a4053SRui Paulo 			    os_memcmp(conn->srv_cert_hash, hash, 32) != 0) {
2576e28a4053SRui Paulo 				err_str = "Server certificate mismatch";
2577e28a4053SRui Paulo 				err = X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN;
2578e28a4053SRui Paulo 				preverify_ok = 0;
25795b9c547cSRui Paulo 			} else if (!preverify_ok) {
25805b9c547cSRui Paulo 				/*
25815b9c547cSRui Paulo 				 * Certificate matches pinned certificate, allow
25825b9c547cSRui Paulo 				 * regardless of other problems.
25835b9c547cSRui Paulo 				 */
25845b9c547cSRui Paulo 				wpa_printf(MSG_DEBUG,
25855b9c547cSRui Paulo 					   "OpenSSL: Ignore validation issues for a pinned server certificate");
25865b9c547cSRui Paulo 				preverify_ok = 1;
2587e28a4053SRui Paulo 			}
2588e28a4053SRui Paulo 			wpabuf_free(cert);
2589e28a4053SRui Paulo 		}
2590e28a4053SRui Paulo 	}
2591e28a4053SRui Paulo #endif /* CONFIG_SHA256 */
2592e28a4053SRui Paulo 
2593206b73d0SCy Schubert 	openssl_tls_cert_event(conn, err_cert, depth, buf);
2594206b73d0SCy Schubert 
259539beb93cSSam Leffler 	if (!preverify_ok) {
2596206b73d0SCy Schubert 		if (depth > 0) {
2597206b73d0SCy Schubert 			/* Send cert event for the peer certificate so that
2598206b73d0SCy Schubert 			 * the upper layers get information about it even if
2599206b73d0SCy Schubert 			 * validation of a CA certificate fails. */
2600206b73d0SCy Schubert 			STACK_OF(X509) *chain;
2601206b73d0SCy Schubert 
2602206b73d0SCy Schubert 			chain = X509_STORE_CTX_get1_chain(x509_ctx);
2603206b73d0SCy Schubert 			if (chain && sk_X509_num(chain) > 0) {
2604206b73d0SCy Schubert 				char buf2[256];
2605206b73d0SCy Schubert 				X509 *cert;
2606206b73d0SCy Schubert 
2607206b73d0SCy Schubert 				cert = sk_X509_value(chain, 0);
2608206b73d0SCy Schubert 				X509_NAME_oneline(X509_get_subject_name(cert),
2609206b73d0SCy Schubert 						  buf2, sizeof(buf2));
2610206b73d0SCy Schubert 
2611206b73d0SCy Schubert 				openssl_tls_cert_event(conn, cert, 0, buf2);
2612206b73d0SCy Schubert 			}
2613206b73d0SCy Schubert 			if (chain)
2614206b73d0SCy Schubert 				sk_X509_pop_free(chain, X509_free);
2615206b73d0SCy Schubert 		}
2616206b73d0SCy Schubert 
261739beb93cSSam Leffler 		wpa_printf(MSG_WARNING, "TLS: Certificate verification failed,"
2618e28a4053SRui Paulo 			   " error %d (%s) depth %d for '%s'", err, err_str,
2619e28a4053SRui Paulo 			   depth, buf);
2620e28a4053SRui Paulo 		openssl_tls_fail_event(conn, err_cert, err, depth, buf,
2621e28a4053SRui Paulo 				       err_str, TLS_FAIL_UNSPECIFIED);
2622e28a4053SRui Paulo 		return preverify_ok;
2623e28a4053SRui Paulo 	}
2624e28a4053SRui Paulo 
2625e28a4053SRui Paulo 	wpa_printf(MSG_DEBUG, "TLS: tls_verify_cb - preverify_ok=%d "
2626e28a4053SRui Paulo 		   "err=%d (%s) ca_cert_verify=%d depth=%d buf='%s'",
2627e28a4053SRui Paulo 		   preverify_ok, err, err_str,
2628e28a4053SRui Paulo 		   conn->ca_cert_verify, depth, buf);
26294bc52338SCy Schubert 	check_cert_subject = conn->check_cert_subject;
26304bc52338SCy Schubert 	if (!check_cert_subject)
26314bc52338SCy Schubert 		check_cert_subject = conn->data->check_cert_subject;
26324bc52338SCy Schubert 	if (check_cert_subject) {
26334bc52338SCy Schubert 		if (depth == 0 &&
26344bc52338SCy Schubert 		    !tls_match_dn_field(err_cert, check_cert_subject)) {
26354bc52338SCy Schubert 			preverify_ok = 0;
26364bc52338SCy Schubert 			openssl_tls_fail_event(conn, err_cert, err, depth, buf,
26374bc52338SCy Schubert 					       "Distinguished Name",
26384bc52338SCy Schubert 					       TLS_FAIL_DN_MISMATCH);
26394bc52338SCy Schubert 		}
26404bc52338SCy Schubert 	}
264139beb93cSSam Leffler 	if (depth == 0 && match && os_strstr(buf, match) == NULL) {
264239beb93cSSam Leffler 		wpa_printf(MSG_WARNING, "TLS: Subject '%s' did not "
264339beb93cSSam Leffler 			   "match with '%s'", buf, match);
264439beb93cSSam Leffler 		preverify_ok = 0;
2645e28a4053SRui Paulo 		openssl_tls_fail_event(conn, err_cert, err, depth, buf,
2646e28a4053SRui Paulo 				       "Subject mismatch",
2647e28a4053SRui Paulo 				       TLS_FAIL_SUBJECT_MISMATCH);
264839beb93cSSam Leffler 	} else if (depth == 0 && altmatch &&
264939beb93cSSam Leffler 		   !tls_match_altsubject(err_cert, altmatch)) {
265039beb93cSSam Leffler 		wpa_printf(MSG_WARNING, "TLS: altSubjectName match "
265139beb93cSSam Leffler 			   "'%s' not found", altmatch);
265239beb93cSSam Leffler 		preverify_ok = 0;
2653e28a4053SRui Paulo 		openssl_tls_fail_event(conn, err_cert, err, depth, buf,
2654e28a4053SRui Paulo 				       "AltSubject mismatch",
2655e28a4053SRui Paulo 				       TLS_FAIL_ALTSUBJECT_MISMATCH);
26565b9c547cSRui Paulo 	} else if (depth == 0 && suffix_match &&
26575b9c547cSRui Paulo 		   !tls_match_suffix(err_cert, suffix_match, 0)) {
26585b9c547cSRui Paulo 		wpa_printf(MSG_WARNING, "TLS: Domain suffix match '%s' not found",
26595b9c547cSRui Paulo 			   suffix_match);
26605b9c547cSRui Paulo 		preverify_ok = 0;
26615b9c547cSRui Paulo 		openssl_tls_fail_event(conn, err_cert, err, depth, buf,
26625b9c547cSRui Paulo 				       "Domain suffix mismatch",
26635b9c547cSRui Paulo 				       TLS_FAIL_DOMAIN_SUFFIX_MISMATCH);
26645b9c547cSRui Paulo 	} else if (depth == 0 && domain_match &&
26655b9c547cSRui Paulo 		   !tls_match_suffix(err_cert, domain_match, 1)) {
26665b9c547cSRui Paulo 		wpa_printf(MSG_WARNING, "TLS: Domain match '%s' not found",
26675b9c547cSRui Paulo 			   domain_match);
26685b9c547cSRui Paulo 		preverify_ok = 0;
26695b9c547cSRui Paulo 		openssl_tls_fail_event(conn, err_cert, err, depth, buf,
26705b9c547cSRui Paulo 				       "Domain mismatch",
26715b9c547cSRui Paulo 				       TLS_FAIL_DOMAIN_MISMATCH);
2672206b73d0SCy Schubert 	}
2673e28a4053SRui Paulo 
2674e28a4053SRui Paulo 	if (conn->cert_probe && preverify_ok && depth == 0) {
2675e28a4053SRui Paulo 		wpa_printf(MSG_DEBUG, "OpenSSL: Reject server certificate "
2676e28a4053SRui Paulo 			   "on probe-only run");
2677e28a4053SRui Paulo 		preverify_ok = 0;
2678e28a4053SRui Paulo 		openssl_tls_fail_event(conn, err_cert, err, depth, buf,
2679e28a4053SRui Paulo 				       "Server certificate chain probe",
2680e28a4053SRui Paulo 				       TLS_FAIL_SERVER_CHAIN_PROBE);
268139beb93cSSam Leffler 	}
268239beb93cSSam Leffler 
268385732ac8SCy Schubert #ifdef CONFIG_SUITEB
268485732ac8SCy Schubert 	if (conn->flags & TLS_CONN_SUITEB) {
268585732ac8SCy Schubert 		EVP_PKEY *pk;
268685732ac8SCy Schubert 		int len = -1;
268785732ac8SCy Schubert 
268885732ac8SCy Schubert 		pk = X509_get_pubkey(err_cert);
268985732ac8SCy Schubert 		if (pk) {
2690*a90b9d01SCy Schubert 			len = EVP_PKEY_bits(pk);
269185732ac8SCy Schubert 			EVP_PKEY_free(pk);
269285732ac8SCy Schubert 		}
269385732ac8SCy Schubert 
269485732ac8SCy Schubert 		if (len >= 0) {
269585732ac8SCy Schubert 			wpa_printf(MSG_DEBUG,
269685732ac8SCy Schubert 				   "OpenSSL: RSA modulus size: %d bits", len);
269785732ac8SCy Schubert 			if (len < 3072) {
269885732ac8SCy Schubert 				preverify_ok = 0;
269985732ac8SCy Schubert 				openssl_tls_fail_event(
270085732ac8SCy Schubert 					conn, err_cert, err,
270185732ac8SCy Schubert 					depth, buf,
270285732ac8SCy Schubert 					"Insufficient RSA modulus size",
270385732ac8SCy Schubert 					TLS_FAIL_INSUFFICIENT_KEY_LEN);
270485732ac8SCy Schubert 			}
270585732ac8SCy Schubert 		}
270685732ac8SCy Schubert 	}
270785732ac8SCy Schubert #endif /* CONFIG_SUITEB */
270885732ac8SCy Schubert 
2709780fb4a2SCy Schubert #ifdef OPENSSL_IS_BORINGSSL
2710780fb4a2SCy Schubert 	if (depth == 0 && (conn->flags & TLS_CONN_REQUEST_OCSP) &&
2711780fb4a2SCy Schubert 	    preverify_ok) {
2712780fb4a2SCy Schubert 		enum ocsp_result res;
2713780fb4a2SCy Schubert 
2714780fb4a2SCy Schubert 		res = check_ocsp_resp(conn->ssl_ctx, conn->ssl, err_cert,
2715780fb4a2SCy Schubert 				      conn->peer_issuer,
2716780fb4a2SCy Schubert 				      conn->peer_issuer_issuer);
2717780fb4a2SCy Schubert 		if (res == OCSP_REVOKED) {
2718780fb4a2SCy Schubert 			preverify_ok = 0;
2719780fb4a2SCy Schubert 			openssl_tls_fail_event(conn, err_cert, err, depth, buf,
2720780fb4a2SCy Schubert 					       "certificate revoked",
2721780fb4a2SCy Schubert 					       TLS_FAIL_REVOKED);
2722780fb4a2SCy Schubert 			if (err == X509_V_OK)
2723780fb4a2SCy Schubert 				X509_STORE_CTX_set_error(
2724780fb4a2SCy Schubert 					x509_ctx, X509_V_ERR_CERT_REVOKED);
2725780fb4a2SCy Schubert 		} else if (res != OCSP_GOOD &&
2726780fb4a2SCy Schubert 			   (conn->flags & TLS_CONN_REQUIRE_OCSP)) {
2727780fb4a2SCy Schubert 			preverify_ok = 0;
2728780fb4a2SCy Schubert 			openssl_tls_fail_event(conn, err_cert, err, depth, buf,
2729780fb4a2SCy Schubert 					       "bad certificate status response",
2730780fb4a2SCy Schubert 					       TLS_FAIL_UNSPECIFIED);
2731780fb4a2SCy Schubert 		}
2732780fb4a2SCy Schubert 	}
2733780fb4a2SCy Schubert #endif /* OPENSSL_IS_BORINGSSL */
2734780fb4a2SCy Schubert 
2735780fb4a2SCy Schubert 	if (depth == 0 && preverify_ok && context->event_cb != NULL)
27365b9c547cSRui Paulo 		context->event_cb(context->cb_ctx,
2737f05cddf9SRui Paulo 				  TLS_CERT_CHAIN_SUCCESS, NULL);
2738f05cddf9SRui Paulo 
2739c1d255d3SCy Schubert 	if (depth == 0 && preverify_ok) {
2740c1d255d3SCy Schubert 		os_free(conn->peer_subject);
2741c1d255d3SCy Schubert 		conn->peer_subject = os_strdup(buf);
2742c1d255d3SCy Schubert 	}
2743c1d255d3SCy Schubert 
274439beb93cSSam Leffler 	return preverify_ok;
274539beb93cSSam Leffler }
274639beb93cSSam Leffler 
274739beb93cSSam Leffler 
274839beb93cSSam Leffler #ifndef OPENSSL_NO_STDIO
tls_load_ca_der(struct tls_data * data,const char * ca_cert)2749325151a3SRui Paulo static int tls_load_ca_der(struct tls_data *data, const char *ca_cert)
275039beb93cSSam Leffler {
2751325151a3SRui Paulo 	SSL_CTX *ssl_ctx = data->ssl;
275239beb93cSSam Leffler 	X509_LOOKUP *lookup;
275339beb93cSSam Leffler 	int ret = 0;
275439beb93cSSam Leffler 
27555b9c547cSRui Paulo 	lookup = X509_STORE_add_lookup(SSL_CTX_get_cert_store(ssl_ctx),
275639beb93cSSam Leffler 				       X509_LOOKUP_file());
275739beb93cSSam Leffler 	if (lookup == NULL) {
275839beb93cSSam Leffler 		tls_show_errors(MSG_WARNING, __func__,
275939beb93cSSam Leffler 				"Failed add lookup for X509 store");
276039beb93cSSam Leffler 		return -1;
276139beb93cSSam Leffler 	}
276239beb93cSSam Leffler 
276339beb93cSSam Leffler 	if (!X509_LOOKUP_load_file(lookup, ca_cert, X509_FILETYPE_ASN1)) {
276439beb93cSSam Leffler 		unsigned long err = ERR_peek_error();
276539beb93cSSam Leffler 		tls_show_errors(MSG_WARNING, __func__,
276639beb93cSSam Leffler 				"Failed load CA in DER format");
276739beb93cSSam Leffler 		if (ERR_GET_LIB(err) == ERR_LIB_X509 &&
276839beb93cSSam Leffler 		    ERR_GET_REASON(err) == X509_R_CERT_ALREADY_IN_HASH_TABLE) {
276939beb93cSSam Leffler 			wpa_printf(MSG_DEBUG, "OpenSSL: %s - ignoring "
277039beb93cSSam Leffler 				   "cert already in hash table error",
277139beb93cSSam Leffler 				   __func__);
277239beb93cSSam Leffler 		} else
277339beb93cSSam Leffler 			ret = -1;
277439beb93cSSam Leffler 	}
277539beb93cSSam Leffler 
277639beb93cSSam Leffler 	return ret;
277739beb93cSSam Leffler }
277839beb93cSSam Leffler #endif /* OPENSSL_NO_STDIO */
277939beb93cSSam Leffler 
278039beb93cSSam Leffler 
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)2781325151a3SRui Paulo static int tls_connection_ca_cert(struct tls_data *data,
2782325151a3SRui Paulo 				  struct tls_connection *conn,
278339beb93cSSam Leffler 				  const char *ca_cert, const u8 *ca_cert_blob,
278439beb93cSSam Leffler 				  size_t ca_cert_blob_len, const char *ca_path)
278539beb93cSSam Leffler {
2786325151a3SRui Paulo 	SSL_CTX *ssl_ctx = data->ssl;
27875b9c547cSRui Paulo 	X509_STORE *store;
278839beb93cSSam Leffler 
278939beb93cSSam Leffler 	/*
279039beb93cSSam Leffler 	 * Remove previously configured trusted CA certificates before adding
279139beb93cSSam Leffler 	 * new ones.
279239beb93cSSam Leffler 	 */
27935b9c547cSRui Paulo 	store = X509_STORE_new();
27945b9c547cSRui Paulo 	if (store == NULL) {
279539beb93cSSam Leffler 		wpa_printf(MSG_DEBUG, "OpenSSL: %s - failed to allocate new "
279639beb93cSSam Leffler 			   "certificate store", __func__);
279739beb93cSSam Leffler 		return -1;
279839beb93cSSam Leffler 	}
27995b9c547cSRui Paulo 	SSL_CTX_set_cert_store(ssl_ctx, store);
280039beb93cSSam Leffler 
2801e28a4053SRui Paulo 	SSL_set_verify(conn->ssl, SSL_VERIFY_PEER, tls_verify_cb);
2802e28a4053SRui Paulo 	conn->ca_cert_verify = 1;
2803e28a4053SRui Paulo 
2804e28a4053SRui Paulo 	if (ca_cert && os_strncmp(ca_cert, "probe://", 8) == 0) {
2805e28a4053SRui Paulo 		wpa_printf(MSG_DEBUG, "OpenSSL: Probe for server certificate "
2806e28a4053SRui Paulo 			   "chain");
2807e28a4053SRui Paulo 		conn->cert_probe = 1;
2808e28a4053SRui Paulo 		conn->ca_cert_verify = 0;
2809e28a4053SRui Paulo 		return 0;
2810e28a4053SRui Paulo 	}
2811e28a4053SRui Paulo 
2812e28a4053SRui Paulo 	if (ca_cert && os_strncmp(ca_cert, "hash://", 7) == 0) {
2813e28a4053SRui Paulo #ifdef CONFIG_SHA256
2814e28a4053SRui Paulo 		const char *pos = ca_cert + 7;
2815e28a4053SRui Paulo 		if (os_strncmp(pos, "server/sha256/", 14) != 0) {
2816e28a4053SRui Paulo 			wpa_printf(MSG_DEBUG, "OpenSSL: Unsupported ca_cert "
2817e28a4053SRui Paulo 				   "hash value '%s'", ca_cert);
2818e28a4053SRui Paulo 			return -1;
2819e28a4053SRui Paulo 		}
2820e28a4053SRui Paulo 		pos += 14;
2821e28a4053SRui Paulo 		if (os_strlen(pos) != 32 * 2) {
2822e28a4053SRui Paulo 			wpa_printf(MSG_DEBUG, "OpenSSL: Unexpected SHA256 "
2823e28a4053SRui Paulo 				   "hash length in ca_cert '%s'", ca_cert);
2824e28a4053SRui Paulo 			return -1;
2825e28a4053SRui Paulo 		}
2826e28a4053SRui Paulo 		if (hexstr2bin(pos, conn->srv_cert_hash, 32) < 0) {
2827e28a4053SRui Paulo 			wpa_printf(MSG_DEBUG, "OpenSSL: Invalid SHA256 hash "
2828e28a4053SRui Paulo 				   "value in ca_cert '%s'", ca_cert);
2829e28a4053SRui Paulo 			return -1;
2830e28a4053SRui Paulo 		}
2831e28a4053SRui Paulo 		conn->server_cert_only = 1;
2832e28a4053SRui Paulo 		wpa_printf(MSG_DEBUG, "OpenSSL: Checking only server "
2833e28a4053SRui Paulo 			   "certificate match");
2834e28a4053SRui Paulo 		return 0;
2835e28a4053SRui Paulo #else /* CONFIG_SHA256 */
2836e28a4053SRui Paulo 		wpa_printf(MSG_INFO, "No SHA256 included in the build - "
2837e28a4053SRui Paulo 			   "cannot validate server certificate hash");
2838e28a4053SRui Paulo 		return -1;
2839e28a4053SRui Paulo #endif /* CONFIG_SHA256 */
2840e28a4053SRui Paulo 	}
2841e28a4053SRui Paulo 
284239beb93cSSam Leffler 	if (ca_cert_blob) {
28435b9c547cSRui Paulo 		X509 *cert = d2i_X509(NULL,
28445b9c547cSRui Paulo 				      (const unsigned char **) &ca_cert_blob,
284539beb93cSSam Leffler 				      ca_cert_blob_len);
284639beb93cSSam Leffler 		if (cert == NULL) {
2847206b73d0SCy Schubert 			BIO *bio = BIO_new_mem_buf(ca_cert_blob,
2848206b73d0SCy Schubert 						   ca_cert_blob_len);
2849206b73d0SCy Schubert 
2850206b73d0SCy Schubert 			if (bio) {
2851206b73d0SCy Schubert 				cert = PEM_read_bio_X509(bio, NULL, NULL, NULL);
2852206b73d0SCy Schubert 				BIO_free(bio);
2853206b73d0SCy Schubert 			}
2854206b73d0SCy Schubert 
2855206b73d0SCy Schubert 			if (!cert) {
285639beb93cSSam Leffler 				tls_show_errors(MSG_WARNING, __func__,
285739beb93cSSam Leffler 						"Failed to parse ca_cert_blob");
285839beb93cSSam Leffler 				return -1;
285939beb93cSSam Leffler 			}
286039beb93cSSam Leffler 
2861206b73d0SCy Schubert 			while (ERR_get_error()) {
2862206b73d0SCy Schubert 				/* Ignore errors from DER conversion. */
2863206b73d0SCy Schubert 			}
2864206b73d0SCy Schubert 		}
2865206b73d0SCy Schubert 
28665b9c547cSRui Paulo 		if (!X509_STORE_add_cert(SSL_CTX_get_cert_store(ssl_ctx),
28675b9c547cSRui Paulo 					 cert)) {
286839beb93cSSam Leffler 			unsigned long err = ERR_peek_error();
286939beb93cSSam Leffler 			tls_show_errors(MSG_WARNING, __func__,
287039beb93cSSam Leffler 					"Failed to add ca_cert_blob to "
287139beb93cSSam Leffler 					"certificate store");
287239beb93cSSam Leffler 			if (ERR_GET_LIB(err) == ERR_LIB_X509 &&
287339beb93cSSam Leffler 			    ERR_GET_REASON(err) ==
287439beb93cSSam Leffler 			    X509_R_CERT_ALREADY_IN_HASH_TABLE) {
287539beb93cSSam Leffler 				wpa_printf(MSG_DEBUG, "OpenSSL: %s - ignoring "
287639beb93cSSam Leffler 					   "cert already in hash table error",
287739beb93cSSam Leffler 					   __func__);
287839beb93cSSam Leffler 			} else {
287939beb93cSSam Leffler 				X509_free(cert);
288039beb93cSSam Leffler 				return -1;
288139beb93cSSam Leffler 			}
288239beb93cSSam Leffler 		}
288339beb93cSSam Leffler 		X509_free(cert);
288439beb93cSSam Leffler 		wpa_printf(MSG_DEBUG, "OpenSSL: %s - added ca_cert_blob "
288539beb93cSSam Leffler 			   "to certificate store", __func__);
288639beb93cSSam Leffler 		return 0;
288739beb93cSSam Leffler 	}
288839beb93cSSam Leffler 
2889f05cddf9SRui Paulo #ifdef ANDROID
2890780fb4a2SCy Schubert 	/* Single alias */
2891f05cddf9SRui Paulo 	if (ca_cert && os_strncmp("keystore://", ca_cert, 11) == 0) {
2892780fb4a2SCy Schubert 		if (tls_add_ca_from_keystore(SSL_CTX_get_cert_store(ssl_ctx),
2893780fb4a2SCy Schubert 					     &ca_cert[11]) < 0)
2894f05cddf9SRui Paulo 			return -1;
2895780fb4a2SCy Schubert 		SSL_set_verify(conn->ssl, SSL_VERIFY_PEER, tls_verify_cb);
2896780fb4a2SCy Schubert 		return 0;
2897780fb4a2SCy Schubert 	}
2898f05cddf9SRui Paulo 
2899780fb4a2SCy Schubert 	/* Multiple aliases separated by space */
2900780fb4a2SCy Schubert 	if (ca_cert && os_strncmp("keystores://", ca_cert, 12) == 0) {
2901780fb4a2SCy Schubert 		char *aliases = os_strdup(&ca_cert[12]);
2902780fb4a2SCy Schubert 		const char *delim = " ";
2903780fb4a2SCy Schubert 		int rc = 0;
2904780fb4a2SCy Schubert 		char *savedptr;
2905780fb4a2SCy Schubert 		char *alias;
2906780fb4a2SCy Schubert 
2907780fb4a2SCy Schubert 		if (!aliases)
2908780fb4a2SCy Schubert 			return -1;
2909780fb4a2SCy Schubert 		alias = strtok_r(aliases, delim, &savedptr);
2910780fb4a2SCy Schubert 		for (; alias; alias = strtok_r(NULL, delim, &savedptr)) {
2911780fb4a2SCy Schubert 			if (tls_add_ca_from_keystore_encoded(
2912780fb4a2SCy Schubert 				    SSL_CTX_get_cert_store(ssl_ctx), alias)) {
2913780fb4a2SCy Schubert 				wpa_printf(MSG_WARNING,
2914780fb4a2SCy Schubert 					   "OpenSSL: %s - Failed to add ca_cert %s from keystore",
2915780fb4a2SCy Schubert 					   __func__, alias);
2916780fb4a2SCy Schubert 				rc = -1;
2917780fb4a2SCy Schubert 				break;
2918f05cddf9SRui Paulo 			}
2919f05cddf9SRui Paulo 		}
2920780fb4a2SCy Schubert 		os_free(aliases);
2921780fb4a2SCy Schubert 		if (rc)
2922780fb4a2SCy Schubert 			return rc;
2923780fb4a2SCy Schubert 
2924f05cddf9SRui Paulo 		SSL_set_verify(conn->ssl, SSL_VERIFY_PEER, tls_verify_cb);
2925f05cddf9SRui Paulo 		return 0;
2926f05cddf9SRui Paulo 	}
2927f05cddf9SRui Paulo #endif /* ANDROID */
2928f05cddf9SRui Paulo 
292939beb93cSSam Leffler #ifdef CONFIG_NATIVE_WINDOWS
293039beb93cSSam Leffler 	if (ca_cert && tls_cryptoapi_ca_cert(ssl_ctx, conn->ssl, ca_cert) ==
293139beb93cSSam Leffler 	    0) {
293239beb93cSSam Leffler 		wpa_printf(MSG_DEBUG, "OpenSSL: Added CA certificates from "
293339beb93cSSam Leffler 			   "system certificate store");
293439beb93cSSam Leffler 		return 0;
293539beb93cSSam Leffler 	}
293639beb93cSSam Leffler #endif /* CONFIG_NATIVE_WINDOWS */
293739beb93cSSam Leffler 
293839beb93cSSam Leffler 	if (ca_cert || ca_path) {
293939beb93cSSam Leffler #ifndef OPENSSL_NO_STDIO
294039beb93cSSam Leffler 		if (SSL_CTX_load_verify_locations(ssl_ctx, ca_cert, ca_path) !=
294139beb93cSSam Leffler 		    1) {
294239beb93cSSam Leffler 			tls_show_errors(MSG_WARNING, __func__,
294339beb93cSSam Leffler 					"Failed to load root certificates");
294439beb93cSSam Leffler 			if (ca_cert &&
2945325151a3SRui Paulo 			    tls_load_ca_der(data, ca_cert) == 0) {
294639beb93cSSam Leffler 				wpa_printf(MSG_DEBUG, "OpenSSL: %s - loaded "
294739beb93cSSam Leffler 					   "DER format CA certificate",
294839beb93cSSam Leffler 					   __func__);
294939beb93cSSam Leffler 			} else
295039beb93cSSam Leffler 				return -1;
295139beb93cSSam Leffler 		} else {
295239beb93cSSam Leffler 			wpa_printf(MSG_DEBUG, "TLS: Trusted root "
295339beb93cSSam Leffler 				   "certificate(s) loaded");
2954325151a3SRui Paulo 			tls_get_errors(data);
295539beb93cSSam Leffler 		}
295639beb93cSSam Leffler #else /* OPENSSL_NO_STDIO */
295739beb93cSSam Leffler 		wpa_printf(MSG_DEBUG, "OpenSSL: %s - OPENSSL_NO_STDIO",
295839beb93cSSam Leffler 			   __func__);
295939beb93cSSam Leffler 		return -1;
296039beb93cSSam Leffler #endif /* OPENSSL_NO_STDIO */
296139beb93cSSam Leffler 	} else {
296239beb93cSSam Leffler 		/* No ca_cert configured - do not try to verify server
296339beb93cSSam Leffler 		 * certificate */
2964e28a4053SRui Paulo 		conn->ca_cert_verify = 0;
296539beb93cSSam Leffler 	}
296639beb93cSSam Leffler 
296739beb93cSSam Leffler 	return 0;
296839beb93cSSam Leffler }
296939beb93cSSam Leffler 
297039beb93cSSam Leffler 
tls_global_ca_cert(struct tls_data * data,const char * ca_cert)2971325151a3SRui Paulo static int tls_global_ca_cert(struct tls_data *data, const char *ca_cert)
297239beb93cSSam Leffler {
2973325151a3SRui Paulo 	SSL_CTX *ssl_ctx = data->ssl;
2974325151a3SRui Paulo 
297539beb93cSSam Leffler 	if (ca_cert) {
297639beb93cSSam Leffler 		if (SSL_CTX_load_verify_locations(ssl_ctx, ca_cert, NULL) != 1)
297739beb93cSSam Leffler 		{
297839beb93cSSam Leffler 			tls_show_errors(MSG_WARNING, __func__,
297939beb93cSSam Leffler 					"Failed to load root certificates");
298039beb93cSSam Leffler 			return -1;
298139beb93cSSam Leffler 		}
298239beb93cSSam Leffler 
298339beb93cSSam Leffler 		wpa_printf(MSG_DEBUG, "TLS: Trusted root "
298439beb93cSSam Leffler 			   "certificate(s) loaded");
298539beb93cSSam Leffler 
298639beb93cSSam Leffler #ifndef OPENSSL_NO_STDIO
298739beb93cSSam Leffler 		/* Add the same CAs to the client certificate requests */
298839beb93cSSam Leffler 		SSL_CTX_set_client_CA_list(ssl_ctx,
298939beb93cSSam Leffler 					   SSL_load_client_CA_file(ca_cert));
299039beb93cSSam Leffler #endif /* OPENSSL_NO_STDIO */
29914bc52338SCy Schubert 
29924bc52338SCy Schubert 		os_free(data->ca_cert);
29934bc52338SCy Schubert 		data->ca_cert = os_strdup(ca_cert);
299439beb93cSSam Leffler 	}
299539beb93cSSam Leffler 
299639beb93cSSam Leffler 	return 0;
299739beb93cSSam Leffler }
299839beb93cSSam Leffler 
299939beb93cSSam Leffler 
tls_global_set_verify(void * ssl_ctx,int check_crl,int strict)30004bc52338SCy Schubert int tls_global_set_verify(void *ssl_ctx, int check_crl, int strict)
300139beb93cSSam Leffler {
300239beb93cSSam Leffler 	int flags;
300339beb93cSSam Leffler 
300439beb93cSSam Leffler 	if (check_crl) {
3005325151a3SRui Paulo 		struct tls_data *data = ssl_ctx;
3006325151a3SRui Paulo 		X509_STORE *cs = SSL_CTX_get_cert_store(data->ssl);
300739beb93cSSam Leffler 		if (cs == NULL) {
300839beb93cSSam Leffler 			tls_show_errors(MSG_INFO, __func__, "Failed to get "
300939beb93cSSam Leffler 					"certificate store when enabling "
301039beb93cSSam Leffler 					"check_crl");
301139beb93cSSam Leffler 			return -1;
301239beb93cSSam Leffler 		}
301339beb93cSSam Leffler 		flags = X509_V_FLAG_CRL_CHECK;
301439beb93cSSam Leffler 		if (check_crl == 2)
301539beb93cSSam Leffler 			flags |= X509_V_FLAG_CRL_CHECK_ALL;
301639beb93cSSam Leffler 		X509_STORE_set_flags(cs, flags);
30174bc52338SCy Schubert 
30184bc52338SCy Schubert 		data->check_crl = check_crl;
30194bc52338SCy Schubert 		data->check_crl_strict = strict;
30204bc52338SCy Schubert 		os_get_reltime(&data->crl_last_reload);
302139beb93cSSam Leffler 	}
302239beb93cSSam Leffler 	return 0;
302339beb93cSSam Leffler }
302439beb93cSSam Leffler 
302539beb93cSSam Leffler 
tls_connection_set_subject_match(struct tls_connection * conn,const char * subject_match,const char * altsubject_match,const char * suffix_match,const char * domain_match,const char * check_cert_subject)302639beb93cSSam Leffler static int tls_connection_set_subject_match(struct tls_connection *conn,
302739beb93cSSam Leffler 					    const char *subject_match,
30285b9c547cSRui Paulo 					    const char *altsubject_match,
30295b9c547cSRui Paulo 					    const char *suffix_match,
30304bc52338SCy Schubert 					    const char *domain_match,
30314bc52338SCy Schubert 					    const char *check_cert_subject)
303239beb93cSSam Leffler {
303339beb93cSSam Leffler 	os_free(conn->subject_match);
303439beb93cSSam Leffler 	conn->subject_match = NULL;
303539beb93cSSam Leffler 	if (subject_match) {
303639beb93cSSam Leffler 		conn->subject_match = os_strdup(subject_match);
303739beb93cSSam Leffler 		if (conn->subject_match == NULL)
303839beb93cSSam Leffler 			return -1;
303939beb93cSSam Leffler 	}
304039beb93cSSam Leffler 
304139beb93cSSam Leffler 	os_free(conn->altsubject_match);
304239beb93cSSam Leffler 	conn->altsubject_match = NULL;
304339beb93cSSam Leffler 	if (altsubject_match) {
304439beb93cSSam Leffler 		conn->altsubject_match = os_strdup(altsubject_match);
304539beb93cSSam Leffler 		if (conn->altsubject_match == NULL)
304639beb93cSSam Leffler 			return -1;
304739beb93cSSam Leffler 	}
304839beb93cSSam Leffler 
30495b9c547cSRui Paulo 	os_free(conn->suffix_match);
30505b9c547cSRui Paulo 	conn->suffix_match = NULL;
30515b9c547cSRui Paulo 	if (suffix_match) {
30525b9c547cSRui Paulo 		conn->suffix_match = os_strdup(suffix_match);
30535b9c547cSRui Paulo 		if (conn->suffix_match == NULL)
30545b9c547cSRui Paulo 			return -1;
30555b9c547cSRui Paulo 	}
30565b9c547cSRui Paulo 
30575b9c547cSRui Paulo 	os_free(conn->domain_match);
30585b9c547cSRui Paulo 	conn->domain_match = NULL;
30595b9c547cSRui Paulo 	if (domain_match) {
30605b9c547cSRui Paulo 		conn->domain_match = os_strdup(domain_match);
30615b9c547cSRui Paulo 		if (conn->domain_match == NULL)
30625b9c547cSRui Paulo 			return -1;
30635b9c547cSRui Paulo 	}
30645b9c547cSRui Paulo 
30654bc52338SCy Schubert 	os_free(conn->check_cert_subject);
30664bc52338SCy Schubert 	conn->check_cert_subject = NULL;
30674bc52338SCy Schubert 	if (check_cert_subject) {
30684bc52338SCy Schubert 		conn->check_cert_subject = os_strdup(check_cert_subject);
30694bc52338SCy Schubert 		if (!conn->check_cert_subject)
30704bc52338SCy Schubert 			return -1;
30714bc52338SCy Schubert 	}
30724bc52338SCy Schubert 
307339beb93cSSam Leffler 	return 0;
307439beb93cSSam Leffler }
307539beb93cSSam Leffler 
307639beb93cSSam Leffler 
307785732ac8SCy Schubert #ifdef CONFIG_SUITEB
suiteb_cert_cb(SSL * ssl,void * arg)307885732ac8SCy Schubert static int suiteb_cert_cb(SSL *ssl, void *arg)
3079325151a3SRui Paulo {
308085732ac8SCy Schubert 	struct tls_connection *conn = arg;
308185732ac8SCy Schubert 
308285732ac8SCy Schubert 	/*
308385732ac8SCy Schubert 	 * This cert_cb() is not really the best location for doing a
308485732ac8SCy Schubert 	 * constraint check for the ServerKeyExchange message, but this seems to
308585732ac8SCy Schubert 	 * be the only place where the current OpenSSL sequence can be
308685732ac8SCy Schubert 	 * terminated cleanly with an TLS alert going out to the server.
308785732ac8SCy Schubert 	 */
308885732ac8SCy Schubert 
308985732ac8SCy Schubert 	if (!(conn->flags & TLS_CONN_SUITEB))
309085732ac8SCy Schubert 		return 1;
309185732ac8SCy Schubert 
309285732ac8SCy Schubert 	/* DHE is enabled only with DHE-RSA-AES256-GCM-SHA384 */
309385732ac8SCy Schubert 	if (conn->cipher_suite != 0x9f)
309485732ac8SCy Schubert 		return 1;
309585732ac8SCy Schubert 
309685732ac8SCy Schubert 	if (conn->server_dh_prime_len >= 3072)
309785732ac8SCy Schubert 		return 1;
309885732ac8SCy Schubert 
309985732ac8SCy Schubert 	wpa_printf(MSG_DEBUG,
310085732ac8SCy Schubert 		   "OpenSSL: Server DH prime length (%d bits) not sufficient for Suite B RSA - reject handshake",
310185732ac8SCy Schubert 		   conn->server_dh_prime_len);
310285732ac8SCy Schubert 	return 0;
310385732ac8SCy Schubert }
310485732ac8SCy Schubert #endif /* CONFIG_SUITEB */
310585732ac8SCy Schubert 
310685732ac8SCy Schubert 
tls_set_conn_flags(struct tls_connection * conn,unsigned int flags,const char * openssl_ciphers)310785732ac8SCy Schubert static int tls_set_conn_flags(struct tls_connection *conn, unsigned int flags,
310885732ac8SCy Schubert 			      const char *openssl_ciphers)
310985732ac8SCy Schubert {
311085732ac8SCy Schubert 	SSL *ssl = conn->ssl;
311185732ac8SCy Schubert 
3112325151a3SRui Paulo #ifdef SSL_OP_NO_TICKET
3113325151a3SRui Paulo 	if (flags & TLS_CONN_DISABLE_SESSION_TICKET)
3114325151a3SRui Paulo 		SSL_set_options(ssl, SSL_OP_NO_TICKET);
3115325151a3SRui Paulo 	else
3116325151a3SRui Paulo 		SSL_clear_options(ssl, SSL_OP_NO_TICKET);
3117325151a3SRui Paulo #endif /* SSL_OP_NO_TICKET */
3118325151a3SRui Paulo 
3119*a90b9d01SCy Schubert #ifdef SSL_OP_LEGACY_SERVER_CONNECT
3120*a90b9d01SCy Schubert 	if (flags & TLS_CONN_ALLOW_UNSAFE_RENEGOTIATION)
3121*a90b9d01SCy Schubert 		SSL_set_options(ssl, SSL_OP_LEGACY_SERVER_CONNECT);
3122*a90b9d01SCy Schubert #endif /* SSL_OP_LEGACY_SERVER_CONNECT */
3123*a90b9d01SCy Schubert 
3124325151a3SRui Paulo #ifdef SSL_OP_NO_TLSv1
3125325151a3SRui Paulo 	if (flags & TLS_CONN_DISABLE_TLSv1_0)
3126325151a3SRui Paulo 		SSL_set_options(ssl, SSL_OP_NO_TLSv1);
3127325151a3SRui Paulo 	else
3128325151a3SRui Paulo 		SSL_clear_options(ssl, SSL_OP_NO_TLSv1);
3129325151a3SRui Paulo #endif /* SSL_OP_NO_TLSv1 */
3130325151a3SRui Paulo #ifdef SSL_OP_NO_TLSv1_1
3131325151a3SRui Paulo 	if (flags & TLS_CONN_DISABLE_TLSv1_1)
3132325151a3SRui Paulo 		SSL_set_options(ssl, SSL_OP_NO_TLSv1_1);
3133325151a3SRui Paulo 	else
3134325151a3SRui Paulo 		SSL_clear_options(ssl, SSL_OP_NO_TLSv1_1);
3135325151a3SRui Paulo #endif /* SSL_OP_NO_TLSv1_1 */
3136325151a3SRui Paulo #ifdef SSL_OP_NO_TLSv1_2
3137325151a3SRui Paulo 	if (flags & TLS_CONN_DISABLE_TLSv1_2)
3138325151a3SRui Paulo 		SSL_set_options(ssl, SSL_OP_NO_TLSv1_2);
3139325151a3SRui Paulo 	else
3140325151a3SRui Paulo 		SSL_clear_options(ssl, SSL_OP_NO_TLSv1_2);
3141325151a3SRui Paulo #endif /* SSL_OP_NO_TLSv1_2 */
314285732ac8SCy Schubert #ifdef SSL_OP_NO_TLSv1_3
314385732ac8SCy Schubert 	if (flags & TLS_CONN_DISABLE_TLSv1_3)
314485732ac8SCy Schubert 		SSL_set_options(ssl, SSL_OP_NO_TLSv1_3);
314585732ac8SCy Schubert 	else
314685732ac8SCy Schubert 		SSL_clear_options(ssl, SSL_OP_NO_TLSv1_3);
314785732ac8SCy Schubert #endif /* SSL_OP_NO_TLSv1_3 */
31484bc52338SCy Schubert #if OPENSSL_VERSION_NUMBER >= 0x10100000L
31494bc52338SCy Schubert 	if (flags & (TLS_CONN_ENABLE_TLSv1_0 |
31504bc52338SCy Schubert 		     TLS_CONN_ENABLE_TLSv1_1 |
31514bc52338SCy Schubert 		     TLS_CONN_ENABLE_TLSv1_2)) {
31524bc52338SCy Schubert 		int version = 0;
31534bc52338SCy Schubert 
31544bc52338SCy Schubert 		/* Explicit request to enable TLS versions even if needing to
31554bc52338SCy Schubert 		 * override systemwide policies. */
3156c1d255d3SCy Schubert 		if (flags & TLS_CONN_ENABLE_TLSv1_0)
31574bc52338SCy Schubert 			version = TLS1_VERSION;
3158c1d255d3SCy Schubert 		else if (flags & TLS_CONN_ENABLE_TLSv1_1)
31594bc52338SCy Schubert 			version = TLS1_1_VERSION;
3160c1d255d3SCy Schubert 		else if (flags & TLS_CONN_ENABLE_TLSv1_2)
31614bc52338SCy Schubert 			version = TLS1_2_VERSION;
31624bc52338SCy Schubert 		if (!version) {
31634bc52338SCy Schubert 			wpa_printf(MSG_DEBUG,
31644bc52338SCy Schubert 				   "OpenSSL: Invalid TLS version configuration");
31654bc52338SCy Schubert 			return -1;
31664bc52338SCy Schubert 		}
31674bc52338SCy Schubert 
31684bc52338SCy Schubert 		if (SSL_set_min_proto_version(ssl, version) != 1) {
31694bc52338SCy Schubert 			wpa_printf(MSG_DEBUG,
31704bc52338SCy Schubert 				   "OpenSSL: Failed to set minimum TLS version");
31714bc52338SCy Schubert 			return -1;
31724bc52338SCy Schubert 		}
31734bc52338SCy Schubert 	}
31744bc52338SCy Schubert #endif /* >= 1.1.0 */
3175c1d255d3SCy Schubert #if OPENSSL_VERSION_NUMBER >= 0x10100000L && \
3176c1d255d3SCy Schubert 	!defined(LIBRESSL_VERSION_NUMBER) && \
3177c1d255d3SCy Schubert 	!defined(OPENSSL_IS_BORINGSSL)
3178ec080394SCy Schubert 	{
3179ec080394SCy Schubert #if OPENSSL_VERSION_NUMBER >= 0x30000000L
3180ec080394SCy Schubert 		int need_level = 0;
3181ec080394SCy Schubert #else
3182ec080394SCy Schubert 		int need_level = 1;
3183ec080394SCy Schubert #endif
3184ec080394SCy Schubert 
3185ec080394SCy Schubert 		if ((flags &
3186ec080394SCy Schubert 		     (TLS_CONN_ENABLE_TLSv1_0 | TLS_CONN_ENABLE_TLSv1_1)) &&
3187ec080394SCy Schubert 		    SSL_get_security_level(ssl) > need_level) {
3188c1d255d3SCy Schubert 			/*
3189ec080394SCy Schubert 			 * Need to drop to security level 1 (or 0  with OpenSSL
3190ec080394SCy Schubert 			 * 3.0) to allow TLS versions older than 1.2 to be used
3191ec080394SCy Schubert 			 * when explicitly enabled in configuration.
3192c1d255d3SCy Schubert 			 */
3193ec080394SCy Schubert 			SSL_set_security_level(conn->ssl, need_level);
3194ec080394SCy Schubert 		}
3195c1d255d3SCy Schubert 	}
3196c1d255d3SCy Schubert #endif
31974bc52338SCy Schubert 
3198*a90b9d01SCy Schubert 	if (!openssl_ciphers)
3199*a90b9d01SCy Schubert 		openssl_ciphers = conn->data->openssl_ciphers;
3200*a90b9d01SCy Schubert 
320185732ac8SCy Schubert #ifdef CONFIG_SUITEB
320285732ac8SCy Schubert #ifdef OPENSSL_IS_BORINGSSL
320385732ac8SCy Schubert 	/* Start with defaults from BoringSSL */
320485732ac8SCy Schubert 	SSL_CTX_set_verify_algorithm_prefs(conn->ssl_ctx, NULL, 0);
320585732ac8SCy Schubert #endif /* OPENSSL_IS_BORINGSSL */
320685732ac8SCy Schubert 	if (flags & TLS_CONN_SUITEB_NO_ECDH) {
320785732ac8SCy Schubert 		const char *ciphers = "DHE-RSA-AES256-GCM-SHA384";
320885732ac8SCy Schubert 
320985732ac8SCy Schubert 		if (openssl_ciphers) {
321085732ac8SCy Schubert 			wpa_printf(MSG_DEBUG,
321185732ac8SCy Schubert 				   "OpenSSL: Override ciphers for Suite B (no ECDH): %s",
321285732ac8SCy Schubert 				   openssl_ciphers);
321385732ac8SCy Schubert 			ciphers = openssl_ciphers;
321485732ac8SCy Schubert 		}
321585732ac8SCy Schubert 		if (SSL_set_cipher_list(ssl, ciphers) != 1) {
321685732ac8SCy Schubert 			wpa_printf(MSG_INFO,
321785732ac8SCy Schubert 				   "OpenSSL: Failed to set Suite B ciphers");
321885732ac8SCy Schubert 			return -1;
321985732ac8SCy Schubert 		}
322085732ac8SCy Schubert 	} else if (flags & TLS_CONN_SUITEB) {
3221*a90b9d01SCy Schubert #if OPENSSL_VERSION_NUMBER < 0x30000000L
322285732ac8SCy Schubert 		EC_KEY *ecdh;
3223*a90b9d01SCy Schubert #endif
322485732ac8SCy Schubert 		const char *ciphers =
322585732ac8SCy Schubert 			"ECDHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES256-GCM-SHA384";
322685732ac8SCy Schubert 		int nid[1] = { NID_secp384r1 };
322785732ac8SCy Schubert 
322885732ac8SCy Schubert 		if (openssl_ciphers) {
322985732ac8SCy Schubert 			wpa_printf(MSG_DEBUG,
323085732ac8SCy Schubert 				   "OpenSSL: Override ciphers for Suite B: %s",
323185732ac8SCy Schubert 				   openssl_ciphers);
323285732ac8SCy Schubert 			ciphers = openssl_ciphers;
323385732ac8SCy Schubert 		}
323485732ac8SCy Schubert 		if (SSL_set_cipher_list(ssl, ciphers) != 1) {
323585732ac8SCy Schubert 			wpa_printf(MSG_INFO,
323685732ac8SCy Schubert 				   "OpenSSL: Failed to set Suite B ciphers");
323785732ac8SCy Schubert 			return -1;
323885732ac8SCy Schubert 		}
323985732ac8SCy Schubert 
3240*a90b9d01SCy Schubert #if OPENSSL_VERSION_NUMBER >= 0x30000000L
3241*a90b9d01SCy Schubert 		if (SSL_set1_groups(ssl, nid, 1) != 1) {
3242*a90b9d01SCy Schubert 			wpa_printf(MSG_INFO,
3243*a90b9d01SCy Schubert 				   "OpenSSL: Failed to set Suite B groups");
3244*a90b9d01SCy Schubert 			return -1;
3245*a90b9d01SCy Schubert 		}
3246*a90b9d01SCy Schubert 
3247*a90b9d01SCy Schubert #else
324885732ac8SCy Schubert 		if (SSL_set1_curves(ssl, nid, 1) != 1) {
324985732ac8SCy Schubert 			wpa_printf(MSG_INFO,
325085732ac8SCy Schubert 				   "OpenSSL: Failed to set Suite B curves");
325185732ac8SCy Schubert 			return -1;
325285732ac8SCy Schubert 		}
325385732ac8SCy Schubert 
325485732ac8SCy Schubert 		ecdh = EC_KEY_new_by_curve_name(NID_secp384r1);
325585732ac8SCy Schubert 		if (!ecdh || SSL_set_tmp_ecdh(ssl, ecdh) != 1) {
325685732ac8SCy Schubert 			EC_KEY_free(ecdh);
325785732ac8SCy Schubert 			wpa_printf(MSG_INFO,
325885732ac8SCy Schubert 				   "OpenSSL: Failed to set ECDH parameter");
325985732ac8SCy Schubert 			return -1;
326085732ac8SCy Schubert 		}
326185732ac8SCy Schubert 		EC_KEY_free(ecdh);
3262*a90b9d01SCy Schubert #endif
326385732ac8SCy Schubert 	}
326485732ac8SCy Schubert 	if (flags & (TLS_CONN_SUITEB | TLS_CONN_SUITEB_NO_ECDH)) {
326585732ac8SCy Schubert #ifdef OPENSSL_IS_BORINGSSL
3266*a90b9d01SCy Schubert 		uint16_t sigalgs[3] = { SSL_SIGN_RSA_PKCS1_SHA384 };
3267*a90b9d01SCy Schubert 		int num = 1;
3268*a90b9d01SCy Schubert 
3269*a90b9d01SCy Schubert 		if (!(flags & TLS_CONN_DISABLE_TLSv1_3)) {
3270*a90b9d01SCy Schubert #ifdef SSL_SIGN_ECDSA_SECP384R1_SHA384
3271*a90b9d01SCy Schubert 			sigalgs[num++] = SSL_SIGN_ECDSA_SECP384R1_SHA384;
3272*a90b9d01SCy Schubert #endif
3273*a90b9d01SCy Schubert #ifdef SSL_SIGN_RSA_PSS_RSAE_SHA384
3274*a90b9d01SCy Schubert 			sigalgs[num++] = SSL_SIGN_RSA_PSS_RSAE_SHA384;
3275*a90b9d01SCy Schubert #endif
3276*a90b9d01SCy Schubert 		}
327785732ac8SCy Schubert 
327885732ac8SCy Schubert 		if (SSL_CTX_set_verify_algorithm_prefs(conn->ssl_ctx, sigalgs,
3279*a90b9d01SCy Schubert 						       num) != 1) {
328085732ac8SCy Schubert 			wpa_printf(MSG_INFO,
328185732ac8SCy Schubert 				   "OpenSSL: Failed to set Suite B sigalgs");
328285732ac8SCy Schubert 			return -1;
328385732ac8SCy Schubert 		}
328485732ac8SCy Schubert #else /* OPENSSL_IS_BORINGSSL */
328585732ac8SCy Schubert 		/* ECDSA+SHA384 if need to add EC support here */
3286*a90b9d01SCy Schubert 		const char *algs = "RSA+SHA384";
3287*a90b9d01SCy Schubert 
3288*a90b9d01SCy Schubert 		if (!(flags & TLS_CONN_DISABLE_TLSv1_3))
3289*a90b9d01SCy Schubert 			algs = "RSA+SHA384:ecdsa_secp384r1_sha384:rsa_pss_rsae_sha384";
3290*a90b9d01SCy Schubert 		if (SSL_set1_sigalgs_list(ssl, algs) != 1) {
329185732ac8SCy Schubert 			wpa_printf(MSG_INFO,
329285732ac8SCy Schubert 				   "OpenSSL: Failed to set Suite B sigalgs");
329385732ac8SCy Schubert 			return -1;
329485732ac8SCy Schubert 		}
329585732ac8SCy Schubert #endif /* OPENSSL_IS_BORINGSSL */
329685732ac8SCy Schubert 
329785732ac8SCy Schubert 		SSL_set_options(ssl, SSL_OP_NO_TLSv1);
329885732ac8SCy Schubert 		SSL_set_options(ssl, SSL_OP_NO_TLSv1_1);
329985732ac8SCy Schubert 		SSL_set_cert_cb(ssl, suiteb_cert_cb, conn);
330085732ac8SCy Schubert 	}
330185732ac8SCy Schubert 
330285732ac8SCy Schubert #ifdef OPENSSL_IS_BORINGSSL
330385732ac8SCy Schubert 	if (openssl_ciphers && os_strcmp(openssl_ciphers, "SUITEB192") == 0) {
330485732ac8SCy Schubert 		uint16_t sigalgs[1] = { SSL_SIGN_ECDSA_SECP384R1_SHA384 };
330585732ac8SCy Schubert 		int nid[1] = { NID_secp384r1 };
330685732ac8SCy Schubert 
330785732ac8SCy Schubert 		if (SSL_set1_curves(ssl, nid, 1) != 1) {
330885732ac8SCy Schubert 			wpa_printf(MSG_INFO,
330985732ac8SCy Schubert 				   "OpenSSL: Failed to set Suite B curves");
331085732ac8SCy Schubert 			return -1;
331185732ac8SCy Schubert 		}
331285732ac8SCy Schubert 
331385732ac8SCy Schubert 		if (SSL_CTX_set_verify_algorithm_prefs(conn->ssl_ctx, sigalgs,
331485732ac8SCy Schubert 						       1) != 1) {
331585732ac8SCy Schubert 			wpa_printf(MSG_INFO,
331685732ac8SCy Schubert 				   "OpenSSL: Failed to set Suite B sigalgs");
331785732ac8SCy Schubert 			return -1;
331885732ac8SCy Schubert 		}
331985732ac8SCy Schubert 	}
33204bc52338SCy Schubert #else /* OPENSSL_IS_BORINGSSL */
33214bc52338SCy Schubert 	if (!(flags & (TLS_CONN_SUITEB | TLS_CONN_SUITEB_NO_ECDH)) &&
33224bc52338SCy Schubert 	    openssl_ciphers && SSL_set_cipher_list(ssl, openssl_ciphers) != 1) {
33234bc52338SCy Schubert 		wpa_printf(MSG_INFO,
33244bc52338SCy Schubert 			   "OpenSSL: Failed to set openssl_ciphers '%s'",
33254bc52338SCy Schubert 			   openssl_ciphers);
33264bc52338SCy Schubert 		return -1;
33274bc52338SCy Schubert 	}
332885732ac8SCy Schubert #endif /* OPENSSL_IS_BORINGSSL */
33294bc52338SCy Schubert #else /* CONFIG_SUITEB */
33304bc52338SCy Schubert 	if (openssl_ciphers && SSL_set_cipher_list(ssl, openssl_ciphers) != 1) {
33314bc52338SCy Schubert 		wpa_printf(MSG_INFO,
33324bc52338SCy Schubert 			   "OpenSSL: Failed to set openssl_ciphers '%s'",
33334bc52338SCy Schubert 			   openssl_ciphers);
33344bc52338SCy Schubert 		return -1;
33354bc52338SCy Schubert 	}
333685732ac8SCy Schubert #endif /* CONFIG_SUITEB */
333785732ac8SCy Schubert 
3338206b73d0SCy Schubert 	if (flags & TLS_CONN_TEAP_ANON_DH) {
3339206b73d0SCy Schubert #ifndef TEAP_DH_ANON_CS
3340206b73d0SCy Schubert #define TEAP_DH_ANON_CS \
3341206b73d0SCy Schubert 	"ECDHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES128-GCM-SHA256:" \
3342206b73d0SCy Schubert 	"ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES128-SHA256:" \
3343206b73d0SCy Schubert 	"ECDHE-RSA-AES256-SHA:ECDHE-RSA-AES128-SHA:" \
3344206b73d0SCy Schubert 	"DHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:" \
3345206b73d0SCy Schubert 	"DHE-RSA-AES256-SHA256:DHE-RSA-AES128-SHA256:" \
3346206b73d0SCy Schubert 	"DHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA:" \
3347206b73d0SCy Schubert 	"ADH-AES256-GCM-SHA384:ADH-AES128-GCM-SHA256:" \
3348206b73d0SCy Schubert 	"ADH-AES256-SHA256:ADH-AES128-SHA256:ADH-AES256-SHA:ADH-AES128-SHA"
3349206b73d0SCy Schubert #endif
3350206b73d0SCy Schubert 		static const char *cs = TEAP_DH_ANON_CS;
3351206b73d0SCy Schubert 
3352206b73d0SCy Schubert #if OPENSSL_VERSION_NUMBER >= 0x10100000L && \
3353206b73d0SCy Schubert 	!defined(LIBRESSL_VERSION_NUMBER) && \
3354206b73d0SCy Schubert 	!defined(OPENSSL_IS_BORINGSSL)
3355206b73d0SCy Schubert 		/*
3356206b73d0SCy Schubert 		 * Need to drop to security level 0 to allow anonymous
3357206b73d0SCy Schubert 		 * cipher suites for EAP-TEAP.
3358206b73d0SCy Schubert 		 */
3359206b73d0SCy Schubert 		SSL_set_security_level(conn->ssl, 0);
3360206b73d0SCy Schubert #endif
3361206b73d0SCy Schubert 
3362206b73d0SCy Schubert 		wpa_printf(MSG_DEBUG,
3363206b73d0SCy Schubert 			   "OpenSSL: Enable cipher suites for anonymous EAP-TEAP provisioning: %s",
3364206b73d0SCy Schubert 			   cs);
3365206b73d0SCy Schubert 		if (SSL_set_cipher_list(conn->ssl, cs) != 1) {
3366206b73d0SCy Schubert 			tls_show_errors(MSG_INFO, __func__,
3367206b73d0SCy Schubert 					"Cipher suite configuration failed");
3368206b73d0SCy Schubert 			return -1;
3369206b73d0SCy Schubert 		}
3370206b73d0SCy Schubert 	}
3371206b73d0SCy Schubert 
337285732ac8SCy Schubert 	return 0;
3373325151a3SRui Paulo }
3374325151a3SRui Paulo 
3375325151a3SRui Paulo 
tls_connection_set_verify(void * ssl_ctx,struct tls_connection * conn,int verify_peer,unsigned int flags,const u8 * session_ctx,size_t session_ctx_len)337639beb93cSSam Leffler int tls_connection_set_verify(void *ssl_ctx, struct tls_connection *conn,
3377325151a3SRui Paulo 			      int verify_peer, unsigned int flags,
3378325151a3SRui Paulo 			      const u8 *session_ctx, size_t session_ctx_len)
337939beb93cSSam Leffler {
338039beb93cSSam Leffler 	static int counter = 0;
3381325151a3SRui Paulo 	struct tls_data *data = ssl_ctx;
338239beb93cSSam Leffler 
338339beb93cSSam Leffler 	if (conn == NULL)
338439beb93cSSam Leffler 		return -1;
338539beb93cSSam Leffler 
3386c1d255d3SCy Schubert 	if (verify_peer == 2) {
3387c1d255d3SCy Schubert 		conn->ca_cert_verify = 1;
3388c1d255d3SCy Schubert 		SSL_set_verify(conn->ssl, SSL_VERIFY_PEER |
3389c1d255d3SCy Schubert 			       SSL_VERIFY_CLIENT_ONCE, tls_verify_cb);
3390c1d255d3SCy Schubert 	} else if (verify_peer) {
3391e28a4053SRui Paulo 		conn->ca_cert_verify = 1;
339239beb93cSSam Leffler 		SSL_set_verify(conn->ssl, SSL_VERIFY_PEER |
339339beb93cSSam Leffler 			       SSL_VERIFY_FAIL_IF_NO_PEER_CERT |
339439beb93cSSam Leffler 			       SSL_VERIFY_CLIENT_ONCE, tls_verify_cb);
339539beb93cSSam Leffler 	} else {
3396e28a4053SRui Paulo 		conn->ca_cert_verify = 0;
339739beb93cSSam Leffler 		SSL_set_verify(conn->ssl, SSL_VERIFY_NONE, NULL);
339839beb93cSSam Leffler 	}
339939beb93cSSam Leffler 
340085732ac8SCy Schubert 	if (tls_set_conn_flags(conn, flags, NULL) < 0)
340185732ac8SCy Schubert 		return -1;
3402325151a3SRui Paulo 	conn->flags = flags;
3403325151a3SRui Paulo 
340439beb93cSSam Leffler 	SSL_set_accept_state(conn->ssl);
340539beb93cSSam Leffler 
3406325151a3SRui Paulo 	if (data->tls_session_lifetime == 0) {
340739beb93cSSam Leffler 		/*
3408325151a3SRui Paulo 		 * Set session id context to a unique value to make sure
3409325151a3SRui Paulo 		 * session resumption cannot be used either through session
3410325151a3SRui Paulo 		 * caching or TLS ticket extension.
341139beb93cSSam Leffler 		 */
341239beb93cSSam Leffler 		counter++;
341339beb93cSSam Leffler 		SSL_set_session_id_context(conn->ssl,
341439beb93cSSam Leffler 					   (const unsigned char *) &counter,
341539beb93cSSam Leffler 					   sizeof(counter));
3416325151a3SRui Paulo 	} else if (session_ctx) {
3417325151a3SRui Paulo 		SSL_set_session_id_context(conn->ssl, session_ctx,
3418325151a3SRui Paulo 					   session_ctx_len);
3419325151a3SRui Paulo 	}
342039beb93cSSam Leffler 
342139beb93cSSam Leffler 	return 0;
342239beb93cSSam Leffler }
342339beb93cSSam Leffler 
342439beb93cSSam Leffler 
tls_connection_client_cert(struct tls_connection * conn,const char * client_cert,const u8 * client_cert_blob,size_t client_cert_blob_len)342539beb93cSSam Leffler static int tls_connection_client_cert(struct tls_connection *conn,
342639beb93cSSam Leffler 				      const char *client_cert,
342739beb93cSSam Leffler 				      const u8 *client_cert_blob,
342839beb93cSSam Leffler 				      size_t client_cert_blob_len)
342939beb93cSSam Leffler {
343039beb93cSSam Leffler 	if (client_cert == NULL && client_cert_blob == NULL)
343139beb93cSSam Leffler 		return 0;
343239beb93cSSam Leffler 
3433780fb4a2SCy Schubert #ifdef PKCS12_FUNCS
3434*a90b9d01SCy Schubert #ifdef LIBRESSL_VERSION_NUMBER
3435780fb4a2SCy Schubert 	/*
3436780fb4a2SCy Schubert 	 * Clear previously set extra chain certificates, if any, from PKCS#12
3437*a90b9d01SCy Schubert 	 * processing in tls_parse_pkcs12() to allow LibreSSL to build a new
3438780fb4a2SCy Schubert 	 * chain properly.
3439780fb4a2SCy Schubert 	 */
3440780fb4a2SCy Schubert 	SSL_CTX_clear_extra_chain_certs(conn->ssl_ctx);
3441*a90b9d01SCy Schubert #endif /* LIBRESSL_VERSION_NUMBER */
3442780fb4a2SCy Schubert #endif /* PKCS12_FUNCS */
3443780fb4a2SCy Schubert 
344439beb93cSSam Leffler 	if (client_cert_blob &&
344539beb93cSSam Leffler 	    SSL_use_certificate_ASN1(conn->ssl, (u8 *) client_cert_blob,
344639beb93cSSam Leffler 				     client_cert_blob_len) == 1) {
344739beb93cSSam Leffler 		wpa_printf(MSG_DEBUG, "OpenSSL: SSL_use_certificate_ASN1 --> "
344839beb93cSSam Leffler 			   "OK");
344939beb93cSSam Leffler 		return 0;
345039beb93cSSam Leffler 	} else if (client_cert_blob) {
3451c1d255d3SCy Schubert #if defined(LIBRESSL_VERSION_NUMBER) && LIBRESSL_VERSION_NUMBER < 0x20901000L
345239beb93cSSam Leffler 		tls_show_errors(MSG_DEBUG, __func__,
345339beb93cSSam Leffler 				"SSL_use_certificate_ASN1 failed");
3454c1d255d3SCy Schubert #else
3455c1d255d3SCy Schubert 		BIO *bio;
3456c1d255d3SCy Schubert 		X509 *x509;
3457c1d255d3SCy Schubert 
3458c1d255d3SCy Schubert 		tls_show_errors(MSG_DEBUG, __func__,
3459c1d255d3SCy Schubert 				"SSL_use_certificate_ASN1 failed");
3460c1d255d3SCy Schubert 		bio = BIO_new(BIO_s_mem());
3461c1d255d3SCy Schubert 		if (!bio)
3462c1d255d3SCy Schubert 			return -1;
3463c1d255d3SCy Schubert 		BIO_write(bio, client_cert_blob, client_cert_blob_len);
3464c1d255d3SCy Schubert 		x509 = PEM_read_bio_X509(bio, NULL, NULL, NULL);
3465c1d255d3SCy Schubert 		if (!x509 || SSL_use_certificate(conn->ssl, x509) != 1) {
3466c1d255d3SCy Schubert 			X509_free(x509);
3467c1d255d3SCy Schubert 			BIO_free(bio);
3468c1d255d3SCy Schubert 			return -1;
3469c1d255d3SCy Schubert 		}
3470c1d255d3SCy Schubert 		X509_free(x509);
3471c1d255d3SCy Schubert 		wpa_printf(MSG_DEBUG,
3472c1d255d3SCy Schubert 			   "OpenSSL: Found PEM encoded certificate from blob");
3473c1d255d3SCy Schubert 		while ((x509 = PEM_read_bio_X509(bio, NULL, NULL, NULL))) {
3474c1d255d3SCy Schubert 			wpa_printf(MSG_DEBUG,
3475c1d255d3SCy Schubert 				   "OpenSSL: Added an additional certificate into the chain");
3476c1d255d3SCy Schubert 			SSL_add0_chain_cert(conn->ssl, x509);
3477c1d255d3SCy Schubert 		}
3478c1d255d3SCy Schubert 		BIO_free(bio);
3479c1d255d3SCy Schubert 		return 0;
3480c1d255d3SCy Schubert #endif
348139beb93cSSam Leffler 	}
348239beb93cSSam Leffler 
348339beb93cSSam Leffler 	if (client_cert == NULL)
348439beb93cSSam Leffler 		return -1;
348539beb93cSSam Leffler 
3486f05cddf9SRui Paulo #ifdef ANDROID
3487f05cddf9SRui Paulo 	if (os_strncmp("keystore://", client_cert, 11) == 0) {
3488f05cddf9SRui Paulo 		BIO *bio = BIO_from_keystore(&client_cert[11]);
3489f05cddf9SRui Paulo 		X509 *x509 = NULL;
3490f05cddf9SRui Paulo 		int ret = -1;
3491f05cddf9SRui Paulo 		if (bio) {
3492f05cddf9SRui Paulo 			x509 = PEM_read_bio_X509(bio, NULL, NULL, NULL);
3493f05cddf9SRui Paulo 		}
3494f05cddf9SRui Paulo 		if (x509) {
3495f05cddf9SRui Paulo 			if (SSL_use_certificate(conn->ssl, x509) == 1)
3496f05cddf9SRui Paulo 				ret = 0;
3497f05cddf9SRui Paulo 			X509_free(x509);
3498f05cddf9SRui Paulo 		}
349985732ac8SCy Schubert 
350085732ac8SCy Schubert 		/* Read additional certificates into the chain. */
350185732ac8SCy Schubert 		while (bio) {
350285732ac8SCy Schubert 			x509 = PEM_read_bio_X509(bio, NULL, NULL, NULL);
350385732ac8SCy Schubert 			if (x509) {
350485732ac8SCy Schubert 				/* Takes ownership of x509 */
350585732ac8SCy Schubert 				SSL_add0_chain_cert(conn->ssl, x509);
350685732ac8SCy Schubert 			} else {
350785732ac8SCy Schubert 				BIO_free(bio);
350885732ac8SCy Schubert 				bio = NULL;
350985732ac8SCy Schubert 			}
351085732ac8SCy Schubert 		}
3511f05cddf9SRui Paulo 		return ret;
3512f05cddf9SRui Paulo 	}
3513f05cddf9SRui Paulo #endif /* ANDROID */
3514f05cddf9SRui Paulo 
351539beb93cSSam Leffler #ifndef OPENSSL_NO_STDIO
351639beb93cSSam Leffler 	if (SSL_use_certificate_file(conn->ssl, client_cert,
351739beb93cSSam Leffler 				     SSL_FILETYPE_ASN1) == 1) {
351839beb93cSSam Leffler 		wpa_printf(MSG_DEBUG, "OpenSSL: SSL_use_certificate_file (DER)"
351939beb93cSSam Leffler 			   " --> OK");
352039beb93cSSam Leffler 		return 0;
352139beb93cSSam Leffler 	}
352239beb93cSSam Leffler 
35234bc52338SCy Schubert #if OPENSSL_VERSION_NUMBER >= 0x10100000L && \
35244bc52338SCy Schubert 	!defined(LIBRESSL_VERSION_NUMBER) && !defined(OPENSSL_IS_BORINGSSL)
35254bc52338SCy Schubert 	if (SSL_use_certificate_chain_file(conn->ssl, client_cert) == 1) {
35264bc52338SCy Schubert 		ERR_clear_error();
35274bc52338SCy Schubert 		wpa_printf(MSG_DEBUG, "OpenSSL: SSL_use_certificate_chain_file"
35284bc52338SCy Schubert 			   " --> OK");
35294bc52338SCy Schubert 		return 0;
35304bc52338SCy Schubert 	}
35314bc52338SCy Schubert #else
353239beb93cSSam Leffler 	if (SSL_use_certificate_file(conn->ssl, client_cert,
353339beb93cSSam Leffler 				     SSL_FILETYPE_PEM) == 1) {
3534f05cddf9SRui Paulo 		ERR_clear_error();
353539beb93cSSam Leffler 		wpa_printf(MSG_DEBUG, "OpenSSL: SSL_use_certificate_file (PEM)"
353639beb93cSSam Leffler 			   " --> OK");
353739beb93cSSam Leffler 		return 0;
353839beb93cSSam Leffler 	}
35394bc52338SCy Schubert #endif
3540f05cddf9SRui Paulo 
3541f05cddf9SRui Paulo 	tls_show_errors(MSG_DEBUG, __func__,
3542f05cddf9SRui Paulo 			"SSL_use_certificate_file failed");
354339beb93cSSam Leffler #else /* OPENSSL_NO_STDIO */
354439beb93cSSam Leffler 	wpa_printf(MSG_DEBUG, "OpenSSL: %s - OPENSSL_NO_STDIO", __func__);
354539beb93cSSam Leffler #endif /* OPENSSL_NO_STDIO */
354639beb93cSSam Leffler 
354739beb93cSSam Leffler 	return -1;
354839beb93cSSam Leffler }
354939beb93cSSam Leffler 
355039beb93cSSam Leffler 
tls_global_client_cert(struct tls_data * data,const char * client_cert)3551325151a3SRui Paulo static int tls_global_client_cert(struct tls_data *data,
3552325151a3SRui Paulo 				  const char *client_cert)
355339beb93cSSam Leffler {
355439beb93cSSam Leffler #ifndef OPENSSL_NO_STDIO
3555325151a3SRui Paulo 	SSL_CTX *ssl_ctx = data->ssl;
3556325151a3SRui Paulo 
355739beb93cSSam Leffler 	if (client_cert == NULL)
355839beb93cSSam Leffler 		return 0;
355939beb93cSSam Leffler 
356039beb93cSSam Leffler 	if (SSL_CTX_use_certificate_file(ssl_ctx, client_cert,
356139beb93cSSam Leffler 					 SSL_FILETYPE_ASN1) != 1 &&
3562f05cddf9SRui Paulo 	    SSL_CTX_use_certificate_chain_file(ssl_ctx, client_cert) != 1 &&
356339beb93cSSam Leffler 	    SSL_CTX_use_certificate_file(ssl_ctx, client_cert,
356439beb93cSSam Leffler 					 SSL_FILETYPE_PEM) != 1) {
356539beb93cSSam Leffler 		tls_show_errors(MSG_INFO, __func__,
356639beb93cSSam Leffler 				"Failed to load client certificate");
356739beb93cSSam Leffler 		return -1;
356839beb93cSSam Leffler 	}
356939beb93cSSam Leffler 	return 0;
357039beb93cSSam Leffler #else /* OPENSSL_NO_STDIO */
357139beb93cSSam Leffler 	if (client_cert == NULL)
357239beb93cSSam Leffler 		return 0;
357339beb93cSSam Leffler 	wpa_printf(MSG_DEBUG, "OpenSSL: %s - OPENSSL_NO_STDIO", __func__);
357439beb93cSSam Leffler 	return -1;
357539beb93cSSam Leffler #endif /* OPENSSL_NO_STDIO */
357639beb93cSSam Leffler }
357739beb93cSSam Leffler 
357839beb93cSSam Leffler 
357939beb93cSSam Leffler #ifdef PKCS12_FUNCS
tls_parse_pkcs12(struct tls_data * data,SSL * ssl,PKCS12 * p12,const char * passwd)3580325151a3SRui Paulo static int tls_parse_pkcs12(struct tls_data *data, SSL *ssl, PKCS12 *p12,
358139beb93cSSam Leffler 			    const char *passwd)
358239beb93cSSam Leffler {
358339beb93cSSam Leffler 	EVP_PKEY *pkey;
358439beb93cSSam Leffler 	X509 *cert;
358539beb93cSSam Leffler 	STACK_OF(X509) *certs;
358639beb93cSSam Leffler 	int res = 0;
358739beb93cSSam Leffler 	char buf[256];
358839beb93cSSam Leffler 
358939beb93cSSam Leffler 	pkey = NULL;
359039beb93cSSam Leffler 	cert = NULL;
359139beb93cSSam Leffler 	certs = NULL;
3592325151a3SRui Paulo 	if (!passwd)
3593325151a3SRui Paulo 		passwd = "";
359439beb93cSSam Leffler 	if (!PKCS12_parse(p12, passwd, &pkey, &cert, &certs)) {
359539beb93cSSam Leffler 		tls_show_errors(MSG_DEBUG, __func__,
359639beb93cSSam Leffler 				"Failed to parse PKCS12 file");
359739beb93cSSam Leffler 		PKCS12_free(p12);
359839beb93cSSam Leffler 		return -1;
359939beb93cSSam Leffler 	}
360039beb93cSSam Leffler 	wpa_printf(MSG_DEBUG, "TLS: Successfully parsed PKCS12 data");
360139beb93cSSam Leffler 
360239beb93cSSam Leffler 	if (cert) {
360339beb93cSSam Leffler 		X509_NAME_oneline(X509_get_subject_name(cert), buf,
360439beb93cSSam Leffler 				  sizeof(buf));
360539beb93cSSam Leffler 		wpa_printf(MSG_DEBUG, "TLS: Got certificate from PKCS12: "
360639beb93cSSam Leffler 			   "subject='%s'", buf);
360739beb93cSSam Leffler 		if (ssl) {
360839beb93cSSam Leffler 			if (SSL_use_certificate(ssl, cert) != 1)
360939beb93cSSam Leffler 				res = -1;
361039beb93cSSam Leffler 		} else {
3611325151a3SRui Paulo 			if (SSL_CTX_use_certificate(data->ssl, cert) != 1)
361239beb93cSSam Leffler 				res = -1;
361339beb93cSSam Leffler 		}
361439beb93cSSam Leffler 		X509_free(cert);
361539beb93cSSam Leffler 	}
361639beb93cSSam Leffler 
361739beb93cSSam Leffler 	if (pkey) {
361839beb93cSSam Leffler 		wpa_printf(MSG_DEBUG, "TLS: Got private key from PKCS12");
361939beb93cSSam Leffler 		if (ssl) {
362039beb93cSSam Leffler 			if (SSL_use_PrivateKey(ssl, pkey) != 1)
362139beb93cSSam Leffler 				res = -1;
362239beb93cSSam Leffler 		} else {
3623325151a3SRui Paulo 			if (SSL_CTX_use_PrivateKey(data->ssl, pkey) != 1)
362439beb93cSSam Leffler 				res = -1;
362539beb93cSSam Leffler 		}
362639beb93cSSam Leffler 		EVP_PKEY_free(pkey);
362739beb93cSSam Leffler 	}
362839beb93cSSam Leffler 
362939beb93cSSam Leffler 	if (certs) {
3630*a90b9d01SCy Schubert #ifndef LIBRESSL_VERSION_NUMBER
3631780fb4a2SCy Schubert 		if (ssl)
3632325151a3SRui Paulo 			SSL_clear_chain_certs(ssl);
3633780fb4a2SCy Schubert 		else
3634780fb4a2SCy Schubert 			SSL_CTX_clear_chain_certs(data->ssl);
3635325151a3SRui Paulo 		while ((cert = sk_X509_pop(certs)) != NULL) {
3636325151a3SRui Paulo 			X509_NAME_oneline(X509_get_subject_name(cert), buf,
3637325151a3SRui Paulo 					  sizeof(buf));
3638325151a3SRui Paulo 			wpa_printf(MSG_DEBUG, "TLS: additional certificate"
3639325151a3SRui Paulo 				   " from PKCS12: subject='%s'", buf);
3640780fb4a2SCy Schubert 			if ((ssl && SSL_add1_chain_cert(ssl, cert) != 1) ||
3641780fb4a2SCy Schubert 			    (!ssl && SSL_CTX_add1_chain_cert(data->ssl,
3642780fb4a2SCy Schubert 							     cert) != 1)) {
3643325151a3SRui Paulo 				tls_show_errors(MSG_DEBUG, __func__,
3644325151a3SRui Paulo 						"Failed to add additional certificate");
3645325151a3SRui Paulo 				res = -1;
3646780fb4a2SCy Schubert 				X509_free(cert);
3647325151a3SRui Paulo 				break;
3648325151a3SRui Paulo 			}
3649780fb4a2SCy Schubert 			X509_free(cert);
3650325151a3SRui Paulo 		}
3651325151a3SRui Paulo 		if (!res) {
3652325151a3SRui Paulo 			/* Try to continue anyway */
3653325151a3SRui Paulo 		}
3654780fb4a2SCy Schubert 		sk_X509_pop_free(certs, X509_free);
3655325151a3SRui Paulo #ifndef OPENSSL_IS_BORINGSSL
3656780fb4a2SCy Schubert 		if (ssl)
3657780fb4a2SCy Schubert 			res = SSL_build_cert_chain(
3658780fb4a2SCy Schubert 				ssl,
3659780fb4a2SCy Schubert 				SSL_BUILD_CHAIN_FLAG_CHECK |
3660780fb4a2SCy Schubert 				SSL_BUILD_CHAIN_FLAG_IGNORE_ERROR);
3661780fb4a2SCy Schubert 		else
3662780fb4a2SCy Schubert 			res = SSL_CTX_build_cert_chain(
3663780fb4a2SCy Schubert 				data->ssl,
3664325151a3SRui Paulo 				SSL_BUILD_CHAIN_FLAG_CHECK |
3665325151a3SRui Paulo 				SSL_BUILD_CHAIN_FLAG_IGNORE_ERROR);
3666325151a3SRui Paulo 		if (!res) {
3667325151a3SRui Paulo 			tls_show_errors(MSG_DEBUG, __func__,
3668325151a3SRui Paulo 					"Failed to build certificate chain");
3669325151a3SRui Paulo 		} else if (res == 2) {
3670325151a3SRui Paulo 			wpa_printf(MSG_DEBUG,
3671325151a3SRui Paulo 				   "TLS: Ignore certificate chain verification error when building chain with PKCS#12 extra certificates");
3672325151a3SRui Paulo 		}
3673325151a3SRui Paulo #endif /* OPENSSL_IS_BORINGSSL */
3674325151a3SRui Paulo 		/*
3675325151a3SRui Paulo 		 * Try to continue regardless of result since it is possible for
3676325151a3SRui Paulo 		 * the extra certificates not to be required.
3677325151a3SRui Paulo 		 */
3678325151a3SRui Paulo 		res = 0;
3679*a90b9d01SCy Schubert #else /* LIBRESSL_VERSION_NUMBER */
3680325151a3SRui Paulo 		SSL_CTX_clear_extra_chain_certs(data->ssl);
368139beb93cSSam Leffler 		while ((cert = sk_X509_pop(certs)) != NULL) {
368239beb93cSSam Leffler 			X509_NAME_oneline(X509_get_subject_name(cert), buf,
368339beb93cSSam Leffler 					  sizeof(buf));
368439beb93cSSam Leffler 			wpa_printf(MSG_DEBUG, "TLS: additional certificate"
368539beb93cSSam Leffler 				   " from PKCS12: subject='%s'", buf);
368639beb93cSSam Leffler 			/*
368739beb93cSSam Leffler 			 * There is no SSL equivalent for the chain cert - so
368839beb93cSSam Leffler 			 * always add it to the context...
368939beb93cSSam Leffler 			 */
3690325151a3SRui Paulo 			if (SSL_CTX_add_extra_chain_cert(data->ssl, cert) != 1)
3691325151a3SRui Paulo 			{
3692780fb4a2SCy Schubert 				X509_free(cert);
369339beb93cSSam Leffler 				res = -1;
369439beb93cSSam Leffler 				break;
369539beb93cSSam Leffler 			}
369639beb93cSSam Leffler 		}
3697780fb4a2SCy Schubert 		sk_X509_pop_free(certs, X509_free);
3698*a90b9d01SCy Schubert #endif /* LIBRSESSL_VERSION_NUMBER */
369939beb93cSSam Leffler 	}
370039beb93cSSam Leffler 
370139beb93cSSam Leffler 	PKCS12_free(p12);
370239beb93cSSam Leffler 
370339beb93cSSam Leffler 	if (res < 0)
3704325151a3SRui Paulo 		tls_get_errors(data);
370539beb93cSSam Leffler 
370639beb93cSSam Leffler 	return res;
370739beb93cSSam Leffler }
370839beb93cSSam Leffler #endif  /* PKCS12_FUNCS */
370939beb93cSSam Leffler 
371039beb93cSSam Leffler 
tls_read_pkcs12(struct tls_data * data,SSL * ssl,const char * private_key,const char * passwd)3711325151a3SRui Paulo static int tls_read_pkcs12(struct tls_data *data, SSL *ssl,
3712325151a3SRui Paulo 			   const char *private_key, const char *passwd)
371339beb93cSSam Leffler {
371439beb93cSSam Leffler #ifdef PKCS12_FUNCS
371539beb93cSSam Leffler 	FILE *f;
371639beb93cSSam Leffler 	PKCS12 *p12;
371739beb93cSSam Leffler 
371839beb93cSSam Leffler 	f = fopen(private_key, "rb");
371939beb93cSSam Leffler 	if (f == NULL)
372039beb93cSSam Leffler 		return -1;
372139beb93cSSam Leffler 
372239beb93cSSam Leffler 	p12 = d2i_PKCS12_fp(f, NULL);
372339beb93cSSam Leffler 	fclose(f);
372439beb93cSSam Leffler 
372539beb93cSSam Leffler 	if (p12 == NULL) {
372639beb93cSSam Leffler 		tls_show_errors(MSG_INFO, __func__,
372739beb93cSSam Leffler 				"Failed to use PKCS#12 file");
372839beb93cSSam Leffler 		return -1;
372939beb93cSSam Leffler 	}
373039beb93cSSam Leffler 
3731325151a3SRui Paulo 	return tls_parse_pkcs12(data, ssl, p12, passwd);
373239beb93cSSam Leffler 
373339beb93cSSam Leffler #else /* PKCS12_FUNCS */
373439beb93cSSam Leffler 	wpa_printf(MSG_INFO, "TLS: PKCS12 support disabled - cannot read "
373539beb93cSSam Leffler 		   "p12/pfx files");
373639beb93cSSam Leffler 	return -1;
373739beb93cSSam Leffler #endif  /* PKCS12_FUNCS */
373839beb93cSSam Leffler }
373939beb93cSSam Leffler 
374039beb93cSSam Leffler 
tls_read_pkcs12_blob(struct tls_data * data,SSL * ssl,const u8 * blob,size_t len,const char * passwd)3741325151a3SRui Paulo static int tls_read_pkcs12_blob(struct tls_data *data, SSL *ssl,
374239beb93cSSam Leffler 				const u8 *blob, size_t len, const char *passwd)
374339beb93cSSam Leffler {
374439beb93cSSam Leffler #ifdef PKCS12_FUNCS
374539beb93cSSam Leffler 	PKCS12 *p12;
374639beb93cSSam Leffler 
37475b9c547cSRui Paulo 	p12 = d2i_PKCS12(NULL, (const unsigned char **) &blob, len);
374839beb93cSSam Leffler 	if (p12 == NULL) {
374939beb93cSSam Leffler 		tls_show_errors(MSG_INFO, __func__,
375039beb93cSSam Leffler 				"Failed to use PKCS#12 blob");
375139beb93cSSam Leffler 		return -1;
375239beb93cSSam Leffler 	}
375339beb93cSSam Leffler 
3754325151a3SRui Paulo 	return tls_parse_pkcs12(data, ssl, p12, passwd);
375539beb93cSSam Leffler 
375639beb93cSSam Leffler #else /* PKCS12_FUNCS */
375739beb93cSSam Leffler 	wpa_printf(MSG_INFO, "TLS: PKCS12 support disabled - cannot parse "
375839beb93cSSam Leffler 		   "p12/pfx blobs");
375939beb93cSSam Leffler 	return -1;
376039beb93cSSam Leffler #endif  /* PKCS12_FUNCS */
376139beb93cSSam Leffler }
376239beb93cSSam Leffler 
376339beb93cSSam Leffler 
376439beb93cSSam Leffler #ifndef OPENSSL_NO_ENGINE
tls_engine_get_cert(struct tls_connection * conn,const char * cert_id,X509 ** cert)376539beb93cSSam Leffler static int tls_engine_get_cert(struct tls_connection *conn,
376639beb93cSSam Leffler 			       const char *cert_id,
376739beb93cSSam Leffler 			       X509 **cert)
376839beb93cSSam Leffler {
376939beb93cSSam Leffler 	/* this runs after the private key is loaded so no PIN is required */
377039beb93cSSam Leffler 	struct {
377139beb93cSSam Leffler 		const char *cert_id;
377239beb93cSSam Leffler 		X509 *cert;
377339beb93cSSam Leffler 	} params;
377439beb93cSSam Leffler 	params.cert_id = cert_id;
377539beb93cSSam Leffler 	params.cert = NULL;
377639beb93cSSam Leffler 
377739beb93cSSam Leffler 	if (!ENGINE_ctrl_cmd(conn->engine, "LOAD_CERT_CTRL",
377839beb93cSSam Leffler 			     0, &params, NULL, 1)) {
3779325151a3SRui Paulo 		unsigned long err = ERR_get_error();
3780325151a3SRui Paulo 
378139beb93cSSam Leffler 		wpa_printf(MSG_ERROR, "ENGINE: cannot load client cert with id"
378239beb93cSSam Leffler 			   " '%s' [%s]", cert_id,
3783325151a3SRui Paulo 			   ERR_error_string(err, NULL));
3784325151a3SRui Paulo 		if (tls_is_pin_error(err))
3785325151a3SRui Paulo 			return TLS_SET_PARAMS_ENGINE_PRV_BAD_PIN;
378639beb93cSSam Leffler 		return TLS_SET_PARAMS_ENGINE_PRV_INIT_FAILED;
378739beb93cSSam Leffler 	}
378839beb93cSSam Leffler 	if (!params.cert) {
378939beb93cSSam Leffler 		wpa_printf(MSG_ERROR, "ENGINE: did not properly cert with id"
379039beb93cSSam Leffler 			   " '%s'", cert_id);
379139beb93cSSam Leffler 		return TLS_SET_PARAMS_ENGINE_PRV_INIT_FAILED;
379239beb93cSSam Leffler 	}
379339beb93cSSam Leffler 	*cert = params.cert;
379439beb93cSSam Leffler 	return 0;
379539beb93cSSam Leffler }
379639beb93cSSam Leffler #endif /* OPENSSL_NO_ENGINE */
379739beb93cSSam Leffler 
379839beb93cSSam Leffler 
tls_connection_engine_client_cert(struct tls_connection * conn,const char * cert_id)379939beb93cSSam Leffler static int tls_connection_engine_client_cert(struct tls_connection *conn,
380039beb93cSSam Leffler 					     const char *cert_id)
380139beb93cSSam Leffler {
380239beb93cSSam Leffler #ifndef OPENSSL_NO_ENGINE
380339beb93cSSam Leffler 	X509 *cert;
380439beb93cSSam Leffler 
380539beb93cSSam Leffler 	if (tls_engine_get_cert(conn, cert_id, &cert))
380639beb93cSSam Leffler 		return -1;
380739beb93cSSam Leffler 
380839beb93cSSam Leffler 	if (!SSL_use_certificate(conn->ssl, cert)) {
380939beb93cSSam Leffler 		tls_show_errors(MSG_ERROR, __func__,
381039beb93cSSam Leffler 				"SSL_use_certificate failed");
381139beb93cSSam Leffler                 X509_free(cert);
381239beb93cSSam Leffler 		return -1;
381339beb93cSSam Leffler 	}
381439beb93cSSam Leffler 	X509_free(cert);
381539beb93cSSam Leffler 	wpa_printf(MSG_DEBUG, "ENGINE: SSL_use_certificate --> "
381639beb93cSSam Leffler 		   "OK");
381739beb93cSSam Leffler 	return 0;
381839beb93cSSam Leffler 
381939beb93cSSam Leffler #else /* OPENSSL_NO_ENGINE */
382039beb93cSSam Leffler 	return -1;
382139beb93cSSam Leffler #endif /* OPENSSL_NO_ENGINE */
382239beb93cSSam Leffler }
382339beb93cSSam Leffler 
382439beb93cSSam Leffler 
tls_connection_engine_ca_cert(struct tls_data * data,struct tls_connection * conn,const char * ca_cert_id)3825325151a3SRui Paulo static int tls_connection_engine_ca_cert(struct tls_data *data,
382639beb93cSSam Leffler 					 struct tls_connection *conn,
382739beb93cSSam Leffler 					 const char *ca_cert_id)
382839beb93cSSam Leffler {
382939beb93cSSam Leffler #ifndef OPENSSL_NO_ENGINE
383039beb93cSSam Leffler 	X509 *cert;
3831325151a3SRui Paulo 	SSL_CTX *ssl_ctx = data->ssl;
38325b9c547cSRui Paulo 	X509_STORE *store;
383339beb93cSSam Leffler 
383439beb93cSSam Leffler 	if (tls_engine_get_cert(conn, ca_cert_id, &cert))
383539beb93cSSam Leffler 		return -1;
383639beb93cSSam Leffler 
383739beb93cSSam Leffler 	/* start off the same as tls_connection_ca_cert */
38385b9c547cSRui Paulo 	store = X509_STORE_new();
38395b9c547cSRui Paulo 	if (store == NULL) {
384039beb93cSSam Leffler 		wpa_printf(MSG_DEBUG, "OpenSSL: %s - failed to allocate new "
384139beb93cSSam Leffler 			   "certificate store", __func__);
384239beb93cSSam Leffler 		X509_free(cert);
384339beb93cSSam Leffler 		return -1;
384439beb93cSSam Leffler 	}
38455b9c547cSRui Paulo 	SSL_CTX_set_cert_store(ssl_ctx, store);
38465b9c547cSRui Paulo 	if (!X509_STORE_add_cert(store, cert)) {
384739beb93cSSam Leffler 		unsigned long err = ERR_peek_error();
384839beb93cSSam Leffler 		tls_show_errors(MSG_WARNING, __func__,
384939beb93cSSam Leffler 				"Failed to add CA certificate from engine "
385039beb93cSSam Leffler 				"to certificate store");
385139beb93cSSam Leffler 		if (ERR_GET_LIB(err) == ERR_LIB_X509 &&
385239beb93cSSam Leffler 		    ERR_GET_REASON(err) == X509_R_CERT_ALREADY_IN_HASH_TABLE) {
385339beb93cSSam Leffler 			wpa_printf(MSG_DEBUG, "OpenSSL: %s - ignoring cert"
385439beb93cSSam Leffler 				   " already in hash table error",
385539beb93cSSam Leffler 				   __func__);
385639beb93cSSam Leffler 		} else {
385739beb93cSSam Leffler 			X509_free(cert);
385839beb93cSSam Leffler 			return -1;
385939beb93cSSam Leffler 		}
386039beb93cSSam Leffler 	}
386139beb93cSSam Leffler 	X509_free(cert);
386239beb93cSSam Leffler 	wpa_printf(MSG_DEBUG, "OpenSSL: %s - added CA certificate from engine "
386339beb93cSSam Leffler 		   "to certificate store", __func__);
386439beb93cSSam Leffler 	SSL_set_verify(conn->ssl, SSL_VERIFY_PEER, tls_verify_cb);
3865f05cddf9SRui Paulo 	conn->ca_cert_verify = 1;
3866f05cddf9SRui Paulo 
386739beb93cSSam Leffler 	return 0;
386839beb93cSSam Leffler 
386939beb93cSSam Leffler #else /* OPENSSL_NO_ENGINE */
387039beb93cSSam Leffler 	return -1;
387139beb93cSSam Leffler #endif /* OPENSSL_NO_ENGINE */
387239beb93cSSam Leffler }
387339beb93cSSam Leffler 
387439beb93cSSam Leffler 
tls_connection_engine_private_key(struct tls_connection * conn)387539beb93cSSam Leffler static int tls_connection_engine_private_key(struct tls_connection *conn)
387639beb93cSSam Leffler {
3877780fb4a2SCy Schubert #if defined(ANDROID) || !defined(OPENSSL_NO_ENGINE)
387839beb93cSSam Leffler 	if (SSL_use_PrivateKey(conn->ssl, conn->private_key) != 1) {
387939beb93cSSam Leffler 		tls_show_errors(MSG_ERROR, __func__,
388039beb93cSSam Leffler 				"ENGINE: cannot use private key for TLS");
388139beb93cSSam Leffler 		return -1;
388239beb93cSSam Leffler 	}
388339beb93cSSam Leffler 	if (!SSL_check_private_key(conn->ssl)) {
388439beb93cSSam Leffler 		tls_show_errors(MSG_INFO, __func__,
388539beb93cSSam Leffler 				"Private key failed verification");
388639beb93cSSam Leffler 		return -1;
388739beb93cSSam Leffler 	}
388839beb93cSSam Leffler 	return 0;
388939beb93cSSam Leffler #else /* OPENSSL_NO_ENGINE */
389039beb93cSSam Leffler 	wpa_printf(MSG_ERROR, "SSL: Configuration uses engine, but "
389139beb93cSSam Leffler 		   "engine support was not compiled in");
389239beb93cSSam Leffler 	return -1;
389339beb93cSSam Leffler #endif /* OPENSSL_NO_ENGINE */
389439beb93cSSam Leffler }
389539beb93cSSam Leffler 
389639beb93cSSam Leffler 
389785732ac8SCy Schubert #ifndef OPENSSL_NO_STDIO
tls_passwd_cb(char * buf,int size,int rwflag,void * password)389885732ac8SCy Schubert static int tls_passwd_cb(char *buf, int size, int rwflag, void *password)
389985732ac8SCy Schubert {
390085732ac8SCy Schubert 	if (!password)
390185732ac8SCy Schubert 		return 0;
390285732ac8SCy Schubert 	os_strlcpy(buf, (const char *) password, size);
390385732ac8SCy Schubert 	return os_strlen(buf);
390485732ac8SCy Schubert }
390585732ac8SCy Schubert #endif /* OPENSSL_NO_STDIO */
390685732ac8SCy Schubert 
390785732ac8SCy Schubert 
tls_use_private_key_file(struct tls_data * data,SSL * ssl,const char * private_key,const char * private_key_passwd)390885732ac8SCy Schubert static int tls_use_private_key_file(struct tls_data *data, SSL *ssl,
390985732ac8SCy Schubert 				    const char *private_key,
391085732ac8SCy Schubert 				    const char *private_key_passwd)
391185732ac8SCy Schubert {
391285732ac8SCy Schubert #ifndef OPENSSL_NO_STDIO
391385732ac8SCy Schubert 	BIO *bio;
391485732ac8SCy Schubert 	EVP_PKEY *pkey;
391585732ac8SCy Schubert 	int ret;
391685732ac8SCy Schubert 
391785732ac8SCy Schubert 	/* First try ASN.1 (DER). */
391885732ac8SCy Schubert 	bio = BIO_new_file(private_key, "r");
391985732ac8SCy Schubert 	if (!bio)
392085732ac8SCy Schubert 		return -1;
392185732ac8SCy Schubert 	pkey = d2i_PrivateKey_bio(bio, NULL);
392285732ac8SCy Schubert 	BIO_free(bio);
392385732ac8SCy Schubert 
392485732ac8SCy Schubert 	if (pkey) {
392585732ac8SCy Schubert 		wpa_printf(MSG_DEBUG, "OpenSSL: %s (DER) --> loaded", __func__);
392685732ac8SCy Schubert 	} else {
392785732ac8SCy Schubert 		/* Try PEM with the provided password. */
392885732ac8SCy Schubert 		bio = BIO_new_file(private_key, "r");
392985732ac8SCy Schubert 		if (!bio)
393085732ac8SCy Schubert 			return -1;
393185732ac8SCy Schubert 		pkey = PEM_read_bio_PrivateKey(bio, NULL, tls_passwd_cb,
393285732ac8SCy Schubert 					       (void *) private_key_passwd);
393385732ac8SCy Schubert 		BIO_free(bio);
393485732ac8SCy Schubert 		if (!pkey)
393585732ac8SCy Schubert 			return -1;
393685732ac8SCy Schubert 		wpa_printf(MSG_DEBUG, "OpenSSL: %s (PEM) --> loaded", __func__);
393785732ac8SCy Schubert 		/* Clear errors from the previous failed load. */
393885732ac8SCy Schubert 		ERR_clear_error();
393985732ac8SCy Schubert 	}
394085732ac8SCy Schubert 
394185732ac8SCy Schubert 	if (ssl)
394285732ac8SCy Schubert 		ret = SSL_use_PrivateKey(ssl, pkey);
394385732ac8SCy Schubert 	else
394485732ac8SCy Schubert 		ret = SSL_CTX_use_PrivateKey(data->ssl, pkey);
394585732ac8SCy Schubert 
394685732ac8SCy Schubert 	EVP_PKEY_free(pkey);
394785732ac8SCy Schubert 	return ret == 1 ? 0 : -1;
394885732ac8SCy Schubert #else /* OPENSSL_NO_STDIO */
394985732ac8SCy Schubert 	wpa_printf(MSG_DEBUG, "OpenSSL: %s - OPENSSL_NO_STDIO", __func__);
395085732ac8SCy Schubert 	return -1;
395185732ac8SCy Schubert #endif /* OPENSSL_NO_STDIO */
395285732ac8SCy Schubert }
395385732ac8SCy Schubert 
395485732ac8SCy Schubert 
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)3955325151a3SRui Paulo static int tls_connection_private_key(struct tls_data *data,
395639beb93cSSam Leffler 				      struct tls_connection *conn,
395739beb93cSSam Leffler 				      const char *private_key,
395839beb93cSSam Leffler 				      const char *private_key_passwd,
395939beb93cSSam Leffler 				      const u8 *private_key_blob,
396039beb93cSSam Leffler 				      size_t private_key_blob_len)
396139beb93cSSam Leffler {
39624b72b91aSCy Schubert 	BIO *bio;
396339beb93cSSam Leffler 	int ok;
396439beb93cSSam Leffler 
396539beb93cSSam Leffler 	if (private_key == NULL && private_key_blob == NULL)
396639beb93cSSam Leffler 		return 0;
396739beb93cSSam Leffler 
396839beb93cSSam Leffler 	ok = 0;
396939beb93cSSam Leffler 	while (private_key_blob) {
397039beb93cSSam Leffler 		if (SSL_use_PrivateKey_ASN1(EVP_PKEY_RSA, conn->ssl,
397139beb93cSSam Leffler 					    (u8 *) private_key_blob,
397239beb93cSSam Leffler 					    private_key_blob_len) == 1) {
397339beb93cSSam Leffler 			wpa_printf(MSG_DEBUG, "OpenSSL: SSL_use_PrivateKey_"
397439beb93cSSam Leffler 				   "ASN1(EVP_PKEY_RSA) --> OK");
397539beb93cSSam Leffler 			ok = 1;
397639beb93cSSam Leffler 			break;
397739beb93cSSam Leffler 		}
397839beb93cSSam Leffler 
397939beb93cSSam Leffler 		if (SSL_use_PrivateKey_ASN1(EVP_PKEY_DSA, conn->ssl,
398039beb93cSSam Leffler 					    (u8 *) private_key_blob,
398139beb93cSSam Leffler 					    private_key_blob_len) == 1) {
398239beb93cSSam Leffler 			wpa_printf(MSG_DEBUG, "OpenSSL: SSL_use_PrivateKey_"
398339beb93cSSam Leffler 				   "ASN1(EVP_PKEY_DSA) --> OK");
398439beb93cSSam Leffler 			ok = 1;
398539beb93cSSam Leffler 			break;
398639beb93cSSam Leffler 		}
398739beb93cSSam Leffler 
3988c1d255d3SCy Schubert #ifndef OPENSSL_NO_EC
3989c1d255d3SCy Schubert 		if (SSL_use_PrivateKey_ASN1(EVP_PKEY_EC, conn->ssl,
3990c1d255d3SCy Schubert 					    (u8 *) private_key_blob,
3991c1d255d3SCy Schubert 					    private_key_blob_len) == 1) {
3992c1d255d3SCy Schubert 			wpa_printf(MSG_DEBUG,
3993c1d255d3SCy Schubert 				   "OpenSSL: SSL_use_PrivateKey_ASN1(EVP_PKEY_EC) --> OK");
3994c1d255d3SCy Schubert 			ok = 1;
3995c1d255d3SCy Schubert 			break;
3996c1d255d3SCy Schubert 		}
3997c1d255d3SCy Schubert #endif /* OPENSSL_NO_EC */
3998c1d255d3SCy Schubert 
3999*a90b9d01SCy Schubert #if OPENSSL_VERSION_NUMBER < 0x30000000L
400039beb93cSSam Leffler 		if (SSL_use_RSAPrivateKey_ASN1(conn->ssl,
400139beb93cSSam Leffler 					       (u8 *) private_key_blob,
400239beb93cSSam Leffler 					       private_key_blob_len) == 1) {
400339beb93cSSam Leffler 			wpa_printf(MSG_DEBUG, "OpenSSL: "
400439beb93cSSam Leffler 				   "SSL_use_RSAPrivateKey_ASN1 --> OK");
400539beb93cSSam Leffler 			ok = 1;
400639beb93cSSam Leffler 			break;
400739beb93cSSam Leffler 		}
4008*a90b9d01SCy Schubert #endif
400939beb93cSSam Leffler 
40104b72b91aSCy Schubert 		bio = BIO_new_mem_buf((u8 *) private_key_blob,
40114b72b91aSCy Schubert 				      private_key_blob_len);
40124b72b91aSCy Schubert 		if (bio) {
40134b72b91aSCy Schubert 			EVP_PKEY *pkey;
40144b72b91aSCy Schubert 
40154b72b91aSCy Schubert 			pkey = PEM_read_bio_PrivateKey(
40164b72b91aSCy Schubert 				bio, NULL, tls_passwd_cb,
40174b72b91aSCy Schubert 				(void *) private_key_passwd);
40184b72b91aSCy Schubert 			if (pkey) {
40194b72b91aSCy Schubert 				if (SSL_use_PrivateKey(conn->ssl, pkey) == 1) {
40204b72b91aSCy Schubert 					wpa_printf(MSG_DEBUG,
40214b72b91aSCy Schubert 						   "OpenSSL: SSL_use_PrivateKey --> OK");
40224b72b91aSCy Schubert 					ok = 1;
40234b72b91aSCy Schubert 					EVP_PKEY_free(pkey);
40244b72b91aSCy Schubert 					BIO_free(bio);
40254b72b91aSCy Schubert 					break;
40264b72b91aSCy Schubert 				}
40274b72b91aSCy Schubert 				EVP_PKEY_free(pkey);
40284b72b91aSCy Schubert 			}
40294b72b91aSCy Schubert 			BIO_free(bio);
40304b72b91aSCy Schubert 		}
40314b72b91aSCy Schubert 
4032325151a3SRui Paulo 		if (tls_read_pkcs12_blob(data, conn->ssl, private_key_blob,
403385732ac8SCy Schubert 					 private_key_blob_len,
403485732ac8SCy Schubert 					 private_key_passwd) == 0) {
403539beb93cSSam Leffler 			wpa_printf(MSG_DEBUG, "OpenSSL: PKCS#12 as blob --> "
403639beb93cSSam Leffler 				   "OK");
403739beb93cSSam Leffler 			ok = 1;
403839beb93cSSam Leffler 			break;
403939beb93cSSam Leffler 		}
404039beb93cSSam Leffler 
404139beb93cSSam Leffler 		break;
404239beb93cSSam Leffler 	}
404339beb93cSSam Leffler 
404439beb93cSSam Leffler 	while (!ok && private_key) {
404585732ac8SCy Schubert 		if (tls_use_private_key_file(data, conn->ssl, private_key,
404685732ac8SCy Schubert 					     private_key_passwd) == 0) {
404739beb93cSSam Leffler 			ok = 1;
404839beb93cSSam Leffler 			break;
404939beb93cSSam Leffler 		}
405039beb93cSSam Leffler 
405185732ac8SCy Schubert 		if (tls_read_pkcs12(data, conn->ssl, private_key,
405285732ac8SCy Schubert 				    private_key_passwd) == 0) {
405339beb93cSSam Leffler 			wpa_printf(MSG_DEBUG, "OpenSSL: Reading PKCS#12 file "
405439beb93cSSam Leffler 				   "--> OK");
405539beb93cSSam Leffler 			ok = 1;
405639beb93cSSam Leffler 			break;
405739beb93cSSam Leffler 		}
405839beb93cSSam Leffler 
405939beb93cSSam Leffler 		if (tls_cryptoapi_cert(conn->ssl, private_key) == 0) {
406039beb93cSSam Leffler 			wpa_printf(MSG_DEBUG, "OpenSSL: Using CryptoAPI to "
406139beb93cSSam Leffler 				   "access certificate store --> OK");
406239beb93cSSam Leffler 			ok = 1;
406339beb93cSSam Leffler 			break;
406439beb93cSSam Leffler 		}
406539beb93cSSam Leffler 
406639beb93cSSam Leffler 		break;
406739beb93cSSam Leffler 	}
406839beb93cSSam Leffler 
406939beb93cSSam Leffler 	if (!ok) {
4070f05cddf9SRui Paulo 		tls_show_errors(MSG_INFO, __func__,
4071f05cddf9SRui Paulo 				"Failed to load private key");
407239beb93cSSam Leffler 		return -1;
407339beb93cSSam Leffler 	}
407439beb93cSSam Leffler 	ERR_clear_error();
407539beb93cSSam Leffler 
407639beb93cSSam Leffler 	if (!SSL_check_private_key(conn->ssl)) {
407739beb93cSSam Leffler 		tls_show_errors(MSG_INFO, __func__, "Private key failed "
407839beb93cSSam Leffler 				"verification");
407939beb93cSSam Leffler 		return -1;
408039beb93cSSam Leffler 	}
408139beb93cSSam Leffler 
408239beb93cSSam Leffler 	wpa_printf(MSG_DEBUG, "SSL: Private key loaded successfully");
408339beb93cSSam Leffler 	return 0;
408439beb93cSSam Leffler }
408539beb93cSSam Leffler 
408639beb93cSSam Leffler 
tls_global_private_key(struct tls_data * data,const char * private_key,const char * private_key_passwd)4087325151a3SRui Paulo static int tls_global_private_key(struct tls_data *data,
4088325151a3SRui Paulo 				  const char *private_key,
408939beb93cSSam Leffler 				  const char *private_key_passwd)
409039beb93cSSam Leffler {
4091325151a3SRui Paulo 	SSL_CTX *ssl_ctx = data->ssl;
409239beb93cSSam Leffler 
409339beb93cSSam Leffler 	if (private_key == NULL)
409439beb93cSSam Leffler 		return 0;
409539beb93cSSam Leffler 
409685732ac8SCy Schubert 	if (tls_use_private_key_file(data, NULL, private_key,
409785732ac8SCy Schubert 				     private_key_passwd) &&
409885732ac8SCy Schubert 	    tls_read_pkcs12(data, NULL, private_key, private_key_passwd)) {
409939beb93cSSam Leffler 		tls_show_errors(MSG_INFO, __func__,
410039beb93cSSam Leffler 				"Failed to load private key");
410139beb93cSSam Leffler 		ERR_clear_error();
410239beb93cSSam Leffler 		return -1;
410339beb93cSSam Leffler 	}
410439beb93cSSam Leffler 	ERR_clear_error();
410539beb93cSSam Leffler 
410639beb93cSSam Leffler 	if (!SSL_CTX_check_private_key(ssl_ctx)) {
410739beb93cSSam Leffler 		tls_show_errors(MSG_INFO, __func__,
410839beb93cSSam Leffler 				"Private key failed verification");
410939beb93cSSam Leffler 		return -1;
411039beb93cSSam Leffler 	}
411139beb93cSSam Leffler 
411239beb93cSSam Leffler 	return 0;
411339beb93cSSam Leffler }
411439beb93cSSam Leffler 
411539beb93cSSam Leffler 
4116*a90b9d01SCy Schubert #if OPENSSL_VERSION_NUMBER >= 0x30000000L
4117*a90b9d01SCy Schubert #ifndef OPENSSL_NO_DH
411839beb93cSSam Leffler #ifndef OPENSSL_NO_DSA
4119*a90b9d01SCy Schubert /* This is needed to replace the deprecated DSA_dup_DH() function */
openssl_dsa_to_dh(EVP_PKEY * dsa)4120*a90b9d01SCy Schubert static EVP_PKEY * openssl_dsa_to_dh(EVP_PKEY *dsa)
4121*a90b9d01SCy Schubert {
4122*a90b9d01SCy Schubert 	OSSL_PARAM_BLD *bld = NULL;
4123*a90b9d01SCy Schubert 	OSSL_PARAM *params = NULL;
4124*a90b9d01SCy Schubert 	BIGNUM *p = NULL, *q = NULL, *g = NULL;
4125*a90b9d01SCy Schubert 	EVP_PKEY_CTX *ctx = NULL;
4126*a90b9d01SCy Schubert 	EVP_PKEY *pkey = NULL;
412739beb93cSSam Leffler 
4128*a90b9d01SCy Schubert 	if (!EVP_PKEY_get_bn_param(dsa, OSSL_PKEY_PARAM_FFC_P, &p) ||
4129*a90b9d01SCy Schubert 	    !EVP_PKEY_get_bn_param(dsa, OSSL_PKEY_PARAM_FFC_Q, &q) ||
4130*a90b9d01SCy Schubert 	    !EVP_PKEY_get_bn_param(dsa, OSSL_PKEY_PARAM_FFC_G, &g) ||
4131*a90b9d01SCy Schubert 	    !(bld = OSSL_PARAM_BLD_new()) ||
4132*a90b9d01SCy Schubert 	    !OSSL_PARAM_BLD_push_BN(bld, OSSL_PKEY_PARAM_FFC_P, p) ||
4133*a90b9d01SCy Schubert 	    !OSSL_PARAM_BLD_push_BN(bld, OSSL_PKEY_PARAM_FFC_Q, q) ||
4134*a90b9d01SCy Schubert 	    !OSSL_PARAM_BLD_push_BN(bld, OSSL_PKEY_PARAM_FFC_G, g) ||
4135*a90b9d01SCy Schubert 	    !(params = OSSL_PARAM_BLD_to_param(bld)) ||
4136*a90b9d01SCy Schubert 	    !(ctx = EVP_PKEY_CTX_new_from_name(NULL, "DHX", NULL)) ||
4137*a90b9d01SCy Schubert 	    EVP_PKEY_fromdata_init(ctx) != 1 ||
4138*a90b9d01SCy Schubert 	    EVP_PKEY_fromdata(ctx, &pkey, EVP_PKEY_KEY_PARAMETERS,
4139*a90b9d01SCy Schubert 			      params) != 1)
4140*a90b9d01SCy Schubert 		wpa_printf(MSG_INFO,
4141*a90b9d01SCy Schubert 			   "TLS: Failed to convert DSA parameters to DH parameters");
4142*a90b9d01SCy Schubert 
4143*a90b9d01SCy Schubert 	EVP_PKEY_CTX_free(ctx);
4144*a90b9d01SCy Schubert 	OSSL_PARAM_free(params);
4145*a90b9d01SCy Schubert 	OSSL_PARAM_BLD_free(bld);
4146*a90b9d01SCy Schubert 	BN_free(p);
4147*a90b9d01SCy Schubert 	BN_free(q);
4148*a90b9d01SCy Schubert 	BN_free(g);
4149*a90b9d01SCy Schubert 	return pkey;
415039beb93cSSam Leffler }
415139beb93cSSam Leffler #endif /* !OPENSSL_NO_DSA */
415239beb93cSSam Leffler #endif /* OPENSSL_NO_DH */
4153*a90b9d01SCy Schubert #endif /* OpenSSL version >= 3.0 */
415439beb93cSSam Leffler 
tls_global_dh(struct tls_data * data,const char * dh_file)4155325151a3SRui Paulo static int tls_global_dh(struct tls_data *data, const char *dh_file)
415639beb93cSSam Leffler {
415739beb93cSSam Leffler #ifdef OPENSSL_NO_DH
415839beb93cSSam Leffler 	if (dh_file == NULL)
415939beb93cSSam Leffler 		return 0;
416039beb93cSSam Leffler 	wpa_printf(MSG_ERROR, "TLS: openssl does not include DH support, but "
416139beb93cSSam Leffler 		   "dh_file specified");
416239beb93cSSam Leffler 	return -1;
416339beb93cSSam Leffler #else /* OPENSSL_NO_DH */
4164*a90b9d01SCy Schubert #if OPENSSL_VERSION_NUMBER >= 0x30000000L
4165*a90b9d01SCy Schubert 	SSL_CTX *ssl_ctx = data->ssl;
4166*a90b9d01SCy Schubert 	BIO *bio;
4167*a90b9d01SCy Schubert 	OSSL_DECODER_CTX *ctx = NULL;
4168*a90b9d01SCy Schubert 	EVP_PKEY *pkey = NULL, *tmpkey = NULL;
4169*a90b9d01SCy Schubert 	bool dsa = false;
4170*a90b9d01SCy Schubert 
4171*a90b9d01SCy Schubert 	if (!ssl_ctx)
4172*a90b9d01SCy Schubert 		return -1;
4173*a90b9d01SCy Schubert 	if (!dh_file) {
4174*a90b9d01SCy Schubert 		SSL_CTX_set_dh_auto(ssl_ctx, 1);
4175*a90b9d01SCy Schubert 		return 0;
4176*a90b9d01SCy Schubert 	}
4177*a90b9d01SCy Schubert 
4178*a90b9d01SCy Schubert 	bio = BIO_new_file(dh_file, "r");
4179*a90b9d01SCy Schubert 	if (!bio) {
4180*a90b9d01SCy Schubert 		wpa_printf(MSG_INFO, "TLS: Failed to open DH file '%s': %s",
4181*a90b9d01SCy Schubert 			   dh_file, ERR_error_string(ERR_get_error(), NULL));
4182*a90b9d01SCy Schubert 		return -1;
4183*a90b9d01SCy Schubert 	}
4184*a90b9d01SCy Schubert 	ctx = OSSL_DECODER_CTX_new_for_pkey(
4185*a90b9d01SCy Schubert 		&tmpkey, "PEM", NULL, NULL,
4186*a90b9d01SCy Schubert 		OSSL_KEYMGMT_SELECT_DOMAIN_PARAMETERS, NULL, NULL);
4187*a90b9d01SCy Schubert 	if (!ctx ||
4188*a90b9d01SCy Schubert 	    OSSL_DECODER_from_bio(ctx, bio) != 1) {
4189*a90b9d01SCy Schubert 		wpa_printf(MSG_INFO,
4190*a90b9d01SCy Schubert 			   "TLS: Failed to decode domain parameters from '%s': %s",
4191*a90b9d01SCy Schubert 			   dh_file, ERR_error_string(ERR_get_error(), NULL));
4192*a90b9d01SCy Schubert 		BIO_free(bio);
4193*a90b9d01SCy Schubert 		OSSL_DECODER_CTX_free(ctx);
4194*a90b9d01SCy Schubert 		return -1;
4195*a90b9d01SCy Schubert 	}
4196*a90b9d01SCy Schubert 	OSSL_DECODER_CTX_free(ctx);
4197*a90b9d01SCy Schubert 	BIO_free(bio);
4198*a90b9d01SCy Schubert 
4199*a90b9d01SCy Schubert 	if (!tmpkey) {
4200*a90b9d01SCy Schubert 		wpa_printf(MSG_INFO, "TLS: Failed to load domain parameters");
4201*a90b9d01SCy Schubert 		return -1;
4202*a90b9d01SCy Schubert 	}
4203*a90b9d01SCy Schubert 
4204*a90b9d01SCy Schubert #ifndef OPENSSL_NO_DSA
4205*a90b9d01SCy Schubert 	if (EVP_PKEY_is_a(tmpkey, "DSA")) {
4206*a90b9d01SCy Schubert 		pkey = openssl_dsa_to_dh(tmpkey);
4207*a90b9d01SCy Schubert 		EVP_PKEY_free(tmpkey);
4208*a90b9d01SCy Schubert 		if (!pkey)
4209*a90b9d01SCy Schubert 			return -1;
4210*a90b9d01SCy Schubert 		dsa = true;
4211*a90b9d01SCy Schubert 	}
4212*a90b9d01SCy Schubert #endif /* !OPENSSL_NO_DSA */
4213*a90b9d01SCy Schubert 	if (!dsa) {
4214*a90b9d01SCy Schubert 		if (EVP_PKEY_is_a(tmpkey, "DH") ||
4215*a90b9d01SCy Schubert 		    EVP_PKEY_is_a(tmpkey, "DHX")) {
4216*a90b9d01SCy Schubert 		} else {
4217*a90b9d01SCy Schubert 			wpa_printf(MSG_INFO,
4218*a90b9d01SCy Schubert 				   "TLS: No DH parameters found in %s",
4219*a90b9d01SCy Schubert 				   dh_file);
4220*a90b9d01SCy Schubert 			EVP_PKEY_free(tmpkey);
4221*a90b9d01SCy Schubert 			return -1;
4222*a90b9d01SCy Schubert 		}
4223*a90b9d01SCy Schubert 		pkey = tmpkey;
4224*a90b9d01SCy Schubert 		tmpkey = NULL;
4225*a90b9d01SCy Schubert 	}
4226*a90b9d01SCy Schubert 
4227*a90b9d01SCy Schubert 	if (SSL_CTX_set0_tmp_dh_pkey(ssl_ctx, pkey) != 1) {
4228*a90b9d01SCy Schubert 		wpa_printf(MSG_INFO,
4229*a90b9d01SCy Schubert 			   "TLS: Failed to set DH params from '%s': %s",
4230*a90b9d01SCy Schubert 			   dh_file, ERR_error_string(ERR_get_error(), NULL));
4231*a90b9d01SCy Schubert 		EVP_PKEY_free(pkey);
4232*a90b9d01SCy Schubert 		return -1;
4233*a90b9d01SCy Schubert 	}
4234*a90b9d01SCy Schubert 	return 0;
4235*a90b9d01SCy Schubert #else /* OpenSSL version >= 3.0 */
4236325151a3SRui Paulo 	SSL_CTX *ssl_ctx = data->ssl;
423739beb93cSSam Leffler 	DH *dh;
423839beb93cSSam Leffler 	BIO *bio;
423939beb93cSSam Leffler 
4240*a90b9d01SCy Schubert 	if (!ssl_ctx)
424139beb93cSSam Leffler 		return -1;
4242*a90b9d01SCy Schubert 	if (!dh_file) {
4243*a90b9d01SCy Schubert #if OPENSSL_VERSION_NUMBER >= 0x10100000L && !defined(OPENSSL_IS_BORINGSSL)
4244*a90b9d01SCy Schubert 		SSL_CTX_set_dh_auto(ssl_ctx, 1);
4245*a90b9d01SCy Schubert #endif
4246*a90b9d01SCy Schubert 		return 0;
4247*a90b9d01SCy Schubert 	}
424839beb93cSSam Leffler 
424939beb93cSSam Leffler 	bio = BIO_new_file(dh_file, "r");
425039beb93cSSam Leffler 	if (bio == NULL) {
425139beb93cSSam Leffler 		wpa_printf(MSG_INFO, "TLS: Failed to open DH file '%s': %s",
425239beb93cSSam Leffler 			   dh_file, ERR_error_string(ERR_get_error(), NULL));
425339beb93cSSam Leffler 		return -1;
425439beb93cSSam Leffler 	}
425539beb93cSSam Leffler 	dh = PEM_read_bio_DHparams(bio, NULL, NULL, NULL);
425639beb93cSSam Leffler 	BIO_free(bio);
425739beb93cSSam Leffler #ifndef OPENSSL_NO_DSA
425839beb93cSSam Leffler 	while (dh == NULL) {
425939beb93cSSam Leffler 		DSA *dsa;
426039beb93cSSam Leffler 		wpa_printf(MSG_DEBUG, "TLS: Failed to parse DH file '%s': %s -"
426139beb93cSSam Leffler 			   " trying to parse as DSA params", dh_file,
426239beb93cSSam Leffler 			   ERR_error_string(ERR_get_error(), NULL));
426339beb93cSSam Leffler 		bio = BIO_new_file(dh_file, "r");
426439beb93cSSam Leffler 		if (bio == NULL)
426539beb93cSSam Leffler 			break;
426639beb93cSSam Leffler 		dsa = PEM_read_bio_DSAparams(bio, NULL, NULL, NULL);
426739beb93cSSam Leffler 		BIO_free(bio);
426839beb93cSSam Leffler 		if (!dsa) {
426939beb93cSSam Leffler 			wpa_printf(MSG_DEBUG, "TLS: Failed to parse DSA file "
427039beb93cSSam Leffler 				   "'%s': %s", dh_file,
427139beb93cSSam Leffler 				   ERR_error_string(ERR_get_error(), NULL));
427239beb93cSSam Leffler 			break;
427339beb93cSSam Leffler 		}
427439beb93cSSam Leffler 
427539beb93cSSam Leffler 		wpa_printf(MSG_DEBUG, "TLS: DH file in DSA param format");
427639beb93cSSam Leffler 		dh = DSA_dup_DH(dsa);
427739beb93cSSam Leffler 		DSA_free(dsa);
427839beb93cSSam Leffler 		if (dh == NULL) {
427939beb93cSSam Leffler 			wpa_printf(MSG_INFO, "TLS: Failed to convert DSA "
428039beb93cSSam Leffler 				   "params into DH params");
428139beb93cSSam Leffler 			break;
428239beb93cSSam Leffler 		}
428339beb93cSSam Leffler 		break;
428439beb93cSSam Leffler 	}
428539beb93cSSam Leffler #endif /* !OPENSSL_NO_DSA */
428639beb93cSSam Leffler 	if (dh == NULL) {
428739beb93cSSam Leffler 		wpa_printf(MSG_INFO, "TLS: Failed to read/parse DH/DSA file "
428839beb93cSSam Leffler 			   "'%s'", dh_file);
428939beb93cSSam Leffler 		return -1;
429039beb93cSSam Leffler 	}
429139beb93cSSam Leffler 
429239beb93cSSam Leffler 	if (SSL_CTX_set_tmp_dh(ssl_ctx, dh) != 1) {
429339beb93cSSam Leffler 		wpa_printf(MSG_INFO, "TLS: Failed to set DH params from '%s': "
429439beb93cSSam Leffler 			   "%s", dh_file,
429539beb93cSSam Leffler 			   ERR_error_string(ERR_get_error(), NULL));
429639beb93cSSam Leffler 		DH_free(dh);
429739beb93cSSam Leffler 		return -1;
429839beb93cSSam Leffler 	}
429939beb93cSSam Leffler 	DH_free(dh);
430039beb93cSSam Leffler 	return 0;
4301*a90b9d01SCy Schubert #endif /* OpenSSL version >= 3.0 */
430239beb93cSSam Leffler #endif /* OPENSSL_NO_DH */
430339beb93cSSam Leffler }
430439beb93cSSam Leffler 
430539beb93cSSam Leffler 
tls_connection_get_random(void * ssl_ctx,struct tls_connection * conn,struct tls_random * keys)4306325151a3SRui Paulo int tls_connection_get_random(void *ssl_ctx, struct tls_connection *conn,
4307325151a3SRui Paulo 			      struct tls_random *keys)
4308325151a3SRui Paulo {
4309325151a3SRui Paulo 	SSL *ssl;
4310325151a3SRui Paulo 
4311325151a3SRui Paulo 	if (conn == NULL || keys == NULL)
4312325151a3SRui Paulo 		return -1;
4313325151a3SRui Paulo 	ssl = conn->ssl;
4314325151a3SRui Paulo 	if (ssl == NULL)
4315325151a3SRui Paulo 		return -1;
4316325151a3SRui Paulo 
4317325151a3SRui Paulo 	os_memset(keys, 0, sizeof(*keys));
4318325151a3SRui Paulo 	keys->client_random = conn->client_random;
4319325151a3SRui Paulo 	keys->client_random_len = SSL_get_client_random(
4320325151a3SRui Paulo 		ssl, conn->client_random, sizeof(conn->client_random));
4321325151a3SRui Paulo 	keys->server_random = conn->server_random;
4322325151a3SRui Paulo 	keys->server_random_len = SSL_get_server_random(
4323325151a3SRui Paulo 		ssl, conn->server_random, sizeof(conn->server_random));
4324325151a3SRui Paulo 
4325325151a3SRui Paulo 	return 0;
4326325151a3SRui Paulo }
4327325151a3SRui Paulo 
4328325151a3SRui Paulo 
4329780fb4a2SCy Schubert #ifdef OPENSSL_NEED_EAP_FAST_PRF
openssl_get_keyblock_size(SSL * ssl)4330325151a3SRui Paulo static int openssl_get_keyblock_size(SSL *ssl)
4331325151a3SRui Paulo {
4332*a90b9d01SCy Schubert #if OPENSSL_VERSION_NUMBER < 0x10100000L
4333325151a3SRui Paulo 	const EVP_CIPHER *c;
4334325151a3SRui Paulo 	const EVP_MD *h;
4335325151a3SRui Paulo 	int md_size;
4336325151a3SRui Paulo 
4337325151a3SRui Paulo 	if (ssl->enc_read_ctx == NULL || ssl->enc_read_ctx->cipher == NULL ||
4338325151a3SRui Paulo 	    ssl->read_hash == NULL)
4339325151a3SRui Paulo 		return -1;
4340325151a3SRui Paulo 
4341325151a3SRui Paulo 	c = ssl->enc_read_ctx->cipher;
4342325151a3SRui Paulo 	h = EVP_MD_CTX_md(ssl->read_hash);
4343325151a3SRui Paulo 	if (h)
4344325151a3SRui Paulo 		md_size = EVP_MD_size(h);
4345325151a3SRui Paulo 	else if (ssl->s3)
4346325151a3SRui Paulo 		md_size = ssl->s3->tmp.new_mac_secret_size;
4347325151a3SRui Paulo 	else
4348325151a3SRui Paulo 		return -1;
4349325151a3SRui Paulo 
4350325151a3SRui Paulo 	wpa_printf(MSG_DEBUG, "OpenSSL: keyblock size: key_len=%d MD_size=%d "
4351325151a3SRui Paulo 		   "IV_len=%d", EVP_CIPHER_key_length(c), md_size,
4352325151a3SRui Paulo 		   EVP_CIPHER_iv_length(c));
4353325151a3SRui Paulo 	return 2 * (EVP_CIPHER_key_length(c) +
4354325151a3SRui Paulo 		    md_size +
4355325151a3SRui Paulo 		    EVP_CIPHER_iv_length(c));
4356325151a3SRui Paulo #else
4357325151a3SRui Paulo 	const SSL_CIPHER *ssl_cipher;
4358325151a3SRui Paulo 	int cipher, digest;
4359325151a3SRui Paulo 	const EVP_CIPHER *c;
4360325151a3SRui Paulo 	const EVP_MD *h;
4361c1d255d3SCy Schubert 	int mac_key_len, enc_key_len, fixed_iv_len;
4362325151a3SRui Paulo 
4363325151a3SRui Paulo 	ssl_cipher = SSL_get_current_cipher(ssl);
4364325151a3SRui Paulo 	if (!ssl_cipher)
4365325151a3SRui Paulo 		return -1;
4366325151a3SRui Paulo 	cipher = SSL_CIPHER_get_cipher_nid(ssl_cipher);
4367325151a3SRui Paulo 	digest = SSL_CIPHER_get_digest_nid(ssl_cipher);
4368325151a3SRui Paulo 	wpa_printf(MSG_DEBUG, "OpenSSL: cipher nid %d digest nid %d",
4369325151a3SRui Paulo 		   cipher, digest);
4370325151a3SRui Paulo 	if (cipher < 0 || digest < 0)
4371325151a3SRui Paulo 		return -1;
4372c1d255d3SCy Schubert 	if (cipher == NID_undef) {
4373c1d255d3SCy Schubert 		wpa_printf(MSG_DEBUG, "OpenSSL: no cipher in use?!");
4374325151a3SRui Paulo 		return -1;
4375c1d255d3SCy Schubert 	}
4376c1d255d3SCy Schubert 	c = EVP_get_cipherbynid(cipher);
4377c1d255d3SCy Schubert 	if (!c)
4378c1d255d3SCy Schubert 		return -1;
4379c1d255d3SCy Schubert 	enc_key_len = EVP_CIPHER_key_length(c);
4380c1d255d3SCy Schubert 	if (EVP_CIPHER_mode(c) == EVP_CIPH_GCM_MODE ||
4381c1d255d3SCy Schubert 	    EVP_CIPHER_mode(c) == EVP_CIPH_CCM_MODE)
4382c1d255d3SCy Schubert 		fixed_iv_len = 4; /* only part of IV from PRF */
4383c1d255d3SCy Schubert 	else
4384c1d255d3SCy Schubert 		fixed_iv_len = EVP_CIPHER_iv_length(c);
4385c1d255d3SCy Schubert 	if (digest == NID_undef) {
4386c1d255d3SCy Schubert 		wpa_printf(MSG_DEBUG, "OpenSSL: no digest in use (e.g., AEAD)");
4387c1d255d3SCy Schubert 		mac_key_len = 0;
4388c1d255d3SCy Schubert 	} else {
4389c1d255d3SCy Schubert 		h = EVP_get_digestbynid(digest);
4390c1d255d3SCy Schubert 		if (!h)
4391c1d255d3SCy Schubert 			return -1;
4392c1d255d3SCy Schubert 		mac_key_len = EVP_MD_size(h);
4393c1d255d3SCy Schubert 	}
4394325151a3SRui Paulo 
4395325151a3SRui Paulo 	wpa_printf(MSG_DEBUG,
4396c1d255d3SCy Schubert 		   "OpenSSL: keyblock size: mac_key_len=%d enc_key_len=%d fixed_iv_len=%d",
4397c1d255d3SCy Schubert 		   mac_key_len, enc_key_len, fixed_iv_len);
4398c1d255d3SCy Schubert 	return 2 * (mac_key_len + enc_key_len + fixed_iv_len);
4399325151a3SRui Paulo #endif
4400325151a3SRui Paulo }
4401780fb4a2SCy Schubert #endif /* OPENSSL_NEED_EAP_FAST_PRF */
4402325151a3SRui Paulo 
4403325151a3SRui Paulo 
tls_connection_export_key(void * tls_ctx,struct tls_connection * conn,const char * label,const u8 * context,size_t context_len,u8 * out,size_t out_len)4404780fb4a2SCy Schubert int tls_connection_export_key(void *tls_ctx, struct tls_connection *conn,
44054bc52338SCy Schubert 			      const char *label, const u8 *context,
44064bc52338SCy Schubert 			      size_t context_len, u8 *out, size_t out_len)
440739beb93cSSam Leffler {
4408780fb4a2SCy Schubert 	if (!conn ||
4409780fb4a2SCy Schubert 	    SSL_export_keying_material(conn->ssl, out, out_len, label,
44104bc52338SCy Schubert 				       os_strlen(label), context, context_len,
44114bc52338SCy Schubert 				       context != NULL) != 1)
4412f05cddf9SRui Paulo 		return -1;
4413780fb4a2SCy Schubert 	return 0;
4414325151a3SRui Paulo }
4415325151a3SRui Paulo 
4416325151a3SRui Paulo 
tls_connection_get_eap_fast_key(void * tls_ctx,struct tls_connection * conn,u8 * out,size_t out_len)4417780fb4a2SCy Schubert int tls_connection_get_eap_fast_key(void *tls_ctx, struct tls_connection *conn,
4418780fb4a2SCy Schubert 				    u8 *out, size_t out_len)
4419780fb4a2SCy Schubert {
4420780fb4a2SCy Schubert #ifdef OPENSSL_NEED_EAP_FAST_PRF
4421325151a3SRui Paulo 	SSL *ssl;
4422325151a3SRui Paulo 	SSL_SESSION *sess;
4423325151a3SRui Paulo 	u8 *rnd;
4424325151a3SRui Paulo 	int ret = -1;
4425325151a3SRui Paulo 	int skip = 0;
4426325151a3SRui Paulo 	u8 *tmp_out = NULL;
4427325151a3SRui Paulo 	u8 *_out = out;
4428325151a3SRui Paulo 	unsigned char client_random[SSL3_RANDOM_SIZE];
4429325151a3SRui Paulo 	unsigned char server_random[SSL3_RANDOM_SIZE];
4430325151a3SRui Paulo 	unsigned char master_key[64];
4431325151a3SRui Paulo 	size_t master_key_len;
4432325151a3SRui Paulo 	const char *ver;
4433325151a3SRui Paulo 
4434325151a3SRui Paulo 	/*
4435780fb4a2SCy Schubert 	 * TLS library did not support EAP-FAST key generation, so get the
4436780fb4a2SCy Schubert 	 * needed TLS session parameters and use an internal implementation of
4437780fb4a2SCy Schubert 	 * TLS PRF to derive the key.
4438325151a3SRui Paulo 	 */
4439325151a3SRui Paulo 
4440325151a3SRui Paulo 	if (conn == NULL)
4441325151a3SRui Paulo 		return -1;
4442325151a3SRui Paulo 	ssl = conn->ssl;
4443325151a3SRui Paulo 	if (ssl == NULL)
4444325151a3SRui Paulo 		return -1;
4445325151a3SRui Paulo 	ver = SSL_get_version(ssl);
4446325151a3SRui Paulo 	sess = SSL_get_session(ssl);
4447325151a3SRui Paulo 	if (!ver || !sess)
444839beb93cSSam Leffler 		return -1;
444939beb93cSSam Leffler 
4450325151a3SRui Paulo 	skip = openssl_get_keyblock_size(ssl);
4451325151a3SRui Paulo 	if (skip < 0)
4452325151a3SRui Paulo 		return -1;
4453325151a3SRui Paulo 	tmp_out = os_malloc(skip + out_len);
4454325151a3SRui Paulo 	if (!tmp_out)
4455325151a3SRui Paulo 		return -1;
4456325151a3SRui Paulo 	_out = tmp_out;
445739beb93cSSam Leffler 
4458325151a3SRui Paulo 	rnd = os_malloc(2 * SSL3_RANDOM_SIZE);
4459325151a3SRui Paulo 	if (!rnd) {
4460325151a3SRui Paulo 		os_free(tmp_out);
4461325151a3SRui Paulo 		return -1;
4462325151a3SRui Paulo 	}
4463325151a3SRui Paulo 
4464325151a3SRui Paulo 	SSL_get_client_random(ssl, client_random, sizeof(client_random));
4465325151a3SRui Paulo 	SSL_get_server_random(ssl, server_random, sizeof(server_random));
4466325151a3SRui Paulo 	master_key_len = SSL_SESSION_get_master_key(sess, master_key,
4467325151a3SRui Paulo 						    sizeof(master_key));
4468325151a3SRui Paulo 
4469325151a3SRui Paulo 	os_memcpy(rnd, server_random, SSL3_RANDOM_SIZE);
4470780fb4a2SCy Schubert 	os_memcpy(rnd + SSL3_RANDOM_SIZE, client_random, SSL3_RANDOM_SIZE);
4471325151a3SRui Paulo 
4472325151a3SRui Paulo 	if (os_strcmp(ver, "TLSv1.2") == 0) {
4473325151a3SRui Paulo 		tls_prf_sha256(master_key, master_key_len,
4474780fb4a2SCy Schubert 			       "key expansion", rnd, 2 * SSL3_RANDOM_SIZE,
4475325151a3SRui Paulo 			       _out, skip + out_len);
4476325151a3SRui Paulo 		ret = 0;
4477325151a3SRui Paulo 	} else if (tls_prf_sha1_md5(master_key, master_key_len,
4478780fb4a2SCy Schubert 				    "key expansion", rnd, 2 * SSL3_RANDOM_SIZE,
4479325151a3SRui Paulo 				    _out, skip + out_len) == 0) {
4480325151a3SRui Paulo 		ret = 0;
4481325151a3SRui Paulo 	}
4482206b73d0SCy Schubert 	forced_memzero(master_key, sizeof(master_key));
4483325151a3SRui Paulo 	os_free(rnd);
4484780fb4a2SCy Schubert 	if (ret == 0)
4485325151a3SRui Paulo 		os_memcpy(out, _out + skip, out_len);
4486325151a3SRui Paulo 	bin_clear_free(tmp_out, skip);
4487325151a3SRui Paulo 
4488325151a3SRui Paulo 	return ret;
4489780fb4a2SCy Schubert #else /* OPENSSL_NEED_EAP_FAST_PRF */
4490780fb4a2SCy Schubert 	wpa_printf(MSG_ERROR,
4491780fb4a2SCy Schubert 		   "OpenSSL: EAP-FAST keys cannot be exported in FIPS mode");
4492f05cddf9SRui Paulo 	return -1;
4493780fb4a2SCy Schubert #endif /* OPENSSL_NEED_EAP_FAST_PRF */
449439beb93cSSam Leffler }
449539beb93cSSam Leffler 
449639beb93cSSam Leffler 
4497e28a4053SRui Paulo static struct wpabuf *
openssl_handshake(struct tls_connection * conn,const struct wpabuf * in_data)449885732ac8SCy Schubert openssl_handshake(struct tls_connection *conn, const struct wpabuf *in_data)
449939beb93cSSam Leffler {
4500*a90b9d01SCy Schubert 	struct tls_context *context = conn->context;
450139beb93cSSam Leffler 	int res;
4502e28a4053SRui Paulo 	struct wpabuf *out_data;
450339beb93cSSam Leffler 
450439beb93cSSam Leffler 	/*
450539beb93cSSam Leffler 	 * Give TLS handshake data from the server (if available) to OpenSSL
450639beb93cSSam Leffler 	 * for processing.
450739beb93cSSam Leffler 	 */
4508325151a3SRui Paulo 	if (in_data && wpabuf_len(in_data) > 0 &&
4509e28a4053SRui Paulo 	    BIO_write(conn->ssl_in, wpabuf_head(in_data), wpabuf_len(in_data))
4510e28a4053SRui Paulo 	    < 0) {
451139beb93cSSam Leffler 		tls_show_errors(MSG_INFO, __func__,
451239beb93cSSam Leffler 				"Handshake failed - BIO_write");
451339beb93cSSam Leffler 		return NULL;
451439beb93cSSam Leffler 	}
451539beb93cSSam Leffler 
451639beb93cSSam Leffler 	/* Initiate TLS handshake or continue the existing handshake */
451785732ac8SCy Schubert 	if (conn->server)
4518e28a4053SRui Paulo 		res = SSL_accept(conn->ssl);
4519e28a4053SRui Paulo 	else
452039beb93cSSam Leffler 		res = SSL_connect(conn->ssl);
452139beb93cSSam Leffler 	if (res != 1) {
452239beb93cSSam Leffler 		int err = SSL_get_error(conn->ssl, res);
452339beb93cSSam Leffler 		if (err == SSL_ERROR_WANT_READ)
452439beb93cSSam Leffler 			wpa_printf(MSG_DEBUG, "SSL: SSL_connect - want "
452539beb93cSSam Leffler 				   "more data");
452639beb93cSSam Leffler 		else if (err == SSL_ERROR_WANT_WRITE)
452739beb93cSSam Leffler 			wpa_printf(MSG_DEBUG, "SSL: SSL_connect - want to "
452839beb93cSSam Leffler 				   "write");
452939beb93cSSam Leffler 		else {
4530*a90b9d01SCy Schubert 			unsigned long error = ERR_peek_last_error();
4531*a90b9d01SCy Schubert 
453239beb93cSSam Leffler 			tls_show_errors(MSG_INFO, __func__, "SSL_connect");
4533*a90b9d01SCy Schubert 
4534*a90b9d01SCy Schubert 			if (context->event_cb &&
4535*a90b9d01SCy Schubert 			    ERR_GET_LIB(error) == ERR_LIB_SSL &&
4536*a90b9d01SCy Schubert 			    ERR_GET_REASON(error) ==
4537*a90b9d01SCy Schubert 			    SSL_R_UNSAFE_LEGACY_RENEGOTIATION_DISABLED) {
4538*a90b9d01SCy Schubert 				context->event_cb(
4539*a90b9d01SCy Schubert 					context->cb_ctx,
4540*a90b9d01SCy Schubert 					TLS_UNSAFE_RENEGOTIATION_DISABLED,
4541*a90b9d01SCy Schubert 					NULL);
4542*a90b9d01SCy Schubert 			}
454339beb93cSSam Leffler 			conn->failed++;
454485732ac8SCy Schubert 			if (!conn->server && !conn->client_hello_generated) {
454585732ac8SCy Schubert 				/* The server would not understand TLS Alert
454685732ac8SCy Schubert 				 * before ClientHello, so simply terminate
454785732ac8SCy Schubert 				 * handshake on this type of error case caused
454885732ac8SCy Schubert 				 * by a likely internal error like no ciphers
454985732ac8SCy Schubert 				 * available. */
455085732ac8SCy Schubert 				wpa_printf(MSG_DEBUG,
455185732ac8SCy Schubert 					   "OpenSSL: Could not generate ClientHello");
455285732ac8SCy Schubert 				conn->write_alerts++;
455385732ac8SCy Schubert 				return NULL;
455439beb93cSSam Leffler 			}
455539beb93cSSam Leffler 		}
455685732ac8SCy Schubert 	}
455785732ac8SCy Schubert 
455885732ac8SCy Schubert 	if (!conn->server && !conn->failed)
455985732ac8SCy Schubert 		conn->client_hello_generated = 1;
456085732ac8SCy Schubert 
456185732ac8SCy Schubert #ifdef CONFIG_SUITEB
456285732ac8SCy Schubert 	if ((conn->flags & TLS_CONN_SUITEB) && !conn->server &&
456385732ac8SCy Schubert 	    os_strncmp(SSL_get_cipher(conn->ssl), "DHE-", 4) == 0 &&
456485732ac8SCy Schubert 	    conn->server_dh_prime_len < 3072) {
456585732ac8SCy Schubert 		/*
456685732ac8SCy Schubert 		 * This should not be reached since earlier cert_cb should have
456785732ac8SCy Schubert 		 * terminated the handshake. Keep this check here for extra
456885732ac8SCy Schubert 		 * protection if anything goes wrong with the more low-level
456985732ac8SCy Schubert 		 * checks based on having to parse the TLS handshake messages.
457085732ac8SCy Schubert 		 */
457185732ac8SCy Schubert 		wpa_printf(MSG_DEBUG,
457285732ac8SCy Schubert 			   "OpenSSL: Server DH prime length: %d bits",
457385732ac8SCy Schubert 			   conn->server_dh_prime_len);
457485732ac8SCy Schubert 
457585732ac8SCy Schubert 		if (context->event_cb) {
457685732ac8SCy Schubert 			union tls_event_data ev;
457785732ac8SCy Schubert 
457885732ac8SCy Schubert 			os_memset(&ev, 0, sizeof(ev));
457985732ac8SCy Schubert 			ev.alert.is_local = 1;
458085732ac8SCy Schubert 			ev.alert.type = "fatal";
458185732ac8SCy Schubert 			ev.alert.description = "insufficient security";
458285732ac8SCy Schubert 			context->event_cb(context->cb_ctx, TLS_ALERT, &ev);
458385732ac8SCy Schubert 		}
458485732ac8SCy Schubert 		/*
458585732ac8SCy Schubert 		 * Could send a TLS Alert to the server, but for now, simply
458685732ac8SCy Schubert 		 * terminate handshake.
458785732ac8SCy Schubert 		 */
458885732ac8SCy Schubert 		conn->failed++;
458985732ac8SCy Schubert 		conn->write_alerts++;
459085732ac8SCy Schubert 		return NULL;
459185732ac8SCy Schubert 	}
459285732ac8SCy Schubert #endif /* CONFIG_SUITEB */
459339beb93cSSam Leffler 
459439beb93cSSam Leffler 	/* Get the TLS handshake data to be sent to the server */
459539beb93cSSam Leffler 	res = BIO_ctrl_pending(conn->ssl_out);
459639beb93cSSam Leffler 	wpa_printf(MSG_DEBUG, "SSL: %d bytes pending from ssl_out", res);
4597e28a4053SRui Paulo 	out_data = wpabuf_alloc(res);
459839beb93cSSam Leffler 	if (out_data == NULL) {
459939beb93cSSam Leffler 		wpa_printf(MSG_DEBUG, "SSL: Failed to allocate memory for "
460039beb93cSSam Leffler 			   "handshake output (%d bytes)", res);
460139beb93cSSam Leffler 		if (BIO_reset(conn->ssl_out) < 0) {
460239beb93cSSam Leffler 			tls_show_errors(MSG_INFO, __func__,
460339beb93cSSam Leffler 					"BIO_reset failed");
460439beb93cSSam Leffler 		}
460539beb93cSSam Leffler 		return NULL;
460639beb93cSSam Leffler 	}
4607e28a4053SRui Paulo 	res = res == 0 ? 0 : BIO_read(conn->ssl_out, wpabuf_mhead(out_data),
4608e28a4053SRui Paulo 				      res);
460939beb93cSSam Leffler 	if (res < 0) {
461039beb93cSSam Leffler 		tls_show_errors(MSG_INFO, __func__,
461139beb93cSSam Leffler 				"Handshake failed - BIO_read");
461239beb93cSSam Leffler 		if (BIO_reset(conn->ssl_out) < 0) {
461339beb93cSSam Leffler 			tls_show_errors(MSG_INFO, __func__,
461439beb93cSSam Leffler 					"BIO_reset failed");
461539beb93cSSam Leffler 		}
4616e28a4053SRui Paulo 		wpabuf_free(out_data);
461739beb93cSSam Leffler 		return NULL;
461839beb93cSSam Leffler 	}
4619e28a4053SRui Paulo 	wpabuf_put(out_data, res);
462039beb93cSSam Leffler 
4621e28a4053SRui Paulo 	return out_data;
4622e28a4053SRui Paulo }
4623e28a4053SRui Paulo 
4624e28a4053SRui Paulo 
4625e28a4053SRui Paulo static struct wpabuf *
openssl_get_appl_data(struct tls_connection * conn,size_t max_len)4626e28a4053SRui Paulo openssl_get_appl_data(struct tls_connection *conn, size_t max_len)
4627e28a4053SRui Paulo {
4628e28a4053SRui Paulo 	struct wpabuf *appl_data;
4629e28a4053SRui Paulo 	int res;
4630e28a4053SRui Paulo 
4631e28a4053SRui Paulo 	appl_data = wpabuf_alloc(max_len + 100);
4632e28a4053SRui Paulo 	if (appl_data == NULL)
4633e28a4053SRui Paulo 		return NULL;
4634e28a4053SRui Paulo 
4635e28a4053SRui Paulo 	res = SSL_read(conn->ssl, wpabuf_mhead(appl_data),
4636e28a4053SRui Paulo 		       wpabuf_size(appl_data));
463739beb93cSSam Leffler 	if (res < 0) {
46383157ba21SRui Paulo 		int err = SSL_get_error(conn->ssl, res);
46393157ba21SRui Paulo 		if (err == SSL_ERROR_WANT_READ ||
46403157ba21SRui Paulo 		    err == SSL_ERROR_WANT_WRITE) {
4641e28a4053SRui Paulo 			wpa_printf(MSG_DEBUG, "SSL: No Application Data "
46423157ba21SRui Paulo 				   "included");
46433157ba21SRui Paulo 		} else {
464439beb93cSSam Leffler 			tls_show_errors(MSG_INFO, __func__,
4645e28a4053SRui Paulo 					"Failed to read possible "
464639beb93cSSam Leffler 					"Application Data");
46473157ba21SRui Paulo 		}
4648e28a4053SRui Paulo 		wpabuf_free(appl_data);
4649e28a4053SRui Paulo 		return NULL;
4650e28a4053SRui Paulo 	}
4651e28a4053SRui Paulo 
4652e28a4053SRui Paulo 	wpabuf_put(appl_data, res);
4653e28a4053SRui Paulo 	wpa_hexdump_buf_key(MSG_MSGDUMP, "SSL: Application Data in Finished "
4654e28a4053SRui Paulo 			    "message", appl_data);
4655e28a4053SRui Paulo 
4656e28a4053SRui Paulo 	return appl_data;
4657e28a4053SRui Paulo }
4658e28a4053SRui Paulo 
4659e28a4053SRui Paulo 
4660e28a4053SRui Paulo static struct wpabuf *
openssl_connection_handshake(struct tls_connection * conn,const struct wpabuf * in_data,struct wpabuf ** appl_data)4661e28a4053SRui Paulo openssl_connection_handshake(struct tls_connection *conn,
4662e28a4053SRui Paulo 			     const struct wpabuf *in_data,
466385732ac8SCy Schubert 			     struct wpabuf **appl_data)
4664e28a4053SRui Paulo {
4665e28a4053SRui Paulo 	struct wpabuf *out_data;
4666e28a4053SRui Paulo 
4667e28a4053SRui Paulo 	if (appl_data)
466839beb93cSSam Leffler 		*appl_data = NULL;
4669e28a4053SRui Paulo 
467085732ac8SCy Schubert 	out_data = openssl_handshake(conn, in_data);
4671e28a4053SRui Paulo 	if (out_data == NULL)
4672e28a4053SRui Paulo 		return NULL;
46735b9c547cSRui Paulo 	if (conn->invalid_hb_used) {
46745b9c547cSRui Paulo 		wpa_printf(MSG_INFO, "TLS: Heartbeat attack detected - do not send response");
46755b9c547cSRui Paulo 		wpabuf_free(out_data);
46765b9c547cSRui Paulo 		return NULL;
46775b9c547cSRui Paulo 	}
4678e28a4053SRui Paulo 
4679325151a3SRui Paulo 	if (SSL_is_init_finished(conn->ssl)) {
4680325151a3SRui Paulo 		wpa_printf(MSG_DEBUG,
4681325151a3SRui Paulo 			   "OpenSSL: Handshake finished - resumed=%d",
4682325151a3SRui Paulo 			   tls_connection_resumed(conn->ssl_ctx, conn));
4683206b73d0SCy Schubert 		if (conn->server) {
4684206b73d0SCy Schubert 			char *buf;
4685206b73d0SCy Schubert 			size_t buflen = 2000;
4686206b73d0SCy Schubert 
4687206b73d0SCy Schubert 			buf = os_malloc(buflen);
4688206b73d0SCy Schubert 			if (buf) {
4689206b73d0SCy Schubert 				if (SSL_get_shared_ciphers(conn->ssl, buf,
4690206b73d0SCy Schubert 							   buflen)) {
4691206b73d0SCy Schubert 					buf[buflen - 1] = '\0';
4692206b73d0SCy Schubert 					wpa_printf(MSG_DEBUG,
4693206b73d0SCy Schubert 						   "OpenSSL: Shared ciphers: %s",
4694206b73d0SCy Schubert 						   buf);
4695206b73d0SCy Schubert 				}
4696206b73d0SCy Schubert 				os_free(buf);
4697206b73d0SCy Schubert 			}
4698206b73d0SCy Schubert 		}
4699325151a3SRui Paulo 		if (appl_data && in_data)
4700325151a3SRui Paulo 			*appl_data = openssl_get_appl_data(conn,
4701325151a3SRui Paulo 							   wpabuf_len(in_data));
4702325151a3SRui Paulo 	}
470339beb93cSSam Leffler 
47045b9c547cSRui Paulo 	if (conn->invalid_hb_used) {
47055b9c547cSRui Paulo 		wpa_printf(MSG_INFO, "TLS: Heartbeat attack detected - do not send response");
47065b9c547cSRui Paulo 		if (appl_data) {
47075b9c547cSRui Paulo 			wpabuf_free(*appl_data);
47085b9c547cSRui Paulo 			*appl_data = NULL;
47095b9c547cSRui Paulo 		}
47105b9c547cSRui Paulo 		wpabuf_free(out_data);
47115b9c547cSRui Paulo 		return NULL;
47125b9c547cSRui Paulo 	}
47135b9c547cSRui Paulo 
471439beb93cSSam Leffler 	return out_data;
471539beb93cSSam Leffler }
471639beb93cSSam Leffler 
471739beb93cSSam Leffler 
4718e28a4053SRui Paulo struct wpabuf *
tls_connection_handshake(void * ssl_ctx,struct tls_connection * conn,const struct wpabuf * in_data,struct wpabuf ** appl_data)4719e28a4053SRui Paulo tls_connection_handshake(void *ssl_ctx, struct tls_connection *conn,
4720e28a4053SRui Paulo 			 const struct wpabuf *in_data,
4721e28a4053SRui Paulo 			 struct wpabuf **appl_data)
4722e28a4053SRui Paulo {
472385732ac8SCy Schubert 	return openssl_connection_handshake(conn, in_data, appl_data);
4724e28a4053SRui Paulo }
4725e28a4053SRui Paulo 
4726e28a4053SRui Paulo 
tls_connection_server_handshake(void * tls_ctx,struct tls_connection * conn,const struct wpabuf * in_data,struct wpabuf ** appl_data)4727e28a4053SRui Paulo struct wpabuf * tls_connection_server_handshake(void *tls_ctx,
472839beb93cSSam Leffler 						struct tls_connection *conn,
4729e28a4053SRui Paulo 						const struct wpabuf *in_data,
4730e28a4053SRui Paulo 						struct wpabuf **appl_data)
4731e28a4053SRui Paulo {
473285732ac8SCy Schubert 	conn->server = 1;
473385732ac8SCy Schubert 	return openssl_connection_handshake(conn, in_data, appl_data);
4734e28a4053SRui Paulo }
4735e28a4053SRui Paulo 
4736e28a4053SRui Paulo 
tls_connection_encrypt(void * tls_ctx,struct tls_connection * conn,const struct wpabuf * in_data)4737e28a4053SRui Paulo struct wpabuf * tls_connection_encrypt(void *tls_ctx,
4738e28a4053SRui Paulo 				       struct tls_connection *conn,
4739e28a4053SRui Paulo 				       const struct wpabuf *in_data)
474039beb93cSSam Leffler {
474139beb93cSSam Leffler 	int res;
4742e28a4053SRui Paulo 	struct wpabuf *buf;
474339beb93cSSam Leffler 
474439beb93cSSam Leffler 	if (conn == NULL)
4745e28a4053SRui Paulo 		return NULL;
474639beb93cSSam Leffler 
474739beb93cSSam Leffler 	/* Give plaintext data for OpenSSL to encrypt into the TLS tunnel. */
474839beb93cSSam Leffler 	if ((res = BIO_reset(conn->ssl_in)) < 0 ||
474939beb93cSSam Leffler 	    (res = BIO_reset(conn->ssl_out)) < 0) {
475039beb93cSSam Leffler 		tls_show_errors(MSG_INFO, __func__, "BIO_reset failed");
4751e28a4053SRui Paulo 		return NULL;
475239beb93cSSam Leffler 	}
4753e28a4053SRui Paulo 	res = SSL_write(conn->ssl, wpabuf_head(in_data), wpabuf_len(in_data));
475439beb93cSSam Leffler 	if (res < 0) {
475539beb93cSSam Leffler 		tls_show_errors(MSG_INFO, __func__,
475639beb93cSSam Leffler 				"Encryption failed - SSL_write");
4757e28a4053SRui Paulo 		return NULL;
475839beb93cSSam Leffler 	}
475939beb93cSSam Leffler 
476039beb93cSSam Leffler 	/* Read encrypted data to be sent to the server */
4761e28a4053SRui Paulo 	buf = wpabuf_alloc(wpabuf_len(in_data) + 300);
4762e28a4053SRui Paulo 	if (buf == NULL)
4763e28a4053SRui Paulo 		return NULL;
4764e28a4053SRui Paulo 	res = BIO_read(conn->ssl_out, wpabuf_mhead(buf), wpabuf_size(buf));
476539beb93cSSam Leffler 	if (res < 0) {
476639beb93cSSam Leffler 		tls_show_errors(MSG_INFO, __func__,
476739beb93cSSam Leffler 				"Encryption failed - BIO_read");
4768e28a4053SRui Paulo 		wpabuf_free(buf);
4769e28a4053SRui Paulo 		return NULL;
477039beb93cSSam Leffler 	}
4771e28a4053SRui Paulo 	wpabuf_put(buf, res);
477239beb93cSSam Leffler 
4773e28a4053SRui Paulo 	return buf;
477439beb93cSSam Leffler }
477539beb93cSSam Leffler 
477639beb93cSSam Leffler 
tls_connection_decrypt(void * tls_ctx,struct tls_connection * conn,const struct wpabuf * in_data)4777e28a4053SRui Paulo struct wpabuf * tls_connection_decrypt(void *tls_ctx,
4778e28a4053SRui Paulo 				       struct tls_connection *conn,
4779e28a4053SRui Paulo 				       const struct wpabuf *in_data)
478039beb93cSSam Leffler {
478139beb93cSSam Leffler 	int res;
4782e28a4053SRui Paulo 	struct wpabuf *buf;
478339beb93cSSam Leffler 
478439beb93cSSam Leffler 	/* Give encrypted data from TLS tunnel for OpenSSL to decrypt. */
4785e28a4053SRui Paulo 	res = BIO_write(conn->ssl_in, wpabuf_head(in_data),
4786e28a4053SRui Paulo 			wpabuf_len(in_data));
478739beb93cSSam Leffler 	if (res < 0) {
478839beb93cSSam Leffler 		tls_show_errors(MSG_INFO, __func__,
478939beb93cSSam Leffler 				"Decryption failed - BIO_write");
4790e28a4053SRui Paulo 		return NULL;
479139beb93cSSam Leffler 	}
479239beb93cSSam Leffler 	if (BIO_reset(conn->ssl_out) < 0) {
479339beb93cSSam Leffler 		tls_show_errors(MSG_INFO, __func__, "BIO_reset failed");
4794e28a4053SRui Paulo 		return NULL;
479539beb93cSSam Leffler 	}
479639beb93cSSam Leffler 
479739beb93cSSam Leffler 	/* Read decrypted data for further processing */
4798e28a4053SRui Paulo 	/*
4799e28a4053SRui Paulo 	 * Even though we try to disable TLS compression, it is possible that
4800e28a4053SRui Paulo 	 * this cannot be done with all TLS libraries. Add extra buffer space
4801e28a4053SRui Paulo 	 * to handle the possibility of the decrypted data being longer than
4802e28a4053SRui Paulo 	 * input data.
4803e28a4053SRui Paulo 	 */
4804e28a4053SRui Paulo 	buf = wpabuf_alloc((wpabuf_len(in_data) + 500) * 3);
4805e28a4053SRui Paulo 	if (buf == NULL)
4806e28a4053SRui Paulo 		return NULL;
4807e28a4053SRui Paulo 	res = SSL_read(conn->ssl, wpabuf_mhead(buf), wpabuf_size(buf));
480839beb93cSSam Leffler 	if (res < 0) {
4809c1d255d3SCy Schubert 		int err = SSL_get_error(conn->ssl, res);
4810c1d255d3SCy Schubert 
4811c1d255d3SCy Schubert 		if (err == SSL_ERROR_WANT_READ) {
4812c1d255d3SCy Schubert 			wpa_printf(MSG_DEBUG,
4813c1d255d3SCy Schubert 				   "SSL: SSL_connect - want more data");
4814c1d255d3SCy Schubert 			res = 0;
4815c1d255d3SCy Schubert 		} else {
481639beb93cSSam Leffler 			tls_show_errors(MSG_INFO, __func__,
481739beb93cSSam Leffler 					"Decryption failed - SSL_read");
4818e28a4053SRui Paulo 			wpabuf_free(buf);
4819e28a4053SRui Paulo 			return NULL;
482039beb93cSSam Leffler 		}
4821c1d255d3SCy Schubert 	}
4822e28a4053SRui Paulo 	wpabuf_put(buf, res);
482339beb93cSSam Leffler 
48245b9c547cSRui Paulo 	if (conn->invalid_hb_used) {
48255b9c547cSRui Paulo 		wpa_printf(MSG_INFO, "TLS: Heartbeat attack detected - do not send response");
48265b9c547cSRui Paulo 		wpabuf_free(buf);
48275b9c547cSRui Paulo 		return NULL;
48285b9c547cSRui Paulo 	}
48295b9c547cSRui Paulo 
4830e28a4053SRui Paulo 	return buf;
483139beb93cSSam Leffler }
483239beb93cSSam Leffler 
483339beb93cSSam Leffler 
tls_connection_resumed(void * ssl_ctx,struct tls_connection * conn)483439beb93cSSam Leffler int tls_connection_resumed(void *ssl_ctx, struct tls_connection *conn)
483539beb93cSSam Leffler {
483685732ac8SCy Schubert 	return conn ? SSL_session_reused(conn->ssl) : 0;
483739beb93cSSam Leffler }
483839beb93cSSam Leffler 
483939beb93cSSam Leffler 
tls_connection_set_cipher_list(void * tls_ctx,struct tls_connection * conn,u8 * ciphers)484039beb93cSSam Leffler int tls_connection_set_cipher_list(void *tls_ctx, struct tls_connection *conn,
484139beb93cSSam Leffler 				   u8 *ciphers)
484239beb93cSSam Leffler {
4843780fb4a2SCy Schubert 	char buf[500], *pos, *end;
484439beb93cSSam Leffler 	u8 *c;
484539beb93cSSam Leffler 	int ret;
484639beb93cSSam Leffler 
484739beb93cSSam Leffler 	if (conn == NULL || conn->ssl == NULL || ciphers == NULL)
484839beb93cSSam Leffler 		return -1;
484939beb93cSSam Leffler 
485039beb93cSSam Leffler 	buf[0] = '\0';
485139beb93cSSam Leffler 	pos = buf;
485239beb93cSSam Leffler 	end = pos + sizeof(buf);
485339beb93cSSam Leffler 
485439beb93cSSam Leffler 	c = ciphers;
485539beb93cSSam Leffler 	while (*c != TLS_CIPHER_NONE) {
485639beb93cSSam Leffler 		const char *suite;
485739beb93cSSam Leffler 
485839beb93cSSam Leffler 		switch (*c) {
485939beb93cSSam Leffler 		case TLS_CIPHER_RC4_SHA:
486039beb93cSSam Leffler 			suite = "RC4-SHA";
486139beb93cSSam Leffler 			break;
486239beb93cSSam Leffler 		case TLS_CIPHER_AES128_SHA:
486339beb93cSSam Leffler 			suite = "AES128-SHA";
486439beb93cSSam Leffler 			break;
486539beb93cSSam Leffler 		case TLS_CIPHER_RSA_DHE_AES128_SHA:
486639beb93cSSam Leffler 			suite = "DHE-RSA-AES128-SHA";
486739beb93cSSam Leffler 			break;
486839beb93cSSam Leffler 		case TLS_CIPHER_ANON_DH_AES128_SHA:
486939beb93cSSam Leffler 			suite = "ADH-AES128-SHA";
487039beb93cSSam Leffler 			break;
4871780fb4a2SCy Schubert 		case TLS_CIPHER_RSA_DHE_AES256_SHA:
4872780fb4a2SCy Schubert 			suite = "DHE-RSA-AES256-SHA";
4873780fb4a2SCy Schubert 			break;
4874780fb4a2SCy Schubert 		case TLS_CIPHER_AES256_SHA:
4875780fb4a2SCy Schubert 			suite = "AES256-SHA";
4876780fb4a2SCy Schubert 			break;
487739beb93cSSam Leffler 		default:
487839beb93cSSam Leffler 			wpa_printf(MSG_DEBUG, "TLS: Unsupported "
487939beb93cSSam Leffler 				   "cipher selection: %d", *c);
488039beb93cSSam Leffler 			return -1;
488139beb93cSSam Leffler 		}
488239beb93cSSam Leffler 		ret = os_snprintf(pos, end - pos, ":%s", suite);
48835b9c547cSRui Paulo 		if (os_snprintf_error(end - pos, ret))
488439beb93cSSam Leffler 			break;
488539beb93cSSam Leffler 		pos += ret;
488639beb93cSSam Leffler 
488739beb93cSSam Leffler 		c++;
488839beb93cSSam Leffler 	}
4889206b73d0SCy Schubert 	if (!buf[0]) {
4890206b73d0SCy Schubert 		wpa_printf(MSG_DEBUG, "OpenSSL: No ciphers listed");
4891206b73d0SCy Schubert 		return -1;
4892206b73d0SCy Schubert 	}
489339beb93cSSam Leffler 
489439beb93cSSam Leffler 	wpa_printf(MSG_DEBUG, "OpenSSL: cipher suites: %s", buf + 1);
489539beb93cSSam Leffler 
4896780fb4a2SCy Schubert #if OPENSSL_VERSION_NUMBER >= 0x10100000L && !defined(LIBRESSL_VERSION_NUMBER)
4897206b73d0SCy Schubert #ifdef EAP_FAST_OR_TEAP
4898325151a3SRui Paulo 	if (os_strstr(buf, ":ADH-")) {
4899325151a3SRui Paulo 		/*
4900325151a3SRui Paulo 		 * Need to drop to security level 0 to allow anonymous
4901325151a3SRui Paulo 		 * cipher suites for EAP-FAST.
4902325151a3SRui Paulo 		 */
4903325151a3SRui Paulo 		SSL_set_security_level(conn->ssl, 0);
4904325151a3SRui Paulo 	} else if (SSL_get_security_level(conn->ssl) == 0) {
4905325151a3SRui Paulo 		/* Force at least security level 1 */
4906325151a3SRui Paulo 		SSL_set_security_level(conn->ssl, 1);
4907325151a3SRui Paulo 	}
4908206b73d0SCy Schubert #endif /* EAP_FAST_OR_TEAP */
4909325151a3SRui Paulo #endif
4910325151a3SRui Paulo 
491139beb93cSSam Leffler 	if (SSL_set_cipher_list(conn->ssl, buf + 1) != 1) {
491239beb93cSSam Leffler 		tls_show_errors(MSG_INFO, __func__,
491339beb93cSSam Leffler 				"Cipher suite configuration failed");
491439beb93cSSam Leffler 		return -1;
491539beb93cSSam Leffler 	}
491639beb93cSSam Leffler 
491739beb93cSSam Leffler 	return 0;
491839beb93cSSam Leffler }
491939beb93cSSam Leffler 
492039beb93cSSam Leffler 
tls_get_version(void * ssl_ctx,struct tls_connection * conn,char * buf,size_t buflen)4921325151a3SRui Paulo int tls_get_version(void *ssl_ctx, struct tls_connection *conn,
4922325151a3SRui Paulo 		    char *buf, size_t buflen)
4923325151a3SRui Paulo {
4924325151a3SRui Paulo 	const char *name;
4925325151a3SRui Paulo 	if (conn == NULL || conn->ssl == NULL)
4926325151a3SRui Paulo 		return -1;
4927325151a3SRui Paulo 
4928325151a3SRui Paulo 	name = SSL_get_version(conn->ssl);
4929325151a3SRui Paulo 	if (name == NULL)
4930325151a3SRui Paulo 		return -1;
4931325151a3SRui Paulo 
4932325151a3SRui Paulo 	os_strlcpy(buf, name, buflen);
4933325151a3SRui Paulo 	return 0;
4934325151a3SRui Paulo }
4935325151a3SRui Paulo 
4936325151a3SRui Paulo 
tls_get_cipher(void * ssl_ctx,struct tls_connection * conn,char * buf,size_t buflen)493739beb93cSSam Leffler int tls_get_cipher(void *ssl_ctx, struct tls_connection *conn,
493839beb93cSSam Leffler 		   char *buf, size_t buflen)
493939beb93cSSam Leffler {
494039beb93cSSam Leffler 	const char *name;
494139beb93cSSam Leffler 	if (conn == NULL || conn->ssl == NULL)
494239beb93cSSam Leffler 		return -1;
494339beb93cSSam Leffler 
494439beb93cSSam Leffler 	name = SSL_get_cipher(conn->ssl);
494539beb93cSSam Leffler 	if (name == NULL)
494639beb93cSSam Leffler 		return -1;
494739beb93cSSam Leffler 
494839beb93cSSam Leffler 	os_strlcpy(buf, name, buflen);
494939beb93cSSam Leffler 	return 0;
495039beb93cSSam Leffler }
495139beb93cSSam Leffler 
495239beb93cSSam Leffler 
tls_connection_enable_workaround(void * ssl_ctx,struct tls_connection * conn)495339beb93cSSam Leffler int tls_connection_enable_workaround(void *ssl_ctx,
495439beb93cSSam Leffler 				     struct tls_connection *conn)
495539beb93cSSam Leffler {
495639beb93cSSam Leffler 	SSL_set_options(conn->ssl, SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS);
495739beb93cSSam Leffler 
495839beb93cSSam Leffler 	return 0;
495939beb93cSSam Leffler }
496039beb93cSSam Leffler 
496139beb93cSSam Leffler 
4962206b73d0SCy Schubert #ifdef EAP_FAST_OR_TEAP
496339beb93cSSam Leffler /* ClientHello TLS extensions require a patch to openssl, so this function is
496439beb93cSSam Leffler  * commented out unless explicitly needed for EAP-FAST in order to be able to
496539beb93cSSam Leffler  * build this file with unmodified openssl. */
tls_connection_client_hello_ext(void * ssl_ctx,struct tls_connection * conn,int ext_type,const u8 * data,size_t data_len)496639beb93cSSam Leffler int tls_connection_client_hello_ext(void *ssl_ctx, struct tls_connection *conn,
496739beb93cSSam Leffler 				    int ext_type, const u8 *data,
496839beb93cSSam Leffler 				    size_t data_len)
496939beb93cSSam Leffler {
497039beb93cSSam Leffler 	if (conn == NULL || conn->ssl == NULL || ext_type != 35)
497139beb93cSSam Leffler 		return -1;
497239beb93cSSam Leffler 
497339beb93cSSam Leffler 	if (SSL_set_session_ticket_ext(conn->ssl, (void *) data,
497439beb93cSSam Leffler 				       data_len) != 1)
497539beb93cSSam Leffler 		return -1;
497639beb93cSSam Leffler 
497739beb93cSSam Leffler 	return 0;
497839beb93cSSam Leffler }
4979206b73d0SCy Schubert #endif /* EAP_FAST_OR_TEAP */
498039beb93cSSam Leffler 
498139beb93cSSam Leffler 
tls_connection_get_failed(void * ssl_ctx,struct tls_connection * conn)498239beb93cSSam Leffler int tls_connection_get_failed(void *ssl_ctx, struct tls_connection *conn)
498339beb93cSSam Leffler {
498439beb93cSSam Leffler 	if (conn == NULL)
498539beb93cSSam Leffler 		return -1;
498639beb93cSSam Leffler 	return conn->failed;
498739beb93cSSam Leffler }
498839beb93cSSam Leffler 
498939beb93cSSam Leffler 
tls_connection_get_read_alerts(void * ssl_ctx,struct tls_connection * conn)499039beb93cSSam Leffler int tls_connection_get_read_alerts(void *ssl_ctx, struct tls_connection *conn)
499139beb93cSSam Leffler {
499239beb93cSSam Leffler 	if (conn == NULL)
499339beb93cSSam Leffler 		return -1;
499439beb93cSSam Leffler 	return conn->read_alerts;
499539beb93cSSam Leffler }
499639beb93cSSam Leffler 
499739beb93cSSam Leffler 
tls_connection_get_write_alerts(void * ssl_ctx,struct tls_connection * conn)499839beb93cSSam Leffler int tls_connection_get_write_alerts(void *ssl_ctx, struct tls_connection *conn)
499939beb93cSSam Leffler {
500039beb93cSSam Leffler 	if (conn == NULL)
500139beb93cSSam Leffler 		return -1;
500239beb93cSSam Leffler 	return conn->write_alerts;
500339beb93cSSam Leffler }
500439beb93cSSam Leffler 
500539beb93cSSam Leffler 
50065b9c547cSRui Paulo #ifdef HAVE_OCSP
50075b9c547cSRui Paulo 
ocsp_debug_print_resp(OCSP_RESPONSE * rsp)50085b9c547cSRui Paulo static void ocsp_debug_print_resp(OCSP_RESPONSE *rsp)
50095b9c547cSRui Paulo {
50105b9c547cSRui Paulo #ifndef CONFIG_NO_STDOUT_DEBUG
50115b9c547cSRui Paulo 	BIO *out;
50125b9c547cSRui Paulo 	size_t rlen;
50135b9c547cSRui Paulo 	char *txt;
50145b9c547cSRui Paulo 	int res;
50155b9c547cSRui Paulo 
50165b9c547cSRui Paulo 	if (wpa_debug_level > MSG_DEBUG)
50175b9c547cSRui Paulo 		return;
50185b9c547cSRui Paulo 
50195b9c547cSRui Paulo 	out = BIO_new(BIO_s_mem());
50205b9c547cSRui Paulo 	if (!out)
50215b9c547cSRui Paulo 		return;
50225b9c547cSRui Paulo 
50235b9c547cSRui Paulo 	OCSP_RESPONSE_print(out, rsp, 0);
50245b9c547cSRui Paulo 	rlen = BIO_ctrl_pending(out);
50255b9c547cSRui Paulo 	txt = os_malloc(rlen + 1);
50265b9c547cSRui Paulo 	if (!txt) {
50275b9c547cSRui Paulo 		BIO_free(out);
50285b9c547cSRui Paulo 		return;
50295b9c547cSRui Paulo 	}
50305b9c547cSRui Paulo 
50315b9c547cSRui Paulo 	res = BIO_read(out, txt, rlen);
50325b9c547cSRui Paulo 	if (res > 0) {
50335b9c547cSRui Paulo 		txt[res] = '\0';
50345b9c547cSRui Paulo 		wpa_printf(MSG_DEBUG, "OpenSSL: OCSP Response\n%s", txt);
50355b9c547cSRui Paulo 	}
50365b9c547cSRui Paulo 	os_free(txt);
50375b9c547cSRui Paulo 	BIO_free(out);
50385b9c547cSRui Paulo #endif /* CONFIG_NO_STDOUT_DEBUG */
50395b9c547cSRui Paulo }
50405b9c547cSRui Paulo 
50415b9c547cSRui Paulo 
ocsp_resp_cb(SSL * s,void * arg)50425b9c547cSRui Paulo static int ocsp_resp_cb(SSL *s, void *arg)
50435b9c547cSRui Paulo {
50445b9c547cSRui Paulo 	struct tls_connection *conn = arg;
50455b9c547cSRui Paulo 	const unsigned char *p;
504685732ac8SCy Schubert 	int len, status, reason, res;
50475b9c547cSRui Paulo 	OCSP_RESPONSE *rsp;
50485b9c547cSRui Paulo 	OCSP_BASICRESP *basic;
50495b9c547cSRui Paulo 	OCSP_CERTID *id;
50505b9c547cSRui Paulo 	ASN1_GENERALIZEDTIME *produced_at, *this_update, *next_update;
50515b9c547cSRui Paulo 	X509_STORE *store;
50525b9c547cSRui Paulo 	STACK_OF(X509) *certs = NULL;
50535b9c547cSRui Paulo 
50545b9c547cSRui Paulo 	len = SSL_get_tlsext_status_ocsp_resp(s, &p);
50555b9c547cSRui Paulo 	if (!p) {
5056*a90b9d01SCy Schubert #if OPENSSL_VERSION_NUMBER >= 0x10101000L
5057*a90b9d01SCy Schubert #if !defined(LIBRESSL_VERSION_NUMBER) || LIBRESSL_VERSION_NUMBER >= 0x30400000L
5058*a90b9d01SCy Schubert 		if (SSL_version(s) == TLS1_3_VERSION && SSL_session_reused(s)) {
5059*a90b9d01SCy Schubert 			/* TLS 1.3 sends the OCSP response with the server
5060*a90b9d01SCy Schubert 			 * Certificate message. Since that Certificate message
5061*a90b9d01SCy Schubert 			 * is not sent when resuming a session, there can be no
5062*a90b9d01SCy Schubert 			 * new OCSP response. Allow this since the OCSP response
5063*a90b9d01SCy Schubert 			 * was validated when checking the initial certificate
5064*a90b9d01SCy Schubert 			 * exchange. */
5065*a90b9d01SCy Schubert 			wpa_printf(MSG_DEBUG,
5066*a90b9d01SCy Schubert 				   "OpenSSL: Allow no OCSP response when using TLS 1.3 and a resumed session");
5067*a90b9d01SCy Schubert 			return 1;
5068*a90b9d01SCy Schubert 		}
5069*a90b9d01SCy Schubert #endif
5070*a90b9d01SCy Schubert #endif
50715b9c547cSRui Paulo 		wpa_printf(MSG_DEBUG, "OpenSSL: No OCSP response received");
50725b9c547cSRui Paulo 		return (conn->flags & TLS_CONN_REQUIRE_OCSP) ? 0 : 1;
50735b9c547cSRui Paulo 	}
50745b9c547cSRui Paulo 
50755b9c547cSRui Paulo 	wpa_hexdump(MSG_DEBUG, "OpenSSL: OCSP response", p, len);
50765b9c547cSRui Paulo 
50775b9c547cSRui Paulo 	rsp = d2i_OCSP_RESPONSE(NULL, &p, len);
50785b9c547cSRui Paulo 	if (!rsp) {
50795b9c547cSRui Paulo 		wpa_printf(MSG_INFO, "OpenSSL: Failed to parse OCSP response");
50805b9c547cSRui Paulo 		return 0;
50815b9c547cSRui Paulo 	}
50825b9c547cSRui Paulo 
50835b9c547cSRui Paulo 	ocsp_debug_print_resp(rsp);
50845b9c547cSRui Paulo 
50855b9c547cSRui Paulo 	status = OCSP_response_status(rsp);
50865b9c547cSRui Paulo 	if (status != OCSP_RESPONSE_STATUS_SUCCESSFUL) {
50875b9c547cSRui Paulo 		wpa_printf(MSG_INFO, "OpenSSL: OCSP responder error %d (%s)",
50885b9c547cSRui Paulo 			   status, OCSP_response_status_str(status));
50895b9c547cSRui Paulo 		return 0;
50905b9c547cSRui Paulo 	}
50915b9c547cSRui Paulo 
50925b9c547cSRui Paulo 	basic = OCSP_response_get1_basic(rsp);
50935b9c547cSRui Paulo 	if (!basic) {
50945b9c547cSRui Paulo 		wpa_printf(MSG_INFO, "OpenSSL: Could not find BasicOCSPResponse");
50955b9c547cSRui Paulo 		return 0;
50965b9c547cSRui Paulo 	}
50975b9c547cSRui Paulo 
50985b9c547cSRui Paulo 	store = SSL_CTX_get_cert_store(conn->ssl_ctx);
50995b9c547cSRui Paulo 	if (conn->peer_issuer) {
51005b9c547cSRui Paulo 		debug_print_cert(conn->peer_issuer, "Add OCSP issuer");
51015b9c547cSRui Paulo 
51025b9c547cSRui Paulo 		if (X509_STORE_add_cert(store, conn->peer_issuer) != 1) {
51035b9c547cSRui Paulo 			tls_show_errors(MSG_INFO, __func__,
51045b9c547cSRui Paulo 					"OpenSSL: Could not add issuer to certificate store");
51055b9c547cSRui Paulo 		}
51065b9c547cSRui Paulo 		certs = sk_X509_new_null();
51075b9c547cSRui Paulo 		if (certs) {
51085b9c547cSRui Paulo 			X509 *cert;
51095b9c547cSRui Paulo 			cert = X509_dup(conn->peer_issuer);
51105b9c547cSRui Paulo 			if (cert && !sk_X509_push(certs, cert)) {
51115b9c547cSRui Paulo 				tls_show_errors(
51125b9c547cSRui Paulo 					MSG_INFO, __func__,
51135b9c547cSRui Paulo 					"OpenSSL: Could not add issuer to OCSP responder trust store");
51145b9c547cSRui Paulo 				X509_free(cert);
51155b9c547cSRui Paulo 				sk_X509_free(certs);
51165b9c547cSRui Paulo 				certs = NULL;
51175b9c547cSRui Paulo 			}
51185b9c547cSRui Paulo 			if (certs && conn->peer_issuer_issuer) {
51195b9c547cSRui Paulo 				cert = X509_dup(conn->peer_issuer_issuer);
51205b9c547cSRui Paulo 				if (cert && !sk_X509_push(certs, cert)) {
51215b9c547cSRui Paulo 					tls_show_errors(
51225b9c547cSRui Paulo 						MSG_INFO, __func__,
51235b9c547cSRui Paulo 						"OpenSSL: Could not add issuer's issuer to OCSP responder trust store");
51245b9c547cSRui Paulo 					X509_free(cert);
51255b9c547cSRui Paulo 				}
51265b9c547cSRui Paulo 			}
51275b9c547cSRui Paulo 		}
51285b9c547cSRui Paulo 	}
51295b9c547cSRui Paulo 
51305b9c547cSRui Paulo 	status = OCSP_basic_verify(basic, certs, store, OCSP_TRUSTOTHER);
51315b9c547cSRui Paulo 	sk_X509_pop_free(certs, X509_free);
51325b9c547cSRui Paulo 	if (status <= 0) {
51335b9c547cSRui Paulo 		tls_show_errors(MSG_INFO, __func__,
51345b9c547cSRui Paulo 				"OpenSSL: OCSP response failed verification");
51355b9c547cSRui Paulo 		OCSP_BASICRESP_free(basic);
51365b9c547cSRui Paulo 		OCSP_RESPONSE_free(rsp);
51375b9c547cSRui Paulo 		return 0;
51385b9c547cSRui Paulo 	}
51395b9c547cSRui Paulo 
51405b9c547cSRui Paulo 	wpa_printf(MSG_DEBUG, "OpenSSL: OCSP response verification succeeded");
51415b9c547cSRui Paulo 
51425b9c547cSRui Paulo 	if (!conn->peer_cert) {
51435b9c547cSRui Paulo 		wpa_printf(MSG_DEBUG, "OpenSSL: Peer certificate not available for OCSP status check");
51445b9c547cSRui Paulo 		OCSP_BASICRESP_free(basic);
51455b9c547cSRui Paulo 		OCSP_RESPONSE_free(rsp);
51465b9c547cSRui Paulo 		return 0;
51475b9c547cSRui Paulo 	}
51485b9c547cSRui Paulo 
51495b9c547cSRui Paulo 	if (!conn->peer_issuer) {
51505b9c547cSRui Paulo 		wpa_printf(MSG_DEBUG, "OpenSSL: Peer issuer certificate not available for OCSP status check");
51515b9c547cSRui Paulo 		OCSP_BASICRESP_free(basic);
51525b9c547cSRui Paulo 		OCSP_RESPONSE_free(rsp);
51535b9c547cSRui Paulo 		return 0;
51545b9c547cSRui Paulo 	}
51555b9c547cSRui Paulo 
515685732ac8SCy Schubert 	id = OCSP_cert_to_id(EVP_sha256(), conn->peer_cert, conn->peer_issuer);
51575b9c547cSRui Paulo 	if (!id) {
515885732ac8SCy Schubert 		wpa_printf(MSG_DEBUG,
515985732ac8SCy Schubert 			   "OpenSSL: Could not create OCSP certificate identifier (SHA256)");
51605b9c547cSRui Paulo 		OCSP_BASICRESP_free(basic);
51615b9c547cSRui Paulo 		OCSP_RESPONSE_free(rsp);
51625b9c547cSRui Paulo 		return 0;
51635b9c547cSRui Paulo 	}
51645b9c547cSRui Paulo 
516585732ac8SCy Schubert 	res = OCSP_resp_find_status(basic, id, &status, &reason, &produced_at,
516685732ac8SCy Schubert 				    &this_update, &next_update);
516785732ac8SCy Schubert 	if (!res) {
5168206b73d0SCy Schubert 		OCSP_CERTID_free(id);
516985732ac8SCy Schubert 		id = OCSP_cert_to_id(NULL, conn->peer_cert, conn->peer_issuer);
517085732ac8SCy Schubert 		if (!id) {
517185732ac8SCy Schubert 			wpa_printf(MSG_DEBUG,
517285732ac8SCy Schubert 				   "OpenSSL: Could not create OCSP certificate identifier (SHA1)");
517385732ac8SCy Schubert 			OCSP_BASICRESP_free(basic);
517485732ac8SCy Schubert 			OCSP_RESPONSE_free(rsp);
517585732ac8SCy Schubert 			return 0;
517685732ac8SCy Schubert 		}
517785732ac8SCy Schubert 
517885732ac8SCy Schubert 		res = OCSP_resp_find_status(basic, id, &status, &reason,
517985732ac8SCy Schubert 					    &produced_at, &this_update,
518085732ac8SCy Schubert 					    &next_update);
518185732ac8SCy Schubert 	}
518285732ac8SCy Schubert 
518385732ac8SCy Schubert 	if (!res) {
51845b9c547cSRui Paulo 		wpa_printf(MSG_INFO, "OpenSSL: Could not find current server certificate from OCSP response%s",
51855b9c547cSRui Paulo 			   (conn->flags & TLS_CONN_REQUIRE_OCSP) ? "" :
51865b9c547cSRui Paulo 			   " (OCSP not required)");
5187780fb4a2SCy Schubert 		OCSP_CERTID_free(id);
51885b9c547cSRui Paulo 		OCSP_BASICRESP_free(basic);
51895b9c547cSRui Paulo 		OCSP_RESPONSE_free(rsp);
51905b9c547cSRui Paulo 		return (conn->flags & TLS_CONN_REQUIRE_OCSP) ? 0 : 1;
51915b9c547cSRui Paulo 	}
5192780fb4a2SCy Schubert 	OCSP_CERTID_free(id);
51935b9c547cSRui Paulo 
51945b9c547cSRui Paulo 	if (!OCSP_check_validity(this_update, next_update, 5 * 60, -1)) {
51955b9c547cSRui Paulo 		tls_show_errors(MSG_INFO, __func__,
51965b9c547cSRui Paulo 				"OpenSSL: OCSP status times invalid");
51975b9c547cSRui Paulo 		OCSP_BASICRESP_free(basic);
51985b9c547cSRui Paulo 		OCSP_RESPONSE_free(rsp);
51995b9c547cSRui Paulo 		return 0;
52005b9c547cSRui Paulo 	}
52015b9c547cSRui Paulo 
52025b9c547cSRui Paulo 	OCSP_BASICRESP_free(basic);
52035b9c547cSRui Paulo 	OCSP_RESPONSE_free(rsp);
52045b9c547cSRui Paulo 
52055b9c547cSRui Paulo 	wpa_printf(MSG_DEBUG, "OpenSSL: OCSP status for server certificate: %s",
52065b9c547cSRui Paulo 		   OCSP_cert_status_str(status));
52075b9c547cSRui Paulo 
52085b9c547cSRui Paulo 	if (status == V_OCSP_CERTSTATUS_GOOD)
52095b9c547cSRui Paulo 		return 1;
52105b9c547cSRui Paulo 	if (status == V_OCSP_CERTSTATUS_REVOKED)
52115b9c547cSRui Paulo 		return 0;
52125b9c547cSRui Paulo 	if (conn->flags & TLS_CONN_REQUIRE_OCSP) {
52135b9c547cSRui Paulo 		wpa_printf(MSG_DEBUG, "OpenSSL: OCSP status unknown, but OCSP required");
52145b9c547cSRui Paulo 		return 0;
52155b9c547cSRui Paulo 	}
52165b9c547cSRui Paulo 	wpa_printf(MSG_DEBUG, "OpenSSL: OCSP status unknown, but OCSP was not required, so allow connection to continue");
52175b9c547cSRui Paulo 	return 1;
52185b9c547cSRui Paulo }
52195b9c547cSRui Paulo 
52205b9c547cSRui Paulo 
ocsp_status_cb(SSL * s,void * arg)52215b9c547cSRui Paulo static int ocsp_status_cb(SSL *s, void *arg)
52225b9c547cSRui Paulo {
52235b9c547cSRui Paulo 	char *tmp;
52245b9c547cSRui Paulo 	char *resp;
52255b9c547cSRui Paulo 	size_t len;
52265b9c547cSRui Paulo 
52275b9c547cSRui Paulo 	if (tls_global->ocsp_stapling_response == NULL) {
52285b9c547cSRui Paulo 		wpa_printf(MSG_DEBUG, "OpenSSL: OCSP status callback - no response configured");
52295b9c547cSRui Paulo 		return SSL_TLSEXT_ERR_OK;
52305b9c547cSRui Paulo 	}
52315b9c547cSRui Paulo 
52325b9c547cSRui Paulo 	resp = os_readfile(tls_global->ocsp_stapling_response, &len);
52335b9c547cSRui Paulo 	if (resp == NULL) {
52345b9c547cSRui Paulo 		wpa_printf(MSG_DEBUG, "OpenSSL: OCSP status callback - could not read response file");
52355b9c547cSRui Paulo 		/* TODO: Build OCSPResponse with responseStatus = internalError
52365b9c547cSRui Paulo 		 */
52375b9c547cSRui Paulo 		return SSL_TLSEXT_ERR_OK;
52385b9c547cSRui Paulo 	}
52395b9c547cSRui Paulo 	wpa_printf(MSG_DEBUG, "OpenSSL: OCSP status callback - send cached response");
52405b9c547cSRui Paulo 	tmp = OPENSSL_malloc(len);
52415b9c547cSRui Paulo 	if (tmp == NULL) {
52425b9c547cSRui Paulo 		os_free(resp);
52435b9c547cSRui Paulo 		return SSL_TLSEXT_ERR_ALERT_FATAL;
52445b9c547cSRui Paulo 	}
52455b9c547cSRui Paulo 
52465b9c547cSRui Paulo 	os_memcpy(tmp, resp, len);
52475b9c547cSRui Paulo 	os_free(resp);
52485b9c547cSRui Paulo 	SSL_set_tlsext_status_ocsp_resp(s, tmp, len);
52495b9c547cSRui Paulo 
52505b9c547cSRui Paulo 	return SSL_TLSEXT_ERR_OK;
52515b9c547cSRui Paulo }
52525b9c547cSRui Paulo 
52535b9c547cSRui Paulo #endif /* HAVE_OCSP */
52545b9c547cSRui Paulo 
52555b9c547cSRui Paulo 
max_str_len(const char ** lines)5256c1d255d3SCy Schubert static size_t max_str_len(const char **lines)
5257c1d255d3SCy Schubert {
5258c1d255d3SCy Schubert 	const char **p;
5259c1d255d3SCy Schubert 	size_t max_len = 0;
5260c1d255d3SCy Schubert 
5261c1d255d3SCy Schubert 	for (p = lines; *p; p++) {
5262c1d255d3SCy Schubert 		size_t len = os_strlen(*p);
5263c1d255d3SCy Schubert 
5264c1d255d3SCy Schubert 		if (len > max_len)
5265c1d255d3SCy Schubert 			max_len = len;
5266c1d255d3SCy Schubert 	}
5267c1d255d3SCy Schubert 
5268c1d255d3SCy Schubert 	return max_len;
5269c1d255d3SCy Schubert }
5270c1d255d3SCy Schubert 
5271c1d255d3SCy Schubert 
match_lines_in_file(const char * path,const char ** lines)5272c1d255d3SCy Schubert static int match_lines_in_file(const char *path, const char **lines)
5273c1d255d3SCy Schubert {
5274c1d255d3SCy Schubert 	FILE *f;
5275c1d255d3SCy Schubert 	char *buf;
5276c1d255d3SCy Schubert 	size_t bufsize;
5277c1d255d3SCy Schubert 	int found = 0, is_linestart = 1;
5278c1d255d3SCy Schubert 
5279c1d255d3SCy Schubert 	bufsize = max_str_len(lines) + sizeof("\r\n");
5280c1d255d3SCy Schubert 	buf = os_malloc(bufsize);
5281c1d255d3SCy Schubert 	if (!buf)
5282c1d255d3SCy Schubert 		return 0;
5283c1d255d3SCy Schubert 
5284c1d255d3SCy Schubert 	f = fopen(path, "r");
5285c1d255d3SCy Schubert 	if (!f) {
5286c1d255d3SCy Schubert 		os_free(buf);
5287c1d255d3SCy Schubert 		return 0;
5288c1d255d3SCy Schubert 	}
5289c1d255d3SCy Schubert 
5290c1d255d3SCy Schubert 	while (!found && fgets(buf, bufsize, f)) {
5291c1d255d3SCy Schubert 		int is_lineend;
5292c1d255d3SCy Schubert 		size_t len;
5293c1d255d3SCy Schubert 		const char **p;
5294c1d255d3SCy Schubert 
5295c1d255d3SCy Schubert 		len = strcspn(buf, "\r\n");
5296c1d255d3SCy Schubert 		is_lineend = buf[len] != '\0';
5297c1d255d3SCy Schubert 		buf[len] = '\0';
5298c1d255d3SCy Schubert 
5299c1d255d3SCy Schubert 		if (is_linestart && is_lineend) {
5300c1d255d3SCy Schubert 			for (p = lines; !found && *p; p++)
5301c1d255d3SCy Schubert 				found = os_strcmp(buf, *p) == 0;
5302c1d255d3SCy Schubert 		}
5303c1d255d3SCy Schubert 		is_linestart = is_lineend;
5304c1d255d3SCy Schubert 	}
5305c1d255d3SCy Schubert 
5306c1d255d3SCy Schubert 	fclose(f);
5307c1d255d3SCy Schubert 	bin_clear_free(buf, bufsize);
5308c1d255d3SCy Schubert 
5309c1d255d3SCy Schubert 	return found;
5310c1d255d3SCy Schubert }
5311c1d255d3SCy Schubert 
5312c1d255d3SCy Schubert 
is_tpm2_key(const char * path)5313c1d255d3SCy Schubert static int is_tpm2_key(const char *path)
5314c1d255d3SCy Schubert {
5315c1d255d3SCy Schubert 	/* Check both new and old format of TPM2 PEM guard tag */
5316c1d255d3SCy Schubert 	static const char *tpm2_tags[] = {
5317c1d255d3SCy Schubert 		"-----BEGIN TSS2 PRIVATE KEY-----",
5318c1d255d3SCy Schubert 		"-----BEGIN TSS2 KEY BLOB-----",
5319c1d255d3SCy Schubert 		NULL
5320c1d255d3SCy Schubert 	};
5321c1d255d3SCy Schubert 
5322c1d255d3SCy Schubert 	return match_lines_in_file(path, tpm2_tags);
5323c1d255d3SCy Schubert }
5324c1d255d3SCy Schubert 
5325c1d255d3SCy Schubert 
tls_connection_set_params(void * tls_ctx,struct tls_connection * conn,const struct tls_connection_params * params)532639beb93cSSam Leffler int tls_connection_set_params(void *tls_ctx, struct tls_connection *conn,
532739beb93cSSam Leffler 			      const struct tls_connection_params *params)
532839beb93cSSam Leffler {
5329325151a3SRui Paulo 	struct tls_data *data = tls_ctx;
533039beb93cSSam Leffler 	int ret;
533139beb93cSSam Leffler 	unsigned long err;
53325b9c547cSRui Paulo 	int can_pkcs11 = 0;
53335b9c547cSRui Paulo 	const char *key_id = params->key_id;
53345b9c547cSRui Paulo 	const char *cert_id = params->cert_id;
53355b9c547cSRui Paulo 	const char *ca_cert_id = params->ca_cert_id;
53365b9c547cSRui Paulo 	const char *engine_id = params->engine ? params->engine_id : NULL;
533785732ac8SCy Schubert 	const char *ciphers;
533839beb93cSSam Leffler 
533939beb93cSSam Leffler 	if (conn == NULL)
534039beb93cSSam Leffler 		return -1;
534139beb93cSSam Leffler 
5342780fb4a2SCy Schubert 	if (params->flags & TLS_CONN_REQUIRE_OCSP_ALL) {
5343780fb4a2SCy Schubert 		wpa_printf(MSG_INFO,
5344780fb4a2SCy Schubert 			   "OpenSSL: ocsp=3 not supported");
5345780fb4a2SCy Schubert 		return -1;
5346780fb4a2SCy Schubert 	}
5347780fb4a2SCy Schubert 
53485b9c547cSRui Paulo 	/*
53495b9c547cSRui Paulo 	 * If the engine isn't explicitly configured, and any of the
53505b9c547cSRui Paulo 	 * cert/key fields are actually PKCS#11 URIs, then automatically
53515b9c547cSRui Paulo 	 * use the PKCS#11 ENGINE.
53525b9c547cSRui Paulo 	 */
53535b9c547cSRui Paulo 	if (!engine_id || os_strcmp(engine_id, "pkcs11") == 0)
53545b9c547cSRui Paulo 		can_pkcs11 = 1;
53555b9c547cSRui Paulo 
53565b9c547cSRui Paulo 	if (!key_id && params->private_key && can_pkcs11 &&
53575b9c547cSRui Paulo 	    os_strncmp(params->private_key, "pkcs11:", 7) == 0) {
53585b9c547cSRui Paulo 		can_pkcs11 = 2;
53595b9c547cSRui Paulo 		key_id = params->private_key;
53605b9c547cSRui Paulo 	}
53615b9c547cSRui Paulo 
53625b9c547cSRui Paulo 	if (!cert_id && params->client_cert && can_pkcs11 &&
53635b9c547cSRui Paulo 	    os_strncmp(params->client_cert, "pkcs11:", 7) == 0) {
53645b9c547cSRui Paulo 		can_pkcs11 = 2;
53655b9c547cSRui Paulo 		cert_id = params->client_cert;
53665b9c547cSRui Paulo 	}
53675b9c547cSRui Paulo 
53685b9c547cSRui Paulo 	if (!ca_cert_id && params->ca_cert && can_pkcs11 &&
53695b9c547cSRui Paulo 	    os_strncmp(params->ca_cert, "pkcs11:", 7) == 0) {
53705b9c547cSRui Paulo 		can_pkcs11 = 2;
53715b9c547cSRui Paulo 		ca_cert_id = params->ca_cert;
53725b9c547cSRui Paulo 	}
53735b9c547cSRui Paulo 
53745b9c547cSRui Paulo 	/* If we need to automatically enable the PKCS#11 ENGINE, do so. */
53755b9c547cSRui Paulo 	if (can_pkcs11 == 2 && !engine_id)
53765b9c547cSRui Paulo 		engine_id = "pkcs11";
53775b9c547cSRui Paulo 
5378c1d255d3SCy Schubert 	/* If private_key points to a TPM2-wrapped key, automatically enable
5379c1d255d3SCy Schubert 	 * tpm2 engine and use it to unwrap the key. */
5380c1d255d3SCy Schubert 	if (params->private_key &&
5381c1d255d3SCy Schubert 	    (!engine_id || os_strcmp(engine_id, "tpm2") == 0) &&
5382c1d255d3SCy Schubert 	    is_tpm2_key(params->private_key)) {
5383c1d255d3SCy Schubert 		wpa_printf(MSG_DEBUG, "OpenSSL: Found TPM2 wrapped key %s",
5384c1d255d3SCy Schubert 			   params->private_key);
5385c1d255d3SCy Schubert 		key_id = key_id ? key_id : params->private_key;
5386c1d255d3SCy Schubert 		engine_id = engine_id ? engine_id : "tpm2";
5387c1d255d3SCy Schubert 	}
5388c1d255d3SCy Schubert 
5389325151a3SRui Paulo #if defined(EAP_FAST) || defined(EAP_FAST_DYNAMIC) || defined(EAP_SERVER_FAST)
539085732ac8SCy Schubert #if OPENSSL_VERSION_NUMBER < 0x10100000L || defined(LIBRESSL_VERSION_NUMBER)
53915b9c547cSRui Paulo 	if (params->flags & TLS_CONN_EAP_FAST) {
53925b9c547cSRui Paulo 		wpa_printf(MSG_DEBUG,
53935b9c547cSRui Paulo 			   "OpenSSL: Use TLSv1_method() for EAP-FAST");
53945b9c547cSRui Paulo 		if (SSL_set_ssl_method(conn->ssl, TLSv1_method()) != 1) {
53955b9c547cSRui Paulo 			tls_show_errors(MSG_INFO, __func__,
53965b9c547cSRui Paulo 					"Failed to set TLSv1_method() for EAP-FAST");
53975b9c547cSRui Paulo 			return -1;
53985b9c547cSRui Paulo 		}
53995b9c547cSRui Paulo 	}
5400325151a3SRui Paulo #endif
540185732ac8SCy Schubert #if OPENSSL_VERSION_NUMBER >= 0x10101000L
540285732ac8SCy Schubert #ifdef SSL_OP_NO_TLSv1_3
540385732ac8SCy Schubert 	if (params->flags & TLS_CONN_EAP_FAST) {
540485732ac8SCy Schubert 		/* Need to disable TLS v1.3 at least for now since OpenSSL 1.1.1
540585732ac8SCy Schubert 		 * refuses to start the handshake with the modified ciphersuite
540685732ac8SCy Schubert 		 * list (no TLS v1.3 ciphersuites included) for EAP-FAST. */
540785732ac8SCy Schubert 		wpa_printf(MSG_DEBUG, "OpenSSL: Disable TLSv1.3 for EAP-FAST");
540885732ac8SCy Schubert 		SSL_set_options(conn->ssl, SSL_OP_NO_TLSv1_3);
540985732ac8SCy Schubert 	}
541085732ac8SCy Schubert #endif /* SSL_OP_NO_TLSv1_3 */
541185732ac8SCy Schubert #endif
5412325151a3SRui Paulo #endif /* EAP_FAST || EAP_FAST_DYNAMIC || EAP_SERVER_FAST */
54135b9c547cSRui Paulo 
541439beb93cSSam Leffler 	while ((err = ERR_get_error())) {
541539beb93cSSam Leffler 		wpa_printf(MSG_INFO, "%s: Clearing pending SSL error: %s",
541639beb93cSSam Leffler 			   __func__, ERR_error_string(err, NULL));
541739beb93cSSam Leffler 	}
541839beb93cSSam Leffler 
5419*a90b9d01SCy Schubert 	if (tls_set_conn_flags(conn, params->flags,
5420*a90b9d01SCy Schubert 			       params->openssl_ciphers) < 0)
5421*a90b9d01SCy Schubert 		return -1;
5422*a90b9d01SCy Schubert 
54235b9c547cSRui Paulo 	if (engine_id) {
5424c1d255d3SCy Schubert 		wpa_printf(MSG_DEBUG, "SSL: Initializing TLS engine %s",
5425c1d255d3SCy Schubert 			   engine_id);
54265b9c547cSRui Paulo 		ret = tls_engine_init(conn, engine_id, params->pin,
54275b9c547cSRui Paulo 				      key_id, cert_id, ca_cert_id);
542839beb93cSSam Leffler 		if (ret)
542939beb93cSSam Leffler 			return ret;
543039beb93cSSam Leffler 	}
543139beb93cSSam Leffler 	if (tls_connection_set_subject_match(conn,
543239beb93cSSam Leffler 					     params->subject_match,
54335b9c547cSRui Paulo 					     params->altsubject_match,
54345b9c547cSRui Paulo 					     params->suffix_match,
54354bc52338SCy Schubert 					     params->domain_match,
54364bc52338SCy Schubert 					     params->check_cert_subject))
543739beb93cSSam Leffler 		return -1;
543839beb93cSSam Leffler 
54395b9c547cSRui Paulo 	if (engine_id && ca_cert_id) {
5440325151a3SRui Paulo 		if (tls_connection_engine_ca_cert(data, conn, ca_cert_id))
544139beb93cSSam Leffler 			return TLS_SET_PARAMS_ENGINE_PRV_VERIFY_FAILED;
5442325151a3SRui Paulo 	} else if (tls_connection_ca_cert(data, conn, params->ca_cert,
544339beb93cSSam Leffler 					  params->ca_cert_blob,
544439beb93cSSam Leffler 					  params->ca_cert_blob_len,
544539beb93cSSam Leffler 					  params->ca_path))
544639beb93cSSam Leffler 		return -1;
544739beb93cSSam Leffler 
54485b9c547cSRui Paulo 	if (engine_id && cert_id) {
54495b9c547cSRui Paulo 		if (tls_connection_engine_client_cert(conn, cert_id))
545039beb93cSSam Leffler 			return TLS_SET_PARAMS_ENGINE_PRV_VERIFY_FAILED;
545139beb93cSSam Leffler 	} else if (tls_connection_client_cert(conn, params->client_cert,
545239beb93cSSam Leffler 					      params->client_cert_blob,
545339beb93cSSam Leffler 					      params->client_cert_blob_len))
545439beb93cSSam Leffler 		return -1;
545539beb93cSSam Leffler 
54565b9c547cSRui Paulo 	if (engine_id && key_id) {
545739beb93cSSam Leffler 		wpa_printf(MSG_DEBUG, "TLS: Using private key from engine");
545839beb93cSSam Leffler 		if (tls_connection_engine_private_key(conn))
545939beb93cSSam Leffler 			return TLS_SET_PARAMS_ENGINE_PRV_VERIFY_FAILED;
5460325151a3SRui Paulo 	} else if (tls_connection_private_key(data, conn,
546139beb93cSSam Leffler 					      params->private_key,
546239beb93cSSam Leffler 					      params->private_key_passwd,
546339beb93cSSam Leffler 					      params->private_key_blob,
546439beb93cSSam Leffler 					      params->private_key_blob_len)) {
546539beb93cSSam Leffler 		wpa_printf(MSG_INFO, "TLS: Failed to load private key '%s'",
546639beb93cSSam Leffler 			   params->private_key);
546739beb93cSSam Leffler 		return -1;
546839beb93cSSam Leffler 	}
546939beb93cSSam Leffler 
547085732ac8SCy Schubert 	ciphers = params->openssl_ciphers;
547185732ac8SCy Schubert #ifdef CONFIG_SUITEB
547285732ac8SCy Schubert #ifdef OPENSSL_IS_BORINGSSL
547385732ac8SCy Schubert 	if (ciphers && os_strcmp(ciphers, "SUITEB192") == 0) {
547485732ac8SCy Schubert 		/* BoringSSL removed support for SUITEB192, so need to handle
547585732ac8SCy Schubert 		 * this with hardcoded ciphersuite and additional checks for
547685732ac8SCy Schubert 		 * other parameters. */
547785732ac8SCy Schubert 		ciphers = "ECDHE-ECDSA-AES256-GCM-SHA384";
547885732ac8SCy Schubert 	}
547985732ac8SCy Schubert #endif /* OPENSSL_IS_BORINGSSL */
548085732ac8SCy Schubert #endif /* CONFIG_SUITEB */
548185732ac8SCy Schubert 	if (ciphers && SSL_set_cipher_list(conn->ssl, ciphers) != 1) {
54825b9c547cSRui Paulo 		wpa_printf(MSG_INFO,
54835b9c547cSRui Paulo 			   "OpenSSL: Failed to set cipher string '%s'",
548485732ac8SCy Schubert 			   ciphers);
54855b9c547cSRui Paulo 		return -1;
54865b9c547cSRui Paulo 	}
54875b9c547cSRui Paulo 
54884bc52338SCy Schubert 	if (!params->openssl_ecdh_curves) {
54894bc52338SCy Schubert #ifndef OPENSSL_IS_BORINGSSL
54904bc52338SCy Schubert #ifndef OPENSSL_NO_EC
5491*a90b9d01SCy Schubert #if OPENSSL_VERSION_NUMBER < 0x10100000L
54924bc52338SCy Schubert 		if (SSL_set_ecdh_auto(conn->ssl, 1) != 1) {
54934bc52338SCy Schubert 			wpa_printf(MSG_INFO,
54944bc52338SCy Schubert 				   "OpenSSL: Failed to set ECDH curves to auto");
54954bc52338SCy Schubert 			return -1;
54964bc52338SCy Schubert 		}
5497*a90b9d01SCy Schubert #endif /* < 1.1.0 */
54984bc52338SCy Schubert #endif /* OPENSSL_NO_EC */
54994bc52338SCy Schubert #endif /* OPENSSL_IS_BORINGSSL */
55004bc52338SCy Schubert 	} else if (params->openssl_ecdh_curves[0]) {
5501*a90b9d01SCy Schubert #ifdef OPENSSL_IS_BORINGSSL
55024bc52338SCy Schubert 		wpa_printf(MSG_INFO,
5503*a90b9d01SCy Schubert 			"OpenSSL: ECDH configuration not supported");
55044bc52338SCy Schubert 		return -1;
5505*a90b9d01SCy Schubert #else /* !OPENSSL_IS_BORINGSSL */
55064bc52338SCy Schubert #ifndef OPENSSL_NO_EC
55074bc52338SCy Schubert 		if (SSL_set1_curves_list(conn->ssl,
55084bc52338SCy Schubert 					 params->openssl_ecdh_curves) != 1) {
55094bc52338SCy Schubert 			wpa_printf(MSG_INFO,
55104bc52338SCy Schubert 				   "OpenSSL: Failed to set ECDH curves '%s'",
55114bc52338SCy Schubert 				   params->openssl_ecdh_curves);
55124bc52338SCy Schubert 			return -1;
55134bc52338SCy Schubert 		}
55144bc52338SCy Schubert #else /* OPENSSL_NO_EC */
55154bc52338SCy Schubert 		wpa_printf(MSG_INFO, "OpenSSL: ECDH not supported");
55164bc52338SCy Schubert 		return -1;
55174bc52338SCy Schubert #endif /* OPENSSL_NO_EC */
55184bc52338SCy Schubert #endif /* OPENSSL_IS_BORINGSSL */
55194bc52338SCy Schubert 	}
55204bc52338SCy Schubert 
5521780fb4a2SCy Schubert #ifdef OPENSSL_IS_BORINGSSL
5522780fb4a2SCy Schubert 	if (params->flags & TLS_CONN_REQUEST_OCSP) {
5523780fb4a2SCy Schubert 		SSL_enable_ocsp_stapling(conn->ssl);
5524780fb4a2SCy Schubert 	}
5525780fb4a2SCy Schubert #else /* OPENSSL_IS_BORINGSSL */
55265b9c547cSRui Paulo #ifdef HAVE_OCSP
55275b9c547cSRui Paulo 	if (params->flags & TLS_CONN_REQUEST_OCSP) {
5528325151a3SRui Paulo 		SSL_CTX *ssl_ctx = data->ssl;
55295b9c547cSRui Paulo 		SSL_set_tlsext_status_type(conn->ssl, TLSEXT_STATUSTYPE_ocsp);
55305b9c547cSRui Paulo 		SSL_CTX_set_tlsext_status_cb(ssl_ctx, ocsp_resp_cb);
55315b9c547cSRui Paulo 		SSL_CTX_set_tlsext_status_arg(ssl_ctx, conn);
55325b9c547cSRui Paulo 	}
5533325151a3SRui Paulo #else /* HAVE_OCSP */
5534325151a3SRui Paulo 	if (params->flags & TLS_CONN_REQUIRE_OCSP) {
5535325151a3SRui Paulo 		wpa_printf(MSG_INFO,
5536325151a3SRui Paulo 			   "OpenSSL: No OCSP support included - reject configuration");
5537325151a3SRui Paulo 		return -1;
5538325151a3SRui Paulo 	}
5539325151a3SRui Paulo 	if (params->flags & TLS_CONN_REQUEST_OCSP) {
5540325151a3SRui Paulo 		wpa_printf(MSG_DEBUG,
5541325151a3SRui Paulo 			   "OpenSSL: No OCSP support included - allow optional OCSP case to continue");
5542325151a3SRui Paulo 	}
55435b9c547cSRui Paulo #endif /* HAVE_OCSP */
5544780fb4a2SCy Schubert #endif /* OPENSSL_IS_BORINGSSL */
55455b9c547cSRui Paulo 
5546f05cddf9SRui Paulo 	conn->flags = params->flags;
5547f05cddf9SRui Paulo 
5548325151a3SRui Paulo 	tls_get_errors(data);
554939beb93cSSam Leffler 
555039beb93cSSam Leffler 	return 0;
555139beb93cSSam Leffler }
555239beb93cSSam Leffler 
555339beb93cSSam Leffler 
openssl_debug_dump_cipher_list(SSL_CTX * ssl_ctx)5554206b73d0SCy Schubert static void openssl_debug_dump_cipher_list(SSL_CTX *ssl_ctx)
5555206b73d0SCy Schubert {
5556206b73d0SCy Schubert 	SSL *ssl;
5557206b73d0SCy Schubert 	int i;
5558206b73d0SCy Schubert 
5559206b73d0SCy Schubert 	ssl = SSL_new(ssl_ctx);
5560206b73d0SCy Schubert 	if (!ssl)
5561206b73d0SCy Schubert 		return;
5562206b73d0SCy Schubert 
5563206b73d0SCy Schubert 	wpa_printf(MSG_DEBUG,
5564206b73d0SCy Schubert 		   "OpenSSL: Enabled cipher suites in priority order");
5565206b73d0SCy Schubert 	for (i = 0; ; i++) {
5566206b73d0SCy Schubert 		const char *cipher;
5567206b73d0SCy Schubert 
5568206b73d0SCy Schubert 		cipher = SSL_get_cipher_list(ssl, i);
5569206b73d0SCy Schubert 		if (!cipher)
5570206b73d0SCy Schubert 			break;
5571206b73d0SCy Schubert 		wpa_printf(MSG_DEBUG, "Cipher %d: %s", i, cipher);
5572206b73d0SCy Schubert 	}
5573206b73d0SCy Schubert 
5574206b73d0SCy Schubert 	SSL_free(ssl);
5575206b73d0SCy Schubert }
5576206b73d0SCy Schubert 
5577206b73d0SCy Schubert 
5578206b73d0SCy Schubert #if !defined(LIBRESSL_VERSION_NUMBER) && !defined(BORINGSSL_API_VERSION)
5579206b73d0SCy Schubert 
openssl_pkey_type_str(const EVP_PKEY * pkey)5580206b73d0SCy Schubert static const char * openssl_pkey_type_str(const EVP_PKEY *pkey)
5581206b73d0SCy Schubert {
5582206b73d0SCy Schubert 	if (!pkey)
5583206b73d0SCy Schubert 		return "NULL";
5584206b73d0SCy Schubert 	switch (EVP_PKEY_type(EVP_PKEY_id(pkey))) {
5585206b73d0SCy Schubert 	case EVP_PKEY_RSA:
5586206b73d0SCy Schubert 		return "RSA";
5587206b73d0SCy Schubert 	case EVP_PKEY_DSA:
5588206b73d0SCy Schubert 		return "DSA";
5589206b73d0SCy Schubert 	case EVP_PKEY_DH:
5590206b73d0SCy Schubert 		return "DH";
5591206b73d0SCy Schubert 	case EVP_PKEY_EC:
5592206b73d0SCy Schubert 		return "EC";
5593*a90b9d01SCy Schubert 	default:
5594206b73d0SCy Schubert 		return "?";
5595206b73d0SCy Schubert 	}
5596*a90b9d01SCy Schubert }
5597206b73d0SCy Schubert 
5598206b73d0SCy Schubert 
openssl_debug_dump_certificate(int i,X509 * cert)5599206b73d0SCy Schubert static void openssl_debug_dump_certificate(int i, X509 *cert)
5600206b73d0SCy Schubert {
5601206b73d0SCy Schubert 	char buf[256];
5602206b73d0SCy Schubert 	EVP_PKEY *pkey;
5603206b73d0SCy Schubert 	ASN1_INTEGER *ser;
5604206b73d0SCy Schubert 	char serial_num[128];
5605206b73d0SCy Schubert 
5606c1d255d3SCy Schubert 	if (!cert)
5607c1d255d3SCy Schubert 		return;
5608c1d255d3SCy Schubert 
5609206b73d0SCy Schubert 	X509_NAME_oneline(X509_get_subject_name(cert), buf, sizeof(buf));
5610206b73d0SCy Schubert 
5611206b73d0SCy Schubert 	ser = X509_get_serialNumber(cert);
5612206b73d0SCy Schubert 	if (ser)
5613206b73d0SCy Schubert 		wpa_snprintf_hex_uppercase(serial_num, sizeof(serial_num),
5614206b73d0SCy Schubert 					   ASN1_STRING_get0_data(ser),
5615206b73d0SCy Schubert 					   ASN1_STRING_length(ser));
5616206b73d0SCy Schubert 	else
5617206b73d0SCy Schubert 		serial_num[0] = '\0';
5618206b73d0SCy Schubert 
5619206b73d0SCy Schubert 	pkey = X509_get_pubkey(cert);
5620206b73d0SCy Schubert 	wpa_printf(MSG_DEBUG, "%d: %s (%s) %s", i, buf,
5621206b73d0SCy Schubert 		   openssl_pkey_type_str(pkey), serial_num);
5622206b73d0SCy Schubert 	EVP_PKEY_free(pkey);
5623206b73d0SCy Schubert }
5624206b73d0SCy Schubert 
5625206b73d0SCy Schubert 
openssl_debug_dump_certificates(SSL_CTX * ssl_ctx)5626206b73d0SCy Schubert static void openssl_debug_dump_certificates(SSL_CTX *ssl_ctx)
5627206b73d0SCy Schubert {
5628206b73d0SCy Schubert 	STACK_OF(X509) *certs;
5629206b73d0SCy Schubert 
5630206b73d0SCy Schubert 	wpa_printf(MSG_DEBUG, "OpenSSL: Configured certificate chain");
5631206b73d0SCy Schubert 	if (SSL_CTX_get0_chain_certs(ssl_ctx, &certs) == 1) {
5632206b73d0SCy Schubert 		int i;
5633206b73d0SCy Schubert 
5634206b73d0SCy Schubert 		for (i = sk_X509_num(certs); i > 0; i--)
5635206b73d0SCy Schubert 			openssl_debug_dump_certificate(i, sk_X509_value(certs,
5636206b73d0SCy Schubert 									i - 1));
5637206b73d0SCy Schubert 	}
5638206b73d0SCy Schubert 	openssl_debug_dump_certificate(0, SSL_CTX_get0_certificate(ssl_ctx));
5639206b73d0SCy Schubert }
5640206b73d0SCy Schubert 
5641206b73d0SCy Schubert #endif
5642206b73d0SCy Schubert 
5643206b73d0SCy Schubert 
openssl_debug_dump_certificate_chains(SSL_CTX * ssl_ctx)5644206b73d0SCy Schubert static void openssl_debug_dump_certificate_chains(SSL_CTX *ssl_ctx)
5645206b73d0SCy Schubert {
5646206b73d0SCy Schubert #if !defined(LIBRESSL_VERSION_NUMBER) && !defined(BORINGSSL_API_VERSION)
5647206b73d0SCy Schubert 	int res;
5648206b73d0SCy Schubert 
5649206b73d0SCy Schubert 	for (res = SSL_CTX_set_current_cert(ssl_ctx, SSL_CERT_SET_FIRST);
5650206b73d0SCy Schubert 	     res == 1;
5651206b73d0SCy Schubert 	     res = SSL_CTX_set_current_cert(ssl_ctx, SSL_CERT_SET_NEXT))
5652206b73d0SCy Schubert 		openssl_debug_dump_certificates(ssl_ctx);
5653206b73d0SCy Schubert 
5654206b73d0SCy Schubert 	SSL_CTX_set_current_cert(ssl_ctx, SSL_CERT_SET_FIRST);
5655206b73d0SCy Schubert #endif
5656206b73d0SCy Schubert }
5657206b73d0SCy Schubert 
5658206b73d0SCy Schubert 
openssl_debug_dump_ctx(SSL_CTX * ssl_ctx)5659206b73d0SCy Schubert static void openssl_debug_dump_ctx(SSL_CTX *ssl_ctx)
5660206b73d0SCy Schubert {
5661206b73d0SCy Schubert 	openssl_debug_dump_cipher_list(ssl_ctx);
5662206b73d0SCy Schubert 	openssl_debug_dump_certificate_chains(ssl_ctx);
5663206b73d0SCy Schubert }
5664206b73d0SCy Schubert 
5665206b73d0SCy Schubert 
tls_global_set_params(void * tls_ctx,const struct tls_connection_params * params)566639beb93cSSam Leffler int tls_global_set_params(void *tls_ctx,
566739beb93cSSam Leffler 			  const struct tls_connection_params *params)
566839beb93cSSam Leffler {
5669325151a3SRui Paulo 	struct tls_data *data = tls_ctx;
5670325151a3SRui Paulo 	SSL_CTX *ssl_ctx = data->ssl;
567139beb93cSSam Leffler 	unsigned long err;
567239beb93cSSam Leffler 
567339beb93cSSam Leffler 	while ((err = ERR_get_error())) {
567439beb93cSSam Leffler 		wpa_printf(MSG_INFO, "%s: Clearing pending SSL error: %s",
567539beb93cSSam Leffler 			   __func__, ERR_error_string(err, NULL));
567639beb93cSSam Leffler 	}
567739beb93cSSam Leffler 
56784bc52338SCy Schubert 	os_free(data->check_cert_subject);
56794bc52338SCy Schubert 	data->check_cert_subject = NULL;
56804bc52338SCy Schubert 	if (params->check_cert_subject) {
56814bc52338SCy Schubert 		data->check_cert_subject =
56824bc52338SCy Schubert 			os_strdup(params->check_cert_subject);
56834bc52338SCy Schubert 		if (!data->check_cert_subject)
56844bc52338SCy Schubert 			return -1;
56854bc52338SCy Schubert 	}
56864bc52338SCy Schubert 
5687325151a3SRui Paulo 	if (tls_global_ca_cert(data, params->ca_cert) ||
5688325151a3SRui Paulo 	    tls_global_client_cert(data, params->client_cert) ||
5689325151a3SRui Paulo 	    tls_global_private_key(data, params->private_key,
5690325151a3SRui Paulo 				   params->private_key_passwd) ||
5691206b73d0SCy Schubert 	    tls_global_client_cert(data, params->client_cert2) ||
5692206b73d0SCy Schubert 	    tls_global_private_key(data, params->private_key2,
5693206b73d0SCy Schubert 				   params->private_key_passwd2) ||
5694325151a3SRui Paulo 	    tls_global_dh(data, params->dh_file)) {
5695325151a3SRui Paulo 		wpa_printf(MSG_INFO, "TLS: Failed to set global parameters");
569639beb93cSSam Leffler 		return -1;
569739beb93cSSam Leffler 	}
569839beb93cSSam Leffler 
5699*a90b9d01SCy Schubert 	os_free(data->openssl_ciphers);
5700*a90b9d01SCy Schubert 	if (params->openssl_ciphers) {
5701*a90b9d01SCy Schubert 		data->openssl_ciphers = os_strdup(params->openssl_ciphers);
5702*a90b9d01SCy Schubert 		if (!data->openssl_ciphers)
5703*a90b9d01SCy Schubert 			return -1;
5704*a90b9d01SCy Schubert 	} else {
5705*a90b9d01SCy Schubert 		data->openssl_ciphers = NULL;
5706*a90b9d01SCy Schubert 	}
57075b9c547cSRui Paulo 	if (params->openssl_ciphers &&
57085b9c547cSRui Paulo 	    SSL_CTX_set_cipher_list(ssl_ctx, params->openssl_ciphers) != 1) {
57095b9c547cSRui Paulo 		wpa_printf(MSG_INFO,
57105b9c547cSRui Paulo 			   "OpenSSL: Failed to set cipher string '%s'",
57115b9c547cSRui Paulo 			   params->openssl_ciphers);
57125b9c547cSRui Paulo 		return -1;
57135b9c547cSRui Paulo 	}
57145b9c547cSRui Paulo 
57154bc52338SCy Schubert 	if (!params->openssl_ecdh_curves) {
57164bc52338SCy Schubert #ifndef OPENSSL_IS_BORINGSSL
57174bc52338SCy Schubert #ifndef OPENSSL_NO_EC
5718*a90b9d01SCy Schubert #if OPENSSL_VERSION_NUMBER < 0x10100000L
57194bc52338SCy Schubert 		if (SSL_CTX_set_ecdh_auto(ssl_ctx, 1) != 1) {
57204bc52338SCy Schubert 			wpa_printf(MSG_INFO,
57214bc52338SCy Schubert 				   "OpenSSL: Failed to set ECDH curves to auto");
57224bc52338SCy Schubert 			return -1;
57234bc52338SCy Schubert 		}
5724*a90b9d01SCy Schubert #endif /* < 1.1.0 */
57254bc52338SCy Schubert #endif /* OPENSSL_NO_EC */
57264bc52338SCy Schubert #endif /* OPENSSL_IS_BORINGSSL */
57274bc52338SCy Schubert 	} else if (params->openssl_ecdh_curves[0]) {
5728*a90b9d01SCy Schubert #ifdef OPENSSL_IS_BORINGSSL
57294bc52338SCy Schubert 		wpa_printf(MSG_INFO,
5730*a90b9d01SCy Schubert 			"OpenSSL: ECDH configuration not supported");
57314bc52338SCy Schubert 		return -1;
5732*a90b9d01SCy Schubert #else /* !OPENSSL_IS_BORINGSSL */
57334bc52338SCy Schubert #ifndef OPENSSL_NO_EC
57344bc52338SCy Schubert #if OPENSSL_VERSION_NUMBER < 0x10100000L
57354bc52338SCy Schubert 		SSL_CTX_set_ecdh_auto(ssl_ctx, 1);
57364bc52338SCy Schubert #endif
57374bc52338SCy Schubert 		if (SSL_CTX_set1_curves_list(ssl_ctx,
57384bc52338SCy Schubert 					     params->openssl_ecdh_curves) !=
57394bc52338SCy Schubert 		    1) {
57404bc52338SCy Schubert 			wpa_printf(MSG_INFO,
57414bc52338SCy Schubert 				   "OpenSSL: Failed to set ECDH curves '%s'",
57424bc52338SCy Schubert 				   params->openssl_ecdh_curves);
57434bc52338SCy Schubert 			return -1;
57444bc52338SCy Schubert 		}
57454bc52338SCy Schubert #else /* OPENSSL_NO_EC */
57464bc52338SCy Schubert 		wpa_printf(MSG_INFO, "OpenSSL: ECDH not supported");
57474bc52338SCy Schubert 		return -1;
57484bc52338SCy Schubert #endif /* OPENSSL_NO_EC */
57494bc52338SCy Schubert #endif /* OPENSSL_IS_BORINGSSL */
57504bc52338SCy Schubert 	}
57514bc52338SCy Schubert 
5752f05cddf9SRui Paulo #ifdef SSL_OP_NO_TICKET
5753f05cddf9SRui Paulo 	if (params->flags & TLS_CONN_DISABLE_SESSION_TICKET)
5754f05cddf9SRui Paulo 		SSL_CTX_set_options(ssl_ctx, SSL_OP_NO_TICKET);
5755f05cddf9SRui Paulo 	else
5756f05cddf9SRui Paulo 		SSL_CTX_clear_options(ssl_ctx, SSL_OP_NO_TICKET);
5757f05cddf9SRui Paulo #endif /*  SSL_OP_NO_TICKET */
5758f05cddf9SRui Paulo 
57595b9c547cSRui Paulo #ifdef HAVE_OCSP
57605b9c547cSRui Paulo 	SSL_CTX_set_tlsext_status_cb(ssl_ctx, ocsp_status_cb);
57615b9c547cSRui Paulo 	SSL_CTX_set_tlsext_status_arg(ssl_ctx, ssl_ctx);
57625b9c547cSRui Paulo 	os_free(tls_global->ocsp_stapling_response);
57635b9c547cSRui Paulo 	if (params->ocsp_stapling_response)
57645b9c547cSRui Paulo 		tls_global->ocsp_stapling_response =
57655b9c547cSRui Paulo 			os_strdup(params->ocsp_stapling_response);
57665b9c547cSRui Paulo 	else
57675b9c547cSRui Paulo 		tls_global->ocsp_stapling_response = NULL;
57685b9c547cSRui Paulo #endif /* HAVE_OCSP */
57695b9c547cSRui Paulo 
5770206b73d0SCy Schubert 	openssl_debug_dump_ctx(ssl_ctx);
5771206b73d0SCy Schubert 
577239beb93cSSam Leffler 	return 0;
577339beb93cSSam Leffler }
577439beb93cSSam Leffler 
577539beb93cSSam Leffler 
5776206b73d0SCy Schubert #ifdef EAP_FAST_OR_TEAP
577739beb93cSSam Leffler /* Pre-shared secred requires a patch to openssl, so this function is
577839beb93cSSam Leffler  * commented out unless explicitly needed for EAP-FAST in order to be able to
577939beb93cSSam Leffler  * build this file with unmodified openssl. */
578039beb93cSSam Leffler 
5781780fb4a2SCy Schubert #if (defined(OPENSSL_IS_BORINGSSL) || OPENSSL_VERSION_NUMBER >= 0x10100000L) && !defined(LIBRESSL_VERSION_NUMBER)
tls_sess_sec_cb(SSL * s,void * secret,int * secret_len,STACK_OF (SSL_CIPHER)* peer_ciphers,const SSL_CIPHER ** cipher,void * arg)57825b9c547cSRui Paulo static int tls_sess_sec_cb(SSL *s, void *secret, int *secret_len,
57835b9c547cSRui Paulo 			   STACK_OF(SSL_CIPHER) *peer_ciphers,
57845b9c547cSRui Paulo 			   const SSL_CIPHER **cipher, void *arg)
57855b9c547cSRui Paulo #else /* OPENSSL_IS_BORINGSSL */
578639beb93cSSam Leffler static int tls_sess_sec_cb(SSL *s, void *secret, int *secret_len,
578739beb93cSSam Leffler 			   STACK_OF(SSL_CIPHER) *peer_ciphers,
578839beb93cSSam Leffler 			   SSL_CIPHER **cipher, void *arg)
57895b9c547cSRui Paulo #endif /* OPENSSL_IS_BORINGSSL */
579039beb93cSSam Leffler {
579139beb93cSSam Leffler 	struct tls_connection *conn = arg;
579239beb93cSSam Leffler 	int ret;
579339beb93cSSam Leffler 
5794*a90b9d01SCy Schubert #if OPENSSL_VERSION_NUMBER < 0x10100000L
579539beb93cSSam Leffler 	if (conn == NULL || conn->session_ticket_cb == NULL)
579639beb93cSSam Leffler 		return 0;
579739beb93cSSam Leffler 
579839beb93cSSam Leffler 	ret = conn->session_ticket_cb(conn->session_ticket_cb_ctx,
579939beb93cSSam Leffler 				      conn->session_ticket,
580039beb93cSSam Leffler 				      conn->session_ticket_len,
580139beb93cSSam Leffler 				      s->s3->client_random,
580239beb93cSSam Leffler 				      s->s3->server_random, secret);
5803325151a3SRui Paulo #else
5804325151a3SRui Paulo 	unsigned char client_random[SSL3_RANDOM_SIZE];
5805325151a3SRui Paulo 	unsigned char server_random[SSL3_RANDOM_SIZE];
5806325151a3SRui Paulo 
5807325151a3SRui Paulo 	if (conn == NULL || conn->session_ticket_cb == NULL)
5808325151a3SRui Paulo 		return 0;
5809325151a3SRui Paulo 
5810325151a3SRui Paulo 	SSL_get_client_random(s, client_random, sizeof(client_random));
5811325151a3SRui Paulo 	SSL_get_server_random(s, server_random, sizeof(server_random));
5812325151a3SRui Paulo 
5813325151a3SRui Paulo 	ret = conn->session_ticket_cb(conn->session_ticket_cb_ctx,
5814325151a3SRui Paulo 				      conn->session_ticket,
5815325151a3SRui Paulo 				      conn->session_ticket_len,
5816325151a3SRui Paulo 				      client_random,
5817325151a3SRui Paulo 				      server_random, secret);
5818325151a3SRui Paulo #endif
5819325151a3SRui Paulo 
582039beb93cSSam Leffler 	os_free(conn->session_ticket);
582139beb93cSSam Leffler 	conn->session_ticket = NULL;
582239beb93cSSam Leffler 
582339beb93cSSam Leffler 	if (ret <= 0)
582439beb93cSSam Leffler 		return 0;
582539beb93cSSam Leffler 
582639beb93cSSam Leffler 	*secret_len = SSL_MAX_MASTER_KEY_LENGTH;
582739beb93cSSam Leffler 	return 1;
582839beb93cSSam Leffler }
582939beb93cSSam Leffler 
583039beb93cSSam Leffler 
tls_session_ticket_ext_cb(SSL * s,const unsigned char * data,int len,void * arg)583139beb93cSSam Leffler static int tls_session_ticket_ext_cb(SSL *s, const unsigned char *data,
583239beb93cSSam Leffler 				     int len, void *arg)
583339beb93cSSam Leffler {
583439beb93cSSam Leffler 	struct tls_connection *conn = arg;
583539beb93cSSam Leffler 
583639beb93cSSam Leffler 	if (conn == NULL || conn->session_ticket_cb == NULL)
583739beb93cSSam Leffler 		return 0;
583839beb93cSSam Leffler 
583939beb93cSSam Leffler 	wpa_printf(MSG_DEBUG, "OpenSSL: %s: length=%d", __func__, len);
584039beb93cSSam Leffler 
584139beb93cSSam Leffler 	os_free(conn->session_ticket);
584239beb93cSSam Leffler 	conn->session_ticket = NULL;
584339beb93cSSam Leffler 
584439beb93cSSam Leffler 	wpa_hexdump(MSG_DEBUG, "OpenSSL: ClientHello SessionTicket "
584539beb93cSSam Leffler 		    "extension", data, len);
584639beb93cSSam Leffler 
584785732ac8SCy Schubert 	conn->session_ticket = os_memdup(data, len);
584839beb93cSSam Leffler 	if (conn->session_ticket == NULL)
584939beb93cSSam Leffler 		return 0;
585039beb93cSSam Leffler 
585139beb93cSSam Leffler 	conn->session_ticket_len = len;
585239beb93cSSam Leffler 
585339beb93cSSam Leffler 	return 1;
585439beb93cSSam Leffler }
5855206b73d0SCy Schubert #endif /* EAP_FAST_OR_TEAP */
585639beb93cSSam Leffler 
585739beb93cSSam Leffler 
tls_connection_set_session_ticket_cb(void * tls_ctx,struct tls_connection * conn,tls_session_ticket_cb cb,void * ctx)585839beb93cSSam Leffler int tls_connection_set_session_ticket_cb(void *tls_ctx,
585939beb93cSSam Leffler 					 struct tls_connection *conn,
586039beb93cSSam Leffler 					 tls_session_ticket_cb cb,
586139beb93cSSam Leffler 					 void *ctx)
586239beb93cSSam Leffler {
5863206b73d0SCy Schubert #ifdef EAP_FAST_OR_TEAP
586439beb93cSSam Leffler 	conn->session_ticket_cb = cb;
586539beb93cSSam Leffler 	conn->session_ticket_cb_ctx = ctx;
586639beb93cSSam Leffler 
586739beb93cSSam Leffler 	if (cb) {
586839beb93cSSam Leffler 		if (SSL_set_session_secret_cb(conn->ssl, tls_sess_sec_cb,
586939beb93cSSam Leffler 					      conn) != 1)
587039beb93cSSam Leffler 			return -1;
587139beb93cSSam Leffler 		SSL_set_session_ticket_ext_cb(conn->ssl,
587239beb93cSSam Leffler 					      tls_session_ticket_ext_cb, conn);
587339beb93cSSam Leffler 	} else {
587439beb93cSSam Leffler 		if (SSL_set_session_secret_cb(conn->ssl, NULL, NULL) != 1)
587539beb93cSSam Leffler 			return -1;
587639beb93cSSam Leffler 		SSL_set_session_ticket_ext_cb(conn->ssl, NULL, NULL);
587739beb93cSSam Leffler 	}
587839beb93cSSam Leffler 
587939beb93cSSam Leffler 	return 0;
5880206b73d0SCy Schubert #else /* EAP_FAST_OR_TEAP */
588139beb93cSSam Leffler 	return -1;
5882206b73d0SCy Schubert #endif /* EAP_FAST_OR_TEAP */
588339beb93cSSam Leffler }
58845b9c547cSRui Paulo 
58855b9c547cSRui Paulo 
tls_get_library_version(char * buf,size_t buf_len)58865b9c547cSRui Paulo int tls_get_library_version(char *buf, size_t buf_len)
58875b9c547cSRui Paulo {
5888780fb4a2SCy Schubert #if OPENSSL_VERSION_NUMBER >= 0x10100000L && !defined(LIBRESSL_VERSION_NUMBER)
5889780fb4a2SCy Schubert 	return os_snprintf(buf, buf_len, "OpenSSL build=%s run=%s",
5890780fb4a2SCy Schubert 			   OPENSSL_VERSION_TEXT,
5891780fb4a2SCy Schubert 			   OpenSSL_version(OPENSSL_VERSION));
5892780fb4a2SCy Schubert #else
58935b9c547cSRui Paulo 	return os_snprintf(buf, buf_len, "OpenSSL build=%s run=%s",
58945b9c547cSRui Paulo 			   OPENSSL_VERSION_TEXT,
58955b9c547cSRui Paulo 			   SSLeay_version(SSLEAY_VERSION));
5896780fb4a2SCy Schubert #endif
58975b9c547cSRui Paulo }
5898325151a3SRui Paulo 
5899325151a3SRui Paulo 
tls_connection_set_success_data(struct tls_connection * conn,struct wpabuf * data)5900325151a3SRui Paulo void tls_connection_set_success_data(struct tls_connection *conn,
5901325151a3SRui Paulo 				     struct wpabuf *data)
5902325151a3SRui Paulo {
5903325151a3SRui Paulo 	SSL_SESSION *sess;
5904325151a3SRui Paulo 	struct wpabuf *old;
5905*a90b9d01SCy Schubert 	struct tls_session_data *sess_data = NULL;
5906325151a3SRui Paulo 
5907325151a3SRui Paulo 	if (tls_ex_idx_session < 0)
5908325151a3SRui Paulo 		goto fail;
5909325151a3SRui Paulo 	sess = SSL_get_session(conn->ssl);
5910325151a3SRui Paulo 	if (!sess)
5911325151a3SRui Paulo 		goto fail;
5912325151a3SRui Paulo 	old = SSL_SESSION_get_ex_data(sess, tls_ex_idx_session);
5913325151a3SRui Paulo 	if (old) {
5914*a90b9d01SCy Schubert 		struct tls_session_data *found;
5915*a90b9d01SCy Schubert 
5916*a90b9d01SCy Schubert 		found = get_session_data(conn->context, old);
5917*a90b9d01SCy Schubert 		wpa_printf(MSG_DEBUG,
5918*a90b9d01SCy Schubert 			   "OpenSSL: Replacing old success data %p (sess %p)%s",
5919*a90b9d01SCy Schubert 			   old, sess, found ? "" : " (not freeing)");
5920*a90b9d01SCy Schubert 		if (found) {
5921*a90b9d01SCy Schubert 			dl_list_del(&found->list);
5922*a90b9d01SCy Schubert 			os_free(found);
5923325151a3SRui Paulo 			wpabuf_free(old);
5924325151a3SRui Paulo 		}
5925*a90b9d01SCy Schubert 	}
5926*a90b9d01SCy Schubert 
5927*a90b9d01SCy Schubert 	sess_data = os_zalloc(sizeof(*sess_data));
5928*a90b9d01SCy Schubert 	if (!sess_data ||
5929*a90b9d01SCy Schubert 	    SSL_SESSION_set_ex_data(sess, tls_ex_idx_session, data) != 1)
5930325151a3SRui Paulo 		goto fail;
5931325151a3SRui Paulo 
5932*a90b9d01SCy Schubert 	sess_data->buf = data;
5933*a90b9d01SCy Schubert 	dl_list_add(&conn->context->sessions, &sess_data->list);
5934*a90b9d01SCy Schubert 	wpa_printf(MSG_DEBUG, "OpenSSL: Stored success data %p (sess %p)",
5935*a90b9d01SCy Schubert 		   data, sess);
5936325151a3SRui Paulo 	conn->success_data = 1;
5937325151a3SRui Paulo 	return;
5938325151a3SRui Paulo 
5939325151a3SRui Paulo fail:
5940325151a3SRui Paulo 	wpa_printf(MSG_INFO, "OpenSSL: Failed to store success data");
5941325151a3SRui Paulo 	wpabuf_free(data);
5942*a90b9d01SCy Schubert 	os_free(sess_data);
5943325151a3SRui Paulo }
5944325151a3SRui Paulo 
5945325151a3SRui Paulo 
tls_connection_set_success_data_resumed(struct tls_connection * conn)5946325151a3SRui Paulo void tls_connection_set_success_data_resumed(struct tls_connection *conn)
5947325151a3SRui Paulo {
5948325151a3SRui Paulo 	wpa_printf(MSG_DEBUG,
5949325151a3SRui Paulo 		   "OpenSSL: Success data accepted for resumed session");
5950325151a3SRui Paulo 	conn->success_data = 1;
5951325151a3SRui Paulo }
5952325151a3SRui Paulo 
5953325151a3SRui Paulo 
5954325151a3SRui Paulo const struct wpabuf *
tls_connection_get_success_data(struct tls_connection * conn)5955325151a3SRui Paulo tls_connection_get_success_data(struct tls_connection *conn)
5956325151a3SRui Paulo {
5957325151a3SRui Paulo 	SSL_SESSION *sess;
5958325151a3SRui Paulo 
5959325151a3SRui Paulo 	if (tls_ex_idx_session < 0 ||
5960325151a3SRui Paulo 	    !(sess = SSL_get_session(conn->ssl)))
5961325151a3SRui Paulo 		return NULL;
5962325151a3SRui Paulo 	return SSL_SESSION_get_ex_data(sess, tls_ex_idx_session);
5963325151a3SRui Paulo }
5964325151a3SRui Paulo 
5965325151a3SRui Paulo 
tls_connection_remove_session(struct tls_connection * conn)5966325151a3SRui Paulo void tls_connection_remove_session(struct tls_connection *conn)
5967325151a3SRui Paulo {
5968325151a3SRui Paulo 	SSL_SESSION *sess;
5969325151a3SRui Paulo 
5970325151a3SRui Paulo 	sess = SSL_get_session(conn->ssl);
5971325151a3SRui Paulo 	if (!sess)
5972325151a3SRui Paulo 		return;
5973325151a3SRui Paulo 
5974325151a3SRui Paulo 	if (SSL_CTX_remove_session(conn->ssl_ctx, sess) != 1)
5975325151a3SRui Paulo 		wpa_printf(MSG_DEBUG,
5976325151a3SRui Paulo 			   "OpenSSL: Session was not cached");
5977325151a3SRui Paulo 	else
5978325151a3SRui Paulo 		wpa_printf(MSG_DEBUG,
5979325151a3SRui Paulo 			   "OpenSSL: Removed cached session to disable session resumption");
5980325151a3SRui Paulo }
5981206b73d0SCy Schubert 
5982206b73d0SCy Schubert 
tls_get_tls_unique(struct tls_connection * conn,u8 * buf,size_t max_len)5983206b73d0SCy Schubert int tls_get_tls_unique(struct tls_connection *conn, u8 *buf, size_t max_len)
5984206b73d0SCy Schubert {
5985206b73d0SCy Schubert 	size_t len;
5986206b73d0SCy Schubert 	int reused;
5987206b73d0SCy Schubert 
5988206b73d0SCy Schubert 	reused = SSL_session_reused(conn->ssl);
5989206b73d0SCy Schubert 	if ((conn->server && !reused) || (!conn->server && reused))
5990206b73d0SCy Schubert 		len = SSL_get_peer_finished(conn->ssl, buf, max_len);
5991206b73d0SCy Schubert 	else
5992206b73d0SCy Schubert 		len = SSL_get_finished(conn->ssl, buf, max_len);
5993206b73d0SCy Schubert 
5994206b73d0SCy Schubert 	if (len == 0 || len > max_len)
5995206b73d0SCy Schubert 		return -1;
5996206b73d0SCy Schubert 
5997206b73d0SCy Schubert 	return len;
5998206b73d0SCy Schubert }
5999206b73d0SCy Schubert 
6000206b73d0SCy Schubert 
tls_connection_get_cipher_suite(struct tls_connection * conn)6001206b73d0SCy Schubert u16 tls_connection_get_cipher_suite(struct tls_connection *conn)
6002206b73d0SCy Schubert {
6003206b73d0SCy Schubert 	const SSL_CIPHER *cipher;
6004206b73d0SCy Schubert 
6005206b73d0SCy Schubert 	cipher = SSL_get_current_cipher(conn->ssl);
6006206b73d0SCy Schubert 	if (!cipher)
6007206b73d0SCy Schubert 		return 0;
6008206b73d0SCy Schubert #if OPENSSL_VERSION_NUMBER >= 0x10101000L && !defined(LIBRESSL_VERSION_NUMBER)
6009206b73d0SCy Schubert 	return SSL_CIPHER_get_protocol_id(cipher);
6010206b73d0SCy Schubert #else
6011206b73d0SCy Schubert 	return SSL_CIPHER_get_id(cipher) & 0xFFFF;
6012206b73d0SCy Schubert #endif
6013206b73d0SCy Schubert }
6014c1d255d3SCy Schubert 
6015c1d255d3SCy Schubert 
tls_connection_get_peer_subject(struct tls_connection * conn)6016c1d255d3SCy Schubert const char * tls_connection_get_peer_subject(struct tls_connection *conn)
6017c1d255d3SCy Schubert {
6018c1d255d3SCy Schubert 	if (conn)
6019c1d255d3SCy Schubert 		return conn->peer_subject;
6020c1d255d3SCy Schubert 	return NULL;
6021c1d255d3SCy Schubert }
6022c1d255d3SCy Schubert 
6023c1d255d3SCy Schubert 
tls_connection_get_own_cert_used(struct tls_connection * conn)6024c1d255d3SCy Schubert bool tls_connection_get_own_cert_used(struct tls_connection *conn)
6025c1d255d3SCy Schubert {
6026c1d255d3SCy Schubert 	if (conn)
6027c1d255d3SCy Schubert 		return SSL_get_certificate(conn->ssl) != NULL;
6028c1d255d3SCy Schubert 	return false;
6029c1d255d3SCy Schubert }
6030