1189251Ssam/*
2214734Srpaulo * SSL/TLS interface functions for OpenSSL
3289549Srpaulo * Copyright (c) 2004-2015, Jouni Malinen <j@w1.fi>
4189251Ssam *
5252726Srpaulo * This software may be distributed under the terms of the BSD license.
6252726Srpaulo * See README for more details.
7189251Ssam */
8189251Ssam
9189251Ssam#include "includes.h"
10189251Ssam
11189251Ssam#ifndef CONFIG_SMARTCARD
12189251Ssam#ifndef OPENSSL_NO_ENGINE
13281806Srpaulo#ifndef ANDROID
14189251Ssam#define OPENSSL_NO_ENGINE
15189251Ssam#endif
16189251Ssam#endif
17281806Srpaulo#endif
18189251Ssam
19189251Ssam#include <openssl/ssl.h>
20189251Ssam#include <openssl/err.h>
21337817Scy#include <openssl/opensslv.h>
22189251Ssam#include <openssl/pkcs12.h>
23189251Ssam#include <openssl/x509v3.h>
24189251Ssam#ifndef OPENSSL_NO_ENGINE
25189251Ssam#include <openssl/engine.h>
26189251Ssam#endif /* OPENSSL_NO_ENGINE */
27289549Srpaulo#ifndef OPENSSL_NO_DSA
28289549Srpaulo#include <openssl/dsa.h>
29289549Srpaulo#endif
30289549Srpaulo#ifndef OPENSSL_NO_DH
31289549Srpaulo#include <openssl/dh.h>
32289549Srpaulo#endif
33189251Ssam
34189251Ssam#include "common.h"
35214734Srpaulo#include "crypto.h"
36289549Srpaulo#include "sha1.h"
37289549Srpaulo#include "sha256.h"
38189251Ssam#include "tls.h"
39337817Scy#include "tls_openssl.h"
40189251Ssam
41337817Scy#if !defined(CONFIG_FIPS) &&                             \
42337817Scy    (defined(EAP_FAST) || defined(EAP_FAST_DYNAMIC) ||   \
43337817Scy     defined(EAP_SERVER_FAST))
44337817Scy#define OPENSSL_NEED_EAP_FAST_PRF
45189251Ssam#endif
46281806Srpaulo
47351611Scy#if defined(EAP_FAST) || defined(EAP_FAST_DYNAMIC) || \
48351611Scy	defined(EAP_SERVER_FAST) || defined(EAP_TEAP) || \
49351611Scy	defined(EAP_SERVER_TEAP)
50351611Scy#define EAP_FAST_OR_TEAP
51351611Scy#endif
52351611Scy
53351611Scy
54281806Srpaulo#if defined(OPENSSL_IS_BORINGSSL)
55281806Srpaulo/* stack_index_t is the return type of OpenSSL's sk_XXX_num() functions. */
56281806Srpaulotypedef size_t stack_index_t;
57281806Srpaulo#else
58281806Srpaulotypedef int stack_index_t;
59189251Ssam#endif
60189251Ssam
61281806Srpaulo#ifdef SSL_set_tlsext_status_type
62281806Srpaulo#ifndef OPENSSL_NO_TLSEXT
63281806Srpaulo#define HAVE_OCSP
64281806Srpaulo#include <openssl/ocsp.h>
65281806Srpaulo#endif /* OPENSSL_NO_TLSEXT */
66281806Srpaulo#endif /* SSL_set_tlsext_status_type */
67281806Srpaulo
68337817Scy#if (OPENSSL_VERSION_NUMBER < 0x10100000L || \
69346981Scy     (defined(LIBRESSL_VERSION_NUMBER) && \
70346981Scy      LIBRESSL_VERSION_NUMBER < 0x20700000L)) && \
71337817Scy    !defined(BORINGSSL_API_VERSION)
72337817Scy/*
73337817Scy * SSL_get_client_random() and SSL_get_server_random() were added in OpenSSL
74337817Scy * 1.1.0 and newer BoringSSL revisions. Provide compatibility wrappers for
75337817Scy * older versions.
76337817Scy */
77337817Scy
78337817Scystatic size_t SSL_get_client_random(const SSL *ssl, unsigned char *out,
79337817Scy				    size_t outlen)
80337817Scy{
81337817Scy	if (!ssl->s3 || outlen < SSL3_RANDOM_SIZE)
82337817Scy		return 0;
83337817Scy	os_memcpy(out, ssl->s3->client_random, SSL3_RANDOM_SIZE);
84337817Scy	return SSL3_RANDOM_SIZE;
85337817Scy}
86337817Scy
87337817Scy
88337817Scystatic size_t SSL_get_server_random(const SSL *ssl, unsigned char *out,
89337817Scy				    size_t outlen)
90337817Scy{
91337817Scy	if (!ssl->s3 || outlen < SSL3_RANDOM_SIZE)
92337817Scy		return 0;
93337817Scy	os_memcpy(out, ssl->s3->server_random, SSL3_RANDOM_SIZE);
94337817Scy	return SSL3_RANDOM_SIZE;
95337817Scy}
96337817Scy
97337817Scy
98337817Scy#ifdef OPENSSL_NEED_EAP_FAST_PRF
99337817Scystatic size_t SSL_SESSION_get_master_key(const SSL_SESSION *session,
100337817Scy					 unsigned char *out, size_t outlen)
101337817Scy{
102337817Scy	if (!session || session->master_key_length < 0 ||
103337817Scy	    (size_t) session->master_key_length > outlen)
104337817Scy		return 0;
105337817Scy	if ((size_t) session->master_key_length < outlen)
106337817Scy		outlen = session->master_key_length;
107337817Scy	os_memcpy(out, session->master_key, outlen);
108337817Scy	return outlen;
109337817Scy}
110337817Scy#endif /* OPENSSL_NEED_EAP_FAST_PRF */
111337817Scy
112337817Scy#endif
113337817Scy
114346981Scy#if OPENSSL_VERSION_NUMBER < 0x10100000L || \
115346981Scy	(defined(LIBRESSL_VERSION_NUMBER) && \
116346981Scy	 LIBRESSL_VERSION_NUMBER < 0x20700000L)
117346981Scy#ifdef CONFIG_SUITEB
118346981Scystatic int RSA_bits(const RSA *r)
119346981Scy{
120346981Scy	return BN_num_bits(r->n);
121346981Scy}
122346981Scy#endif /* CONFIG_SUITEB */
123346981Scy
124346981Scy
125346981Scystatic const unsigned char * ASN1_STRING_get0_data(const ASN1_STRING *x)
126346981Scy{
127346981Scy	return ASN1_STRING_data((ASN1_STRING *) x);
128346981Scy}
129346981Scy#endif
130346981Scy
131281806Srpaulo#ifdef ANDROID
132281806Srpaulo#include <openssl/pem.h>
133281806Srpaulo#include <keystore/keystore_get.h>
134281806Srpaulo
135281806Srpaulostatic BIO * BIO_from_keystore(const char *key)
136281806Srpaulo{
137281806Srpaulo	BIO *bio = NULL;
138281806Srpaulo	uint8_t *value = NULL;
139281806Srpaulo	int length = keystore_get(key, strlen(key), &value);
140281806Srpaulo	if (length != -1 && (bio = BIO_new(BIO_s_mem())) != NULL)
141281806Srpaulo		BIO_write(bio, value, length);
142281806Srpaulo	free(value);
143281806Srpaulo	return bio;
144281806Srpaulo}
145337817Scy
146337817Scy
147337817Scystatic int tls_add_ca_from_keystore(X509_STORE *ctx, const char *key_alias)
148337817Scy{
149337817Scy	BIO *bio = BIO_from_keystore(key_alias);
150337817Scy	STACK_OF(X509_INFO) *stack = NULL;
151337817Scy	stack_index_t i;
152337817Scy
153337817Scy	if (bio) {
154337817Scy		stack = PEM_X509_INFO_read_bio(bio, NULL, NULL, NULL);
155337817Scy		BIO_free(bio);
156337817Scy	}
157337817Scy
158337817Scy	if (!stack) {
159337817Scy		wpa_printf(MSG_WARNING, "TLS: Failed to parse certificate: %s",
160337817Scy			   key_alias);
161337817Scy		return -1;
162337817Scy	}
163337817Scy
164337817Scy	for (i = 0; i < sk_X509_INFO_num(stack); ++i) {
165337817Scy		X509_INFO *info = sk_X509_INFO_value(stack, i);
166337817Scy
167337817Scy		if (info->x509)
168337817Scy			X509_STORE_add_cert(ctx, info->x509);
169337817Scy		if (info->crl)
170337817Scy			X509_STORE_add_crl(ctx, info->crl);
171337817Scy	}
172337817Scy
173337817Scy	sk_X509_INFO_pop_free(stack, X509_INFO_free);
174337817Scy
175337817Scy	return 0;
176337817Scy}
177337817Scy
178337817Scy
179337817Scystatic int tls_add_ca_from_keystore_encoded(X509_STORE *ctx,
180337817Scy					    const char *encoded_key_alias)
181337817Scy{
182337817Scy	int rc = -1;
183337817Scy	int len = os_strlen(encoded_key_alias);
184337817Scy	unsigned char *decoded_alias;
185337817Scy
186337817Scy	if (len & 1) {
187337817Scy		wpa_printf(MSG_WARNING, "Invalid hex-encoded alias: %s",
188337817Scy			   encoded_key_alias);
189337817Scy		return rc;
190337817Scy	}
191337817Scy
192337817Scy	decoded_alias = os_malloc(len / 2 + 1);
193337817Scy	if (decoded_alias) {
194337817Scy		if (!hexstr2bin(encoded_key_alias, decoded_alias, len / 2)) {
195337817Scy			decoded_alias[len / 2] = '\0';
196337817Scy			rc = tls_add_ca_from_keystore(
197337817Scy				ctx, (const char *) decoded_alias);
198337817Scy		}
199337817Scy		os_free(decoded_alias);
200337817Scy	}
201337817Scy
202337817Scy	return rc;
203337817Scy}
204337817Scy
205281806Srpaulo#endif /* ANDROID */
206281806Srpaulo
207189251Ssamstatic int tls_openssl_ref_count = 0;
208289549Srpaulostatic int tls_ex_idx_session = -1;
209189251Ssam
210281806Srpaulostruct tls_context {
211214734Srpaulo	void (*event_cb)(void *ctx, enum tls_event ev,
212214734Srpaulo			 union tls_event_data *data);
213214734Srpaulo	void *cb_ctx;
214252726Srpaulo	int cert_in_cb;
215281806Srpaulo	char *ocsp_stapling_response;
216214734Srpaulo};
217214734Srpaulo
218281806Srpaulostatic struct tls_context *tls_global = NULL;
219214734Srpaulo
220214734Srpaulo
221289549Srpaulostruct tls_data {
222289549Srpaulo	SSL_CTX *ssl;
223289549Srpaulo	unsigned int tls_session_lifetime;
224346981Scy	int check_crl;
225346981Scy	int check_crl_strict;
226346981Scy	char *ca_cert;
227346981Scy	unsigned int crl_reload_interval;
228346981Scy	struct os_reltime crl_last_reload;
229346981Scy	char *check_cert_subject;
230289549Srpaulo};
231289549Srpaulo
232189251Ssamstruct tls_connection {
233281806Srpaulo	struct tls_context *context;
234346981Scy	struct tls_data *data;
235281806Srpaulo	SSL_CTX *ssl_ctx;
236189251Ssam	SSL *ssl;
237189251Ssam	BIO *ssl_in, *ssl_out;
238337817Scy#if defined(ANDROID) || !defined(OPENSSL_NO_ENGINE)
239189251Ssam	ENGINE *engine;        /* functional reference to the engine */
240189251Ssam	EVP_PKEY *private_key; /* the private key if using engine */
241189251Ssam#endif /* OPENSSL_NO_ENGINE */
242281806Srpaulo	char *subject_match, *altsubject_match, *suffix_match, *domain_match;
243346981Scy	char *check_cert_subject;
244189251Ssam	int read_alerts, write_alerts, failed;
245189251Ssam
246189251Ssam	tls_session_ticket_cb session_ticket_cb;
247189251Ssam	void *session_ticket_cb_ctx;
248189251Ssam
249189251Ssam	/* SessionTicket received from OpenSSL hello_extension_cb (server) */
250189251Ssam	u8 *session_ticket;
251189251Ssam	size_t session_ticket_len;
252214734Srpaulo
253214734Srpaulo	unsigned int ca_cert_verify:1;
254214734Srpaulo	unsigned int cert_probe:1;
255214734Srpaulo	unsigned int server_cert_only:1;
256281806Srpaulo	unsigned int invalid_hb_used:1;
257289549Srpaulo	unsigned int success_data:1;
258346981Scy	unsigned int client_hello_generated:1;
259346981Scy	unsigned int server:1;
260214734Srpaulo
261214734Srpaulo	u8 srv_cert_hash[32];
262252726Srpaulo
263252726Srpaulo	unsigned int flags;
264281806Srpaulo
265281806Srpaulo	X509 *peer_cert;
266281806Srpaulo	X509 *peer_issuer;
267281806Srpaulo	X509 *peer_issuer_issuer;
268289549Srpaulo
269289549Srpaulo	unsigned char client_random[SSL3_RANDOM_SIZE];
270289549Srpaulo	unsigned char server_random[SSL3_RANDOM_SIZE];
271346981Scy
272346981Scy	u16 cipher_suite;
273346981Scy	int server_dh_prime_len;
274189251Ssam};
275189251Ssam
276189251Ssam
277281806Srpaulostatic struct tls_context * tls_context_new(const struct tls_config *conf)
278281806Srpaulo{
279281806Srpaulo	struct tls_context *context = os_zalloc(sizeof(*context));
280281806Srpaulo	if (context == NULL)
281281806Srpaulo		return NULL;
282281806Srpaulo	if (conf) {
283281806Srpaulo		context->event_cb = conf->event_cb;
284281806Srpaulo		context->cb_ctx = conf->cb_ctx;
285281806Srpaulo		context->cert_in_cb = conf->cert_in_cb;
286281806Srpaulo	}
287281806Srpaulo	return context;
288281806Srpaulo}
289281806Srpaulo
290281806Srpaulo
291189251Ssam#ifdef CONFIG_NO_STDOUT_DEBUG
292189251Ssam
293189251Ssamstatic void _tls_show_errors(void)
294189251Ssam{
295189251Ssam	unsigned long err;
296189251Ssam
297189251Ssam	while ((err = ERR_get_error())) {
298189251Ssam		/* Just ignore the errors, since stdout is disabled */
299189251Ssam	}
300189251Ssam}
301189251Ssam#define tls_show_errors(l, f, t) _tls_show_errors()
302189251Ssam
303189251Ssam#else /* CONFIG_NO_STDOUT_DEBUG */
304189251Ssam
305189251Ssamstatic void tls_show_errors(int level, const char *func, const char *txt)
306189251Ssam{
307189251Ssam	unsigned long err;
308189251Ssam
309189251Ssam	wpa_printf(level, "OpenSSL: %s - %s %s",
310189251Ssam		   func, txt, ERR_error_string(ERR_get_error(), NULL));
311189251Ssam
312189251Ssam	while ((err = ERR_get_error())) {
313189251Ssam		wpa_printf(MSG_INFO, "OpenSSL: pending error: %s",
314189251Ssam			   ERR_error_string(err, NULL));
315189251Ssam	}
316189251Ssam}
317189251Ssam
318189251Ssam#endif /* CONFIG_NO_STDOUT_DEBUG */
319189251Ssam
320189251Ssam
321346981Scystatic X509_STORE * tls_crl_cert_reload(const char *ca_cert, int check_crl)
322346981Scy{
323346981Scy	int flags;
324346981Scy	X509_STORE *store;
325346981Scy
326346981Scy	store = X509_STORE_new();
327346981Scy	if (!store) {
328346981Scy		wpa_printf(MSG_DEBUG,
329346981Scy			   "OpenSSL: %s - failed to allocate new certificate store",
330346981Scy			   __func__);
331346981Scy		return NULL;
332346981Scy	}
333346981Scy
334346981Scy	if (ca_cert && X509_STORE_load_locations(store, ca_cert, NULL) != 1) {
335346981Scy		tls_show_errors(MSG_WARNING, __func__,
336346981Scy				"Failed to load root certificates");
337346981Scy		X509_STORE_free(store);
338346981Scy		return NULL;
339346981Scy	}
340346981Scy
341346981Scy	flags = check_crl ? X509_V_FLAG_CRL_CHECK : 0;
342346981Scy	if (check_crl == 2)
343346981Scy		flags |= X509_V_FLAG_CRL_CHECK_ALL;
344346981Scy
345346981Scy	X509_STORE_set_flags(store, flags);
346346981Scy
347346981Scy	return store;
348346981Scy}
349346981Scy
350346981Scy
351189251Ssam#ifdef CONFIG_NATIVE_WINDOWS
352189251Ssam
353189251Ssam/* Windows CryptoAPI and access to certificate stores */
354189251Ssam#include <wincrypt.h>
355189251Ssam
356189251Ssam#ifdef __MINGW32_VERSION
357189251Ssam/*
358189251Ssam * MinGW does not yet include all the needed definitions for CryptoAPI, so
359189251Ssam * define here whatever extra is needed.
360189251Ssam */
361189251Ssam#define CERT_SYSTEM_STORE_CURRENT_USER (1 << 16)
362189251Ssam#define CERT_STORE_READONLY_FLAG 0x00008000
363189251Ssam#define CERT_STORE_OPEN_EXISTING_FLAG 0x00004000
364189251Ssam
365189251Ssam#endif /* __MINGW32_VERSION */
366189251Ssam
367189251Ssam
368189251Ssamstruct cryptoapi_rsa_data {
369189251Ssam	const CERT_CONTEXT *cert;
370189251Ssam	HCRYPTPROV crypt_prov;
371189251Ssam	DWORD key_spec;
372189251Ssam	BOOL free_crypt_prov;
373189251Ssam};
374189251Ssam
375189251Ssam
376189251Ssamstatic void cryptoapi_error(const char *msg)
377189251Ssam{
378189251Ssam	wpa_printf(MSG_INFO, "CryptoAPI: %s; err=%u",
379189251Ssam		   msg, (unsigned int) GetLastError());
380189251Ssam}
381189251Ssam
382189251Ssam
383189251Ssamstatic int cryptoapi_rsa_pub_enc(int flen, const unsigned char *from,
384189251Ssam				 unsigned char *to, RSA *rsa, int padding)
385189251Ssam{
386189251Ssam	wpa_printf(MSG_DEBUG, "%s - not implemented", __func__);
387189251Ssam	return 0;
388189251Ssam}
389189251Ssam
390189251Ssam
391189251Ssamstatic int cryptoapi_rsa_pub_dec(int flen, const unsigned char *from,
392189251Ssam				 unsigned char *to, RSA *rsa, int padding)
393189251Ssam{
394189251Ssam	wpa_printf(MSG_DEBUG, "%s - not implemented", __func__);
395189251Ssam	return 0;
396189251Ssam}
397189251Ssam
398189251Ssam
399189251Ssamstatic int cryptoapi_rsa_priv_enc(int flen, const unsigned char *from,
400189251Ssam				  unsigned char *to, RSA *rsa, int padding)
401189251Ssam{
402189251Ssam	struct cryptoapi_rsa_data *priv =
403189251Ssam		(struct cryptoapi_rsa_data *) rsa->meth->app_data;
404189251Ssam	HCRYPTHASH hash;
405189251Ssam	DWORD hash_size, len, i;
406189251Ssam	unsigned char *buf = NULL;
407189251Ssam	int ret = 0;
408189251Ssam
409189251Ssam	if (priv == NULL) {
410189251Ssam		RSAerr(RSA_F_RSA_EAY_PRIVATE_ENCRYPT,
411189251Ssam		       ERR_R_PASSED_NULL_PARAMETER);
412189251Ssam		return 0;
413189251Ssam	}
414189251Ssam
415189251Ssam	if (padding != RSA_PKCS1_PADDING) {
416189251Ssam		RSAerr(RSA_F_RSA_EAY_PRIVATE_ENCRYPT,
417189251Ssam		       RSA_R_UNKNOWN_PADDING_TYPE);
418189251Ssam		return 0;
419189251Ssam	}
420189251Ssam
421189251Ssam	if (flen != 16 /* MD5 */ + 20 /* SHA-1 */) {
422189251Ssam		wpa_printf(MSG_INFO, "%s - only MD5-SHA1 hash supported",
423189251Ssam			   __func__);
424189251Ssam		RSAerr(RSA_F_RSA_EAY_PRIVATE_ENCRYPT,
425189251Ssam		       RSA_R_INVALID_MESSAGE_LENGTH);
426189251Ssam		return 0;
427189251Ssam	}
428189251Ssam
429189251Ssam	if (!CryptCreateHash(priv->crypt_prov, CALG_SSL3_SHAMD5, 0, 0, &hash))
430189251Ssam	{
431189251Ssam		cryptoapi_error("CryptCreateHash failed");
432189251Ssam		return 0;
433189251Ssam	}
434189251Ssam
435189251Ssam	len = sizeof(hash_size);
436189251Ssam	if (!CryptGetHashParam(hash, HP_HASHSIZE, (BYTE *) &hash_size, &len,
437189251Ssam			       0)) {
438189251Ssam		cryptoapi_error("CryptGetHashParam failed");
439189251Ssam		goto err;
440189251Ssam	}
441189251Ssam
442189251Ssam	if ((int) hash_size != flen) {
443189251Ssam		wpa_printf(MSG_INFO, "CryptoAPI: Invalid hash size (%u != %d)",
444189251Ssam			   (unsigned) hash_size, flen);
445189251Ssam		RSAerr(RSA_F_RSA_EAY_PRIVATE_ENCRYPT,
446189251Ssam		       RSA_R_INVALID_MESSAGE_LENGTH);
447189251Ssam		goto err;
448189251Ssam	}
449189251Ssam	if (!CryptSetHashParam(hash, HP_HASHVAL, (BYTE * ) from, 0)) {
450189251Ssam		cryptoapi_error("CryptSetHashParam failed");
451189251Ssam		goto err;
452189251Ssam	}
453189251Ssam
454189251Ssam	len = RSA_size(rsa);
455189251Ssam	buf = os_malloc(len);
456189251Ssam	if (buf == NULL) {
457189251Ssam		RSAerr(RSA_F_RSA_EAY_PRIVATE_ENCRYPT, ERR_R_MALLOC_FAILURE);
458189251Ssam		goto err;
459189251Ssam	}
460189251Ssam
461189251Ssam	if (!CryptSignHash(hash, priv->key_spec, NULL, 0, buf, &len)) {
462189251Ssam		cryptoapi_error("CryptSignHash failed");
463189251Ssam		goto err;
464189251Ssam	}
465189251Ssam
466189251Ssam	for (i = 0; i < len; i++)
467189251Ssam		to[i] = buf[len - i - 1];
468189251Ssam	ret = len;
469189251Ssam
470189251Ssamerr:
471189251Ssam	os_free(buf);
472189251Ssam	CryptDestroyHash(hash);
473189251Ssam
474189251Ssam	return ret;
475189251Ssam}
476189251Ssam
477189251Ssam
478189251Ssamstatic int cryptoapi_rsa_priv_dec(int flen, const unsigned char *from,
479189251Ssam				  unsigned char *to, RSA *rsa, int padding)
480189251Ssam{
481189251Ssam	wpa_printf(MSG_DEBUG, "%s - not implemented", __func__);
482189251Ssam	return 0;
483189251Ssam}
484189251Ssam
485189251Ssam
486189251Ssamstatic void cryptoapi_free_data(struct cryptoapi_rsa_data *priv)
487189251Ssam{
488189251Ssam	if (priv == NULL)
489189251Ssam		return;
490189251Ssam	if (priv->crypt_prov && priv->free_crypt_prov)
491189251Ssam		CryptReleaseContext(priv->crypt_prov, 0);
492189251Ssam	if (priv->cert)
493189251Ssam		CertFreeCertificateContext(priv->cert);
494189251Ssam	os_free(priv);
495189251Ssam}
496189251Ssam
497189251Ssam
498189251Ssamstatic int cryptoapi_finish(RSA *rsa)
499189251Ssam{
500189251Ssam	cryptoapi_free_data((struct cryptoapi_rsa_data *) rsa->meth->app_data);
501189251Ssam	os_free((void *) rsa->meth);
502189251Ssam	rsa->meth = NULL;
503189251Ssam	return 1;
504189251Ssam}
505189251Ssam
506189251Ssam
507189251Ssamstatic const CERT_CONTEXT * cryptoapi_find_cert(const char *name, DWORD store)
508189251Ssam{
509189251Ssam	HCERTSTORE cs;
510189251Ssam	const CERT_CONTEXT *ret = NULL;
511189251Ssam
512189251Ssam	cs = CertOpenStore((LPCSTR) CERT_STORE_PROV_SYSTEM, 0, 0,
513189251Ssam			   store | CERT_STORE_OPEN_EXISTING_FLAG |
514189251Ssam			   CERT_STORE_READONLY_FLAG, L"MY");
515189251Ssam	if (cs == NULL) {
516189251Ssam		cryptoapi_error("Failed to open 'My system store'");
517189251Ssam		return NULL;
518189251Ssam	}
519189251Ssam
520189251Ssam	if (strncmp(name, "cert://", 7) == 0) {
521189251Ssam		unsigned short wbuf[255];
522189251Ssam		MultiByteToWideChar(CP_ACP, 0, name + 7, -1, wbuf, 255);
523189251Ssam		ret = CertFindCertificateInStore(cs, X509_ASN_ENCODING |
524189251Ssam						 PKCS_7_ASN_ENCODING,
525189251Ssam						 0, CERT_FIND_SUBJECT_STR,
526189251Ssam						 wbuf, NULL);
527189251Ssam	} else if (strncmp(name, "hash://", 7) == 0) {
528189251Ssam		CRYPT_HASH_BLOB blob;
529189251Ssam		int len;
530189251Ssam		const char *hash = name + 7;
531189251Ssam		unsigned char *buf;
532189251Ssam
533189251Ssam		len = os_strlen(hash) / 2;
534189251Ssam		buf = os_malloc(len);
535189251Ssam		if (buf && hexstr2bin(hash, buf, len) == 0) {
536189251Ssam			blob.cbData = len;
537189251Ssam			blob.pbData = buf;
538189251Ssam			ret = CertFindCertificateInStore(cs,
539189251Ssam							 X509_ASN_ENCODING |
540189251Ssam							 PKCS_7_ASN_ENCODING,
541189251Ssam							 0, CERT_FIND_HASH,
542189251Ssam							 &blob, NULL);
543189251Ssam		}
544189251Ssam		os_free(buf);
545189251Ssam	}
546189251Ssam
547189251Ssam	CertCloseStore(cs, 0);
548189251Ssam
549189251Ssam	return ret;
550189251Ssam}
551189251Ssam
552189251Ssam
553189251Ssamstatic int tls_cryptoapi_cert(SSL *ssl, const char *name)
554189251Ssam{
555189251Ssam	X509 *cert = NULL;
556189251Ssam	RSA *rsa = NULL, *pub_rsa;
557189251Ssam	struct cryptoapi_rsa_data *priv;
558189251Ssam	RSA_METHOD *rsa_meth;
559189251Ssam
560189251Ssam	if (name == NULL ||
561189251Ssam	    (strncmp(name, "cert://", 7) != 0 &&
562189251Ssam	     strncmp(name, "hash://", 7) != 0))
563189251Ssam		return -1;
564189251Ssam
565189251Ssam	priv = os_zalloc(sizeof(*priv));
566189251Ssam	rsa_meth = os_zalloc(sizeof(*rsa_meth));
567189251Ssam	if (priv == NULL || rsa_meth == NULL) {
568189251Ssam		wpa_printf(MSG_WARNING, "CryptoAPI: Failed to allocate memory "
569189251Ssam			   "for CryptoAPI RSA method");
570189251Ssam		os_free(priv);
571189251Ssam		os_free(rsa_meth);
572189251Ssam		return -1;
573189251Ssam	}
574189251Ssam
575189251Ssam	priv->cert = cryptoapi_find_cert(name, CERT_SYSTEM_STORE_CURRENT_USER);
576189251Ssam	if (priv->cert == NULL) {
577189251Ssam		priv->cert = cryptoapi_find_cert(
578189251Ssam			name, CERT_SYSTEM_STORE_LOCAL_MACHINE);
579189251Ssam	}
580189251Ssam	if (priv->cert == NULL) {
581189251Ssam		wpa_printf(MSG_INFO, "CryptoAPI: Could not find certificate "
582189251Ssam			   "'%s'", name);
583189251Ssam		goto err;
584189251Ssam	}
585189251Ssam
586281806Srpaulo	cert = d2i_X509(NULL,
587281806Srpaulo			(const unsigned char **) &priv->cert->pbCertEncoded,
588189251Ssam			priv->cert->cbCertEncoded);
589189251Ssam	if (cert == NULL) {
590189251Ssam		wpa_printf(MSG_INFO, "CryptoAPI: Could not process X509 DER "
591189251Ssam			   "encoding");
592189251Ssam		goto err;
593189251Ssam	}
594189251Ssam
595189251Ssam	if (!CryptAcquireCertificatePrivateKey(priv->cert,
596189251Ssam					       CRYPT_ACQUIRE_COMPARE_KEY_FLAG,
597189251Ssam					       NULL, &priv->crypt_prov,
598189251Ssam					       &priv->key_spec,
599189251Ssam					       &priv->free_crypt_prov)) {
600189251Ssam		cryptoapi_error("Failed to acquire a private key for the "
601189251Ssam				"certificate");
602189251Ssam		goto err;
603189251Ssam	}
604189251Ssam
605189251Ssam	rsa_meth->name = "Microsoft CryptoAPI RSA Method";
606189251Ssam	rsa_meth->rsa_pub_enc = cryptoapi_rsa_pub_enc;
607189251Ssam	rsa_meth->rsa_pub_dec = cryptoapi_rsa_pub_dec;
608189251Ssam	rsa_meth->rsa_priv_enc = cryptoapi_rsa_priv_enc;
609189251Ssam	rsa_meth->rsa_priv_dec = cryptoapi_rsa_priv_dec;
610189251Ssam	rsa_meth->finish = cryptoapi_finish;
611189251Ssam	rsa_meth->flags = RSA_METHOD_FLAG_NO_CHECK;
612189251Ssam	rsa_meth->app_data = (char *) priv;
613189251Ssam
614189251Ssam	rsa = RSA_new();
615189251Ssam	if (rsa == NULL) {
616189251Ssam		SSLerr(SSL_F_SSL_CTX_USE_CERTIFICATE_FILE,
617189251Ssam		       ERR_R_MALLOC_FAILURE);
618189251Ssam		goto err;
619189251Ssam	}
620189251Ssam
621189251Ssam	if (!SSL_use_certificate(ssl, cert)) {
622189251Ssam		RSA_free(rsa);
623189251Ssam		rsa = NULL;
624189251Ssam		goto err;
625189251Ssam	}
626189251Ssam	pub_rsa = cert->cert_info->key->pkey->pkey.rsa;
627189251Ssam	X509_free(cert);
628189251Ssam	cert = NULL;
629189251Ssam
630189251Ssam	rsa->n = BN_dup(pub_rsa->n);
631189251Ssam	rsa->e = BN_dup(pub_rsa->e);
632189251Ssam	if (!RSA_set_method(rsa, rsa_meth))
633189251Ssam		goto err;
634189251Ssam
635189251Ssam	if (!SSL_use_RSAPrivateKey(ssl, rsa))
636189251Ssam		goto err;
637189251Ssam	RSA_free(rsa);
638189251Ssam
639189251Ssam	return 0;
640189251Ssam
641189251Ssamerr:
642189251Ssam	if (cert)
643189251Ssam		X509_free(cert);
644189251Ssam	if (rsa)
645189251Ssam		RSA_free(rsa);
646189251Ssam	else {
647189251Ssam		os_free(rsa_meth);
648189251Ssam		cryptoapi_free_data(priv);
649189251Ssam	}
650189251Ssam	return -1;
651189251Ssam}
652189251Ssam
653189251Ssam
654189251Ssamstatic int tls_cryptoapi_ca_cert(SSL_CTX *ssl_ctx, SSL *ssl, const char *name)
655189251Ssam{
656189251Ssam	HCERTSTORE cs;
657189251Ssam	PCCERT_CONTEXT ctx = NULL;
658189251Ssam	X509 *cert;
659189251Ssam	char buf[128];
660189251Ssam	const char *store;
661189251Ssam#ifdef UNICODE
662189251Ssam	WCHAR *wstore;
663189251Ssam#endif /* UNICODE */
664189251Ssam
665189251Ssam	if (name == NULL || strncmp(name, "cert_store://", 13) != 0)
666189251Ssam		return -1;
667189251Ssam
668189251Ssam	store = name + 13;
669189251Ssam#ifdef UNICODE
670189251Ssam	wstore = os_malloc((os_strlen(store) + 1) * sizeof(WCHAR));
671189251Ssam	if (wstore == NULL)
672189251Ssam		return -1;
673189251Ssam	wsprintf(wstore, L"%S", store);
674189251Ssam	cs = CertOpenSystemStore(0, wstore);
675189251Ssam	os_free(wstore);
676189251Ssam#else /* UNICODE */
677189251Ssam	cs = CertOpenSystemStore(0, store);
678189251Ssam#endif /* UNICODE */
679189251Ssam	if (cs == NULL) {
680189251Ssam		wpa_printf(MSG_DEBUG, "%s: failed to open system cert store "
681189251Ssam			   "'%s': error=%d", __func__, store,
682189251Ssam			   (int) GetLastError());
683189251Ssam		return -1;
684189251Ssam	}
685189251Ssam
686189251Ssam	while ((ctx = CertEnumCertificatesInStore(cs, ctx))) {
687281806Srpaulo		cert = d2i_X509(NULL,
688281806Srpaulo				(const unsigned char **) &ctx->pbCertEncoded,
689189251Ssam				ctx->cbCertEncoded);
690189251Ssam		if (cert == NULL) {
691189251Ssam			wpa_printf(MSG_INFO, "CryptoAPI: Could not process "
692189251Ssam				   "X509 DER encoding for CA cert");
693189251Ssam			continue;
694189251Ssam		}
695189251Ssam
696189251Ssam		X509_NAME_oneline(X509_get_subject_name(cert), buf,
697189251Ssam				  sizeof(buf));
698189251Ssam		wpa_printf(MSG_DEBUG, "OpenSSL: Loaded CA certificate for "
699189251Ssam			   "system certificate store: subject='%s'", buf);
700189251Ssam
701337817Scy		if (!X509_STORE_add_cert(SSL_CTX_get_cert_store(ssl_ctx),
702337817Scy					 cert)) {
703189251Ssam			tls_show_errors(MSG_WARNING, __func__,
704189251Ssam					"Failed to add ca_cert to OpenSSL "
705189251Ssam					"certificate store");
706189251Ssam		}
707189251Ssam
708189251Ssam		X509_free(cert);
709189251Ssam	}
710189251Ssam
711189251Ssam	if (!CertCloseStore(cs, 0)) {
712189251Ssam		wpa_printf(MSG_DEBUG, "%s: failed to close system cert store "
713189251Ssam			   "'%s': error=%d", __func__, name + 13,
714189251Ssam			   (int) GetLastError());
715189251Ssam	}
716189251Ssam
717189251Ssam	return 0;
718189251Ssam}
719189251Ssam
720189251Ssam
721189251Ssam#else /* CONFIG_NATIVE_WINDOWS */
722189251Ssam
723189251Ssamstatic int tls_cryptoapi_cert(SSL *ssl, const char *name)
724189251Ssam{
725189251Ssam	return -1;
726189251Ssam}
727189251Ssam
728189251Ssam#endif /* CONFIG_NATIVE_WINDOWS */
729189251Ssam
730189251Ssam
731189251Ssamstatic void ssl_info_cb(const SSL *ssl, int where, int ret)
732189251Ssam{
733189251Ssam	const char *str;
734189251Ssam	int w;
735189251Ssam
736189251Ssam	wpa_printf(MSG_DEBUG, "SSL: (where=0x%x ret=0x%x)", where, ret);
737189251Ssam	w = where & ~SSL_ST_MASK;
738189251Ssam	if (w & SSL_ST_CONNECT)
739189251Ssam		str = "SSL_connect";
740189251Ssam	else if (w & SSL_ST_ACCEPT)
741189251Ssam		str = "SSL_accept";
742189251Ssam	else
743189251Ssam		str = "undefined";
744189251Ssam
745189251Ssam	if (where & SSL_CB_LOOP) {
746189251Ssam		wpa_printf(MSG_DEBUG, "SSL: %s:%s",
747189251Ssam			   str, SSL_state_string_long(ssl));
748189251Ssam	} else if (where & SSL_CB_ALERT) {
749281806Srpaulo		struct tls_connection *conn = SSL_get_app_data((SSL *) ssl);
750189251Ssam		wpa_printf(MSG_INFO, "SSL: SSL3 alert: %s:%s:%s",
751189251Ssam			   where & SSL_CB_READ ?
752189251Ssam			   "read (remote end reported an error)" :
753189251Ssam			   "write (local SSL3 detected an error)",
754189251Ssam			   SSL_alert_type_string_long(ret),
755189251Ssam			   SSL_alert_desc_string_long(ret));
756189251Ssam		if ((ret >> 8) == SSL3_AL_FATAL) {
757189251Ssam			if (where & SSL_CB_READ)
758189251Ssam				conn->read_alerts++;
759189251Ssam			else
760189251Ssam				conn->write_alerts++;
761189251Ssam		}
762281806Srpaulo		if (conn->context->event_cb != NULL) {
763252726Srpaulo			union tls_event_data ev;
764281806Srpaulo			struct tls_context *context = conn->context;
765252726Srpaulo			os_memset(&ev, 0, sizeof(ev));
766252726Srpaulo			ev.alert.is_local = !(where & SSL_CB_READ);
767252726Srpaulo			ev.alert.type = SSL_alert_type_string_long(ret);
768252726Srpaulo			ev.alert.description = SSL_alert_desc_string_long(ret);
769281806Srpaulo			context->event_cb(context->cb_ctx, TLS_ALERT, &ev);
770252726Srpaulo		}
771189251Ssam	} else if (where & SSL_CB_EXIT && ret <= 0) {
772189251Ssam		wpa_printf(MSG_DEBUG, "SSL: %s:%s in %s",
773189251Ssam			   str, ret == 0 ? "failed" : "error",
774189251Ssam			   SSL_state_string_long(ssl));
775189251Ssam	}
776189251Ssam}
777189251Ssam
778189251Ssam
779189251Ssam#ifndef OPENSSL_NO_ENGINE
780189251Ssam/**
781189251Ssam * tls_engine_load_dynamic_generic - load any openssl engine
782189251Ssam * @pre: an array of commands and values that load an engine initialized
783189251Ssam *       in the engine specific function
784189251Ssam * @post: an array of commands and values that initialize an already loaded
785189251Ssam *        engine (or %NULL if not required)
786189251Ssam * @id: the engine id of the engine to load (only required if post is not %NULL
787189251Ssam *
788189251Ssam * This function is a generic function that loads any openssl engine.
789189251Ssam *
790189251Ssam * Returns: 0 on success, -1 on failure
791189251Ssam */
792189251Ssamstatic int tls_engine_load_dynamic_generic(const char *pre[],
793189251Ssam					   const char *post[], const char *id)
794189251Ssam{
795189251Ssam	ENGINE *engine;
796189251Ssam	const char *dynamic_id = "dynamic";
797189251Ssam
798189251Ssam	engine = ENGINE_by_id(id);
799189251Ssam	if (engine) {
800189251Ssam		wpa_printf(MSG_DEBUG, "ENGINE: engine '%s' is already "
801189251Ssam			   "available", id);
802337817Scy		/*
803337817Scy		 * If it was auto-loaded by ENGINE_by_id() we might still
804337817Scy		 * need to tell it which PKCS#11 module to use in legacy
805337817Scy		 * (non-p11-kit) environments. Do so now; even if it was
806337817Scy		 * properly initialised before, setting it again will be
807337817Scy		 * harmless.
808337817Scy		 */
809337817Scy		goto found;
810189251Ssam	}
811189251Ssam	ERR_clear_error();
812189251Ssam
813189251Ssam	engine = ENGINE_by_id(dynamic_id);
814189251Ssam	if (engine == NULL) {
815189251Ssam		wpa_printf(MSG_INFO, "ENGINE: Can't find engine %s [%s]",
816189251Ssam			   dynamic_id,
817189251Ssam			   ERR_error_string(ERR_get_error(), NULL));
818189251Ssam		return -1;
819189251Ssam	}
820189251Ssam
821189251Ssam	/* Perform the pre commands. This will load the engine. */
822189251Ssam	while (pre && pre[0]) {
823189251Ssam		wpa_printf(MSG_DEBUG, "ENGINE: '%s' '%s'", pre[0], pre[1]);
824189251Ssam		if (ENGINE_ctrl_cmd_string(engine, pre[0], pre[1], 0) == 0) {
825189251Ssam			wpa_printf(MSG_INFO, "ENGINE: ctrl cmd_string failed: "
826189251Ssam				   "%s %s [%s]", pre[0], pre[1],
827189251Ssam				   ERR_error_string(ERR_get_error(), NULL));
828189251Ssam			ENGINE_free(engine);
829189251Ssam			return -1;
830189251Ssam		}
831189251Ssam		pre += 2;
832189251Ssam	}
833189251Ssam
834189251Ssam	/*
835189251Ssam	 * Free the reference to the "dynamic" engine. The loaded engine can
836189251Ssam	 * now be looked up using ENGINE_by_id().
837189251Ssam	 */
838189251Ssam	ENGINE_free(engine);
839189251Ssam
840189251Ssam	engine = ENGINE_by_id(id);
841189251Ssam	if (engine == NULL) {
842189251Ssam		wpa_printf(MSG_INFO, "ENGINE: Can't find engine %s [%s]",
843189251Ssam			   id, ERR_error_string(ERR_get_error(), NULL));
844189251Ssam		return -1;
845189251Ssam	}
846337817Scy found:
847189251Ssam	while (post && post[0]) {
848189251Ssam		wpa_printf(MSG_DEBUG, "ENGINE: '%s' '%s'", post[0], post[1]);
849189251Ssam		if (ENGINE_ctrl_cmd_string(engine, post[0], post[1], 0) == 0) {
850189251Ssam			wpa_printf(MSG_DEBUG, "ENGINE: ctrl cmd_string failed:"
851189251Ssam				" %s %s [%s]", post[0], post[1],
852189251Ssam				   ERR_error_string(ERR_get_error(), NULL));
853189251Ssam			ENGINE_remove(engine);
854189251Ssam			ENGINE_free(engine);
855189251Ssam			return -1;
856189251Ssam		}
857189251Ssam		post += 2;
858189251Ssam	}
859189251Ssam	ENGINE_free(engine);
860189251Ssam
861189251Ssam	return 0;
862189251Ssam}
863189251Ssam
864189251Ssam
865189251Ssam/**
866189251Ssam * tls_engine_load_dynamic_pkcs11 - load the pkcs11 engine provided by opensc
867189251Ssam * @pkcs11_so_path: pksc11_so_path from the configuration
868189251Ssam * @pcks11_module_path: pkcs11_module_path from the configuration
869189251Ssam */
870189251Ssamstatic int tls_engine_load_dynamic_pkcs11(const char *pkcs11_so_path,
871189251Ssam					  const char *pkcs11_module_path)
872189251Ssam{
873189251Ssam	char *engine_id = "pkcs11";
874189251Ssam	const char *pre_cmd[] = {
875189251Ssam		"SO_PATH", NULL /* pkcs11_so_path */,
876189251Ssam		"ID", NULL /* engine_id */,
877189251Ssam		"LIST_ADD", "1",
878189251Ssam		/* "NO_VCHECK", "1", */
879189251Ssam		"LOAD", NULL,
880189251Ssam		NULL, NULL
881189251Ssam	};
882189251Ssam	const char *post_cmd[] = {
883189251Ssam		"MODULE_PATH", NULL /* pkcs11_module_path */,
884189251Ssam		NULL, NULL
885189251Ssam	};
886189251Ssam
887281806Srpaulo	if (!pkcs11_so_path)
888189251Ssam		return 0;
889189251Ssam
890189251Ssam	pre_cmd[1] = pkcs11_so_path;
891189251Ssam	pre_cmd[3] = engine_id;
892281806Srpaulo	if (pkcs11_module_path)
893281806Srpaulo		post_cmd[1] = pkcs11_module_path;
894281806Srpaulo	else
895281806Srpaulo		post_cmd[0] = NULL;
896189251Ssam
897189251Ssam	wpa_printf(MSG_DEBUG, "ENGINE: Loading pkcs11 Engine from %s",
898189251Ssam		   pkcs11_so_path);
899189251Ssam
900189251Ssam	return tls_engine_load_dynamic_generic(pre_cmd, post_cmd, engine_id);
901189251Ssam}
902189251Ssam
903189251Ssam
904189251Ssam/**
905189251Ssam * tls_engine_load_dynamic_opensc - load the opensc engine provided by opensc
906189251Ssam * @opensc_so_path: opensc_so_path from the configuration
907189251Ssam */
908189251Ssamstatic int tls_engine_load_dynamic_opensc(const char *opensc_so_path)
909189251Ssam{
910189251Ssam	char *engine_id = "opensc";
911189251Ssam	const char *pre_cmd[] = {
912189251Ssam		"SO_PATH", NULL /* opensc_so_path */,
913189251Ssam		"ID", NULL /* engine_id */,
914189251Ssam		"LIST_ADD", "1",
915189251Ssam		"LOAD", NULL,
916189251Ssam		NULL, NULL
917189251Ssam	};
918189251Ssam
919189251Ssam	if (!opensc_so_path)
920189251Ssam		return 0;
921189251Ssam
922189251Ssam	pre_cmd[1] = opensc_so_path;
923189251Ssam	pre_cmd[3] = engine_id;
924189251Ssam
925189251Ssam	wpa_printf(MSG_DEBUG, "ENGINE: Loading OpenSC Engine from %s",
926189251Ssam		   opensc_so_path);
927189251Ssam
928189251Ssam	return tls_engine_load_dynamic_generic(pre_cmd, NULL, engine_id);
929189251Ssam}
930189251Ssam#endif /* OPENSSL_NO_ENGINE */
931189251Ssam
932189251Ssam
933289549Srpaulostatic void remove_session_cb(SSL_CTX *ctx, SSL_SESSION *sess)
934289549Srpaulo{
935289549Srpaulo	struct wpabuf *buf;
936289549Srpaulo
937289549Srpaulo	if (tls_ex_idx_session < 0)
938289549Srpaulo		return;
939289549Srpaulo	buf = SSL_SESSION_get_ex_data(sess, tls_ex_idx_session);
940289549Srpaulo	if (!buf)
941289549Srpaulo		return;
942289549Srpaulo	wpa_printf(MSG_DEBUG,
943289549Srpaulo		   "OpenSSL: Free application session data %p (sess %p)",
944289549Srpaulo		   buf, sess);
945289549Srpaulo	wpabuf_free(buf);
946289549Srpaulo
947289549Srpaulo	SSL_SESSION_set_ex_data(sess, tls_ex_idx_session, NULL);
948289549Srpaulo}
949289549Srpaulo
950289549Srpaulo
951189251Ssamvoid * tls_init(const struct tls_config *conf)
952189251Ssam{
953289549Srpaulo	struct tls_data *data;
954189251Ssam	SSL_CTX *ssl;
955281806Srpaulo	struct tls_context *context;
956281806Srpaulo	const char *ciphers;
957189251Ssam
958189251Ssam	if (tls_openssl_ref_count == 0) {
959281806Srpaulo		tls_global = context = tls_context_new(conf);
960281806Srpaulo		if (context == NULL)
961214734Srpaulo			return NULL;
962214734Srpaulo#ifdef CONFIG_FIPS
963214734Srpaulo#ifdef OPENSSL_FIPS
964214734Srpaulo		if (conf && conf->fips_mode) {
965289549Srpaulo			static int fips_enabled = 0;
966289549Srpaulo
967289549Srpaulo			if (!fips_enabled && !FIPS_mode_set(1)) {
968214734Srpaulo				wpa_printf(MSG_ERROR, "Failed to enable FIPS "
969214734Srpaulo					   "mode");
970214734Srpaulo				ERR_load_crypto_strings();
971214734Srpaulo				ERR_print_errors_fp(stderr);
972252726Srpaulo				os_free(tls_global);
973252726Srpaulo				tls_global = NULL;
974214734Srpaulo				return NULL;
975289549Srpaulo			} else {
976214734Srpaulo				wpa_printf(MSG_INFO, "Running in FIPS mode");
977289549Srpaulo				fips_enabled = 1;
978289549Srpaulo			}
979214734Srpaulo		}
980214734Srpaulo#else /* OPENSSL_FIPS */
981214734Srpaulo		if (conf && conf->fips_mode) {
982214734Srpaulo			wpa_printf(MSG_ERROR, "FIPS mode requested, but not "
983214734Srpaulo				   "supported");
984252726Srpaulo			os_free(tls_global);
985252726Srpaulo			tls_global = NULL;
986214734Srpaulo			return NULL;
987214734Srpaulo		}
988214734Srpaulo#endif /* OPENSSL_FIPS */
989214734Srpaulo#endif /* CONFIG_FIPS */
990346981Scy#if OPENSSL_VERSION_NUMBER < 0x10100000L || \
991346981Scy	(defined(LIBRESSL_VERSION_NUMBER) && \
992346981Scy	 LIBRESSL_VERSION_NUMBER < 0x20700000L)
993189251Ssam		SSL_load_error_strings();
994189251Ssam		SSL_library_init();
995281806Srpaulo#ifndef OPENSSL_NO_SHA256
996209158Srpaulo		EVP_add_digest(EVP_sha256());
997209158Srpaulo#endif /* OPENSSL_NO_SHA256 */
998189251Ssam		/* TODO: if /dev/urandom is available, PRNG is seeded
999189251Ssam		 * automatically. If this is not the case, random data should
1000189251Ssam		 * be added here. */
1001189251Ssam
1002189251Ssam#ifdef PKCS12_FUNCS
1003209158Srpaulo#ifndef OPENSSL_NO_RC2
1004209158Srpaulo		/*
1005209158Srpaulo		 * 40-bit RC2 is commonly used in PKCS#12 files, so enable it.
1006209158Srpaulo		 * This is enabled by PKCS12_PBE_add() in OpenSSL 0.9.8
1007209158Srpaulo		 * versions, but it looks like OpenSSL 1.0.0 does not do that
1008209158Srpaulo		 * anymore.
1009209158Srpaulo		 */
1010209158Srpaulo		EVP_add_cipher(EVP_rc2_40_cbc());
1011209158Srpaulo#endif /* OPENSSL_NO_RC2 */
1012189251Ssam		PKCS12_PBE_add();
1013189251Ssam#endif  /* PKCS12_FUNCS */
1014337817Scy#endif /* < 1.1.0 */
1015281806Srpaulo	} else {
1016281806Srpaulo		context = tls_context_new(conf);
1017281806Srpaulo		if (context == NULL)
1018281806Srpaulo			return NULL;
1019189251Ssam	}
1020189251Ssam	tls_openssl_ref_count++;
1021189251Ssam
1022289549Srpaulo	data = os_zalloc(sizeof(*data));
1023289549Srpaulo	if (data)
1024289549Srpaulo		ssl = SSL_CTX_new(SSLv23_method());
1025289549Srpaulo	else
1026289549Srpaulo		ssl = NULL;
1027281806Srpaulo	if (ssl == NULL) {
1028281806Srpaulo		tls_openssl_ref_count--;
1029281806Srpaulo		if (context != tls_global)
1030281806Srpaulo			os_free(context);
1031281806Srpaulo		if (tls_openssl_ref_count == 0) {
1032281806Srpaulo			os_free(tls_global);
1033281806Srpaulo			tls_global = NULL;
1034281806Srpaulo		}
1035337817Scy		os_free(data);
1036189251Ssam		return NULL;
1037281806Srpaulo	}
1038289549Srpaulo	data->ssl = ssl;
1039346981Scy	if (conf) {
1040289549Srpaulo		data->tls_session_lifetime = conf->tls_session_lifetime;
1041346981Scy		data->crl_reload_interval = conf->crl_reload_interval;
1042346981Scy	}
1043189251Ssam
1044281806Srpaulo	SSL_CTX_set_options(ssl, SSL_OP_NO_SSLv2);
1045281806Srpaulo	SSL_CTX_set_options(ssl, SSL_OP_NO_SSLv3);
1046281806Srpaulo
1047346981Scy#ifdef SSL_MODE_NO_AUTO_CHAIN
1048346981Scy	/* Number of deployed use cases assume the default OpenSSL behavior of
1049346981Scy	 * auto chaining the local certificate is in use. BoringSSL removed this
1050346981Scy	 * functionality by default, so we need to restore it here to avoid
1051346981Scy	 * breaking existing use cases. */
1052346981Scy	SSL_CTX_clear_mode(ssl, SSL_MODE_NO_AUTO_CHAIN);
1053346981Scy#endif /* SSL_MODE_NO_AUTO_CHAIN */
1054346981Scy
1055189251Ssam	SSL_CTX_set_info_callback(ssl, ssl_info_cb);
1056281806Srpaulo	SSL_CTX_set_app_data(ssl, context);
1057289549Srpaulo	if (data->tls_session_lifetime > 0) {
1058289549Srpaulo		SSL_CTX_set_quiet_shutdown(ssl, 1);
1059289549Srpaulo		/*
1060289549Srpaulo		 * Set default context here. In practice, this will be replaced
1061289549Srpaulo		 * by the per-EAP method context in tls_connection_set_verify().
1062289549Srpaulo		 */
1063289549Srpaulo		SSL_CTX_set_session_id_context(ssl, (u8 *) "hostapd", 7);
1064289549Srpaulo		SSL_CTX_set_session_cache_mode(ssl, SSL_SESS_CACHE_SERVER);
1065289549Srpaulo		SSL_CTX_set_timeout(ssl, data->tls_session_lifetime);
1066289549Srpaulo		SSL_CTX_sess_set_remove_cb(ssl, remove_session_cb);
1067289549Srpaulo	} else {
1068289549Srpaulo		SSL_CTX_set_session_cache_mode(ssl, SSL_SESS_CACHE_OFF);
1069289549Srpaulo	}
1070189251Ssam
1071289549Srpaulo	if (tls_ex_idx_session < 0) {
1072289549Srpaulo		tls_ex_idx_session = SSL_SESSION_get_ex_new_index(
1073289549Srpaulo			0, NULL, NULL, NULL, NULL);
1074289549Srpaulo		if (tls_ex_idx_session < 0) {
1075289549Srpaulo			tls_deinit(data);
1076289549Srpaulo			return NULL;
1077289549Srpaulo		}
1078289549Srpaulo	}
1079289549Srpaulo
1080189251Ssam#ifndef OPENSSL_NO_ENGINE
1081351611Scy	wpa_printf(MSG_DEBUG, "ENGINE: Loading builtin engines");
1082351611Scy	ENGINE_load_builtin_engines();
1083281806Srpaulo
1084189251Ssam	if (conf &&
1085189251Ssam	    (conf->opensc_engine_path || conf->pkcs11_engine_path ||
1086189251Ssam	     conf->pkcs11_module_path)) {
1087189251Ssam		if (tls_engine_load_dynamic_opensc(conf->opensc_engine_path) ||
1088189251Ssam		    tls_engine_load_dynamic_pkcs11(conf->pkcs11_engine_path,
1089189251Ssam						   conf->pkcs11_module_path)) {
1090289549Srpaulo			tls_deinit(data);
1091189251Ssam			return NULL;
1092189251Ssam		}
1093189251Ssam	}
1094189251Ssam#endif /* OPENSSL_NO_ENGINE */
1095189251Ssam
1096281806Srpaulo	if (conf && conf->openssl_ciphers)
1097281806Srpaulo		ciphers = conf->openssl_ciphers;
1098281806Srpaulo	else
1099346981Scy		ciphers = TLS_DEFAULT_CIPHERS;
1100281806Srpaulo	if (SSL_CTX_set_cipher_list(ssl, ciphers) != 1) {
1101281806Srpaulo		wpa_printf(MSG_ERROR,
1102281806Srpaulo			   "OpenSSL: Failed to set cipher string '%s'",
1103281806Srpaulo			   ciphers);
1104289549Srpaulo		tls_deinit(data);
1105281806Srpaulo		return NULL;
1106281806Srpaulo	}
1107281806Srpaulo
1108289549Srpaulo	return data;
1109189251Ssam}
1110189251Ssam
1111189251Ssam
1112189251Ssamvoid tls_deinit(void *ssl_ctx)
1113189251Ssam{
1114289549Srpaulo	struct tls_data *data = ssl_ctx;
1115289549Srpaulo	SSL_CTX *ssl = data->ssl;
1116281806Srpaulo	struct tls_context *context = SSL_CTX_get_app_data(ssl);
1117281806Srpaulo	if (context != tls_global)
1118281806Srpaulo		os_free(context);
1119289549Srpaulo	if (data->tls_session_lifetime > 0)
1120289549Srpaulo		SSL_CTX_flush_sessions(ssl, 0);
1121346981Scy	os_free(data->ca_cert);
1122189251Ssam	SSL_CTX_free(ssl);
1123189251Ssam
1124189251Ssam	tls_openssl_ref_count--;
1125189251Ssam	if (tls_openssl_ref_count == 0) {
1126346981Scy#if OPENSSL_VERSION_NUMBER < 0x10100000L || \
1127346981Scy	(defined(LIBRESSL_VERSION_NUMBER) && \
1128346981Scy	 LIBRESSL_VERSION_NUMBER < 0x20700000L)
1129189251Ssam#ifndef OPENSSL_NO_ENGINE
1130189251Ssam		ENGINE_cleanup();
1131189251Ssam#endif /* OPENSSL_NO_ENGINE */
1132189251Ssam		CRYPTO_cleanup_all_ex_data();
1133281806Srpaulo		ERR_remove_thread_state(NULL);
1134189251Ssam		ERR_free_strings();
1135189251Ssam		EVP_cleanup();
1136337817Scy#endif /* < 1.1.0 */
1137281806Srpaulo		os_free(tls_global->ocsp_stapling_response);
1138281806Srpaulo		tls_global->ocsp_stapling_response = NULL;
1139214734Srpaulo		os_free(tls_global);
1140214734Srpaulo		tls_global = NULL;
1141189251Ssam	}
1142289549Srpaulo
1143346981Scy	os_free(data->check_cert_subject);
1144289549Srpaulo	os_free(data);
1145189251Ssam}
1146189251Ssam
1147189251Ssam
1148289549Srpaulo#ifndef OPENSSL_NO_ENGINE
1149289549Srpaulo
1150289549Srpaulo/* Cryptoki return values */
1151289549Srpaulo#define CKR_PIN_INCORRECT 0x000000a0
1152289549Srpaulo#define CKR_PIN_INVALID 0x000000a1
1153289549Srpaulo#define CKR_PIN_LEN_RANGE 0x000000a2
1154289549Srpaulo
1155289549Srpaulo/* libp11 */
1156289549Srpaulo#define ERR_LIB_PKCS11	ERR_LIB_USER
1157289549Srpaulo
1158289549Srpaulostatic int tls_is_pin_error(unsigned int err)
1159289549Srpaulo{
1160289549Srpaulo	return ERR_GET_LIB(err) == ERR_LIB_PKCS11 &&
1161289549Srpaulo		(ERR_GET_REASON(err) == CKR_PIN_INCORRECT ||
1162289549Srpaulo		 ERR_GET_REASON(err) == CKR_PIN_INVALID ||
1163289549Srpaulo		 ERR_GET_REASON(err) == CKR_PIN_LEN_RANGE);
1164289549Srpaulo}
1165289549Srpaulo
1166289549Srpaulo#endif /* OPENSSL_NO_ENGINE */
1167289549Srpaulo
1168289549Srpaulo
1169337817Scy#ifdef ANDROID
1170337817Scy/* EVP_PKEY_from_keystore comes from system/security/keystore-engine. */
1171337817ScyEVP_PKEY * EVP_PKEY_from_keystore(const char *key_id);
1172337817Scy#endif /* ANDROID */
1173337817Scy
1174189251Ssamstatic int tls_engine_init(struct tls_connection *conn, const char *engine_id,
1175189251Ssam			   const char *pin, const char *key_id,
1176189251Ssam			   const char *cert_id, const char *ca_cert_id)
1177189251Ssam{
1178337817Scy#if defined(ANDROID) && defined(OPENSSL_IS_BORINGSSL)
1179337817Scy#if !defined(OPENSSL_NO_ENGINE)
1180337817Scy#error "This code depends on OPENSSL_NO_ENGINE being defined by BoringSSL."
1181337817Scy#endif
1182337817Scy	if (!key_id)
1183337817Scy		return TLS_SET_PARAMS_ENGINE_PRV_INIT_FAILED;
1184337817Scy	conn->engine = NULL;
1185337817Scy	conn->private_key = EVP_PKEY_from_keystore(key_id);
1186337817Scy	if (!conn->private_key) {
1187337817Scy		wpa_printf(MSG_ERROR,
1188337817Scy			   "ENGINE: cannot load private key with id '%s' [%s]",
1189337817Scy			   key_id,
1190337817Scy			   ERR_error_string(ERR_get_error(), NULL));
1191337817Scy		return TLS_SET_PARAMS_ENGINE_PRV_INIT_FAILED;
1192337817Scy	}
1193337817Scy#endif /* ANDROID && OPENSSL_IS_BORINGSSL */
1194337817Scy
1195189251Ssam#ifndef OPENSSL_NO_ENGINE
1196189251Ssam	int ret = -1;
1197189251Ssam	if (engine_id == NULL) {
1198189251Ssam		wpa_printf(MSG_ERROR, "ENGINE: Engine ID not set");
1199189251Ssam		return -1;
1200189251Ssam	}
1201189251Ssam
1202189251Ssam	ERR_clear_error();
1203281806Srpaulo#ifdef ANDROID
1204281806Srpaulo	ENGINE_load_dynamic();
1205281806Srpaulo#endif
1206189251Ssam	conn->engine = ENGINE_by_id(engine_id);
1207189251Ssam	if (!conn->engine) {
1208189251Ssam		wpa_printf(MSG_ERROR, "ENGINE: engine %s not available [%s]",
1209189251Ssam			   engine_id, ERR_error_string(ERR_get_error(), NULL));
1210189251Ssam		goto err;
1211189251Ssam	}
1212189251Ssam	if (ENGINE_init(conn->engine) != 1) {
1213189251Ssam		wpa_printf(MSG_ERROR, "ENGINE: engine init failed "
1214189251Ssam			   "(engine: %s) [%s]", engine_id,
1215189251Ssam			   ERR_error_string(ERR_get_error(), NULL));
1216189251Ssam		goto err;
1217189251Ssam	}
1218189251Ssam	wpa_printf(MSG_DEBUG, "ENGINE: engine initialized");
1219189251Ssam
1220281806Srpaulo#ifndef ANDROID
1221281806Srpaulo	if (pin && ENGINE_ctrl_cmd_string(conn->engine, "PIN", pin, 0) == 0) {
1222189251Ssam		wpa_printf(MSG_ERROR, "ENGINE: cannot set pin [%s]",
1223189251Ssam			   ERR_error_string(ERR_get_error(), NULL));
1224189251Ssam		goto err;
1225189251Ssam	}
1226281806Srpaulo#endif
1227281806Srpaulo	if (key_id) {
1228281806Srpaulo		/*
1229281806Srpaulo		 * Ensure that the ENGINE does not attempt to use the OpenSSL
1230281806Srpaulo		 * UI system to obtain a PIN, if we didn't provide one.
1231281806Srpaulo		 */
1232281806Srpaulo		struct {
1233281806Srpaulo			const void *password;
1234281806Srpaulo			const char *prompt_info;
1235281806Srpaulo		} key_cb = { "", NULL };
1236281806Srpaulo
1237281806Srpaulo		/* load private key first in-case PIN is required for cert */
1238281806Srpaulo		conn->private_key = ENGINE_load_private_key(conn->engine,
1239281806Srpaulo							    key_id, NULL,
1240281806Srpaulo							    &key_cb);
1241281806Srpaulo		if (!conn->private_key) {
1242289549Srpaulo			unsigned long err = ERR_get_error();
1243289549Srpaulo
1244281806Srpaulo			wpa_printf(MSG_ERROR,
1245281806Srpaulo				   "ENGINE: cannot load private key with id '%s' [%s]",
1246281806Srpaulo				   key_id,
1247289549Srpaulo				   ERR_error_string(err, NULL));
1248289549Srpaulo			if (tls_is_pin_error(err))
1249289549Srpaulo				ret = TLS_SET_PARAMS_ENGINE_PRV_BAD_PIN;
1250289549Srpaulo			else
1251289549Srpaulo				ret = TLS_SET_PARAMS_ENGINE_PRV_INIT_FAILED;
1252281806Srpaulo			goto err;
1253281806Srpaulo		}
1254189251Ssam	}
1255189251Ssam
1256189251Ssam	/* handle a certificate and/or CA certificate */
1257189251Ssam	if (cert_id || ca_cert_id) {
1258189251Ssam		const char *cmd_name = "LOAD_CERT_CTRL";
1259189251Ssam
1260189251Ssam		/* test if the engine supports a LOAD_CERT_CTRL */
1261189251Ssam		if (!ENGINE_ctrl(conn->engine, ENGINE_CTRL_GET_CMD_FROM_NAME,
1262189251Ssam				 0, (void *)cmd_name, NULL)) {
1263189251Ssam			wpa_printf(MSG_ERROR, "ENGINE: engine does not support"
1264189251Ssam				   " loading certificates");
1265189251Ssam			ret = TLS_SET_PARAMS_ENGINE_PRV_INIT_FAILED;
1266189251Ssam			goto err;
1267189251Ssam		}
1268189251Ssam	}
1269189251Ssam
1270189251Ssam	return 0;
1271189251Ssam
1272189251Ssamerr:
1273189251Ssam	if (conn->engine) {
1274189251Ssam		ENGINE_free(conn->engine);
1275189251Ssam		conn->engine = NULL;
1276189251Ssam	}
1277189251Ssam
1278189251Ssam	if (conn->private_key) {
1279189251Ssam		EVP_PKEY_free(conn->private_key);
1280189251Ssam		conn->private_key = NULL;
1281189251Ssam	}
1282189251Ssam
1283189251Ssam	return ret;
1284189251Ssam#else /* OPENSSL_NO_ENGINE */
1285189251Ssam	return 0;
1286189251Ssam#endif /* OPENSSL_NO_ENGINE */
1287189251Ssam}
1288189251Ssam
1289189251Ssam
1290189251Ssamstatic void tls_engine_deinit(struct tls_connection *conn)
1291189251Ssam{
1292337817Scy#if defined(ANDROID) || !defined(OPENSSL_NO_ENGINE)
1293189251Ssam	wpa_printf(MSG_DEBUG, "ENGINE: engine deinit");
1294189251Ssam	if (conn->private_key) {
1295189251Ssam		EVP_PKEY_free(conn->private_key);
1296189251Ssam		conn->private_key = NULL;
1297189251Ssam	}
1298189251Ssam	if (conn->engine) {
1299337817Scy#if !defined(OPENSSL_IS_BORINGSSL)
1300189251Ssam		ENGINE_finish(conn->engine);
1301337817Scy#endif /* !OPENSSL_IS_BORINGSSL */
1302189251Ssam		conn->engine = NULL;
1303189251Ssam	}
1304337817Scy#endif /* ANDROID || !OPENSSL_NO_ENGINE */
1305189251Ssam}
1306189251Ssam
1307189251Ssam
1308189251Ssamint tls_get_errors(void *ssl_ctx)
1309189251Ssam{
1310189251Ssam	int count = 0;
1311189251Ssam	unsigned long err;
1312189251Ssam
1313189251Ssam	while ((err = ERR_get_error())) {
1314189251Ssam		wpa_printf(MSG_INFO, "TLS - SSL error: %s",
1315189251Ssam			   ERR_error_string(err, NULL));
1316189251Ssam		count++;
1317189251Ssam	}
1318189251Ssam
1319189251Ssam	return count;
1320189251Ssam}
1321189251Ssam
1322281806Srpaulo
1323337817Scystatic const char * openssl_content_type(int content_type)
1324337817Scy{
1325337817Scy	switch (content_type) {
1326337817Scy	case 20:
1327337817Scy		return "change cipher spec";
1328337817Scy	case 21:
1329337817Scy		return "alert";
1330337817Scy	case 22:
1331337817Scy		return "handshake";
1332337817Scy	case 23:
1333337817Scy		return "application data";
1334337817Scy	case 24:
1335337817Scy		return "heartbeat";
1336337817Scy	case 256:
1337337817Scy		return "TLS header info"; /* pseudo content type */
1338351611Scy	case 257:
1339351611Scy		return "inner content type"; /* pseudo content type */
1340337817Scy	default:
1341337817Scy		return "?";
1342337817Scy	}
1343337817Scy}
1344337817Scy
1345337817Scy
1346337817Scystatic const char * openssl_handshake_type(int content_type, const u8 *buf,
1347337817Scy					   size_t len)
1348337817Scy{
1349351611Scy	if (content_type == 257 && buf && len == 1)
1350351611Scy		return openssl_content_type(buf[0]);
1351337817Scy	if (content_type != 22 || !buf || len == 0)
1352337817Scy		return "";
1353337817Scy	switch (buf[0]) {
1354337817Scy	case 0:
1355337817Scy		return "hello request";
1356337817Scy	case 1:
1357337817Scy		return "client hello";
1358337817Scy	case 2:
1359337817Scy		return "server hello";
1360346981Scy	case 3:
1361346981Scy		return "hello verify request";
1362337817Scy	case 4:
1363337817Scy		return "new session ticket";
1364346981Scy	case 5:
1365346981Scy		return "end of early data";
1366346981Scy	case 6:
1367346981Scy		return "hello retry request";
1368346981Scy	case 8:
1369346981Scy		return "encrypted extensions";
1370337817Scy	case 11:
1371337817Scy		return "certificate";
1372337817Scy	case 12:
1373337817Scy		return "server key exchange";
1374337817Scy	case 13:
1375337817Scy		return "certificate request";
1376337817Scy	case 14:
1377337817Scy		return "server hello done";
1378337817Scy	case 15:
1379337817Scy		return "certificate verify";
1380337817Scy	case 16:
1381337817Scy		return "client key exchange";
1382337817Scy	case 20:
1383337817Scy		return "finished";
1384337817Scy	case 21:
1385337817Scy		return "certificate url";
1386337817Scy	case 22:
1387337817Scy		return "certificate status";
1388346981Scy	case 23:
1389346981Scy		return "supplemental data";
1390346981Scy	case 24:
1391346981Scy		return "key update";
1392346981Scy	case 254:
1393346981Scy		return "message hash";
1394337817Scy	default:
1395337817Scy		return "?";
1396337817Scy	}
1397337817Scy}
1398337817Scy
1399337817Scy
1400346981Scy#ifdef CONFIG_SUITEB
1401346981Scy
1402346981Scystatic void check_server_hello(struct tls_connection *conn,
1403346981Scy			       const u8 *pos, const u8 *end)
1404346981Scy{
1405346981Scy	size_t payload_len, id_len;
1406346981Scy
1407346981Scy	/*
1408346981Scy	 * Parse ServerHello to get the selected cipher suite since OpenSSL does
1409346981Scy	 * not make it cleanly available during handshake and we need to know
1410346981Scy	 * whether DHE was selected.
1411346981Scy	 */
1412346981Scy
1413346981Scy	if (end - pos < 3)
1414346981Scy		return;
1415346981Scy	payload_len = WPA_GET_BE24(pos);
1416346981Scy	pos += 3;
1417346981Scy
1418346981Scy	if ((size_t) (end - pos) < payload_len)
1419346981Scy		return;
1420346981Scy	end = pos + payload_len;
1421346981Scy
1422346981Scy	/* Skip Version and Random */
1423346981Scy	if (end - pos < 2 + SSL3_RANDOM_SIZE)
1424346981Scy		return;
1425346981Scy	pos += 2 + SSL3_RANDOM_SIZE;
1426346981Scy
1427346981Scy	/* Skip Session ID */
1428346981Scy	if (end - pos < 1)
1429346981Scy		return;
1430346981Scy	id_len = *pos++;
1431346981Scy	if ((size_t) (end - pos) < id_len)
1432346981Scy		return;
1433346981Scy	pos += id_len;
1434346981Scy
1435346981Scy	if (end - pos < 2)
1436346981Scy		return;
1437346981Scy	conn->cipher_suite = WPA_GET_BE16(pos);
1438346981Scy	wpa_printf(MSG_DEBUG, "OpenSSL: Server selected cipher suite 0x%x",
1439346981Scy		   conn->cipher_suite);
1440346981Scy}
1441346981Scy
1442346981Scy
1443346981Scystatic void check_server_key_exchange(SSL *ssl, struct tls_connection *conn,
1444346981Scy				      const u8 *pos, const u8 *end)
1445346981Scy{
1446346981Scy	size_t payload_len;
1447346981Scy	u16 dh_len;
1448346981Scy	BIGNUM *p;
1449346981Scy	int bits;
1450346981Scy
1451346981Scy	if (!(conn->flags & TLS_CONN_SUITEB))
1452346981Scy		return;
1453346981Scy
1454346981Scy	/* DHE is enabled only with DHE-RSA-AES256-GCM-SHA384 */
1455346981Scy	if (conn->cipher_suite != 0x9f)
1456346981Scy		return;
1457346981Scy
1458346981Scy	if (end - pos < 3)
1459346981Scy		return;
1460346981Scy	payload_len = WPA_GET_BE24(pos);
1461346981Scy	pos += 3;
1462346981Scy
1463346981Scy	if ((size_t) (end - pos) < payload_len)
1464346981Scy		return;
1465346981Scy	end = pos + payload_len;
1466346981Scy
1467346981Scy	if (end - pos < 2)
1468346981Scy		return;
1469346981Scy	dh_len = WPA_GET_BE16(pos);
1470346981Scy	pos += 2;
1471346981Scy
1472346981Scy	if ((size_t) (end - pos) < dh_len)
1473346981Scy		return;
1474346981Scy	p = BN_bin2bn(pos, dh_len, NULL);
1475346981Scy	if (!p)
1476346981Scy		return;
1477346981Scy
1478346981Scy	bits = BN_num_bits(p);
1479346981Scy	BN_free(p);
1480346981Scy
1481346981Scy	conn->server_dh_prime_len = bits;
1482346981Scy	wpa_printf(MSG_DEBUG, "OpenSSL: Server DH prime length: %d bits",
1483346981Scy		   conn->server_dh_prime_len);
1484346981Scy}
1485346981Scy
1486346981Scy#endif /* CONFIG_SUITEB */
1487346981Scy
1488346981Scy
1489281806Srpaulostatic void tls_msg_cb(int write_p, int version, int content_type,
1490281806Srpaulo		       const void *buf, size_t len, SSL *ssl, void *arg)
1491281806Srpaulo{
1492281806Srpaulo	struct tls_connection *conn = arg;
1493281806Srpaulo	const u8 *pos = buf;
1494281806Srpaulo
1495337817Scy	if (write_p == 2) {
1496337817Scy		wpa_printf(MSG_DEBUG,
1497337817Scy			   "OpenSSL: session ver=0x%x content_type=%d",
1498337817Scy			   version, content_type);
1499337817Scy		wpa_hexdump_key(MSG_MSGDUMP, "OpenSSL: Data", buf, len);
1500337817Scy		return;
1501337817Scy	}
1502337817Scy
1503337817Scy	wpa_printf(MSG_DEBUG, "OpenSSL: %s ver=0x%x content_type=%d (%s/%s)",
1504337817Scy		   write_p ? "TX" : "RX", version, content_type,
1505337817Scy		   openssl_content_type(content_type),
1506337817Scy		   openssl_handshake_type(content_type, buf, len));
1507281806Srpaulo	wpa_hexdump_key(MSG_MSGDUMP, "OpenSSL: Message", buf, len);
1508281806Srpaulo	if (content_type == 24 && len >= 3 && pos[0] == 1) {
1509281806Srpaulo		size_t payload_len = WPA_GET_BE16(pos + 1);
1510281806Srpaulo		if (payload_len + 3 > len) {
1511281806Srpaulo			wpa_printf(MSG_ERROR, "OpenSSL: Heartbeat attack detected");
1512281806Srpaulo			conn->invalid_hb_used = 1;
1513281806Srpaulo		}
1514281806Srpaulo	}
1515346981Scy
1516346981Scy#ifdef CONFIG_SUITEB
1517346981Scy	/*
1518346981Scy	 * Need to parse these handshake messages to be able to check DH prime
1519346981Scy	 * length since OpenSSL does not expose the new cipher suite and DH
1520346981Scy	 * parameters during handshake (e.g., for cert_cb() callback).
1521346981Scy	 */
1522346981Scy	if (content_type == 22 && pos && len > 0 && pos[0] == 2)
1523346981Scy		check_server_hello(conn, pos + 1, pos + len);
1524346981Scy	if (content_type == 22 && pos && len > 0 && pos[0] == 12)
1525346981Scy		check_server_key_exchange(ssl, conn, pos + 1, pos + len);
1526346981Scy#endif /* CONFIG_SUITEB */
1527281806Srpaulo}
1528281806Srpaulo
1529281806Srpaulo
1530189251Ssamstruct tls_connection * tls_connection_init(void *ssl_ctx)
1531189251Ssam{
1532289549Srpaulo	struct tls_data *data = ssl_ctx;
1533289549Srpaulo	SSL_CTX *ssl = data->ssl;
1534189251Ssam	struct tls_connection *conn;
1535189251Ssam	long options;
1536346981Scy	X509_STORE *new_cert_store;
1537346981Scy	struct os_reltime now;
1538281806Srpaulo	struct tls_context *context = SSL_CTX_get_app_data(ssl);
1539189251Ssam
1540346981Scy	/* Replace X509 store if it is time to update CRL. */
1541346981Scy	if (data->crl_reload_interval > 0 && os_get_reltime(&now) == 0 &&
1542346981Scy	    os_reltime_expired(&now, &data->crl_last_reload,
1543346981Scy			       data->crl_reload_interval)) {
1544346981Scy		wpa_printf(MSG_INFO,
1545346981Scy			   "OpenSSL: Flushing X509 store with ca_cert file");
1546346981Scy		new_cert_store = tls_crl_cert_reload(data->ca_cert,
1547346981Scy						     data->check_crl);
1548346981Scy		if (!new_cert_store) {
1549346981Scy			wpa_printf(MSG_ERROR,
1550346981Scy				   "OpenSSL: Error replacing X509 store with ca_cert file");
1551346981Scy		} else {
1552346981Scy			/* Replace old store */
1553346981Scy			SSL_CTX_set_cert_store(ssl, new_cert_store);
1554346981Scy			data->crl_last_reload = now;
1555346981Scy		}
1556346981Scy	}
1557346981Scy
1558189251Ssam	conn = os_zalloc(sizeof(*conn));
1559189251Ssam	if (conn == NULL)
1560189251Ssam		return NULL;
1561346981Scy	conn->data = data;
1562289549Srpaulo	conn->ssl_ctx = ssl;
1563189251Ssam	conn->ssl = SSL_new(ssl);
1564189251Ssam	if (conn->ssl == NULL) {
1565189251Ssam		tls_show_errors(MSG_INFO, __func__,
1566189251Ssam				"Failed to initialize new SSL connection");
1567189251Ssam		os_free(conn);
1568189251Ssam		return NULL;
1569189251Ssam	}
1570189251Ssam
1571281806Srpaulo	conn->context = context;
1572189251Ssam	SSL_set_app_data(conn->ssl, conn);
1573281806Srpaulo	SSL_set_msg_callback(conn->ssl, tls_msg_cb);
1574281806Srpaulo	SSL_set_msg_callback_arg(conn->ssl, conn);
1575189251Ssam	options = SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3 |
1576189251Ssam		SSL_OP_SINGLE_DH_USE;
1577189251Ssam#ifdef SSL_OP_NO_COMPRESSION
1578189251Ssam	options |= SSL_OP_NO_COMPRESSION;
1579189251Ssam#endif /* SSL_OP_NO_COMPRESSION */
1580189251Ssam	SSL_set_options(conn->ssl, options);
1581351611Scy#ifdef SSL_OP_ENABLE_MIDDLEBOX_COMPAT
1582351611Scy	/* Hopefully there is no need for middlebox compatibility mechanisms
1583351611Scy	 * when going through EAP authentication. */
1584351611Scy	SSL_clear_options(conn->ssl, SSL_OP_ENABLE_MIDDLEBOX_COMPAT);
1585351611Scy#endif
1586189251Ssam
1587189251Ssam	conn->ssl_in = BIO_new(BIO_s_mem());
1588189251Ssam	if (!conn->ssl_in) {
1589189251Ssam		tls_show_errors(MSG_INFO, __func__,
1590189251Ssam				"Failed to create a new BIO for ssl_in");
1591189251Ssam		SSL_free(conn->ssl);
1592189251Ssam		os_free(conn);
1593189251Ssam		return NULL;
1594189251Ssam	}
1595189251Ssam
1596189251Ssam	conn->ssl_out = BIO_new(BIO_s_mem());
1597189251Ssam	if (!conn->ssl_out) {
1598189251Ssam		tls_show_errors(MSG_INFO, __func__,
1599189251Ssam				"Failed to create a new BIO for ssl_out");
1600189251Ssam		SSL_free(conn->ssl);
1601189251Ssam		BIO_free(conn->ssl_in);
1602189251Ssam		os_free(conn);
1603189251Ssam		return NULL;
1604189251Ssam	}
1605189251Ssam
1606189251Ssam	SSL_set_bio(conn->ssl, conn->ssl_in, conn->ssl_out);
1607189251Ssam
1608189251Ssam	return conn;
1609189251Ssam}
1610189251Ssam
1611189251Ssam
1612189251Ssamvoid tls_connection_deinit(void *ssl_ctx, struct tls_connection *conn)
1613189251Ssam{
1614189251Ssam	if (conn == NULL)
1615189251Ssam		return;
1616289549Srpaulo	if (conn->success_data) {
1617289549Srpaulo		/*
1618289549Srpaulo		 * Make sure ssl_clear_bad_session() does not remove this
1619289549Srpaulo		 * session.
1620289549Srpaulo		 */
1621289549Srpaulo		SSL_set_quiet_shutdown(conn->ssl, 1);
1622289549Srpaulo		SSL_shutdown(conn->ssl);
1623289549Srpaulo	}
1624189251Ssam	SSL_free(conn->ssl);
1625189251Ssam	tls_engine_deinit(conn);
1626189251Ssam	os_free(conn->subject_match);
1627189251Ssam	os_free(conn->altsubject_match);
1628281806Srpaulo	os_free(conn->suffix_match);
1629281806Srpaulo	os_free(conn->domain_match);
1630346981Scy	os_free(conn->check_cert_subject);
1631189251Ssam	os_free(conn->session_ticket);
1632189251Ssam	os_free(conn);
1633189251Ssam}
1634189251Ssam
1635189251Ssam
1636189251Ssamint tls_connection_established(void *ssl_ctx, struct tls_connection *conn)
1637189251Ssam{
1638189251Ssam	return conn ? SSL_is_init_finished(conn->ssl) : 0;
1639189251Ssam}
1640189251Ssam
1641189251Ssam
1642346981Scychar * tls_connection_peer_serial_num(void *tls_ctx,
1643346981Scy				      struct tls_connection *conn)
1644346981Scy{
1645346981Scy	ASN1_INTEGER *ser;
1646346981Scy	char *serial_num;
1647346981Scy	size_t len;
1648346981Scy
1649346981Scy	if (!conn->peer_cert)
1650346981Scy		return NULL;
1651346981Scy
1652346981Scy	ser = X509_get_serialNumber(conn->peer_cert);
1653346981Scy	if (!ser)
1654346981Scy		return NULL;
1655346981Scy
1656346981Scy	len = ASN1_STRING_length(ser) * 2 + 1;
1657346981Scy	serial_num = os_malloc(len);
1658346981Scy	if (!serial_num)
1659346981Scy		return NULL;
1660346981Scy	wpa_snprintf_hex_uppercase(serial_num, len,
1661346981Scy				   ASN1_STRING_get0_data(ser),
1662346981Scy				   ASN1_STRING_length(ser));
1663346981Scy	return serial_num;
1664346981Scy}
1665346981Scy
1666346981Scy
1667189251Ssamint tls_connection_shutdown(void *ssl_ctx, struct tls_connection *conn)
1668189251Ssam{
1669189251Ssam	if (conn == NULL)
1670189251Ssam		return -1;
1671189251Ssam
1672189251Ssam	/* Shutdown previous TLS connection without notifying the peer
1673189251Ssam	 * because the connection was already terminated in practice
1674189251Ssam	 * and "close notify" shutdown alert would confuse AS. */
1675189251Ssam	SSL_set_quiet_shutdown(conn->ssl, 1);
1676189251Ssam	SSL_shutdown(conn->ssl);
1677289549Srpaulo	return SSL_clear(conn->ssl) == 1 ? 0 : -1;
1678189251Ssam}
1679189251Ssam
1680189251Ssam
1681189251Ssamstatic int tls_match_altsubject_component(X509 *cert, int type,
1682189251Ssam					  const char *value, size_t len)
1683189251Ssam{
1684189251Ssam	GENERAL_NAME *gen;
1685189251Ssam	void *ext;
1686281806Srpaulo	int found = 0;
1687281806Srpaulo	stack_index_t i;
1688189251Ssam
1689189251Ssam	ext = X509_get_ext_d2i(cert, NID_subject_alt_name, NULL, NULL);
1690189251Ssam
1691189251Ssam	for (i = 0; ext && i < sk_GENERAL_NAME_num(ext); i++) {
1692189251Ssam		gen = sk_GENERAL_NAME_value(ext, i);
1693189251Ssam		if (gen->type != type)
1694189251Ssam			continue;
1695189251Ssam		if (os_strlen((char *) gen->d.ia5->data) == len &&
1696189251Ssam		    os_memcmp(value, gen->d.ia5->data, len) == 0)
1697189251Ssam			found++;
1698189251Ssam	}
1699189251Ssam
1700337817Scy	sk_GENERAL_NAME_pop_free(ext, GENERAL_NAME_free);
1701337817Scy
1702189251Ssam	return found;
1703189251Ssam}
1704189251Ssam
1705189251Ssam
1706189251Ssamstatic int tls_match_altsubject(X509 *cert, const char *match)
1707189251Ssam{
1708189251Ssam	int type;
1709189251Ssam	const char *pos, *end;
1710189251Ssam	size_t len;
1711189251Ssam
1712189251Ssam	pos = match;
1713189251Ssam	do {
1714189251Ssam		if (os_strncmp(pos, "EMAIL:", 6) == 0) {
1715189251Ssam			type = GEN_EMAIL;
1716189251Ssam			pos += 6;
1717189251Ssam		} else if (os_strncmp(pos, "DNS:", 4) == 0) {
1718189251Ssam			type = GEN_DNS;
1719189251Ssam			pos += 4;
1720189251Ssam		} else if (os_strncmp(pos, "URI:", 4) == 0) {
1721189251Ssam			type = GEN_URI;
1722189251Ssam			pos += 4;
1723189251Ssam		} else {
1724189251Ssam			wpa_printf(MSG_INFO, "TLS: Invalid altSubjectName "
1725189251Ssam				   "match '%s'", pos);
1726189251Ssam			return 0;
1727189251Ssam		}
1728189251Ssam		end = os_strchr(pos, ';');
1729189251Ssam		while (end) {
1730189251Ssam			if (os_strncmp(end + 1, "EMAIL:", 6) == 0 ||
1731189251Ssam			    os_strncmp(end + 1, "DNS:", 4) == 0 ||
1732189251Ssam			    os_strncmp(end + 1, "URI:", 4) == 0)
1733189251Ssam				break;
1734189251Ssam			end = os_strchr(end + 1, ';');
1735189251Ssam		}
1736189251Ssam		if (end)
1737189251Ssam			len = end - pos;
1738189251Ssam		else
1739189251Ssam			len = os_strlen(pos);
1740189251Ssam		if (tls_match_altsubject_component(cert, type, pos, len) > 0)
1741189251Ssam			return 1;
1742189251Ssam		pos = end + 1;
1743189251Ssam	} while (end);
1744189251Ssam
1745189251Ssam	return 0;
1746189251Ssam}
1747189251Ssam
1748189251Ssam
1749281806Srpaulo#ifndef CONFIG_NATIVE_WINDOWS
1750281806Srpaulostatic int domain_suffix_match(const u8 *val, size_t len, const char *match,
1751346981Scy			       size_t match_len, int full)
1752281806Srpaulo{
1753346981Scy	size_t i;
1754281806Srpaulo
1755281806Srpaulo	/* Check for embedded nuls that could mess up suffix matching */
1756281806Srpaulo	for (i = 0; i < len; i++) {
1757281806Srpaulo		if (val[i] == '\0') {
1758281806Srpaulo			wpa_printf(MSG_DEBUG, "TLS: Embedded null in a string - reject");
1759281806Srpaulo			return 0;
1760281806Srpaulo		}
1761281806Srpaulo	}
1762281806Srpaulo
1763281806Srpaulo	if (match_len > len || (full && match_len != len))
1764281806Srpaulo		return 0;
1765281806Srpaulo
1766281806Srpaulo	if (os_strncasecmp((const char *) val + len - match_len, match,
1767281806Srpaulo			   match_len) != 0)
1768281806Srpaulo		return 0; /* no match */
1769281806Srpaulo
1770281806Srpaulo	if (match_len == len)
1771281806Srpaulo		return 1; /* exact match */
1772281806Srpaulo
1773281806Srpaulo	if (val[len - match_len - 1] == '.')
1774281806Srpaulo		return 1; /* full label match completes suffix match */
1775281806Srpaulo
1776281806Srpaulo	wpa_printf(MSG_DEBUG, "TLS: Reject due to incomplete label match");
1777281806Srpaulo	return 0;
1778281806Srpaulo}
1779281806Srpaulo#endif /* CONFIG_NATIVE_WINDOWS */
1780281806Srpaulo
1781281806Srpaulo
1782346981Scystruct tls_dn_field_order_cnt {
1783346981Scy	u8 cn;
1784346981Scy	u8 c;
1785346981Scy	u8 l;
1786346981Scy	u8 st;
1787346981Scy	u8 o;
1788346981Scy	u8 ou;
1789346981Scy	u8 email;
1790346981Scy};
1791346981Scy
1792346981Scy
1793346981Scystatic int get_dn_field_index(const struct tls_dn_field_order_cnt *dn_cnt,
1794346981Scy			      int nid)
1795281806Srpaulo{
1796346981Scy	switch (nid) {
1797346981Scy	case NID_commonName:
1798346981Scy		return dn_cnt->cn;
1799346981Scy	case NID_countryName:
1800346981Scy		return dn_cnt->c;
1801346981Scy	case NID_localityName:
1802346981Scy		return dn_cnt->l;
1803346981Scy	case NID_stateOrProvinceName:
1804346981Scy		return dn_cnt->st;
1805346981Scy	case NID_organizationName:
1806346981Scy		return dn_cnt->o;
1807346981Scy	case NID_organizationalUnitName:
1808346981Scy		return dn_cnt->ou;
1809346981Scy	case NID_pkcs9_emailAddress:
1810346981Scy		return dn_cnt->email;
1811346981Scy	default:
1812346981Scy		wpa_printf(MSG_ERROR,
1813346981Scy			   "TLS: Unknown NID '%d' in check_cert_subject",
1814346981Scy			   nid);
1815346981Scy		return -1;
1816346981Scy	}
1817346981Scy}
1818346981Scy
1819346981Scy
1820346981Scy/**
1821346981Scy * match_dn_field - Match configuration DN field against Certificate DN field
1822346981Scy * @cert: Certificate
1823346981Scy * @nid: NID of DN field
1824346981Scy * @field: Field name
1825346981Scy * @value DN field value which is passed from configuration
1826346981Scy *	e.g., if configuration have C=US and this argument will point to US.
1827346981Scy * @dn_cnt: DN matching context
1828346981Scy * Returns: 1 on success and 0 on failure
1829346981Scy */
1830346981Scystatic int match_dn_field(const X509 *cert, int nid, const char *field,
1831346981Scy			  const char *value,
1832346981Scy			  const struct tls_dn_field_order_cnt *dn_cnt)
1833346981Scy{
1834346981Scy	int i, ret = 0, len, config_dn_field_index, match_index = 0;
1835346981Scy	X509_NAME *name;
1836346981Scy
1837346981Scy	len = os_strlen(value);
1838346981Scy	name = X509_get_subject_name((X509 *) cert);
1839346981Scy
1840346981Scy	/* Assign incremented cnt for every field of DN to check DN field in
1841346981Scy	 * right order */
1842346981Scy	config_dn_field_index = get_dn_field_index(dn_cnt, nid);
1843346981Scy	if (config_dn_field_index < 0)
1844346981Scy		return 0;
1845346981Scy
1846346981Scy	/* Fetch value based on NID */
1847346981Scy	for (i = -1; (i = X509_NAME_get_index_by_NID(name, nid, i)) > -1;) {
1848346981Scy		X509_NAME_ENTRY *e;
1849346981Scy		ASN1_STRING *cn;
1850346981Scy
1851346981Scy		e = X509_NAME_get_entry(name, i);
1852346981Scy		if (!e)
1853346981Scy			continue;
1854346981Scy
1855346981Scy		cn = X509_NAME_ENTRY_get_data(e);
1856346981Scy		if (!cn)
1857346981Scy			continue;
1858346981Scy
1859346981Scy		match_index++;
1860346981Scy
1861346981Scy		/* check for more than one DN field with same name */
1862346981Scy		if (match_index != config_dn_field_index)
1863346981Scy			continue;
1864346981Scy
1865346981Scy		/* Check wildcard at the right end side */
1866346981Scy		/* E.g., if OU=develop* mentioned in configuration, allow 'OU'
1867346981Scy		 * of the subject in the client certificate to start with
1868346981Scy		 * 'develop' */
1869346981Scy		if (len > 0 && value[len - 1] == '*') {
1870346981Scy			/* Compare actual certificate DN field value with
1871346981Scy			 * configuration DN field value up to the specified
1872346981Scy			 * length. */
1873346981Scy			ret = ASN1_STRING_length(cn) >= len - 1 &&
1874346981Scy				os_memcmp(ASN1_STRING_get0_data(cn), value,
1875346981Scy					  len - 1) == 0;
1876346981Scy		} else {
1877346981Scy			/* Compare actual certificate DN field value with
1878346981Scy			 * configuration DN field value */
1879346981Scy			ret = ASN1_STRING_length(cn) == len &&
1880346981Scy				os_memcmp(ASN1_STRING_get0_data(cn), value,
1881346981Scy					  len) == 0;
1882346981Scy		}
1883346981Scy		if (!ret) {
1884346981Scy			wpa_printf(MSG_ERROR,
1885346981Scy				   "OpenSSL: Failed to match %s '%s' with certificate DN field value '%s'",
1886346981Scy				   field, value, ASN1_STRING_get0_data(cn));
1887346981Scy		}
1888346981Scy		break;
1889346981Scy	}
1890346981Scy
1891346981Scy	return ret;
1892346981Scy}
1893346981Scy
1894346981Scy
1895346981Scy/**
1896346981Scy * get_value_from_field - Get value from DN field
1897346981Scy * @cert: Certificate
1898346981Scy * @field_str: DN field string which is passed from configuration file (e.g.,
1899346981Scy *	 C=US)
1900346981Scy * @dn_cnt: DN matching context
1901346981Scy * Returns: 1 on success and 0 on failure
1902346981Scy */
1903346981Scystatic int get_value_from_field(const X509 *cert, char *field_str,
1904346981Scy				struct tls_dn_field_order_cnt *dn_cnt)
1905346981Scy{
1906346981Scy	int nid;
1907346981Scy	char *context = NULL, *name, *value;
1908346981Scy
1909346981Scy	if (os_strcmp(field_str, "*") == 0)
1910346981Scy		return 1; /* wildcard matches everything */
1911346981Scy
1912346981Scy	name = str_token(field_str, "=", &context);
1913346981Scy	if (!name)
1914346981Scy		return 0;
1915346981Scy
1916346981Scy	/* Compare all configured DN fields and assign nid based on that to
1917346981Scy	 * fetch correct value from certificate subject */
1918346981Scy	if (os_strcmp(name, "CN") == 0) {
1919346981Scy		nid = NID_commonName;
1920346981Scy		dn_cnt->cn++;
1921346981Scy	} else if(os_strcmp(name, "C") == 0) {
1922346981Scy		nid = NID_countryName;
1923346981Scy		dn_cnt->c++;
1924346981Scy	} else if (os_strcmp(name, "L") == 0) {
1925346981Scy		nid = NID_localityName;
1926346981Scy		dn_cnt->l++;
1927346981Scy	} else if (os_strcmp(name, "ST") == 0) {
1928346981Scy		nid = NID_stateOrProvinceName;
1929346981Scy		dn_cnt->st++;
1930346981Scy	} else if (os_strcmp(name, "O") == 0) {
1931346981Scy		nid = NID_organizationName;
1932346981Scy		dn_cnt->o++;
1933346981Scy	} else if (os_strcmp(name, "OU") == 0) {
1934346981Scy		nid = NID_organizationalUnitName;
1935346981Scy		dn_cnt->ou++;
1936346981Scy	} else if (os_strcmp(name, "emailAddress") == 0) {
1937346981Scy		nid = NID_pkcs9_emailAddress;
1938346981Scy		dn_cnt->email++;
1939346981Scy	} else {
1940346981Scy		wpa_printf(MSG_ERROR,
1941346981Scy			"TLS: Unknown field '%s' in check_cert_subject", name);
1942346981Scy		return 0;
1943346981Scy	}
1944346981Scy
1945346981Scy	value = str_token(field_str, "=", &context);
1946346981Scy	if (!value) {
1947346981Scy		wpa_printf(MSG_ERROR,
1948346981Scy			   "TLS: Distinguished Name field '%s' value is not defined in check_cert_subject",
1949346981Scy			   name);
1950346981Scy		return 0;
1951346981Scy	}
1952346981Scy
1953346981Scy	return match_dn_field(cert, nid, name, value, dn_cnt);
1954346981Scy}
1955346981Scy
1956346981Scy
1957346981Scy/**
1958346981Scy * tls_match_dn_field - Match subject DN field with check_cert_subject
1959346981Scy * @cert: Certificate
1960346981Scy * @match: check_cert_subject string
1961346981Scy * Returns: Return 1 on success and 0 on failure
1962346981Scy*/
1963346981Scystatic int tls_match_dn_field(X509 *cert, const char *match)
1964346981Scy{
1965346981Scy	const char *token, *last = NULL;
1966346981Scy	char field[256];
1967346981Scy	struct tls_dn_field_order_cnt dn_cnt;
1968346981Scy
1969346981Scy	os_memset(&dn_cnt, 0, sizeof(dn_cnt));
1970346981Scy
1971346981Scy	/* Maximum length of each DN field is 255 characters */
1972346981Scy
1973346981Scy	/* Process each '/' delimited field */
1974346981Scy	while ((token = cstr_token(match, "/", &last))) {
1975346981Scy		if (last - token >= (int) sizeof(field)) {
1976346981Scy			wpa_printf(MSG_ERROR,
1977346981Scy				   "OpenSSL: Too long DN matching field value in '%s'",
1978346981Scy				   match);
1979346981Scy			return 0;
1980346981Scy		}
1981346981Scy		os_memcpy(field, token, last - token);
1982346981Scy		field[last - token] = '\0';
1983346981Scy
1984346981Scy		if (!get_value_from_field(cert, field, &dn_cnt)) {
1985346981Scy			wpa_printf(MSG_DEBUG, "OpenSSL: No match for DN '%s'",
1986346981Scy				   field);
1987346981Scy			return 0;
1988346981Scy		}
1989346981Scy	}
1990346981Scy
1991346981Scy	return 1;
1992346981Scy}
1993346981Scy
1994346981Scy
1995346981Scy#ifndef CONFIG_NATIVE_WINDOWS
1996346981Scystatic int tls_match_suffix_helper(X509 *cert, const char *match,
1997346981Scy				   size_t match_len, int full)
1998346981Scy{
1999281806Srpaulo	GENERAL_NAME *gen;
2000281806Srpaulo	void *ext;
2001281806Srpaulo	int i;
2002281806Srpaulo	stack_index_t j;
2003281806Srpaulo	int dns_name = 0;
2004281806Srpaulo	X509_NAME *name;
2005281806Srpaulo
2006281806Srpaulo	wpa_printf(MSG_DEBUG, "TLS: Match domain against %s%s",
2007281806Srpaulo		   full ? "": "suffix ", match);
2008281806Srpaulo
2009281806Srpaulo	ext = X509_get_ext_d2i(cert, NID_subject_alt_name, NULL, NULL);
2010281806Srpaulo
2011281806Srpaulo	for (j = 0; ext && j < sk_GENERAL_NAME_num(ext); j++) {
2012281806Srpaulo		gen = sk_GENERAL_NAME_value(ext, j);
2013281806Srpaulo		if (gen->type != GEN_DNS)
2014281806Srpaulo			continue;
2015281806Srpaulo		dns_name++;
2016281806Srpaulo		wpa_hexdump_ascii(MSG_DEBUG, "TLS: Certificate dNSName",
2017281806Srpaulo				  gen->d.dNSName->data,
2018281806Srpaulo				  gen->d.dNSName->length);
2019281806Srpaulo		if (domain_suffix_match(gen->d.dNSName->data,
2020346981Scy					gen->d.dNSName->length,
2021346981Scy					match, match_len, full) == 1) {
2022281806Srpaulo			wpa_printf(MSG_DEBUG, "TLS: %s in dNSName found",
2023281806Srpaulo				   full ? "Match" : "Suffix match");
2024337817Scy			sk_GENERAL_NAME_pop_free(ext, GENERAL_NAME_free);
2025281806Srpaulo			return 1;
2026281806Srpaulo		}
2027281806Srpaulo	}
2028337817Scy	sk_GENERAL_NAME_pop_free(ext, GENERAL_NAME_free);
2029281806Srpaulo
2030281806Srpaulo	if (dns_name) {
2031281806Srpaulo		wpa_printf(MSG_DEBUG, "TLS: None of the dNSName(s) matched");
2032281806Srpaulo		return 0;
2033281806Srpaulo	}
2034281806Srpaulo
2035281806Srpaulo	name = X509_get_subject_name(cert);
2036281806Srpaulo	i = -1;
2037281806Srpaulo	for (;;) {
2038281806Srpaulo		X509_NAME_ENTRY *e;
2039281806Srpaulo		ASN1_STRING *cn;
2040281806Srpaulo
2041281806Srpaulo		i = X509_NAME_get_index_by_NID(name, NID_commonName, i);
2042281806Srpaulo		if (i == -1)
2043281806Srpaulo			break;
2044281806Srpaulo		e = X509_NAME_get_entry(name, i);
2045281806Srpaulo		if (e == NULL)
2046281806Srpaulo			continue;
2047281806Srpaulo		cn = X509_NAME_ENTRY_get_data(e);
2048281806Srpaulo		if (cn == NULL)
2049281806Srpaulo			continue;
2050281806Srpaulo		wpa_hexdump_ascii(MSG_DEBUG, "TLS: Certificate commonName",
2051281806Srpaulo				  cn->data, cn->length);
2052346981Scy		if (domain_suffix_match(cn->data, cn->length,
2053346981Scy					match, match_len, full) == 1) {
2054281806Srpaulo			wpa_printf(MSG_DEBUG, "TLS: %s in commonName found",
2055281806Srpaulo				   full ? "Match" : "Suffix match");
2056281806Srpaulo			return 1;
2057281806Srpaulo		}
2058281806Srpaulo	}
2059281806Srpaulo
2060281806Srpaulo	wpa_printf(MSG_DEBUG, "TLS: No CommonName %smatch found",
2061281806Srpaulo		   full ? "": "suffix ");
2062281806Srpaulo	return 0;
2063346981Scy}
2064281806Srpaulo#endif /* CONFIG_NATIVE_WINDOWS */
2065346981Scy
2066346981Scy
2067346981Scystatic int tls_match_suffix(X509 *cert, const char *match, int full)
2068346981Scy{
2069346981Scy#ifdef CONFIG_NATIVE_WINDOWS
2070346981Scy	/* wincrypt.h has conflicting X509_NAME definition */
2071346981Scy	return -1;
2072346981Scy#else /* CONFIG_NATIVE_WINDOWS */
2073346981Scy	const char *token, *last = NULL;
2074346981Scy
2075346981Scy	/* Process each match alternative separately until a match is found */
2076346981Scy	while ((token = cstr_token(match, ";", &last))) {
2077346981Scy		if (tls_match_suffix_helper(cert, token, last - token, full))
2078346981Scy			return 1;
2079346981Scy	}
2080346981Scy
2081346981Scy	return 0;
2082346981Scy#endif /* CONFIG_NATIVE_WINDOWS */
2083281806Srpaulo}
2084281806Srpaulo
2085281806Srpaulo
2086214734Srpaulostatic enum tls_fail_reason openssl_tls_fail_reason(int err)
2087214734Srpaulo{
2088214734Srpaulo	switch (err) {
2089214734Srpaulo	case X509_V_ERR_CERT_REVOKED:
2090214734Srpaulo		return TLS_FAIL_REVOKED;
2091214734Srpaulo	case X509_V_ERR_CERT_NOT_YET_VALID:
2092214734Srpaulo	case X509_V_ERR_CRL_NOT_YET_VALID:
2093214734Srpaulo		return TLS_FAIL_NOT_YET_VALID;
2094214734Srpaulo	case X509_V_ERR_CERT_HAS_EXPIRED:
2095214734Srpaulo	case X509_V_ERR_CRL_HAS_EXPIRED:
2096214734Srpaulo		return TLS_FAIL_EXPIRED;
2097214734Srpaulo	case X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT:
2098214734Srpaulo	case X509_V_ERR_UNABLE_TO_GET_CRL:
2099214734Srpaulo	case X509_V_ERR_UNABLE_TO_GET_CRL_ISSUER:
2100214734Srpaulo	case X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN:
2101214734Srpaulo	case X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY:
2102214734Srpaulo	case X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT:
2103214734Srpaulo	case X509_V_ERR_UNABLE_TO_VERIFY_LEAF_SIGNATURE:
2104214734Srpaulo	case X509_V_ERR_CERT_CHAIN_TOO_LONG:
2105214734Srpaulo	case X509_V_ERR_PATH_LENGTH_EXCEEDED:
2106214734Srpaulo	case X509_V_ERR_INVALID_CA:
2107214734Srpaulo		return TLS_FAIL_UNTRUSTED;
2108214734Srpaulo	case X509_V_ERR_UNABLE_TO_DECRYPT_CERT_SIGNATURE:
2109214734Srpaulo	case X509_V_ERR_UNABLE_TO_DECRYPT_CRL_SIGNATURE:
2110214734Srpaulo	case X509_V_ERR_UNABLE_TO_DECODE_ISSUER_PUBLIC_KEY:
2111214734Srpaulo	case X509_V_ERR_ERROR_IN_CERT_NOT_BEFORE_FIELD:
2112214734Srpaulo	case X509_V_ERR_ERROR_IN_CERT_NOT_AFTER_FIELD:
2113214734Srpaulo	case X509_V_ERR_ERROR_IN_CRL_LAST_UPDATE_FIELD:
2114214734Srpaulo	case X509_V_ERR_ERROR_IN_CRL_NEXT_UPDATE_FIELD:
2115214734Srpaulo	case X509_V_ERR_CERT_UNTRUSTED:
2116214734Srpaulo	case X509_V_ERR_CERT_REJECTED:
2117214734Srpaulo		return TLS_FAIL_BAD_CERTIFICATE;
2118214734Srpaulo	default:
2119214734Srpaulo		return TLS_FAIL_UNSPECIFIED;
2120214734Srpaulo	}
2121214734Srpaulo}
2122214734Srpaulo
2123214734Srpaulo
2124214734Srpaulostatic struct wpabuf * get_x509_cert(X509 *cert)
2125214734Srpaulo{
2126214734Srpaulo	struct wpabuf *buf;
2127214734Srpaulo	u8 *tmp;
2128214734Srpaulo
2129214734Srpaulo	int cert_len = i2d_X509(cert, NULL);
2130214734Srpaulo	if (cert_len <= 0)
2131214734Srpaulo		return NULL;
2132214734Srpaulo
2133214734Srpaulo	buf = wpabuf_alloc(cert_len);
2134214734Srpaulo	if (buf == NULL)
2135214734Srpaulo		return NULL;
2136214734Srpaulo
2137214734Srpaulo	tmp = wpabuf_put(buf, cert_len);
2138214734Srpaulo	i2d_X509(cert, &tmp);
2139214734Srpaulo	return buf;
2140214734Srpaulo}
2141214734Srpaulo
2142214734Srpaulo
2143214734Srpaulostatic void openssl_tls_fail_event(struct tls_connection *conn,
2144214734Srpaulo				   X509 *err_cert, int err, int depth,
2145214734Srpaulo				   const char *subject, const char *err_str,
2146214734Srpaulo				   enum tls_fail_reason reason)
2147214734Srpaulo{
2148214734Srpaulo	union tls_event_data ev;
2149214734Srpaulo	struct wpabuf *cert = NULL;
2150281806Srpaulo	struct tls_context *context = conn->context;
2151214734Srpaulo
2152281806Srpaulo	if (context->event_cb == NULL)
2153214734Srpaulo		return;
2154214734Srpaulo
2155214734Srpaulo	cert = get_x509_cert(err_cert);
2156214734Srpaulo	os_memset(&ev, 0, sizeof(ev));
2157214734Srpaulo	ev.cert_fail.reason = reason != TLS_FAIL_UNSPECIFIED ?
2158214734Srpaulo		reason : openssl_tls_fail_reason(err);
2159214734Srpaulo	ev.cert_fail.depth = depth;
2160214734Srpaulo	ev.cert_fail.subject = subject;
2161214734Srpaulo	ev.cert_fail.reason_txt = err_str;
2162214734Srpaulo	ev.cert_fail.cert = cert;
2163281806Srpaulo	context->event_cb(context->cb_ctx, TLS_CERT_CHAIN_FAILURE, &ev);
2164214734Srpaulo	wpabuf_free(cert);
2165214734Srpaulo}
2166214734Srpaulo
2167214734Srpaulo
2168351611Scystatic int openssl_cert_tod(X509 *cert)
2169351611Scy{
2170351611Scy	CERTIFICATEPOLICIES *ext;
2171351611Scy	stack_index_t i;
2172351611Scy	char buf[100];
2173351611Scy	int res;
2174351611Scy	int tod = 0;
2175351611Scy
2176351611Scy	ext = X509_get_ext_d2i(cert, NID_certificate_policies, NULL, NULL);
2177351611Scy	if (!ext)
2178351611Scy		return 0;
2179351611Scy
2180351611Scy	for (i = 0; i < sk_POLICYINFO_num(ext); i++) {
2181351611Scy		POLICYINFO *policy;
2182351611Scy
2183351611Scy		policy = sk_POLICYINFO_value(ext, i);
2184351611Scy		res = OBJ_obj2txt(buf, sizeof(buf), policy->policyid, 0);
2185351611Scy		if (res < 0 || (size_t) res >= sizeof(buf))
2186351611Scy			continue;
2187351611Scy		wpa_printf(MSG_DEBUG, "OpenSSL: Certificate Policy %s", buf);
2188351611Scy		if (os_strcmp(buf, "1.3.6.1.4.1.40808.1.3.1") == 0)
2189351611Scy			tod = 1;
2190351611Scy	}
2191351611Scy
2192351611Scy	return tod;
2193351611Scy}
2194351611Scy
2195351611Scy
2196214734Srpaulostatic void openssl_tls_cert_event(struct tls_connection *conn,
2197214734Srpaulo				   X509 *err_cert, int depth,
2198214734Srpaulo				   const char *subject)
2199214734Srpaulo{
2200214734Srpaulo	struct wpabuf *cert = NULL;
2201214734Srpaulo	union tls_event_data ev;
2202281806Srpaulo	struct tls_context *context = conn->context;
2203281806Srpaulo	char *altsubject[TLS_MAX_ALT_SUBJECT];
2204281806Srpaulo	int alt, num_altsubject = 0;
2205281806Srpaulo	GENERAL_NAME *gen;
2206281806Srpaulo	void *ext;
2207281806Srpaulo	stack_index_t i;
2208346981Scy	ASN1_INTEGER *ser;
2209346981Scy	char serial_num[128];
2210214734Srpaulo#ifdef CONFIG_SHA256
2211214734Srpaulo	u8 hash[32];
2212214734Srpaulo#endif /* CONFIG_SHA256 */
2213214734Srpaulo
2214281806Srpaulo	if (context->event_cb == NULL)
2215214734Srpaulo		return;
2216214734Srpaulo
2217214734Srpaulo	os_memset(&ev, 0, sizeof(ev));
2218337817Scy	if (conn->cert_probe || (conn->flags & TLS_CONN_EXT_CERT_CHECK) ||
2219337817Scy	    context->cert_in_cb) {
2220214734Srpaulo		cert = get_x509_cert(err_cert);
2221214734Srpaulo		ev.peer_cert.cert = cert;
2222214734Srpaulo	}
2223214734Srpaulo#ifdef CONFIG_SHA256
2224214734Srpaulo	if (cert) {
2225214734Srpaulo		const u8 *addr[1];
2226214734Srpaulo		size_t len[1];
2227214734Srpaulo		addr[0] = wpabuf_head(cert);
2228214734Srpaulo		len[0] = wpabuf_len(cert);
2229214734Srpaulo		if (sha256_vector(1, addr, len, hash) == 0) {
2230214734Srpaulo			ev.peer_cert.hash = hash;
2231214734Srpaulo			ev.peer_cert.hash_len = sizeof(hash);
2232214734Srpaulo		}
2233214734Srpaulo	}
2234214734Srpaulo#endif /* CONFIG_SHA256 */
2235214734Srpaulo	ev.peer_cert.depth = depth;
2236214734Srpaulo	ev.peer_cert.subject = subject;
2237281806Srpaulo
2238346981Scy	ser = X509_get_serialNumber(err_cert);
2239346981Scy	if (ser) {
2240346981Scy		wpa_snprintf_hex_uppercase(serial_num, sizeof(serial_num),
2241346981Scy					   ASN1_STRING_get0_data(ser),
2242346981Scy					   ASN1_STRING_length(ser));
2243346981Scy		ev.peer_cert.serial_num = serial_num;
2244346981Scy	}
2245346981Scy
2246281806Srpaulo	ext = X509_get_ext_d2i(err_cert, NID_subject_alt_name, NULL, NULL);
2247281806Srpaulo	for (i = 0; ext && i < sk_GENERAL_NAME_num(ext); i++) {
2248281806Srpaulo		char *pos;
2249281806Srpaulo
2250281806Srpaulo		if (num_altsubject == TLS_MAX_ALT_SUBJECT)
2251281806Srpaulo			break;
2252281806Srpaulo		gen = sk_GENERAL_NAME_value(ext, i);
2253281806Srpaulo		if (gen->type != GEN_EMAIL &&
2254281806Srpaulo		    gen->type != GEN_DNS &&
2255281806Srpaulo		    gen->type != GEN_URI)
2256281806Srpaulo			continue;
2257281806Srpaulo
2258281806Srpaulo		pos = os_malloc(10 + gen->d.ia5->length + 1);
2259281806Srpaulo		if (pos == NULL)
2260281806Srpaulo			break;
2261281806Srpaulo		altsubject[num_altsubject++] = pos;
2262281806Srpaulo
2263281806Srpaulo		switch (gen->type) {
2264281806Srpaulo		case GEN_EMAIL:
2265281806Srpaulo			os_memcpy(pos, "EMAIL:", 6);
2266281806Srpaulo			pos += 6;
2267281806Srpaulo			break;
2268281806Srpaulo		case GEN_DNS:
2269281806Srpaulo			os_memcpy(pos, "DNS:", 4);
2270281806Srpaulo			pos += 4;
2271281806Srpaulo			break;
2272281806Srpaulo		case GEN_URI:
2273281806Srpaulo			os_memcpy(pos, "URI:", 4);
2274281806Srpaulo			pos += 4;
2275281806Srpaulo			break;
2276281806Srpaulo		}
2277281806Srpaulo
2278281806Srpaulo		os_memcpy(pos, gen->d.ia5->data, gen->d.ia5->length);
2279281806Srpaulo		pos += gen->d.ia5->length;
2280281806Srpaulo		*pos = '\0';
2281281806Srpaulo	}
2282337817Scy	sk_GENERAL_NAME_pop_free(ext, GENERAL_NAME_free);
2283281806Srpaulo
2284281806Srpaulo	for (alt = 0; alt < num_altsubject; alt++)
2285281806Srpaulo		ev.peer_cert.altsubject[alt] = altsubject[alt];
2286281806Srpaulo	ev.peer_cert.num_altsubject = num_altsubject;
2287281806Srpaulo
2288351611Scy	ev.peer_cert.tod = openssl_cert_tod(err_cert);
2289351611Scy
2290281806Srpaulo	context->event_cb(context->cb_ctx, TLS_PEER_CERTIFICATE, &ev);
2291214734Srpaulo	wpabuf_free(cert);
2292281806Srpaulo	for (alt = 0; alt < num_altsubject; alt++)
2293281806Srpaulo		os_free(altsubject[alt]);
2294214734Srpaulo}
2295214734Srpaulo
2296214734Srpaulo
2297189251Ssamstatic int tls_verify_cb(int preverify_ok, X509_STORE_CTX *x509_ctx)
2298189251Ssam{
2299189251Ssam	char buf[256];
2300189251Ssam	X509 *err_cert;
2301189251Ssam	int err, depth;
2302189251Ssam	SSL *ssl;
2303189251Ssam	struct tls_connection *conn;
2304281806Srpaulo	struct tls_context *context;
2305281806Srpaulo	char *match, *altmatch, *suffix_match, *domain_match;
2306346981Scy	const char *check_cert_subject;
2307214734Srpaulo	const char *err_str;
2308189251Ssam
2309189251Ssam	err_cert = X509_STORE_CTX_get_current_cert(x509_ctx);
2310281806Srpaulo	if (!err_cert)
2311281806Srpaulo		return 0;
2312281806Srpaulo
2313189251Ssam	err = X509_STORE_CTX_get_error(x509_ctx);
2314189251Ssam	depth = X509_STORE_CTX_get_error_depth(x509_ctx);
2315189251Ssam	ssl = X509_STORE_CTX_get_ex_data(x509_ctx,
2316189251Ssam					 SSL_get_ex_data_X509_STORE_CTX_idx());
2317189251Ssam	X509_NAME_oneline(X509_get_subject_name(err_cert), buf, sizeof(buf));
2318189251Ssam
2319189251Ssam	conn = SSL_get_app_data(ssl);
2320252726Srpaulo	if (conn == NULL)
2321252726Srpaulo		return 0;
2322281806Srpaulo
2323281806Srpaulo	if (depth == 0)
2324281806Srpaulo		conn->peer_cert = err_cert;
2325281806Srpaulo	else if (depth == 1)
2326281806Srpaulo		conn->peer_issuer = err_cert;
2327281806Srpaulo	else if (depth == 2)
2328281806Srpaulo		conn->peer_issuer_issuer = err_cert;
2329281806Srpaulo
2330281806Srpaulo	context = conn->context;
2331252726Srpaulo	match = conn->subject_match;
2332252726Srpaulo	altmatch = conn->altsubject_match;
2333281806Srpaulo	suffix_match = conn->suffix_match;
2334281806Srpaulo	domain_match = conn->domain_match;
2335189251Ssam
2336214734Srpaulo	if (!preverify_ok && !conn->ca_cert_verify)
2337214734Srpaulo		preverify_ok = 1;
2338214734Srpaulo	if (!preverify_ok && depth > 0 && conn->server_cert_only)
2339214734Srpaulo		preverify_ok = 1;
2340252726Srpaulo	if (!preverify_ok && (conn->flags & TLS_CONN_DISABLE_TIME_CHECKS) &&
2341252726Srpaulo	    (err == X509_V_ERR_CERT_HAS_EXPIRED ||
2342252726Srpaulo	     err == X509_V_ERR_CERT_NOT_YET_VALID)) {
2343252726Srpaulo		wpa_printf(MSG_DEBUG, "OpenSSL: Ignore certificate validity "
2344252726Srpaulo			   "time mismatch");
2345252726Srpaulo		preverify_ok = 1;
2346252726Srpaulo	}
2347346981Scy	if (!preverify_ok && !conn->data->check_crl_strict &&
2348346981Scy	    (err == X509_V_ERR_CRL_HAS_EXPIRED ||
2349346981Scy	     err == X509_V_ERR_CRL_NOT_YET_VALID)) {
2350346981Scy		wpa_printf(MSG_DEBUG,
2351346981Scy			   "OpenSSL: Ignore certificate validity CRL time mismatch");
2352346981Scy		preverify_ok = 1;
2353346981Scy	}
2354214734Srpaulo
2355214734Srpaulo	err_str = X509_verify_cert_error_string(err);
2356214734Srpaulo
2357214734Srpaulo#ifdef CONFIG_SHA256
2358281806Srpaulo	/*
2359281806Srpaulo	 * Do not require preverify_ok so we can explicity allow otherwise
2360281806Srpaulo	 * invalid pinned server certificates.
2361281806Srpaulo	 */
2362281806Srpaulo	if (depth == 0 && conn->server_cert_only) {
2363214734Srpaulo		struct wpabuf *cert;
2364214734Srpaulo		cert = get_x509_cert(err_cert);
2365214734Srpaulo		if (!cert) {
2366214734Srpaulo			wpa_printf(MSG_DEBUG, "OpenSSL: Could not fetch "
2367214734Srpaulo				   "server certificate data");
2368189251Ssam			preverify_ok = 0;
2369214734Srpaulo		} else {
2370214734Srpaulo			u8 hash[32];
2371214734Srpaulo			const u8 *addr[1];
2372214734Srpaulo			size_t len[1];
2373214734Srpaulo			addr[0] = wpabuf_head(cert);
2374214734Srpaulo			len[0] = wpabuf_len(cert);
2375214734Srpaulo			if (sha256_vector(1, addr, len, hash) < 0 ||
2376214734Srpaulo			    os_memcmp(conn->srv_cert_hash, hash, 32) != 0) {
2377214734Srpaulo				err_str = "Server certificate mismatch";
2378214734Srpaulo				err = X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN;
2379214734Srpaulo				preverify_ok = 0;
2380281806Srpaulo			} else if (!preverify_ok) {
2381281806Srpaulo				/*
2382281806Srpaulo				 * Certificate matches pinned certificate, allow
2383281806Srpaulo				 * regardless of other problems.
2384281806Srpaulo				 */
2385281806Srpaulo				wpa_printf(MSG_DEBUG,
2386281806Srpaulo					   "OpenSSL: Ignore validation issues for a pinned server certificate");
2387281806Srpaulo				preverify_ok = 1;
2388214734Srpaulo			}
2389214734Srpaulo			wpabuf_free(cert);
2390189251Ssam		}
2391189251Ssam	}
2392214734Srpaulo#endif /* CONFIG_SHA256 */
2393189251Ssam
2394351611Scy	openssl_tls_cert_event(conn, err_cert, depth, buf);
2395351611Scy
2396214734Srpaulo	if (!preverify_ok) {
2397351611Scy		if (depth > 0) {
2398351611Scy			/* Send cert event for the peer certificate so that
2399351611Scy			 * the upper layers get information about it even if
2400351611Scy			 * validation of a CA certificate fails. */
2401351611Scy			STACK_OF(X509) *chain;
2402351611Scy
2403351611Scy			chain = X509_STORE_CTX_get1_chain(x509_ctx);
2404351611Scy			if (chain && sk_X509_num(chain) > 0) {
2405351611Scy				char buf2[256];
2406351611Scy				X509 *cert;
2407351611Scy
2408351611Scy				cert = sk_X509_value(chain, 0);
2409351611Scy				X509_NAME_oneline(X509_get_subject_name(cert),
2410351611Scy						  buf2, sizeof(buf2));
2411351611Scy
2412351611Scy				openssl_tls_cert_event(conn, cert, 0, buf2);
2413351611Scy			}
2414351611Scy			if (chain)
2415351611Scy				sk_X509_pop_free(chain, X509_free);
2416351611Scy		}
2417351611Scy
2418214734Srpaulo		wpa_printf(MSG_WARNING, "TLS: Certificate verification failed,"
2419214734Srpaulo			   " error %d (%s) depth %d for '%s'", err, err_str,
2420214734Srpaulo			   depth, buf);
2421214734Srpaulo		openssl_tls_fail_event(conn, err_cert, err, depth, buf,
2422214734Srpaulo				       err_str, TLS_FAIL_UNSPECIFIED);
2423214734Srpaulo		return preverify_ok;
2424214734Srpaulo	}
2425214734Srpaulo
2426214734Srpaulo	wpa_printf(MSG_DEBUG, "TLS: tls_verify_cb - preverify_ok=%d "
2427214734Srpaulo		   "err=%d (%s) ca_cert_verify=%d depth=%d buf='%s'",
2428214734Srpaulo		   preverify_ok, err, err_str,
2429214734Srpaulo		   conn->ca_cert_verify, depth, buf);
2430346981Scy	check_cert_subject = conn->check_cert_subject;
2431346981Scy	if (!check_cert_subject)
2432346981Scy		check_cert_subject = conn->data->check_cert_subject;
2433346981Scy	if (check_cert_subject) {
2434346981Scy		if (depth == 0 &&
2435346981Scy		    !tls_match_dn_field(err_cert, check_cert_subject)) {
2436346981Scy			preverify_ok = 0;
2437346981Scy			openssl_tls_fail_event(conn, err_cert, err, depth, buf,
2438346981Scy					       "Distinguished Name",
2439346981Scy					       TLS_FAIL_DN_MISMATCH);
2440346981Scy		}
2441346981Scy	}
2442214734Srpaulo	if (depth == 0 && match && os_strstr(buf, match) == NULL) {
2443214734Srpaulo		wpa_printf(MSG_WARNING, "TLS: Subject '%s' did not "
2444214734Srpaulo			   "match with '%s'", buf, match);
2445214734Srpaulo		preverify_ok = 0;
2446214734Srpaulo		openssl_tls_fail_event(conn, err_cert, err, depth, buf,
2447214734Srpaulo				       "Subject mismatch",
2448214734Srpaulo				       TLS_FAIL_SUBJECT_MISMATCH);
2449214734Srpaulo	} else if (depth == 0 && altmatch &&
2450214734Srpaulo		   !tls_match_altsubject(err_cert, altmatch)) {
2451214734Srpaulo		wpa_printf(MSG_WARNING, "TLS: altSubjectName match "
2452214734Srpaulo			   "'%s' not found", altmatch);
2453214734Srpaulo		preverify_ok = 0;
2454214734Srpaulo		openssl_tls_fail_event(conn, err_cert, err, depth, buf,
2455214734Srpaulo				       "AltSubject mismatch",
2456214734Srpaulo				       TLS_FAIL_ALTSUBJECT_MISMATCH);
2457281806Srpaulo	} else if (depth == 0 && suffix_match &&
2458281806Srpaulo		   !tls_match_suffix(err_cert, suffix_match, 0)) {
2459281806Srpaulo		wpa_printf(MSG_WARNING, "TLS: Domain suffix match '%s' not found",
2460281806Srpaulo			   suffix_match);
2461281806Srpaulo		preverify_ok = 0;
2462281806Srpaulo		openssl_tls_fail_event(conn, err_cert, err, depth, buf,
2463281806Srpaulo				       "Domain suffix mismatch",
2464281806Srpaulo				       TLS_FAIL_DOMAIN_SUFFIX_MISMATCH);
2465281806Srpaulo	} else if (depth == 0 && domain_match &&
2466281806Srpaulo		   !tls_match_suffix(err_cert, domain_match, 1)) {
2467281806Srpaulo		wpa_printf(MSG_WARNING, "TLS: Domain match '%s' not found",
2468281806Srpaulo			   domain_match);
2469281806Srpaulo		preverify_ok = 0;
2470281806Srpaulo		openssl_tls_fail_event(conn, err_cert, err, depth, buf,
2471281806Srpaulo				       "Domain mismatch",
2472281806Srpaulo				       TLS_FAIL_DOMAIN_MISMATCH);
2473351611Scy	}
2474214734Srpaulo
2475214734Srpaulo	if (conn->cert_probe && preverify_ok && depth == 0) {
2476214734Srpaulo		wpa_printf(MSG_DEBUG, "OpenSSL: Reject server certificate "
2477214734Srpaulo			   "on probe-only run");
2478214734Srpaulo		preverify_ok = 0;
2479214734Srpaulo		openssl_tls_fail_event(conn, err_cert, err, depth, buf,
2480214734Srpaulo				       "Server certificate chain probe",
2481214734Srpaulo				       TLS_FAIL_SERVER_CHAIN_PROBE);
2482214734Srpaulo	}
2483214734Srpaulo
2484346981Scy#ifdef CONFIG_SUITEB
2485346981Scy	if (conn->flags & TLS_CONN_SUITEB) {
2486346981Scy		EVP_PKEY *pk;
2487346981Scy		RSA *rsa;
2488346981Scy		int len = -1;
2489346981Scy
2490346981Scy		pk = X509_get_pubkey(err_cert);
2491346981Scy		if (pk) {
2492346981Scy			rsa = EVP_PKEY_get1_RSA(pk);
2493346981Scy			if (rsa) {
2494346981Scy				len = RSA_bits(rsa);
2495346981Scy				RSA_free(rsa);
2496346981Scy			}
2497346981Scy			EVP_PKEY_free(pk);
2498346981Scy		}
2499346981Scy
2500346981Scy		if (len >= 0) {
2501346981Scy			wpa_printf(MSG_DEBUG,
2502346981Scy				   "OpenSSL: RSA modulus size: %d bits", len);
2503346981Scy			if (len < 3072) {
2504346981Scy				preverify_ok = 0;
2505346981Scy				openssl_tls_fail_event(
2506346981Scy					conn, err_cert, err,
2507346981Scy					depth, buf,
2508346981Scy					"Insufficient RSA modulus size",
2509346981Scy					TLS_FAIL_INSUFFICIENT_KEY_LEN);
2510346981Scy			}
2511346981Scy		}
2512346981Scy	}
2513346981Scy#endif /* CONFIG_SUITEB */
2514346981Scy
2515337817Scy#ifdef OPENSSL_IS_BORINGSSL
2516337817Scy	if (depth == 0 && (conn->flags & TLS_CONN_REQUEST_OCSP) &&
2517337817Scy	    preverify_ok) {
2518337817Scy		enum ocsp_result res;
2519337817Scy
2520337817Scy		res = check_ocsp_resp(conn->ssl_ctx, conn->ssl, err_cert,
2521337817Scy				      conn->peer_issuer,
2522337817Scy				      conn->peer_issuer_issuer);
2523337817Scy		if (res == OCSP_REVOKED) {
2524337817Scy			preverify_ok = 0;
2525337817Scy			openssl_tls_fail_event(conn, err_cert, err, depth, buf,
2526337817Scy					       "certificate revoked",
2527337817Scy					       TLS_FAIL_REVOKED);
2528337817Scy			if (err == X509_V_OK)
2529337817Scy				X509_STORE_CTX_set_error(
2530337817Scy					x509_ctx, X509_V_ERR_CERT_REVOKED);
2531337817Scy		} else if (res != OCSP_GOOD &&
2532337817Scy			   (conn->flags & TLS_CONN_REQUIRE_OCSP)) {
2533337817Scy			preverify_ok = 0;
2534337817Scy			openssl_tls_fail_event(conn, err_cert, err, depth, buf,
2535337817Scy					       "bad certificate status response",
2536337817Scy					       TLS_FAIL_UNSPECIFIED);
2537337817Scy		}
2538337817Scy	}
2539337817Scy#endif /* OPENSSL_IS_BORINGSSL */
2540337817Scy
2541337817Scy	if (depth == 0 && preverify_ok && context->event_cb != NULL)
2542281806Srpaulo		context->event_cb(context->cb_ctx,
2543281806Srpaulo				  TLS_CERT_CHAIN_SUCCESS, NULL);
2544252726Srpaulo
2545189251Ssam	return preverify_ok;
2546189251Ssam}
2547189251Ssam
2548189251Ssam
2549189251Ssam#ifndef OPENSSL_NO_STDIO
2550289549Srpaulostatic int tls_load_ca_der(struct tls_data *data, const char *ca_cert)
2551189251Ssam{
2552289549Srpaulo	SSL_CTX *ssl_ctx = data->ssl;
2553189251Ssam	X509_LOOKUP *lookup;
2554189251Ssam	int ret = 0;
2555189251Ssam
2556281806Srpaulo	lookup = X509_STORE_add_lookup(SSL_CTX_get_cert_store(ssl_ctx),
2557189251Ssam				       X509_LOOKUP_file());
2558189251Ssam	if (lookup == NULL) {
2559189251Ssam		tls_show_errors(MSG_WARNING, __func__,
2560189251Ssam				"Failed add lookup for X509 store");
2561189251Ssam		return -1;
2562189251Ssam	}
2563189251Ssam
2564189251Ssam	if (!X509_LOOKUP_load_file(lookup, ca_cert, X509_FILETYPE_ASN1)) {
2565189251Ssam		unsigned long err = ERR_peek_error();
2566189251Ssam		tls_show_errors(MSG_WARNING, __func__,
2567189251Ssam				"Failed load CA in DER format");
2568189251Ssam		if (ERR_GET_LIB(err) == ERR_LIB_X509 &&
2569189251Ssam		    ERR_GET_REASON(err) == X509_R_CERT_ALREADY_IN_HASH_TABLE) {
2570189251Ssam			wpa_printf(MSG_DEBUG, "OpenSSL: %s - ignoring "
2571189251Ssam				   "cert already in hash table error",
2572189251Ssam				   __func__);
2573189251Ssam		} else
2574189251Ssam			ret = -1;
2575189251Ssam	}
2576189251Ssam
2577189251Ssam	return ret;
2578189251Ssam}
2579189251Ssam#endif /* OPENSSL_NO_STDIO */
2580189251Ssam
2581189251Ssam
2582289549Srpaulostatic int tls_connection_ca_cert(struct tls_data *data,
2583289549Srpaulo				  struct tls_connection *conn,
2584189251Ssam				  const char *ca_cert, const u8 *ca_cert_blob,
2585189251Ssam				  size_t ca_cert_blob_len, const char *ca_path)
2586189251Ssam{
2587289549Srpaulo	SSL_CTX *ssl_ctx = data->ssl;
2588281806Srpaulo	X509_STORE *store;
2589189251Ssam
2590189251Ssam	/*
2591189251Ssam	 * Remove previously configured trusted CA certificates before adding
2592189251Ssam	 * new ones.
2593189251Ssam	 */
2594281806Srpaulo	store = X509_STORE_new();
2595281806Srpaulo	if (store == NULL) {
2596189251Ssam		wpa_printf(MSG_DEBUG, "OpenSSL: %s - failed to allocate new "
2597189251Ssam			   "certificate store", __func__);
2598189251Ssam		return -1;
2599189251Ssam	}
2600281806Srpaulo	SSL_CTX_set_cert_store(ssl_ctx, store);
2601189251Ssam
2602214734Srpaulo	SSL_set_verify(conn->ssl, SSL_VERIFY_PEER, tls_verify_cb);
2603214734Srpaulo	conn->ca_cert_verify = 1;
2604214734Srpaulo
2605214734Srpaulo	if (ca_cert && os_strncmp(ca_cert, "probe://", 8) == 0) {
2606214734Srpaulo		wpa_printf(MSG_DEBUG, "OpenSSL: Probe for server certificate "
2607214734Srpaulo			   "chain");
2608214734Srpaulo		conn->cert_probe = 1;
2609214734Srpaulo		conn->ca_cert_verify = 0;
2610214734Srpaulo		return 0;
2611214734Srpaulo	}
2612214734Srpaulo
2613214734Srpaulo	if (ca_cert && os_strncmp(ca_cert, "hash://", 7) == 0) {
2614214734Srpaulo#ifdef CONFIG_SHA256
2615214734Srpaulo		const char *pos = ca_cert + 7;
2616214734Srpaulo		if (os_strncmp(pos, "server/sha256/", 14) != 0) {
2617214734Srpaulo			wpa_printf(MSG_DEBUG, "OpenSSL: Unsupported ca_cert "
2618214734Srpaulo				   "hash value '%s'", ca_cert);
2619214734Srpaulo			return -1;
2620214734Srpaulo		}
2621214734Srpaulo		pos += 14;
2622214734Srpaulo		if (os_strlen(pos) != 32 * 2) {
2623214734Srpaulo			wpa_printf(MSG_DEBUG, "OpenSSL: Unexpected SHA256 "
2624214734Srpaulo				   "hash length in ca_cert '%s'", ca_cert);
2625214734Srpaulo			return -1;
2626214734Srpaulo		}
2627214734Srpaulo		if (hexstr2bin(pos, conn->srv_cert_hash, 32) < 0) {
2628214734Srpaulo			wpa_printf(MSG_DEBUG, "OpenSSL: Invalid SHA256 hash "
2629214734Srpaulo				   "value in ca_cert '%s'", ca_cert);
2630214734Srpaulo			return -1;
2631214734Srpaulo		}
2632214734Srpaulo		conn->server_cert_only = 1;
2633214734Srpaulo		wpa_printf(MSG_DEBUG, "OpenSSL: Checking only server "
2634214734Srpaulo			   "certificate match");
2635214734Srpaulo		return 0;
2636214734Srpaulo#else /* CONFIG_SHA256 */
2637214734Srpaulo		wpa_printf(MSG_INFO, "No SHA256 included in the build - "
2638214734Srpaulo			   "cannot validate server certificate hash");
2639214734Srpaulo		return -1;
2640214734Srpaulo#endif /* CONFIG_SHA256 */
2641214734Srpaulo	}
2642214734Srpaulo
2643189251Ssam	if (ca_cert_blob) {
2644281806Srpaulo		X509 *cert = d2i_X509(NULL,
2645281806Srpaulo				      (const unsigned char **) &ca_cert_blob,
2646189251Ssam				      ca_cert_blob_len);
2647189251Ssam		if (cert == NULL) {
2648351611Scy			BIO *bio = BIO_new_mem_buf(ca_cert_blob,
2649351611Scy						   ca_cert_blob_len);
2650351611Scy
2651351611Scy			if (bio) {
2652351611Scy				cert = PEM_read_bio_X509(bio, NULL, NULL, NULL);
2653351611Scy				BIO_free(bio);
2654351611Scy			}
2655351611Scy
2656351611Scy			if (!cert) {
2657351611Scy				tls_show_errors(MSG_WARNING, __func__,
2658351611Scy						"Failed to parse ca_cert_blob");
2659351611Scy				return -1;
2660351611Scy			}
2661351611Scy
2662351611Scy			while (ERR_get_error()) {
2663351611Scy				/* Ignore errors from DER conversion. */
2664351611Scy			}
2665189251Ssam		}
2666189251Ssam
2667281806Srpaulo		if (!X509_STORE_add_cert(SSL_CTX_get_cert_store(ssl_ctx),
2668281806Srpaulo					 cert)) {
2669189251Ssam			unsigned long err = ERR_peek_error();
2670189251Ssam			tls_show_errors(MSG_WARNING, __func__,
2671189251Ssam					"Failed to add ca_cert_blob to "
2672189251Ssam					"certificate store");
2673189251Ssam			if (ERR_GET_LIB(err) == ERR_LIB_X509 &&
2674189251Ssam			    ERR_GET_REASON(err) ==
2675189251Ssam			    X509_R_CERT_ALREADY_IN_HASH_TABLE) {
2676189251Ssam				wpa_printf(MSG_DEBUG, "OpenSSL: %s - ignoring "
2677189251Ssam					   "cert already in hash table error",
2678189251Ssam					   __func__);
2679189251Ssam			} else {
2680189251Ssam				X509_free(cert);
2681189251Ssam				return -1;
2682189251Ssam			}
2683189251Ssam		}
2684189251Ssam		X509_free(cert);
2685189251Ssam		wpa_printf(MSG_DEBUG, "OpenSSL: %s - added ca_cert_blob "
2686189251Ssam			   "to certificate store", __func__);
2687189251Ssam		return 0;
2688189251Ssam	}
2689189251Ssam
2690252726Srpaulo#ifdef ANDROID
2691337817Scy	/* Single alias */
2692252726Srpaulo	if (ca_cert && os_strncmp("keystore://", ca_cert, 11) == 0) {
2693337817Scy		if (tls_add_ca_from_keystore(SSL_CTX_get_cert_store(ssl_ctx),
2694337817Scy					     &ca_cert[11]) < 0)
2695337817Scy			return -1;
2696337817Scy		SSL_set_verify(conn->ssl, SSL_VERIFY_PEER, tls_verify_cb);
2697337817Scy		return 0;
2698337817Scy	}
2699252726Srpaulo
2700337817Scy	/* Multiple aliases separated by space */
2701337817Scy	if (ca_cert && os_strncmp("keystores://", ca_cert, 12) == 0) {
2702337817Scy		char *aliases = os_strdup(&ca_cert[12]);
2703337817Scy		const char *delim = " ";
2704337817Scy		int rc = 0;
2705337817Scy		char *savedptr;
2706337817Scy		char *alias;
2707337817Scy
2708337817Scy		if (!aliases)
2709252726Srpaulo			return -1;
2710337817Scy		alias = strtok_r(aliases, delim, &savedptr);
2711337817Scy		for (; alias; alias = strtok_r(NULL, delim, &savedptr)) {
2712337817Scy			if (tls_add_ca_from_keystore_encoded(
2713337817Scy				    SSL_CTX_get_cert_store(ssl_ctx), alias)) {
2714337817Scy				wpa_printf(MSG_WARNING,
2715337817Scy					   "OpenSSL: %s - Failed to add ca_cert %s from keystore",
2716337817Scy					   __func__, alias);
2717337817Scy				rc = -1;
2718337817Scy				break;
2719252726Srpaulo			}
2720252726Srpaulo		}
2721337817Scy		os_free(aliases);
2722337817Scy		if (rc)
2723337817Scy			return rc;
2724337817Scy
2725252726Srpaulo		SSL_set_verify(conn->ssl, SSL_VERIFY_PEER, tls_verify_cb);
2726252726Srpaulo		return 0;
2727252726Srpaulo	}
2728252726Srpaulo#endif /* ANDROID */
2729252726Srpaulo
2730189251Ssam#ifdef CONFIG_NATIVE_WINDOWS
2731189251Ssam	if (ca_cert && tls_cryptoapi_ca_cert(ssl_ctx, conn->ssl, ca_cert) ==
2732189251Ssam	    0) {
2733189251Ssam		wpa_printf(MSG_DEBUG, "OpenSSL: Added CA certificates from "
2734189251Ssam			   "system certificate store");
2735189251Ssam		return 0;
2736189251Ssam	}
2737189251Ssam#endif /* CONFIG_NATIVE_WINDOWS */
2738189251Ssam
2739189251Ssam	if (ca_cert || ca_path) {
2740189251Ssam#ifndef OPENSSL_NO_STDIO
2741189251Ssam		if (SSL_CTX_load_verify_locations(ssl_ctx, ca_cert, ca_path) !=
2742189251Ssam		    1) {
2743189251Ssam			tls_show_errors(MSG_WARNING, __func__,
2744189251Ssam					"Failed to load root certificates");
2745189251Ssam			if (ca_cert &&
2746289549Srpaulo			    tls_load_ca_der(data, ca_cert) == 0) {
2747189251Ssam				wpa_printf(MSG_DEBUG, "OpenSSL: %s - loaded "
2748189251Ssam					   "DER format CA certificate",
2749189251Ssam					   __func__);
2750189251Ssam			} else
2751189251Ssam				return -1;
2752189251Ssam		} else {
2753189251Ssam			wpa_printf(MSG_DEBUG, "TLS: Trusted root "
2754189251Ssam				   "certificate(s) loaded");
2755289549Srpaulo			tls_get_errors(data);
2756189251Ssam		}
2757189251Ssam#else /* OPENSSL_NO_STDIO */
2758189251Ssam		wpa_printf(MSG_DEBUG, "OpenSSL: %s - OPENSSL_NO_STDIO",
2759189251Ssam			   __func__);
2760189251Ssam		return -1;
2761189251Ssam#endif /* OPENSSL_NO_STDIO */
2762189251Ssam	} else {
2763189251Ssam		/* No ca_cert configured - do not try to verify server
2764189251Ssam		 * certificate */
2765214734Srpaulo		conn->ca_cert_verify = 0;
2766189251Ssam	}
2767189251Ssam
2768189251Ssam	return 0;
2769189251Ssam}
2770189251Ssam
2771189251Ssam
2772289549Srpaulostatic int tls_global_ca_cert(struct tls_data *data, const char *ca_cert)
2773189251Ssam{
2774289549Srpaulo	SSL_CTX *ssl_ctx = data->ssl;
2775289549Srpaulo
2776189251Ssam	if (ca_cert) {
2777189251Ssam		if (SSL_CTX_load_verify_locations(ssl_ctx, ca_cert, NULL) != 1)
2778189251Ssam		{
2779189251Ssam			tls_show_errors(MSG_WARNING, __func__,
2780189251Ssam					"Failed to load root certificates");
2781189251Ssam			return -1;
2782189251Ssam		}
2783189251Ssam
2784189251Ssam		wpa_printf(MSG_DEBUG, "TLS: Trusted root "
2785189251Ssam			   "certificate(s) loaded");
2786189251Ssam
2787189251Ssam#ifndef OPENSSL_NO_STDIO
2788189251Ssam		/* Add the same CAs to the client certificate requests */
2789189251Ssam		SSL_CTX_set_client_CA_list(ssl_ctx,
2790189251Ssam					   SSL_load_client_CA_file(ca_cert));
2791189251Ssam#endif /* OPENSSL_NO_STDIO */
2792346981Scy
2793346981Scy		os_free(data->ca_cert);
2794346981Scy		data->ca_cert = os_strdup(ca_cert);
2795189251Ssam	}
2796189251Ssam
2797189251Ssam	return 0;
2798189251Ssam}
2799189251Ssam
2800189251Ssam
2801346981Scyint tls_global_set_verify(void *ssl_ctx, int check_crl, int strict)
2802189251Ssam{
2803189251Ssam	int flags;
2804189251Ssam
2805189251Ssam	if (check_crl) {
2806289549Srpaulo		struct tls_data *data = ssl_ctx;
2807289549Srpaulo		X509_STORE *cs = SSL_CTX_get_cert_store(data->ssl);
2808189251Ssam		if (cs == NULL) {
2809189251Ssam			tls_show_errors(MSG_INFO, __func__, "Failed to get "
2810189251Ssam					"certificate store when enabling "
2811189251Ssam					"check_crl");
2812189251Ssam			return -1;
2813189251Ssam		}
2814189251Ssam		flags = X509_V_FLAG_CRL_CHECK;
2815189251Ssam		if (check_crl == 2)
2816189251Ssam			flags |= X509_V_FLAG_CRL_CHECK_ALL;
2817189251Ssam		X509_STORE_set_flags(cs, flags);
2818346981Scy
2819346981Scy		data->check_crl = check_crl;
2820346981Scy		data->check_crl_strict = strict;
2821346981Scy		os_get_reltime(&data->crl_last_reload);
2822189251Ssam	}
2823189251Ssam	return 0;
2824189251Ssam}
2825189251Ssam
2826189251Ssam
2827189251Ssamstatic int tls_connection_set_subject_match(struct tls_connection *conn,
2828189251Ssam					    const char *subject_match,
2829281806Srpaulo					    const char *altsubject_match,
2830281806Srpaulo					    const char *suffix_match,
2831346981Scy					    const char *domain_match,
2832346981Scy					    const char *check_cert_subject)
2833189251Ssam{
2834189251Ssam	os_free(conn->subject_match);
2835189251Ssam	conn->subject_match = NULL;
2836189251Ssam	if (subject_match) {
2837189251Ssam		conn->subject_match = os_strdup(subject_match);
2838189251Ssam		if (conn->subject_match == NULL)
2839189251Ssam			return -1;
2840189251Ssam	}
2841189251Ssam
2842189251Ssam	os_free(conn->altsubject_match);
2843189251Ssam	conn->altsubject_match = NULL;
2844189251Ssam	if (altsubject_match) {
2845189251Ssam		conn->altsubject_match = os_strdup(altsubject_match);
2846189251Ssam		if (conn->altsubject_match == NULL)
2847189251Ssam			return -1;
2848189251Ssam	}
2849189251Ssam
2850281806Srpaulo	os_free(conn->suffix_match);
2851281806Srpaulo	conn->suffix_match = NULL;
2852281806Srpaulo	if (suffix_match) {
2853281806Srpaulo		conn->suffix_match = os_strdup(suffix_match);
2854281806Srpaulo		if (conn->suffix_match == NULL)
2855281806Srpaulo			return -1;
2856281806Srpaulo	}
2857281806Srpaulo
2858281806Srpaulo	os_free(conn->domain_match);
2859281806Srpaulo	conn->domain_match = NULL;
2860281806Srpaulo	if (domain_match) {
2861281806Srpaulo		conn->domain_match = os_strdup(domain_match);
2862281806Srpaulo		if (conn->domain_match == NULL)
2863281806Srpaulo			return -1;
2864281806Srpaulo	}
2865281806Srpaulo
2866346981Scy	os_free(conn->check_cert_subject);
2867346981Scy	conn->check_cert_subject = NULL;
2868346981Scy	if (check_cert_subject) {
2869346981Scy		conn->check_cert_subject = os_strdup(check_cert_subject);
2870346981Scy		if (!conn->check_cert_subject)
2871346981Scy			return -1;
2872346981Scy	}
2873346981Scy
2874189251Ssam	return 0;
2875189251Ssam}
2876189251Ssam
2877189251Ssam
2878346981Scy#ifdef CONFIG_SUITEB
2879346981Scy#if OPENSSL_VERSION_NUMBER >= 0x10002000L
2880346981Scystatic int suiteb_cert_cb(SSL *ssl, void *arg)
2881289549Srpaulo{
2882346981Scy	struct tls_connection *conn = arg;
2883346981Scy
2884346981Scy	/*
2885346981Scy	 * This cert_cb() is not really the best location for doing a
2886346981Scy	 * constraint check for the ServerKeyExchange message, but this seems to
2887346981Scy	 * be the only place where the current OpenSSL sequence can be
2888346981Scy	 * terminated cleanly with an TLS alert going out to the server.
2889346981Scy	 */
2890346981Scy
2891346981Scy	if (!(conn->flags & TLS_CONN_SUITEB))
2892346981Scy		return 1;
2893346981Scy
2894346981Scy	/* DHE is enabled only with DHE-RSA-AES256-GCM-SHA384 */
2895346981Scy	if (conn->cipher_suite != 0x9f)
2896346981Scy		return 1;
2897346981Scy
2898346981Scy	if (conn->server_dh_prime_len >= 3072)
2899346981Scy		return 1;
2900346981Scy
2901346981Scy	wpa_printf(MSG_DEBUG,
2902346981Scy		   "OpenSSL: Server DH prime length (%d bits) not sufficient for Suite B RSA - reject handshake",
2903346981Scy		   conn->server_dh_prime_len);
2904346981Scy	return 0;
2905346981Scy}
2906346981Scy#endif /* OPENSSL_VERSION_NUMBER */
2907346981Scy#endif /* CONFIG_SUITEB */
2908346981Scy
2909346981Scy
2910346981Scystatic int tls_set_conn_flags(struct tls_connection *conn, unsigned int flags,
2911346981Scy			      const char *openssl_ciphers)
2912346981Scy{
2913346981Scy	SSL *ssl = conn->ssl;
2914346981Scy
2915289549Srpaulo#ifdef SSL_OP_NO_TICKET
2916289549Srpaulo	if (flags & TLS_CONN_DISABLE_SESSION_TICKET)
2917289549Srpaulo		SSL_set_options(ssl, SSL_OP_NO_TICKET);
2918289549Srpaulo	else
2919289549Srpaulo		SSL_clear_options(ssl, SSL_OP_NO_TICKET);
2920289549Srpaulo#endif /* SSL_OP_NO_TICKET */
2921289549Srpaulo
2922289549Srpaulo#ifdef SSL_OP_NO_TLSv1
2923289549Srpaulo	if (flags & TLS_CONN_DISABLE_TLSv1_0)
2924289549Srpaulo		SSL_set_options(ssl, SSL_OP_NO_TLSv1);
2925289549Srpaulo	else
2926289549Srpaulo		SSL_clear_options(ssl, SSL_OP_NO_TLSv1);
2927289549Srpaulo#endif /* SSL_OP_NO_TLSv1 */
2928289549Srpaulo#ifdef SSL_OP_NO_TLSv1_1
2929289549Srpaulo	if (flags & TLS_CONN_DISABLE_TLSv1_1)
2930289549Srpaulo		SSL_set_options(ssl, SSL_OP_NO_TLSv1_1);
2931289549Srpaulo	else
2932289549Srpaulo		SSL_clear_options(ssl, SSL_OP_NO_TLSv1_1);
2933289549Srpaulo#endif /* SSL_OP_NO_TLSv1_1 */
2934289549Srpaulo#ifdef SSL_OP_NO_TLSv1_2
2935289549Srpaulo	if (flags & TLS_CONN_DISABLE_TLSv1_2)
2936289549Srpaulo		SSL_set_options(ssl, SSL_OP_NO_TLSv1_2);
2937289549Srpaulo	else
2938289549Srpaulo		SSL_clear_options(ssl, SSL_OP_NO_TLSv1_2);
2939289549Srpaulo#endif /* SSL_OP_NO_TLSv1_2 */
2940346981Scy#ifdef SSL_OP_NO_TLSv1_3
2941346981Scy	if (flags & TLS_CONN_DISABLE_TLSv1_3)
2942346981Scy		SSL_set_options(ssl, SSL_OP_NO_TLSv1_3);
2943346981Scy	else
2944346981Scy		SSL_clear_options(ssl, SSL_OP_NO_TLSv1_3);
2945346981Scy#endif /* SSL_OP_NO_TLSv1_3 */
2946346981Scy#if OPENSSL_VERSION_NUMBER >= 0x10100000L
2947346981Scy	if (flags & (TLS_CONN_ENABLE_TLSv1_0 |
2948346981Scy		     TLS_CONN_ENABLE_TLSv1_1 |
2949346981Scy		     TLS_CONN_ENABLE_TLSv1_2)) {
2950346981Scy		int version = 0;
2951346981Scy
2952346981Scy		/* Explicit request to enable TLS versions even if needing to
2953346981Scy		 * override systemwide policies. */
2954346981Scy		if (flags & TLS_CONN_ENABLE_TLSv1_0) {
2955346981Scy			version = TLS1_VERSION;
2956346981Scy		} else if (flags & TLS_CONN_ENABLE_TLSv1_1) {
2957346981Scy			if (!(flags & TLS_CONN_DISABLE_TLSv1_0))
2958346981Scy				version = TLS1_1_VERSION;
2959346981Scy		} else if (flags & TLS_CONN_ENABLE_TLSv1_2) {
2960346981Scy			if (!(flags & (TLS_CONN_DISABLE_TLSv1_0 |
2961346981Scy				       TLS_CONN_DISABLE_TLSv1_1)))
2962346981Scy				version = TLS1_2_VERSION;
2963346981Scy		}
2964346981Scy		if (!version) {
2965346981Scy			wpa_printf(MSG_DEBUG,
2966346981Scy				   "OpenSSL: Invalid TLS version configuration");
2967346981Scy			return -1;
2968346981Scy		}
2969346981Scy
2970346981Scy		if (SSL_set_min_proto_version(ssl, version) != 1) {
2971346981Scy			wpa_printf(MSG_DEBUG,
2972346981Scy				   "OpenSSL: Failed to set minimum TLS version");
2973346981Scy			return -1;
2974346981Scy		}
2975346981Scy	}
2976346981Scy#endif /* >= 1.1.0 */
2977346981Scy
2978346981Scy#ifdef CONFIG_SUITEB
2979346981Scy#ifdef OPENSSL_IS_BORINGSSL
2980346981Scy	/* Start with defaults from BoringSSL */
2981346981Scy	SSL_CTX_set_verify_algorithm_prefs(conn->ssl_ctx, NULL, 0);
2982346981Scy#endif /* OPENSSL_IS_BORINGSSL */
2983346981Scy#if OPENSSL_VERSION_NUMBER >= 0x10002000L
2984346981Scy	if (flags & TLS_CONN_SUITEB_NO_ECDH) {
2985346981Scy		const char *ciphers = "DHE-RSA-AES256-GCM-SHA384";
2986346981Scy
2987346981Scy		if (openssl_ciphers) {
2988346981Scy			wpa_printf(MSG_DEBUG,
2989346981Scy				   "OpenSSL: Override ciphers for Suite B (no ECDH): %s",
2990346981Scy				   openssl_ciphers);
2991346981Scy			ciphers = openssl_ciphers;
2992346981Scy		}
2993346981Scy		if (SSL_set_cipher_list(ssl, ciphers) != 1) {
2994346981Scy			wpa_printf(MSG_INFO,
2995346981Scy				   "OpenSSL: Failed to set Suite B ciphers");
2996346981Scy			return -1;
2997346981Scy		}
2998346981Scy	} else if (flags & TLS_CONN_SUITEB) {
2999346981Scy		EC_KEY *ecdh;
3000346981Scy		const char *ciphers =
3001346981Scy			"ECDHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES256-GCM-SHA384";
3002346981Scy		int nid[1] = { NID_secp384r1 };
3003346981Scy
3004346981Scy		if (openssl_ciphers) {
3005346981Scy			wpa_printf(MSG_DEBUG,
3006346981Scy				   "OpenSSL: Override ciphers for Suite B: %s",
3007346981Scy				   openssl_ciphers);
3008346981Scy			ciphers = openssl_ciphers;
3009346981Scy		}
3010346981Scy		if (SSL_set_cipher_list(ssl, ciphers) != 1) {
3011346981Scy			wpa_printf(MSG_INFO,
3012346981Scy				   "OpenSSL: Failed to set Suite B ciphers");
3013346981Scy			return -1;
3014346981Scy		}
3015346981Scy
3016346981Scy		if (SSL_set1_curves(ssl, nid, 1) != 1) {
3017346981Scy			wpa_printf(MSG_INFO,
3018346981Scy				   "OpenSSL: Failed to set Suite B curves");
3019346981Scy			return -1;
3020346981Scy		}
3021346981Scy
3022346981Scy		ecdh = EC_KEY_new_by_curve_name(NID_secp384r1);
3023346981Scy		if (!ecdh || SSL_set_tmp_ecdh(ssl, ecdh) != 1) {
3024346981Scy			EC_KEY_free(ecdh);
3025346981Scy			wpa_printf(MSG_INFO,
3026346981Scy				   "OpenSSL: Failed to set ECDH parameter");
3027346981Scy			return -1;
3028346981Scy		}
3029346981Scy		EC_KEY_free(ecdh);
3030346981Scy	}
3031346981Scy	if (flags & (TLS_CONN_SUITEB | TLS_CONN_SUITEB_NO_ECDH)) {
3032346981Scy#ifdef OPENSSL_IS_BORINGSSL
3033346981Scy		uint16_t sigalgs[1] = { SSL_SIGN_RSA_PKCS1_SHA384 };
3034346981Scy
3035346981Scy		if (SSL_CTX_set_verify_algorithm_prefs(conn->ssl_ctx, sigalgs,
3036346981Scy						       1) != 1) {
3037346981Scy			wpa_printf(MSG_INFO,
3038346981Scy				   "OpenSSL: Failed to set Suite B sigalgs");
3039346981Scy			return -1;
3040346981Scy		}
3041346981Scy#else /* OPENSSL_IS_BORINGSSL */
3042346981Scy		/* ECDSA+SHA384 if need to add EC support here */
3043346981Scy		if (SSL_set1_sigalgs_list(ssl, "RSA+SHA384") != 1) {
3044346981Scy			wpa_printf(MSG_INFO,
3045346981Scy				   "OpenSSL: Failed to set Suite B sigalgs");
3046346981Scy			return -1;
3047346981Scy		}
3048346981Scy#endif /* OPENSSL_IS_BORINGSSL */
3049346981Scy
3050346981Scy		SSL_set_options(ssl, SSL_OP_NO_TLSv1);
3051346981Scy		SSL_set_options(ssl, SSL_OP_NO_TLSv1_1);
3052346981Scy		SSL_set_cert_cb(ssl, suiteb_cert_cb, conn);
3053346981Scy	}
3054346981Scy#else /* OPENSSL_VERSION_NUMBER < 0x10002000L */
3055346981Scy	if (flags & (TLS_CONN_SUITEB | TLS_CONN_SUITEB_NO_ECDH)) {
3056346981Scy		wpa_printf(MSG_ERROR,
3057346981Scy			   "OpenSSL: Suite B RSA case not supported with this OpenSSL version");
3058346981Scy		return -1;
3059346981Scy	}
3060346981Scy#endif /* OPENSSL_VERSION_NUMBER */
3061346981Scy
3062346981Scy#ifdef OPENSSL_IS_BORINGSSL
3063346981Scy	if (openssl_ciphers && os_strcmp(openssl_ciphers, "SUITEB192") == 0) {
3064346981Scy		uint16_t sigalgs[1] = { SSL_SIGN_ECDSA_SECP384R1_SHA384 };
3065346981Scy		int nid[1] = { NID_secp384r1 };
3066346981Scy
3067346981Scy		if (SSL_set1_curves(ssl, nid, 1) != 1) {
3068346981Scy			wpa_printf(MSG_INFO,
3069346981Scy				   "OpenSSL: Failed to set Suite B curves");
3070346981Scy			return -1;
3071346981Scy		}
3072346981Scy
3073346981Scy		if (SSL_CTX_set_verify_algorithm_prefs(conn->ssl_ctx, sigalgs,
3074346981Scy						       1) != 1) {
3075346981Scy			wpa_printf(MSG_INFO,
3076346981Scy				   "OpenSSL: Failed to set Suite B sigalgs");
3077346981Scy			return -1;
3078346981Scy		}
3079346981Scy	}
3080346981Scy#else /* OPENSSL_IS_BORINGSSL */
3081346981Scy	if (!(flags & (TLS_CONN_SUITEB | TLS_CONN_SUITEB_NO_ECDH)) &&
3082346981Scy	    openssl_ciphers && SSL_set_cipher_list(ssl, openssl_ciphers) != 1) {
3083346981Scy		wpa_printf(MSG_INFO,
3084346981Scy			   "OpenSSL: Failed to set openssl_ciphers '%s'",
3085346981Scy			   openssl_ciphers);
3086346981Scy		return -1;
3087346981Scy	}
3088346981Scy#endif /* OPENSSL_IS_BORINGSSL */
3089346981Scy#else /* CONFIG_SUITEB */
3090346981Scy	if (openssl_ciphers && SSL_set_cipher_list(ssl, openssl_ciphers) != 1) {
3091346981Scy		wpa_printf(MSG_INFO,
3092346981Scy			   "OpenSSL: Failed to set openssl_ciphers '%s'",
3093346981Scy			   openssl_ciphers);
3094346981Scy		return -1;
3095346981Scy	}
3096346981Scy#endif /* CONFIG_SUITEB */
3097346981Scy
3098351611Scy	if (flags & TLS_CONN_TEAP_ANON_DH) {
3099351611Scy#ifndef TEAP_DH_ANON_CS
3100351611Scy#define TEAP_DH_ANON_CS \
3101351611Scy	"ECDHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES128-GCM-SHA256:" \
3102351611Scy	"ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES128-SHA256:" \
3103351611Scy	"ECDHE-RSA-AES256-SHA:ECDHE-RSA-AES128-SHA:" \
3104351611Scy	"DHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:" \
3105351611Scy	"DHE-RSA-AES256-SHA256:DHE-RSA-AES128-SHA256:" \
3106351611Scy	"DHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA:" \
3107351611Scy	"ADH-AES256-GCM-SHA384:ADH-AES128-GCM-SHA256:" \
3108351611Scy	"ADH-AES256-SHA256:ADH-AES128-SHA256:ADH-AES256-SHA:ADH-AES128-SHA"
3109351611Scy#endif
3110351611Scy		static const char *cs = TEAP_DH_ANON_CS;
3111351611Scy
3112351611Scy#if OPENSSL_VERSION_NUMBER >= 0x10100000L && \
3113351611Scy	!defined(LIBRESSL_VERSION_NUMBER) && \
3114351611Scy	!defined(OPENSSL_IS_BORINGSSL)
3115351611Scy		/*
3116351611Scy		 * Need to drop to security level 0 to allow anonymous
3117351611Scy		 * cipher suites for EAP-TEAP.
3118351611Scy		 */
3119351611Scy		SSL_set_security_level(conn->ssl, 0);
3120351611Scy#endif
3121351611Scy
3122351611Scy		wpa_printf(MSG_DEBUG,
3123351611Scy			   "OpenSSL: Enable cipher suites for anonymous EAP-TEAP provisioning: %s",
3124351611Scy			   cs);
3125351611Scy		if (SSL_set_cipher_list(conn->ssl, cs) != 1) {
3126351611Scy			tls_show_errors(MSG_INFO, __func__,
3127351611Scy					"Cipher suite configuration failed");
3128351611Scy			return -1;
3129351611Scy		}
3130351611Scy	}
3131351611Scy
3132346981Scy	return 0;
3133289549Srpaulo}
3134289549Srpaulo
3135289549Srpaulo
3136189251Ssamint tls_connection_set_verify(void *ssl_ctx, struct tls_connection *conn,
3137289549Srpaulo			      int verify_peer, unsigned int flags,
3138289549Srpaulo			      const u8 *session_ctx, size_t session_ctx_len)
3139189251Ssam{
3140189251Ssam	static int counter = 0;
3141289549Srpaulo	struct tls_data *data = ssl_ctx;
3142189251Ssam
3143189251Ssam	if (conn == NULL)
3144189251Ssam		return -1;
3145189251Ssam
3146189251Ssam	if (verify_peer) {
3147214734Srpaulo		conn->ca_cert_verify = 1;
3148189251Ssam		SSL_set_verify(conn->ssl, SSL_VERIFY_PEER |
3149189251Ssam			       SSL_VERIFY_FAIL_IF_NO_PEER_CERT |
3150189251Ssam			       SSL_VERIFY_CLIENT_ONCE, tls_verify_cb);
3151189251Ssam	} else {
3152214734Srpaulo		conn->ca_cert_verify = 0;
3153189251Ssam		SSL_set_verify(conn->ssl, SSL_VERIFY_NONE, NULL);
3154189251Ssam	}
3155189251Ssam
3156346981Scy	if (tls_set_conn_flags(conn, flags, NULL) < 0)
3157346981Scy		return -1;
3158289549Srpaulo	conn->flags = flags;
3159289549Srpaulo
3160189251Ssam	SSL_set_accept_state(conn->ssl);
3161189251Ssam
3162289549Srpaulo	if (data->tls_session_lifetime == 0) {
3163289549Srpaulo		/*
3164289549Srpaulo		 * Set session id context to a unique value to make sure
3165289549Srpaulo		 * session resumption cannot be used either through session
3166289549Srpaulo		 * caching or TLS ticket extension.
3167289549Srpaulo		 */
3168289549Srpaulo		counter++;
3169289549Srpaulo		SSL_set_session_id_context(conn->ssl,
3170289549Srpaulo					   (const unsigned char *) &counter,
3171289549Srpaulo					   sizeof(counter));
3172289549Srpaulo	} else if (session_ctx) {
3173289549Srpaulo		SSL_set_session_id_context(conn->ssl, session_ctx,
3174289549Srpaulo					   session_ctx_len);
3175289549Srpaulo	}
3176189251Ssam
3177189251Ssam	return 0;
3178189251Ssam}
3179189251Ssam
3180189251Ssam
3181189251Ssamstatic int tls_connection_client_cert(struct tls_connection *conn,
3182189251Ssam				      const char *client_cert,
3183189251Ssam				      const u8 *client_cert_blob,
3184189251Ssam				      size_t client_cert_blob_len)
3185189251Ssam{
3186189251Ssam	if (client_cert == NULL && client_cert_blob == NULL)
3187189251Ssam		return 0;
3188189251Ssam
3189337817Scy#ifdef PKCS12_FUNCS
3190346981Scy#if OPENSSL_VERSION_NUMBER < 0x10002000L || defined(LIBRESSL_VERSION_NUMBER)
3191337817Scy	/*
3192337817Scy	 * Clear previously set extra chain certificates, if any, from PKCS#12
3193337817Scy	 * processing in tls_parse_pkcs12() to allow OpenSSL to build a new
3194337817Scy	 * chain properly.
3195337817Scy	 */
3196337817Scy	SSL_CTX_clear_extra_chain_certs(conn->ssl_ctx);
3197337817Scy#endif /* OPENSSL_VERSION_NUMBER < 0x10002000L */
3198337817Scy#endif /* PKCS12_FUNCS */
3199337817Scy
3200189251Ssam	if (client_cert_blob &&
3201189251Ssam	    SSL_use_certificate_ASN1(conn->ssl, (u8 *) client_cert_blob,
3202189251Ssam				     client_cert_blob_len) == 1) {
3203189251Ssam		wpa_printf(MSG_DEBUG, "OpenSSL: SSL_use_certificate_ASN1 --> "
3204189251Ssam			   "OK");
3205189251Ssam		return 0;
3206189251Ssam	} else if (client_cert_blob) {
3207189251Ssam		tls_show_errors(MSG_DEBUG, __func__,
3208189251Ssam				"SSL_use_certificate_ASN1 failed");
3209189251Ssam	}
3210189251Ssam
3211189251Ssam	if (client_cert == NULL)
3212189251Ssam		return -1;
3213189251Ssam
3214252726Srpaulo#ifdef ANDROID
3215252726Srpaulo	if (os_strncmp("keystore://", client_cert, 11) == 0) {
3216252726Srpaulo		BIO *bio = BIO_from_keystore(&client_cert[11]);
3217252726Srpaulo		X509 *x509 = NULL;
3218252726Srpaulo		int ret = -1;
3219252726Srpaulo		if (bio) {
3220252726Srpaulo			x509 = PEM_read_bio_X509(bio, NULL, NULL, NULL);
3221252726Srpaulo		}
3222252726Srpaulo		if (x509) {
3223252726Srpaulo			if (SSL_use_certificate(conn->ssl, x509) == 1)
3224252726Srpaulo				ret = 0;
3225252726Srpaulo			X509_free(x509);
3226252726Srpaulo		}
3227346981Scy
3228346981Scy		/* Read additional certificates into the chain. */
3229346981Scy		while (bio) {
3230346981Scy			x509 = PEM_read_bio_X509(bio, NULL, NULL, NULL);
3231346981Scy			if (x509) {
3232346981Scy				/* Takes ownership of x509 */
3233346981Scy				SSL_add0_chain_cert(conn->ssl, x509);
3234346981Scy			} else {
3235346981Scy				BIO_free(bio);
3236346981Scy				bio = NULL;
3237346981Scy			}
3238346981Scy		}
3239252726Srpaulo		return ret;
3240252726Srpaulo	}
3241252726Srpaulo#endif /* ANDROID */
3242252726Srpaulo
3243189251Ssam#ifndef OPENSSL_NO_STDIO
3244189251Ssam	if (SSL_use_certificate_file(conn->ssl, client_cert,
3245189251Ssam				     SSL_FILETYPE_ASN1) == 1) {
3246189251Ssam		wpa_printf(MSG_DEBUG, "OpenSSL: SSL_use_certificate_file (DER)"
3247189251Ssam			   " --> OK");
3248189251Ssam		return 0;
3249189251Ssam	}
3250189251Ssam
3251346981Scy#if OPENSSL_VERSION_NUMBER >= 0x10100000L && \
3252346981Scy	!defined(LIBRESSL_VERSION_NUMBER) && !defined(OPENSSL_IS_BORINGSSL)
3253346981Scy	if (SSL_use_certificate_chain_file(conn->ssl, client_cert) == 1) {
3254346981Scy		ERR_clear_error();
3255346981Scy		wpa_printf(MSG_DEBUG, "OpenSSL: SSL_use_certificate_chain_file"
3256346981Scy			   " --> OK");
3257346981Scy		return 0;
3258346981Scy	}
3259346981Scy#else
3260189251Ssam	if (SSL_use_certificate_file(conn->ssl, client_cert,
3261189251Ssam				     SSL_FILETYPE_PEM) == 1) {
3262252726Srpaulo		ERR_clear_error();
3263189251Ssam		wpa_printf(MSG_DEBUG, "OpenSSL: SSL_use_certificate_file (PEM)"
3264189251Ssam			   " --> OK");
3265189251Ssam		return 0;
3266189251Ssam	}
3267346981Scy#endif
3268252726Srpaulo
3269252726Srpaulo	tls_show_errors(MSG_DEBUG, __func__,
3270252726Srpaulo			"SSL_use_certificate_file failed");
3271189251Ssam#else /* OPENSSL_NO_STDIO */
3272189251Ssam	wpa_printf(MSG_DEBUG, "OpenSSL: %s - OPENSSL_NO_STDIO", __func__);
3273189251Ssam#endif /* OPENSSL_NO_STDIO */
3274189251Ssam
3275189251Ssam	return -1;
3276189251Ssam}
3277189251Ssam
3278189251Ssam
3279289549Srpaulostatic int tls_global_client_cert(struct tls_data *data,
3280289549Srpaulo				  const char *client_cert)
3281189251Ssam{
3282189251Ssam#ifndef OPENSSL_NO_STDIO
3283289549Srpaulo	SSL_CTX *ssl_ctx = data->ssl;
3284289549Srpaulo
3285189251Ssam	if (client_cert == NULL)
3286189251Ssam		return 0;
3287189251Ssam
3288189251Ssam	if (SSL_CTX_use_certificate_file(ssl_ctx, client_cert,
3289189251Ssam					 SSL_FILETYPE_ASN1) != 1 &&
3290252726Srpaulo	    SSL_CTX_use_certificate_chain_file(ssl_ctx, client_cert) != 1 &&
3291189251Ssam	    SSL_CTX_use_certificate_file(ssl_ctx, client_cert,
3292189251Ssam					 SSL_FILETYPE_PEM) != 1) {
3293189251Ssam		tls_show_errors(MSG_INFO, __func__,
3294189251Ssam				"Failed to load client certificate");
3295189251Ssam		return -1;
3296189251Ssam	}
3297189251Ssam	return 0;
3298189251Ssam#else /* OPENSSL_NO_STDIO */
3299189251Ssam	if (client_cert == NULL)
3300189251Ssam		return 0;
3301189251Ssam	wpa_printf(MSG_DEBUG, "OpenSSL: %s - OPENSSL_NO_STDIO", __func__);
3302189251Ssam	return -1;
3303189251Ssam#endif /* OPENSSL_NO_STDIO */
3304189251Ssam}
3305189251Ssam
3306189251Ssam
3307189251Ssam#ifdef PKCS12_FUNCS
3308289549Srpaulostatic int tls_parse_pkcs12(struct tls_data *data, SSL *ssl, PKCS12 *p12,
3309189251Ssam			    const char *passwd)
3310189251Ssam{
3311189251Ssam	EVP_PKEY *pkey;
3312189251Ssam	X509 *cert;
3313189251Ssam	STACK_OF(X509) *certs;
3314189251Ssam	int res = 0;
3315189251Ssam	char buf[256];
3316189251Ssam
3317189251Ssam	pkey = NULL;
3318189251Ssam	cert = NULL;
3319189251Ssam	certs = NULL;
3320289549Srpaulo	if (!passwd)
3321289549Srpaulo		passwd = "";
3322189251Ssam	if (!PKCS12_parse(p12, passwd, &pkey, &cert, &certs)) {
3323189251Ssam		tls_show_errors(MSG_DEBUG, __func__,
3324189251Ssam				"Failed to parse PKCS12 file");
3325189251Ssam		PKCS12_free(p12);
3326189251Ssam		return -1;
3327189251Ssam	}
3328189251Ssam	wpa_printf(MSG_DEBUG, "TLS: Successfully parsed PKCS12 data");
3329189251Ssam
3330189251Ssam	if (cert) {
3331189251Ssam		X509_NAME_oneline(X509_get_subject_name(cert), buf,
3332189251Ssam				  sizeof(buf));
3333189251Ssam		wpa_printf(MSG_DEBUG, "TLS: Got certificate from PKCS12: "
3334189251Ssam			   "subject='%s'", buf);
3335189251Ssam		if (ssl) {
3336189251Ssam			if (SSL_use_certificate(ssl, cert) != 1)
3337189251Ssam				res = -1;
3338189251Ssam		} else {
3339289549Srpaulo			if (SSL_CTX_use_certificate(data->ssl, cert) != 1)
3340189251Ssam				res = -1;
3341189251Ssam		}
3342189251Ssam		X509_free(cert);
3343189251Ssam	}
3344189251Ssam
3345189251Ssam	if (pkey) {
3346189251Ssam		wpa_printf(MSG_DEBUG, "TLS: Got private key from PKCS12");
3347189251Ssam		if (ssl) {
3348189251Ssam			if (SSL_use_PrivateKey(ssl, pkey) != 1)
3349189251Ssam				res = -1;
3350189251Ssam		} else {
3351289549Srpaulo			if (SSL_CTX_use_PrivateKey(data->ssl, pkey) != 1)
3352189251Ssam				res = -1;
3353189251Ssam		}
3354189251Ssam		EVP_PKEY_free(pkey);
3355189251Ssam	}
3356189251Ssam
3357189251Ssam	if (certs) {
3358337817Scy#if OPENSSL_VERSION_NUMBER >= 0x10002000L && !defined(LIBRESSL_VERSION_NUMBER)
3359337817Scy		if (ssl)
3360337817Scy			SSL_clear_chain_certs(ssl);
3361337817Scy		else
3362337817Scy			SSL_CTX_clear_chain_certs(data->ssl);
3363189251Ssam		while ((cert = sk_X509_pop(certs)) != NULL) {
3364189251Ssam			X509_NAME_oneline(X509_get_subject_name(cert), buf,
3365189251Ssam					  sizeof(buf));
3366189251Ssam			wpa_printf(MSG_DEBUG, "TLS: additional certificate"
3367189251Ssam				   " from PKCS12: subject='%s'", buf);
3368337817Scy			if ((ssl && SSL_add1_chain_cert(ssl, cert) != 1) ||
3369337817Scy			    (!ssl && SSL_CTX_add1_chain_cert(data->ssl,
3370337817Scy							     cert) != 1)) {
3371289549Srpaulo				tls_show_errors(MSG_DEBUG, __func__,
3372289549Srpaulo						"Failed to add additional certificate");
3373289549Srpaulo				res = -1;
3374337817Scy				X509_free(cert);
3375289549Srpaulo				break;
3376289549Srpaulo			}
3377337817Scy			X509_free(cert);
3378289549Srpaulo		}
3379289549Srpaulo		if (!res) {
3380289549Srpaulo			/* Try to continue anyway */
3381289549Srpaulo		}
3382337817Scy		sk_X509_pop_free(certs, X509_free);
3383289549Srpaulo#ifndef OPENSSL_IS_BORINGSSL
3384337817Scy		if (ssl)
3385337817Scy			res = SSL_build_cert_chain(
3386337817Scy				ssl,
3387337817Scy				SSL_BUILD_CHAIN_FLAG_CHECK |
3388337817Scy				SSL_BUILD_CHAIN_FLAG_IGNORE_ERROR);
3389337817Scy		else
3390337817Scy			res = SSL_CTX_build_cert_chain(
3391337817Scy				data->ssl,
3392337817Scy				SSL_BUILD_CHAIN_FLAG_CHECK |
3393337817Scy				SSL_BUILD_CHAIN_FLAG_IGNORE_ERROR);
3394289549Srpaulo		if (!res) {
3395289549Srpaulo			tls_show_errors(MSG_DEBUG, __func__,
3396289549Srpaulo					"Failed to build certificate chain");
3397289549Srpaulo		} else if (res == 2) {
3398289549Srpaulo			wpa_printf(MSG_DEBUG,
3399289549Srpaulo				   "TLS: Ignore certificate chain verification error when building chain with PKCS#12 extra certificates");
3400289549Srpaulo		}
3401289549Srpaulo#endif /* OPENSSL_IS_BORINGSSL */
3402289549Srpaulo		/*
3403289549Srpaulo		 * Try to continue regardless of result since it is possible for
3404289549Srpaulo		 * the extra certificates not to be required.
3405289549Srpaulo		 */
3406289549Srpaulo		res = 0;
3407289549Srpaulo#else /* OPENSSL_VERSION_NUMBER >= 0x10002000L */
3408289549Srpaulo		SSL_CTX_clear_extra_chain_certs(data->ssl);
3409289549Srpaulo		while ((cert = sk_X509_pop(certs)) != NULL) {
3410289549Srpaulo			X509_NAME_oneline(X509_get_subject_name(cert), buf,
3411289549Srpaulo					  sizeof(buf));
3412289549Srpaulo			wpa_printf(MSG_DEBUG, "TLS: additional certificate"
3413289549Srpaulo				   " from PKCS12: subject='%s'", buf);
3414189251Ssam			/*
3415189251Ssam			 * There is no SSL equivalent for the chain cert - so
3416189251Ssam			 * always add it to the context...
3417189251Ssam			 */
3418289549Srpaulo			if (SSL_CTX_add_extra_chain_cert(data->ssl, cert) != 1)
3419289549Srpaulo			{
3420337817Scy				X509_free(cert);
3421189251Ssam				res = -1;
3422189251Ssam				break;
3423189251Ssam			}
3424189251Ssam		}
3425337817Scy		sk_X509_pop_free(certs, X509_free);
3426289549Srpaulo#endif /* OPENSSL_VERSION_NUMBER >= 0x10002000L */
3427189251Ssam	}
3428189251Ssam
3429189251Ssam	PKCS12_free(p12);
3430189251Ssam
3431189251Ssam	if (res < 0)
3432289549Srpaulo		tls_get_errors(data);
3433189251Ssam
3434189251Ssam	return res;
3435189251Ssam}
3436189251Ssam#endif  /* PKCS12_FUNCS */
3437189251Ssam
3438189251Ssam
3439289549Srpaulostatic int tls_read_pkcs12(struct tls_data *data, SSL *ssl,
3440289549Srpaulo			   const char *private_key, const char *passwd)
3441189251Ssam{
3442189251Ssam#ifdef PKCS12_FUNCS
3443189251Ssam	FILE *f;
3444189251Ssam	PKCS12 *p12;
3445189251Ssam
3446189251Ssam	f = fopen(private_key, "rb");
3447189251Ssam	if (f == NULL)
3448189251Ssam		return -1;
3449189251Ssam
3450189251Ssam	p12 = d2i_PKCS12_fp(f, NULL);
3451189251Ssam	fclose(f);
3452189251Ssam
3453189251Ssam	if (p12 == NULL) {
3454189251Ssam		tls_show_errors(MSG_INFO, __func__,
3455189251Ssam				"Failed to use PKCS#12 file");
3456189251Ssam		return -1;
3457189251Ssam	}
3458189251Ssam
3459289549Srpaulo	return tls_parse_pkcs12(data, ssl, p12, passwd);
3460189251Ssam
3461189251Ssam#else /* PKCS12_FUNCS */
3462189251Ssam	wpa_printf(MSG_INFO, "TLS: PKCS12 support disabled - cannot read "
3463189251Ssam		   "p12/pfx files");
3464189251Ssam	return -1;
3465189251Ssam#endif  /* PKCS12_FUNCS */
3466189251Ssam}
3467189251Ssam
3468189251Ssam
3469289549Srpaulostatic int tls_read_pkcs12_blob(struct tls_data *data, SSL *ssl,
3470189251Ssam				const u8 *blob, size_t len, const char *passwd)
3471189251Ssam{
3472189251Ssam#ifdef PKCS12_FUNCS
3473189251Ssam	PKCS12 *p12;
3474189251Ssam
3475281806Srpaulo	p12 = d2i_PKCS12(NULL, (const unsigned char **) &blob, len);
3476189251Ssam	if (p12 == NULL) {
3477189251Ssam		tls_show_errors(MSG_INFO, __func__,
3478189251Ssam				"Failed to use PKCS#12 blob");
3479189251Ssam		return -1;
3480189251Ssam	}
3481189251Ssam
3482289549Srpaulo	return tls_parse_pkcs12(data, ssl, p12, passwd);
3483189251Ssam
3484189251Ssam#else /* PKCS12_FUNCS */
3485189251Ssam	wpa_printf(MSG_INFO, "TLS: PKCS12 support disabled - cannot parse "
3486189251Ssam		   "p12/pfx blobs");
3487189251Ssam	return -1;
3488189251Ssam#endif  /* PKCS12_FUNCS */
3489189251Ssam}
3490189251Ssam
3491189251Ssam
3492189251Ssam#ifndef OPENSSL_NO_ENGINE
3493189251Ssamstatic int tls_engine_get_cert(struct tls_connection *conn,
3494189251Ssam			       const char *cert_id,
3495189251Ssam			       X509 **cert)
3496189251Ssam{
3497189251Ssam	/* this runs after the private key is loaded so no PIN is required */
3498189251Ssam	struct {
3499189251Ssam		const char *cert_id;
3500189251Ssam		X509 *cert;
3501189251Ssam	} params;
3502189251Ssam	params.cert_id = cert_id;
3503189251Ssam	params.cert = NULL;
3504189251Ssam
3505189251Ssam	if (!ENGINE_ctrl_cmd(conn->engine, "LOAD_CERT_CTRL",
3506189251Ssam			     0, &params, NULL, 1)) {
3507289549Srpaulo		unsigned long err = ERR_get_error();
3508289549Srpaulo
3509189251Ssam		wpa_printf(MSG_ERROR, "ENGINE: cannot load client cert with id"
3510189251Ssam			   " '%s' [%s]", cert_id,
3511289549Srpaulo			   ERR_error_string(err, NULL));
3512289549Srpaulo		if (tls_is_pin_error(err))
3513289549Srpaulo			return TLS_SET_PARAMS_ENGINE_PRV_BAD_PIN;
3514189251Ssam		return TLS_SET_PARAMS_ENGINE_PRV_INIT_FAILED;
3515189251Ssam	}
3516189251Ssam	if (!params.cert) {
3517189251Ssam		wpa_printf(MSG_ERROR, "ENGINE: did not properly cert with id"
3518189251Ssam			   " '%s'", cert_id);
3519189251Ssam		return TLS_SET_PARAMS_ENGINE_PRV_INIT_FAILED;
3520189251Ssam	}
3521189251Ssam	*cert = params.cert;
3522189251Ssam	return 0;
3523189251Ssam}
3524189251Ssam#endif /* OPENSSL_NO_ENGINE */
3525189251Ssam
3526189251Ssam
3527189251Ssamstatic int tls_connection_engine_client_cert(struct tls_connection *conn,
3528189251Ssam					     const char *cert_id)
3529189251Ssam{
3530189251Ssam#ifndef OPENSSL_NO_ENGINE
3531189251Ssam	X509 *cert;
3532189251Ssam
3533189251Ssam	if (tls_engine_get_cert(conn, cert_id, &cert))
3534189251Ssam		return -1;
3535189251Ssam
3536189251Ssam	if (!SSL_use_certificate(conn->ssl, cert)) {
3537189251Ssam		tls_show_errors(MSG_ERROR, __func__,
3538189251Ssam				"SSL_use_certificate failed");
3539189251Ssam                X509_free(cert);
3540189251Ssam		return -1;
3541189251Ssam	}
3542189251Ssam	X509_free(cert);
3543189251Ssam	wpa_printf(MSG_DEBUG, "ENGINE: SSL_use_certificate --> "
3544189251Ssam		   "OK");
3545189251Ssam	return 0;
3546189251Ssam
3547189251Ssam#else /* OPENSSL_NO_ENGINE */
3548189251Ssam	return -1;
3549189251Ssam#endif /* OPENSSL_NO_ENGINE */
3550189251Ssam}
3551189251Ssam
3552189251Ssam
3553289549Srpaulostatic int tls_connection_engine_ca_cert(struct tls_data *data,
3554189251Ssam					 struct tls_connection *conn,
3555189251Ssam					 const char *ca_cert_id)
3556189251Ssam{
3557189251Ssam#ifndef OPENSSL_NO_ENGINE
3558189251Ssam	X509 *cert;
3559289549Srpaulo	SSL_CTX *ssl_ctx = data->ssl;
3560281806Srpaulo	X509_STORE *store;
3561189251Ssam
3562189251Ssam	if (tls_engine_get_cert(conn, ca_cert_id, &cert))
3563189251Ssam		return -1;
3564189251Ssam
3565189251Ssam	/* start off the same as tls_connection_ca_cert */
3566281806Srpaulo	store = X509_STORE_new();
3567281806Srpaulo	if (store == NULL) {
3568189251Ssam		wpa_printf(MSG_DEBUG, "OpenSSL: %s - failed to allocate new "
3569189251Ssam			   "certificate store", __func__);
3570189251Ssam		X509_free(cert);
3571189251Ssam		return -1;
3572189251Ssam	}
3573281806Srpaulo	SSL_CTX_set_cert_store(ssl_ctx, store);
3574281806Srpaulo	if (!X509_STORE_add_cert(store, cert)) {
3575189251Ssam		unsigned long err = ERR_peek_error();
3576189251Ssam		tls_show_errors(MSG_WARNING, __func__,
3577189251Ssam				"Failed to add CA certificate from engine "
3578189251Ssam				"to certificate store");
3579189251Ssam		if (ERR_GET_LIB(err) == ERR_LIB_X509 &&
3580189251Ssam		    ERR_GET_REASON(err) == X509_R_CERT_ALREADY_IN_HASH_TABLE) {
3581189251Ssam			wpa_printf(MSG_DEBUG, "OpenSSL: %s - ignoring cert"
3582189251Ssam				   " already in hash table error",
3583189251Ssam				   __func__);
3584189251Ssam		} else {
3585189251Ssam			X509_free(cert);
3586189251Ssam			return -1;
3587189251Ssam		}
3588189251Ssam	}
3589189251Ssam	X509_free(cert);
3590189251Ssam	wpa_printf(MSG_DEBUG, "OpenSSL: %s - added CA certificate from engine "
3591189251Ssam		   "to certificate store", __func__);
3592189251Ssam	SSL_set_verify(conn->ssl, SSL_VERIFY_PEER, tls_verify_cb);
3593252726Srpaulo	conn->ca_cert_verify = 1;
3594252726Srpaulo
3595189251Ssam	return 0;
3596189251Ssam
3597189251Ssam#else /* OPENSSL_NO_ENGINE */
3598189251Ssam	return -1;
3599189251Ssam#endif /* OPENSSL_NO_ENGINE */
3600189251Ssam}
3601189251Ssam
3602189251Ssam
3603189251Ssamstatic int tls_connection_engine_private_key(struct tls_connection *conn)
3604189251Ssam{
3605337817Scy#if defined(ANDROID) || !defined(OPENSSL_NO_ENGINE)
3606189251Ssam	if (SSL_use_PrivateKey(conn->ssl, conn->private_key) != 1) {
3607189251Ssam		tls_show_errors(MSG_ERROR, __func__,
3608189251Ssam				"ENGINE: cannot use private key for TLS");
3609189251Ssam		return -1;
3610189251Ssam	}
3611189251Ssam	if (!SSL_check_private_key(conn->ssl)) {
3612189251Ssam		tls_show_errors(MSG_INFO, __func__,
3613189251Ssam				"Private key failed verification");
3614189251Ssam		return -1;
3615189251Ssam	}
3616189251Ssam	return 0;
3617189251Ssam#else /* OPENSSL_NO_ENGINE */
3618189251Ssam	wpa_printf(MSG_ERROR, "SSL: Configuration uses engine, but "
3619189251Ssam		   "engine support was not compiled in");
3620189251Ssam	return -1;
3621189251Ssam#endif /* OPENSSL_NO_ENGINE */
3622189251Ssam}
3623189251Ssam
3624189251Ssam
3625346981Scy#ifndef OPENSSL_NO_STDIO
3626346981Scystatic int tls_passwd_cb(char *buf, int size, int rwflag, void *password)
3627346981Scy{
3628346981Scy	if (!password)
3629346981Scy		return 0;
3630346981Scy	os_strlcpy(buf, (const char *) password, size);
3631346981Scy	return os_strlen(buf);
3632346981Scy}
3633346981Scy#endif /* OPENSSL_NO_STDIO */
3634346981Scy
3635346981Scy
3636346981Scystatic int tls_use_private_key_file(struct tls_data *data, SSL *ssl,
3637346981Scy				    const char *private_key,
3638346981Scy				    const char *private_key_passwd)
3639346981Scy{
3640346981Scy#ifndef OPENSSL_NO_STDIO
3641346981Scy	BIO *bio;
3642346981Scy	EVP_PKEY *pkey;
3643346981Scy	int ret;
3644346981Scy
3645346981Scy	/* First try ASN.1 (DER). */
3646346981Scy	bio = BIO_new_file(private_key, "r");
3647346981Scy	if (!bio)
3648346981Scy		return -1;
3649346981Scy	pkey = d2i_PrivateKey_bio(bio, NULL);
3650346981Scy	BIO_free(bio);
3651346981Scy
3652346981Scy	if (pkey) {
3653346981Scy		wpa_printf(MSG_DEBUG, "OpenSSL: %s (DER) --> loaded", __func__);
3654346981Scy	} else {
3655346981Scy		/* Try PEM with the provided password. */
3656346981Scy		bio = BIO_new_file(private_key, "r");
3657346981Scy		if (!bio)
3658346981Scy			return -1;
3659346981Scy		pkey = PEM_read_bio_PrivateKey(bio, NULL, tls_passwd_cb,
3660346981Scy					       (void *) private_key_passwd);
3661346981Scy		BIO_free(bio);
3662346981Scy		if (!pkey)
3663346981Scy			return -1;
3664346981Scy		wpa_printf(MSG_DEBUG, "OpenSSL: %s (PEM) --> loaded", __func__);
3665346981Scy		/* Clear errors from the previous failed load. */
3666346981Scy		ERR_clear_error();
3667346981Scy	}
3668346981Scy
3669346981Scy	if (ssl)
3670346981Scy		ret = SSL_use_PrivateKey(ssl, pkey);
3671346981Scy	else
3672346981Scy		ret = SSL_CTX_use_PrivateKey(data->ssl, pkey);
3673346981Scy
3674346981Scy	EVP_PKEY_free(pkey);
3675346981Scy	return ret == 1 ? 0 : -1;
3676346981Scy#else /* OPENSSL_NO_STDIO */
3677346981Scy	wpa_printf(MSG_DEBUG, "OpenSSL: %s - OPENSSL_NO_STDIO", __func__);
3678346981Scy	return -1;
3679346981Scy#endif /* OPENSSL_NO_STDIO */
3680346981Scy}
3681346981Scy
3682346981Scy
3683289549Srpaulostatic int tls_connection_private_key(struct tls_data *data,
3684189251Ssam				      struct tls_connection *conn,
3685189251Ssam				      const char *private_key,
3686189251Ssam				      const char *private_key_passwd,
3687189251Ssam				      const u8 *private_key_blob,
3688189251Ssam				      size_t private_key_blob_len)
3689189251Ssam{
3690189251Ssam	int ok;
3691189251Ssam
3692189251Ssam	if (private_key == NULL && private_key_blob == NULL)
3693189251Ssam		return 0;
3694189251Ssam
3695189251Ssam	ok = 0;
3696189251Ssam	while (private_key_blob) {
3697189251Ssam		if (SSL_use_PrivateKey_ASN1(EVP_PKEY_RSA, conn->ssl,
3698189251Ssam					    (u8 *) private_key_blob,
3699189251Ssam					    private_key_blob_len) == 1) {
3700189251Ssam			wpa_printf(MSG_DEBUG, "OpenSSL: SSL_use_PrivateKey_"
3701189251Ssam				   "ASN1(EVP_PKEY_RSA) --> OK");
3702189251Ssam			ok = 1;
3703189251Ssam			break;
3704189251Ssam		}
3705189251Ssam
3706189251Ssam		if (SSL_use_PrivateKey_ASN1(EVP_PKEY_DSA, conn->ssl,
3707189251Ssam					    (u8 *) private_key_blob,
3708189251Ssam					    private_key_blob_len) == 1) {
3709189251Ssam			wpa_printf(MSG_DEBUG, "OpenSSL: SSL_use_PrivateKey_"
3710189251Ssam				   "ASN1(EVP_PKEY_DSA) --> OK");
3711189251Ssam			ok = 1;
3712189251Ssam			break;
3713189251Ssam		}
3714189251Ssam
3715189251Ssam		if (SSL_use_RSAPrivateKey_ASN1(conn->ssl,
3716189251Ssam					       (u8 *) private_key_blob,
3717189251Ssam					       private_key_blob_len) == 1) {
3718189251Ssam			wpa_printf(MSG_DEBUG, "OpenSSL: "
3719189251Ssam				   "SSL_use_RSAPrivateKey_ASN1 --> OK");
3720189251Ssam			ok = 1;
3721189251Ssam			break;
3722189251Ssam		}
3723189251Ssam
3724289549Srpaulo		if (tls_read_pkcs12_blob(data, conn->ssl, private_key_blob,
3725346981Scy					 private_key_blob_len,
3726346981Scy					 private_key_passwd) == 0) {
3727189251Ssam			wpa_printf(MSG_DEBUG, "OpenSSL: PKCS#12 as blob --> "
3728189251Ssam				   "OK");
3729189251Ssam			ok = 1;
3730189251Ssam			break;
3731189251Ssam		}
3732189251Ssam
3733189251Ssam		break;
3734189251Ssam	}
3735189251Ssam
3736189251Ssam	while (!ok && private_key) {
3737346981Scy		if (tls_use_private_key_file(data, conn->ssl, private_key,
3738346981Scy					     private_key_passwd) == 0) {
3739189251Ssam			ok = 1;
3740189251Ssam			break;
3741189251Ssam		}
3742189251Ssam
3743346981Scy		if (tls_read_pkcs12(data, conn->ssl, private_key,
3744346981Scy				    private_key_passwd) == 0) {
3745189251Ssam			wpa_printf(MSG_DEBUG, "OpenSSL: Reading PKCS#12 file "
3746189251Ssam				   "--> OK");
3747189251Ssam			ok = 1;
3748189251Ssam			break;
3749189251Ssam		}
3750189251Ssam
3751189251Ssam		if (tls_cryptoapi_cert(conn->ssl, private_key) == 0) {
3752189251Ssam			wpa_printf(MSG_DEBUG, "OpenSSL: Using CryptoAPI to "
3753189251Ssam				   "access certificate store --> OK");
3754189251Ssam			ok = 1;
3755189251Ssam			break;
3756189251Ssam		}
3757189251Ssam
3758189251Ssam		break;
3759189251Ssam	}
3760189251Ssam
3761189251Ssam	if (!ok) {
3762252726Srpaulo		tls_show_errors(MSG_INFO, __func__,
3763252726Srpaulo				"Failed to load private key");
3764189251Ssam		return -1;
3765189251Ssam	}
3766189251Ssam	ERR_clear_error();
3767252726Srpaulo
3768189251Ssam	if (!SSL_check_private_key(conn->ssl)) {
3769189251Ssam		tls_show_errors(MSG_INFO, __func__, "Private key failed "
3770189251Ssam				"verification");
3771189251Ssam		return -1;
3772189251Ssam	}
3773189251Ssam
3774189251Ssam	wpa_printf(MSG_DEBUG, "SSL: Private key loaded successfully");
3775189251Ssam	return 0;
3776189251Ssam}
3777189251Ssam
3778189251Ssam
3779289549Srpaulostatic int tls_global_private_key(struct tls_data *data,
3780289549Srpaulo				  const char *private_key,
3781189251Ssam				  const char *private_key_passwd)
3782189251Ssam{
3783289549Srpaulo	SSL_CTX *ssl_ctx = data->ssl;
3784189251Ssam
3785189251Ssam	if (private_key == NULL)
3786189251Ssam		return 0;
3787189251Ssam
3788346981Scy	if (tls_use_private_key_file(data, NULL, private_key,
3789346981Scy				     private_key_passwd) &&
3790346981Scy	    tls_read_pkcs12(data, NULL, private_key, private_key_passwd)) {
3791189251Ssam		tls_show_errors(MSG_INFO, __func__,
3792189251Ssam				"Failed to load private key");
3793189251Ssam		ERR_clear_error();
3794189251Ssam		return -1;
3795189251Ssam	}
3796189251Ssam	ERR_clear_error();
3797252726Srpaulo
3798189251Ssam	if (!SSL_CTX_check_private_key(ssl_ctx)) {
3799189251Ssam		tls_show_errors(MSG_INFO, __func__,
3800189251Ssam				"Private key failed verification");
3801189251Ssam		return -1;
3802189251Ssam	}
3803189251Ssam
3804189251Ssam	return 0;
3805189251Ssam}
3806189251Ssam
3807189251Ssam
3808189251Ssamstatic int tls_connection_dh(struct tls_connection *conn, const char *dh_file)
3809189251Ssam{
3810189251Ssam#ifdef OPENSSL_NO_DH
3811189251Ssam	if (dh_file == NULL)
3812189251Ssam		return 0;
3813189251Ssam	wpa_printf(MSG_ERROR, "TLS: openssl does not include DH support, but "
3814189251Ssam		   "dh_file specified");
3815189251Ssam	return -1;
3816189251Ssam#else /* OPENSSL_NO_DH */
3817189251Ssam	DH *dh;
3818189251Ssam	BIO *bio;
3819189251Ssam
3820189251Ssam	/* TODO: add support for dh_blob */
3821189251Ssam	if (dh_file == NULL)
3822189251Ssam		return 0;
3823189251Ssam	if (conn == NULL)
3824189251Ssam		return -1;
3825189251Ssam
3826189251Ssam	bio = BIO_new_file(dh_file, "r");
3827189251Ssam	if (bio == NULL) {
3828189251Ssam		wpa_printf(MSG_INFO, "TLS: Failed to open DH file '%s': %s",
3829189251Ssam			   dh_file, ERR_error_string(ERR_get_error(), NULL));
3830189251Ssam		return -1;
3831189251Ssam	}
3832189251Ssam	dh = PEM_read_bio_DHparams(bio, NULL, NULL, NULL);
3833189251Ssam	BIO_free(bio);
3834189251Ssam#ifndef OPENSSL_NO_DSA
3835189251Ssam	while (dh == NULL) {
3836189251Ssam		DSA *dsa;
3837189251Ssam		wpa_printf(MSG_DEBUG, "TLS: Failed to parse DH file '%s': %s -"
3838189251Ssam			   " trying to parse as DSA params", dh_file,
3839189251Ssam			   ERR_error_string(ERR_get_error(), NULL));
3840189251Ssam		bio = BIO_new_file(dh_file, "r");
3841189251Ssam		if (bio == NULL)
3842189251Ssam			break;
3843189251Ssam		dsa = PEM_read_bio_DSAparams(bio, NULL, NULL, NULL);
3844189251Ssam		BIO_free(bio);
3845189251Ssam		if (!dsa) {
3846189251Ssam			wpa_printf(MSG_DEBUG, "TLS: Failed to parse DSA file "
3847189251Ssam				   "'%s': %s", dh_file,
3848189251Ssam				   ERR_error_string(ERR_get_error(), NULL));
3849189251Ssam			break;
3850189251Ssam		}
3851189251Ssam
3852189251Ssam		wpa_printf(MSG_DEBUG, "TLS: DH file in DSA param format");
3853189251Ssam		dh = DSA_dup_DH(dsa);
3854189251Ssam		DSA_free(dsa);
3855189251Ssam		if (dh == NULL) {
3856189251Ssam			wpa_printf(MSG_INFO, "TLS: Failed to convert DSA "
3857189251Ssam				   "params into DH params");
3858189251Ssam			break;
3859189251Ssam		}
3860189251Ssam		break;
3861189251Ssam	}
3862189251Ssam#endif /* !OPENSSL_NO_DSA */
3863189251Ssam	if (dh == NULL) {
3864189251Ssam		wpa_printf(MSG_INFO, "TLS: Failed to read/parse DH/DSA file "
3865189251Ssam			   "'%s'", dh_file);
3866189251Ssam		return -1;
3867189251Ssam	}
3868189251Ssam
3869189251Ssam	if (SSL_set_tmp_dh(conn->ssl, dh) != 1) {
3870189251Ssam		wpa_printf(MSG_INFO, "TLS: Failed to set DH params from '%s': "
3871189251Ssam			   "%s", dh_file,
3872189251Ssam			   ERR_error_string(ERR_get_error(), NULL));
3873189251Ssam		DH_free(dh);
3874189251Ssam		return -1;
3875189251Ssam	}
3876189251Ssam	DH_free(dh);
3877189251Ssam	return 0;
3878189251Ssam#endif /* OPENSSL_NO_DH */
3879189251Ssam}
3880189251Ssam
3881189251Ssam
3882289549Srpaulostatic int tls_global_dh(struct tls_data *data, const char *dh_file)
3883189251Ssam{
3884189251Ssam#ifdef OPENSSL_NO_DH
3885189251Ssam	if (dh_file == NULL)
3886189251Ssam		return 0;
3887189251Ssam	wpa_printf(MSG_ERROR, "TLS: openssl does not include DH support, but "
3888189251Ssam		   "dh_file specified");
3889189251Ssam	return -1;
3890189251Ssam#else /* OPENSSL_NO_DH */
3891289549Srpaulo	SSL_CTX *ssl_ctx = data->ssl;
3892189251Ssam	DH *dh;
3893189251Ssam	BIO *bio;
3894189251Ssam
3895189251Ssam	/* TODO: add support for dh_blob */
3896189251Ssam	if (dh_file == NULL)
3897189251Ssam		return 0;
3898189251Ssam	if (ssl_ctx == NULL)
3899189251Ssam		return -1;
3900189251Ssam
3901189251Ssam	bio = BIO_new_file(dh_file, "r");
3902189251Ssam	if (bio == NULL) {
3903189251Ssam		wpa_printf(MSG_INFO, "TLS: Failed to open DH file '%s': %s",
3904189251Ssam			   dh_file, ERR_error_string(ERR_get_error(), NULL));
3905189251Ssam		return -1;
3906189251Ssam	}
3907189251Ssam	dh = PEM_read_bio_DHparams(bio, NULL, NULL, NULL);
3908189251Ssam	BIO_free(bio);
3909189251Ssam#ifndef OPENSSL_NO_DSA
3910189251Ssam	while (dh == NULL) {
3911189251Ssam		DSA *dsa;
3912189251Ssam		wpa_printf(MSG_DEBUG, "TLS: Failed to parse DH file '%s': %s -"
3913189251Ssam			   " trying to parse as DSA params", dh_file,
3914189251Ssam			   ERR_error_string(ERR_get_error(), NULL));
3915189251Ssam		bio = BIO_new_file(dh_file, "r");
3916189251Ssam		if (bio == NULL)
3917189251Ssam			break;
3918189251Ssam		dsa = PEM_read_bio_DSAparams(bio, NULL, NULL, NULL);
3919189251Ssam		BIO_free(bio);
3920189251Ssam		if (!dsa) {
3921189251Ssam			wpa_printf(MSG_DEBUG, "TLS: Failed to parse DSA file "
3922189251Ssam				   "'%s': %s", dh_file,
3923189251Ssam				   ERR_error_string(ERR_get_error(), NULL));
3924189251Ssam			break;
3925189251Ssam		}
3926189251Ssam
3927189251Ssam		wpa_printf(MSG_DEBUG, "TLS: DH file in DSA param format");
3928189251Ssam		dh = DSA_dup_DH(dsa);
3929189251Ssam		DSA_free(dsa);
3930189251Ssam		if (dh == NULL) {
3931189251Ssam			wpa_printf(MSG_INFO, "TLS: Failed to convert DSA "
3932189251Ssam				   "params into DH params");
3933189251Ssam			break;
3934189251Ssam		}
3935189251Ssam		break;
3936189251Ssam	}
3937189251Ssam#endif /* !OPENSSL_NO_DSA */
3938189251Ssam	if (dh == NULL) {
3939189251Ssam		wpa_printf(MSG_INFO, "TLS: Failed to read/parse DH/DSA file "
3940189251Ssam			   "'%s'", dh_file);
3941189251Ssam		return -1;
3942189251Ssam	}
3943189251Ssam
3944189251Ssam	if (SSL_CTX_set_tmp_dh(ssl_ctx, dh) != 1) {
3945189251Ssam		wpa_printf(MSG_INFO, "TLS: Failed to set DH params from '%s': "
3946189251Ssam			   "%s", dh_file,
3947189251Ssam			   ERR_error_string(ERR_get_error(), NULL));
3948189251Ssam		DH_free(dh);
3949189251Ssam		return -1;
3950189251Ssam	}
3951189251Ssam	DH_free(dh);
3952189251Ssam	return 0;
3953189251Ssam#endif /* OPENSSL_NO_DH */
3954189251Ssam}
3955189251Ssam
3956189251Ssam
3957289549Srpauloint tls_connection_get_random(void *ssl_ctx, struct tls_connection *conn,
3958289549Srpaulo			      struct tls_random *keys)
3959189251Ssam{
3960189251Ssam	SSL *ssl;
3961189251Ssam
3962189251Ssam	if (conn == NULL || keys == NULL)
3963189251Ssam		return -1;
3964189251Ssam	ssl = conn->ssl;
3965289549Srpaulo	if (ssl == NULL)
3966289549Srpaulo		return -1;
3967189251Ssam
3968289549Srpaulo	os_memset(keys, 0, sizeof(*keys));
3969289549Srpaulo	keys->client_random = conn->client_random;
3970289549Srpaulo	keys->client_random_len = SSL_get_client_random(
3971289549Srpaulo		ssl, conn->client_random, sizeof(conn->client_random));
3972289549Srpaulo	keys->server_random = conn->server_random;
3973289549Srpaulo	keys->server_random_len = SSL_get_server_random(
3974289549Srpaulo		ssl, conn->server_random, sizeof(conn->server_random));
3975289549Srpaulo
3976189251Ssam	return 0;
3977289549Srpaulo}
3978289549Srpaulo
3979289549Srpaulo
3980337817Scy#ifdef OPENSSL_NEED_EAP_FAST_PRF
3981289549Srpaulostatic int openssl_get_keyblock_size(SSL *ssl)
3982289549Srpaulo{
3983346981Scy#if OPENSSL_VERSION_NUMBER < 0x10100000L || \
3984346981Scy	(defined(LIBRESSL_VERSION_NUMBER) && \
3985346981Scy	 LIBRESSL_VERSION_NUMBER < 0x20700000L)
3986289549Srpaulo	const EVP_CIPHER *c;
3987289549Srpaulo	const EVP_MD *h;
3988289549Srpaulo	int md_size;
3989289549Srpaulo
3990289549Srpaulo	if (ssl->enc_read_ctx == NULL || ssl->enc_read_ctx->cipher == NULL ||
3991289549Srpaulo	    ssl->read_hash == NULL)
3992289549Srpaulo		return -1;
3993289549Srpaulo
3994289549Srpaulo	c = ssl->enc_read_ctx->cipher;
3995289549Srpaulo	h = EVP_MD_CTX_md(ssl->read_hash);
3996289549Srpaulo	if (h)
3997289549Srpaulo		md_size = EVP_MD_size(h);
3998289549Srpaulo	else if (ssl->s3)
3999289549Srpaulo		md_size = ssl->s3->tmp.new_mac_secret_size;
4000289549Srpaulo	else
4001289549Srpaulo		return -1;
4002289549Srpaulo
4003289549Srpaulo	wpa_printf(MSG_DEBUG, "OpenSSL: keyblock size: key_len=%d MD_size=%d "
4004289549Srpaulo		   "IV_len=%d", EVP_CIPHER_key_length(c), md_size,
4005289549Srpaulo		   EVP_CIPHER_iv_length(c));
4006289549Srpaulo	return 2 * (EVP_CIPHER_key_length(c) +
4007289549Srpaulo		    md_size +
4008289549Srpaulo		    EVP_CIPHER_iv_length(c));
4009289549Srpaulo#else
4010289549Srpaulo	const SSL_CIPHER *ssl_cipher;
4011289549Srpaulo	int cipher, digest;
4012289549Srpaulo	const EVP_CIPHER *c;
4013289549Srpaulo	const EVP_MD *h;
4014289549Srpaulo
4015289549Srpaulo	ssl_cipher = SSL_get_current_cipher(ssl);
4016289549Srpaulo	if (!ssl_cipher)
4017289549Srpaulo		return -1;
4018289549Srpaulo	cipher = SSL_CIPHER_get_cipher_nid(ssl_cipher);
4019289549Srpaulo	digest = SSL_CIPHER_get_digest_nid(ssl_cipher);
4020289549Srpaulo	wpa_printf(MSG_DEBUG, "OpenSSL: cipher nid %d digest nid %d",
4021289549Srpaulo		   cipher, digest);
4022289549Srpaulo	if (cipher < 0 || digest < 0)
4023289549Srpaulo		return -1;
4024289549Srpaulo	c = EVP_get_cipherbynid(cipher);
4025289549Srpaulo	h = EVP_get_digestbynid(digest);
4026289549Srpaulo	if (!c || !h)
4027289549Srpaulo		return -1;
4028289549Srpaulo
4029289549Srpaulo	wpa_printf(MSG_DEBUG,
4030289549Srpaulo		   "OpenSSL: keyblock size: key_len=%d MD_size=%d IV_len=%d",
4031289549Srpaulo		   EVP_CIPHER_key_length(c), EVP_MD_size(h),
4032289549Srpaulo		   EVP_CIPHER_iv_length(c));
4033289549Srpaulo	return 2 * (EVP_CIPHER_key_length(c) + EVP_MD_size(h) +
4034289549Srpaulo		    EVP_CIPHER_iv_length(c));
4035289549Srpaulo#endif
4036289549Srpaulo}
4037337817Scy#endif /* OPENSSL_NEED_EAP_FAST_PRF */
4038289549Srpaulo
4039289549Srpaulo
4040337817Scyint tls_connection_export_key(void *tls_ctx, struct tls_connection *conn,
4041346981Scy			      const char *label, const u8 *context,
4042346981Scy			      size_t context_len, u8 *out, size_t out_len)
4043289549Srpaulo{
4044337817Scy	if (!conn ||
4045337817Scy	    SSL_export_keying_material(conn->ssl, out, out_len, label,
4046346981Scy				       os_strlen(label), context, context_len,
4047346981Scy				       context != NULL) != 1)
4048289549Srpaulo		return -1;
4049337817Scy	return 0;
4050337817Scy}
4051289549Srpaulo
4052289549Srpaulo
4053337817Scyint tls_connection_get_eap_fast_key(void *tls_ctx, struct tls_connection *conn,
4054337817Scy				    u8 *out, size_t out_len)
4055337817Scy{
4056337817Scy#ifdef OPENSSL_NEED_EAP_FAST_PRF
4057289549Srpaulo	SSL *ssl;
4058289549Srpaulo	SSL_SESSION *sess;
4059289549Srpaulo	u8 *rnd;
4060289549Srpaulo	int ret = -1;
4061289549Srpaulo	int skip = 0;
4062289549Srpaulo	u8 *tmp_out = NULL;
4063289549Srpaulo	u8 *_out = out;
4064289549Srpaulo	unsigned char client_random[SSL3_RANDOM_SIZE];
4065289549Srpaulo	unsigned char server_random[SSL3_RANDOM_SIZE];
4066289549Srpaulo	unsigned char master_key[64];
4067289549Srpaulo	size_t master_key_len;
4068289549Srpaulo	const char *ver;
4069289549Srpaulo
4070289549Srpaulo	/*
4071337817Scy	 * TLS library did not support EAP-FAST key generation, so get the
4072337817Scy	 * needed TLS session parameters and use an internal implementation of
4073337817Scy	 * TLS PRF to derive the key.
4074289549Srpaulo	 */
4075289549Srpaulo
4076289549Srpaulo	if (conn == NULL)
4077289549Srpaulo		return -1;
4078289549Srpaulo	ssl = conn->ssl;
4079289549Srpaulo	if (ssl == NULL)
4080289549Srpaulo		return -1;
4081289549Srpaulo	ver = SSL_get_version(ssl);
4082289549Srpaulo	sess = SSL_get_session(ssl);
4083289549Srpaulo	if (!ver || !sess)
4084289549Srpaulo		return -1;
4085289549Srpaulo
4086337817Scy	skip = openssl_get_keyblock_size(ssl);
4087337817Scy	if (skip < 0)
4088337817Scy		return -1;
4089337817Scy	tmp_out = os_malloc(skip + out_len);
4090337817Scy	if (!tmp_out)
4091337817Scy		return -1;
4092337817Scy	_out = tmp_out;
4093289549Srpaulo
4094289549Srpaulo	rnd = os_malloc(2 * SSL3_RANDOM_SIZE);
4095289549Srpaulo	if (!rnd) {
4096289549Srpaulo		os_free(tmp_out);
4097289549Srpaulo		return -1;
4098289549Srpaulo	}
4099289549Srpaulo
4100289549Srpaulo	SSL_get_client_random(ssl, client_random, sizeof(client_random));
4101289549Srpaulo	SSL_get_server_random(ssl, server_random, sizeof(server_random));
4102289549Srpaulo	master_key_len = SSL_SESSION_get_master_key(sess, master_key,
4103289549Srpaulo						    sizeof(master_key));
4104289549Srpaulo
4105337817Scy	os_memcpy(rnd, server_random, SSL3_RANDOM_SIZE);
4106337817Scy	os_memcpy(rnd + SSL3_RANDOM_SIZE, client_random, SSL3_RANDOM_SIZE);
4107289549Srpaulo
4108289549Srpaulo	if (os_strcmp(ver, "TLSv1.2") == 0) {
4109289549Srpaulo		tls_prf_sha256(master_key, master_key_len,
4110337817Scy			       "key expansion", rnd, 2 * SSL3_RANDOM_SIZE,
4111289549Srpaulo			       _out, skip + out_len);
4112289549Srpaulo		ret = 0;
4113289549Srpaulo	} else if (tls_prf_sha1_md5(master_key, master_key_len,
4114337817Scy				    "key expansion", rnd, 2 * SSL3_RANDOM_SIZE,
4115289549Srpaulo				    _out, skip + out_len) == 0) {
4116289549Srpaulo		ret = 0;
4117289549Srpaulo	}
4118351611Scy	forced_memzero(master_key, sizeof(master_key));
4119289549Srpaulo	os_free(rnd);
4120337817Scy	if (ret == 0)
4121289549Srpaulo		os_memcpy(out, _out + skip, out_len);
4122289549Srpaulo	bin_clear_free(tmp_out, skip);
4123289549Srpaulo
4124289549Srpaulo	return ret;
4125337817Scy#else /* OPENSSL_NEED_EAP_FAST_PRF */
4126337817Scy	wpa_printf(MSG_ERROR,
4127337817Scy		   "OpenSSL: EAP-FAST keys cannot be exported in FIPS mode");
4128337817Scy	return -1;
4129337817Scy#endif /* OPENSSL_NEED_EAP_FAST_PRF */
4130189251Ssam}
4131189251Ssam
4132189251Ssam
4133214734Srpaulostatic struct wpabuf *
4134346981Scyopenssl_handshake(struct tls_connection *conn, const struct wpabuf *in_data)
4135189251Ssam{
4136189251Ssam	int res;
4137214734Srpaulo	struct wpabuf *out_data;
4138189251Ssam
4139189251Ssam	/*
4140189251Ssam	 * Give TLS handshake data from the server (if available) to OpenSSL
4141189251Ssam	 * for processing.
4142189251Ssam	 */
4143289549Srpaulo	if (in_data && wpabuf_len(in_data) > 0 &&
4144214734Srpaulo	    BIO_write(conn->ssl_in, wpabuf_head(in_data), wpabuf_len(in_data))
4145214734Srpaulo	    < 0) {
4146189251Ssam		tls_show_errors(MSG_INFO, __func__,
4147189251Ssam				"Handshake failed - BIO_write");
4148189251Ssam		return NULL;
4149189251Ssam	}
4150189251Ssam
4151189251Ssam	/* Initiate TLS handshake or continue the existing handshake */
4152346981Scy	if (conn->server)
4153214734Srpaulo		res = SSL_accept(conn->ssl);
4154214734Srpaulo	else
4155214734Srpaulo		res = SSL_connect(conn->ssl);
4156189251Ssam	if (res != 1) {
4157189251Ssam		int err = SSL_get_error(conn->ssl, res);
4158189251Ssam		if (err == SSL_ERROR_WANT_READ)
4159189251Ssam			wpa_printf(MSG_DEBUG, "SSL: SSL_connect - want "
4160189251Ssam				   "more data");
4161189251Ssam		else if (err == SSL_ERROR_WANT_WRITE)
4162189251Ssam			wpa_printf(MSG_DEBUG, "SSL: SSL_connect - want to "
4163189251Ssam				   "write");
4164189251Ssam		else {
4165189251Ssam			tls_show_errors(MSG_INFO, __func__, "SSL_connect");
4166189251Ssam			conn->failed++;
4167346981Scy			if (!conn->server && !conn->client_hello_generated) {
4168346981Scy				/* The server would not understand TLS Alert
4169346981Scy				 * before ClientHello, so simply terminate
4170346981Scy				 * handshake on this type of error case caused
4171346981Scy				 * by a likely internal error like no ciphers
4172346981Scy				 * available. */
4173346981Scy				wpa_printf(MSG_DEBUG,
4174346981Scy					   "OpenSSL: Could not generate ClientHello");
4175346981Scy				conn->write_alerts++;
4176346981Scy				return NULL;
4177346981Scy			}
4178189251Ssam		}
4179189251Ssam	}
4180189251Ssam
4181346981Scy	if (!conn->server && !conn->failed)
4182346981Scy		conn->client_hello_generated = 1;
4183346981Scy
4184346981Scy#ifdef CONFIG_SUITEB
4185346981Scy	if ((conn->flags & TLS_CONN_SUITEB) && !conn->server &&
4186346981Scy	    os_strncmp(SSL_get_cipher(conn->ssl), "DHE-", 4) == 0 &&
4187346981Scy	    conn->server_dh_prime_len < 3072) {
4188346981Scy		struct tls_context *context = conn->context;
4189346981Scy
4190346981Scy		/*
4191346981Scy		 * This should not be reached since earlier cert_cb should have
4192346981Scy		 * terminated the handshake. Keep this check here for extra
4193346981Scy		 * protection if anything goes wrong with the more low-level
4194346981Scy		 * checks based on having to parse the TLS handshake messages.
4195346981Scy		 */
4196346981Scy		wpa_printf(MSG_DEBUG,
4197346981Scy			   "OpenSSL: Server DH prime length: %d bits",
4198346981Scy			   conn->server_dh_prime_len);
4199346981Scy
4200346981Scy		if (context->event_cb) {
4201346981Scy			union tls_event_data ev;
4202346981Scy
4203346981Scy			os_memset(&ev, 0, sizeof(ev));
4204346981Scy			ev.alert.is_local = 1;
4205346981Scy			ev.alert.type = "fatal";
4206346981Scy			ev.alert.description = "insufficient security";
4207346981Scy			context->event_cb(context->cb_ctx, TLS_ALERT, &ev);
4208346981Scy		}
4209346981Scy		/*
4210346981Scy		 * Could send a TLS Alert to the server, but for now, simply
4211346981Scy		 * terminate handshake.
4212346981Scy		 */
4213346981Scy		conn->failed++;
4214346981Scy		conn->write_alerts++;
4215346981Scy		return NULL;
4216346981Scy	}
4217346981Scy#endif /* CONFIG_SUITEB */
4218346981Scy
4219189251Ssam	/* Get the TLS handshake data to be sent to the server */
4220189251Ssam	res = BIO_ctrl_pending(conn->ssl_out);
4221189251Ssam	wpa_printf(MSG_DEBUG, "SSL: %d bytes pending from ssl_out", res);
4222214734Srpaulo	out_data = wpabuf_alloc(res);
4223189251Ssam	if (out_data == NULL) {
4224189251Ssam		wpa_printf(MSG_DEBUG, "SSL: Failed to allocate memory for "
4225189251Ssam			   "handshake output (%d bytes)", res);
4226189251Ssam		if (BIO_reset(conn->ssl_out) < 0) {
4227189251Ssam			tls_show_errors(MSG_INFO, __func__,
4228189251Ssam					"BIO_reset failed");
4229189251Ssam		}
4230189251Ssam		return NULL;
4231189251Ssam	}
4232214734Srpaulo	res = res == 0 ? 0 : BIO_read(conn->ssl_out, wpabuf_mhead(out_data),
4233214734Srpaulo				      res);
4234189251Ssam	if (res < 0) {
4235189251Ssam		tls_show_errors(MSG_INFO, __func__,
4236189251Ssam				"Handshake failed - BIO_read");
4237189251Ssam		if (BIO_reset(conn->ssl_out) < 0) {
4238189251Ssam			tls_show_errors(MSG_INFO, __func__,
4239189251Ssam					"BIO_reset failed");
4240189251Ssam		}
4241214734Srpaulo		wpabuf_free(out_data);
4242189251Ssam		return NULL;
4243189251Ssam	}
4244214734Srpaulo	wpabuf_put(out_data, res);
4245189251Ssam
4246189251Ssam	return out_data;
4247189251Ssam}
4248189251Ssam
4249189251Ssam
4250214734Srpaulostatic struct wpabuf *
4251214734Srpauloopenssl_get_appl_data(struct tls_connection *conn, size_t max_len)
4252189251Ssam{
4253214734Srpaulo	struct wpabuf *appl_data;
4254189251Ssam	int res;
4255189251Ssam
4256214734Srpaulo	appl_data = wpabuf_alloc(max_len + 100);
4257214734Srpaulo	if (appl_data == NULL)
4258189251Ssam		return NULL;
4259189251Ssam
4260214734Srpaulo	res = SSL_read(conn->ssl, wpabuf_mhead(appl_data),
4261214734Srpaulo		       wpabuf_size(appl_data));
4262214734Srpaulo	if (res < 0) {
4263189251Ssam		int err = SSL_get_error(conn->ssl, res);
4264214734Srpaulo		if (err == SSL_ERROR_WANT_READ ||
4265214734Srpaulo		    err == SSL_ERROR_WANT_WRITE) {
4266214734Srpaulo			wpa_printf(MSG_DEBUG, "SSL: No Application Data "
4267214734Srpaulo				   "included");
4268214734Srpaulo		} else {
4269189251Ssam			tls_show_errors(MSG_INFO, __func__,
4270214734Srpaulo					"Failed to read possible "
4271214734Srpaulo					"Application Data");
4272189251Ssam		}
4273214734Srpaulo		wpabuf_free(appl_data);
4274189251Ssam		return NULL;
4275189251Ssam	}
4276214734Srpaulo
4277214734Srpaulo	wpabuf_put(appl_data, res);
4278214734Srpaulo	wpa_hexdump_buf_key(MSG_MSGDUMP, "SSL: Application Data in Finished "
4279214734Srpaulo			    "message", appl_data);
4280214734Srpaulo
4281214734Srpaulo	return appl_data;
4282214734Srpaulo}
4283214734Srpaulo
4284214734Srpaulo
4285214734Srpaulostatic struct wpabuf *
4286214734Srpauloopenssl_connection_handshake(struct tls_connection *conn,
4287214734Srpaulo			     const struct wpabuf *in_data,
4288346981Scy			     struct wpabuf **appl_data)
4289214734Srpaulo{
4290214734Srpaulo	struct wpabuf *out_data;
4291214734Srpaulo
4292214734Srpaulo	if (appl_data)
4293214734Srpaulo		*appl_data = NULL;
4294214734Srpaulo
4295346981Scy	out_data = openssl_handshake(conn, in_data);
4296214734Srpaulo	if (out_data == NULL)
4297189251Ssam		return NULL;
4298281806Srpaulo	if (conn->invalid_hb_used) {
4299281806Srpaulo		wpa_printf(MSG_INFO, "TLS: Heartbeat attack detected - do not send response");
4300281806Srpaulo		wpabuf_free(out_data);
4301281806Srpaulo		return NULL;
4302281806Srpaulo	}
4303214734Srpaulo
4304289549Srpaulo	if (SSL_is_init_finished(conn->ssl)) {
4305289549Srpaulo		wpa_printf(MSG_DEBUG,
4306289549Srpaulo			   "OpenSSL: Handshake finished - resumed=%d",
4307289549Srpaulo			   tls_connection_resumed(conn->ssl_ctx, conn));
4308351611Scy		if (conn->server) {
4309351611Scy			char *buf;
4310351611Scy			size_t buflen = 2000;
4311351611Scy
4312351611Scy			buf = os_malloc(buflen);
4313351611Scy			if (buf) {
4314351611Scy				if (SSL_get_shared_ciphers(conn->ssl, buf,
4315351611Scy							   buflen)) {
4316351611Scy					buf[buflen - 1] = '\0';
4317351611Scy					wpa_printf(MSG_DEBUG,
4318351611Scy						   "OpenSSL: Shared ciphers: %s",
4319351611Scy						   buf);
4320351611Scy				}
4321351611Scy				os_free(buf);
4322351611Scy			}
4323351611Scy		}
4324289549Srpaulo		if (appl_data && in_data)
4325289549Srpaulo			*appl_data = openssl_get_appl_data(conn,
4326289549Srpaulo							   wpabuf_len(in_data));
4327289549Srpaulo	}
4328214734Srpaulo
4329281806Srpaulo	if (conn->invalid_hb_used) {
4330281806Srpaulo		wpa_printf(MSG_INFO, "TLS: Heartbeat attack detected - do not send response");
4331281806Srpaulo		if (appl_data) {
4332281806Srpaulo			wpabuf_free(*appl_data);
4333281806Srpaulo			*appl_data = NULL;
4334281806Srpaulo		}
4335281806Srpaulo		wpabuf_free(out_data);
4336281806Srpaulo		return NULL;
4337281806Srpaulo	}
4338281806Srpaulo
4339189251Ssam	return out_data;
4340189251Ssam}
4341189251Ssam
4342189251Ssam
4343214734Srpaulostruct wpabuf *
4344214734Srpaulotls_connection_handshake(void *ssl_ctx, struct tls_connection *conn,
4345214734Srpaulo			 const struct wpabuf *in_data,
4346214734Srpaulo			 struct wpabuf **appl_data)
4347189251Ssam{
4348346981Scy	return openssl_connection_handshake(conn, in_data, appl_data);
4349214734Srpaulo}
4350214734Srpaulo
4351214734Srpaulo
4352214734Srpaulostruct wpabuf * tls_connection_server_handshake(void *tls_ctx,
4353214734Srpaulo						struct tls_connection *conn,
4354214734Srpaulo						const struct wpabuf *in_data,
4355214734Srpaulo						struct wpabuf **appl_data)
4356214734Srpaulo{
4357346981Scy	conn->server = 1;
4358346981Scy	return openssl_connection_handshake(conn, in_data, appl_data);
4359214734Srpaulo}
4360214734Srpaulo
4361214734Srpaulo
4362214734Srpaulostruct wpabuf * tls_connection_encrypt(void *tls_ctx,
4363214734Srpaulo				       struct tls_connection *conn,
4364214734Srpaulo				       const struct wpabuf *in_data)
4365214734Srpaulo{
4366189251Ssam	int res;
4367214734Srpaulo	struct wpabuf *buf;
4368189251Ssam
4369189251Ssam	if (conn == NULL)
4370214734Srpaulo		return NULL;
4371189251Ssam
4372189251Ssam	/* Give plaintext data for OpenSSL to encrypt into the TLS tunnel. */
4373189251Ssam	if ((res = BIO_reset(conn->ssl_in)) < 0 ||
4374189251Ssam	    (res = BIO_reset(conn->ssl_out)) < 0) {
4375189251Ssam		tls_show_errors(MSG_INFO, __func__, "BIO_reset failed");
4376214734Srpaulo		return NULL;
4377189251Ssam	}
4378214734Srpaulo	res = SSL_write(conn->ssl, wpabuf_head(in_data), wpabuf_len(in_data));
4379189251Ssam	if (res < 0) {
4380189251Ssam		tls_show_errors(MSG_INFO, __func__,
4381189251Ssam				"Encryption failed - SSL_write");
4382214734Srpaulo		return NULL;
4383189251Ssam	}
4384189251Ssam
4385189251Ssam	/* Read encrypted data to be sent to the server */
4386214734Srpaulo	buf = wpabuf_alloc(wpabuf_len(in_data) + 300);
4387214734Srpaulo	if (buf == NULL)
4388214734Srpaulo		return NULL;
4389214734Srpaulo	res = BIO_read(conn->ssl_out, wpabuf_mhead(buf), wpabuf_size(buf));
4390189251Ssam	if (res < 0) {
4391189251Ssam		tls_show_errors(MSG_INFO, __func__,
4392189251Ssam				"Encryption failed - BIO_read");
4393214734Srpaulo		wpabuf_free(buf);
4394214734Srpaulo		return NULL;
4395189251Ssam	}
4396214734Srpaulo	wpabuf_put(buf, res);
4397189251Ssam
4398214734Srpaulo	return buf;
4399189251Ssam}
4400189251Ssam
4401189251Ssam
4402214734Srpaulostruct wpabuf * tls_connection_decrypt(void *tls_ctx,
4403214734Srpaulo				       struct tls_connection *conn,
4404214734Srpaulo				       const struct wpabuf *in_data)
4405189251Ssam{
4406189251Ssam	int res;
4407214734Srpaulo	struct wpabuf *buf;
4408189251Ssam
4409189251Ssam	/* Give encrypted data from TLS tunnel for OpenSSL to decrypt. */
4410214734Srpaulo	res = BIO_write(conn->ssl_in, wpabuf_head(in_data),
4411214734Srpaulo			wpabuf_len(in_data));
4412189251Ssam	if (res < 0) {
4413189251Ssam		tls_show_errors(MSG_INFO, __func__,
4414189251Ssam				"Decryption failed - BIO_write");
4415214734Srpaulo		return NULL;
4416189251Ssam	}
4417189251Ssam	if (BIO_reset(conn->ssl_out) < 0) {
4418189251Ssam		tls_show_errors(MSG_INFO, __func__, "BIO_reset failed");
4419214734Srpaulo		return NULL;
4420189251Ssam	}
4421189251Ssam
4422189251Ssam	/* Read decrypted data for further processing */
4423214734Srpaulo	/*
4424214734Srpaulo	 * Even though we try to disable TLS compression, it is possible that
4425214734Srpaulo	 * this cannot be done with all TLS libraries. Add extra buffer space
4426214734Srpaulo	 * to handle the possibility of the decrypted data being longer than
4427214734Srpaulo	 * input data.
4428214734Srpaulo	 */
4429214734Srpaulo	buf = wpabuf_alloc((wpabuf_len(in_data) + 500) * 3);
4430214734Srpaulo	if (buf == NULL)
4431214734Srpaulo		return NULL;
4432214734Srpaulo	res = SSL_read(conn->ssl, wpabuf_mhead(buf), wpabuf_size(buf));
4433189251Ssam	if (res < 0) {
4434189251Ssam		tls_show_errors(MSG_INFO, __func__,
4435189251Ssam				"Decryption failed - SSL_read");
4436214734Srpaulo		wpabuf_free(buf);
4437214734Srpaulo		return NULL;
4438189251Ssam	}
4439214734Srpaulo	wpabuf_put(buf, res);
4440189251Ssam
4441281806Srpaulo	if (conn->invalid_hb_used) {
4442281806Srpaulo		wpa_printf(MSG_INFO, "TLS: Heartbeat attack detected - do not send response");
4443281806Srpaulo		wpabuf_free(buf);
4444281806Srpaulo		return NULL;
4445281806Srpaulo	}
4446281806Srpaulo
4447214734Srpaulo	return buf;
4448189251Ssam}
4449189251Ssam
4450189251Ssam
4451189251Ssamint tls_connection_resumed(void *ssl_ctx, struct tls_connection *conn)
4452189251Ssam{
4453346981Scy	return conn ? SSL_session_reused(conn->ssl) : 0;
4454189251Ssam}
4455189251Ssam
4456189251Ssam
4457189251Ssamint tls_connection_set_cipher_list(void *tls_ctx, struct tls_connection *conn,
4458189251Ssam				   u8 *ciphers)
4459189251Ssam{
4460337817Scy	char buf[500], *pos, *end;
4461189251Ssam	u8 *c;
4462189251Ssam	int ret;
4463189251Ssam
4464189251Ssam	if (conn == NULL || conn->ssl == NULL || ciphers == NULL)
4465189251Ssam		return -1;
4466189251Ssam
4467189251Ssam	buf[0] = '\0';
4468189251Ssam	pos = buf;
4469189251Ssam	end = pos + sizeof(buf);
4470189251Ssam
4471189251Ssam	c = ciphers;
4472189251Ssam	while (*c != TLS_CIPHER_NONE) {
4473189251Ssam		const char *suite;
4474189251Ssam
4475189251Ssam		switch (*c) {
4476189251Ssam		case TLS_CIPHER_RC4_SHA:
4477189251Ssam			suite = "RC4-SHA";
4478189251Ssam			break;
4479189251Ssam		case TLS_CIPHER_AES128_SHA:
4480189251Ssam			suite = "AES128-SHA";
4481189251Ssam			break;
4482189251Ssam		case TLS_CIPHER_RSA_DHE_AES128_SHA:
4483189251Ssam			suite = "DHE-RSA-AES128-SHA";
4484189251Ssam			break;
4485189251Ssam		case TLS_CIPHER_ANON_DH_AES128_SHA:
4486189251Ssam			suite = "ADH-AES128-SHA";
4487189251Ssam			break;
4488337817Scy		case TLS_CIPHER_RSA_DHE_AES256_SHA:
4489337817Scy			suite = "DHE-RSA-AES256-SHA";
4490337817Scy			break;
4491337817Scy		case TLS_CIPHER_AES256_SHA:
4492337817Scy			suite = "AES256-SHA";
4493337817Scy			break;
4494189251Ssam		default:
4495189251Ssam			wpa_printf(MSG_DEBUG, "TLS: Unsupported "
4496189251Ssam				   "cipher selection: %d", *c);
4497189251Ssam			return -1;
4498189251Ssam		}
4499189251Ssam		ret = os_snprintf(pos, end - pos, ":%s", suite);
4500281806Srpaulo		if (os_snprintf_error(end - pos, ret))
4501189251Ssam			break;
4502189251Ssam		pos += ret;
4503189251Ssam
4504189251Ssam		c++;
4505189251Ssam	}
4506351611Scy	if (!buf[0]) {
4507351611Scy		wpa_printf(MSG_DEBUG, "OpenSSL: No ciphers listed");
4508351611Scy		return -1;
4509351611Scy	}
4510189251Ssam
4511189251Ssam	wpa_printf(MSG_DEBUG, "OpenSSL: cipher suites: %s", buf + 1);
4512189251Ssam
4513337817Scy#if OPENSSL_VERSION_NUMBER >= 0x10100000L && !defined(LIBRESSL_VERSION_NUMBER)
4514351611Scy#ifdef EAP_FAST_OR_TEAP
4515289549Srpaulo	if (os_strstr(buf, ":ADH-")) {
4516289549Srpaulo		/*
4517289549Srpaulo		 * Need to drop to security level 0 to allow anonymous
4518289549Srpaulo		 * cipher suites for EAP-FAST.
4519289549Srpaulo		 */
4520289549Srpaulo		SSL_set_security_level(conn->ssl, 0);
4521289549Srpaulo	} else if (SSL_get_security_level(conn->ssl) == 0) {
4522289549Srpaulo		/* Force at least security level 1 */
4523289549Srpaulo		SSL_set_security_level(conn->ssl, 1);
4524289549Srpaulo	}
4525351611Scy#endif /* EAP_FAST_OR_TEAP */
4526289549Srpaulo#endif
4527289549Srpaulo
4528189251Ssam	if (SSL_set_cipher_list(conn->ssl, buf + 1) != 1) {
4529189251Ssam		tls_show_errors(MSG_INFO, __func__,
4530189251Ssam				"Cipher suite configuration failed");
4531189251Ssam		return -1;
4532189251Ssam	}
4533189251Ssam
4534189251Ssam	return 0;
4535189251Ssam}
4536189251Ssam
4537189251Ssam
4538289549Srpauloint tls_get_version(void *ssl_ctx, struct tls_connection *conn,
4539289549Srpaulo		    char *buf, size_t buflen)
4540289549Srpaulo{
4541289549Srpaulo	const char *name;
4542289549Srpaulo	if (conn == NULL || conn->ssl == NULL)
4543289549Srpaulo		return -1;
4544289549Srpaulo
4545289549Srpaulo	name = SSL_get_version(conn->ssl);
4546289549Srpaulo	if (name == NULL)
4547289549Srpaulo		return -1;
4548289549Srpaulo
4549289549Srpaulo	os_strlcpy(buf, name, buflen);
4550289549Srpaulo	return 0;
4551289549Srpaulo}
4552289549Srpaulo
4553289549Srpaulo
4554189251Ssamint tls_get_cipher(void *ssl_ctx, struct tls_connection *conn,
4555189251Ssam		   char *buf, size_t buflen)
4556189251Ssam{
4557189251Ssam	const char *name;
4558189251Ssam	if (conn == NULL || conn->ssl == NULL)
4559189251Ssam		return -1;
4560189251Ssam
4561189251Ssam	name = SSL_get_cipher(conn->ssl);
4562189251Ssam	if (name == NULL)
4563189251Ssam		return -1;
4564189251Ssam
4565189251Ssam	os_strlcpy(buf, name, buflen);
4566189251Ssam	return 0;
4567189251Ssam}
4568189251Ssam
4569189251Ssam
4570189251Ssamint tls_connection_enable_workaround(void *ssl_ctx,
4571189251Ssam				     struct tls_connection *conn)
4572189251Ssam{
4573189251Ssam	SSL_set_options(conn->ssl, SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS);
4574189251Ssam
4575189251Ssam	return 0;
4576189251Ssam}
4577189251Ssam
4578189251Ssam
4579351611Scy#ifdef EAP_FAST_OR_TEAP
4580189251Ssam/* ClientHello TLS extensions require a patch to openssl, so this function is
4581189251Ssam * commented out unless explicitly needed for EAP-FAST in order to be able to
4582189251Ssam * build this file with unmodified openssl. */
4583189251Ssamint tls_connection_client_hello_ext(void *ssl_ctx, struct tls_connection *conn,
4584189251Ssam				    int ext_type, const u8 *data,
4585189251Ssam				    size_t data_len)
4586189251Ssam{
4587189251Ssam	if (conn == NULL || conn->ssl == NULL || ext_type != 35)
4588189251Ssam		return -1;
4589189251Ssam
4590189251Ssam	if (SSL_set_session_ticket_ext(conn->ssl, (void *) data,
4591189251Ssam				       data_len) != 1)
4592189251Ssam		return -1;
4593189251Ssam
4594189251Ssam	return 0;
4595189251Ssam}
4596351611Scy#endif /* EAP_FAST_OR_TEAP */
4597189251Ssam
4598189251Ssam
4599189251Ssamint tls_connection_get_failed(void *ssl_ctx, struct tls_connection *conn)
4600189251Ssam{
4601189251Ssam	if (conn == NULL)
4602189251Ssam		return -1;
4603189251Ssam	return conn->failed;
4604189251Ssam}
4605189251Ssam
4606189251Ssam
4607189251Ssamint tls_connection_get_read_alerts(void *ssl_ctx, struct tls_connection *conn)
4608189251Ssam{
4609189251Ssam	if (conn == NULL)
4610189251Ssam		return -1;
4611189251Ssam	return conn->read_alerts;
4612189251Ssam}
4613189251Ssam
4614189251Ssam
4615189251Ssamint tls_connection_get_write_alerts(void *ssl_ctx, struct tls_connection *conn)
4616189251Ssam{
4617189251Ssam	if (conn == NULL)
4618189251Ssam		return -1;
4619189251Ssam	return conn->write_alerts;
4620189251Ssam}
4621189251Ssam
4622189251Ssam
4623281806Srpaulo#ifdef HAVE_OCSP
4624281806Srpaulo
4625281806Srpaulostatic void ocsp_debug_print_resp(OCSP_RESPONSE *rsp)
4626281806Srpaulo{
4627281806Srpaulo#ifndef CONFIG_NO_STDOUT_DEBUG
4628281806Srpaulo	BIO *out;
4629281806Srpaulo	size_t rlen;
4630281806Srpaulo	char *txt;
4631281806Srpaulo	int res;
4632281806Srpaulo
4633281806Srpaulo	if (wpa_debug_level > MSG_DEBUG)
4634281806Srpaulo		return;
4635281806Srpaulo
4636281806Srpaulo	out = BIO_new(BIO_s_mem());
4637281806Srpaulo	if (!out)
4638281806Srpaulo		return;
4639281806Srpaulo
4640281806Srpaulo	OCSP_RESPONSE_print(out, rsp, 0);
4641281806Srpaulo	rlen = BIO_ctrl_pending(out);
4642281806Srpaulo	txt = os_malloc(rlen + 1);
4643281806Srpaulo	if (!txt) {
4644281806Srpaulo		BIO_free(out);
4645281806Srpaulo		return;
4646281806Srpaulo	}
4647281806Srpaulo
4648281806Srpaulo	res = BIO_read(out, txt, rlen);
4649281806Srpaulo	if (res > 0) {
4650281806Srpaulo		txt[res] = '\0';
4651281806Srpaulo		wpa_printf(MSG_DEBUG, "OpenSSL: OCSP Response\n%s", txt);
4652281806Srpaulo	}
4653281806Srpaulo	os_free(txt);
4654281806Srpaulo	BIO_free(out);
4655281806Srpaulo#endif /* CONFIG_NO_STDOUT_DEBUG */
4656281806Srpaulo}
4657281806Srpaulo
4658281806Srpaulo
4659281806Srpaulostatic void debug_print_cert(X509 *cert, const char *title)
4660281806Srpaulo{
4661281806Srpaulo#ifndef CONFIG_NO_STDOUT_DEBUG
4662281806Srpaulo	BIO *out;
4663281806Srpaulo	size_t rlen;
4664281806Srpaulo	char *txt;
4665281806Srpaulo	int res;
4666281806Srpaulo
4667281806Srpaulo	if (wpa_debug_level > MSG_DEBUG)
4668281806Srpaulo		return;
4669281806Srpaulo
4670281806Srpaulo	out = BIO_new(BIO_s_mem());
4671281806Srpaulo	if (!out)
4672281806Srpaulo		return;
4673281806Srpaulo
4674281806Srpaulo	X509_print(out, cert);
4675281806Srpaulo	rlen = BIO_ctrl_pending(out);
4676281806Srpaulo	txt = os_malloc(rlen + 1);
4677281806Srpaulo	if (!txt) {
4678281806Srpaulo		BIO_free(out);
4679281806Srpaulo		return;
4680281806Srpaulo	}
4681281806Srpaulo
4682281806Srpaulo	res = BIO_read(out, txt, rlen);
4683281806Srpaulo	if (res > 0) {
4684281806Srpaulo		txt[res] = '\0';
4685281806Srpaulo		wpa_printf(MSG_DEBUG, "OpenSSL: %s\n%s", title, txt);
4686281806Srpaulo	}
4687281806Srpaulo	os_free(txt);
4688281806Srpaulo
4689281806Srpaulo	BIO_free(out);
4690281806Srpaulo#endif /* CONFIG_NO_STDOUT_DEBUG */
4691281806Srpaulo}
4692281806Srpaulo
4693281806Srpaulo
4694281806Srpaulostatic int ocsp_resp_cb(SSL *s, void *arg)
4695281806Srpaulo{
4696281806Srpaulo	struct tls_connection *conn = arg;
4697281806Srpaulo	const unsigned char *p;
4698346981Scy	int len, status, reason, res;
4699281806Srpaulo	OCSP_RESPONSE *rsp;
4700281806Srpaulo	OCSP_BASICRESP *basic;
4701281806Srpaulo	OCSP_CERTID *id;
4702281806Srpaulo	ASN1_GENERALIZEDTIME *produced_at, *this_update, *next_update;
4703281806Srpaulo	X509_STORE *store;
4704281806Srpaulo	STACK_OF(X509) *certs = NULL;
4705281806Srpaulo
4706281806Srpaulo	len = SSL_get_tlsext_status_ocsp_resp(s, &p);
4707281806Srpaulo	if (!p) {
4708281806Srpaulo		wpa_printf(MSG_DEBUG, "OpenSSL: No OCSP response received");
4709281806Srpaulo		return (conn->flags & TLS_CONN_REQUIRE_OCSP) ? 0 : 1;
4710281806Srpaulo	}
4711281806Srpaulo
4712281806Srpaulo	wpa_hexdump(MSG_DEBUG, "OpenSSL: OCSP response", p, len);
4713281806Srpaulo
4714281806Srpaulo	rsp = d2i_OCSP_RESPONSE(NULL, &p, len);
4715281806Srpaulo	if (!rsp) {
4716281806Srpaulo		wpa_printf(MSG_INFO, "OpenSSL: Failed to parse OCSP response");
4717281806Srpaulo		return 0;
4718281806Srpaulo	}
4719281806Srpaulo
4720281806Srpaulo	ocsp_debug_print_resp(rsp);
4721281806Srpaulo
4722281806Srpaulo	status = OCSP_response_status(rsp);
4723281806Srpaulo	if (status != OCSP_RESPONSE_STATUS_SUCCESSFUL) {
4724281806Srpaulo		wpa_printf(MSG_INFO, "OpenSSL: OCSP responder error %d (%s)",
4725281806Srpaulo			   status, OCSP_response_status_str(status));
4726281806Srpaulo		return 0;
4727281806Srpaulo	}
4728281806Srpaulo
4729281806Srpaulo	basic = OCSP_response_get1_basic(rsp);
4730281806Srpaulo	if (!basic) {
4731281806Srpaulo		wpa_printf(MSG_INFO, "OpenSSL: Could not find BasicOCSPResponse");
4732281806Srpaulo		return 0;
4733281806Srpaulo	}
4734281806Srpaulo
4735281806Srpaulo	store = SSL_CTX_get_cert_store(conn->ssl_ctx);
4736281806Srpaulo	if (conn->peer_issuer) {
4737281806Srpaulo		debug_print_cert(conn->peer_issuer, "Add OCSP issuer");
4738281806Srpaulo
4739281806Srpaulo		if (X509_STORE_add_cert(store, conn->peer_issuer) != 1) {
4740281806Srpaulo			tls_show_errors(MSG_INFO, __func__,
4741281806Srpaulo					"OpenSSL: Could not add issuer to certificate store");
4742281806Srpaulo		}
4743281806Srpaulo		certs = sk_X509_new_null();
4744281806Srpaulo		if (certs) {
4745281806Srpaulo			X509 *cert;
4746281806Srpaulo			cert = X509_dup(conn->peer_issuer);
4747281806Srpaulo			if (cert && !sk_X509_push(certs, cert)) {
4748281806Srpaulo				tls_show_errors(
4749281806Srpaulo					MSG_INFO, __func__,
4750281806Srpaulo					"OpenSSL: Could not add issuer to OCSP responder trust store");
4751281806Srpaulo				X509_free(cert);
4752281806Srpaulo				sk_X509_free(certs);
4753281806Srpaulo				certs = NULL;
4754281806Srpaulo			}
4755281806Srpaulo			if (certs && conn->peer_issuer_issuer) {
4756281806Srpaulo				cert = X509_dup(conn->peer_issuer_issuer);
4757281806Srpaulo				if (cert && !sk_X509_push(certs, cert)) {
4758281806Srpaulo					tls_show_errors(
4759281806Srpaulo						MSG_INFO, __func__,
4760281806Srpaulo						"OpenSSL: Could not add issuer's issuer to OCSP responder trust store");
4761281806Srpaulo					X509_free(cert);
4762281806Srpaulo				}
4763281806Srpaulo			}
4764281806Srpaulo		}
4765281806Srpaulo	}
4766281806Srpaulo
4767281806Srpaulo	status = OCSP_basic_verify(basic, certs, store, OCSP_TRUSTOTHER);
4768281806Srpaulo	sk_X509_pop_free(certs, X509_free);
4769281806Srpaulo	if (status <= 0) {
4770281806Srpaulo		tls_show_errors(MSG_INFO, __func__,
4771281806Srpaulo				"OpenSSL: OCSP response failed verification");
4772281806Srpaulo		OCSP_BASICRESP_free(basic);
4773281806Srpaulo		OCSP_RESPONSE_free(rsp);
4774281806Srpaulo		return 0;
4775281806Srpaulo	}
4776281806Srpaulo
4777281806Srpaulo	wpa_printf(MSG_DEBUG, "OpenSSL: OCSP response verification succeeded");
4778281806Srpaulo
4779281806Srpaulo	if (!conn->peer_cert) {
4780281806Srpaulo		wpa_printf(MSG_DEBUG, "OpenSSL: Peer certificate not available for OCSP status check");
4781281806Srpaulo		OCSP_BASICRESP_free(basic);
4782281806Srpaulo		OCSP_RESPONSE_free(rsp);
4783281806Srpaulo		return 0;
4784281806Srpaulo	}
4785281806Srpaulo
4786281806Srpaulo	if (!conn->peer_issuer) {
4787281806Srpaulo		wpa_printf(MSG_DEBUG, "OpenSSL: Peer issuer certificate not available for OCSP status check");
4788281806Srpaulo		OCSP_BASICRESP_free(basic);
4789281806Srpaulo		OCSP_RESPONSE_free(rsp);
4790281806Srpaulo		return 0;
4791281806Srpaulo	}
4792281806Srpaulo
4793346981Scy	id = OCSP_cert_to_id(EVP_sha256(), conn->peer_cert, conn->peer_issuer);
4794281806Srpaulo	if (!id) {
4795346981Scy		wpa_printf(MSG_DEBUG,
4796346981Scy			   "OpenSSL: Could not create OCSP certificate identifier (SHA256)");
4797281806Srpaulo		OCSP_BASICRESP_free(basic);
4798281806Srpaulo		OCSP_RESPONSE_free(rsp);
4799281806Srpaulo		return 0;
4800281806Srpaulo	}
4801281806Srpaulo
4802346981Scy	res = OCSP_resp_find_status(basic, id, &status, &reason, &produced_at,
4803346981Scy				    &this_update, &next_update);
4804346981Scy	if (!res) {
4805351611Scy		OCSP_CERTID_free(id);
4806346981Scy		id = OCSP_cert_to_id(NULL, conn->peer_cert, conn->peer_issuer);
4807346981Scy		if (!id) {
4808346981Scy			wpa_printf(MSG_DEBUG,
4809346981Scy				   "OpenSSL: Could not create OCSP certificate identifier (SHA1)");
4810346981Scy			OCSP_BASICRESP_free(basic);
4811346981Scy			OCSP_RESPONSE_free(rsp);
4812346981Scy			return 0;
4813346981Scy		}
4814346981Scy
4815346981Scy		res = OCSP_resp_find_status(basic, id, &status, &reason,
4816346981Scy					    &produced_at, &this_update,
4817346981Scy					    &next_update);
4818346981Scy	}
4819346981Scy
4820346981Scy	if (!res) {
4821281806Srpaulo		wpa_printf(MSG_INFO, "OpenSSL: Could not find current server certificate from OCSP response%s",
4822281806Srpaulo			   (conn->flags & TLS_CONN_REQUIRE_OCSP) ? "" :
4823281806Srpaulo			   " (OCSP not required)");
4824337817Scy		OCSP_CERTID_free(id);
4825281806Srpaulo		OCSP_BASICRESP_free(basic);
4826281806Srpaulo		OCSP_RESPONSE_free(rsp);
4827281806Srpaulo		return (conn->flags & TLS_CONN_REQUIRE_OCSP) ? 0 : 1;
4828281806Srpaulo	}
4829337817Scy	OCSP_CERTID_free(id);
4830281806Srpaulo
4831281806Srpaulo	if (!OCSP_check_validity(this_update, next_update, 5 * 60, -1)) {
4832281806Srpaulo		tls_show_errors(MSG_INFO, __func__,
4833281806Srpaulo				"OpenSSL: OCSP status times invalid");
4834281806Srpaulo		OCSP_BASICRESP_free(basic);
4835281806Srpaulo		OCSP_RESPONSE_free(rsp);
4836281806Srpaulo		return 0;
4837281806Srpaulo	}
4838281806Srpaulo
4839281806Srpaulo	OCSP_BASICRESP_free(basic);
4840281806Srpaulo	OCSP_RESPONSE_free(rsp);
4841281806Srpaulo
4842281806Srpaulo	wpa_printf(MSG_DEBUG, "OpenSSL: OCSP status for server certificate: %s",
4843281806Srpaulo		   OCSP_cert_status_str(status));
4844281806Srpaulo
4845281806Srpaulo	if (status == V_OCSP_CERTSTATUS_GOOD)
4846281806Srpaulo		return 1;
4847281806Srpaulo	if (status == V_OCSP_CERTSTATUS_REVOKED)
4848281806Srpaulo		return 0;
4849281806Srpaulo	if (conn->flags & TLS_CONN_REQUIRE_OCSP) {
4850281806Srpaulo		wpa_printf(MSG_DEBUG, "OpenSSL: OCSP status unknown, but OCSP required");
4851281806Srpaulo		return 0;
4852281806Srpaulo	}
4853281806Srpaulo	wpa_printf(MSG_DEBUG, "OpenSSL: OCSP status unknown, but OCSP was not required, so allow connection to continue");
4854281806Srpaulo	return 1;
4855281806Srpaulo}
4856281806Srpaulo
4857281806Srpaulo
4858281806Srpaulostatic int ocsp_status_cb(SSL *s, void *arg)
4859281806Srpaulo{
4860281806Srpaulo	char *tmp;
4861281806Srpaulo	char *resp;
4862281806Srpaulo	size_t len;
4863281806Srpaulo
4864281806Srpaulo	if (tls_global->ocsp_stapling_response == NULL) {
4865281806Srpaulo		wpa_printf(MSG_DEBUG, "OpenSSL: OCSP status callback - no response configured");
4866281806Srpaulo		return SSL_TLSEXT_ERR_OK;
4867281806Srpaulo	}
4868281806Srpaulo
4869281806Srpaulo	resp = os_readfile(tls_global->ocsp_stapling_response, &len);
4870281806Srpaulo	if (resp == NULL) {
4871281806Srpaulo		wpa_printf(MSG_DEBUG, "OpenSSL: OCSP status callback - could not read response file");
4872281806Srpaulo		/* TODO: Build OCSPResponse with responseStatus = internalError
4873281806Srpaulo		 */
4874281806Srpaulo		return SSL_TLSEXT_ERR_OK;
4875281806Srpaulo	}
4876281806Srpaulo	wpa_printf(MSG_DEBUG, "OpenSSL: OCSP status callback - send cached response");
4877281806Srpaulo	tmp = OPENSSL_malloc(len);
4878281806Srpaulo	if (tmp == NULL) {
4879281806Srpaulo		os_free(resp);
4880281806Srpaulo		return SSL_TLSEXT_ERR_ALERT_FATAL;
4881281806Srpaulo	}
4882281806Srpaulo
4883281806Srpaulo	os_memcpy(tmp, resp, len);
4884281806Srpaulo	os_free(resp);
4885281806Srpaulo	SSL_set_tlsext_status_ocsp_resp(s, tmp, len);
4886281806Srpaulo
4887281806Srpaulo	return SSL_TLSEXT_ERR_OK;
4888281806Srpaulo}
4889281806Srpaulo
4890281806Srpaulo#endif /* HAVE_OCSP */
4891281806Srpaulo
4892281806Srpaulo
4893189251Ssamint tls_connection_set_params(void *tls_ctx, struct tls_connection *conn,
4894189251Ssam			      const struct tls_connection_params *params)
4895189251Ssam{
4896289549Srpaulo	struct tls_data *data = tls_ctx;
4897189251Ssam	int ret;
4898189251Ssam	unsigned long err;
4899281806Srpaulo	int can_pkcs11 = 0;
4900281806Srpaulo	const char *key_id = params->key_id;
4901281806Srpaulo	const char *cert_id = params->cert_id;
4902281806Srpaulo	const char *ca_cert_id = params->ca_cert_id;
4903281806Srpaulo	const char *engine_id = params->engine ? params->engine_id : NULL;
4904346981Scy	const char *ciphers;
4905189251Ssam
4906189251Ssam	if (conn == NULL)
4907189251Ssam		return -1;
4908189251Ssam
4909337817Scy	if (params->flags & TLS_CONN_REQUIRE_OCSP_ALL) {
4910337817Scy		wpa_printf(MSG_INFO,
4911337817Scy			   "OpenSSL: ocsp=3 not supported");
4912337817Scy		return -1;
4913337817Scy	}
4914337817Scy
4915281806Srpaulo	/*
4916281806Srpaulo	 * If the engine isn't explicitly configured, and any of the
4917281806Srpaulo	 * cert/key fields are actually PKCS#11 URIs, then automatically
4918281806Srpaulo	 * use the PKCS#11 ENGINE.
4919281806Srpaulo	 */
4920281806Srpaulo	if (!engine_id || os_strcmp(engine_id, "pkcs11") == 0)
4921281806Srpaulo		can_pkcs11 = 1;
4922281806Srpaulo
4923281806Srpaulo	if (!key_id && params->private_key && can_pkcs11 &&
4924281806Srpaulo	    os_strncmp(params->private_key, "pkcs11:", 7) == 0) {
4925281806Srpaulo		can_pkcs11 = 2;
4926281806Srpaulo		key_id = params->private_key;
4927281806Srpaulo	}
4928281806Srpaulo
4929281806Srpaulo	if (!cert_id && params->client_cert && can_pkcs11 &&
4930281806Srpaulo	    os_strncmp(params->client_cert, "pkcs11:", 7) == 0) {
4931281806Srpaulo		can_pkcs11 = 2;
4932281806Srpaulo		cert_id = params->client_cert;
4933281806Srpaulo	}
4934281806Srpaulo
4935281806Srpaulo	if (!ca_cert_id && params->ca_cert && can_pkcs11 &&
4936281806Srpaulo	    os_strncmp(params->ca_cert, "pkcs11:", 7) == 0) {
4937281806Srpaulo		can_pkcs11 = 2;
4938281806Srpaulo		ca_cert_id = params->ca_cert;
4939281806Srpaulo	}
4940281806Srpaulo
4941281806Srpaulo	/* If we need to automatically enable the PKCS#11 ENGINE, do so. */
4942281806Srpaulo	if (can_pkcs11 == 2 && !engine_id)
4943281806Srpaulo		engine_id = "pkcs11";
4944281806Srpaulo
4945289549Srpaulo#if defined(EAP_FAST) || defined(EAP_FAST_DYNAMIC) || defined(EAP_SERVER_FAST)
4946346981Scy#if OPENSSL_VERSION_NUMBER < 0x10100000L || defined(LIBRESSL_VERSION_NUMBER)
4947281806Srpaulo	if (params->flags & TLS_CONN_EAP_FAST) {
4948281806Srpaulo		wpa_printf(MSG_DEBUG,
4949281806Srpaulo			   "OpenSSL: Use TLSv1_method() for EAP-FAST");
4950281806Srpaulo		if (SSL_set_ssl_method(conn->ssl, TLSv1_method()) != 1) {
4951281806Srpaulo			tls_show_errors(MSG_INFO, __func__,
4952281806Srpaulo					"Failed to set TLSv1_method() for EAP-FAST");
4953281806Srpaulo			return -1;
4954281806Srpaulo		}
4955281806Srpaulo	}
4956289549Srpaulo#endif
4957346981Scy#if OPENSSL_VERSION_NUMBER >= 0x10101000L
4958346981Scy#ifdef SSL_OP_NO_TLSv1_3
4959346981Scy	if (params->flags & TLS_CONN_EAP_FAST) {
4960346981Scy		/* Need to disable TLS v1.3 at least for now since OpenSSL 1.1.1
4961346981Scy		 * refuses to start the handshake with the modified ciphersuite
4962346981Scy		 * list (no TLS v1.3 ciphersuites included) for EAP-FAST. */
4963346981Scy		wpa_printf(MSG_DEBUG, "OpenSSL: Disable TLSv1.3 for EAP-FAST");
4964346981Scy		SSL_set_options(conn->ssl, SSL_OP_NO_TLSv1_3);
4965346981Scy	}
4966346981Scy#endif /* SSL_OP_NO_TLSv1_3 */
4967346981Scy#endif
4968289549Srpaulo#endif /* EAP_FAST || EAP_FAST_DYNAMIC || EAP_SERVER_FAST */
4969281806Srpaulo
4970189251Ssam	while ((err = ERR_get_error())) {
4971189251Ssam		wpa_printf(MSG_INFO, "%s: Clearing pending SSL error: %s",
4972189251Ssam			   __func__, ERR_error_string(err, NULL));
4973189251Ssam	}
4974189251Ssam
4975281806Srpaulo	if (engine_id) {
4976189251Ssam		wpa_printf(MSG_DEBUG, "SSL: Initializing TLS engine");
4977281806Srpaulo		ret = tls_engine_init(conn, engine_id, params->pin,
4978281806Srpaulo				      key_id, cert_id, ca_cert_id);
4979189251Ssam		if (ret)
4980189251Ssam			return ret;
4981189251Ssam	}
4982189251Ssam	if (tls_connection_set_subject_match(conn,
4983189251Ssam					     params->subject_match,
4984281806Srpaulo					     params->altsubject_match,
4985281806Srpaulo					     params->suffix_match,
4986346981Scy					     params->domain_match,
4987346981Scy					     params->check_cert_subject))
4988189251Ssam		return -1;
4989189251Ssam
4990281806Srpaulo	if (engine_id && ca_cert_id) {
4991289549Srpaulo		if (tls_connection_engine_ca_cert(data, conn, ca_cert_id))
4992189251Ssam			return TLS_SET_PARAMS_ENGINE_PRV_VERIFY_FAILED;
4993289549Srpaulo	} else if (tls_connection_ca_cert(data, conn, params->ca_cert,
4994189251Ssam					  params->ca_cert_blob,
4995189251Ssam					  params->ca_cert_blob_len,
4996189251Ssam					  params->ca_path))
4997189251Ssam		return -1;
4998189251Ssam
4999281806Srpaulo	if (engine_id && cert_id) {
5000281806Srpaulo		if (tls_connection_engine_client_cert(conn, cert_id))
5001189251Ssam			return TLS_SET_PARAMS_ENGINE_PRV_VERIFY_FAILED;
5002189251Ssam	} else if (tls_connection_client_cert(conn, params->client_cert,
5003189251Ssam					      params->client_cert_blob,
5004189251Ssam					      params->client_cert_blob_len))
5005189251Ssam		return -1;
5006189251Ssam
5007281806Srpaulo	if (engine_id && key_id) {
5008189251Ssam		wpa_printf(MSG_DEBUG, "TLS: Using private key from engine");
5009189251Ssam		if (tls_connection_engine_private_key(conn))
5010189251Ssam			return TLS_SET_PARAMS_ENGINE_PRV_VERIFY_FAILED;
5011289549Srpaulo	} else if (tls_connection_private_key(data, conn,
5012189251Ssam					      params->private_key,
5013189251Ssam					      params->private_key_passwd,
5014189251Ssam					      params->private_key_blob,
5015189251Ssam					      params->private_key_blob_len)) {
5016189251Ssam		wpa_printf(MSG_INFO, "TLS: Failed to load private key '%s'",
5017189251Ssam			   params->private_key);
5018189251Ssam		return -1;
5019189251Ssam	}
5020189251Ssam
5021189251Ssam	if (tls_connection_dh(conn, params->dh_file)) {
5022189251Ssam		wpa_printf(MSG_INFO, "TLS: Failed to load DH file '%s'",
5023189251Ssam			   params->dh_file);
5024189251Ssam		return -1;
5025189251Ssam	}
5026189251Ssam
5027346981Scy	ciphers = params->openssl_ciphers;
5028346981Scy#ifdef CONFIG_SUITEB
5029346981Scy#ifdef OPENSSL_IS_BORINGSSL
5030346981Scy	if (ciphers && os_strcmp(ciphers, "SUITEB192") == 0) {
5031346981Scy		/* BoringSSL removed support for SUITEB192, so need to handle
5032346981Scy		 * this with hardcoded ciphersuite and additional checks for
5033346981Scy		 * other parameters. */
5034346981Scy		ciphers = "ECDHE-ECDSA-AES256-GCM-SHA384";
5035346981Scy	}
5036346981Scy#endif /* OPENSSL_IS_BORINGSSL */
5037346981Scy#endif /* CONFIG_SUITEB */
5038346981Scy	if (ciphers && SSL_set_cipher_list(conn->ssl, ciphers) != 1) {
5039281806Srpaulo		wpa_printf(MSG_INFO,
5040281806Srpaulo			   "OpenSSL: Failed to set cipher string '%s'",
5041346981Scy			   ciphers);
5042281806Srpaulo		return -1;
5043281806Srpaulo	}
5044281806Srpaulo
5045346981Scy	if (!params->openssl_ecdh_curves) {
5046346981Scy#ifndef OPENSSL_IS_BORINGSSL
5047346981Scy#ifndef OPENSSL_NO_EC
5048346981Scy#if (OPENSSL_VERSION_NUMBER >= 0x10002000L) && \
5049346981Scy	(OPENSSL_VERSION_NUMBER < 0x10100000L)
5050346981Scy		if (SSL_set_ecdh_auto(conn->ssl, 1) != 1) {
5051346981Scy			wpa_printf(MSG_INFO,
5052346981Scy				   "OpenSSL: Failed to set ECDH curves to auto");
5053346981Scy			return -1;
5054346981Scy		}
5055346981Scy#endif /* >= 1.0.2 && < 1.1.0 */
5056346981Scy#endif /* OPENSSL_NO_EC */
5057346981Scy#endif /* OPENSSL_IS_BORINGSSL */
5058346981Scy	} else if (params->openssl_ecdh_curves[0]) {
5059346981Scy#if defined(OPENSSL_IS_BORINGSSL) || (OPENSSL_VERSION_NUMBER < 0x10002000L)
5060346981Scy		wpa_printf(MSG_INFO,
5061346981Scy			"OpenSSL: ECDH configuration nnot supported");
5062346981Scy		return -1;
5063346981Scy#else /* OPENSSL_IS_BORINGSSL || < 1.0.2 */
5064346981Scy#ifndef OPENSSL_NO_EC
5065346981Scy		if (SSL_set1_curves_list(conn->ssl,
5066346981Scy					 params->openssl_ecdh_curves) != 1) {
5067346981Scy			wpa_printf(MSG_INFO,
5068346981Scy				   "OpenSSL: Failed to set ECDH curves '%s'",
5069346981Scy				   params->openssl_ecdh_curves);
5070346981Scy			return -1;
5071346981Scy		}
5072346981Scy#else /* OPENSSL_NO_EC */
5073346981Scy		wpa_printf(MSG_INFO, "OpenSSL: ECDH not supported");
5074346981Scy		return -1;
5075346981Scy#endif /* OPENSSL_NO_EC */
5076346981Scy#endif /* OPENSSL_IS_BORINGSSL */
5077346981Scy	}
5078252726Srpaulo
5079346981Scy	if (tls_set_conn_flags(conn, params->flags,
5080346981Scy			       params->openssl_ciphers) < 0)
5081346981Scy		return -1;
5082346981Scy
5083337817Scy#ifdef OPENSSL_IS_BORINGSSL
5084337817Scy	if (params->flags & TLS_CONN_REQUEST_OCSP) {
5085337817Scy		SSL_enable_ocsp_stapling(conn->ssl);
5086337817Scy	}
5087337817Scy#else /* OPENSSL_IS_BORINGSSL */
5088281806Srpaulo#ifdef HAVE_OCSP
5089281806Srpaulo	if (params->flags & TLS_CONN_REQUEST_OCSP) {
5090289549Srpaulo		SSL_CTX *ssl_ctx = data->ssl;
5091281806Srpaulo		SSL_set_tlsext_status_type(conn->ssl, TLSEXT_STATUSTYPE_ocsp);
5092281806Srpaulo		SSL_CTX_set_tlsext_status_cb(ssl_ctx, ocsp_resp_cb);
5093281806Srpaulo		SSL_CTX_set_tlsext_status_arg(ssl_ctx, conn);
5094281806Srpaulo	}
5095289549Srpaulo#else /* HAVE_OCSP */
5096289549Srpaulo	if (params->flags & TLS_CONN_REQUIRE_OCSP) {
5097289549Srpaulo		wpa_printf(MSG_INFO,
5098289549Srpaulo			   "OpenSSL: No OCSP support included - reject configuration");
5099289549Srpaulo		return -1;
5100289549Srpaulo	}
5101289549Srpaulo	if (params->flags & TLS_CONN_REQUEST_OCSP) {
5102289549Srpaulo		wpa_printf(MSG_DEBUG,
5103289549Srpaulo			   "OpenSSL: No OCSP support included - allow optional OCSP case to continue");
5104289549Srpaulo	}
5105281806Srpaulo#endif /* HAVE_OCSP */
5106337817Scy#endif /* OPENSSL_IS_BORINGSSL */
5107281806Srpaulo
5108252726Srpaulo	conn->flags = params->flags;
5109252726Srpaulo
5110289549Srpaulo	tls_get_errors(data);
5111189251Ssam
5112189251Ssam	return 0;
5113189251Ssam}
5114189251Ssam
5115189251Ssam
5116351611Scystatic void openssl_debug_dump_cipher_list(SSL_CTX *ssl_ctx)
5117351611Scy{
5118351611Scy	SSL *ssl;
5119351611Scy	int i;
5120351611Scy
5121351611Scy	ssl = SSL_new(ssl_ctx);
5122351611Scy	if (!ssl)
5123351611Scy		return;
5124351611Scy
5125351611Scy	wpa_printf(MSG_DEBUG,
5126351611Scy		   "OpenSSL: Enabled cipher suites in priority order");
5127351611Scy	for (i = 0; ; i++) {
5128351611Scy		const char *cipher;
5129351611Scy
5130351611Scy		cipher = SSL_get_cipher_list(ssl, i);
5131351611Scy		if (!cipher)
5132351611Scy			break;
5133351611Scy		wpa_printf(MSG_DEBUG, "Cipher %d: %s", i, cipher);
5134351611Scy	}
5135351611Scy
5136351611Scy	SSL_free(ssl);
5137351611Scy}
5138351611Scy
5139351611Scy
5140351611Scy#if !defined(LIBRESSL_VERSION_NUMBER) && !defined(BORINGSSL_API_VERSION)
5141351611Scy
5142351611Scystatic const char * openssl_pkey_type_str(const EVP_PKEY *pkey)
5143351611Scy{
5144351611Scy	if (!pkey)
5145351611Scy		return "NULL";
5146351611Scy	switch (EVP_PKEY_type(EVP_PKEY_id(pkey))) {
5147351611Scy	case EVP_PKEY_RSA:
5148351611Scy		return "RSA";
5149351611Scy	case EVP_PKEY_DSA:
5150351611Scy		return "DSA";
5151351611Scy	case EVP_PKEY_DH:
5152351611Scy		return "DH";
5153351611Scy	case EVP_PKEY_EC:
5154351611Scy		return "EC";
5155351611Scy	}
5156351611Scy	return "?";
5157351611Scy}
5158351611Scy
5159351611Scy
5160351611Scystatic void openssl_debug_dump_certificate(int i, X509 *cert)
5161351611Scy{
5162351611Scy	char buf[256];
5163351611Scy	EVP_PKEY *pkey;
5164351611Scy	ASN1_INTEGER *ser;
5165351611Scy	char serial_num[128];
5166351611Scy
5167351611Scy	X509_NAME_oneline(X509_get_subject_name(cert), buf, sizeof(buf));
5168351611Scy
5169351611Scy	ser = X509_get_serialNumber(cert);
5170351611Scy	if (ser)
5171351611Scy		wpa_snprintf_hex_uppercase(serial_num, sizeof(serial_num),
5172351611Scy					   ASN1_STRING_get0_data(ser),
5173351611Scy					   ASN1_STRING_length(ser));
5174351611Scy	else
5175351611Scy		serial_num[0] = '\0';
5176351611Scy
5177351611Scy	pkey = X509_get_pubkey(cert);
5178351611Scy	wpa_printf(MSG_DEBUG, "%d: %s (%s) %s", i, buf,
5179351611Scy		   openssl_pkey_type_str(pkey), serial_num);
5180351611Scy	EVP_PKEY_free(pkey);
5181351611Scy}
5182351611Scy
5183351611Scy
5184351611Scystatic void openssl_debug_dump_certificates(SSL_CTX *ssl_ctx)
5185351611Scy{
5186351611Scy	STACK_OF(X509) *certs;
5187351611Scy
5188351611Scy	wpa_printf(MSG_DEBUG, "OpenSSL: Configured certificate chain");
5189351611Scy	if (SSL_CTX_get0_chain_certs(ssl_ctx, &certs) == 1) {
5190351611Scy		int i;
5191351611Scy
5192351611Scy		for (i = sk_X509_num(certs); i > 0; i--)
5193351611Scy			openssl_debug_dump_certificate(i, sk_X509_value(certs,
5194351611Scy									i - 1));
5195351611Scy	}
5196351611Scy	openssl_debug_dump_certificate(0, SSL_CTX_get0_certificate(ssl_ctx));
5197351611Scy}
5198351611Scy
5199351611Scy#endif
5200351611Scy
5201351611Scy
5202351611Scystatic void openssl_debug_dump_certificate_chains(SSL_CTX *ssl_ctx)
5203351611Scy{
5204351611Scy#if !defined(LIBRESSL_VERSION_NUMBER) && !defined(BORINGSSL_API_VERSION)
5205351611Scy	int res;
5206351611Scy
5207351611Scy	for (res = SSL_CTX_set_current_cert(ssl_ctx, SSL_CERT_SET_FIRST);
5208351611Scy	     res == 1;
5209351611Scy	     res = SSL_CTX_set_current_cert(ssl_ctx, SSL_CERT_SET_NEXT))
5210351611Scy		openssl_debug_dump_certificates(ssl_ctx);
5211351611Scy
5212351611Scy	SSL_CTX_set_current_cert(ssl_ctx, SSL_CERT_SET_FIRST);
5213351611Scy#endif
5214351611Scy}
5215351611Scy
5216351611Scy
5217351611Scystatic void openssl_debug_dump_ctx(SSL_CTX *ssl_ctx)
5218351611Scy{
5219351611Scy	openssl_debug_dump_cipher_list(ssl_ctx);
5220351611Scy	openssl_debug_dump_certificate_chains(ssl_ctx);
5221351611Scy}
5222351611Scy
5223351611Scy
5224189251Ssamint tls_global_set_params(void *tls_ctx,
5225189251Ssam			  const struct tls_connection_params *params)
5226189251Ssam{
5227289549Srpaulo	struct tls_data *data = tls_ctx;
5228289549Srpaulo	SSL_CTX *ssl_ctx = data->ssl;
5229189251Ssam	unsigned long err;
5230189251Ssam
5231189251Ssam	while ((err = ERR_get_error())) {
5232189251Ssam		wpa_printf(MSG_INFO, "%s: Clearing pending SSL error: %s",
5233189251Ssam			   __func__, ERR_error_string(err, NULL));
5234189251Ssam	}
5235189251Ssam
5236346981Scy	os_free(data->check_cert_subject);
5237346981Scy	data->check_cert_subject = NULL;
5238346981Scy	if (params->check_cert_subject) {
5239346981Scy		data->check_cert_subject =
5240346981Scy			os_strdup(params->check_cert_subject);
5241346981Scy		if (!data->check_cert_subject)
5242346981Scy			return -1;
5243346981Scy	}
5244346981Scy
5245289549Srpaulo	if (tls_global_ca_cert(data, params->ca_cert) ||
5246289549Srpaulo	    tls_global_client_cert(data, params->client_cert) ||
5247289549Srpaulo	    tls_global_private_key(data, params->private_key,
5248289549Srpaulo				   params->private_key_passwd) ||
5249351611Scy	    tls_global_client_cert(data, params->client_cert2) ||
5250351611Scy	    tls_global_private_key(data, params->private_key2,
5251351611Scy				   params->private_key_passwd2) ||
5252289549Srpaulo	    tls_global_dh(data, params->dh_file)) {
5253289549Srpaulo		wpa_printf(MSG_INFO, "TLS: Failed to set global parameters");
5254189251Ssam		return -1;
5255189251Ssam	}
5256189251Ssam
5257281806Srpaulo	if (params->openssl_ciphers &&
5258281806Srpaulo	    SSL_CTX_set_cipher_list(ssl_ctx, params->openssl_ciphers) != 1) {
5259281806Srpaulo		wpa_printf(MSG_INFO,
5260281806Srpaulo			   "OpenSSL: Failed to set cipher string '%s'",
5261281806Srpaulo			   params->openssl_ciphers);
5262281806Srpaulo		return -1;
5263281806Srpaulo	}
5264281806Srpaulo
5265346981Scy	if (!params->openssl_ecdh_curves) {
5266346981Scy#ifndef OPENSSL_IS_BORINGSSL
5267346981Scy#ifndef OPENSSL_NO_EC
5268346981Scy#if (OPENSSL_VERSION_NUMBER >= 0x10002000L) && \
5269346981Scy	(OPENSSL_VERSION_NUMBER < 0x10100000L)
5270346981Scy		if (SSL_CTX_set_ecdh_auto(ssl_ctx, 1) != 1) {
5271346981Scy			wpa_printf(MSG_INFO,
5272346981Scy				   "OpenSSL: Failed to set ECDH curves to auto");
5273346981Scy			return -1;
5274346981Scy		}
5275346981Scy#endif /* >= 1.0.2 && < 1.1.0 */
5276346981Scy#endif /* OPENSSL_NO_EC */
5277346981Scy#endif /* OPENSSL_IS_BORINGSSL */
5278346981Scy	} else if (params->openssl_ecdh_curves[0]) {
5279346981Scy#if defined(OPENSSL_IS_BORINGSSL) || (OPENSSL_VERSION_NUMBER < 0x10002000L)
5280346981Scy		wpa_printf(MSG_INFO,
5281346981Scy			"OpenSSL: ECDH configuration nnot supported");
5282346981Scy		return -1;
5283346981Scy#else /* OPENSSL_IS_BORINGSSL || < 1.0.2 */
5284346981Scy#ifndef OPENSSL_NO_EC
5285346981Scy#if OPENSSL_VERSION_NUMBER < 0x10100000L
5286346981Scy		SSL_CTX_set_ecdh_auto(ssl_ctx, 1);
5287346981Scy#endif
5288346981Scy		if (SSL_CTX_set1_curves_list(ssl_ctx,
5289346981Scy					     params->openssl_ecdh_curves) !=
5290346981Scy		    1) {
5291346981Scy			wpa_printf(MSG_INFO,
5292346981Scy				   "OpenSSL: Failed to set ECDH curves '%s'",
5293346981Scy				   params->openssl_ecdh_curves);
5294346981Scy			return -1;
5295346981Scy		}
5296346981Scy#else /* OPENSSL_NO_EC */
5297346981Scy		wpa_printf(MSG_INFO, "OpenSSL: ECDH not supported");
5298346981Scy		return -1;
5299346981Scy#endif /* OPENSSL_NO_EC */
5300346981Scy#endif /* OPENSSL_IS_BORINGSSL */
5301346981Scy	}
5302346981Scy
5303252726Srpaulo#ifdef SSL_OP_NO_TICKET
5304252726Srpaulo	if (params->flags & TLS_CONN_DISABLE_SESSION_TICKET)
5305252726Srpaulo		SSL_CTX_set_options(ssl_ctx, SSL_OP_NO_TICKET);
5306252726Srpaulo	else
5307252726Srpaulo		SSL_CTX_clear_options(ssl_ctx, SSL_OP_NO_TICKET);
5308252726Srpaulo#endif /*  SSL_OP_NO_TICKET */
5309252726Srpaulo
5310281806Srpaulo#ifdef HAVE_OCSP
5311281806Srpaulo	SSL_CTX_set_tlsext_status_cb(ssl_ctx, ocsp_status_cb);
5312281806Srpaulo	SSL_CTX_set_tlsext_status_arg(ssl_ctx, ssl_ctx);
5313281806Srpaulo	os_free(tls_global->ocsp_stapling_response);
5314281806Srpaulo	if (params->ocsp_stapling_response)
5315281806Srpaulo		tls_global->ocsp_stapling_response =
5316281806Srpaulo			os_strdup(params->ocsp_stapling_response);
5317281806Srpaulo	else
5318281806Srpaulo		tls_global->ocsp_stapling_response = NULL;
5319281806Srpaulo#endif /* HAVE_OCSP */
5320281806Srpaulo
5321351611Scy	openssl_debug_dump_ctx(ssl_ctx);
5322351611Scy
5323189251Ssam	return 0;
5324189251Ssam}
5325189251Ssam
5326189251Ssam
5327351611Scy#ifdef EAP_FAST_OR_TEAP
5328189251Ssam/* Pre-shared secred requires a patch to openssl, so this function is
5329189251Ssam * commented out unless explicitly needed for EAP-FAST in order to be able to
5330189251Ssam * build this file with unmodified openssl. */
5331189251Ssam
5332337817Scy#if (defined(OPENSSL_IS_BORINGSSL) || OPENSSL_VERSION_NUMBER >= 0x10100000L) && !defined(LIBRESSL_VERSION_NUMBER)
5333189251Ssamstatic int tls_sess_sec_cb(SSL *s, void *secret, int *secret_len,
5334189251Ssam			   STACK_OF(SSL_CIPHER) *peer_ciphers,
5335281806Srpaulo			   const SSL_CIPHER **cipher, void *arg)
5336281806Srpaulo#else /* OPENSSL_IS_BORINGSSL */
5337281806Srpaulostatic int tls_sess_sec_cb(SSL *s, void *secret, int *secret_len,
5338281806Srpaulo			   STACK_OF(SSL_CIPHER) *peer_ciphers,
5339189251Ssam			   SSL_CIPHER **cipher, void *arg)
5340281806Srpaulo#endif /* OPENSSL_IS_BORINGSSL */
5341189251Ssam{
5342189251Ssam	struct tls_connection *conn = arg;
5343189251Ssam	int ret;
5344189251Ssam
5345346981Scy#if OPENSSL_VERSION_NUMBER < 0x10100000L || \
5346346981Scy	(defined(LIBRESSL_VERSION_NUMBER) && \
5347346981Scy	 LIBRESSL_VERSION_NUMBER < 0x20700000L)
5348189251Ssam	if (conn == NULL || conn->session_ticket_cb == NULL)
5349189251Ssam		return 0;
5350189251Ssam
5351189251Ssam	ret = conn->session_ticket_cb(conn->session_ticket_cb_ctx,
5352189251Ssam				      conn->session_ticket,
5353189251Ssam				      conn->session_ticket_len,
5354189251Ssam				      s->s3->client_random,
5355189251Ssam				      s->s3->server_random, secret);
5356289549Srpaulo#else
5357289549Srpaulo	unsigned char client_random[SSL3_RANDOM_SIZE];
5358289549Srpaulo	unsigned char server_random[SSL3_RANDOM_SIZE];
5359289549Srpaulo
5360289549Srpaulo	if (conn == NULL || conn->session_ticket_cb == NULL)
5361289549Srpaulo		return 0;
5362289549Srpaulo
5363289549Srpaulo	SSL_get_client_random(s, client_random, sizeof(client_random));
5364289549Srpaulo	SSL_get_server_random(s, server_random, sizeof(server_random));
5365289549Srpaulo
5366289549Srpaulo	ret = conn->session_ticket_cb(conn->session_ticket_cb_ctx,
5367289549Srpaulo				      conn->session_ticket,
5368289549Srpaulo				      conn->session_ticket_len,
5369289549Srpaulo				      client_random,
5370289549Srpaulo				      server_random, secret);
5371289549Srpaulo#endif
5372289549Srpaulo
5373189251Ssam	os_free(conn->session_ticket);
5374189251Ssam	conn->session_ticket = NULL;
5375189251Ssam
5376189251Ssam	if (ret <= 0)
5377189251Ssam		return 0;
5378189251Ssam
5379189251Ssam	*secret_len = SSL_MAX_MASTER_KEY_LENGTH;
5380189251Ssam	return 1;
5381189251Ssam}
5382189251Ssam
5383189251Ssam
5384189251Ssamstatic int tls_session_ticket_ext_cb(SSL *s, const unsigned char *data,
5385189251Ssam				     int len, void *arg)
5386189251Ssam{
5387189251Ssam	struct tls_connection *conn = arg;
5388189251Ssam
5389189251Ssam	if (conn == NULL || conn->session_ticket_cb == NULL)
5390189251Ssam		return 0;
5391189251Ssam
5392189251Ssam	wpa_printf(MSG_DEBUG, "OpenSSL: %s: length=%d", __func__, len);
5393189251Ssam
5394189251Ssam	os_free(conn->session_ticket);
5395189251Ssam	conn->session_ticket = NULL;
5396189251Ssam
5397189251Ssam	wpa_hexdump(MSG_DEBUG, "OpenSSL: ClientHello SessionTicket "
5398189251Ssam		    "extension", data, len);
5399189251Ssam
5400346981Scy	conn->session_ticket = os_memdup(data, len);
5401189251Ssam	if (conn->session_ticket == NULL)
5402189251Ssam		return 0;
5403189251Ssam
5404189251Ssam	conn->session_ticket_len = len;
5405189251Ssam
5406189251Ssam	return 1;
5407189251Ssam}
5408351611Scy#endif /* EAP_FAST_OR_TEAP */
5409189251Ssam
5410189251Ssam
5411189251Ssamint tls_connection_set_session_ticket_cb(void *tls_ctx,
5412189251Ssam					 struct tls_connection *conn,
5413189251Ssam					 tls_session_ticket_cb cb,
5414189251Ssam					 void *ctx)
5415189251Ssam{
5416351611Scy#ifdef EAP_FAST_OR_TEAP
5417189251Ssam	conn->session_ticket_cb = cb;
5418189251Ssam	conn->session_ticket_cb_ctx = ctx;
5419189251Ssam
5420189251Ssam	if (cb) {
5421189251Ssam		if (SSL_set_session_secret_cb(conn->ssl, tls_sess_sec_cb,
5422189251Ssam					      conn) != 1)
5423189251Ssam			return -1;
5424189251Ssam		SSL_set_session_ticket_ext_cb(conn->ssl,
5425189251Ssam					      tls_session_ticket_ext_cb, conn);
5426189251Ssam	} else {
5427189251Ssam		if (SSL_set_session_secret_cb(conn->ssl, NULL, NULL) != 1)
5428189251Ssam			return -1;
5429189251Ssam		SSL_set_session_ticket_ext_cb(conn->ssl, NULL, NULL);
5430189251Ssam	}
5431189251Ssam
5432189251Ssam	return 0;
5433351611Scy#else /* EAP_FAST_OR_TEAP */
5434189251Ssam	return -1;
5435351611Scy#endif /* EAP_FAST_OR_TEAP */
5436189251Ssam}
5437281806Srpaulo
5438281806Srpaulo
5439281806Srpauloint tls_get_library_version(char *buf, size_t buf_len)
5440281806Srpaulo{
5441337817Scy#if OPENSSL_VERSION_NUMBER >= 0x10100000L && !defined(LIBRESSL_VERSION_NUMBER)
5442281806Srpaulo	return os_snprintf(buf, buf_len, "OpenSSL build=%s run=%s",
5443281806Srpaulo			   OPENSSL_VERSION_TEXT,
5444337817Scy			   OpenSSL_version(OPENSSL_VERSION));
5445337817Scy#else
5446337817Scy	return os_snprintf(buf, buf_len, "OpenSSL build=%s run=%s",
5447337817Scy			   OPENSSL_VERSION_TEXT,
5448281806Srpaulo			   SSLeay_version(SSLEAY_VERSION));
5449337817Scy#endif
5450281806Srpaulo}
5451289549Srpaulo
5452289549Srpaulo
5453289549Srpaulovoid tls_connection_set_success_data(struct tls_connection *conn,
5454289549Srpaulo				     struct wpabuf *data)
5455289549Srpaulo{
5456289549Srpaulo	SSL_SESSION *sess;
5457289549Srpaulo	struct wpabuf *old;
5458289549Srpaulo
5459289549Srpaulo	if (tls_ex_idx_session < 0)
5460289549Srpaulo		goto fail;
5461289549Srpaulo	sess = SSL_get_session(conn->ssl);
5462289549Srpaulo	if (!sess)
5463289549Srpaulo		goto fail;
5464289549Srpaulo	old = SSL_SESSION_get_ex_data(sess, tls_ex_idx_session);
5465289549Srpaulo	if (old) {
5466289549Srpaulo		wpa_printf(MSG_DEBUG, "OpenSSL: Replacing old success data %p",
5467289549Srpaulo			   old);
5468289549Srpaulo		wpabuf_free(old);
5469289549Srpaulo	}
5470289549Srpaulo	if (SSL_SESSION_set_ex_data(sess, tls_ex_idx_session, data) != 1)
5471289549Srpaulo		goto fail;
5472289549Srpaulo
5473289549Srpaulo	wpa_printf(MSG_DEBUG, "OpenSSL: Stored success data %p", data);
5474289549Srpaulo	conn->success_data = 1;
5475289549Srpaulo	return;
5476289549Srpaulo
5477289549Srpaulofail:
5478289549Srpaulo	wpa_printf(MSG_INFO, "OpenSSL: Failed to store success data");
5479289549Srpaulo	wpabuf_free(data);
5480289549Srpaulo}
5481289549Srpaulo
5482289549Srpaulo
5483289549Srpaulovoid tls_connection_set_success_data_resumed(struct tls_connection *conn)
5484289549Srpaulo{
5485289549Srpaulo	wpa_printf(MSG_DEBUG,
5486289549Srpaulo		   "OpenSSL: Success data accepted for resumed session");
5487289549Srpaulo	conn->success_data = 1;
5488289549Srpaulo}
5489289549Srpaulo
5490289549Srpaulo
5491289549Srpauloconst struct wpabuf *
5492289549Srpaulotls_connection_get_success_data(struct tls_connection *conn)
5493289549Srpaulo{
5494289549Srpaulo	SSL_SESSION *sess;
5495289549Srpaulo
5496289549Srpaulo	if (tls_ex_idx_session < 0 ||
5497289549Srpaulo	    !(sess = SSL_get_session(conn->ssl)))
5498289549Srpaulo		return NULL;
5499289549Srpaulo	return SSL_SESSION_get_ex_data(sess, tls_ex_idx_session);
5500289549Srpaulo}
5501289549Srpaulo
5502289549Srpaulo
5503289549Srpaulovoid tls_connection_remove_session(struct tls_connection *conn)
5504289549Srpaulo{
5505289549Srpaulo	SSL_SESSION *sess;
5506289549Srpaulo
5507289549Srpaulo	sess = SSL_get_session(conn->ssl);
5508289549Srpaulo	if (!sess)
5509289549Srpaulo		return;
5510289549Srpaulo
5511289549Srpaulo	if (SSL_CTX_remove_session(conn->ssl_ctx, sess) != 1)
5512289549Srpaulo		wpa_printf(MSG_DEBUG,
5513289549Srpaulo			   "OpenSSL: Session was not cached");
5514289549Srpaulo	else
5515289549Srpaulo		wpa_printf(MSG_DEBUG,
5516289549Srpaulo			   "OpenSSL: Removed cached session to disable session resumption");
5517289549Srpaulo}
5518351611Scy
5519351611Scy
5520351611Scyint tls_get_tls_unique(struct tls_connection *conn, u8 *buf, size_t max_len)
5521351611Scy{
5522351611Scy	size_t len;
5523351611Scy	int reused;
5524351611Scy
5525351611Scy	reused = SSL_session_reused(conn->ssl);
5526351611Scy	if ((conn->server && !reused) || (!conn->server && reused))
5527351611Scy		len = SSL_get_peer_finished(conn->ssl, buf, max_len);
5528351611Scy	else
5529351611Scy		len = SSL_get_finished(conn->ssl, buf, max_len);
5530351611Scy
5531351611Scy	if (len == 0 || len > max_len)
5532351611Scy		return -1;
5533351611Scy
5534351611Scy	return len;
5535351611Scy}
5536351611Scy
5537351611Scy
5538351611Scyu16 tls_connection_get_cipher_suite(struct tls_connection *conn)
5539351611Scy{
5540351611Scy	const SSL_CIPHER *cipher;
5541351611Scy
5542351611Scy	cipher = SSL_get_current_cipher(conn->ssl);
5543351611Scy	if (!cipher)
5544351611Scy		return 0;
5545351611Scy#if OPENSSL_VERSION_NUMBER >= 0x10101000L && !defined(LIBRESSL_VERSION_NUMBER)
5546351611Scy	return SSL_CIPHER_get_protocol_id(cipher);
5547351611Scy#else
5548351611Scy	return SSL_CIPHER_get_id(cipher) & 0xFFFF;
5549351611Scy#endif
5550351611Scy}
5551