139beb93cSSam Leffler /*
2e28a4053SRui Paulo * SSL/TLS interface functions for OpenSSL
3325151a3SRui Paulo * Copyright (c) 2004-2015, Jouni Malinen <j@w1.fi>
439beb93cSSam Leffler *
5f05cddf9SRui Paulo * This software may be distributed under the terms of the BSD license.
6f05cddf9SRui Paulo * See README for more details.
739beb93cSSam Leffler */
839beb93cSSam Leffler
939beb93cSSam Leffler #include "includes.h"
1039beb93cSSam Leffler
1139beb93cSSam Leffler #ifndef CONFIG_SMARTCARD
1239beb93cSSam Leffler #ifndef OPENSSL_NO_ENGINE
135b9c547cSRui Paulo #ifndef ANDROID
1439beb93cSSam Leffler #define OPENSSL_NO_ENGINE
1539beb93cSSam Leffler #endif
1639beb93cSSam Leffler #endif
175b9c547cSRui Paulo #endif
1839beb93cSSam Leffler
1939beb93cSSam Leffler #include <openssl/ssl.h>
2039beb93cSSam Leffler #include <openssl/err.h>
21780fb4a2SCy Schubert #include <openssl/opensslv.h>
2239beb93cSSam Leffler #include <openssl/pkcs12.h>
2339beb93cSSam Leffler #include <openssl/x509v3.h>
2439beb93cSSam Leffler #ifndef OPENSSL_NO_ENGINE
2539beb93cSSam Leffler #include <openssl/engine.h>
2639beb93cSSam Leffler #endif /* OPENSSL_NO_ENGINE */
27325151a3SRui Paulo #ifndef OPENSSL_NO_DSA
28325151a3SRui Paulo #include <openssl/dsa.h>
29325151a3SRui Paulo #endif
30325151a3SRui Paulo #ifndef OPENSSL_NO_DH
31325151a3SRui Paulo #include <openssl/dh.h>
32325151a3SRui Paulo #endif
3339beb93cSSam Leffler
3439beb93cSSam Leffler #include "common.h"
35e28a4053SRui Paulo #include "crypto.h"
36325151a3SRui Paulo #include "sha1.h"
37325151a3SRui Paulo #include "sha256.h"
3839beb93cSSam Leffler #include "tls.h"
39780fb4a2SCy Schubert #include "tls_openssl.h"
4039beb93cSSam Leffler
41780fb4a2SCy Schubert #if !defined(CONFIG_FIPS) && \
42780fb4a2SCy Schubert (defined(EAP_FAST) || defined(EAP_FAST_DYNAMIC) || \
43780fb4a2SCy Schubert defined(EAP_SERVER_FAST))
44780fb4a2SCy Schubert #define OPENSSL_NEED_EAP_FAST_PRF
4539beb93cSSam Leffler #endif
465b9c547cSRui Paulo
47206b73d0SCy Schubert #if defined(EAP_FAST) || defined(EAP_FAST_DYNAMIC) || \
48206b73d0SCy Schubert defined(EAP_SERVER_FAST) || defined(EAP_TEAP) || \
49206b73d0SCy Schubert defined(EAP_SERVER_TEAP)
50206b73d0SCy Schubert #define EAP_FAST_OR_TEAP
51206b73d0SCy Schubert #endif
52206b73d0SCy Schubert
53206b73d0SCy Schubert
545b9c547cSRui Paulo #if defined(OPENSSL_IS_BORINGSSL)
555b9c547cSRui Paulo /* stack_index_t is the return type of OpenSSL's sk_XXX_num() functions. */
565b9c547cSRui Paulo typedef size_t stack_index_t;
575b9c547cSRui Paulo #else
585b9c547cSRui Paulo typedef int stack_index_t;
5939beb93cSSam Leffler #endif
6039beb93cSSam Leffler
615b9c547cSRui Paulo #ifdef SSL_set_tlsext_status_type
625b9c547cSRui Paulo #ifndef OPENSSL_NO_TLSEXT
635b9c547cSRui Paulo #define HAVE_OCSP
645b9c547cSRui Paulo #include <openssl/ocsp.h>
655b9c547cSRui Paulo #endif /* OPENSSL_NO_TLSEXT */
665b9c547cSRui Paulo #endif /* SSL_set_tlsext_status_type */
675b9c547cSRui Paulo
68780fb4a2SCy Schubert #if (OPENSSL_VERSION_NUMBER < 0x10100000L || \
6985732ac8SCy Schubert (defined(LIBRESSL_VERSION_NUMBER) && \
7085732ac8SCy Schubert LIBRESSL_VERSION_NUMBER < 0x20700000L)) && \
71780fb4a2SCy Schubert !defined(BORINGSSL_API_VERSION)
72780fb4a2SCy Schubert /*
73780fb4a2SCy Schubert * SSL_get_client_random() and SSL_get_server_random() were added in OpenSSL
74780fb4a2SCy Schubert * 1.1.0 and newer BoringSSL revisions. Provide compatibility wrappers for
75780fb4a2SCy Schubert * older versions.
76780fb4a2SCy Schubert */
77780fb4a2SCy Schubert
SSL_get_client_random(const SSL * ssl,unsigned char * out,size_t outlen)78780fb4a2SCy Schubert static size_t SSL_get_client_random(const SSL *ssl, unsigned char *out,
79780fb4a2SCy Schubert size_t outlen)
80780fb4a2SCy Schubert {
81780fb4a2SCy Schubert if (!ssl->s3 || outlen < SSL3_RANDOM_SIZE)
82780fb4a2SCy Schubert return 0;
83780fb4a2SCy Schubert os_memcpy(out, ssl->s3->client_random, SSL3_RANDOM_SIZE);
84780fb4a2SCy Schubert return SSL3_RANDOM_SIZE;
85780fb4a2SCy Schubert }
86780fb4a2SCy Schubert
87780fb4a2SCy Schubert
SSL_get_server_random(const SSL * ssl,unsigned char * out,size_t outlen)88780fb4a2SCy Schubert static size_t SSL_get_server_random(const SSL *ssl, unsigned char *out,
89780fb4a2SCy Schubert size_t outlen)
90780fb4a2SCy Schubert {
91780fb4a2SCy Schubert if (!ssl->s3 || outlen < SSL3_RANDOM_SIZE)
92780fb4a2SCy Schubert return 0;
93780fb4a2SCy Schubert os_memcpy(out, ssl->s3->server_random, SSL3_RANDOM_SIZE);
94780fb4a2SCy Schubert return SSL3_RANDOM_SIZE;
95780fb4a2SCy Schubert }
96780fb4a2SCy Schubert
97780fb4a2SCy Schubert
98780fb4a2SCy Schubert #ifdef OPENSSL_NEED_EAP_FAST_PRF
SSL_SESSION_get_master_key(const SSL_SESSION * session,unsigned char * out,size_t outlen)99780fb4a2SCy Schubert static size_t SSL_SESSION_get_master_key(const SSL_SESSION *session,
100780fb4a2SCy Schubert unsigned char *out, size_t outlen)
101780fb4a2SCy Schubert {
102780fb4a2SCy Schubert if (!session || session->master_key_length < 0 ||
103780fb4a2SCy Schubert (size_t) session->master_key_length > outlen)
104780fb4a2SCy Schubert return 0;
105780fb4a2SCy Schubert if ((size_t) session->master_key_length < outlen)
106780fb4a2SCy Schubert outlen = session->master_key_length;
107780fb4a2SCy Schubert os_memcpy(out, session->master_key, outlen);
108780fb4a2SCy Schubert return outlen;
109780fb4a2SCy Schubert }
110780fb4a2SCy Schubert #endif /* OPENSSL_NEED_EAP_FAST_PRF */
111780fb4a2SCy Schubert
112780fb4a2SCy Schubert #endif
113780fb4a2SCy Schubert
1144bc52338SCy Schubert #if OPENSSL_VERSION_NUMBER < 0x10100000L || \
1154bc52338SCy Schubert (defined(LIBRESSL_VERSION_NUMBER) && \
1164bc52338SCy Schubert LIBRESSL_VERSION_NUMBER < 0x20700000L)
11785732ac8SCy Schubert #ifdef CONFIG_SUITEB
RSA_bits(const RSA * r)11885732ac8SCy Schubert static int RSA_bits(const RSA *r)
11985732ac8SCy Schubert {
12085732ac8SCy Schubert return BN_num_bits(r->n);
12185732ac8SCy Schubert }
12285732ac8SCy Schubert #endif /* CONFIG_SUITEB */
12385732ac8SCy Schubert
12485732ac8SCy Schubert
ASN1_STRING_get0_data(const ASN1_STRING * x)12585732ac8SCy Schubert static const unsigned char * ASN1_STRING_get0_data(const ASN1_STRING *x)
12685732ac8SCy Schubert {
12785732ac8SCy Schubert return ASN1_STRING_data((ASN1_STRING *) x);
12885732ac8SCy Schubert }
12985732ac8SCy Schubert #endif
13085732ac8SCy Schubert
1315b9c547cSRui Paulo #ifdef ANDROID
1325b9c547cSRui Paulo #include <openssl/pem.h>
1335b9c547cSRui Paulo #include <keystore/keystore_get.h>
1345b9c547cSRui Paulo
BIO_from_keystore(const char * key)1355b9c547cSRui Paulo static BIO * BIO_from_keystore(const char *key)
1365b9c547cSRui Paulo {
1375b9c547cSRui Paulo BIO *bio = NULL;
1385b9c547cSRui Paulo uint8_t *value = NULL;
1395b9c547cSRui Paulo int length = keystore_get(key, strlen(key), &value);
1405b9c547cSRui Paulo if (length != -1 && (bio = BIO_new(BIO_s_mem())) != NULL)
1415b9c547cSRui Paulo BIO_write(bio, value, length);
1425b9c547cSRui Paulo free(value);
1435b9c547cSRui Paulo return bio;
1445b9c547cSRui Paulo }
145780fb4a2SCy Schubert
146780fb4a2SCy Schubert
tls_add_ca_from_keystore(X509_STORE * ctx,const char * key_alias)147780fb4a2SCy Schubert static int tls_add_ca_from_keystore(X509_STORE *ctx, const char *key_alias)
148780fb4a2SCy Schubert {
149780fb4a2SCy Schubert BIO *bio = BIO_from_keystore(key_alias);
150780fb4a2SCy Schubert STACK_OF(X509_INFO) *stack = NULL;
151780fb4a2SCy Schubert stack_index_t i;
152780fb4a2SCy Schubert
153780fb4a2SCy Schubert if (bio) {
154780fb4a2SCy Schubert stack = PEM_X509_INFO_read_bio(bio, NULL, NULL, NULL);
155780fb4a2SCy Schubert BIO_free(bio);
156780fb4a2SCy Schubert }
157780fb4a2SCy Schubert
158780fb4a2SCy Schubert if (!stack) {
159780fb4a2SCy Schubert wpa_printf(MSG_WARNING, "TLS: Failed to parse certificate: %s",
160780fb4a2SCy Schubert key_alias);
161780fb4a2SCy Schubert return -1;
162780fb4a2SCy Schubert }
163780fb4a2SCy Schubert
164780fb4a2SCy Schubert for (i = 0; i < sk_X509_INFO_num(stack); ++i) {
165780fb4a2SCy Schubert X509_INFO *info = sk_X509_INFO_value(stack, i);
166780fb4a2SCy Schubert
167780fb4a2SCy Schubert if (info->x509)
168780fb4a2SCy Schubert X509_STORE_add_cert(ctx, info->x509);
169780fb4a2SCy Schubert if (info->crl)
170780fb4a2SCy Schubert X509_STORE_add_crl(ctx, info->crl);
171780fb4a2SCy Schubert }
172780fb4a2SCy Schubert
173780fb4a2SCy Schubert sk_X509_INFO_pop_free(stack, X509_INFO_free);
174780fb4a2SCy Schubert
175780fb4a2SCy Schubert return 0;
176780fb4a2SCy Schubert }
177780fb4a2SCy Schubert
178780fb4a2SCy Schubert
tls_add_ca_from_keystore_encoded(X509_STORE * ctx,const char * encoded_key_alias)179780fb4a2SCy Schubert static int tls_add_ca_from_keystore_encoded(X509_STORE *ctx,
180780fb4a2SCy Schubert const char *encoded_key_alias)
181780fb4a2SCy Schubert {
182780fb4a2SCy Schubert int rc = -1;
183780fb4a2SCy Schubert int len = os_strlen(encoded_key_alias);
184780fb4a2SCy Schubert unsigned char *decoded_alias;
185780fb4a2SCy Schubert
186780fb4a2SCy Schubert if (len & 1) {
187780fb4a2SCy Schubert wpa_printf(MSG_WARNING, "Invalid hex-encoded alias: %s",
188780fb4a2SCy Schubert encoded_key_alias);
189780fb4a2SCy Schubert return rc;
190780fb4a2SCy Schubert }
191780fb4a2SCy Schubert
192780fb4a2SCy Schubert decoded_alias = os_malloc(len / 2 + 1);
193780fb4a2SCy Schubert if (decoded_alias) {
194780fb4a2SCy Schubert if (!hexstr2bin(encoded_key_alias, decoded_alias, len / 2)) {
195780fb4a2SCy Schubert decoded_alias[len / 2] = '\0';
196780fb4a2SCy Schubert rc = tls_add_ca_from_keystore(
197780fb4a2SCy Schubert ctx, (const char *) decoded_alias);
198780fb4a2SCy Schubert }
199780fb4a2SCy Schubert os_free(decoded_alias);
200780fb4a2SCy Schubert }
201780fb4a2SCy Schubert
202780fb4a2SCy Schubert return rc;
203780fb4a2SCy Schubert }
204780fb4a2SCy Schubert
2055b9c547cSRui Paulo #endif /* ANDROID */
2065b9c547cSRui Paulo
20739beb93cSSam Leffler static int tls_openssl_ref_count = 0;
208325151a3SRui Paulo static int tls_ex_idx_session = -1;
20939beb93cSSam Leffler
2105b9c547cSRui Paulo struct tls_context {
211e28a4053SRui Paulo void (*event_cb)(void *ctx, enum tls_event ev,
212e28a4053SRui Paulo union tls_event_data *data);
213e28a4053SRui Paulo void *cb_ctx;
214f05cddf9SRui Paulo int cert_in_cb;
2155b9c547cSRui Paulo char *ocsp_stapling_response;
216e28a4053SRui Paulo };
217e28a4053SRui Paulo
2185b9c547cSRui Paulo static struct tls_context *tls_global = NULL;
219e28a4053SRui Paulo
220e28a4053SRui Paulo
221325151a3SRui Paulo struct tls_data {
222325151a3SRui Paulo SSL_CTX *ssl;
223325151a3SRui Paulo unsigned int tls_session_lifetime;
2244bc52338SCy Schubert int check_crl;
2254bc52338SCy Schubert int check_crl_strict;
2264bc52338SCy Schubert char *ca_cert;
2274bc52338SCy Schubert unsigned int crl_reload_interval;
2284bc52338SCy Schubert struct os_reltime crl_last_reload;
2294bc52338SCy Schubert char *check_cert_subject;
230325151a3SRui Paulo };
231325151a3SRui Paulo
23239beb93cSSam Leffler struct tls_connection {
2335b9c547cSRui Paulo struct tls_context *context;
2344bc52338SCy Schubert struct tls_data *data;
2355b9c547cSRui Paulo SSL_CTX *ssl_ctx;
23639beb93cSSam Leffler SSL *ssl;
23739beb93cSSam Leffler BIO *ssl_in, *ssl_out;
238780fb4a2SCy Schubert #if defined(ANDROID) || !defined(OPENSSL_NO_ENGINE)
23939beb93cSSam Leffler ENGINE *engine; /* functional reference to the engine */
24039beb93cSSam Leffler EVP_PKEY *private_key; /* the private key if using engine */
24139beb93cSSam Leffler #endif /* OPENSSL_NO_ENGINE */
2425b9c547cSRui Paulo char *subject_match, *altsubject_match, *suffix_match, *domain_match;
2434bc52338SCy Schubert char *check_cert_subject;
24439beb93cSSam Leffler int read_alerts, write_alerts, failed;
24539beb93cSSam Leffler
24639beb93cSSam Leffler tls_session_ticket_cb session_ticket_cb;
24739beb93cSSam Leffler void *session_ticket_cb_ctx;
24839beb93cSSam Leffler
24939beb93cSSam Leffler /* SessionTicket received from OpenSSL hello_extension_cb (server) */
25039beb93cSSam Leffler u8 *session_ticket;
25139beb93cSSam Leffler size_t session_ticket_len;
252e28a4053SRui Paulo
253e28a4053SRui Paulo unsigned int ca_cert_verify:1;
254e28a4053SRui Paulo unsigned int cert_probe:1;
255e28a4053SRui Paulo unsigned int server_cert_only:1;
2565b9c547cSRui Paulo unsigned int invalid_hb_used:1;
257325151a3SRui Paulo unsigned int success_data:1;
25885732ac8SCy Schubert unsigned int client_hello_generated:1;
25985732ac8SCy Schubert unsigned int server:1;
260e28a4053SRui Paulo
261e28a4053SRui Paulo u8 srv_cert_hash[32];
262f05cddf9SRui Paulo
263f05cddf9SRui Paulo unsigned int flags;
2645b9c547cSRui Paulo
2655b9c547cSRui Paulo X509 *peer_cert;
2665b9c547cSRui Paulo X509 *peer_issuer;
2675b9c547cSRui Paulo X509 *peer_issuer_issuer;
268c1d255d3SCy Schubert char *peer_subject; /* peer subject info for authenticated peer */
269325151a3SRui Paulo
270325151a3SRui Paulo unsigned char client_random[SSL3_RANDOM_SIZE];
271325151a3SRui Paulo unsigned char server_random[SSL3_RANDOM_SIZE];
27285732ac8SCy Schubert
27385732ac8SCy Schubert u16 cipher_suite;
27485732ac8SCy Schubert int server_dh_prime_len;
27539beb93cSSam Leffler };
27639beb93cSSam Leffler
27739beb93cSSam Leffler
tls_context_new(const struct tls_config * conf)2785b9c547cSRui Paulo static struct tls_context * tls_context_new(const struct tls_config *conf)
2795b9c547cSRui Paulo {
2805b9c547cSRui Paulo struct tls_context *context = os_zalloc(sizeof(*context));
2815b9c547cSRui Paulo if (context == NULL)
2825b9c547cSRui Paulo return NULL;
2835b9c547cSRui Paulo if (conf) {
2845b9c547cSRui Paulo context->event_cb = conf->event_cb;
2855b9c547cSRui Paulo context->cb_ctx = conf->cb_ctx;
2865b9c547cSRui Paulo context->cert_in_cb = conf->cert_in_cb;
2875b9c547cSRui Paulo }
2885b9c547cSRui Paulo return context;
2895b9c547cSRui Paulo }
2905b9c547cSRui Paulo
2915b9c547cSRui Paulo
29239beb93cSSam Leffler #ifdef CONFIG_NO_STDOUT_DEBUG
29339beb93cSSam Leffler
_tls_show_errors(void)29439beb93cSSam Leffler static void _tls_show_errors(void)
29539beb93cSSam Leffler {
29639beb93cSSam Leffler unsigned long err;
29739beb93cSSam Leffler
29839beb93cSSam Leffler while ((err = ERR_get_error())) {
29939beb93cSSam Leffler /* Just ignore the errors, since stdout is disabled */
30039beb93cSSam Leffler }
30139beb93cSSam Leffler }
30239beb93cSSam Leffler #define tls_show_errors(l, f, t) _tls_show_errors()
30339beb93cSSam Leffler
30439beb93cSSam Leffler #else /* CONFIG_NO_STDOUT_DEBUG */
30539beb93cSSam Leffler
tls_show_errors(int level,const char * func,const char * txt)30639beb93cSSam Leffler static void tls_show_errors(int level, const char *func, const char *txt)
30739beb93cSSam Leffler {
30839beb93cSSam Leffler unsigned long err;
30939beb93cSSam Leffler
31039beb93cSSam Leffler wpa_printf(level, "OpenSSL: %s - %s %s",
31139beb93cSSam Leffler func, txt, ERR_error_string(ERR_get_error(), NULL));
31239beb93cSSam Leffler
31339beb93cSSam Leffler while ((err = ERR_get_error())) {
31439beb93cSSam Leffler wpa_printf(MSG_INFO, "OpenSSL: pending error: %s",
31539beb93cSSam Leffler ERR_error_string(err, NULL));
31639beb93cSSam Leffler }
31739beb93cSSam Leffler }
31839beb93cSSam Leffler
31939beb93cSSam Leffler #endif /* CONFIG_NO_STDOUT_DEBUG */
32039beb93cSSam Leffler
32139beb93cSSam Leffler
tls_crl_cert_reload(const char * ca_cert,int check_crl)3224bc52338SCy Schubert static X509_STORE * tls_crl_cert_reload(const char *ca_cert, int check_crl)
3234bc52338SCy Schubert {
3244bc52338SCy Schubert int flags;
3254bc52338SCy Schubert X509_STORE *store;
3264bc52338SCy Schubert
3274bc52338SCy Schubert store = X509_STORE_new();
3284bc52338SCy Schubert if (!store) {
3294bc52338SCy Schubert wpa_printf(MSG_DEBUG,
3304bc52338SCy Schubert "OpenSSL: %s - failed to allocate new certificate store",
3314bc52338SCy Schubert __func__);
3324bc52338SCy Schubert return NULL;
3334bc52338SCy Schubert }
3344bc52338SCy Schubert
3354bc52338SCy Schubert if (ca_cert && X509_STORE_load_locations(store, ca_cert, NULL) != 1) {
3364bc52338SCy Schubert tls_show_errors(MSG_WARNING, __func__,
3374bc52338SCy Schubert "Failed to load root certificates");
3384bc52338SCy Schubert X509_STORE_free(store);
3394bc52338SCy Schubert return NULL;
3404bc52338SCy Schubert }
3414bc52338SCy Schubert
3424bc52338SCy Schubert flags = check_crl ? X509_V_FLAG_CRL_CHECK : 0;
3434bc52338SCy Schubert if (check_crl == 2)
3444bc52338SCy Schubert flags |= X509_V_FLAG_CRL_CHECK_ALL;
3454bc52338SCy Schubert
3464bc52338SCy Schubert X509_STORE_set_flags(store, flags);
3474bc52338SCy Schubert
3484bc52338SCy Schubert return store;
3494bc52338SCy Schubert }
3504bc52338SCy Schubert
3514bc52338SCy Schubert
35239beb93cSSam Leffler #ifdef CONFIG_NATIVE_WINDOWS
35339beb93cSSam Leffler
35439beb93cSSam Leffler /* Windows CryptoAPI and access to certificate stores */
35539beb93cSSam Leffler #include <wincrypt.h>
35639beb93cSSam Leffler
35739beb93cSSam Leffler #ifdef __MINGW32_VERSION
35839beb93cSSam Leffler /*
35939beb93cSSam Leffler * MinGW does not yet include all the needed definitions for CryptoAPI, so
36039beb93cSSam Leffler * define here whatever extra is needed.
36139beb93cSSam Leffler */
36239beb93cSSam Leffler #define CERT_SYSTEM_STORE_CURRENT_USER (1 << 16)
36339beb93cSSam Leffler #define CERT_STORE_READONLY_FLAG 0x00008000
36439beb93cSSam Leffler #define CERT_STORE_OPEN_EXISTING_FLAG 0x00004000
36539beb93cSSam Leffler
36639beb93cSSam Leffler #endif /* __MINGW32_VERSION */
36739beb93cSSam Leffler
36839beb93cSSam Leffler
36939beb93cSSam Leffler struct cryptoapi_rsa_data {
37039beb93cSSam Leffler const CERT_CONTEXT *cert;
37139beb93cSSam Leffler HCRYPTPROV crypt_prov;
37239beb93cSSam Leffler DWORD key_spec;
37339beb93cSSam Leffler BOOL free_crypt_prov;
37439beb93cSSam Leffler };
37539beb93cSSam Leffler
37639beb93cSSam Leffler
cryptoapi_error(const char * msg)37739beb93cSSam Leffler static void cryptoapi_error(const char *msg)
37839beb93cSSam Leffler {
37939beb93cSSam Leffler wpa_printf(MSG_INFO, "CryptoAPI: %s; err=%u",
38039beb93cSSam Leffler msg, (unsigned int) GetLastError());
38139beb93cSSam Leffler }
38239beb93cSSam Leffler
38339beb93cSSam Leffler
cryptoapi_rsa_pub_enc(int flen,const unsigned char * from,unsigned char * to,RSA * rsa,int padding)38439beb93cSSam Leffler static int cryptoapi_rsa_pub_enc(int flen, const unsigned char *from,
38539beb93cSSam Leffler unsigned char *to, RSA *rsa, int padding)
38639beb93cSSam Leffler {
38739beb93cSSam Leffler wpa_printf(MSG_DEBUG, "%s - not implemented", __func__);
38839beb93cSSam Leffler return 0;
38939beb93cSSam Leffler }
39039beb93cSSam Leffler
39139beb93cSSam Leffler
cryptoapi_rsa_pub_dec(int flen,const unsigned char * from,unsigned char * to,RSA * rsa,int padding)39239beb93cSSam Leffler static int cryptoapi_rsa_pub_dec(int flen, const unsigned char *from,
39339beb93cSSam Leffler unsigned char *to, RSA *rsa, int padding)
39439beb93cSSam Leffler {
39539beb93cSSam Leffler wpa_printf(MSG_DEBUG, "%s - not implemented", __func__);
39639beb93cSSam Leffler return 0;
39739beb93cSSam Leffler }
39839beb93cSSam Leffler
39939beb93cSSam Leffler
cryptoapi_rsa_priv_enc(int flen,const unsigned char * from,unsigned char * to,RSA * rsa,int padding)40039beb93cSSam Leffler static int cryptoapi_rsa_priv_enc(int flen, const unsigned char *from,
40139beb93cSSam Leffler unsigned char *to, RSA *rsa, int padding)
40239beb93cSSam Leffler {
40339beb93cSSam Leffler struct cryptoapi_rsa_data *priv =
40439beb93cSSam Leffler (struct cryptoapi_rsa_data *) rsa->meth->app_data;
40539beb93cSSam Leffler HCRYPTHASH hash;
40639beb93cSSam Leffler DWORD hash_size, len, i;
40739beb93cSSam Leffler unsigned char *buf = NULL;
40839beb93cSSam Leffler int ret = 0;
40939beb93cSSam Leffler
41039beb93cSSam Leffler if (priv == NULL) {
41139beb93cSSam Leffler RSAerr(RSA_F_RSA_EAY_PRIVATE_ENCRYPT,
41239beb93cSSam Leffler ERR_R_PASSED_NULL_PARAMETER);
41339beb93cSSam Leffler return 0;
41439beb93cSSam Leffler }
41539beb93cSSam Leffler
41639beb93cSSam Leffler if (padding != RSA_PKCS1_PADDING) {
41739beb93cSSam Leffler RSAerr(RSA_F_RSA_EAY_PRIVATE_ENCRYPT,
41839beb93cSSam Leffler RSA_R_UNKNOWN_PADDING_TYPE);
41939beb93cSSam Leffler return 0;
42039beb93cSSam Leffler }
42139beb93cSSam Leffler
42239beb93cSSam Leffler if (flen != 16 /* MD5 */ + 20 /* SHA-1 */) {
42339beb93cSSam Leffler wpa_printf(MSG_INFO, "%s - only MD5-SHA1 hash supported",
42439beb93cSSam Leffler __func__);
42539beb93cSSam Leffler RSAerr(RSA_F_RSA_EAY_PRIVATE_ENCRYPT,
42639beb93cSSam Leffler RSA_R_INVALID_MESSAGE_LENGTH);
42739beb93cSSam Leffler return 0;
42839beb93cSSam Leffler }
42939beb93cSSam Leffler
43039beb93cSSam Leffler if (!CryptCreateHash(priv->crypt_prov, CALG_SSL3_SHAMD5, 0, 0, &hash))
43139beb93cSSam Leffler {
43239beb93cSSam Leffler cryptoapi_error("CryptCreateHash failed");
43339beb93cSSam Leffler return 0;
43439beb93cSSam Leffler }
43539beb93cSSam Leffler
43639beb93cSSam Leffler len = sizeof(hash_size);
43739beb93cSSam Leffler if (!CryptGetHashParam(hash, HP_HASHSIZE, (BYTE *) &hash_size, &len,
43839beb93cSSam Leffler 0)) {
43939beb93cSSam Leffler cryptoapi_error("CryptGetHashParam failed");
44039beb93cSSam Leffler goto err;
44139beb93cSSam Leffler }
44239beb93cSSam Leffler
44339beb93cSSam Leffler if ((int) hash_size != flen) {
44439beb93cSSam Leffler wpa_printf(MSG_INFO, "CryptoAPI: Invalid hash size (%u != %d)",
44539beb93cSSam Leffler (unsigned) hash_size, flen);
44639beb93cSSam Leffler RSAerr(RSA_F_RSA_EAY_PRIVATE_ENCRYPT,
44739beb93cSSam Leffler RSA_R_INVALID_MESSAGE_LENGTH);
44839beb93cSSam Leffler goto err;
44939beb93cSSam Leffler }
45039beb93cSSam Leffler if (!CryptSetHashParam(hash, HP_HASHVAL, (BYTE * ) from, 0)) {
45139beb93cSSam Leffler cryptoapi_error("CryptSetHashParam failed");
45239beb93cSSam Leffler goto err;
45339beb93cSSam Leffler }
45439beb93cSSam Leffler
45539beb93cSSam Leffler len = RSA_size(rsa);
45639beb93cSSam Leffler buf = os_malloc(len);
45739beb93cSSam Leffler if (buf == NULL) {
45839beb93cSSam Leffler RSAerr(RSA_F_RSA_EAY_PRIVATE_ENCRYPT, ERR_R_MALLOC_FAILURE);
45939beb93cSSam Leffler goto err;
46039beb93cSSam Leffler }
46139beb93cSSam Leffler
46239beb93cSSam Leffler if (!CryptSignHash(hash, priv->key_spec, NULL, 0, buf, &len)) {
46339beb93cSSam Leffler cryptoapi_error("CryptSignHash failed");
46439beb93cSSam Leffler goto err;
46539beb93cSSam Leffler }
46639beb93cSSam Leffler
46739beb93cSSam Leffler for (i = 0; i < len; i++)
46839beb93cSSam Leffler to[i] = buf[len - i - 1];
46939beb93cSSam Leffler ret = len;
47039beb93cSSam Leffler
47139beb93cSSam Leffler err:
47239beb93cSSam Leffler os_free(buf);
47339beb93cSSam Leffler CryptDestroyHash(hash);
47439beb93cSSam Leffler
47539beb93cSSam Leffler return ret;
47639beb93cSSam Leffler }
47739beb93cSSam Leffler
47839beb93cSSam Leffler
cryptoapi_rsa_priv_dec(int flen,const unsigned char * from,unsigned char * to,RSA * rsa,int padding)47939beb93cSSam Leffler static int cryptoapi_rsa_priv_dec(int flen, const unsigned char *from,
48039beb93cSSam Leffler unsigned char *to, RSA *rsa, int padding)
48139beb93cSSam Leffler {
48239beb93cSSam Leffler wpa_printf(MSG_DEBUG, "%s - not implemented", __func__);
48339beb93cSSam Leffler return 0;
48439beb93cSSam Leffler }
48539beb93cSSam Leffler
48639beb93cSSam Leffler
cryptoapi_free_data(struct cryptoapi_rsa_data * priv)48739beb93cSSam Leffler static void cryptoapi_free_data(struct cryptoapi_rsa_data *priv)
48839beb93cSSam Leffler {
48939beb93cSSam Leffler if (priv == NULL)
49039beb93cSSam Leffler return;
49139beb93cSSam Leffler if (priv->crypt_prov && priv->free_crypt_prov)
49239beb93cSSam Leffler CryptReleaseContext(priv->crypt_prov, 0);
49339beb93cSSam Leffler if (priv->cert)
49439beb93cSSam Leffler CertFreeCertificateContext(priv->cert);
49539beb93cSSam Leffler os_free(priv);
49639beb93cSSam Leffler }
49739beb93cSSam Leffler
49839beb93cSSam Leffler
cryptoapi_finish(RSA * rsa)49939beb93cSSam Leffler static int cryptoapi_finish(RSA *rsa)
50039beb93cSSam Leffler {
50139beb93cSSam Leffler cryptoapi_free_data((struct cryptoapi_rsa_data *) rsa->meth->app_data);
50239beb93cSSam Leffler os_free((void *) rsa->meth);
50339beb93cSSam Leffler rsa->meth = NULL;
50439beb93cSSam Leffler return 1;
50539beb93cSSam Leffler }
50639beb93cSSam Leffler
50739beb93cSSam Leffler
cryptoapi_find_cert(const char * name,DWORD store)50839beb93cSSam Leffler static const CERT_CONTEXT * cryptoapi_find_cert(const char *name, DWORD store)
50939beb93cSSam Leffler {
51039beb93cSSam Leffler HCERTSTORE cs;
51139beb93cSSam Leffler const CERT_CONTEXT *ret = NULL;
51239beb93cSSam Leffler
51339beb93cSSam Leffler cs = CertOpenStore((LPCSTR) CERT_STORE_PROV_SYSTEM, 0, 0,
51439beb93cSSam Leffler store | CERT_STORE_OPEN_EXISTING_FLAG |
51539beb93cSSam Leffler CERT_STORE_READONLY_FLAG, L"MY");
51639beb93cSSam Leffler if (cs == NULL) {
51739beb93cSSam Leffler cryptoapi_error("Failed to open 'My system store'");
51839beb93cSSam Leffler return NULL;
51939beb93cSSam Leffler }
52039beb93cSSam Leffler
52139beb93cSSam Leffler if (strncmp(name, "cert://", 7) == 0) {
52239beb93cSSam Leffler unsigned short wbuf[255];
52339beb93cSSam Leffler MultiByteToWideChar(CP_ACP, 0, name + 7, -1, wbuf, 255);
52439beb93cSSam Leffler ret = CertFindCertificateInStore(cs, X509_ASN_ENCODING |
52539beb93cSSam Leffler PKCS_7_ASN_ENCODING,
52639beb93cSSam Leffler 0, CERT_FIND_SUBJECT_STR,
52739beb93cSSam Leffler wbuf, NULL);
52839beb93cSSam Leffler } else if (strncmp(name, "hash://", 7) == 0) {
52939beb93cSSam Leffler CRYPT_HASH_BLOB blob;
53039beb93cSSam Leffler int len;
53139beb93cSSam Leffler const char *hash = name + 7;
53239beb93cSSam Leffler unsigned char *buf;
53339beb93cSSam Leffler
53439beb93cSSam Leffler len = os_strlen(hash) / 2;
53539beb93cSSam Leffler buf = os_malloc(len);
53639beb93cSSam Leffler if (buf && hexstr2bin(hash, buf, len) == 0) {
53739beb93cSSam Leffler blob.cbData = len;
53839beb93cSSam Leffler blob.pbData = buf;
53939beb93cSSam Leffler ret = CertFindCertificateInStore(cs,
54039beb93cSSam Leffler X509_ASN_ENCODING |
54139beb93cSSam Leffler PKCS_7_ASN_ENCODING,
54239beb93cSSam Leffler 0, CERT_FIND_HASH,
54339beb93cSSam Leffler &blob, NULL);
54439beb93cSSam Leffler }
54539beb93cSSam Leffler os_free(buf);
54639beb93cSSam Leffler }
54739beb93cSSam Leffler
54839beb93cSSam Leffler CertCloseStore(cs, 0);
54939beb93cSSam Leffler
55039beb93cSSam Leffler return ret;
55139beb93cSSam Leffler }
55239beb93cSSam Leffler
55339beb93cSSam Leffler
tls_cryptoapi_cert(SSL * ssl,const char * name)55439beb93cSSam Leffler static int tls_cryptoapi_cert(SSL *ssl, const char *name)
55539beb93cSSam Leffler {
55639beb93cSSam Leffler X509 *cert = NULL;
55739beb93cSSam Leffler RSA *rsa = NULL, *pub_rsa;
55839beb93cSSam Leffler struct cryptoapi_rsa_data *priv;
55939beb93cSSam Leffler RSA_METHOD *rsa_meth;
56039beb93cSSam Leffler
56139beb93cSSam Leffler if (name == NULL ||
56239beb93cSSam Leffler (strncmp(name, "cert://", 7) != 0 &&
56339beb93cSSam Leffler strncmp(name, "hash://", 7) != 0))
56439beb93cSSam Leffler return -1;
56539beb93cSSam Leffler
56639beb93cSSam Leffler priv = os_zalloc(sizeof(*priv));
56739beb93cSSam Leffler rsa_meth = os_zalloc(sizeof(*rsa_meth));
56839beb93cSSam Leffler if (priv == NULL || rsa_meth == NULL) {
56939beb93cSSam Leffler wpa_printf(MSG_WARNING, "CryptoAPI: Failed to allocate memory "
57039beb93cSSam Leffler "for CryptoAPI RSA method");
57139beb93cSSam Leffler os_free(priv);
57239beb93cSSam Leffler os_free(rsa_meth);
57339beb93cSSam Leffler return -1;
57439beb93cSSam Leffler }
57539beb93cSSam Leffler
57639beb93cSSam Leffler priv->cert = cryptoapi_find_cert(name, CERT_SYSTEM_STORE_CURRENT_USER);
57739beb93cSSam Leffler if (priv->cert == NULL) {
57839beb93cSSam Leffler priv->cert = cryptoapi_find_cert(
57939beb93cSSam Leffler name, CERT_SYSTEM_STORE_LOCAL_MACHINE);
58039beb93cSSam Leffler }
58139beb93cSSam Leffler if (priv->cert == NULL) {
58239beb93cSSam Leffler wpa_printf(MSG_INFO, "CryptoAPI: Could not find certificate "
58339beb93cSSam Leffler "'%s'", name);
58439beb93cSSam Leffler goto err;
58539beb93cSSam Leffler }
58639beb93cSSam Leffler
5875b9c547cSRui Paulo cert = d2i_X509(NULL,
5885b9c547cSRui Paulo (const unsigned char **) &priv->cert->pbCertEncoded,
58939beb93cSSam Leffler priv->cert->cbCertEncoded);
59039beb93cSSam Leffler if (cert == NULL) {
59139beb93cSSam Leffler wpa_printf(MSG_INFO, "CryptoAPI: Could not process X509 DER "
59239beb93cSSam Leffler "encoding");
59339beb93cSSam Leffler goto err;
59439beb93cSSam Leffler }
59539beb93cSSam Leffler
59639beb93cSSam Leffler if (!CryptAcquireCertificatePrivateKey(priv->cert,
59739beb93cSSam Leffler CRYPT_ACQUIRE_COMPARE_KEY_FLAG,
59839beb93cSSam Leffler NULL, &priv->crypt_prov,
59939beb93cSSam Leffler &priv->key_spec,
60039beb93cSSam Leffler &priv->free_crypt_prov)) {
60139beb93cSSam Leffler cryptoapi_error("Failed to acquire a private key for the "
60239beb93cSSam Leffler "certificate");
60339beb93cSSam Leffler goto err;
60439beb93cSSam Leffler }
60539beb93cSSam Leffler
60639beb93cSSam Leffler rsa_meth->name = "Microsoft CryptoAPI RSA Method";
60739beb93cSSam Leffler rsa_meth->rsa_pub_enc = cryptoapi_rsa_pub_enc;
60839beb93cSSam Leffler rsa_meth->rsa_pub_dec = cryptoapi_rsa_pub_dec;
60939beb93cSSam Leffler rsa_meth->rsa_priv_enc = cryptoapi_rsa_priv_enc;
61039beb93cSSam Leffler rsa_meth->rsa_priv_dec = cryptoapi_rsa_priv_dec;
61139beb93cSSam Leffler rsa_meth->finish = cryptoapi_finish;
61239beb93cSSam Leffler rsa_meth->flags = RSA_METHOD_FLAG_NO_CHECK;
61339beb93cSSam Leffler rsa_meth->app_data = (char *) priv;
61439beb93cSSam Leffler
61539beb93cSSam Leffler rsa = RSA_new();
61639beb93cSSam Leffler if (rsa == NULL) {
61739beb93cSSam Leffler SSLerr(SSL_F_SSL_CTX_USE_CERTIFICATE_FILE,
61839beb93cSSam Leffler ERR_R_MALLOC_FAILURE);
61939beb93cSSam Leffler goto err;
62039beb93cSSam Leffler }
62139beb93cSSam Leffler
62239beb93cSSam Leffler if (!SSL_use_certificate(ssl, cert)) {
62339beb93cSSam Leffler RSA_free(rsa);
62439beb93cSSam Leffler rsa = NULL;
62539beb93cSSam Leffler goto err;
62639beb93cSSam Leffler }
62739beb93cSSam Leffler pub_rsa = cert->cert_info->key->pkey->pkey.rsa;
62839beb93cSSam Leffler X509_free(cert);
62939beb93cSSam Leffler cert = NULL;
63039beb93cSSam Leffler
63139beb93cSSam Leffler rsa->n = BN_dup(pub_rsa->n);
63239beb93cSSam Leffler rsa->e = BN_dup(pub_rsa->e);
63339beb93cSSam Leffler if (!RSA_set_method(rsa, rsa_meth))
63439beb93cSSam Leffler goto err;
63539beb93cSSam Leffler
63639beb93cSSam Leffler if (!SSL_use_RSAPrivateKey(ssl, rsa))
63739beb93cSSam Leffler goto err;
63839beb93cSSam Leffler RSA_free(rsa);
63939beb93cSSam Leffler
64039beb93cSSam Leffler return 0;
64139beb93cSSam Leffler
64239beb93cSSam Leffler err:
64339beb93cSSam Leffler if (cert)
64439beb93cSSam Leffler X509_free(cert);
64539beb93cSSam Leffler if (rsa)
64639beb93cSSam Leffler RSA_free(rsa);
64739beb93cSSam Leffler else {
64839beb93cSSam Leffler os_free(rsa_meth);
64939beb93cSSam Leffler cryptoapi_free_data(priv);
65039beb93cSSam Leffler }
65139beb93cSSam Leffler return -1;
65239beb93cSSam Leffler }
65339beb93cSSam Leffler
65439beb93cSSam Leffler
tls_cryptoapi_ca_cert(SSL_CTX * ssl_ctx,SSL * ssl,const char * name)65539beb93cSSam Leffler static int tls_cryptoapi_ca_cert(SSL_CTX *ssl_ctx, SSL *ssl, const char *name)
65639beb93cSSam Leffler {
65739beb93cSSam Leffler HCERTSTORE cs;
65839beb93cSSam Leffler PCCERT_CONTEXT ctx = NULL;
65939beb93cSSam Leffler X509 *cert;
66039beb93cSSam Leffler char buf[128];
66139beb93cSSam Leffler const char *store;
66239beb93cSSam Leffler #ifdef UNICODE
66339beb93cSSam Leffler WCHAR *wstore;
66439beb93cSSam Leffler #endif /* UNICODE */
66539beb93cSSam Leffler
66639beb93cSSam Leffler if (name == NULL || strncmp(name, "cert_store://", 13) != 0)
66739beb93cSSam Leffler return -1;
66839beb93cSSam Leffler
66939beb93cSSam Leffler store = name + 13;
67039beb93cSSam Leffler #ifdef UNICODE
67139beb93cSSam Leffler wstore = os_malloc((os_strlen(store) + 1) * sizeof(WCHAR));
67239beb93cSSam Leffler if (wstore == NULL)
67339beb93cSSam Leffler return -1;
67439beb93cSSam Leffler wsprintf(wstore, L"%S", store);
67539beb93cSSam Leffler cs = CertOpenSystemStore(0, wstore);
67639beb93cSSam Leffler os_free(wstore);
67739beb93cSSam Leffler #else /* UNICODE */
67839beb93cSSam Leffler cs = CertOpenSystemStore(0, store);
67939beb93cSSam Leffler #endif /* UNICODE */
68039beb93cSSam Leffler if (cs == NULL) {
68139beb93cSSam Leffler wpa_printf(MSG_DEBUG, "%s: failed to open system cert store "
68239beb93cSSam Leffler "'%s': error=%d", __func__, store,
68339beb93cSSam Leffler (int) GetLastError());
68439beb93cSSam Leffler return -1;
68539beb93cSSam Leffler }
68639beb93cSSam Leffler
68739beb93cSSam Leffler while ((ctx = CertEnumCertificatesInStore(cs, ctx))) {
6885b9c547cSRui Paulo cert = d2i_X509(NULL,
6895b9c547cSRui Paulo (const unsigned char **) &ctx->pbCertEncoded,
69039beb93cSSam Leffler ctx->cbCertEncoded);
69139beb93cSSam Leffler if (cert == NULL) {
69239beb93cSSam Leffler wpa_printf(MSG_INFO, "CryptoAPI: Could not process "
69339beb93cSSam Leffler "X509 DER encoding for CA cert");
69439beb93cSSam Leffler continue;
69539beb93cSSam Leffler }
69639beb93cSSam Leffler
69739beb93cSSam Leffler X509_NAME_oneline(X509_get_subject_name(cert), buf,
69839beb93cSSam Leffler sizeof(buf));
69939beb93cSSam Leffler wpa_printf(MSG_DEBUG, "OpenSSL: Loaded CA certificate for "
70039beb93cSSam Leffler "system certificate store: subject='%s'", buf);
70139beb93cSSam Leffler
702780fb4a2SCy Schubert if (!X509_STORE_add_cert(SSL_CTX_get_cert_store(ssl_ctx),
703780fb4a2SCy Schubert cert)) {
70439beb93cSSam Leffler tls_show_errors(MSG_WARNING, __func__,
70539beb93cSSam Leffler "Failed to add ca_cert to OpenSSL "
70639beb93cSSam Leffler "certificate store");
70739beb93cSSam Leffler }
70839beb93cSSam Leffler
70939beb93cSSam Leffler X509_free(cert);
71039beb93cSSam Leffler }
71139beb93cSSam Leffler
71239beb93cSSam Leffler if (!CertCloseStore(cs, 0)) {
71339beb93cSSam Leffler wpa_printf(MSG_DEBUG, "%s: failed to close system cert store "
71439beb93cSSam Leffler "'%s': error=%d", __func__, name + 13,
71539beb93cSSam Leffler (int) GetLastError());
71639beb93cSSam Leffler }
71739beb93cSSam Leffler
71839beb93cSSam Leffler return 0;
71939beb93cSSam Leffler }
72039beb93cSSam Leffler
72139beb93cSSam Leffler
72239beb93cSSam Leffler #else /* CONFIG_NATIVE_WINDOWS */
72339beb93cSSam Leffler
tls_cryptoapi_cert(SSL * ssl,const char * name)72439beb93cSSam Leffler static int tls_cryptoapi_cert(SSL *ssl, const char *name)
72539beb93cSSam Leffler {
72639beb93cSSam Leffler return -1;
72739beb93cSSam Leffler }
72839beb93cSSam Leffler
72939beb93cSSam Leffler #endif /* CONFIG_NATIVE_WINDOWS */
73039beb93cSSam Leffler
73139beb93cSSam Leffler
ssl_info_cb(const SSL * ssl,int where,int ret)73239beb93cSSam Leffler static void ssl_info_cb(const SSL *ssl, int where, int ret)
73339beb93cSSam Leffler {
73439beb93cSSam Leffler const char *str;
73539beb93cSSam Leffler int w;
73639beb93cSSam Leffler
73739beb93cSSam Leffler wpa_printf(MSG_DEBUG, "SSL: (where=0x%x ret=0x%x)", where, ret);
73839beb93cSSam Leffler w = where & ~SSL_ST_MASK;
73939beb93cSSam Leffler if (w & SSL_ST_CONNECT)
74039beb93cSSam Leffler str = "SSL_connect";
74139beb93cSSam Leffler else if (w & SSL_ST_ACCEPT)
74239beb93cSSam Leffler str = "SSL_accept";
74339beb93cSSam Leffler else
74439beb93cSSam Leffler str = "undefined";
74539beb93cSSam Leffler
74639beb93cSSam Leffler if (where & SSL_CB_LOOP) {
74739beb93cSSam Leffler wpa_printf(MSG_DEBUG, "SSL: %s:%s",
74839beb93cSSam Leffler str, SSL_state_string_long(ssl));
74939beb93cSSam Leffler } else if (where & SSL_CB_ALERT) {
7505b9c547cSRui Paulo struct tls_connection *conn = SSL_get_app_data((SSL *) ssl);
75139beb93cSSam Leffler wpa_printf(MSG_INFO, "SSL: SSL3 alert: %s:%s:%s",
75239beb93cSSam Leffler where & SSL_CB_READ ?
75339beb93cSSam Leffler "read (remote end reported an error)" :
75439beb93cSSam Leffler "write (local SSL3 detected an error)",
75539beb93cSSam Leffler SSL_alert_type_string_long(ret),
75639beb93cSSam Leffler SSL_alert_desc_string_long(ret));
75739beb93cSSam Leffler if ((ret >> 8) == SSL3_AL_FATAL) {
75839beb93cSSam Leffler if (where & SSL_CB_READ)
75939beb93cSSam Leffler conn->read_alerts++;
76039beb93cSSam Leffler else
76139beb93cSSam Leffler conn->write_alerts++;
76239beb93cSSam Leffler }
7635b9c547cSRui Paulo if (conn->context->event_cb != NULL) {
764f05cddf9SRui Paulo union tls_event_data ev;
7655b9c547cSRui Paulo struct tls_context *context = conn->context;
766f05cddf9SRui Paulo os_memset(&ev, 0, sizeof(ev));
767f05cddf9SRui Paulo ev.alert.is_local = !(where & SSL_CB_READ);
768f05cddf9SRui Paulo ev.alert.type = SSL_alert_type_string_long(ret);
769f05cddf9SRui Paulo ev.alert.description = SSL_alert_desc_string_long(ret);
7705b9c547cSRui Paulo context->event_cb(context->cb_ctx, TLS_ALERT, &ev);
771f05cddf9SRui Paulo }
77239beb93cSSam Leffler } else if (where & SSL_CB_EXIT && ret <= 0) {
77339beb93cSSam Leffler wpa_printf(MSG_DEBUG, "SSL: %s:%s in %s",
77439beb93cSSam Leffler str, ret == 0 ? "failed" : "error",
77539beb93cSSam Leffler SSL_state_string_long(ssl));
77639beb93cSSam Leffler }
77739beb93cSSam Leffler }
77839beb93cSSam Leffler
77939beb93cSSam Leffler
78039beb93cSSam Leffler #ifndef OPENSSL_NO_ENGINE
78139beb93cSSam Leffler /**
78239beb93cSSam Leffler * tls_engine_load_dynamic_generic - load any openssl engine
78339beb93cSSam Leffler * @pre: an array of commands and values that load an engine initialized
78439beb93cSSam Leffler * in the engine specific function
78539beb93cSSam Leffler * @post: an array of commands and values that initialize an already loaded
78639beb93cSSam Leffler * engine (or %NULL if not required)
78739beb93cSSam Leffler * @id: the engine id of the engine to load (only required if post is not %NULL
78839beb93cSSam Leffler *
78939beb93cSSam Leffler * This function is a generic function that loads any openssl engine.
79039beb93cSSam Leffler *
79139beb93cSSam Leffler * Returns: 0 on success, -1 on failure
79239beb93cSSam Leffler */
tls_engine_load_dynamic_generic(const char * pre[],const char * post[],const char * id)79339beb93cSSam Leffler static int tls_engine_load_dynamic_generic(const char *pre[],
79439beb93cSSam Leffler const char *post[], const char *id)
79539beb93cSSam Leffler {
79639beb93cSSam Leffler ENGINE *engine;
79739beb93cSSam Leffler const char *dynamic_id = "dynamic";
79839beb93cSSam Leffler
79939beb93cSSam Leffler engine = ENGINE_by_id(id);
80039beb93cSSam Leffler if (engine) {
80139beb93cSSam Leffler wpa_printf(MSG_DEBUG, "ENGINE: engine '%s' is already "
80239beb93cSSam Leffler "available", id);
803780fb4a2SCy Schubert /*
804780fb4a2SCy Schubert * If it was auto-loaded by ENGINE_by_id() we might still
805780fb4a2SCy Schubert * need to tell it which PKCS#11 module to use in legacy
806780fb4a2SCy Schubert * (non-p11-kit) environments. Do so now; even if it was
807780fb4a2SCy Schubert * properly initialised before, setting it again will be
808780fb4a2SCy Schubert * harmless.
809780fb4a2SCy Schubert */
810780fb4a2SCy Schubert goto found;
81139beb93cSSam Leffler }
81239beb93cSSam Leffler ERR_clear_error();
81339beb93cSSam Leffler
81439beb93cSSam Leffler engine = ENGINE_by_id(dynamic_id);
81539beb93cSSam Leffler if (engine == NULL) {
81639beb93cSSam Leffler wpa_printf(MSG_INFO, "ENGINE: Can't find engine %s [%s]",
81739beb93cSSam Leffler dynamic_id,
81839beb93cSSam Leffler ERR_error_string(ERR_get_error(), NULL));
81939beb93cSSam Leffler return -1;
82039beb93cSSam Leffler }
82139beb93cSSam Leffler
82239beb93cSSam Leffler /* Perform the pre commands. This will load the engine. */
82339beb93cSSam Leffler while (pre && pre[0]) {
82439beb93cSSam Leffler wpa_printf(MSG_DEBUG, "ENGINE: '%s' '%s'", pre[0], pre[1]);
82539beb93cSSam Leffler if (ENGINE_ctrl_cmd_string(engine, pre[0], pre[1], 0) == 0) {
82639beb93cSSam Leffler wpa_printf(MSG_INFO, "ENGINE: ctrl cmd_string failed: "
82739beb93cSSam Leffler "%s %s [%s]", pre[0], pre[1],
82839beb93cSSam Leffler ERR_error_string(ERR_get_error(), NULL));
82939beb93cSSam Leffler ENGINE_free(engine);
83039beb93cSSam Leffler return -1;
83139beb93cSSam Leffler }
83239beb93cSSam Leffler pre += 2;
83339beb93cSSam Leffler }
83439beb93cSSam Leffler
83539beb93cSSam Leffler /*
83639beb93cSSam Leffler * Free the reference to the "dynamic" engine. The loaded engine can
83739beb93cSSam Leffler * now be looked up using ENGINE_by_id().
83839beb93cSSam Leffler */
83939beb93cSSam Leffler ENGINE_free(engine);
84039beb93cSSam Leffler
84139beb93cSSam Leffler engine = ENGINE_by_id(id);
84239beb93cSSam Leffler if (engine == NULL) {
84339beb93cSSam Leffler wpa_printf(MSG_INFO, "ENGINE: Can't find engine %s [%s]",
84439beb93cSSam Leffler id, ERR_error_string(ERR_get_error(), NULL));
84539beb93cSSam Leffler return -1;
84639beb93cSSam Leffler }
847780fb4a2SCy Schubert found:
84839beb93cSSam Leffler while (post && post[0]) {
84939beb93cSSam Leffler wpa_printf(MSG_DEBUG, "ENGINE: '%s' '%s'", post[0], post[1]);
85039beb93cSSam Leffler if (ENGINE_ctrl_cmd_string(engine, post[0], post[1], 0) == 0) {
85139beb93cSSam Leffler wpa_printf(MSG_DEBUG, "ENGINE: ctrl cmd_string failed:"
85239beb93cSSam Leffler " %s %s [%s]", post[0], post[1],
85339beb93cSSam Leffler ERR_error_string(ERR_get_error(), NULL));
85439beb93cSSam Leffler ENGINE_remove(engine);
85539beb93cSSam Leffler ENGINE_free(engine);
85639beb93cSSam Leffler return -1;
85739beb93cSSam Leffler }
85839beb93cSSam Leffler post += 2;
85939beb93cSSam Leffler }
86039beb93cSSam Leffler ENGINE_free(engine);
86139beb93cSSam Leffler
86239beb93cSSam Leffler return 0;
86339beb93cSSam Leffler }
86439beb93cSSam Leffler
86539beb93cSSam Leffler
86639beb93cSSam Leffler /**
86739beb93cSSam Leffler * tls_engine_load_dynamic_pkcs11 - load the pkcs11 engine provided by opensc
86839beb93cSSam Leffler * @pkcs11_so_path: pksc11_so_path from the configuration
86939beb93cSSam Leffler * @pcks11_module_path: pkcs11_module_path from the configuration
87039beb93cSSam Leffler */
tls_engine_load_dynamic_pkcs11(const char * pkcs11_so_path,const char * pkcs11_module_path)87139beb93cSSam Leffler static int tls_engine_load_dynamic_pkcs11(const char *pkcs11_so_path,
87239beb93cSSam Leffler const char *pkcs11_module_path)
87339beb93cSSam Leffler {
87439beb93cSSam Leffler char *engine_id = "pkcs11";
87539beb93cSSam Leffler const char *pre_cmd[] = {
87639beb93cSSam Leffler "SO_PATH", NULL /* pkcs11_so_path */,
87739beb93cSSam Leffler "ID", NULL /* engine_id */,
87839beb93cSSam Leffler "LIST_ADD", "1",
87939beb93cSSam Leffler /* "NO_VCHECK", "1", */
88039beb93cSSam Leffler "LOAD", NULL,
88139beb93cSSam Leffler NULL, NULL
88239beb93cSSam Leffler };
88339beb93cSSam Leffler const char *post_cmd[] = {
88439beb93cSSam Leffler "MODULE_PATH", NULL /* pkcs11_module_path */,
88539beb93cSSam Leffler NULL, NULL
88639beb93cSSam Leffler };
88739beb93cSSam Leffler
8885b9c547cSRui Paulo if (!pkcs11_so_path)
88939beb93cSSam Leffler return 0;
89039beb93cSSam Leffler
89139beb93cSSam Leffler pre_cmd[1] = pkcs11_so_path;
89239beb93cSSam Leffler pre_cmd[3] = engine_id;
8935b9c547cSRui Paulo if (pkcs11_module_path)
89439beb93cSSam Leffler post_cmd[1] = pkcs11_module_path;
8955b9c547cSRui Paulo else
8965b9c547cSRui Paulo post_cmd[0] = NULL;
89739beb93cSSam Leffler
89839beb93cSSam Leffler wpa_printf(MSG_DEBUG, "ENGINE: Loading pkcs11 Engine from %s",
89939beb93cSSam Leffler pkcs11_so_path);
90039beb93cSSam Leffler
90139beb93cSSam Leffler return tls_engine_load_dynamic_generic(pre_cmd, post_cmd, engine_id);
90239beb93cSSam Leffler }
90339beb93cSSam Leffler
90439beb93cSSam Leffler
90539beb93cSSam Leffler /**
90639beb93cSSam Leffler * tls_engine_load_dynamic_opensc - load the opensc engine provided by opensc
90739beb93cSSam Leffler * @opensc_so_path: opensc_so_path from the configuration
90839beb93cSSam Leffler */
tls_engine_load_dynamic_opensc(const char * opensc_so_path)90939beb93cSSam Leffler static int tls_engine_load_dynamic_opensc(const char *opensc_so_path)
91039beb93cSSam Leffler {
91139beb93cSSam Leffler char *engine_id = "opensc";
91239beb93cSSam Leffler const char *pre_cmd[] = {
91339beb93cSSam Leffler "SO_PATH", NULL /* opensc_so_path */,
91439beb93cSSam Leffler "ID", NULL /* engine_id */,
91539beb93cSSam Leffler "LIST_ADD", "1",
91639beb93cSSam Leffler "LOAD", NULL,
91739beb93cSSam Leffler NULL, NULL
91839beb93cSSam Leffler };
91939beb93cSSam Leffler
92039beb93cSSam Leffler if (!opensc_so_path)
92139beb93cSSam Leffler return 0;
92239beb93cSSam Leffler
92339beb93cSSam Leffler pre_cmd[1] = opensc_so_path;
92439beb93cSSam Leffler pre_cmd[3] = engine_id;
92539beb93cSSam Leffler
92639beb93cSSam Leffler wpa_printf(MSG_DEBUG, "ENGINE: Loading OpenSC Engine from %s",
92739beb93cSSam Leffler opensc_so_path);
92839beb93cSSam Leffler
92939beb93cSSam Leffler return tls_engine_load_dynamic_generic(pre_cmd, NULL, engine_id);
93039beb93cSSam Leffler }
93139beb93cSSam Leffler #endif /* OPENSSL_NO_ENGINE */
93239beb93cSSam Leffler
93339beb93cSSam Leffler
remove_session_cb(SSL_CTX * ctx,SSL_SESSION * sess)934325151a3SRui Paulo static void remove_session_cb(SSL_CTX *ctx, SSL_SESSION *sess)
935325151a3SRui Paulo {
936325151a3SRui Paulo struct wpabuf *buf;
937325151a3SRui Paulo
938325151a3SRui Paulo if (tls_ex_idx_session < 0)
939325151a3SRui Paulo return;
940325151a3SRui Paulo buf = SSL_SESSION_get_ex_data(sess, tls_ex_idx_session);
941325151a3SRui Paulo if (!buf)
942325151a3SRui Paulo return;
943325151a3SRui Paulo wpa_printf(MSG_DEBUG,
944325151a3SRui Paulo "OpenSSL: Free application session data %p (sess %p)",
945325151a3SRui Paulo buf, sess);
946325151a3SRui Paulo wpabuf_free(buf);
947325151a3SRui Paulo
948325151a3SRui Paulo SSL_SESSION_set_ex_data(sess, tls_ex_idx_session, NULL);
949325151a3SRui Paulo }
950325151a3SRui Paulo
951325151a3SRui Paulo
tls_init(const struct tls_config * conf)95239beb93cSSam Leffler void * tls_init(const struct tls_config *conf)
95339beb93cSSam Leffler {
954325151a3SRui Paulo struct tls_data *data;
95539beb93cSSam Leffler SSL_CTX *ssl;
9565b9c547cSRui Paulo struct tls_context *context;
9575b9c547cSRui Paulo const char *ciphers;
95839beb93cSSam Leffler
95939beb93cSSam Leffler if (tls_openssl_ref_count == 0) {
960ec080394SCy Schubert void openssl_load_legacy_provider(void);
961ec080394SCy Schubert
962ec080394SCy Schubert openssl_load_legacy_provider();
963ec080394SCy Schubert
9645b9c547cSRui Paulo tls_global = context = tls_context_new(conf);
9655b9c547cSRui Paulo if (context == NULL)
966e28a4053SRui Paulo return NULL;
967e28a4053SRui Paulo #ifdef CONFIG_FIPS
968e28a4053SRui Paulo #ifdef OPENSSL_FIPS
969e28a4053SRui Paulo if (conf && conf->fips_mode) {
970325151a3SRui Paulo static int fips_enabled = 0;
971325151a3SRui Paulo
972325151a3SRui Paulo if (!fips_enabled && !FIPS_mode_set(1)) {
973e28a4053SRui Paulo wpa_printf(MSG_ERROR, "Failed to enable FIPS "
974e28a4053SRui Paulo "mode");
975e28a4053SRui Paulo ERR_load_crypto_strings();
976e28a4053SRui Paulo ERR_print_errors_fp(stderr);
977f05cddf9SRui Paulo os_free(tls_global);
978f05cddf9SRui Paulo tls_global = NULL;
979e28a4053SRui Paulo return NULL;
980325151a3SRui Paulo } else {
981e28a4053SRui Paulo wpa_printf(MSG_INFO, "Running in FIPS mode");
982325151a3SRui Paulo fips_enabled = 1;
983325151a3SRui Paulo }
984e28a4053SRui Paulo }
985e28a4053SRui Paulo #else /* OPENSSL_FIPS */
986e28a4053SRui Paulo if (conf && conf->fips_mode) {
987e28a4053SRui Paulo wpa_printf(MSG_ERROR, "FIPS mode requested, but not "
988e28a4053SRui Paulo "supported");
989f05cddf9SRui Paulo os_free(tls_global);
990f05cddf9SRui Paulo tls_global = NULL;
991e28a4053SRui Paulo return NULL;
992e28a4053SRui Paulo }
993e28a4053SRui Paulo #endif /* OPENSSL_FIPS */
994e28a4053SRui Paulo #endif /* CONFIG_FIPS */
99585732ac8SCy Schubert #if OPENSSL_VERSION_NUMBER < 0x10100000L || \
99685732ac8SCy Schubert (defined(LIBRESSL_VERSION_NUMBER) && \
99785732ac8SCy Schubert LIBRESSL_VERSION_NUMBER < 0x20700000L)
99839beb93cSSam Leffler SSL_load_error_strings();
99939beb93cSSam Leffler SSL_library_init();
10005b9c547cSRui Paulo #ifndef OPENSSL_NO_SHA256
10013157ba21SRui Paulo EVP_add_digest(EVP_sha256());
10023157ba21SRui Paulo #endif /* OPENSSL_NO_SHA256 */
100339beb93cSSam Leffler /* TODO: if /dev/urandom is available, PRNG is seeded
100439beb93cSSam Leffler * automatically. If this is not the case, random data should
100539beb93cSSam Leffler * be added here. */
100639beb93cSSam Leffler
100739beb93cSSam Leffler #ifdef PKCS12_FUNCS
10083157ba21SRui Paulo #ifndef OPENSSL_NO_RC2
10093157ba21SRui Paulo /*
10103157ba21SRui Paulo * 40-bit RC2 is commonly used in PKCS#12 files, so enable it.
10113157ba21SRui Paulo * This is enabled by PKCS12_PBE_add() in OpenSSL 0.9.8
10123157ba21SRui Paulo * versions, but it looks like OpenSSL 1.0.0 does not do that
10133157ba21SRui Paulo * anymore.
10143157ba21SRui Paulo */
10153157ba21SRui Paulo EVP_add_cipher(EVP_rc2_40_cbc());
10163157ba21SRui Paulo #endif /* OPENSSL_NO_RC2 */
101739beb93cSSam Leffler PKCS12_PBE_add();
101839beb93cSSam Leffler #endif /* PKCS12_FUNCS */
1019780fb4a2SCy Schubert #endif /* < 1.1.0 */
10205b9c547cSRui Paulo } else {
10215b9c547cSRui Paulo context = tls_context_new(conf);
10225b9c547cSRui Paulo if (context == NULL)
10235b9c547cSRui Paulo return NULL;
102439beb93cSSam Leffler }
102539beb93cSSam Leffler tls_openssl_ref_count++;
102639beb93cSSam Leffler
1027325151a3SRui Paulo data = os_zalloc(sizeof(*data));
1028325151a3SRui Paulo if (data)
10295b9c547cSRui Paulo ssl = SSL_CTX_new(SSLv23_method());
1030325151a3SRui Paulo else
1031325151a3SRui Paulo ssl = NULL;
10325b9c547cSRui Paulo if (ssl == NULL) {
10335b9c547cSRui Paulo tls_openssl_ref_count--;
10345b9c547cSRui Paulo if (context != tls_global)
10355b9c547cSRui Paulo os_free(context);
10365b9c547cSRui Paulo if (tls_openssl_ref_count == 0) {
10375b9c547cSRui Paulo os_free(tls_global);
10385b9c547cSRui Paulo tls_global = NULL;
10395b9c547cSRui Paulo }
1040780fb4a2SCy Schubert os_free(data);
104139beb93cSSam Leffler return NULL;
10425b9c547cSRui Paulo }
1043325151a3SRui Paulo data->ssl = ssl;
10444bc52338SCy Schubert if (conf) {
1045325151a3SRui Paulo data->tls_session_lifetime = conf->tls_session_lifetime;
10464bc52338SCy Schubert data->crl_reload_interval = conf->crl_reload_interval;
10474bc52338SCy Schubert }
10485b9c547cSRui Paulo
10495b9c547cSRui Paulo SSL_CTX_set_options(ssl, SSL_OP_NO_SSLv2);
10505b9c547cSRui Paulo SSL_CTX_set_options(ssl, SSL_OP_NO_SSLv3);
105139beb93cSSam Leffler
1052c1d255d3SCy Schubert SSL_CTX_set_mode(ssl, SSL_MODE_AUTO_RETRY);
1053c1d255d3SCy Schubert
105485732ac8SCy Schubert #ifdef SSL_MODE_NO_AUTO_CHAIN
105585732ac8SCy Schubert /* Number of deployed use cases assume the default OpenSSL behavior of
105685732ac8SCy Schubert * auto chaining the local certificate is in use. BoringSSL removed this
105785732ac8SCy Schubert * functionality by default, so we need to restore it here to avoid
105885732ac8SCy Schubert * breaking existing use cases. */
105985732ac8SCy Schubert SSL_CTX_clear_mode(ssl, SSL_MODE_NO_AUTO_CHAIN);
106085732ac8SCy Schubert #endif /* SSL_MODE_NO_AUTO_CHAIN */
106185732ac8SCy Schubert
106239beb93cSSam Leffler SSL_CTX_set_info_callback(ssl, ssl_info_cb);
10635b9c547cSRui Paulo SSL_CTX_set_app_data(ssl, context);
1064325151a3SRui Paulo if (data->tls_session_lifetime > 0) {
1065325151a3SRui Paulo SSL_CTX_set_quiet_shutdown(ssl, 1);
1066325151a3SRui Paulo /*
1067325151a3SRui Paulo * Set default context here. In practice, this will be replaced
1068325151a3SRui Paulo * by the per-EAP method context in tls_connection_set_verify().
1069325151a3SRui Paulo */
1070325151a3SRui Paulo SSL_CTX_set_session_id_context(ssl, (u8 *) "hostapd", 7);
1071325151a3SRui Paulo SSL_CTX_set_session_cache_mode(ssl, SSL_SESS_CACHE_SERVER);
1072325151a3SRui Paulo SSL_CTX_set_timeout(ssl, data->tls_session_lifetime);
1073325151a3SRui Paulo SSL_CTX_sess_set_remove_cb(ssl, remove_session_cb);
1074325151a3SRui Paulo } else {
1075325151a3SRui Paulo SSL_CTX_set_session_cache_mode(ssl, SSL_SESS_CACHE_OFF);
1076325151a3SRui Paulo }
1077325151a3SRui Paulo
1078325151a3SRui Paulo if (tls_ex_idx_session < 0) {
1079325151a3SRui Paulo tls_ex_idx_session = SSL_SESSION_get_ex_new_index(
1080325151a3SRui Paulo 0, NULL, NULL, NULL, NULL);
1081325151a3SRui Paulo if (tls_ex_idx_session < 0) {
1082325151a3SRui Paulo tls_deinit(data);
1083325151a3SRui Paulo return NULL;
1084325151a3SRui Paulo }
1085325151a3SRui Paulo }
108639beb93cSSam Leffler
108739beb93cSSam Leffler #ifndef OPENSSL_NO_ENGINE
1088206b73d0SCy Schubert wpa_printf(MSG_DEBUG, "ENGINE: Loading builtin engines");
1089206b73d0SCy Schubert ENGINE_load_builtin_engines();
109039beb93cSSam Leffler
10915b9c547cSRui Paulo if (conf &&
10925b9c547cSRui Paulo (conf->opensc_engine_path || conf->pkcs11_engine_path ||
10935b9c547cSRui Paulo conf->pkcs11_module_path)) {
109439beb93cSSam Leffler if (tls_engine_load_dynamic_opensc(conf->opensc_engine_path) ||
109539beb93cSSam Leffler tls_engine_load_dynamic_pkcs11(conf->pkcs11_engine_path,
109639beb93cSSam Leffler conf->pkcs11_module_path)) {
1097325151a3SRui Paulo tls_deinit(data);
109839beb93cSSam Leffler return NULL;
109939beb93cSSam Leffler }
110039beb93cSSam Leffler }
110139beb93cSSam Leffler #endif /* OPENSSL_NO_ENGINE */
110239beb93cSSam Leffler
11035b9c547cSRui Paulo if (conf && conf->openssl_ciphers)
11045b9c547cSRui Paulo ciphers = conf->openssl_ciphers;
11055b9c547cSRui Paulo else
110685732ac8SCy Schubert ciphers = TLS_DEFAULT_CIPHERS;
11075b9c547cSRui Paulo if (SSL_CTX_set_cipher_list(ssl, ciphers) != 1) {
11085b9c547cSRui Paulo wpa_printf(MSG_ERROR,
11095b9c547cSRui Paulo "OpenSSL: Failed to set cipher string '%s'",
11105b9c547cSRui Paulo ciphers);
1111325151a3SRui Paulo tls_deinit(data);
11125b9c547cSRui Paulo return NULL;
11135b9c547cSRui Paulo }
11145b9c547cSRui Paulo
1115325151a3SRui Paulo return data;
111639beb93cSSam Leffler }
111739beb93cSSam Leffler
111839beb93cSSam Leffler
tls_deinit(void * ssl_ctx)111939beb93cSSam Leffler void tls_deinit(void *ssl_ctx)
112039beb93cSSam Leffler {
1121325151a3SRui Paulo struct tls_data *data = ssl_ctx;
1122325151a3SRui Paulo SSL_CTX *ssl = data->ssl;
11235b9c547cSRui Paulo struct tls_context *context = SSL_CTX_get_app_data(ssl);
11245b9c547cSRui Paulo if (context != tls_global)
11255b9c547cSRui Paulo os_free(context);
1126325151a3SRui Paulo if (data->tls_session_lifetime > 0)
1127325151a3SRui Paulo SSL_CTX_flush_sessions(ssl, 0);
11284bc52338SCy Schubert os_free(data->ca_cert);
112939beb93cSSam Leffler SSL_CTX_free(ssl);
113039beb93cSSam Leffler
113139beb93cSSam Leffler tls_openssl_ref_count--;
113239beb93cSSam Leffler if (tls_openssl_ref_count == 0) {
113385732ac8SCy Schubert #if OPENSSL_VERSION_NUMBER < 0x10100000L || \
113485732ac8SCy Schubert (defined(LIBRESSL_VERSION_NUMBER) && \
113585732ac8SCy Schubert LIBRESSL_VERSION_NUMBER < 0x20700000L)
113639beb93cSSam Leffler #ifndef OPENSSL_NO_ENGINE
113739beb93cSSam Leffler ENGINE_cleanup();
113839beb93cSSam Leffler #endif /* OPENSSL_NO_ENGINE */
113939beb93cSSam Leffler CRYPTO_cleanup_all_ex_data();
11405b9c547cSRui Paulo ERR_remove_thread_state(NULL);
114139beb93cSSam Leffler ERR_free_strings();
114239beb93cSSam Leffler EVP_cleanup();
1143780fb4a2SCy Schubert #endif /* < 1.1.0 */
11445b9c547cSRui Paulo os_free(tls_global->ocsp_stapling_response);
11455b9c547cSRui Paulo tls_global->ocsp_stapling_response = NULL;
1146e28a4053SRui Paulo os_free(tls_global);
1147e28a4053SRui Paulo tls_global = NULL;
114839beb93cSSam Leffler }
1149325151a3SRui Paulo
11504bc52338SCy Schubert os_free(data->check_cert_subject);
1151325151a3SRui Paulo os_free(data);
115239beb93cSSam Leffler }
115339beb93cSSam Leffler
115439beb93cSSam Leffler
1155325151a3SRui Paulo #ifndef OPENSSL_NO_ENGINE
1156325151a3SRui Paulo
1157325151a3SRui Paulo /* Cryptoki return values */
1158325151a3SRui Paulo #define CKR_PIN_INCORRECT 0x000000a0
1159325151a3SRui Paulo #define CKR_PIN_INVALID 0x000000a1
1160325151a3SRui Paulo #define CKR_PIN_LEN_RANGE 0x000000a2
1161325151a3SRui Paulo
1162325151a3SRui Paulo /* libp11 */
1163325151a3SRui Paulo #define ERR_LIB_PKCS11 ERR_LIB_USER
1164325151a3SRui Paulo
tls_is_pin_error(unsigned int err)1165325151a3SRui Paulo static int tls_is_pin_error(unsigned int err)
1166325151a3SRui Paulo {
1167325151a3SRui Paulo return ERR_GET_LIB(err) == ERR_LIB_PKCS11 &&
1168325151a3SRui Paulo (ERR_GET_REASON(err) == CKR_PIN_INCORRECT ||
1169325151a3SRui Paulo ERR_GET_REASON(err) == CKR_PIN_INVALID ||
1170325151a3SRui Paulo ERR_GET_REASON(err) == CKR_PIN_LEN_RANGE);
1171325151a3SRui Paulo }
1172325151a3SRui Paulo
1173325151a3SRui Paulo #endif /* OPENSSL_NO_ENGINE */
1174325151a3SRui Paulo
1175325151a3SRui Paulo
1176780fb4a2SCy Schubert #ifdef ANDROID
1177780fb4a2SCy Schubert /* EVP_PKEY_from_keystore comes from system/security/keystore-engine. */
1178780fb4a2SCy Schubert EVP_PKEY * EVP_PKEY_from_keystore(const char *key_id);
1179780fb4a2SCy Schubert #endif /* ANDROID */
1180780fb4a2SCy Schubert
tls_engine_init(struct tls_connection * conn,const char * engine_id,const char * pin,const char * key_id,const char * cert_id,const char * ca_cert_id)118139beb93cSSam Leffler static int tls_engine_init(struct tls_connection *conn, const char *engine_id,
118239beb93cSSam Leffler const char *pin, const char *key_id,
118339beb93cSSam Leffler const char *cert_id, const char *ca_cert_id)
118439beb93cSSam Leffler {
1185780fb4a2SCy Schubert #if defined(ANDROID) && defined(OPENSSL_IS_BORINGSSL)
1186780fb4a2SCy Schubert #if !defined(OPENSSL_NO_ENGINE)
1187780fb4a2SCy Schubert #error "This code depends on OPENSSL_NO_ENGINE being defined by BoringSSL."
1188780fb4a2SCy Schubert #endif
1189780fb4a2SCy Schubert if (!key_id)
1190780fb4a2SCy Schubert return TLS_SET_PARAMS_ENGINE_PRV_INIT_FAILED;
1191780fb4a2SCy Schubert conn->engine = NULL;
1192780fb4a2SCy Schubert conn->private_key = EVP_PKEY_from_keystore(key_id);
1193780fb4a2SCy Schubert if (!conn->private_key) {
1194780fb4a2SCy Schubert wpa_printf(MSG_ERROR,
1195780fb4a2SCy Schubert "ENGINE: cannot load private key with id '%s' [%s]",
1196780fb4a2SCy Schubert key_id,
1197780fb4a2SCy Schubert ERR_error_string(ERR_get_error(), NULL));
1198780fb4a2SCy Schubert return TLS_SET_PARAMS_ENGINE_PRV_INIT_FAILED;
1199780fb4a2SCy Schubert }
1200780fb4a2SCy Schubert #endif /* ANDROID && OPENSSL_IS_BORINGSSL */
1201780fb4a2SCy Schubert
120239beb93cSSam Leffler #ifndef OPENSSL_NO_ENGINE
120339beb93cSSam Leffler int ret = -1;
120439beb93cSSam Leffler if (engine_id == NULL) {
120539beb93cSSam Leffler wpa_printf(MSG_ERROR, "ENGINE: Engine ID not set");
120639beb93cSSam Leffler return -1;
120739beb93cSSam Leffler }
120839beb93cSSam Leffler
120939beb93cSSam Leffler ERR_clear_error();
12105b9c547cSRui Paulo #ifdef ANDROID
12115b9c547cSRui Paulo ENGINE_load_dynamic();
12125b9c547cSRui Paulo #endif
121339beb93cSSam Leffler conn->engine = ENGINE_by_id(engine_id);
121439beb93cSSam Leffler if (!conn->engine) {
121539beb93cSSam Leffler wpa_printf(MSG_ERROR, "ENGINE: engine %s not available [%s]",
121639beb93cSSam Leffler engine_id, ERR_error_string(ERR_get_error(), NULL));
121739beb93cSSam Leffler goto err;
121839beb93cSSam Leffler }
121939beb93cSSam Leffler if (ENGINE_init(conn->engine) != 1) {
122039beb93cSSam Leffler wpa_printf(MSG_ERROR, "ENGINE: engine init failed "
122139beb93cSSam Leffler "(engine: %s) [%s]", engine_id,
122239beb93cSSam Leffler ERR_error_string(ERR_get_error(), NULL));
122339beb93cSSam Leffler goto err;
122439beb93cSSam Leffler }
122539beb93cSSam Leffler wpa_printf(MSG_DEBUG, "ENGINE: engine initialized");
122639beb93cSSam Leffler
12275b9c547cSRui Paulo #ifndef ANDROID
12285b9c547cSRui Paulo if (pin && ENGINE_ctrl_cmd_string(conn->engine, "PIN", pin, 0) == 0) {
122939beb93cSSam Leffler wpa_printf(MSG_ERROR, "ENGINE: cannot set pin [%s]",
123039beb93cSSam Leffler ERR_error_string(ERR_get_error(), NULL));
123139beb93cSSam Leffler goto err;
123239beb93cSSam Leffler }
12335b9c547cSRui Paulo #endif
12345b9c547cSRui Paulo if (key_id) {
12355b9c547cSRui Paulo /*
12365b9c547cSRui Paulo * Ensure that the ENGINE does not attempt to use the OpenSSL
12375b9c547cSRui Paulo * UI system to obtain a PIN, if we didn't provide one.
12385b9c547cSRui Paulo */
12395b9c547cSRui Paulo struct {
12405b9c547cSRui Paulo const void *password;
12415b9c547cSRui Paulo const char *prompt_info;
12425b9c547cSRui Paulo } key_cb = { "", NULL };
12435b9c547cSRui Paulo
124439beb93cSSam Leffler /* load private key first in-case PIN is required for cert */
124539beb93cSSam Leffler conn->private_key = ENGINE_load_private_key(conn->engine,
12465b9c547cSRui Paulo key_id, NULL,
12475b9c547cSRui Paulo &key_cb);
124839beb93cSSam Leffler if (!conn->private_key) {
1249325151a3SRui Paulo unsigned long err = ERR_get_error();
1250325151a3SRui Paulo
12515b9c547cSRui Paulo wpa_printf(MSG_ERROR,
12525b9c547cSRui Paulo "ENGINE: cannot load private key with id '%s' [%s]",
12535b9c547cSRui Paulo key_id,
1254325151a3SRui Paulo ERR_error_string(err, NULL));
1255325151a3SRui Paulo if (tls_is_pin_error(err))
1256325151a3SRui Paulo ret = TLS_SET_PARAMS_ENGINE_PRV_BAD_PIN;
1257325151a3SRui Paulo else
125839beb93cSSam Leffler ret = TLS_SET_PARAMS_ENGINE_PRV_INIT_FAILED;
125939beb93cSSam Leffler goto err;
126039beb93cSSam Leffler }
12615b9c547cSRui Paulo }
126239beb93cSSam Leffler
126339beb93cSSam Leffler /* handle a certificate and/or CA certificate */
126439beb93cSSam Leffler if (cert_id || ca_cert_id) {
126539beb93cSSam Leffler const char *cmd_name = "LOAD_CERT_CTRL";
126639beb93cSSam Leffler
126739beb93cSSam Leffler /* test if the engine supports a LOAD_CERT_CTRL */
126839beb93cSSam Leffler if (!ENGINE_ctrl(conn->engine, ENGINE_CTRL_GET_CMD_FROM_NAME,
126939beb93cSSam Leffler 0, (void *)cmd_name, NULL)) {
127039beb93cSSam Leffler wpa_printf(MSG_ERROR, "ENGINE: engine does not support"
127139beb93cSSam Leffler " loading certificates");
127239beb93cSSam Leffler ret = TLS_SET_PARAMS_ENGINE_PRV_INIT_FAILED;
127339beb93cSSam Leffler goto err;
127439beb93cSSam Leffler }
127539beb93cSSam Leffler }
127639beb93cSSam Leffler
127739beb93cSSam Leffler return 0;
127839beb93cSSam Leffler
127939beb93cSSam Leffler err:
128039beb93cSSam Leffler if (conn->engine) {
128139beb93cSSam Leffler ENGINE_free(conn->engine);
128239beb93cSSam Leffler conn->engine = NULL;
128339beb93cSSam Leffler }
128439beb93cSSam Leffler
128539beb93cSSam Leffler if (conn->private_key) {
128639beb93cSSam Leffler EVP_PKEY_free(conn->private_key);
128739beb93cSSam Leffler conn->private_key = NULL;
128839beb93cSSam Leffler }
128939beb93cSSam Leffler
129039beb93cSSam Leffler return ret;
129139beb93cSSam Leffler #else /* OPENSSL_NO_ENGINE */
129239beb93cSSam Leffler return 0;
129339beb93cSSam Leffler #endif /* OPENSSL_NO_ENGINE */
129439beb93cSSam Leffler }
129539beb93cSSam Leffler
129639beb93cSSam Leffler
tls_engine_deinit(struct tls_connection * conn)129739beb93cSSam Leffler static void tls_engine_deinit(struct tls_connection *conn)
129839beb93cSSam Leffler {
1299780fb4a2SCy Schubert #if defined(ANDROID) || !defined(OPENSSL_NO_ENGINE)
130039beb93cSSam Leffler wpa_printf(MSG_DEBUG, "ENGINE: engine deinit");
130139beb93cSSam Leffler if (conn->private_key) {
130239beb93cSSam Leffler EVP_PKEY_free(conn->private_key);
130339beb93cSSam Leffler conn->private_key = NULL;
130439beb93cSSam Leffler }
130539beb93cSSam Leffler if (conn->engine) {
1306780fb4a2SCy Schubert #if !defined(OPENSSL_IS_BORINGSSL)
130739beb93cSSam Leffler ENGINE_finish(conn->engine);
1308780fb4a2SCy Schubert #endif /* !OPENSSL_IS_BORINGSSL */
130939beb93cSSam Leffler conn->engine = NULL;
131039beb93cSSam Leffler }
1311780fb4a2SCy Schubert #endif /* ANDROID || !OPENSSL_NO_ENGINE */
131239beb93cSSam Leffler }
131339beb93cSSam Leffler
131439beb93cSSam Leffler
tls_get_errors(void * ssl_ctx)131539beb93cSSam Leffler int tls_get_errors(void *ssl_ctx)
131639beb93cSSam Leffler {
131739beb93cSSam Leffler int count = 0;
131839beb93cSSam Leffler unsigned long err;
131939beb93cSSam Leffler
132039beb93cSSam Leffler while ((err = ERR_get_error())) {
132139beb93cSSam Leffler wpa_printf(MSG_INFO, "TLS - SSL error: %s",
132239beb93cSSam Leffler ERR_error_string(err, NULL));
132339beb93cSSam Leffler count++;
132439beb93cSSam Leffler }
132539beb93cSSam Leffler
132639beb93cSSam Leffler return count;
132739beb93cSSam Leffler }
132839beb93cSSam Leffler
13295b9c547cSRui Paulo
openssl_content_type(int content_type)1330780fb4a2SCy Schubert static const char * openssl_content_type(int content_type)
1331780fb4a2SCy Schubert {
1332780fb4a2SCy Schubert switch (content_type) {
1333780fb4a2SCy Schubert case 20:
1334780fb4a2SCy Schubert return "change cipher spec";
1335780fb4a2SCy Schubert case 21:
1336780fb4a2SCy Schubert return "alert";
1337780fb4a2SCy Schubert case 22:
1338780fb4a2SCy Schubert return "handshake";
1339780fb4a2SCy Schubert case 23:
1340780fb4a2SCy Schubert return "application data";
1341780fb4a2SCy Schubert case 24:
1342780fb4a2SCy Schubert return "heartbeat";
1343780fb4a2SCy Schubert case 256:
1344780fb4a2SCy Schubert return "TLS header info"; /* pseudo content type */
1345206b73d0SCy Schubert case 257:
1346206b73d0SCy Schubert return "inner content type"; /* pseudo content type */
1347780fb4a2SCy Schubert default:
1348780fb4a2SCy Schubert return "?";
1349780fb4a2SCy Schubert }
1350780fb4a2SCy Schubert }
1351780fb4a2SCy Schubert
1352780fb4a2SCy Schubert
openssl_handshake_type(int content_type,const u8 * buf,size_t len)1353780fb4a2SCy Schubert static const char * openssl_handshake_type(int content_type, const u8 *buf,
1354780fb4a2SCy Schubert size_t len)
1355780fb4a2SCy Schubert {
1356206b73d0SCy Schubert if (content_type == 257 && buf && len == 1)
1357206b73d0SCy Schubert return openssl_content_type(buf[0]);
1358780fb4a2SCy Schubert if (content_type != 22 || !buf || len == 0)
1359780fb4a2SCy Schubert return "";
1360780fb4a2SCy Schubert switch (buf[0]) {
1361780fb4a2SCy Schubert case 0:
1362780fb4a2SCy Schubert return "hello request";
1363780fb4a2SCy Schubert case 1:
1364780fb4a2SCy Schubert return "client hello";
1365780fb4a2SCy Schubert case 2:
1366780fb4a2SCy Schubert return "server hello";
13674bc52338SCy Schubert case 3:
13684bc52338SCy Schubert return "hello verify request";
1369780fb4a2SCy Schubert case 4:
1370780fb4a2SCy Schubert return "new session ticket";
13714bc52338SCy Schubert case 5:
13724bc52338SCy Schubert return "end of early data";
13734bc52338SCy Schubert case 6:
13744bc52338SCy Schubert return "hello retry request";
13754bc52338SCy Schubert case 8:
13764bc52338SCy Schubert return "encrypted extensions";
1377780fb4a2SCy Schubert case 11:
1378780fb4a2SCy Schubert return "certificate";
1379780fb4a2SCy Schubert case 12:
1380780fb4a2SCy Schubert return "server key exchange";
1381780fb4a2SCy Schubert case 13:
1382780fb4a2SCy Schubert return "certificate request";
1383780fb4a2SCy Schubert case 14:
1384780fb4a2SCy Schubert return "server hello done";
1385780fb4a2SCy Schubert case 15:
1386780fb4a2SCy Schubert return "certificate verify";
1387780fb4a2SCy Schubert case 16:
1388780fb4a2SCy Schubert return "client key exchange";
1389780fb4a2SCy Schubert case 20:
1390780fb4a2SCy Schubert return "finished";
1391780fb4a2SCy Schubert case 21:
1392780fb4a2SCy Schubert return "certificate url";
1393780fb4a2SCy Schubert case 22:
1394780fb4a2SCy Schubert return "certificate status";
13954bc52338SCy Schubert case 23:
13964bc52338SCy Schubert return "supplemental data";
13974bc52338SCy Schubert case 24:
13984bc52338SCy Schubert return "key update";
13994bc52338SCy Schubert case 254:
14004bc52338SCy Schubert return "message hash";
1401780fb4a2SCy Schubert default:
1402780fb4a2SCy Schubert return "?";
1403780fb4a2SCy Schubert }
1404780fb4a2SCy Schubert }
1405780fb4a2SCy Schubert
1406780fb4a2SCy Schubert
140785732ac8SCy Schubert #ifdef CONFIG_SUITEB
140885732ac8SCy Schubert
check_server_hello(struct tls_connection * conn,const u8 * pos,const u8 * end)140985732ac8SCy Schubert static void check_server_hello(struct tls_connection *conn,
141085732ac8SCy Schubert const u8 *pos, const u8 *end)
141185732ac8SCy Schubert {
141285732ac8SCy Schubert size_t payload_len, id_len;
141385732ac8SCy Schubert
141485732ac8SCy Schubert /*
141585732ac8SCy Schubert * Parse ServerHello to get the selected cipher suite since OpenSSL does
141685732ac8SCy Schubert * not make it cleanly available during handshake and we need to know
141785732ac8SCy Schubert * whether DHE was selected.
141885732ac8SCy Schubert */
141985732ac8SCy Schubert
142085732ac8SCy Schubert if (end - pos < 3)
142185732ac8SCy Schubert return;
142285732ac8SCy Schubert payload_len = WPA_GET_BE24(pos);
142385732ac8SCy Schubert pos += 3;
142485732ac8SCy Schubert
142585732ac8SCy Schubert if ((size_t) (end - pos) < payload_len)
142685732ac8SCy Schubert return;
142785732ac8SCy Schubert end = pos + payload_len;
142885732ac8SCy Schubert
142985732ac8SCy Schubert /* Skip Version and Random */
143085732ac8SCy Schubert if (end - pos < 2 + SSL3_RANDOM_SIZE)
143185732ac8SCy Schubert return;
143285732ac8SCy Schubert pos += 2 + SSL3_RANDOM_SIZE;
143385732ac8SCy Schubert
143485732ac8SCy Schubert /* Skip Session ID */
143585732ac8SCy Schubert if (end - pos < 1)
143685732ac8SCy Schubert return;
143785732ac8SCy Schubert id_len = *pos++;
143885732ac8SCy Schubert if ((size_t) (end - pos) < id_len)
143985732ac8SCy Schubert return;
144085732ac8SCy Schubert pos += id_len;
144185732ac8SCy Schubert
144285732ac8SCy Schubert if (end - pos < 2)
144385732ac8SCy Schubert return;
144485732ac8SCy Schubert conn->cipher_suite = WPA_GET_BE16(pos);
144585732ac8SCy Schubert wpa_printf(MSG_DEBUG, "OpenSSL: Server selected cipher suite 0x%x",
144685732ac8SCy Schubert conn->cipher_suite);
144785732ac8SCy Schubert }
144885732ac8SCy Schubert
144985732ac8SCy Schubert
check_server_key_exchange(SSL * ssl,struct tls_connection * conn,const u8 * pos,const u8 * end)145085732ac8SCy Schubert static void check_server_key_exchange(SSL *ssl, struct tls_connection *conn,
145185732ac8SCy Schubert const u8 *pos, const u8 *end)
145285732ac8SCy Schubert {
145385732ac8SCy Schubert size_t payload_len;
145485732ac8SCy Schubert u16 dh_len;
145585732ac8SCy Schubert BIGNUM *p;
145685732ac8SCy Schubert int bits;
145785732ac8SCy Schubert
145885732ac8SCy Schubert if (!(conn->flags & TLS_CONN_SUITEB))
145985732ac8SCy Schubert return;
146085732ac8SCy Schubert
146185732ac8SCy Schubert /* DHE is enabled only with DHE-RSA-AES256-GCM-SHA384 */
146285732ac8SCy Schubert if (conn->cipher_suite != 0x9f)
146385732ac8SCy Schubert return;
146485732ac8SCy Schubert
146585732ac8SCy Schubert if (end - pos < 3)
146685732ac8SCy Schubert return;
146785732ac8SCy Schubert payload_len = WPA_GET_BE24(pos);
146885732ac8SCy Schubert pos += 3;
146985732ac8SCy Schubert
147085732ac8SCy Schubert if ((size_t) (end - pos) < payload_len)
147185732ac8SCy Schubert return;
147285732ac8SCy Schubert end = pos + payload_len;
147385732ac8SCy Schubert
147485732ac8SCy Schubert if (end - pos < 2)
147585732ac8SCy Schubert return;
147685732ac8SCy Schubert dh_len = WPA_GET_BE16(pos);
147785732ac8SCy Schubert pos += 2;
147885732ac8SCy Schubert
147985732ac8SCy Schubert if ((size_t) (end - pos) < dh_len)
148085732ac8SCy Schubert return;
148185732ac8SCy Schubert p = BN_bin2bn(pos, dh_len, NULL);
148285732ac8SCy Schubert if (!p)
148385732ac8SCy Schubert return;
148485732ac8SCy Schubert
148585732ac8SCy Schubert bits = BN_num_bits(p);
148685732ac8SCy Schubert BN_free(p);
148785732ac8SCy Schubert
148885732ac8SCy Schubert conn->server_dh_prime_len = bits;
148985732ac8SCy Schubert wpa_printf(MSG_DEBUG, "OpenSSL: Server DH prime length: %d bits",
149085732ac8SCy Schubert conn->server_dh_prime_len);
149185732ac8SCy Schubert }
149285732ac8SCy Schubert
149385732ac8SCy Schubert #endif /* CONFIG_SUITEB */
149485732ac8SCy Schubert
149585732ac8SCy Schubert
tls_msg_cb(int write_p,int version,int content_type,const void * buf,size_t len,SSL * ssl,void * arg)14965b9c547cSRui Paulo static void tls_msg_cb(int write_p, int version, int content_type,
14975b9c547cSRui Paulo const void *buf, size_t len, SSL *ssl, void *arg)
14985b9c547cSRui Paulo {
14995b9c547cSRui Paulo struct tls_connection *conn = arg;
15005b9c547cSRui Paulo const u8 *pos = buf;
15015b9c547cSRui Paulo
1502780fb4a2SCy Schubert if (write_p == 2) {
1503780fb4a2SCy Schubert wpa_printf(MSG_DEBUG,
1504780fb4a2SCy Schubert "OpenSSL: session ver=0x%x content_type=%d",
1505780fb4a2SCy Schubert version, content_type);
1506780fb4a2SCy Schubert wpa_hexdump_key(MSG_MSGDUMP, "OpenSSL: Data", buf, len);
1507780fb4a2SCy Schubert return;
1508780fb4a2SCy Schubert }
1509780fb4a2SCy Schubert
1510780fb4a2SCy Schubert wpa_printf(MSG_DEBUG, "OpenSSL: %s ver=0x%x content_type=%d (%s/%s)",
1511780fb4a2SCy Schubert write_p ? "TX" : "RX", version, content_type,
1512780fb4a2SCy Schubert openssl_content_type(content_type),
1513780fb4a2SCy Schubert openssl_handshake_type(content_type, buf, len));
15145b9c547cSRui Paulo wpa_hexdump_key(MSG_MSGDUMP, "OpenSSL: Message", buf, len);
15155b9c547cSRui Paulo if (content_type == 24 && len >= 3 && pos[0] == 1) {
15165b9c547cSRui Paulo size_t payload_len = WPA_GET_BE16(pos + 1);
15175b9c547cSRui Paulo if (payload_len + 3 > len) {
15185b9c547cSRui Paulo wpa_printf(MSG_ERROR, "OpenSSL: Heartbeat attack detected");
15195b9c547cSRui Paulo conn->invalid_hb_used = 1;
15205b9c547cSRui Paulo }
15215b9c547cSRui Paulo }
152285732ac8SCy Schubert
152385732ac8SCy Schubert #ifdef CONFIG_SUITEB
152485732ac8SCy Schubert /*
152585732ac8SCy Schubert * Need to parse these handshake messages to be able to check DH prime
152685732ac8SCy Schubert * length since OpenSSL does not expose the new cipher suite and DH
152785732ac8SCy Schubert * parameters during handshake (e.g., for cert_cb() callback).
152885732ac8SCy Schubert */
152985732ac8SCy Schubert if (content_type == 22 && pos && len > 0 && pos[0] == 2)
153085732ac8SCy Schubert check_server_hello(conn, pos + 1, pos + len);
153185732ac8SCy Schubert if (content_type == 22 && pos && len > 0 && pos[0] == 12)
153285732ac8SCy Schubert check_server_key_exchange(ssl, conn, pos + 1, pos + len);
153385732ac8SCy Schubert #endif /* CONFIG_SUITEB */
15345b9c547cSRui Paulo }
15355b9c547cSRui Paulo
15365b9c547cSRui Paulo
tls_connection_init(void * ssl_ctx)153739beb93cSSam Leffler struct tls_connection * tls_connection_init(void *ssl_ctx)
153839beb93cSSam Leffler {
1539325151a3SRui Paulo struct tls_data *data = ssl_ctx;
1540325151a3SRui Paulo SSL_CTX *ssl = data->ssl;
154139beb93cSSam Leffler struct tls_connection *conn;
154239beb93cSSam Leffler long options;
15434bc52338SCy Schubert X509_STORE *new_cert_store;
15444bc52338SCy Schubert struct os_reltime now;
15455b9c547cSRui Paulo struct tls_context *context = SSL_CTX_get_app_data(ssl);
154639beb93cSSam Leffler
15474bc52338SCy Schubert /* Replace X509 store if it is time to update CRL. */
15484bc52338SCy Schubert if (data->crl_reload_interval > 0 && os_get_reltime(&now) == 0 &&
15494bc52338SCy Schubert os_reltime_expired(&now, &data->crl_last_reload,
15504bc52338SCy Schubert data->crl_reload_interval)) {
15514bc52338SCy Schubert wpa_printf(MSG_INFO,
15524bc52338SCy Schubert "OpenSSL: Flushing X509 store with ca_cert file");
15534bc52338SCy Schubert new_cert_store = tls_crl_cert_reload(data->ca_cert,
15544bc52338SCy Schubert data->check_crl);
15554bc52338SCy Schubert if (!new_cert_store) {
15564bc52338SCy Schubert wpa_printf(MSG_ERROR,
15574bc52338SCy Schubert "OpenSSL: Error replacing X509 store with ca_cert file");
15584bc52338SCy Schubert } else {
15594bc52338SCy Schubert /* Replace old store */
15604bc52338SCy Schubert SSL_CTX_set_cert_store(ssl, new_cert_store);
15614bc52338SCy Schubert data->crl_last_reload = now;
15624bc52338SCy Schubert }
15634bc52338SCy Schubert }
15644bc52338SCy Schubert
156539beb93cSSam Leffler conn = os_zalloc(sizeof(*conn));
156639beb93cSSam Leffler if (conn == NULL)
156739beb93cSSam Leffler return NULL;
15684bc52338SCy Schubert conn->data = data;
1569325151a3SRui Paulo conn->ssl_ctx = ssl;
157039beb93cSSam Leffler conn->ssl = SSL_new(ssl);
157139beb93cSSam Leffler if (conn->ssl == NULL) {
157239beb93cSSam Leffler tls_show_errors(MSG_INFO, __func__,
157339beb93cSSam Leffler "Failed to initialize new SSL connection");
157439beb93cSSam Leffler os_free(conn);
157539beb93cSSam Leffler return NULL;
157639beb93cSSam Leffler }
157739beb93cSSam Leffler
15785b9c547cSRui Paulo conn->context = context;
157939beb93cSSam Leffler SSL_set_app_data(conn->ssl, conn);
15805b9c547cSRui Paulo SSL_set_msg_callback(conn->ssl, tls_msg_cb);
15815b9c547cSRui Paulo SSL_set_msg_callback_arg(conn->ssl, conn);
158239beb93cSSam Leffler options = SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3 |
158339beb93cSSam Leffler SSL_OP_SINGLE_DH_USE;
158439beb93cSSam Leffler #ifdef SSL_OP_NO_COMPRESSION
158539beb93cSSam Leffler options |= SSL_OP_NO_COMPRESSION;
158639beb93cSSam Leffler #endif /* SSL_OP_NO_COMPRESSION */
158739beb93cSSam Leffler SSL_set_options(conn->ssl, options);
1588206b73d0SCy Schubert #ifdef SSL_OP_ENABLE_MIDDLEBOX_COMPAT
1589206b73d0SCy Schubert /* Hopefully there is no need for middlebox compatibility mechanisms
1590206b73d0SCy Schubert * when going through EAP authentication. */
1591206b73d0SCy Schubert SSL_clear_options(conn->ssl, SSL_OP_ENABLE_MIDDLEBOX_COMPAT);
1592206b73d0SCy Schubert #endif
159339beb93cSSam Leffler
159439beb93cSSam Leffler conn->ssl_in = BIO_new(BIO_s_mem());
159539beb93cSSam Leffler if (!conn->ssl_in) {
159639beb93cSSam Leffler tls_show_errors(MSG_INFO, __func__,
159739beb93cSSam Leffler "Failed to create a new BIO for ssl_in");
159839beb93cSSam Leffler SSL_free(conn->ssl);
159939beb93cSSam Leffler os_free(conn);
160039beb93cSSam Leffler return NULL;
160139beb93cSSam Leffler }
160239beb93cSSam Leffler
160339beb93cSSam Leffler conn->ssl_out = BIO_new(BIO_s_mem());
160439beb93cSSam Leffler if (!conn->ssl_out) {
160539beb93cSSam Leffler tls_show_errors(MSG_INFO, __func__,
160639beb93cSSam Leffler "Failed to create a new BIO for ssl_out");
160739beb93cSSam Leffler SSL_free(conn->ssl);
160839beb93cSSam Leffler BIO_free(conn->ssl_in);
160939beb93cSSam Leffler os_free(conn);
161039beb93cSSam Leffler return NULL;
161139beb93cSSam Leffler }
161239beb93cSSam Leffler
161339beb93cSSam Leffler SSL_set_bio(conn->ssl, conn->ssl_in, conn->ssl_out);
161439beb93cSSam Leffler
161539beb93cSSam Leffler return conn;
161639beb93cSSam Leffler }
161739beb93cSSam Leffler
161839beb93cSSam Leffler
tls_connection_deinit(void * ssl_ctx,struct tls_connection * conn)161939beb93cSSam Leffler void tls_connection_deinit(void *ssl_ctx, struct tls_connection *conn)
162039beb93cSSam Leffler {
162139beb93cSSam Leffler if (conn == NULL)
162239beb93cSSam Leffler return;
1623325151a3SRui Paulo if (conn->success_data) {
1624325151a3SRui Paulo /*
1625325151a3SRui Paulo * Make sure ssl_clear_bad_session() does not remove this
1626325151a3SRui Paulo * session.
1627325151a3SRui Paulo */
1628325151a3SRui Paulo SSL_set_quiet_shutdown(conn->ssl, 1);
1629325151a3SRui Paulo SSL_shutdown(conn->ssl);
1630325151a3SRui Paulo }
163139beb93cSSam Leffler SSL_free(conn->ssl);
163239beb93cSSam Leffler tls_engine_deinit(conn);
163339beb93cSSam Leffler os_free(conn->subject_match);
163439beb93cSSam Leffler os_free(conn->altsubject_match);
16355b9c547cSRui Paulo os_free(conn->suffix_match);
16365b9c547cSRui Paulo os_free(conn->domain_match);
16374bc52338SCy Schubert os_free(conn->check_cert_subject);
163839beb93cSSam Leffler os_free(conn->session_ticket);
1639c1d255d3SCy Schubert os_free(conn->peer_subject);
164039beb93cSSam Leffler os_free(conn);
164139beb93cSSam Leffler }
164239beb93cSSam Leffler
164339beb93cSSam Leffler
tls_connection_established(void * ssl_ctx,struct tls_connection * conn)164439beb93cSSam Leffler int tls_connection_established(void *ssl_ctx, struct tls_connection *conn)
164539beb93cSSam Leffler {
164639beb93cSSam Leffler return conn ? SSL_is_init_finished(conn->ssl) : 0;
164739beb93cSSam Leffler }
164839beb93cSSam Leffler
164939beb93cSSam Leffler
tls_connection_peer_serial_num(void * tls_ctx,struct tls_connection * conn)165085732ac8SCy Schubert char * tls_connection_peer_serial_num(void *tls_ctx,
165185732ac8SCy Schubert struct tls_connection *conn)
165285732ac8SCy Schubert {
165385732ac8SCy Schubert ASN1_INTEGER *ser;
165485732ac8SCy Schubert char *serial_num;
165585732ac8SCy Schubert size_t len;
165685732ac8SCy Schubert
165785732ac8SCy Schubert if (!conn->peer_cert)
165885732ac8SCy Schubert return NULL;
165985732ac8SCy Schubert
166085732ac8SCy Schubert ser = X509_get_serialNumber(conn->peer_cert);
166185732ac8SCy Schubert if (!ser)
166285732ac8SCy Schubert return NULL;
166385732ac8SCy Schubert
166485732ac8SCy Schubert len = ASN1_STRING_length(ser) * 2 + 1;
166585732ac8SCy Schubert serial_num = os_malloc(len);
166685732ac8SCy Schubert if (!serial_num)
166785732ac8SCy Schubert return NULL;
166885732ac8SCy Schubert wpa_snprintf_hex_uppercase(serial_num, len,
166985732ac8SCy Schubert ASN1_STRING_get0_data(ser),
167085732ac8SCy Schubert ASN1_STRING_length(ser));
167185732ac8SCy Schubert return serial_num;
167285732ac8SCy Schubert }
167385732ac8SCy Schubert
167485732ac8SCy Schubert
tls_connection_shutdown(void * ssl_ctx,struct tls_connection * conn)167539beb93cSSam Leffler int tls_connection_shutdown(void *ssl_ctx, struct tls_connection *conn)
167639beb93cSSam Leffler {
167739beb93cSSam Leffler if (conn == NULL)
167839beb93cSSam Leffler return -1;
167939beb93cSSam Leffler
168039beb93cSSam Leffler /* Shutdown previous TLS connection without notifying the peer
168139beb93cSSam Leffler * because the connection was already terminated in practice
168239beb93cSSam Leffler * and "close notify" shutdown alert would confuse AS. */
168339beb93cSSam Leffler SSL_set_quiet_shutdown(conn->ssl, 1);
168439beb93cSSam Leffler SSL_shutdown(conn->ssl);
1685325151a3SRui Paulo return SSL_clear(conn->ssl) == 1 ? 0 : -1;
168639beb93cSSam Leffler }
168739beb93cSSam Leffler
168839beb93cSSam Leffler
tls_match_altsubject_component(X509 * cert,int type,const char * value,size_t len)168939beb93cSSam Leffler static int tls_match_altsubject_component(X509 *cert, int type,
169039beb93cSSam Leffler const char *value, size_t len)
169139beb93cSSam Leffler {
169239beb93cSSam Leffler GENERAL_NAME *gen;
169339beb93cSSam Leffler void *ext;
16945b9c547cSRui Paulo int found = 0;
16955b9c547cSRui Paulo stack_index_t i;
169639beb93cSSam Leffler
169739beb93cSSam Leffler ext = X509_get_ext_d2i(cert, NID_subject_alt_name, NULL, NULL);
169839beb93cSSam Leffler
169939beb93cSSam Leffler for (i = 0; ext && i < sk_GENERAL_NAME_num(ext); i++) {
170039beb93cSSam Leffler gen = sk_GENERAL_NAME_value(ext, i);
170139beb93cSSam Leffler if (gen->type != type)
170239beb93cSSam Leffler continue;
170339beb93cSSam Leffler if (os_strlen((char *) gen->d.ia5->data) == len &&
170439beb93cSSam Leffler os_memcmp(value, gen->d.ia5->data, len) == 0)
170539beb93cSSam Leffler found++;
170639beb93cSSam Leffler }
170739beb93cSSam Leffler
1708780fb4a2SCy Schubert sk_GENERAL_NAME_pop_free(ext, GENERAL_NAME_free);
1709780fb4a2SCy Schubert
171039beb93cSSam Leffler return found;
171139beb93cSSam Leffler }
171239beb93cSSam Leffler
171339beb93cSSam Leffler
tls_match_altsubject(X509 * cert,const char * match)171439beb93cSSam Leffler static int tls_match_altsubject(X509 *cert, const char *match)
171539beb93cSSam Leffler {
171639beb93cSSam Leffler int type;
171739beb93cSSam Leffler const char *pos, *end;
171839beb93cSSam Leffler size_t len;
171939beb93cSSam Leffler
172039beb93cSSam Leffler pos = match;
172139beb93cSSam Leffler do {
172239beb93cSSam Leffler if (os_strncmp(pos, "EMAIL:", 6) == 0) {
172339beb93cSSam Leffler type = GEN_EMAIL;
172439beb93cSSam Leffler pos += 6;
172539beb93cSSam Leffler } else if (os_strncmp(pos, "DNS:", 4) == 0) {
172639beb93cSSam Leffler type = GEN_DNS;
172739beb93cSSam Leffler pos += 4;
172839beb93cSSam Leffler } else if (os_strncmp(pos, "URI:", 4) == 0) {
172939beb93cSSam Leffler type = GEN_URI;
173039beb93cSSam Leffler pos += 4;
173139beb93cSSam Leffler } else {
173239beb93cSSam Leffler wpa_printf(MSG_INFO, "TLS: Invalid altSubjectName "
173339beb93cSSam Leffler "match '%s'", pos);
173439beb93cSSam Leffler return 0;
173539beb93cSSam Leffler }
173639beb93cSSam Leffler end = os_strchr(pos, ';');
173739beb93cSSam Leffler while (end) {
173839beb93cSSam Leffler if (os_strncmp(end + 1, "EMAIL:", 6) == 0 ||
173939beb93cSSam Leffler os_strncmp(end + 1, "DNS:", 4) == 0 ||
174039beb93cSSam Leffler os_strncmp(end + 1, "URI:", 4) == 0)
174139beb93cSSam Leffler break;
174239beb93cSSam Leffler end = os_strchr(end + 1, ';');
174339beb93cSSam Leffler }
174439beb93cSSam Leffler if (end)
174539beb93cSSam Leffler len = end - pos;
174639beb93cSSam Leffler else
174739beb93cSSam Leffler len = os_strlen(pos);
174839beb93cSSam Leffler if (tls_match_altsubject_component(cert, type, pos, len) > 0)
174939beb93cSSam Leffler return 1;
175039beb93cSSam Leffler pos = end + 1;
175139beb93cSSam Leffler } while (end);
175239beb93cSSam Leffler
175339beb93cSSam Leffler return 0;
175439beb93cSSam Leffler }
175539beb93cSSam Leffler
175639beb93cSSam Leffler
17575b9c547cSRui Paulo #ifndef CONFIG_NATIVE_WINDOWS
domain_suffix_match(const u8 * val,size_t len,const char * match,size_t match_len,int full)17585b9c547cSRui Paulo static int domain_suffix_match(const u8 *val, size_t len, const char *match,
17594bc52338SCy Schubert size_t match_len, int full)
17605b9c547cSRui Paulo {
17614bc52338SCy Schubert size_t i;
17625b9c547cSRui Paulo
17635b9c547cSRui Paulo /* Check for embedded nuls that could mess up suffix matching */
17645b9c547cSRui Paulo for (i = 0; i < len; i++) {
17655b9c547cSRui Paulo if (val[i] == '\0') {
17665b9c547cSRui Paulo wpa_printf(MSG_DEBUG, "TLS: Embedded null in a string - reject");
17675b9c547cSRui Paulo return 0;
17685b9c547cSRui Paulo }
17695b9c547cSRui Paulo }
17705b9c547cSRui Paulo
17715b9c547cSRui Paulo if (match_len > len || (full && match_len != len))
17725b9c547cSRui Paulo return 0;
17735b9c547cSRui Paulo
17745b9c547cSRui Paulo if (os_strncasecmp((const char *) val + len - match_len, match,
17755b9c547cSRui Paulo match_len) != 0)
17765b9c547cSRui Paulo return 0; /* no match */
17775b9c547cSRui Paulo
17785b9c547cSRui Paulo if (match_len == len)
17795b9c547cSRui Paulo return 1; /* exact match */
17805b9c547cSRui Paulo
17815b9c547cSRui Paulo if (val[len - match_len - 1] == '.')
17825b9c547cSRui Paulo return 1; /* full label match completes suffix match */
17835b9c547cSRui Paulo
17845b9c547cSRui Paulo wpa_printf(MSG_DEBUG, "TLS: Reject due to incomplete label match");
17855b9c547cSRui Paulo return 0;
17865b9c547cSRui Paulo }
17875b9c547cSRui Paulo #endif /* CONFIG_NATIVE_WINDOWS */
17885b9c547cSRui Paulo
17895b9c547cSRui Paulo
17904bc52338SCy Schubert struct tls_dn_field_order_cnt {
17914bc52338SCy Schubert u8 cn;
17924bc52338SCy Schubert u8 c;
17934bc52338SCy Schubert u8 l;
17944bc52338SCy Schubert u8 st;
17954bc52338SCy Schubert u8 o;
17964bc52338SCy Schubert u8 ou;
17974bc52338SCy Schubert u8 email;
17984bc52338SCy Schubert };
17994bc52338SCy Schubert
18004bc52338SCy Schubert
get_dn_field_index(const struct tls_dn_field_order_cnt * dn_cnt,int nid)18014bc52338SCy Schubert static int get_dn_field_index(const struct tls_dn_field_order_cnt *dn_cnt,
18024bc52338SCy Schubert int nid)
18035b9c547cSRui Paulo {
18044bc52338SCy Schubert switch (nid) {
18054bc52338SCy Schubert case NID_commonName:
18064bc52338SCy Schubert return dn_cnt->cn;
18074bc52338SCy Schubert case NID_countryName:
18084bc52338SCy Schubert return dn_cnt->c;
18094bc52338SCy Schubert case NID_localityName:
18104bc52338SCy Schubert return dn_cnt->l;
18114bc52338SCy Schubert case NID_stateOrProvinceName:
18124bc52338SCy Schubert return dn_cnt->st;
18134bc52338SCy Schubert case NID_organizationName:
18144bc52338SCy Schubert return dn_cnt->o;
18154bc52338SCy Schubert case NID_organizationalUnitName:
18164bc52338SCy Schubert return dn_cnt->ou;
18174bc52338SCy Schubert case NID_pkcs9_emailAddress:
18184bc52338SCy Schubert return dn_cnt->email;
18194bc52338SCy Schubert default:
18204bc52338SCy Schubert wpa_printf(MSG_ERROR,
18214bc52338SCy Schubert "TLS: Unknown NID '%d' in check_cert_subject",
18224bc52338SCy Schubert nid);
18235b9c547cSRui Paulo return -1;
18244bc52338SCy Schubert }
18254bc52338SCy Schubert }
18264bc52338SCy Schubert
18274bc52338SCy Schubert
18284bc52338SCy Schubert /**
18294bc52338SCy Schubert * match_dn_field - Match configuration DN field against Certificate DN field
18304bc52338SCy Schubert * @cert: Certificate
18314bc52338SCy Schubert * @nid: NID of DN field
18324bc52338SCy Schubert * @field: Field name
18334bc52338SCy Schubert * @value DN field value which is passed from configuration
18344bc52338SCy Schubert * e.g., if configuration have C=US and this argument will point to US.
18354bc52338SCy Schubert * @dn_cnt: DN matching context
18364bc52338SCy Schubert * Returns: 1 on success and 0 on failure
18374bc52338SCy Schubert */
match_dn_field(const X509 * cert,int nid,const char * field,const char * value,const struct tls_dn_field_order_cnt * dn_cnt)18384bc52338SCy Schubert static int match_dn_field(const X509 *cert, int nid, const char *field,
18394bc52338SCy Schubert const char *value,
18404bc52338SCy Schubert const struct tls_dn_field_order_cnt *dn_cnt)
18414bc52338SCy Schubert {
18424bc52338SCy Schubert int i, ret = 0, len, config_dn_field_index, match_index = 0;
18434bc52338SCy Schubert X509_NAME *name;
18444bc52338SCy Schubert
18454bc52338SCy Schubert len = os_strlen(value);
18464bc52338SCy Schubert name = X509_get_subject_name((X509 *) cert);
18474bc52338SCy Schubert
18484bc52338SCy Schubert /* Assign incremented cnt for every field of DN to check DN field in
18494bc52338SCy Schubert * right order */
18504bc52338SCy Schubert config_dn_field_index = get_dn_field_index(dn_cnt, nid);
18514bc52338SCy Schubert if (config_dn_field_index < 0)
18524bc52338SCy Schubert return 0;
18534bc52338SCy Schubert
18544bc52338SCy Schubert /* Fetch value based on NID */
18554bc52338SCy Schubert for (i = -1; (i = X509_NAME_get_index_by_NID(name, nid, i)) > -1;) {
18564bc52338SCy Schubert X509_NAME_ENTRY *e;
18574bc52338SCy Schubert ASN1_STRING *cn;
18584bc52338SCy Schubert
18594bc52338SCy Schubert e = X509_NAME_get_entry(name, i);
18604bc52338SCy Schubert if (!e)
18614bc52338SCy Schubert continue;
18624bc52338SCy Schubert
18634bc52338SCy Schubert cn = X509_NAME_ENTRY_get_data(e);
18644bc52338SCy Schubert if (!cn)
18654bc52338SCy Schubert continue;
18664bc52338SCy Schubert
18674bc52338SCy Schubert match_index++;
18684bc52338SCy Schubert
18694bc52338SCy Schubert /* check for more than one DN field with same name */
18704bc52338SCy Schubert if (match_index != config_dn_field_index)
18714bc52338SCy Schubert continue;
18724bc52338SCy Schubert
18734bc52338SCy Schubert /* Check wildcard at the right end side */
18744bc52338SCy Schubert /* E.g., if OU=develop* mentioned in configuration, allow 'OU'
18754bc52338SCy Schubert * of the subject in the client certificate to start with
18764bc52338SCy Schubert * 'develop' */
18774bc52338SCy Schubert if (len > 0 && value[len - 1] == '*') {
18784bc52338SCy Schubert /* Compare actual certificate DN field value with
18794bc52338SCy Schubert * configuration DN field value up to the specified
18804bc52338SCy Schubert * length. */
18814bc52338SCy Schubert ret = ASN1_STRING_length(cn) >= len - 1 &&
18824bc52338SCy Schubert os_memcmp(ASN1_STRING_get0_data(cn), value,
18834bc52338SCy Schubert len - 1) == 0;
18844bc52338SCy Schubert } else {
18854bc52338SCy Schubert /* Compare actual certificate DN field value with
18864bc52338SCy Schubert * configuration DN field value */
18874bc52338SCy Schubert ret = ASN1_STRING_length(cn) == len &&
18884bc52338SCy Schubert os_memcmp(ASN1_STRING_get0_data(cn), value,
18894bc52338SCy Schubert len) == 0;
18904bc52338SCy Schubert }
18914bc52338SCy Schubert if (!ret) {
18924bc52338SCy Schubert wpa_printf(MSG_ERROR,
18934bc52338SCy Schubert "OpenSSL: Failed to match %s '%s' with certificate DN field value '%s'",
18944bc52338SCy Schubert field, value, ASN1_STRING_get0_data(cn));
18954bc52338SCy Schubert }
18964bc52338SCy Schubert break;
18974bc52338SCy Schubert }
18984bc52338SCy Schubert
18994bc52338SCy Schubert return ret;
19004bc52338SCy Schubert }
19014bc52338SCy Schubert
19024bc52338SCy Schubert
19034bc52338SCy Schubert /**
19044bc52338SCy Schubert * get_value_from_field - Get value from DN field
19054bc52338SCy Schubert * @cert: Certificate
19064bc52338SCy Schubert * @field_str: DN field string which is passed from configuration file (e.g.,
19074bc52338SCy Schubert * C=US)
19084bc52338SCy Schubert * @dn_cnt: DN matching context
19094bc52338SCy Schubert * Returns: 1 on success and 0 on failure
19104bc52338SCy Schubert */
get_value_from_field(const X509 * cert,char * field_str,struct tls_dn_field_order_cnt * dn_cnt)19114bc52338SCy Schubert static int get_value_from_field(const X509 *cert, char *field_str,
19124bc52338SCy Schubert struct tls_dn_field_order_cnt *dn_cnt)
19134bc52338SCy Schubert {
19144bc52338SCy Schubert int nid;
19154bc52338SCy Schubert char *context = NULL, *name, *value;
19164bc52338SCy Schubert
19174bc52338SCy Schubert if (os_strcmp(field_str, "*") == 0)
19184bc52338SCy Schubert return 1; /* wildcard matches everything */
19194bc52338SCy Schubert
19204bc52338SCy Schubert name = str_token(field_str, "=", &context);
19214bc52338SCy Schubert if (!name)
19224bc52338SCy Schubert return 0;
19234bc52338SCy Schubert
19244bc52338SCy Schubert /* Compare all configured DN fields and assign nid based on that to
19254bc52338SCy Schubert * fetch correct value from certificate subject */
19264bc52338SCy Schubert if (os_strcmp(name, "CN") == 0) {
19274bc52338SCy Schubert nid = NID_commonName;
19284bc52338SCy Schubert dn_cnt->cn++;
19294bc52338SCy Schubert } else if(os_strcmp(name, "C") == 0) {
19304bc52338SCy Schubert nid = NID_countryName;
19314bc52338SCy Schubert dn_cnt->c++;
19324bc52338SCy Schubert } else if (os_strcmp(name, "L") == 0) {
19334bc52338SCy Schubert nid = NID_localityName;
19344bc52338SCy Schubert dn_cnt->l++;
19354bc52338SCy Schubert } else if (os_strcmp(name, "ST") == 0) {
19364bc52338SCy Schubert nid = NID_stateOrProvinceName;
19374bc52338SCy Schubert dn_cnt->st++;
19384bc52338SCy Schubert } else if (os_strcmp(name, "O") == 0) {
19394bc52338SCy Schubert nid = NID_organizationName;
19404bc52338SCy Schubert dn_cnt->o++;
19414bc52338SCy Schubert } else if (os_strcmp(name, "OU") == 0) {
19424bc52338SCy Schubert nid = NID_organizationalUnitName;
19434bc52338SCy Schubert dn_cnt->ou++;
19444bc52338SCy Schubert } else if (os_strcmp(name, "emailAddress") == 0) {
19454bc52338SCy Schubert nid = NID_pkcs9_emailAddress;
19464bc52338SCy Schubert dn_cnt->email++;
19474bc52338SCy Schubert } else {
19484bc52338SCy Schubert wpa_printf(MSG_ERROR,
19494bc52338SCy Schubert "TLS: Unknown field '%s' in check_cert_subject", name);
19504bc52338SCy Schubert return 0;
19514bc52338SCy Schubert }
19524bc52338SCy Schubert
19534bc52338SCy Schubert value = str_token(field_str, "=", &context);
19544bc52338SCy Schubert if (!value) {
19554bc52338SCy Schubert wpa_printf(MSG_ERROR,
19564bc52338SCy Schubert "TLS: Distinguished Name field '%s' value is not defined in check_cert_subject",
19574bc52338SCy Schubert name);
19584bc52338SCy Schubert return 0;
19594bc52338SCy Schubert }
19604bc52338SCy Schubert
19614bc52338SCy Schubert return match_dn_field(cert, nid, name, value, dn_cnt);
19624bc52338SCy Schubert }
19634bc52338SCy Schubert
19644bc52338SCy Schubert
19654bc52338SCy Schubert /**
19664bc52338SCy Schubert * tls_match_dn_field - Match subject DN field with check_cert_subject
19674bc52338SCy Schubert * @cert: Certificate
19684bc52338SCy Schubert * @match: check_cert_subject string
19694bc52338SCy Schubert * Returns: Return 1 on success and 0 on failure
19704bc52338SCy Schubert */
tls_match_dn_field(X509 * cert,const char * match)19714bc52338SCy Schubert static int tls_match_dn_field(X509 *cert, const char *match)
19724bc52338SCy Schubert {
19734bc52338SCy Schubert const char *token, *last = NULL;
19744bc52338SCy Schubert char field[256];
19754bc52338SCy Schubert struct tls_dn_field_order_cnt dn_cnt;
19764bc52338SCy Schubert
19774bc52338SCy Schubert os_memset(&dn_cnt, 0, sizeof(dn_cnt));
19784bc52338SCy Schubert
19794bc52338SCy Schubert /* Maximum length of each DN field is 255 characters */
19804bc52338SCy Schubert
19814bc52338SCy Schubert /* Process each '/' delimited field */
19824bc52338SCy Schubert while ((token = cstr_token(match, "/", &last))) {
19834bc52338SCy Schubert if (last - token >= (int) sizeof(field)) {
19844bc52338SCy Schubert wpa_printf(MSG_ERROR,
19854bc52338SCy Schubert "OpenSSL: Too long DN matching field value in '%s'",
19864bc52338SCy Schubert match);
19874bc52338SCy Schubert return 0;
19884bc52338SCy Schubert }
19894bc52338SCy Schubert os_memcpy(field, token, last - token);
19904bc52338SCy Schubert field[last - token] = '\0';
19914bc52338SCy Schubert
19924bc52338SCy Schubert if (!get_value_from_field(cert, field, &dn_cnt)) {
19934bc52338SCy Schubert wpa_printf(MSG_DEBUG, "OpenSSL: No match for DN '%s'",
19944bc52338SCy Schubert field);
19954bc52338SCy Schubert return 0;
19964bc52338SCy Schubert }
19974bc52338SCy Schubert }
19984bc52338SCy Schubert
19994bc52338SCy Schubert return 1;
20004bc52338SCy Schubert }
20014bc52338SCy Schubert
20024bc52338SCy Schubert
20034bc52338SCy Schubert #ifndef CONFIG_NATIVE_WINDOWS
tls_match_suffix_helper(X509 * cert,const char * match,size_t match_len,int full)20044bc52338SCy Schubert static int tls_match_suffix_helper(X509 *cert, const char *match,
20054bc52338SCy Schubert size_t match_len, int full)
20064bc52338SCy Schubert {
20075b9c547cSRui Paulo GENERAL_NAME *gen;
20085b9c547cSRui Paulo void *ext;
20095b9c547cSRui Paulo int i;
20105b9c547cSRui Paulo stack_index_t j;
20115b9c547cSRui Paulo int dns_name = 0;
20125b9c547cSRui Paulo X509_NAME *name;
20135b9c547cSRui Paulo
20145b9c547cSRui Paulo wpa_printf(MSG_DEBUG, "TLS: Match domain against %s%s",
20155b9c547cSRui Paulo full ? "": "suffix ", match);
20165b9c547cSRui Paulo
20175b9c547cSRui Paulo ext = X509_get_ext_d2i(cert, NID_subject_alt_name, NULL, NULL);
20185b9c547cSRui Paulo
20195b9c547cSRui Paulo for (j = 0; ext && j < sk_GENERAL_NAME_num(ext); j++) {
20205b9c547cSRui Paulo gen = sk_GENERAL_NAME_value(ext, j);
20215b9c547cSRui Paulo if (gen->type != GEN_DNS)
20225b9c547cSRui Paulo continue;
20235b9c547cSRui Paulo dns_name++;
20245b9c547cSRui Paulo wpa_hexdump_ascii(MSG_DEBUG, "TLS: Certificate dNSName",
20255b9c547cSRui Paulo gen->d.dNSName->data,
20265b9c547cSRui Paulo gen->d.dNSName->length);
20275b9c547cSRui Paulo if (domain_suffix_match(gen->d.dNSName->data,
20284bc52338SCy Schubert gen->d.dNSName->length,
20294bc52338SCy Schubert match, match_len, full) == 1) {
20305b9c547cSRui Paulo wpa_printf(MSG_DEBUG, "TLS: %s in dNSName found",
20315b9c547cSRui Paulo full ? "Match" : "Suffix match");
2032780fb4a2SCy Schubert sk_GENERAL_NAME_pop_free(ext, GENERAL_NAME_free);
20335b9c547cSRui Paulo return 1;
20345b9c547cSRui Paulo }
20355b9c547cSRui Paulo }
2036780fb4a2SCy Schubert sk_GENERAL_NAME_pop_free(ext, GENERAL_NAME_free);
20375b9c547cSRui Paulo
20385b9c547cSRui Paulo if (dns_name) {
20395b9c547cSRui Paulo wpa_printf(MSG_DEBUG, "TLS: None of the dNSName(s) matched");
20405b9c547cSRui Paulo return 0;
20415b9c547cSRui Paulo }
20425b9c547cSRui Paulo
20435b9c547cSRui Paulo name = X509_get_subject_name(cert);
20445b9c547cSRui Paulo i = -1;
20455b9c547cSRui Paulo for (;;) {
20465b9c547cSRui Paulo X509_NAME_ENTRY *e;
20475b9c547cSRui Paulo ASN1_STRING *cn;
20485b9c547cSRui Paulo
20495b9c547cSRui Paulo i = X509_NAME_get_index_by_NID(name, NID_commonName, i);
20505b9c547cSRui Paulo if (i == -1)
20515b9c547cSRui Paulo break;
20525b9c547cSRui Paulo e = X509_NAME_get_entry(name, i);
20535b9c547cSRui Paulo if (e == NULL)
20545b9c547cSRui Paulo continue;
20555b9c547cSRui Paulo cn = X509_NAME_ENTRY_get_data(e);
20565b9c547cSRui Paulo if (cn == NULL)
20575b9c547cSRui Paulo continue;
20585b9c547cSRui Paulo wpa_hexdump_ascii(MSG_DEBUG, "TLS: Certificate commonName",
20595b9c547cSRui Paulo cn->data, cn->length);
20604bc52338SCy Schubert if (domain_suffix_match(cn->data, cn->length,
20614bc52338SCy Schubert match, match_len, full) == 1) {
20625b9c547cSRui Paulo wpa_printf(MSG_DEBUG, "TLS: %s in commonName found",
20635b9c547cSRui Paulo full ? "Match" : "Suffix match");
20645b9c547cSRui Paulo return 1;
20655b9c547cSRui Paulo }
20665b9c547cSRui Paulo }
20675b9c547cSRui Paulo
20685b9c547cSRui Paulo wpa_printf(MSG_DEBUG, "TLS: No CommonName %smatch found",
20695b9c547cSRui Paulo full ? "": "suffix ");
20705b9c547cSRui Paulo return 0;
20714bc52338SCy Schubert }
20724bc52338SCy Schubert #endif /* CONFIG_NATIVE_WINDOWS */
20734bc52338SCy Schubert
20744bc52338SCy Schubert
tls_match_suffix(X509 * cert,const char * match,int full)20754bc52338SCy Schubert static int tls_match_suffix(X509 *cert, const char *match, int full)
20764bc52338SCy Schubert {
20774bc52338SCy Schubert #ifdef CONFIG_NATIVE_WINDOWS
20784bc52338SCy Schubert /* wincrypt.h has conflicting X509_NAME definition */
20794bc52338SCy Schubert return -1;
20804bc52338SCy Schubert #else /* CONFIG_NATIVE_WINDOWS */
20814bc52338SCy Schubert const char *token, *last = NULL;
20824bc52338SCy Schubert
20834bc52338SCy Schubert /* Process each match alternative separately until a match is found */
20844bc52338SCy Schubert while ((token = cstr_token(match, ";", &last))) {
20854bc52338SCy Schubert if (tls_match_suffix_helper(cert, token, last - token, full))
20864bc52338SCy Schubert return 1;
20874bc52338SCy Schubert }
20884bc52338SCy Schubert
20894bc52338SCy Schubert return 0;
20905b9c547cSRui Paulo #endif /* CONFIG_NATIVE_WINDOWS */
20915b9c547cSRui Paulo }
20925b9c547cSRui Paulo
20935b9c547cSRui Paulo
openssl_tls_fail_reason(int err)2094e28a4053SRui Paulo static enum tls_fail_reason openssl_tls_fail_reason(int err)
2095e28a4053SRui Paulo {
2096e28a4053SRui Paulo switch (err) {
2097e28a4053SRui Paulo case X509_V_ERR_CERT_REVOKED:
2098e28a4053SRui Paulo return TLS_FAIL_REVOKED;
2099e28a4053SRui Paulo case X509_V_ERR_CERT_NOT_YET_VALID:
2100e28a4053SRui Paulo case X509_V_ERR_CRL_NOT_YET_VALID:
2101e28a4053SRui Paulo return TLS_FAIL_NOT_YET_VALID;
2102e28a4053SRui Paulo case X509_V_ERR_CERT_HAS_EXPIRED:
2103e28a4053SRui Paulo case X509_V_ERR_CRL_HAS_EXPIRED:
2104e28a4053SRui Paulo return TLS_FAIL_EXPIRED;
2105e28a4053SRui Paulo case X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT:
2106e28a4053SRui Paulo case X509_V_ERR_UNABLE_TO_GET_CRL:
2107e28a4053SRui Paulo case X509_V_ERR_UNABLE_TO_GET_CRL_ISSUER:
2108e28a4053SRui Paulo case X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN:
2109e28a4053SRui Paulo case X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY:
2110e28a4053SRui Paulo case X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT:
2111e28a4053SRui Paulo case X509_V_ERR_UNABLE_TO_VERIFY_LEAF_SIGNATURE:
2112e28a4053SRui Paulo case X509_V_ERR_CERT_CHAIN_TOO_LONG:
2113e28a4053SRui Paulo case X509_V_ERR_PATH_LENGTH_EXCEEDED:
2114e28a4053SRui Paulo case X509_V_ERR_INVALID_CA:
2115e28a4053SRui Paulo return TLS_FAIL_UNTRUSTED;
2116e28a4053SRui Paulo case X509_V_ERR_UNABLE_TO_DECRYPT_CERT_SIGNATURE:
2117e28a4053SRui Paulo case X509_V_ERR_UNABLE_TO_DECRYPT_CRL_SIGNATURE:
2118e28a4053SRui Paulo case X509_V_ERR_UNABLE_TO_DECODE_ISSUER_PUBLIC_KEY:
2119e28a4053SRui Paulo case X509_V_ERR_ERROR_IN_CERT_NOT_BEFORE_FIELD:
2120e28a4053SRui Paulo case X509_V_ERR_ERROR_IN_CERT_NOT_AFTER_FIELD:
2121e28a4053SRui Paulo case X509_V_ERR_ERROR_IN_CRL_LAST_UPDATE_FIELD:
2122e28a4053SRui Paulo case X509_V_ERR_ERROR_IN_CRL_NEXT_UPDATE_FIELD:
2123e28a4053SRui Paulo case X509_V_ERR_CERT_UNTRUSTED:
2124e28a4053SRui Paulo case X509_V_ERR_CERT_REJECTED:
2125e28a4053SRui Paulo return TLS_FAIL_BAD_CERTIFICATE;
2126e28a4053SRui Paulo default:
2127e28a4053SRui Paulo return TLS_FAIL_UNSPECIFIED;
2128e28a4053SRui Paulo }
2129e28a4053SRui Paulo }
2130e28a4053SRui Paulo
2131e28a4053SRui Paulo
get_x509_cert(X509 * cert)2132e28a4053SRui Paulo static struct wpabuf * get_x509_cert(X509 *cert)
2133e28a4053SRui Paulo {
2134e28a4053SRui Paulo struct wpabuf *buf;
2135e28a4053SRui Paulo u8 *tmp;
2136e28a4053SRui Paulo
2137e28a4053SRui Paulo int cert_len = i2d_X509(cert, NULL);
2138e28a4053SRui Paulo if (cert_len <= 0)
2139e28a4053SRui Paulo return NULL;
2140e28a4053SRui Paulo
2141e28a4053SRui Paulo buf = wpabuf_alloc(cert_len);
2142e28a4053SRui Paulo if (buf == NULL)
2143e28a4053SRui Paulo return NULL;
2144e28a4053SRui Paulo
2145e28a4053SRui Paulo tmp = wpabuf_put(buf, cert_len);
2146e28a4053SRui Paulo i2d_X509(cert, &tmp);
2147e28a4053SRui Paulo return buf;
2148e28a4053SRui Paulo }
2149e28a4053SRui Paulo
2150e28a4053SRui Paulo
openssl_tls_fail_event(struct tls_connection * conn,X509 * err_cert,int err,int depth,const char * subject,const char * err_str,enum tls_fail_reason reason)2151e28a4053SRui Paulo static void openssl_tls_fail_event(struct tls_connection *conn,
2152e28a4053SRui Paulo X509 *err_cert, int err, int depth,
2153e28a4053SRui Paulo const char *subject, const char *err_str,
2154e28a4053SRui Paulo enum tls_fail_reason reason)
2155e28a4053SRui Paulo {
2156e28a4053SRui Paulo union tls_event_data ev;
2157e28a4053SRui Paulo struct wpabuf *cert = NULL;
21585b9c547cSRui Paulo struct tls_context *context = conn->context;
2159e28a4053SRui Paulo
21605b9c547cSRui Paulo if (context->event_cb == NULL)
2161e28a4053SRui Paulo return;
2162e28a4053SRui Paulo
2163e28a4053SRui Paulo cert = get_x509_cert(err_cert);
2164e28a4053SRui Paulo os_memset(&ev, 0, sizeof(ev));
2165e28a4053SRui Paulo ev.cert_fail.reason = reason != TLS_FAIL_UNSPECIFIED ?
2166e28a4053SRui Paulo reason : openssl_tls_fail_reason(err);
2167e28a4053SRui Paulo ev.cert_fail.depth = depth;
2168e28a4053SRui Paulo ev.cert_fail.subject = subject;
2169e28a4053SRui Paulo ev.cert_fail.reason_txt = err_str;
2170e28a4053SRui Paulo ev.cert_fail.cert = cert;
21715b9c547cSRui Paulo context->event_cb(context->cb_ctx, TLS_CERT_CHAIN_FAILURE, &ev);
2172e28a4053SRui Paulo wpabuf_free(cert);
2173e28a4053SRui Paulo }
2174e28a4053SRui Paulo
2175e28a4053SRui Paulo
openssl_cert_tod(X509 * cert)2176206b73d0SCy Schubert static int openssl_cert_tod(X509 *cert)
2177206b73d0SCy Schubert {
2178206b73d0SCy Schubert CERTIFICATEPOLICIES *ext;
2179206b73d0SCy Schubert stack_index_t i;
2180206b73d0SCy Schubert char buf[100];
2181206b73d0SCy Schubert int res;
2182206b73d0SCy Schubert int tod = 0;
2183206b73d0SCy Schubert
2184206b73d0SCy Schubert ext = X509_get_ext_d2i(cert, NID_certificate_policies, NULL, NULL);
2185206b73d0SCy Schubert if (!ext)
2186206b73d0SCy Schubert return 0;
2187206b73d0SCy Schubert
2188206b73d0SCy Schubert for (i = 0; i < sk_POLICYINFO_num(ext); i++) {
2189206b73d0SCy Schubert POLICYINFO *policy;
2190206b73d0SCy Schubert
2191206b73d0SCy Schubert policy = sk_POLICYINFO_value(ext, i);
2192206b73d0SCy Schubert res = OBJ_obj2txt(buf, sizeof(buf), policy->policyid, 0);
2193206b73d0SCy Schubert if (res < 0 || (size_t) res >= sizeof(buf))
2194206b73d0SCy Schubert continue;
2195206b73d0SCy Schubert wpa_printf(MSG_DEBUG, "OpenSSL: Certificate Policy %s", buf);
2196206b73d0SCy Schubert if (os_strcmp(buf, "1.3.6.1.4.1.40808.1.3.1") == 0)
2197c1d255d3SCy Schubert tod = 1; /* TOD-STRICT */
2198c1d255d3SCy Schubert else if (os_strcmp(buf, "1.3.6.1.4.1.40808.1.3.2") == 0 && !tod)
2199c1d255d3SCy Schubert tod = 2; /* TOD-TOFU */
2200206b73d0SCy Schubert }
2201c1d255d3SCy Schubert sk_POLICYINFO_pop_free(ext, POLICYINFO_free);
2202206b73d0SCy Schubert
2203206b73d0SCy Schubert return tod;
2204206b73d0SCy Schubert }
2205206b73d0SCy Schubert
2206206b73d0SCy Schubert
openssl_tls_cert_event(struct tls_connection * conn,X509 * err_cert,int depth,const char * subject)2207e28a4053SRui Paulo static void openssl_tls_cert_event(struct tls_connection *conn,
2208e28a4053SRui Paulo X509 *err_cert, int depth,
2209e28a4053SRui Paulo const char *subject)
2210e28a4053SRui Paulo {
2211e28a4053SRui Paulo struct wpabuf *cert = NULL;
2212e28a4053SRui Paulo union tls_event_data ev;
22135b9c547cSRui Paulo struct tls_context *context = conn->context;
22145b9c547cSRui Paulo char *altsubject[TLS_MAX_ALT_SUBJECT];
22155b9c547cSRui Paulo int alt, num_altsubject = 0;
22165b9c547cSRui Paulo GENERAL_NAME *gen;
22175b9c547cSRui Paulo void *ext;
22185b9c547cSRui Paulo stack_index_t i;
221985732ac8SCy Schubert ASN1_INTEGER *ser;
222085732ac8SCy Schubert char serial_num[128];
2221e28a4053SRui Paulo #ifdef CONFIG_SHA256
2222e28a4053SRui Paulo u8 hash[32];
2223e28a4053SRui Paulo #endif /* CONFIG_SHA256 */
2224e28a4053SRui Paulo
22255b9c547cSRui Paulo if (context->event_cb == NULL)
2226e28a4053SRui Paulo return;
2227e28a4053SRui Paulo
2228e28a4053SRui Paulo os_memset(&ev, 0, sizeof(ev));
2229780fb4a2SCy Schubert if (conn->cert_probe || (conn->flags & TLS_CONN_EXT_CERT_CHECK) ||
2230780fb4a2SCy Schubert context->cert_in_cb) {
2231e28a4053SRui Paulo cert = get_x509_cert(err_cert);
2232e28a4053SRui Paulo ev.peer_cert.cert = cert;
2233e28a4053SRui Paulo }
2234e28a4053SRui Paulo #ifdef CONFIG_SHA256
2235e28a4053SRui Paulo if (cert) {
2236e28a4053SRui Paulo const u8 *addr[1];
2237e28a4053SRui Paulo size_t len[1];
2238e28a4053SRui Paulo addr[0] = wpabuf_head(cert);
2239e28a4053SRui Paulo len[0] = wpabuf_len(cert);
2240e28a4053SRui Paulo if (sha256_vector(1, addr, len, hash) == 0) {
2241e28a4053SRui Paulo ev.peer_cert.hash = hash;
2242e28a4053SRui Paulo ev.peer_cert.hash_len = sizeof(hash);
2243e28a4053SRui Paulo }
2244e28a4053SRui Paulo }
2245e28a4053SRui Paulo #endif /* CONFIG_SHA256 */
2246e28a4053SRui Paulo ev.peer_cert.depth = depth;
2247e28a4053SRui Paulo ev.peer_cert.subject = subject;
22485b9c547cSRui Paulo
224985732ac8SCy Schubert ser = X509_get_serialNumber(err_cert);
225085732ac8SCy Schubert if (ser) {
225185732ac8SCy Schubert wpa_snprintf_hex_uppercase(serial_num, sizeof(serial_num),
225285732ac8SCy Schubert ASN1_STRING_get0_data(ser),
225385732ac8SCy Schubert ASN1_STRING_length(ser));
225485732ac8SCy Schubert ev.peer_cert.serial_num = serial_num;
225585732ac8SCy Schubert }
225685732ac8SCy Schubert
22575b9c547cSRui Paulo ext = X509_get_ext_d2i(err_cert, NID_subject_alt_name, NULL, NULL);
22585b9c547cSRui Paulo for (i = 0; ext && i < sk_GENERAL_NAME_num(ext); i++) {
22595b9c547cSRui Paulo char *pos;
22605b9c547cSRui Paulo
22615b9c547cSRui Paulo if (num_altsubject == TLS_MAX_ALT_SUBJECT)
22625b9c547cSRui Paulo break;
22635b9c547cSRui Paulo gen = sk_GENERAL_NAME_value(ext, i);
22645b9c547cSRui Paulo if (gen->type != GEN_EMAIL &&
22655b9c547cSRui Paulo gen->type != GEN_DNS &&
22665b9c547cSRui Paulo gen->type != GEN_URI)
22675b9c547cSRui Paulo continue;
22685b9c547cSRui Paulo
22695b9c547cSRui Paulo pos = os_malloc(10 + gen->d.ia5->length + 1);
22705b9c547cSRui Paulo if (pos == NULL)
22715b9c547cSRui Paulo break;
22725b9c547cSRui Paulo altsubject[num_altsubject++] = pos;
22735b9c547cSRui Paulo
22745b9c547cSRui Paulo switch (gen->type) {
22755b9c547cSRui Paulo case GEN_EMAIL:
22765b9c547cSRui Paulo os_memcpy(pos, "EMAIL:", 6);
22775b9c547cSRui Paulo pos += 6;
22785b9c547cSRui Paulo break;
22795b9c547cSRui Paulo case GEN_DNS:
22805b9c547cSRui Paulo os_memcpy(pos, "DNS:", 4);
22815b9c547cSRui Paulo pos += 4;
22825b9c547cSRui Paulo break;
22835b9c547cSRui Paulo case GEN_URI:
22845b9c547cSRui Paulo os_memcpy(pos, "URI:", 4);
22855b9c547cSRui Paulo pos += 4;
22865b9c547cSRui Paulo break;
22875b9c547cSRui Paulo }
22885b9c547cSRui Paulo
22895b9c547cSRui Paulo os_memcpy(pos, gen->d.ia5->data, gen->d.ia5->length);
22905b9c547cSRui Paulo pos += gen->d.ia5->length;
22915b9c547cSRui Paulo *pos = '\0';
22925b9c547cSRui Paulo }
2293780fb4a2SCy Schubert sk_GENERAL_NAME_pop_free(ext, GENERAL_NAME_free);
22945b9c547cSRui Paulo
22955b9c547cSRui Paulo for (alt = 0; alt < num_altsubject; alt++)
22965b9c547cSRui Paulo ev.peer_cert.altsubject[alt] = altsubject[alt];
22975b9c547cSRui Paulo ev.peer_cert.num_altsubject = num_altsubject;
22985b9c547cSRui Paulo
2299206b73d0SCy Schubert ev.peer_cert.tod = openssl_cert_tod(err_cert);
2300206b73d0SCy Schubert
23015b9c547cSRui Paulo context->event_cb(context->cb_ctx, TLS_PEER_CERTIFICATE, &ev);
2302e28a4053SRui Paulo wpabuf_free(cert);
23035b9c547cSRui Paulo for (alt = 0; alt < num_altsubject; alt++)
23045b9c547cSRui Paulo os_free(altsubject[alt]);
2305e28a4053SRui Paulo }
2306e28a4053SRui Paulo
2307e28a4053SRui Paulo
debug_print_cert(X509 * cert,const char * title)2308c1d255d3SCy Schubert static void debug_print_cert(X509 *cert, const char *title)
2309c1d255d3SCy Schubert {
2310c1d255d3SCy Schubert #ifndef CONFIG_NO_STDOUT_DEBUG
2311c1d255d3SCy Schubert BIO *out;
2312c1d255d3SCy Schubert size_t rlen;
2313c1d255d3SCy Schubert char *txt;
2314c1d255d3SCy Schubert int res;
2315c1d255d3SCy Schubert
2316c1d255d3SCy Schubert if (wpa_debug_level > MSG_DEBUG)
2317c1d255d3SCy Schubert return;
2318c1d255d3SCy Schubert
2319c1d255d3SCy Schubert out = BIO_new(BIO_s_mem());
2320c1d255d3SCy Schubert if (!out)
2321c1d255d3SCy Schubert return;
2322c1d255d3SCy Schubert
2323c1d255d3SCy Schubert X509_print(out, cert);
2324c1d255d3SCy Schubert rlen = BIO_ctrl_pending(out);
2325c1d255d3SCy Schubert txt = os_malloc(rlen + 1);
2326c1d255d3SCy Schubert if (txt) {
2327c1d255d3SCy Schubert res = BIO_read(out, txt, rlen);
2328c1d255d3SCy Schubert if (res > 0) {
2329c1d255d3SCy Schubert txt[res] = '\0';
2330c1d255d3SCy Schubert wpa_printf(MSG_DEBUG, "OpenSSL: %s\n%s", title, txt);
2331c1d255d3SCy Schubert }
2332c1d255d3SCy Schubert os_free(txt);
2333c1d255d3SCy Schubert }
2334c1d255d3SCy Schubert
2335c1d255d3SCy Schubert BIO_free(out);
2336c1d255d3SCy Schubert #endif /* CONFIG_NO_STDOUT_DEBUG */
2337c1d255d3SCy Schubert }
2338c1d255d3SCy Schubert
2339c1d255d3SCy Schubert
tls_verify_cb(int preverify_ok,X509_STORE_CTX * x509_ctx)234039beb93cSSam Leffler static int tls_verify_cb(int preverify_ok, X509_STORE_CTX *x509_ctx)
234139beb93cSSam Leffler {
234239beb93cSSam Leffler char buf[256];
234339beb93cSSam Leffler X509 *err_cert;
234439beb93cSSam Leffler int err, depth;
234539beb93cSSam Leffler SSL *ssl;
234639beb93cSSam Leffler struct tls_connection *conn;
23475b9c547cSRui Paulo struct tls_context *context;
23485b9c547cSRui Paulo char *match, *altmatch, *suffix_match, *domain_match;
23494bc52338SCy Schubert const char *check_cert_subject;
2350e28a4053SRui Paulo const char *err_str;
235139beb93cSSam Leffler
235239beb93cSSam Leffler err_cert = X509_STORE_CTX_get_current_cert(x509_ctx);
23535b9c547cSRui Paulo if (!err_cert)
23545b9c547cSRui Paulo return 0;
23555b9c547cSRui Paulo
235639beb93cSSam Leffler err = X509_STORE_CTX_get_error(x509_ctx);
235739beb93cSSam Leffler depth = X509_STORE_CTX_get_error_depth(x509_ctx);
235839beb93cSSam Leffler ssl = X509_STORE_CTX_get_ex_data(x509_ctx,
235939beb93cSSam Leffler SSL_get_ex_data_X509_STORE_CTX_idx());
2360c1d255d3SCy Schubert os_snprintf(buf, sizeof(buf), "Peer certificate - depth %d", depth);
2361c1d255d3SCy Schubert debug_print_cert(err_cert, buf);
236239beb93cSSam Leffler X509_NAME_oneline(X509_get_subject_name(err_cert), buf, sizeof(buf));
236339beb93cSSam Leffler
236439beb93cSSam Leffler conn = SSL_get_app_data(ssl);
2365f05cddf9SRui Paulo if (conn == NULL)
2366f05cddf9SRui Paulo return 0;
23675b9c547cSRui Paulo
23685b9c547cSRui Paulo if (depth == 0)
23695b9c547cSRui Paulo conn->peer_cert = err_cert;
23705b9c547cSRui Paulo else if (depth == 1)
23715b9c547cSRui Paulo conn->peer_issuer = err_cert;
23725b9c547cSRui Paulo else if (depth == 2)
23735b9c547cSRui Paulo conn->peer_issuer_issuer = err_cert;
23745b9c547cSRui Paulo
23755b9c547cSRui Paulo context = conn->context;
2376f05cddf9SRui Paulo match = conn->subject_match;
2377f05cddf9SRui Paulo altmatch = conn->altsubject_match;
23785b9c547cSRui Paulo suffix_match = conn->suffix_match;
23795b9c547cSRui Paulo domain_match = conn->domain_match;
238039beb93cSSam Leffler
2381e28a4053SRui Paulo if (!preverify_ok && !conn->ca_cert_verify)
2382e28a4053SRui Paulo preverify_ok = 1;
2383e28a4053SRui Paulo if (!preverify_ok && depth > 0 && conn->server_cert_only)
2384e28a4053SRui Paulo preverify_ok = 1;
2385f05cddf9SRui Paulo if (!preverify_ok && (conn->flags & TLS_CONN_DISABLE_TIME_CHECKS) &&
2386f05cddf9SRui Paulo (err == X509_V_ERR_CERT_HAS_EXPIRED ||
2387f05cddf9SRui Paulo err == X509_V_ERR_CERT_NOT_YET_VALID)) {
2388f05cddf9SRui Paulo wpa_printf(MSG_DEBUG, "OpenSSL: Ignore certificate validity "
2389f05cddf9SRui Paulo "time mismatch");
2390f05cddf9SRui Paulo preverify_ok = 1;
2391f05cddf9SRui Paulo }
23924bc52338SCy Schubert if (!preverify_ok && !conn->data->check_crl_strict &&
23934bc52338SCy Schubert (err == X509_V_ERR_CRL_HAS_EXPIRED ||
23944bc52338SCy Schubert err == X509_V_ERR_CRL_NOT_YET_VALID)) {
23954bc52338SCy Schubert wpa_printf(MSG_DEBUG,
23964bc52338SCy Schubert "OpenSSL: Ignore certificate validity CRL time mismatch");
23974bc52338SCy Schubert preverify_ok = 1;
23984bc52338SCy Schubert }
2399e28a4053SRui Paulo
2400e28a4053SRui Paulo err_str = X509_verify_cert_error_string(err);
2401e28a4053SRui Paulo
2402e28a4053SRui Paulo #ifdef CONFIG_SHA256
24035b9c547cSRui Paulo /*
24045b9c547cSRui Paulo * Do not require preverify_ok so we can explicity allow otherwise
24055b9c547cSRui Paulo * invalid pinned server certificates.
24065b9c547cSRui Paulo */
24075b9c547cSRui Paulo if (depth == 0 && conn->server_cert_only) {
2408e28a4053SRui Paulo struct wpabuf *cert;
2409e28a4053SRui Paulo cert = get_x509_cert(err_cert);
2410e28a4053SRui Paulo if (!cert) {
2411e28a4053SRui Paulo wpa_printf(MSG_DEBUG, "OpenSSL: Could not fetch "
2412e28a4053SRui Paulo "server certificate data");
2413e28a4053SRui Paulo preverify_ok = 0;
2414e28a4053SRui Paulo } else {
2415e28a4053SRui Paulo u8 hash[32];
2416e28a4053SRui Paulo const u8 *addr[1];
2417e28a4053SRui Paulo size_t len[1];
2418e28a4053SRui Paulo addr[0] = wpabuf_head(cert);
2419e28a4053SRui Paulo len[0] = wpabuf_len(cert);
2420e28a4053SRui Paulo if (sha256_vector(1, addr, len, hash) < 0 ||
2421e28a4053SRui Paulo os_memcmp(conn->srv_cert_hash, hash, 32) != 0) {
2422e28a4053SRui Paulo err_str = "Server certificate mismatch";
2423e28a4053SRui Paulo err = X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN;
2424e28a4053SRui Paulo preverify_ok = 0;
24255b9c547cSRui Paulo } else if (!preverify_ok) {
24265b9c547cSRui Paulo /*
24275b9c547cSRui Paulo * Certificate matches pinned certificate, allow
24285b9c547cSRui Paulo * regardless of other problems.
24295b9c547cSRui Paulo */
24305b9c547cSRui Paulo wpa_printf(MSG_DEBUG,
24315b9c547cSRui Paulo "OpenSSL: Ignore validation issues for a pinned server certificate");
24325b9c547cSRui Paulo preverify_ok = 1;
2433e28a4053SRui Paulo }
2434e28a4053SRui Paulo wpabuf_free(cert);
2435e28a4053SRui Paulo }
2436e28a4053SRui Paulo }
2437e28a4053SRui Paulo #endif /* CONFIG_SHA256 */
2438e28a4053SRui Paulo
2439206b73d0SCy Schubert openssl_tls_cert_event(conn, err_cert, depth, buf);
2440206b73d0SCy Schubert
244139beb93cSSam Leffler if (!preverify_ok) {
2442206b73d0SCy Schubert if (depth > 0) {
2443206b73d0SCy Schubert /* Send cert event for the peer certificate so that
2444206b73d0SCy Schubert * the upper layers get information about it even if
2445206b73d0SCy Schubert * validation of a CA certificate fails. */
2446206b73d0SCy Schubert STACK_OF(X509) *chain;
2447206b73d0SCy Schubert
2448206b73d0SCy Schubert chain = X509_STORE_CTX_get1_chain(x509_ctx);
2449206b73d0SCy Schubert if (chain && sk_X509_num(chain) > 0) {
2450206b73d0SCy Schubert char buf2[256];
2451206b73d0SCy Schubert X509 *cert;
2452206b73d0SCy Schubert
2453206b73d0SCy Schubert cert = sk_X509_value(chain, 0);
2454206b73d0SCy Schubert X509_NAME_oneline(X509_get_subject_name(cert),
2455206b73d0SCy Schubert buf2, sizeof(buf2));
2456206b73d0SCy Schubert
2457206b73d0SCy Schubert openssl_tls_cert_event(conn, cert, 0, buf2);
2458206b73d0SCy Schubert }
2459206b73d0SCy Schubert if (chain)
2460206b73d0SCy Schubert sk_X509_pop_free(chain, X509_free);
2461206b73d0SCy Schubert }
2462206b73d0SCy Schubert
246339beb93cSSam Leffler wpa_printf(MSG_WARNING, "TLS: Certificate verification failed,"
2464e28a4053SRui Paulo " error %d (%s) depth %d for '%s'", err, err_str,
2465e28a4053SRui Paulo depth, buf);
2466e28a4053SRui Paulo openssl_tls_fail_event(conn, err_cert, err, depth, buf,
2467e28a4053SRui Paulo err_str, TLS_FAIL_UNSPECIFIED);
2468e28a4053SRui Paulo return preverify_ok;
2469e28a4053SRui Paulo }
2470e28a4053SRui Paulo
2471e28a4053SRui Paulo wpa_printf(MSG_DEBUG, "TLS: tls_verify_cb - preverify_ok=%d "
2472e28a4053SRui Paulo "err=%d (%s) ca_cert_verify=%d depth=%d buf='%s'",
2473e28a4053SRui Paulo preverify_ok, err, err_str,
2474e28a4053SRui Paulo conn->ca_cert_verify, depth, buf);
24754bc52338SCy Schubert check_cert_subject = conn->check_cert_subject;
24764bc52338SCy Schubert if (!check_cert_subject)
24774bc52338SCy Schubert check_cert_subject = conn->data->check_cert_subject;
24784bc52338SCy Schubert if (check_cert_subject) {
24794bc52338SCy Schubert if (depth == 0 &&
24804bc52338SCy Schubert !tls_match_dn_field(err_cert, check_cert_subject)) {
24814bc52338SCy Schubert preverify_ok = 0;
24824bc52338SCy Schubert openssl_tls_fail_event(conn, err_cert, err, depth, buf,
24834bc52338SCy Schubert "Distinguished Name",
24844bc52338SCy Schubert TLS_FAIL_DN_MISMATCH);
24854bc52338SCy Schubert }
24864bc52338SCy Schubert }
248739beb93cSSam Leffler if (depth == 0 && match && os_strstr(buf, match) == NULL) {
248839beb93cSSam Leffler wpa_printf(MSG_WARNING, "TLS: Subject '%s' did not "
248939beb93cSSam Leffler "match with '%s'", buf, match);
249039beb93cSSam Leffler preverify_ok = 0;
2491e28a4053SRui Paulo openssl_tls_fail_event(conn, err_cert, err, depth, buf,
2492e28a4053SRui Paulo "Subject mismatch",
2493e28a4053SRui Paulo TLS_FAIL_SUBJECT_MISMATCH);
249439beb93cSSam Leffler } else if (depth == 0 && altmatch &&
249539beb93cSSam Leffler !tls_match_altsubject(err_cert, altmatch)) {
249639beb93cSSam Leffler wpa_printf(MSG_WARNING, "TLS: altSubjectName match "
249739beb93cSSam Leffler "'%s' not found", altmatch);
249839beb93cSSam Leffler preverify_ok = 0;
2499e28a4053SRui Paulo openssl_tls_fail_event(conn, err_cert, err, depth, buf,
2500e28a4053SRui Paulo "AltSubject mismatch",
2501e28a4053SRui Paulo TLS_FAIL_ALTSUBJECT_MISMATCH);
25025b9c547cSRui Paulo } else if (depth == 0 && suffix_match &&
25035b9c547cSRui Paulo !tls_match_suffix(err_cert, suffix_match, 0)) {
25045b9c547cSRui Paulo wpa_printf(MSG_WARNING, "TLS: Domain suffix match '%s' not found",
25055b9c547cSRui Paulo suffix_match);
25065b9c547cSRui Paulo preverify_ok = 0;
25075b9c547cSRui Paulo openssl_tls_fail_event(conn, err_cert, err, depth, buf,
25085b9c547cSRui Paulo "Domain suffix mismatch",
25095b9c547cSRui Paulo TLS_FAIL_DOMAIN_SUFFIX_MISMATCH);
25105b9c547cSRui Paulo } else if (depth == 0 && domain_match &&
25115b9c547cSRui Paulo !tls_match_suffix(err_cert, domain_match, 1)) {
25125b9c547cSRui Paulo wpa_printf(MSG_WARNING, "TLS: Domain match '%s' not found",
25135b9c547cSRui Paulo domain_match);
25145b9c547cSRui Paulo preverify_ok = 0;
25155b9c547cSRui Paulo openssl_tls_fail_event(conn, err_cert, err, depth, buf,
25165b9c547cSRui Paulo "Domain mismatch",
25175b9c547cSRui Paulo TLS_FAIL_DOMAIN_MISMATCH);
2518206b73d0SCy Schubert }
2519e28a4053SRui Paulo
2520e28a4053SRui Paulo if (conn->cert_probe && preverify_ok && depth == 0) {
2521e28a4053SRui Paulo wpa_printf(MSG_DEBUG, "OpenSSL: Reject server certificate "
2522e28a4053SRui Paulo "on probe-only run");
2523e28a4053SRui Paulo preverify_ok = 0;
2524e28a4053SRui Paulo openssl_tls_fail_event(conn, err_cert, err, depth, buf,
2525e28a4053SRui Paulo "Server certificate chain probe",
2526e28a4053SRui Paulo TLS_FAIL_SERVER_CHAIN_PROBE);
252739beb93cSSam Leffler }
252839beb93cSSam Leffler
252985732ac8SCy Schubert #ifdef CONFIG_SUITEB
253085732ac8SCy Schubert if (conn->flags & TLS_CONN_SUITEB) {
253185732ac8SCy Schubert EVP_PKEY *pk;
253285732ac8SCy Schubert RSA *rsa;
253385732ac8SCy Schubert int len = -1;
253485732ac8SCy Schubert
253585732ac8SCy Schubert pk = X509_get_pubkey(err_cert);
253685732ac8SCy Schubert if (pk) {
253785732ac8SCy Schubert rsa = EVP_PKEY_get1_RSA(pk);
253885732ac8SCy Schubert if (rsa) {
253985732ac8SCy Schubert len = RSA_bits(rsa);
254085732ac8SCy Schubert RSA_free(rsa);
254185732ac8SCy Schubert }
254285732ac8SCy Schubert EVP_PKEY_free(pk);
254385732ac8SCy Schubert }
254485732ac8SCy Schubert
254585732ac8SCy Schubert if (len >= 0) {
254685732ac8SCy Schubert wpa_printf(MSG_DEBUG,
254785732ac8SCy Schubert "OpenSSL: RSA modulus size: %d bits", len);
254885732ac8SCy Schubert if (len < 3072) {
254985732ac8SCy Schubert preverify_ok = 0;
255085732ac8SCy Schubert openssl_tls_fail_event(
255185732ac8SCy Schubert conn, err_cert, err,
255285732ac8SCy Schubert depth, buf,
255385732ac8SCy Schubert "Insufficient RSA modulus size",
255485732ac8SCy Schubert TLS_FAIL_INSUFFICIENT_KEY_LEN);
255585732ac8SCy Schubert }
255685732ac8SCy Schubert }
255785732ac8SCy Schubert }
255885732ac8SCy Schubert #endif /* CONFIG_SUITEB */
255985732ac8SCy Schubert
2560780fb4a2SCy Schubert #ifdef OPENSSL_IS_BORINGSSL
2561780fb4a2SCy Schubert if (depth == 0 && (conn->flags & TLS_CONN_REQUEST_OCSP) &&
2562780fb4a2SCy Schubert preverify_ok) {
2563780fb4a2SCy Schubert enum ocsp_result res;
2564780fb4a2SCy Schubert
2565780fb4a2SCy Schubert res = check_ocsp_resp(conn->ssl_ctx, conn->ssl, err_cert,
2566780fb4a2SCy Schubert conn->peer_issuer,
2567780fb4a2SCy Schubert conn->peer_issuer_issuer);
2568780fb4a2SCy Schubert if (res == OCSP_REVOKED) {
2569780fb4a2SCy Schubert preverify_ok = 0;
2570780fb4a2SCy Schubert openssl_tls_fail_event(conn, err_cert, err, depth, buf,
2571780fb4a2SCy Schubert "certificate revoked",
2572780fb4a2SCy Schubert TLS_FAIL_REVOKED);
2573780fb4a2SCy Schubert if (err == X509_V_OK)
2574780fb4a2SCy Schubert X509_STORE_CTX_set_error(
2575780fb4a2SCy Schubert x509_ctx, X509_V_ERR_CERT_REVOKED);
2576780fb4a2SCy Schubert } else if (res != OCSP_GOOD &&
2577780fb4a2SCy Schubert (conn->flags & TLS_CONN_REQUIRE_OCSP)) {
2578780fb4a2SCy Schubert preverify_ok = 0;
2579780fb4a2SCy Schubert openssl_tls_fail_event(conn, err_cert, err, depth, buf,
2580780fb4a2SCy Schubert "bad certificate status response",
2581780fb4a2SCy Schubert TLS_FAIL_UNSPECIFIED);
2582780fb4a2SCy Schubert }
2583780fb4a2SCy Schubert }
2584780fb4a2SCy Schubert #endif /* OPENSSL_IS_BORINGSSL */
2585780fb4a2SCy Schubert
2586780fb4a2SCy Schubert if (depth == 0 && preverify_ok && context->event_cb != NULL)
25875b9c547cSRui Paulo context->event_cb(context->cb_ctx,
2588f05cddf9SRui Paulo TLS_CERT_CHAIN_SUCCESS, NULL);
2589f05cddf9SRui Paulo
2590c1d255d3SCy Schubert if (depth == 0 && preverify_ok) {
2591c1d255d3SCy Schubert os_free(conn->peer_subject);
2592c1d255d3SCy Schubert conn->peer_subject = os_strdup(buf);
2593c1d255d3SCy Schubert }
2594c1d255d3SCy Schubert
259539beb93cSSam Leffler return preverify_ok;
259639beb93cSSam Leffler }
259739beb93cSSam Leffler
259839beb93cSSam Leffler
259939beb93cSSam Leffler #ifndef OPENSSL_NO_STDIO
tls_load_ca_der(struct tls_data * data,const char * ca_cert)2600325151a3SRui Paulo static int tls_load_ca_der(struct tls_data *data, const char *ca_cert)
260139beb93cSSam Leffler {
2602325151a3SRui Paulo SSL_CTX *ssl_ctx = data->ssl;
260339beb93cSSam Leffler X509_LOOKUP *lookup;
260439beb93cSSam Leffler int ret = 0;
260539beb93cSSam Leffler
26065b9c547cSRui Paulo lookup = X509_STORE_add_lookup(SSL_CTX_get_cert_store(ssl_ctx),
260739beb93cSSam Leffler X509_LOOKUP_file());
260839beb93cSSam Leffler if (lookup == NULL) {
260939beb93cSSam Leffler tls_show_errors(MSG_WARNING, __func__,
261039beb93cSSam Leffler "Failed add lookup for X509 store");
261139beb93cSSam Leffler return -1;
261239beb93cSSam Leffler }
261339beb93cSSam Leffler
261439beb93cSSam Leffler if (!X509_LOOKUP_load_file(lookup, ca_cert, X509_FILETYPE_ASN1)) {
261539beb93cSSam Leffler unsigned long err = ERR_peek_error();
261639beb93cSSam Leffler tls_show_errors(MSG_WARNING, __func__,
261739beb93cSSam Leffler "Failed load CA in DER format");
261839beb93cSSam Leffler if (ERR_GET_LIB(err) == ERR_LIB_X509 &&
261939beb93cSSam Leffler ERR_GET_REASON(err) == X509_R_CERT_ALREADY_IN_HASH_TABLE) {
262039beb93cSSam Leffler wpa_printf(MSG_DEBUG, "OpenSSL: %s - ignoring "
262139beb93cSSam Leffler "cert already in hash table error",
262239beb93cSSam Leffler __func__);
262339beb93cSSam Leffler } else
262439beb93cSSam Leffler ret = -1;
262539beb93cSSam Leffler }
262639beb93cSSam Leffler
262739beb93cSSam Leffler return ret;
262839beb93cSSam Leffler }
262939beb93cSSam Leffler #endif /* OPENSSL_NO_STDIO */
263039beb93cSSam Leffler
263139beb93cSSam Leffler
tls_connection_ca_cert(struct tls_data * data,struct tls_connection * conn,const char * ca_cert,const u8 * ca_cert_blob,size_t ca_cert_blob_len,const char * ca_path)2632325151a3SRui Paulo static int tls_connection_ca_cert(struct tls_data *data,
2633325151a3SRui Paulo struct tls_connection *conn,
263439beb93cSSam Leffler const char *ca_cert, const u8 *ca_cert_blob,
263539beb93cSSam Leffler size_t ca_cert_blob_len, const char *ca_path)
263639beb93cSSam Leffler {
2637325151a3SRui Paulo SSL_CTX *ssl_ctx = data->ssl;
26385b9c547cSRui Paulo X509_STORE *store;
263939beb93cSSam Leffler
264039beb93cSSam Leffler /*
264139beb93cSSam Leffler * Remove previously configured trusted CA certificates before adding
264239beb93cSSam Leffler * new ones.
264339beb93cSSam Leffler */
26445b9c547cSRui Paulo store = X509_STORE_new();
26455b9c547cSRui Paulo if (store == NULL) {
264639beb93cSSam Leffler wpa_printf(MSG_DEBUG, "OpenSSL: %s - failed to allocate new "
264739beb93cSSam Leffler "certificate store", __func__);
264839beb93cSSam Leffler return -1;
264939beb93cSSam Leffler }
26505b9c547cSRui Paulo SSL_CTX_set_cert_store(ssl_ctx, store);
265139beb93cSSam Leffler
2652e28a4053SRui Paulo SSL_set_verify(conn->ssl, SSL_VERIFY_PEER, tls_verify_cb);
2653e28a4053SRui Paulo conn->ca_cert_verify = 1;
2654e28a4053SRui Paulo
2655e28a4053SRui Paulo if (ca_cert && os_strncmp(ca_cert, "probe://", 8) == 0) {
2656e28a4053SRui Paulo wpa_printf(MSG_DEBUG, "OpenSSL: Probe for server certificate "
2657e28a4053SRui Paulo "chain");
2658e28a4053SRui Paulo conn->cert_probe = 1;
2659e28a4053SRui Paulo conn->ca_cert_verify = 0;
2660e28a4053SRui Paulo return 0;
2661e28a4053SRui Paulo }
2662e28a4053SRui Paulo
2663e28a4053SRui Paulo if (ca_cert && os_strncmp(ca_cert, "hash://", 7) == 0) {
2664e28a4053SRui Paulo #ifdef CONFIG_SHA256
2665e28a4053SRui Paulo const char *pos = ca_cert + 7;
2666e28a4053SRui Paulo if (os_strncmp(pos, "server/sha256/", 14) != 0) {
2667e28a4053SRui Paulo wpa_printf(MSG_DEBUG, "OpenSSL: Unsupported ca_cert "
2668e28a4053SRui Paulo "hash value '%s'", ca_cert);
2669e28a4053SRui Paulo return -1;
2670e28a4053SRui Paulo }
2671e28a4053SRui Paulo pos += 14;
2672e28a4053SRui Paulo if (os_strlen(pos) != 32 * 2) {
2673e28a4053SRui Paulo wpa_printf(MSG_DEBUG, "OpenSSL: Unexpected SHA256 "
2674e28a4053SRui Paulo "hash length in ca_cert '%s'", ca_cert);
2675e28a4053SRui Paulo return -1;
2676e28a4053SRui Paulo }
2677e28a4053SRui Paulo if (hexstr2bin(pos, conn->srv_cert_hash, 32) < 0) {
2678e28a4053SRui Paulo wpa_printf(MSG_DEBUG, "OpenSSL: Invalid SHA256 hash "
2679e28a4053SRui Paulo "value in ca_cert '%s'", ca_cert);
2680e28a4053SRui Paulo return -1;
2681e28a4053SRui Paulo }
2682e28a4053SRui Paulo conn->server_cert_only = 1;
2683e28a4053SRui Paulo wpa_printf(MSG_DEBUG, "OpenSSL: Checking only server "
2684e28a4053SRui Paulo "certificate match");
2685e28a4053SRui Paulo return 0;
2686e28a4053SRui Paulo #else /* CONFIG_SHA256 */
2687e28a4053SRui Paulo wpa_printf(MSG_INFO, "No SHA256 included in the build - "
2688e28a4053SRui Paulo "cannot validate server certificate hash");
2689e28a4053SRui Paulo return -1;
2690e28a4053SRui Paulo #endif /* CONFIG_SHA256 */
2691e28a4053SRui Paulo }
2692e28a4053SRui Paulo
269339beb93cSSam Leffler if (ca_cert_blob) {
26945b9c547cSRui Paulo X509 *cert = d2i_X509(NULL,
26955b9c547cSRui Paulo (const unsigned char **) &ca_cert_blob,
269639beb93cSSam Leffler ca_cert_blob_len);
269739beb93cSSam Leffler if (cert == NULL) {
2698206b73d0SCy Schubert BIO *bio = BIO_new_mem_buf(ca_cert_blob,
2699206b73d0SCy Schubert ca_cert_blob_len);
2700206b73d0SCy Schubert
2701206b73d0SCy Schubert if (bio) {
2702206b73d0SCy Schubert cert = PEM_read_bio_X509(bio, NULL, NULL, NULL);
2703206b73d0SCy Schubert BIO_free(bio);
2704206b73d0SCy Schubert }
2705206b73d0SCy Schubert
2706206b73d0SCy Schubert if (!cert) {
270739beb93cSSam Leffler tls_show_errors(MSG_WARNING, __func__,
270839beb93cSSam Leffler "Failed to parse ca_cert_blob");
270939beb93cSSam Leffler return -1;
271039beb93cSSam Leffler }
271139beb93cSSam Leffler
2712206b73d0SCy Schubert while (ERR_get_error()) {
2713206b73d0SCy Schubert /* Ignore errors from DER conversion. */
2714206b73d0SCy Schubert }
2715206b73d0SCy Schubert }
2716206b73d0SCy Schubert
27175b9c547cSRui Paulo if (!X509_STORE_add_cert(SSL_CTX_get_cert_store(ssl_ctx),
27185b9c547cSRui Paulo cert)) {
271939beb93cSSam Leffler unsigned long err = ERR_peek_error();
272039beb93cSSam Leffler tls_show_errors(MSG_WARNING, __func__,
272139beb93cSSam Leffler "Failed to add ca_cert_blob to "
272239beb93cSSam Leffler "certificate store");
272339beb93cSSam Leffler if (ERR_GET_LIB(err) == ERR_LIB_X509 &&
272439beb93cSSam Leffler ERR_GET_REASON(err) ==
272539beb93cSSam Leffler X509_R_CERT_ALREADY_IN_HASH_TABLE) {
272639beb93cSSam Leffler wpa_printf(MSG_DEBUG, "OpenSSL: %s - ignoring "
272739beb93cSSam Leffler "cert already in hash table error",
272839beb93cSSam Leffler __func__);
272939beb93cSSam Leffler } else {
273039beb93cSSam Leffler X509_free(cert);
273139beb93cSSam Leffler return -1;
273239beb93cSSam Leffler }
273339beb93cSSam Leffler }
273439beb93cSSam Leffler X509_free(cert);
273539beb93cSSam Leffler wpa_printf(MSG_DEBUG, "OpenSSL: %s - added ca_cert_blob "
273639beb93cSSam Leffler "to certificate store", __func__);
273739beb93cSSam Leffler return 0;
273839beb93cSSam Leffler }
273939beb93cSSam Leffler
2740f05cddf9SRui Paulo #ifdef ANDROID
2741780fb4a2SCy Schubert /* Single alias */
2742f05cddf9SRui Paulo if (ca_cert && os_strncmp("keystore://", ca_cert, 11) == 0) {
2743780fb4a2SCy Schubert if (tls_add_ca_from_keystore(SSL_CTX_get_cert_store(ssl_ctx),
2744780fb4a2SCy Schubert &ca_cert[11]) < 0)
2745f05cddf9SRui Paulo return -1;
2746780fb4a2SCy Schubert SSL_set_verify(conn->ssl, SSL_VERIFY_PEER, tls_verify_cb);
2747780fb4a2SCy Schubert return 0;
2748780fb4a2SCy Schubert }
2749f05cddf9SRui Paulo
2750780fb4a2SCy Schubert /* Multiple aliases separated by space */
2751780fb4a2SCy Schubert if (ca_cert && os_strncmp("keystores://", ca_cert, 12) == 0) {
2752780fb4a2SCy Schubert char *aliases = os_strdup(&ca_cert[12]);
2753780fb4a2SCy Schubert const char *delim = " ";
2754780fb4a2SCy Schubert int rc = 0;
2755780fb4a2SCy Schubert char *savedptr;
2756780fb4a2SCy Schubert char *alias;
2757780fb4a2SCy Schubert
2758780fb4a2SCy Schubert if (!aliases)
2759780fb4a2SCy Schubert return -1;
2760780fb4a2SCy Schubert alias = strtok_r(aliases, delim, &savedptr);
2761780fb4a2SCy Schubert for (; alias; alias = strtok_r(NULL, delim, &savedptr)) {
2762780fb4a2SCy Schubert if (tls_add_ca_from_keystore_encoded(
2763780fb4a2SCy Schubert SSL_CTX_get_cert_store(ssl_ctx), alias)) {
2764780fb4a2SCy Schubert wpa_printf(MSG_WARNING,
2765780fb4a2SCy Schubert "OpenSSL: %s - Failed to add ca_cert %s from keystore",
2766780fb4a2SCy Schubert __func__, alias);
2767780fb4a2SCy Schubert rc = -1;
2768780fb4a2SCy Schubert break;
2769f05cddf9SRui Paulo }
2770f05cddf9SRui Paulo }
2771780fb4a2SCy Schubert os_free(aliases);
2772780fb4a2SCy Schubert if (rc)
2773780fb4a2SCy Schubert return rc;
2774780fb4a2SCy Schubert
2775f05cddf9SRui Paulo SSL_set_verify(conn->ssl, SSL_VERIFY_PEER, tls_verify_cb);
2776f05cddf9SRui Paulo return 0;
2777f05cddf9SRui Paulo }
2778f05cddf9SRui Paulo #endif /* ANDROID */
2779f05cddf9SRui Paulo
278039beb93cSSam Leffler #ifdef CONFIG_NATIVE_WINDOWS
278139beb93cSSam Leffler if (ca_cert && tls_cryptoapi_ca_cert(ssl_ctx, conn->ssl, ca_cert) ==
278239beb93cSSam Leffler 0) {
278339beb93cSSam Leffler wpa_printf(MSG_DEBUG, "OpenSSL: Added CA certificates from "
278439beb93cSSam Leffler "system certificate store");
278539beb93cSSam Leffler return 0;
278639beb93cSSam Leffler }
278739beb93cSSam Leffler #endif /* CONFIG_NATIVE_WINDOWS */
278839beb93cSSam Leffler
278939beb93cSSam Leffler if (ca_cert || ca_path) {
279039beb93cSSam Leffler #ifndef OPENSSL_NO_STDIO
279139beb93cSSam Leffler if (SSL_CTX_load_verify_locations(ssl_ctx, ca_cert, ca_path) !=
279239beb93cSSam Leffler 1) {
279339beb93cSSam Leffler tls_show_errors(MSG_WARNING, __func__,
279439beb93cSSam Leffler "Failed to load root certificates");
279539beb93cSSam Leffler if (ca_cert &&
2796325151a3SRui Paulo tls_load_ca_der(data, ca_cert) == 0) {
279739beb93cSSam Leffler wpa_printf(MSG_DEBUG, "OpenSSL: %s - loaded "
279839beb93cSSam Leffler "DER format CA certificate",
279939beb93cSSam Leffler __func__);
280039beb93cSSam Leffler } else
280139beb93cSSam Leffler return -1;
280239beb93cSSam Leffler } else {
280339beb93cSSam Leffler wpa_printf(MSG_DEBUG, "TLS: Trusted root "
280439beb93cSSam Leffler "certificate(s) loaded");
2805325151a3SRui Paulo tls_get_errors(data);
280639beb93cSSam Leffler }
280739beb93cSSam Leffler #else /* OPENSSL_NO_STDIO */
280839beb93cSSam Leffler wpa_printf(MSG_DEBUG, "OpenSSL: %s - OPENSSL_NO_STDIO",
280939beb93cSSam Leffler __func__);
281039beb93cSSam Leffler return -1;
281139beb93cSSam Leffler #endif /* OPENSSL_NO_STDIO */
281239beb93cSSam Leffler } else {
281339beb93cSSam Leffler /* No ca_cert configured - do not try to verify server
281439beb93cSSam Leffler * certificate */
2815e28a4053SRui Paulo conn->ca_cert_verify = 0;
281639beb93cSSam Leffler }
281739beb93cSSam Leffler
281839beb93cSSam Leffler return 0;
281939beb93cSSam Leffler }
282039beb93cSSam Leffler
282139beb93cSSam Leffler
tls_global_ca_cert(struct tls_data * data,const char * ca_cert)2822325151a3SRui Paulo static int tls_global_ca_cert(struct tls_data *data, const char *ca_cert)
282339beb93cSSam Leffler {
2824325151a3SRui Paulo SSL_CTX *ssl_ctx = data->ssl;
2825325151a3SRui Paulo
282639beb93cSSam Leffler if (ca_cert) {
282739beb93cSSam Leffler if (SSL_CTX_load_verify_locations(ssl_ctx, ca_cert, NULL) != 1)
282839beb93cSSam Leffler {
282939beb93cSSam Leffler tls_show_errors(MSG_WARNING, __func__,
283039beb93cSSam Leffler "Failed to load root certificates");
283139beb93cSSam Leffler return -1;
283239beb93cSSam Leffler }
283339beb93cSSam Leffler
283439beb93cSSam Leffler wpa_printf(MSG_DEBUG, "TLS: Trusted root "
283539beb93cSSam Leffler "certificate(s) loaded");
283639beb93cSSam Leffler
283739beb93cSSam Leffler #ifndef OPENSSL_NO_STDIO
283839beb93cSSam Leffler /* Add the same CAs to the client certificate requests */
283939beb93cSSam Leffler SSL_CTX_set_client_CA_list(ssl_ctx,
284039beb93cSSam Leffler SSL_load_client_CA_file(ca_cert));
284139beb93cSSam Leffler #endif /* OPENSSL_NO_STDIO */
28424bc52338SCy Schubert
28434bc52338SCy Schubert os_free(data->ca_cert);
28444bc52338SCy Schubert data->ca_cert = os_strdup(ca_cert);
284539beb93cSSam Leffler }
284639beb93cSSam Leffler
284739beb93cSSam Leffler return 0;
284839beb93cSSam Leffler }
284939beb93cSSam Leffler
285039beb93cSSam Leffler
tls_global_set_verify(void * ssl_ctx,int check_crl,int strict)28514bc52338SCy Schubert int tls_global_set_verify(void *ssl_ctx, int check_crl, int strict)
285239beb93cSSam Leffler {
285339beb93cSSam Leffler int flags;
285439beb93cSSam Leffler
285539beb93cSSam Leffler if (check_crl) {
2856325151a3SRui Paulo struct tls_data *data = ssl_ctx;
2857325151a3SRui Paulo X509_STORE *cs = SSL_CTX_get_cert_store(data->ssl);
285839beb93cSSam Leffler if (cs == NULL) {
285939beb93cSSam Leffler tls_show_errors(MSG_INFO, __func__, "Failed to get "
286039beb93cSSam Leffler "certificate store when enabling "
286139beb93cSSam Leffler "check_crl");
286239beb93cSSam Leffler return -1;
286339beb93cSSam Leffler }
286439beb93cSSam Leffler flags = X509_V_FLAG_CRL_CHECK;
286539beb93cSSam Leffler if (check_crl == 2)
286639beb93cSSam Leffler flags |= X509_V_FLAG_CRL_CHECK_ALL;
286739beb93cSSam Leffler X509_STORE_set_flags(cs, flags);
28684bc52338SCy Schubert
28694bc52338SCy Schubert data->check_crl = check_crl;
28704bc52338SCy Schubert data->check_crl_strict = strict;
28714bc52338SCy Schubert os_get_reltime(&data->crl_last_reload);
287239beb93cSSam Leffler }
287339beb93cSSam Leffler return 0;
287439beb93cSSam Leffler }
287539beb93cSSam Leffler
287639beb93cSSam Leffler
tls_connection_set_subject_match(struct tls_connection * conn,const char * subject_match,const char * altsubject_match,const char * suffix_match,const char * domain_match,const char * check_cert_subject)287739beb93cSSam Leffler static int tls_connection_set_subject_match(struct tls_connection *conn,
287839beb93cSSam Leffler const char *subject_match,
28795b9c547cSRui Paulo const char *altsubject_match,
28805b9c547cSRui Paulo const char *suffix_match,
28814bc52338SCy Schubert const char *domain_match,
28824bc52338SCy Schubert const char *check_cert_subject)
288339beb93cSSam Leffler {
288439beb93cSSam Leffler os_free(conn->subject_match);
288539beb93cSSam Leffler conn->subject_match = NULL;
288639beb93cSSam Leffler if (subject_match) {
288739beb93cSSam Leffler conn->subject_match = os_strdup(subject_match);
288839beb93cSSam Leffler if (conn->subject_match == NULL)
288939beb93cSSam Leffler return -1;
289039beb93cSSam Leffler }
289139beb93cSSam Leffler
289239beb93cSSam Leffler os_free(conn->altsubject_match);
289339beb93cSSam Leffler conn->altsubject_match = NULL;
289439beb93cSSam Leffler if (altsubject_match) {
289539beb93cSSam Leffler conn->altsubject_match = os_strdup(altsubject_match);
289639beb93cSSam Leffler if (conn->altsubject_match == NULL)
289739beb93cSSam Leffler return -1;
289839beb93cSSam Leffler }
289939beb93cSSam Leffler
29005b9c547cSRui Paulo os_free(conn->suffix_match);
29015b9c547cSRui Paulo conn->suffix_match = NULL;
29025b9c547cSRui Paulo if (suffix_match) {
29035b9c547cSRui Paulo conn->suffix_match = os_strdup(suffix_match);
29045b9c547cSRui Paulo if (conn->suffix_match == NULL)
29055b9c547cSRui Paulo return -1;
29065b9c547cSRui Paulo }
29075b9c547cSRui Paulo
29085b9c547cSRui Paulo os_free(conn->domain_match);
29095b9c547cSRui Paulo conn->domain_match = NULL;
29105b9c547cSRui Paulo if (domain_match) {
29115b9c547cSRui Paulo conn->domain_match = os_strdup(domain_match);
29125b9c547cSRui Paulo if (conn->domain_match == NULL)
29135b9c547cSRui Paulo return -1;
29145b9c547cSRui Paulo }
29155b9c547cSRui Paulo
29164bc52338SCy Schubert os_free(conn->check_cert_subject);
29174bc52338SCy Schubert conn->check_cert_subject = NULL;
29184bc52338SCy Schubert if (check_cert_subject) {
29194bc52338SCy Schubert conn->check_cert_subject = os_strdup(check_cert_subject);
29204bc52338SCy Schubert if (!conn->check_cert_subject)
29214bc52338SCy Schubert return -1;
29224bc52338SCy Schubert }
29234bc52338SCy Schubert
292439beb93cSSam Leffler return 0;
292539beb93cSSam Leffler }
292639beb93cSSam Leffler
292739beb93cSSam Leffler
292885732ac8SCy Schubert #ifdef CONFIG_SUITEB
292985732ac8SCy Schubert #if OPENSSL_VERSION_NUMBER >= 0x10002000L
suiteb_cert_cb(SSL * ssl,void * arg)293085732ac8SCy Schubert static int suiteb_cert_cb(SSL *ssl, void *arg)
2931325151a3SRui Paulo {
293285732ac8SCy Schubert struct tls_connection *conn = arg;
293385732ac8SCy Schubert
293485732ac8SCy Schubert /*
293585732ac8SCy Schubert * This cert_cb() is not really the best location for doing a
293685732ac8SCy Schubert * constraint check for the ServerKeyExchange message, but this seems to
293785732ac8SCy Schubert * be the only place where the current OpenSSL sequence can be
293885732ac8SCy Schubert * terminated cleanly with an TLS alert going out to the server.
293985732ac8SCy Schubert */
294085732ac8SCy Schubert
294185732ac8SCy Schubert if (!(conn->flags & TLS_CONN_SUITEB))
294285732ac8SCy Schubert return 1;
294385732ac8SCy Schubert
294485732ac8SCy Schubert /* DHE is enabled only with DHE-RSA-AES256-GCM-SHA384 */
294585732ac8SCy Schubert if (conn->cipher_suite != 0x9f)
294685732ac8SCy Schubert return 1;
294785732ac8SCy Schubert
294885732ac8SCy Schubert if (conn->server_dh_prime_len >= 3072)
294985732ac8SCy Schubert return 1;
295085732ac8SCy Schubert
295185732ac8SCy Schubert wpa_printf(MSG_DEBUG,
295285732ac8SCy Schubert "OpenSSL: Server DH prime length (%d bits) not sufficient for Suite B RSA - reject handshake",
295385732ac8SCy Schubert conn->server_dh_prime_len);
295485732ac8SCy Schubert return 0;
295585732ac8SCy Schubert }
295685732ac8SCy Schubert #endif /* OPENSSL_VERSION_NUMBER */
295785732ac8SCy Schubert #endif /* CONFIG_SUITEB */
295885732ac8SCy Schubert
295985732ac8SCy Schubert
tls_set_conn_flags(struct tls_connection * conn,unsigned int flags,const char * openssl_ciphers)296085732ac8SCy Schubert static int tls_set_conn_flags(struct tls_connection *conn, unsigned int flags,
296185732ac8SCy Schubert const char *openssl_ciphers)
296285732ac8SCy Schubert {
296385732ac8SCy Schubert SSL *ssl = conn->ssl;
296485732ac8SCy Schubert
2965325151a3SRui Paulo #ifdef SSL_OP_NO_TICKET
2966325151a3SRui Paulo if (flags & TLS_CONN_DISABLE_SESSION_TICKET)
2967325151a3SRui Paulo SSL_set_options(ssl, SSL_OP_NO_TICKET);
2968325151a3SRui Paulo else
2969325151a3SRui Paulo SSL_clear_options(ssl, SSL_OP_NO_TICKET);
2970325151a3SRui Paulo #endif /* SSL_OP_NO_TICKET */
2971325151a3SRui Paulo
2972325151a3SRui Paulo #ifdef SSL_OP_NO_TLSv1
2973325151a3SRui Paulo if (flags & TLS_CONN_DISABLE_TLSv1_0)
2974325151a3SRui Paulo SSL_set_options(ssl, SSL_OP_NO_TLSv1);
2975325151a3SRui Paulo else
2976325151a3SRui Paulo SSL_clear_options(ssl, SSL_OP_NO_TLSv1);
2977325151a3SRui Paulo #endif /* SSL_OP_NO_TLSv1 */
2978325151a3SRui Paulo #ifdef SSL_OP_NO_TLSv1_1
2979325151a3SRui Paulo if (flags & TLS_CONN_DISABLE_TLSv1_1)
2980325151a3SRui Paulo SSL_set_options(ssl, SSL_OP_NO_TLSv1_1);
2981325151a3SRui Paulo else
2982325151a3SRui Paulo SSL_clear_options(ssl, SSL_OP_NO_TLSv1_1);
2983325151a3SRui Paulo #endif /* SSL_OP_NO_TLSv1_1 */
2984325151a3SRui Paulo #ifdef SSL_OP_NO_TLSv1_2
2985325151a3SRui Paulo if (flags & TLS_CONN_DISABLE_TLSv1_2)
2986325151a3SRui Paulo SSL_set_options(ssl, SSL_OP_NO_TLSv1_2);
2987325151a3SRui Paulo else
2988325151a3SRui Paulo SSL_clear_options(ssl, SSL_OP_NO_TLSv1_2);
2989325151a3SRui Paulo #endif /* SSL_OP_NO_TLSv1_2 */
299085732ac8SCy Schubert #ifdef SSL_OP_NO_TLSv1_3
299185732ac8SCy Schubert if (flags & TLS_CONN_DISABLE_TLSv1_3)
299285732ac8SCy Schubert SSL_set_options(ssl, SSL_OP_NO_TLSv1_3);
299385732ac8SCy Schubert else
299485732ac8SCy Schubert SSL_clear_options(ssl, SSL_OP_NO_TLSv1_3);
299585732ac8SCy Schubert #endif /* SSL_OP_NO_TLSv1_3 */
29964bc52338SCy Schubert #if OPENSSL_VERSION_NUMBER >= 0x10100000L
29974bc52338SCy Schubert if (flags & (TLS_CONN_ENABLE_TLSv1_0 |
29984bc52338SCy Schubert TLS_CONN_ENABLE_TLSv1_1 |
29994bc52338SCy Schubert TLS_CONN_ENABLE_TLSv1_2)) {
30004bc52338SCy Schubert int version = 0;
30014bc52338SCy Schubert
30024bc52338SCy Schubert /* Explicit request to enable TLS versions even if needing to
30034bc52338SCy Schubert * override systemwide policies. */
3004c1d255d3SCy Schubert if (flags & TLS_CONN_ENABLE_TLSv1_0)
30054bc52338SCy Schubert version = TLS1_VERSION;
3006c1d255d3SCy Schubert else if (flags & TLS_CONN_ENABLE_TLSv1_1)
30074bc52338SCy Schubert version = TLS1_1_VERSION;
3008c1d255d3SCy Schubert else if (flags & TLS_CONN_ENABLE_TLSv1_2)
30094bc52338SCy Schubert version = TLS1_2_VERSION;
30104bc52338SCy Schubert if (!version) {
30114bc52338SCy Schubert wpa_printf(MSG_DEBUG,
30124bc52338SCy Schubert "OpenSSL: Invalid TLS version configuration");
30134bc52338SCy Schubert return -1;
30144bc52338SCy Schubert }
30154bc52338SCy Schubert
30164bc52338SCy Schubert if (SSL_set_min_proto_version(ssl, version) != 1) {
30174bc52338SCy Schubert wpa_printf(MSG_DEBUG,
30184bc52338SCy Schubert "OpenSSL: Failed to set minimum TLS version");
30194bc52338SCy Schubert return -1;
30204bc52338SCy Schubert }
30214bc52338SCy Schubert }
30224bc52338SCy Schubert #endif /* >= 1.1.0 */
3023c1d255d3SCy Schubert #if OPENSSL_VERSION_NUMBER >= 0x10100000L && \
3024c1d255d3SCy Schubert !defined(LIBRESSL_VERSION_NUMBER) && \
3025c1d255d3SCy Schubert !defined(OPENSSL_IS_BORINGSSL)
3026ec080394SCy Schubert {
3027ec080394SCy Schubert #if OPENSSL_VERSION_NUMBER >= 0x30000000L
3028ec080394SCy Schubert int need_level = 0;
3029ec080394SCy Schubert #else
3030ec080394SCy Schubert int need_level = 1;
3031ec080394SCy Schubert #endif
3032ec080394SCy Schubert
3033ec080394SCy Schubert if ((flags &
3034ec080394SCy Schubert (TLS_CONN_ENABLE_TLSv1_0 | TLS_CONN_ENABLE_TLSv1_1)) &&
3035ec080394SCy Schubert SSL_get_security_level(ssl) > need_level) {
3036c1d255d3SCy Schubert /*
3037ec080394SCy Schubert * Need to drop to security level 1 (or 0 with OpenSSL
3038ec080394SCy Schubert * 3.0) to allow TLS versions older than 1.2 to be used
3039ec080394SCy Schubert * when explicitly enabled in configuration.
3040c1d255d3SCy Schubert */
3041ec080394SCy Schubert SSL_set_security_level(conn->ssl, need_level);
3042ec080394SCy Schubert }
3043c1d255d3SCy Schubert }
3044c1d255d3SCy Schubert #endif
30454bc52338SCy Schubert
304685732ac8SCy Schubert #ifdef CONFIG_SUITEB
304785732ac8SCy Schubert #ifdef OPENSSL_IS_BORINGSSL
304885732ac8SCy Schubert /* Start with defaults from BoringSSL */
304985732ac8SCy Schubert SSL_CTX_set_verify_algorithm_prefs(conn->ssl_ctx, NULL, 0);
305085732ac8SCy Schubert #endif /* OPENSSL_IS_BORINGSSL */
305185732ac8SCy Schubert #if OPENSSL_VERSION_NUMBER >= 0x10002000L
305285732ac8SCy Schubert if (flags & TLS_CONN_SUITEB_NO_ECDH) {
305385732ac8SCy Schubert const char *ciphers = "DHE-RSA-AES256-GCM-SHA384";
305485732ac8SCy Schubert
305585732ac8SCy Schubert if (openssl_ciphers) {
305685732ac8SCy Schubert wpa_printf(MSG_DEBUG,
305785732ac8SCy Schubert "OpenSSL: Override ciphers for Suite B (no ECDH): %s",
305885732ac8SCy Schubert openssl_ciphers);
305985732ac8SCy Schubert ciphers = openssl_ciphers;
306085732ac8SCy Schubert }
306185732ac8SCy Schubert if (SSL_set_cipher_list(ssl, ciphers) != 1) {
306285732ac8SCy Schubert wpa_printf(MSG_INFO,
306385732ac8SCy Schubert "OpenSSL: Failed to set Suite B ciphers");
306485732ac8SCy Schubert return -1;
306585732ac8SCy Schubert }
306685732ac8SCy Schubert } else if (flags & TLS_CONN_SUITEB) {
306785732ac8SCy Schubert EC_KEY *ecdh;
306885732ac8SCy Schubert const char *ciphers =
306985732ac8SCy Schubert "ECDHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES256-GCM-SHA384";
307085732ac8SCy Schubert int nid[1] = { NID_secp384r1 };
307185732ac8SCy Schubert
307285732ac8SCy Schubert if (openssl_ciphers) {
307385732ac8SCy Schubert wpa_printf(MSG_DEBUG,
307485732ac8SCy Schubert "OpenSSL: Override ciphers for Suite B: %s",
307585732ac8SCy Schubert openssl_ciphers);
307685732ac8SCy Schubert ciphers = openssl_ciphers;
307785732ac8SCy Schubert }
307885732ac8SCy Schubert if (SSL_set_cipher_list(ssl, ciphers) != 1) {
307985732ac8SCy Schubert wpa_printf(MSG_INFO,
308085732ac8SCy Schubert "OpenSSL: Failed to set Suite B ciphers");
308185732ac8SCy Schubert return -1;
308285732ac8SCy Schubert }
308385732ac8SCy Schubert
308485732ac8SCy Schubert if (SSL_set1_curves(ssl, nid, 1) != 1) {
308585732ac8SCy Schubert wpa_printf(MSG_INFO,
308685732ac8SCy Schubert "OpenSSL: Failed to set Suite B curves");
308785732ac8SCy Schubert return -1;
308885732ac8SCy Schubert }
308985732ac8SCy Schubert
309085732ac8SCy Schubert ecdh = EC_KEY_new_by_curve_name(NID_secp384r1);
309185732ac8SCy Schubert if (!ecdh || SSL_set_tmp_ecdh(ssl, ecdh) != 1) {
309285732ac8SCy Schubert EC_KEY_free(ecdh);
309385732ac8SCy Schubert wpa_printf(MSG_INFO,
309485732ac8SCy Schubert "OpenSSL: Failed to set ECDH parameter");
309585732ac8SCy Schubert return -1;
309685732ac8SCy Schubert }
309785732ac8SCy Schubert EC_KEY_free(ecdh);
309885732ac8SCy Schubert }
309985732ac8SCy Schubert if (flags & (TLS_CONN_SUITEB | TLS_CONN_SUITEB_NO_ECDH)) {
310085732ac8SCy Schubert #ifdef OPENSSL_IS_BORINGSSL
310185732ac8SCy Schubert uint16_t sigalgs[1] = { SSL_SIGN_RSA_PKCS1_SHA384 };
310285732ac8SCy Schubert
310385732ac8SCy Schubert if (SSL_CTX_set_verify_algorithm_prefs(conn->ssl_ctx, sigalgs,
310485732ac8SCy Schubert 1) != 1) {
310585732ac8SCy Schubert wpa_printf(MSG_INFO,
310685732ac8SCy Schubert "OpenSSL: Failed to set Suite B sigalgs");
310785732ac8SCy Schubert return -1;
310885732ac8SCy Schubert }
310985732ac8SCy Schubert #else /* OPENSSL_IS_BORINGSSL */
311085732ac8SCy Schubert /* ECDSA+SHA384 if need to add EC support here */
311185732ac8SCy Schubert if (SSL_set1_sigalgs_list(ssl, "RSA+SHA384") != 1) {
311285732ac8SCy Schubert wpa_printf(MSG_INFO,
311385732ac8SCy Schubert "OpenSSL: Failed to set Suite B sigalgs");
311485732ac8SCy Schubert return -1;
311585732ac8SCy Schubert }
311685732ac8SCy Schubert #endif /* OPENSSL_IS_BORINGSSL */
311785732ac8SCy Schubert
311885732ac8SCy Schubert SSL_set_options(ssl, SSL_OP_NO_TLSv1);
311985732ac8SCy Schubert SSL_set_options(ssl, SSL_OP_NO_TLSv1_1);
312085732ac8SCy Schubert SSL_set_cert_cb(ssl, suiteb_cert_cb, conn);
312185732ac8SCy Schubert }
312285732ac8SCy Schubert #else /* OPENSSL_VERSION_NUMBER < 0x10002000L */
312385732ac8SCy Schubert if (flags & (TLS_CONN_SUITEB | TLS_CONN_SUITEB_NO_ECDH)) {
312485732ac8SCy Schubert wpa_printf(MSG_ERROR,
312585732ac8SCy Schubert "OpenSSL: Suite B RSA case not supported with this OpenSSL version");
312685732ac8SCy Schubert return -1;
312785732ac8SCy Schubert }
312885732ac8SCy Schubert #endif /* OPENSSL_VERSION_NUMBER */
312985732ac8SCy Schubert
313085732ac8SCy Schubert #ifdef OPENSSL_IS_BORINGSSL
313185732ac8SCy Schubert if (openssl_ciphers && os_strcmp(openssl_ciphers, "SUITEB192") == 0) {
313285732ac8SCy Schubert uint16_t sigalgs[1] = { SSL_SIGN_ECDSA_SECP384R1_SHA384 };
313385732ac8SCy Schubert int nid[1] = { NID_secp384r1 };
313485732ac8SCy Schubert
313585732ac8SCy Schubert if (SSL_set1_curves(ssl, nid, 1) != 1) {
313685732ac8SCy Schubert wpa_printf(MSG_INFO,
313785732ac8SCy Schubert "OpenSSL: Failed to set Suite B curves");
313885732ac8SCy Schubert return -1;
313985732ac8SCy Schubert }
314085732ac8SCy Schubert
314185732ac8SCy Schubert if (SSL_CTX_set_verify_algorithm_prefs(conn->ssl_ctx, sigalgs,
314285732ac8SCy Schubert 1) != 1) {
314385732ac8SCy Schubert wpa_printf(MSG_INFO,
314485732ac8SCy Schubert "OpenSSL: Failed to set Suite B sigalgs");
314585732ac8SCy Schubert return -1;
314685732ac8SCy Schubert }
314785732ac8SCy Schubert }
31484bc52338SCy Schubert #else /* OPENSSL_IS_BORINGSSL */
31494bc52338SCy Schubert if (!(flags & (TLS_CONN_SUITEB | TLS_CONN_SUITEB_NO_ECDH)) &&
31504bc52338SCy Schubert openssl_ciphers && SSL_set_cipher_list(ssl, openssl_ciphers) != 1) {
31514bc52338SCy Schubert wpa_printf(MSG_INFO,
31524bc52338SCy Schubert "OpenSSL: Failed to set openssl_ciphers '%s'",
31534bc52338SCy Schubert openssl_ciphers);
31544bc52338SCy Schubert return -1;
31554bc52338SCy Schubert }
315685732ac8SCy Schubert #endif /* OPENSSL_IS_BORINGSSL */
31574bc52338SCy Schubert #else /* CONFIG_SUITEB */
31584bc52338SCy Schubert if (openssl_ciphers && SSL_set_cipher_list(ssl, openssl_ciphers) != 1) {
31594bc52338SCy Schubert wpa_printf(MSG_INFO,
31604bc52338SCy Schubert "OpenSSL: Failed to set openssl_ciphers '%s'",
31614bc52338SCy Schubert openssl_ciphers);
31624bc52338SCy Schubert return -1;
31634bc52338SCy Schubert }
316485732ac8SCy Schubert #endif /* CONFIG_SUITEB */
316585732ac8SCy Schubert
3166206b73d0SCy Schubert if (flags & TLS_CONN_TEAP_ANON_DH) {
3167206b73d0SCy Schubert #ifndef TEAP_DH_ANON_CS
3168206b73d0SCy Schubert #define TEAP_DH_ANON_CS \
3169206b73d0SCy Schubert "ECDHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES128-GCM-SHA256:" \
3170206b73d0SCy Schubert "ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES128-SHA256:" \
3171206b73d0SCy Schubert "ECDHE-RSA-AES256-SHA:ECDHE-RSA-AES128-SHA:" \
3172206b73d0SCy Schubert "DHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:" \
3173206b73d0SCy Schubert "DHE-RSA-AES256-SHA256:DHE-RSA-AES128-SHA256:" \
3174206b73d0SCy Schubert "DHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA:" \
3175206b73d0SCy Schubert "ADH-AES256-GCM-SHA384:ADH-AES128-GCM-SHA256:" \
3176206b73d0SCy Schubert "ADH-AES256-SHA256:ADH-AES128-SHA256:ADH-AES256-SHA:ADH-AES128-SHA"
3177206b73d0SCy Schubert #endif
3178206b73d0SCy Schubert static const char *cs = TEAP_DH_ANON_CS;
3179206b73d0SCy Schubert
3180206b73d0SCy Schubert #if OPENSSL_VERSION_NUMBER >= 0x10100000L && \
3181206b73d0SCy Schubert !defined(LIBRESSL_VERSION_NUMBER) && \
3182206b73d0SCy Schubert !defined(OPENSSL_IS_BORINGSSL)
3183206b73d0SCy Schubert /*
3184206b73d0SCy Schubert * Need to drop to security level 0 to allow anonymous
3185206b73d0SCy Schubert * cipher suites for EAP-TEAP.
3186206b73d0SCy Schubert */
3187206b73d0SCy Schubert SSL_set_security_level(conn->ssl, 0);
3188206b73d0SCy Schubert #endif
3189206b73d0SCy Schubert
3190206b73d0SCy Schubert wpa_printf(MSG_DEBUG,
3191206b73d0SCy Schubert "OpenSSL: Enable cipher suites for anonymous EAP-TEAP provisioning: %s",
3192206b73d0SCy Schubert cs);
3193206b73d0SCy Schubert if (SSL_set_cipher_list(conn->ssl, cs) != 1) {
3194206b73d0SCy Schubert tls_show_errors(MSG_INFO, __func__,
3195206b73d0SCy Schubert "Cipher suite configuration failed");
3196206b73d0SCy Schubert return -1;
3197206b73d0SCy Schubert }
3198206b73d0SCy Schubert }
3199206b73d0SCy Schubert
320085732ac8SCy Schubert return 0;
3201325151a3SRui Paulo }
3202325151a3SRui Paulo
3203325151a3SRui Paulo
tls_connection_set_verify(void * ssl_ctx,struct tls_connection * conn,int verify_peer,unsigned int flags,const u8 * session_ctx,size_t session_ctx_len)320439beb93cSSam Leffler int tls_connection_set_verify(void *ssl_ctx, struct tls_connection *conn,
3205325151a3SRui Paulo int verify_peer, unsigned int flags,
3206325151a3SRui Paulo const u8 *session_ctx, size_t session_ctx_len)
320739beb93cSSam Leffler {
320839beb93cSSam Leffler static int counter = 0;
3209325151a3SRui Paulo struct tls_data *data = ssl_ctx;
321039beb93cSSam Leffler
321139beb93cSSam Leffler if (conn == NULL)
321239beb93cSSam Leffler return -1;
321339beb93cSSam Leffler
3214c1d255d3SCy Schubert if (verify_peer == 2) {
3215c1d255d3SCy Schubert conn->ca_cert_verify = 1;
3216c1d255d3SCy Schubert SSL_set_verify(conn->ssl, SSL_VERIFY_PEER |
3217c1d255d3SCy Schubert SSL_VERIFY_CLIENT_ONCE, tls_verify_cb);
3218c1d255d3SCy Schubert } else if (verify_peer) {
3219e28a4053SRui Paulo conn->ca_cert_verify = 1;
322039beb93cSSam Leffler SSL_set_verify(conn->ssl, SSL_VERIFY_PEER |
322139beb93cSSam Leffler SSL_VERIFY_FAIL_IF_NO_PEER_CERT |
322239beb93cSSam Leffler SSL_VERIFY_CLIENT_ONCE, tls_verify_cb);
322339beb93cSSam Leffler } else {
3224e28a4053SRui Paulo conn->ca_cert_verify = 0;
322539beb93cSSam Leffler SSL_set_verify(conn->ssl, SSL_VERIFY_NONE, NULL);
322639beb93cSSam Leffler }
322739beb93cSSam Leffler
322885732ac8SCy Schubert if (tls_set_conn_flags(conn, flags, NULL) < 0)
322985732ac8SCy Schubert return -1;
3230325151a3SRui Paulo conn->flags = flags;
3231325151a3SRui Paulo
323239beb93cSSam Leffler SSL_set_accept_state(conn->ssl);
323339beb93cSSam Leffler
3234325151a3SRui Paulo if (data->tls_session_lifetime == 0) {
323539beb93cSSam Leffler /*
3236325151a3SRui Paulo * Set session id context to a unique value to make sure
3237325151a3SRui Paulo * session resumption cannot be used either through session
3238325151a3SRui Paulo * caching or TLS ticket extension.
323939beb93cSSam Leffler */
324039beb93cSSam Leffler counter++;
324139beb93cSSam Leffler SSL_set_session_id_context(conn->ssl,
324239beb93cSSam Leffler (const unsigned char *) &counter,
324339beb93cSSam Leffler sizeof(counter));
3244325151a3SRui Paulo } else if (session_ctx) {
3245325151a3SRui Paulo SSL_set_session_id_context(conn->ssl, session_ctx,
3246325151a3SRui Paulo session_ctx_len);
3247325151a3SRui Paulo }
324839beb93cSSam Leffler
324939beb93cSSam Leffler return 0;
325039beb93cSSam Leffler }
325139beb93cSSam Leffler
325239beb93cSSam Leffler
tls_connection_client_cert(struct tls_connection * conn,const char * client_cert,const u8 * client_cert_blob,size_t client_cert_blob_len)325339beb93cSSam Leffler static int tls_connection_client_cert(struct tls_connection *conn,
325439beb93cSSam Leffler const char *client_cert,
325539beb93cSSam Leffler const u8 *client_cert_blob,
325639beb93cSSam Leffler size_t client_cert_blob_len)
325739beb93cSSam Leffler {
325839beb93cSSam Leffler if (client_cert == NULL && client_cert_blob == NULL)
325939beb93cSSam Leffler return 0;
326039beb93cSSam Leffler
3261780fb4a2SCy Schubert #ifdef PKCS12_FUNCS
326285732ac8SCy Schubert #if OPENSSL_VERSION_NUMBER < 0x10002000L || defined(LIBRESSL_VERSION_NUMBER)
3263780fb4a2SCy Schubert /*
3264780fb4a2SCy Schubert * Clear previously set extra chain certificates, if any, from PKCS#12
3265780fb4a2SCy Schubert * processing in tls_parse_pkcs12() to allow OpenSSL to build a new
3266780fb4a2SCy Schubert * chain properly.
3267780fb4a2SCy Schubert */
3268780fb4a2SCy Schubert SSL_CTX_clear_extra_chain_certs(conn->ssl_ctx);
3269780fb4a2SCy Schubert #endif /* OPENSSL_VERSION_NUMBER < 0x10002000L */
3270780fb4a2SCy Schubert #endif /* PKCS12_FUNCS */
3271780fb4a2SCy Schubert
327239beb93cSSam Leffler if (client_cert_blob &&
327339beb93cSSam Leffler SSL_use_certificate_ASN1(conn->ssl, (u8 *) client_cert_blob,
327439beb93cSSam Leffler client_cert_blob_len) == 1) {
327539beb93cSSam Leffler wpa_printf(MSG_DEBUG, "OpenSSL: SSL_use_certificate_ASN1 --> "
327639beb93cSSam Leffler "OK");
327739beb93cSSam Leffler return 0;
327839beb93cSSam Leffler } else if (client_cert_blob) {
3279c1d255d3SCy Schubert #if defined(LIBRESSL_VERSION_NUMBER) && LIBRESSL_VERSION_NUMBER < 0x20901000L
328039beb93cSSam Leffler tls_show_errors(MSG_DEBUG, __func__,
328139beb93cSSam Leffler "SSL_use_certificate_ASN1 failed");
3282c1d255d3SCy Schubert #else
3283c1d255d3SCy Schubert BIO *bio;
3284c1d255d3SCy Schubert X509 *x509;
3285c1d255d3SCy Schubert
3286c1d255d3SCy Schubert tls_show_errors(MSG_DEBUG, __func__,
3287c1d255d3SCy Schubert "SSL_use_certificate_ASN1 failed");
3288c1d255d3SCy Schubert bio = BIO_new(BIO_s_mem());
3289c1d255d3SCy Schubert if (!bio)
3290c1d255d3SCy Schubert return -1;
3291c1d255d3SCy Schubert BIO_write(bio, client_cert_blob, client_cert_blob_len);
3292c1d255d3SCy Schubert x509 = PEM_read_bio_X509(bio, NULL, NULL, NULL);
3293c1d255d3SCy Schubert if (!x509 || SSL_use_certificate(conn->ssl, x509) != 1) {
3294c1d255d3SCy Schubert X509_free(x509);
3295c1d255d3SCy Schubert BIO_free(bio);
3296c1d255d3SCy Schubert return -1;
3297c1d255d3SCy Schubert }
3298c1d255d3SCy Schubert X509_free(x509);
3299c1d255d3SCy Schubert wpa_printf(MSG_DEBUG,
3300c1d255d3SCy Schubert "OpenSSL: Found PEM encoded certificate from blob");
3301c1d255d3SCy Schubert while ((x509 = PEM_read_bio_X509(bio, NULL, NULL, NULL))) {
3302c1d255d3SCy Schubert wpa_printf(MSG_DEBUG,
3303c1d255d3SCy Schubert "OpenSSL: Added an additional certificate into the chain");
3304c1d255d3SCy Schubert SSL_add0_chain_cert(conn->ssl, x509);
3305c1d255d3SCy Schubert }
3306c1d255d3SCy Schubert BIO_free(bio);
3307c1d255d3SCy Schubert return 0;
3308c1d255d3SCy Schubert #endif
330939beb93cSSam Leffler }
331039beb93cSSam Leffler
331139beb93cSSam Leffler if (client_cert == NULL)
331239beb93cSSam Leffler return -1;
331339beb93cSSam Leffler
3314f05cddf9SRui Paulo #ifdef ANDROID
3315f05cddf9SRui Paulo if (os_strncmp("keystore://", client_cert, 11) == 0) {
3316f05cddf9SRui Paulo BIO *bio = BIO_from_keystore(&client_cert[11]);
3317f05cddf9SRui Paulo X509 *x509 = NULL;
3318f05cddf9SRui Paulo int ret = -1;
3319f05cddf9SRui Paulo if (bio) {
3320f05cddf9SRui Paulo x509 = PEM_read_bio_X509(bio, NULL, NULL, NULL);
3321f05cddf9SRui Paulo }
3322f05cddf9SRui Paulo if (x509) {
3323f05cddf9SRui Paulo if (SSL_use_certificate(conn->ssl, x509) == 1)
3324f05cddf9SRui Paulo ret = 0;
3325f05cddf9SRui Paulo X509_free(x509);
3326f05cddf9SRui Paulo }
332785732ac8SCy Schubert
332885732ac8SCy Schubert /* Read additional certificates into the chain. */
332985732ac8SCy Schubert while (bio) {
333085732ac8SCy Schubert x509 = PEM_read_bio_X509(bio, NULL, NULL, NULL);
333185732ac8SCy Schubert if (x509) {
333285732ac8SCy Schubert /* Takes ownership of x509 */
333385732ac8SCy Schubert SSL_add0_chain_cert(conn->ssl, x509);
333485732ac8SCy Schubert } else {
333585732ac8SCy Schubert BIO_free(bio);
333685732ac8SCy Schubert bio = NULL;
333785732ac8SCy Schubert }
333885732ac8SCy Schubert }
3339f05cddf9SRui Paulo return ret;
3340f05cddf9SRui Paulo }
3341f05cddf9SRui Paulo #endif /* ANDROID */
3342f05cddf9SRui Paulo
334339beb93cSSam Leffler #ifndef OPENSSL_NO_STDIO
334439beb93cSSam Leffler if (SSL_use_certificate_file(conn->ssl, client_cert,
334539beb93cSSam Leffler SSL_FILETYPE_ASN1) == 1) {
334639beb93cSSam Leffler wpa_printf(MSG_DEBUG, "OpenSSL: SSL_use_certificate_file (DER)"
334739beb93cSSam Leffler " --> OK");
334839beb93cSSam Leffler return 0;
334939beb93cSSam Leffler }
335039beb93cSSam Leffler
33514bc52338SCy Schubert #if OPENSSL_VERSION_NUMBER >= 0x10100000L && \
33524bc52338SCy Schubert !defined(LIBRESSL_VERSION_NUMBER) && !defined(OPENSSL_IS_BORINGSSL)
33534bc52338SCy Schubert if (SSL_use_certificate_chain_file(conn->ssl, client_cert) == 1) {
33544bc52338SCy Schubert ERR_clear_error();
33554bc52338SCy Schubert wpa_printf(MSG_DEBUG, "OpenSSL: SSL_use_certificate_chain_file"
33564bc52338SCy Schubert " --> OK");
33574bc52338SCy Schubert return 0;
33584bc52338SCy Schubert }
33594bc52338SCy Schubert #else
336039beb93cSSam Leffler if (SSL_use_certificate_file(conn->ssl, client_cert,
336139beb93cSSam Leffler SSL_FILETYPE_PEM) == 1) {
3362f05cddf9SRui Paulo ERR_clear_error();
336339beb93cSSam Leffler wpa_printf(MSG_DEBUG, "OpenSSL: SSL_use_certificate_file (PEM)"
336439beb93cSSam Leffler " --> OK");
336539beb93cSSam Leffler return 0;
336639beb93cSSam Leffler }
33674bc52338SCy Schubert #endif
3368f05cddf9SRui Paulo
3369f05cddf9SRui Paulo tls_show_errors(MSG_DEBUG, __func__,
3370f05cddf9SRui Paulo "SSL_use_certificate_file failed");
337139beb93cSSam Leffler #else /* OPENSSL_NO_STDIO */
337239beb93cSSam Leffler wpa_printf(MSG_DEBUG, "OpenSSL: %s - OPENSSL_NO_STDIO", __func__);
337339beb93cSSam Leffler #endif /* OPENSSL_NO_STDIO */
337439beb93cSSam Leffler
337539beb93cSSam Leffler return -1;
337639beb93cSSam Leffler }
337739beb93cSSam Leffler
337839beb93cSSam Leffler
tls_global_client_cert(struct tls_data * data,const char * client_cert)3379325151a3SRui Paulo static int tls_global_client_cert(struct tls_data *data,
3380325151a3SRui Paulo const char *client_cert)
338139beb93cSSam Leffler {
338239beb93cSSam Leffler #ifndef OPENSSL_NO_STDIO
3383325151a3SRui Paulo SSL_CTX *ssl_ctx = data->ssl;
3384325151a3SRui Paulo
338539beb93cSSam Leffler if (client_cert == NULL)
338639beb93cSSam Leffler return 0;
338739beb93cSSam Leffler
338839beb93cSSam Leffler if (SSL_CTX_use_certificate_file(ssl_ctx, client_cert,
338939beb93cSSam Leffler SSL_FILETYPE_ASN1) != 1 &&
3390f05cddf9SRui Paulo SSL_CTX_use_certificate_chain_file(ssl_ctx, client_cert) != 1 &&
339139beb93cSSam Leffler SSL_CTX_use_certificate_file(ssl_ctx, client_cert,
339239beb93cSSam Leffler SSL_FILETYPE_PEM) != 1) {
339339beb93cSSam Leffler tls_show_errors(MSG_INFO, __func__,
339439beb93cSSam Leffler "Failed to load client certificate");
339539beb93cSSam Leffler return -1;
339639beb93cSSam Leffler }
339739beb93cSSam Leffler return 0;
339839beb93cSSam Leffler #else /* OPENSSL_NO_STDIO */
339939beb93cSSam Leffler if (client_cert == NULL)
340039beb93cSSam Leffler return 0;
340139beb93cSSam Leffler wpa_printf(MSG_DEBUG, "OpenSSL: %s - OPENSSL_NO_STDIO", __func__);
340239beb93cSSam Leffler return -1;
340339beb93cSSam Leffler #endif /* OPENSSL_NO_STDIO */
340439beb93cSSam Leffler }
340539beb93cSSam Leffler
340639beb93cSSam Leffler
340739beb93cSSam Leffler #ifdef PKCS12_FUNCS
tls_parse_pkcs12(struct tls_data * data,SSL * ssl,PKCS12 * p12,const char * passwd)3408325151a3SRui Paulo static int tls_parse_pkcs12(struct tls_data *data, SSL *ssl, PKCS12 *p12,
340939beb93cSSam Leffler const char *passwd)
341039beb93cSSam Leffler {
341139beb93cSSam Leffler EVP_PKEY *pkey;
341239beb93cSSam Leffler X509 *cert;
341339beb93cSSam Leffler STACK_OF(X509) *certs;
341439beb93cSSam Leffler int res = 0;
341539beb93cSSam Leffler char buf[256];
341639beb93cSSam Leffler
341739beb93cSSam Leffler pkey = NULL;
341839beb93cSSam Leffler cert = NULL;
341939beb93cSSam Leffler certs = NULL;
3420325151a3SRui Paulo if (!passwd)
3421325151a3SRui Paulo passwd = "";
342239beb93cSSam Leffler if (!PKCS12_parse(p12, passwd, &pkey, &cert, &certs)) {
342339beb93cSSam Leffler tls_show_errors(MSG_DEBUG, __func__,
342439beb93cSSam Leffler "Failed to parse PKCS12 file");
342539beb93cSSam Leffler PKCS12_free(p12);
342639beb93cSSam Leffler return -1;
342739beb93cSSam Leffler }
342839beb93cSSam Leffler wpa_printf(MSG_DEBUG, "TLS: Successfully parsed PKCS12 data");
342939beb93cSSam Leffler
343039beb93cSSam Leffler if (cert) {
343139beb93cSSam Leffler X509_NAME_oneline(X509_get_subject_name(cert), buf,
343239beb93cSSam Leffler sizeof(buf));
343339beb93cSSam Leffler wpa_printf(MSG_DEBUG, "TLS: Got certificate from PKCS12: "
343439beb93cSSam Leffler "subject='%s'", buf);
343539beb93cSSam Leffler if (ssl) {
343639beb93cSSam Leffler if (SSL_use_certificate(ssl, cert) != 1)
343739beb93cSSam Leffler res = -1;
343839beb93cSSam Leffler } else {
3439325151a3SRui Paulo if (SSL_CTX_use_certificate(data->ssl, cert) != 1)
344039beb93cSSam Leffler res = -1;
344139beb93cSSam Leffler }
344239beb93cSSam Leffler X509_free(cert);
344339beb93cSSam Leffler }
344439beb93cSSam Leffler
344539beb93cSSam Leffler if (pkey) {
344639beb93cSSam Leffler wpa_printf(MSG_DEBUG, "TLS: Got private key from PKCS12");
344739beb93cSSam Leffler if (ssl) {
344839beb93cSSam Leffler if (SSL_use_PrivateKey(ssl, pkey) != 1)
344939beb93cSSam Leffler res = -1;
345039beb93cSSam Leffler } else {
3451325151a3SRui Paulo if (SSL_CTX_use_PrivateKey(data->ssl, pkey) != 1)
345239beb93cSSam Leffler res = -1;
345339beb93cSSam Leffler }
345439beb93cSSam Leffler EVP_PKEY_free(pkey);
345539beb93cSSam Leffler }
345639beb93cSSam Leffler
345739beb93cSSam Leffler if (certs) {
3458780fb4a2SCy Schubert #if OPENSSL_VERSION_NUMBER >= 0x10002000L && !defined(LIBRESSL_VERSION_NUMBER)
3459780fb4a2SCy Schubert if (ssl)
3460325151a3SRui Paulo SSL_clear_chain_certs(ssl);
3461780fb4a2SCy Schubert else
3462780fb4a2SCy Schubert SSL_CTX_clear_chain_certs(data->ssl);
3463325151a3SRui Paulo while ((cert = sk_X509_pop(certs)) != NULL) {
3464325151a3SRui Paulo X509_NAME_oneline(X509_get_subject_name(cert), buf,
3465325151a3SRui Paulo sizeof(buf));
3466325151a3SRui Paulo wpa_printf(MSG_DEBUG, "TLS: additional certificate"
3467325151a3SRui Paulo " from PKCS12: subject='%s'", buf);
3468780fb4a2SCy Schubert if ((ssl && SSL_add1_chain_cert(ssl, cert) != 1) ||
3469780fb4a2SCy Schubert (!ssl && SSL_CTX_add1_chain_cert(data->ssl,
3470780fb4a2SCy Schubert cert) != 1)) {
3471325151a3SRui Paulo tls_show_errors(MSG_DEBUG, __func__,
3472325151a3SRui Paulo "Failed to add additional certificate");
3473325151a3SRui Paulo res = -1;
3474780fb4a2SCy Schubert X509_free(cert);
3475325151a3SRui Paulo break;
3476325151a3SRui Paulo }
3477780fb4a2SCy Schubert X509_free(cert);
3478325151a3SRui Paulo }
3479325151a3SRui Paulo if (!res) {
3480325151a3SRui Paulo /* Try to continue anyway */
3481325151a3SRui Paulo }
3482780fb4a2SCy Schubert sk_X509_pop_free(certs, X509_free);
3483325151a3SRui Paulo #ifndef OPENSSL_IS_BORINGSSL
3484780fb4a2SCy Schubert if (ssl)
3485780fb4a2SCy Schubert res = SSL_build_cert_chain(
3486780fb4a2SCy Schubert ssl,
3487780fb4a2SCy Schubert SSL_BUILD_CHAIN_FLAG_CHECK |
3488780fb4a2SCy Schubert SSL_BUILD_CHAIN_FLAG_IGNORE_ERROR);
3489780fb4a2SCy Schubert else
3490780fb4a2SCy Schubert res = SSL_CTX_build_cert_chain(
3491780fb4a2SCy Schubert data->ssl,
3492325151a3SRui Paulo SSL_BUILD_CHAIN_FLAG_CHECK |
3493325151a3SRui Paulo SSL_BUILD_CHAIN_FLAG_IGNORE_ERROR);
3494325151a3SRui Paulo if (!res) {
3495325151a3SRui Paulo tls_show_errors(MSG_DEBUG, __func__,
3496325151a3SRui Paulo "Failed to build certificate chain");
3497325151a3SRui Paulo } else if (res == 2) {
3498325151a3SRui Paulo wpa_printf(MSG_DEBUG,
3499325151a3SRui Paulo "TLS: Ignore certificate chain verification error when building chain with PKCS#12 extra certificates");
3500325151a3SRui Paulo }
3501325151a3SRui Paulo #endif /* OPENSSL_IS_BORINGSSL */
3502325151a3SRui Paulo /*
3503325151a3SRui Paulo * Try to continue regardless of result since it is possible for
3504325151a3SRui Paulo * the extra certificates not to be required.
3505325151a3SRui Paulo */
3506325151a3SRui Paulo res = 0;
3507325151a3SRui Paulo #else /* OPENSSL_VERSION_NUMBER >= 0x10002000L */
3508325151a3SRui Paulo SSL_CTX_clear_extra_chain_certs(data->ssl);
350939beb93cSSam Leffler while ((cert = sk_X509_pop(certs)) != NULL) {
351039beb93cSSam Leffler X509_NAME_oneline(X509_get_subject_name(cert), buf,
351139beb93cSSam Leffler sizeof(buf));
351239beb93cSSam Leffler wpa_printf(MSG_DEBUG, "TLS: additional certificate"
351339beb93cSSam Leffler " from PKCS12: subject='%s'", buf);
351439beb93cSSam Leffler /*
351539beb93cSSam Leffler * There is no SSL equivalent for the chain cert - so
351639beb93cSSam Leffler * always add it to the context...
351739beb93cSSam Leffler */
3518325151a3SRui Paulo if (SSL_CTX_add_extra_chain_cert(data->ssl, cert) != 1)
3519325151a3SRui Paulo {
3520780fb4a2SCy Schubert X509_free(cert);
352139beb93cSSam Leffler res = -1;
352239beb93cSSam Leffler break;
352339beb93cSSam Leffler }
352439beb93cSSam Leffler }
3525780fb4a2SCy Schubert sk_X509_pop_free(certs, X509_free);
3526325151a3SRui Paulo #endif /* OPENSSL_VERSION_NUMBER >= 0x10002000L */
352739beb93cSSam Leffler }
352839beb93cSSam Leffler
352939beb93cSSam Leffler PKCS12_free(p12);
353039beb93cSSam Leffler
353139beb93cSSam Leffler if (res < 0)
3532325151a3SRui Paulo tls_get_errors(data);
353339beb93cSSam Leffler
353439beb93cSSam Leffler return res;
353539beb93cSSam Leffler }
353639beb93cSSam Leffler #endif /* PKCS12_FUNCS */
353739beb93cSSam Leffler
353839beb93cSSam Leffler
tls_read_pkcs12(struct tls_data * data,SSL * ssl,const char * private_key,const char * passwd)3539325151a3SRui Paulo static int tls_read_pkcs12(struct tls_data *data, SSL *ssl,
3540325151a3SRui Paulo const char *private_key, const char *passwd)
354139beb93cSSam Leffler {
354239beb93cSSam Leffler #ifdef PKCS12_FUNCS
354339beb93cSSam Leffler FILE *f;
354439beb93cSSam Leffler PKCS12 *p12;
354539beb93cSSam Leffler
354639beb93cSSam Leffler f = fopen(private_key, "rb");
354739beb93cSSam Leffler if (f == NULL)
354839beb93cSSam Leffler return -1;
354939beb93cSSam Leffler
355039beb93cSSam Leffler p12 = d2i_PKCS12_fp(f, NULL);
355139beb93cSSam Leffler fclose(f);
355239beb93cSSam Leffler
355339beb93cSSam Leffler if (p12 == NULL) {
355439beb93cSSam Leffler tls_show_errors(MSG_INFO, __func__,
355539beb93cSSam Leffler "Failed to use PKCS#12 file");
355639beb93cSSam Leffler return -1;
355739beb93cSSam Leffler }
355839beb93cSSam Leffler
3559325151a3SRui Paulo return tls_parse_pkcs12(data, ssl, p12, passwd);
356039beb93cSSam Leffler
356139beb93cSSam Leffler #else /* PKCS12_FUNCS */
356239beb93cSSam Leffler wpa_printf(MSG_INFO, "TLS: PKCS12 support disabled - cannot read "
356339beb93cSSam Leffler "p12/pfx files");
356439beb93cSSam Leffler return -1;
356539beb93cSSam Leffler #endif /* PKCS12_FUNCS */
356639beb93cSSam Leffler }
356739beb93cSSam Leffler
356839beb93cSSam Leffler
tls_read_pkcs12_blob(struct tls_data * data,SSL * ssl,const u8 * blob,size_t len,const char * passwd)3569325151a3SRui Paulo static int tls_read_pkcs12_blob(struct tls_data *data, SSL *ssl,
357039beb93cSSam Leffler const u8 *blob, size_t len, const char *passwd)
357139beb93cSSam Leffler {
357239beb93cSSam Leffler #ifdef PKCS12_FUNCS
357339beb93cSSam Leffler PKCS12 *p12;
357439beb93cSSam Leffler
35755b9c547cSRui Paulo p12 = d2i_PKCS12(NULL, (const unsigned char **) &blob, len);
357639beb93cSSam Leffler if (p12 == NULL) {
357739beb93cSSam Leffler tls_show_errors(MSG_INFO, __func__,
357839beb93cSSam Leffler "Failed to use PKCS#12 blob");
357939beb93cSSam Leffler return -1;
358039beb93cSSam Leffler }
358139beb93cSSam Leffler
3582325151a3SRui Paulo return tls_parse_pkcs12(data, ssl, p12, passwd);
358339beb93cSSam Leffler
358439beb93cSSam Leffler #else /* PKCS12_FUNCS */
358539beb93cSSam Leffler wpa_printf(MSG_INFO, "TLS: PKCS12 support disabled - cannot parse "
358639beb93cSSam Leffler "p12/pfx blobs");
358739beb93cSSam Leffler return -1;
358839beb93cSSam Leffler #endif /* PKCS12_FUNCS */
358939beb93cSSam Leffler }
359039beb93cSSam Leffler
359139beb93cSSam Leffler
359239beb93cSSam Leffler #ifndef OPENSSL_NO_ENGINE
tls_engine_get_cert(struct tls_connection * conn,const char * cert_id,X509 ** cert)359339beb93cSSam Leffler static int tls_engine_get_cert(struct tls_connection *conn,
359439beb93cSSam Leffler const char *cert_id,
359539beb93cSSam Leffler X509 **cert)
359639beb93cSSam Leffler {
359739beb93cSSam Leffler /* this runs after the private key is loaded so no PIN is required */
359839beb93cSSam Leffler struct {
359939beb93cSSam Leffler const char *cert_id;
360039beb93cSSam Leffler X509 *cert;
360139beb93cSSam Leffler } params;
360239beb93cSSam Leffler params.cert_id = cert_id;
360339beb93cSSam Leffler params.cert = NULL;
360439beb93cSSam Leffler
360539beb93cSSam Leffler if (!ENGINE_ctrl_cmd(conn->engine, "LOAD_CERT_CTRL",
360639beb93cSSam Leffler 0, ¶ms, NULL, 1)) {
3607325151a3SRui Paulo unsigned long err = ERR_get_error();
3608325151a3SRui Paulo
360939beb93cSSam Leffler wpa_printf(MSG_ERROR, "ENGINE: cannot load client cert with id"
361039beb93cSSam Leffler " '%s' [%s]", cert_id,
3611325151a3SRui Paulo ERR_error_string(err, NULL));
3612325151a3SRui Paulo if (tls_is_pin_error(err))
3613325151a3SRui Paulo return TLS_SET_PARAMS_ENGINE_PRV_BAD_PIN;
361439beb93cSSam Leffler return TLS_SET_PARAMS_ENGINE_PRV_INIT_FAILED;
361539beb93cSSam Leffler }
361639beb93cSSam Leffler if (!params.cert) {
361739beb93cSSam Leffler wpa_printf(MSG_ERROR, "ENGINE: did not properly cert with id"
361839beb93cSSam Leffler " '%s'", cert_id);
361939beb93cSSam Leffler return TLS_SET_PARAMS_ENGINE_PRV_INIT_FAILED;
362039beb93cSSam Leffler }
362139beb93cSSam Leffler *cert = params.cert;
362239beb93cSSam Leffler return 0;
362339beb93cSSam Leffler }
362439beb93cSSam Leffler #endif /* OPENSSL_NO_ENGINE */
362539beb93cSSam Leffler
362639beb93cSSam Leffler
tls_connection_engine_client_cert(struct tls_connection * conn,const char * cert_id)362739beb93cSSam Leffler static int tls_connection_engine_client_cert(struct tls_connection *conn,
362839beb93cSSam Leffler const char *cert_id)
362939beb93cSSam Leffler {
363039beb93cSSam Leffler #ifndef OPENSSL_NO_ENGINE
363139beb93cSSam Leffler X509 *cert;
363239beb93cSSam Leffler
363339beb93cSSam Leffler if (tls_engine_get_cert(conn, cert_id, &cert))
363439beb93cSSam Leffler return -1;
363539beb93cSSam Leffler
363639beb93cSSam Leffler if (!SSL_use_certificate(conn->ssl, cert)) {
363739beb93cSSam Leffler tls_show_errors(MSG_ERROR, __func__,
363839beb93cSSam Leffler "SSL_use_certificate failed");
363939beb93cSSam Leffler X509_free(cert);
364039beb93cSSam Leffler return -1;
364139beb93cSSam Leffler }
364239beb93cSSam Leffler X509_free(cert);
364339beb93cSSam Leffler wpa_printf(MSG_DEBUG, "ENGINE: SSL_use_certificate --> "
364439beb93cSSam Leffler "OK");
364539beb93cSSam Leffler return 0;
364639beb93cSSam Leffler
364739beb93cSSam Leffler #else /* OPENSSL_NO_ENGINE */
364839beb93cSSam Leffler return -1;
364939beb93cSSam Leffler #endif /* OPENSSL_NO_ENGINE */
365039beb93cSSam Leffler }
365139beb93cSSam Leffler
365239beb93cSSam Leffler
tls_connection_engine_ca_cert(struct tls_data * data,struct tls_connection * conn,const char * ca_cert_id)3653325151a3SRui Paulo static int tls_connection_engine_ca_cert(struct tls_data *data,
365439beb93cSSam Leffler struct tls_connection *conn,
365539beb93cSSam Leffler const char *ca_cert_id)
365639beb93cSSam Leffler {
365739beb93cSSam Leffler #ifndef OPENSSL_NO_ENGINE
365839beb93cSSam Leffler X509 *cert;
3659325151a3SRui Paulo SSL_CTX *ssl_ctx = data->ssl;
36605b9c547cSRui Paulo X509_STORE *store;
366139beb93cSSam Leffler
366239beb93cSSam Leffler if (tls_engine_get_cert(conn, ca_cert_id, &cert))
366339beb93cSSam Leffler return -1;
366439beb93cSSam Leffler
366539beb93cSSam Leffler /* start off the same as tls_connection_ca_cert */
36665b9c547cSRui Paulo store = X509_STORE_new();
36675b9c547cSRui Paulo if (store == NULL) {
366839beb93cSSam Leffler wpa_printf(MSG_DEBUG, "OpenSSL: %s - failed to allocate new "
366939beb93cSSam Leffler "certificate store", __func__);
367039beb93cSSam Leffler X509_free(cert);
367139beb93cSSam Leffler return -1;
367239beb93cSSam Leffler }
36735b9c547cSRui Paulo SSL_CTX_set_cert_store(ssl_ctx, store);
36745b9c547cSRui Paulo if (!X509_STORE_add_cert(store, cert)) {
367539beb93cSSam Leffler unsigned long err = ERR_peek_error();
367639beb93cSSam Leffler tls_show_errors(MSG_WARNING, __func__,
367739beb93cSSam Leffler "Failed to add CA certificate from engine "
367839beb93cSSam Leffler "to certificate store");
367939beb93cSSam Leffler if (ERR_GET_LIB(err) == ERR_LIB_X509 &&
368039beb93cSSam Leffler ERR_GET_REASON(err) == X509_R_CERT_ALREADY_IN_HASH_TABLE) {
368139beb93cSSam Leffler wpa_printf(MSG_DEBUG, "OpenSSL: %s - ignoring cert"
368239beb93cSSam Leffler " already in hash table error",
368339beb93cSSam Leffler __func__);
368439beb93cSSam Leffler } else {
368539beb93cSSam Leffler X509_free(cert);
368639beb93cSSam Leffler return -1;
368739beb93cSSam Leffler }
368839beb93cSSam Leffler }
368939beb93cSSam Leffler X509_free(cert);
369039beb93cSSam Leffler wpa_printf(MSG_DEBUG, "OpenSSL: %s - added CA certificate from engine "
369139beb93cSSam Leffler "to certificate store", __func__);
369239beb93cSSam Leffler SSL_set_verify(conn->ssl, SSL_VERIFY_PEER, tls_verify_cb);
3693f05cddf9SRui Paulo conn->ca_cert_verify = 1;
3694f05cddf9SRui Paulo
369539beb93cSSam Leffler return 0;
369639beb93cSSam Leffler
369739beb93cSSam Leffler #else /* OPENSSL_NO_ENGINE */
369839beb93cSSam Leffler return -1;
369939beb93cSSam Leffler #endif /* OPENSSL_NO_ENGINE */
370039beb93cSSam Leffler }
370139beb93cSSam Leffler
370239beb93cSSam Leffler
tls_connection_engine_private_key(struct tls_connection * conn)370339beb93cSSam Leffler static int tls_connection_engine_private_key(struct tls_connection *conn)
370439beb93cSSam Leffler {
3705780fb4a2SCy Schubert #if defined(ANDROID) || !defined(OPENSSL_NO_ENGINE)
370639beb93cSSam Leffler if (SSL_use_PrivateKey(conn->ssl, conn->private_key) != 1) {
370739beb93cSSam Leffler tls_show_errors(MSG_ERROR, __func__,
370839beb93cSSam Leffler "ENGINE: cannot use private key for TLS");
370939beb93cSSam Leffler return -1;
371039beb93cSSam Leffler }
371139beb93cSSam Leffler if (!SSL_check_private_key(conn->ssl)) {
371239beb93cSSam Leffler tls_show_errors(MSG_INFO, __func__,
371339beb93cSSam Leffler "Private key failed verification");
371439beb93cSSam Leffler return -1;
371539beb93cSSam Leffler }
371639beb93cSSam Leffler return 0;
371739beb93cSSam Leffler #else /* OPENSSL_NO_ENGINE */
371839beb93cSSam Leffler wpa_printf(MSG_ERROR, "SSL: Configuration uses engine, but "
371939beb93cSSam Leffler "engine support was not compiled in");
372039beb93cSSam Leffler return -1;
372139beb93cSSam Leffler #endif /* OPENSSL_NO_ENGINE */
372239beb93cSSam Leffler }
372339beb93cSSam Leffler
372439beb93cSSam Leffler
372585732ac8SCy Schubert #ifndef OPENSSL_NO_STDIO
tls_passwd_cb(char * buf,int size,int rwflag,void * password)372685732ac8SCy Schubert static int tls_passwd_cb(char *buf, int size, int rwflag, void *password)
372785732ac8SCy Schubert {
372885732ac8SCy Schubert if (!password)
372985732ac8SCy Schubert return 0;
373085732ac8SCy Schubert os_strlcpy(buf, (const char *) password, size);
373185732ac8SCy Schubert return os_strlen(buf);
373285732ac8SCy Schubert }
373385732ac8SCy Schubert #endif /* OPENSSL_NO_STDIO */
373485732ac8SCy Schubert
373585732ac8SCy Schubert
tls_use_private_key_file(struct tls_data * data,SSL * ssl,const char * private_key,const char * private_key_passwd)373685732ac8SCy Schubert static int tls_use_private_key_file(struct tls_data *data, SSL *ssl,
373785732ac8SCy Schubert const char *private_key,
373885732ac8SCy Schubert const char *private_key_passwd)
373985732ac8SCy Schubert {
374085732ac8SCy Schubert #ifndef OPENSSL_NO_STDIO
374185732ac8SCy Schubert BIO *bio;
374285732ac8SCy Schubert EVP_PKEY *pkey;
374385732ac8SCy Schubert int ret;
374485732ac8SCy Schubert
374585732ac8SCy Schubert /* First try ASN.1 (DER). */
374685732ac8SCy Schubert bio = BIO_new_file(private_key, "r");
374785732ac8SCy Schubert if (!bio)
374885732ac8SCy Schubert return -1;
374985732ac8SCy Schubert pkey = d2i_PrivateKey_bio(bio, NULL);
375085732ac8SCy Schubert BIO_free(bio);
375185732ac8SCy Schubert
375285732ac8SCy Schubert if (pkey) {
375385732ac8SCy Schubert wpa_printf(MSG_DEBUG, "OpenSSL: %s (DER) --> loaded", __func__);
375485732ac8SCy Schubert } else {
375585732ac8SCy Schubert /* Try PEM with the provided password. */
375685732ac8SCy Schubert bio = BIO_new_file(private_key, "r");
375785732ac8SCy Schubert if (!bio)
375885732ac8SCy Schubert return -1;
375985732ac8SCy Schubert pkey = PEM_read_bio_PrivateKey(bio, NULL, tls_passwd_cb,
376085732ac8SCy Schubert (void *) private_key_passwd);
376185732ac8SCy Schubert BIO_free(bio);
376285732ac8SCy Schubert if (!pkey)
376385732ac8SCy Schubert return -1;
376485732ac8SCy Schubert wpa_printf(MSG_DEBUG, "OpenSSL: %s (PEM) --> loaded", __func__);
376585732ac8SCy Schubert /* Clear errors from the previous failed load. */
376685732ac8SCy Schubert ERR_clear_error();
376785732ac8SCy Schubert }
376885732ac8SCy Schubert
376985732ac8SCy Schubert if (ssl)
377085732ac8SCy Schubert ret = SSL_use_PrivateKey(ssl, pkey);
377185732ac8SCy Schubert else
377285732ac8SCy Schubert ret = SSL_CTX_use_PrivateKey(data->ssl, pkey);
377385732ac8SCy Schubert
377485732ac8SCy Schubert EVP_PKEY_free(pkey);
377585732ac8SCy Schubert return ret == 1 ? 0 : -1;
377685732ac8SCy Schubert #else /* OPENSSL_NO_STDIO */
377785732ac8SCy Schubert wpa_printf(MSG_DEBUG, "OpenSSL: %s - OPENSSL_NO_STDIO", __func__);
377885732ac8SCy Schubert return -1;
377985732ac8SCy Schubert #endif /* OPENSSL_NO_STDIO */
378085732ac8SCy Schubert }
378185732ac8SCy Schubert
378285732ac8SCy Schubert
tls_connection_private_key(struct tls_data * data,struct tls_connection * conn,const char * private_key,const char * private_key_passwd,const u8 * private_key_blob,size_t private_key_blob_len)3783325151a3SRui Paulo static int tls_connection_private_key(struct tls_data *data,
378439beb93cSSam Leffler struct tls_connection *conn,
378539beb93cSSam Leffler const char *private_key,
378639beb93cSSam Leffler const char *private_key_passwd,
378739beb93cSSam Leffler const u8 *private_key_blob,
378839beb93cSSam Leffler size_t private_key_blob_len)
378939beb93cSSam Leffler {
37904b72b91aSCy Schubert BIO *bio;
379139beb93cSSam Leffler int ok;
379239beb93cSSam Leffler
379339beb93cSSam Leffler if (private_key == NULL && private_key_blob == NULL)
379439beb93cSSam Leffler return 0;
379539beb93cSSam Leffler
379639beb93cSSam Leffler ok = 0;
379739beb93cSSam Leffler while (private_key_blob) {
379839beb93cSSam Leffler if (SSL_use_PrivateKey_ASN1(EVP_PKEY_RSA, conn->ssl,
379939beb93cSSam Leffler (u8 *) private_key_blob,
380039beb93cSSam Leffler private_key_blob_len) == 1) {
380139beb93cSSam Leffler wpa_printf(MSG_DEBUG, "OpenSSL: SSL_use_PrivateKey_"
380239beb93cSSam Leffler "ASN1(EVP_PKEY_RSA) --> OK");
380339beb93cSSam Leffler ok = 1;
380439beb93cSSam Leffler break;
380539beb93cSSam Leffler }
380639beb93cSSam Leffler
380739beb93cSSam Leffler if (SSL_use_PrivateKey_ASN1(EVP_PKEY_DSA, conn->ssl,
380839beb93cSSam Leffler (u8 *) private_key_blob,
380939beb93cSSam Leffler private_key_blob_len) == 1) {
381039beb93cSSam Leffler wpa_printf(MSG_DEBUG, "OpenSSL: SSL_use_PrivateKey_"
381139beb93cSSam Leffler "ASN1(EVP_PKEY_DSA) --> OK");
381239beb93cSSam Leffler ok = 1;
381339beb93cSSam Leffler break;
381439beb93cSSam Leffler }
381539beb93cSSam Leffler
3816c1d255d3SCy Schubert #ifndef OPENSSL_NO_EC
3817c1d255d3SCy Schubert if (SSL_use_PrivateKey_ASN1(EVP_PKEY_EC, conn->ssl,
3818c1d255d3SCy Schubert (u8 *) private_key_blob,
3819c1d255d3SCy Schubert private_key_blob_len) == 1) {
3820c1d255d3SCy Schubert wpa_printf(MSG_DEBUG,
3821c1d255d3SCy Schubert "OpenSSL: SSL_use_PrivateKey_ASN1(EVP_PKEY_EC) --> OK");
3822c1d255d3SCy Schubert ok = 1;
3823c1d255d3SCy Schubert break;
3824c1d255d3SCy Schubert }
3825c1d255d3SCy Schubert #endif /* OPENSSL_NO_EC */
3826c1d255d3SCy Schubert
382739beb93cSSam Leffler if (SSL_use_RSAPrivateKey_ASN1(conn->ssl,
382839beb93cSSam Leffler (u8 *) private_key_blob,
382939beb93cSSam Leffler private_key_blob_len) == 1) {
383039beb93cSSam Leffler wpa_printf(MSG_DEBUG, "OpenSSL: "
383139beb93cSSam Leffler "SSL_use_RSAPrivateKey_ASN1 --> OK");
383239beb93cSSam Leffler ok = 1;
383339beb93cSSam Leffler break;
383439beb93cSSam Leffler }
383539beb93cSSam Leffler
38364b72b91aSCy Schubert bio = BIO_new_mem_buf((u8 *) private_key_blob,
38374b72b91aSCy Schubert private_key_blob_len);
38384b72b91aSCy Schubert if (bio) {
38394b72b91aSCy Schubert EVP_PKEY *pkey;
38404b72b91aSCy Schubert
38414b72b91aSCy Schubert pkey = PEM_read_bio_PrivateKey(
38424b72b91aSCy Schubert bio, NULL, tls_passwd_cb,
38434b72b91aSCy Schubert (void *) private_key_passwd);
38444b72b91aSCy Schubert if (pkey) {
38454b72b91aSCy Schubert if (SSL_use_PrivateKey(conn->ssl, pkey) == 1) {
38464b72b91aSCy Schubert wpa_printf(MSG_DEBUG,
38474b72b91aSCy Schubert "OpenSSL: SSL_use_PrivateKey --> OK");
38484b72b91aSCy Schubert ok = 1;
38494b72b91aSCy Schubert EVP_PKEY_free(pkey);
38504b72b91aSCy Schubert BIO_free(bio);
38514b72b91aSCy Schubert break;
38524b72b91aSCy Schubert }
38534b72b91aSCy Schubert EVP_PKEY_free(pkey);
38544b72b91aSCy Schubert }
38554b72b91aSCy Schubert BIO_free(bio);
38564b72b91aSCy Schubert }
38574b72b91aSCy Schubert
3858325151a3SRui Paulo if (tls_read_pkcs12_blob(data, conn->ssl, private_key_blob,
385985732ac8SCy Schubert private_key_blob_len,
386085732ac8SCy Schubert private_key_passwd) == 0) {
386139beb93cSSam Leffler wpa_printf(MSG_DEBUG, "OpenSSL: PKCS#12 as blob --> "
386239beb93cSSam Leffler "OK");
386339beb93cSSam Leffler ok = 1;
386439beb93cSSam Leffler break;
386539beb93cSSam Leffler }
386639beb93cSSam Leffler
386739beb93cSSam Leffler break;
386839beb93cSSam Leffler }
386939beb93cSSam Leffler
387039beb93cSSam Leffler while (!ok && private_key) {
387185732ac8SCy Schubert if (tls_use_private_key_file(data, conn->ssl, private_key,
387285732ac8SCy Schubert private_key_passwd) == 0) {
387339beb93cSSam Leffler ok = 1;
387439beb93cSSam Leffler break;
387539beb93cSSam Leffler }
387639beb93cSSam Leffler
387785732ac8SCy Schubert if (tls_read_pkcs12(data, conn->ssl, private_key,
387885732ac8SCy Schubert private_key_passwd) == 0) {
387939beb93cSSam Leffler wpa_printf(MSG_DEBUG, "OpenSSL: Reading PKCS#12 file "
388039beb93cSSam Leffler "--> OK");
388139beb93cSSam Leffler ok = 1;
388239beb93cSSam Leffler break;
388339beb93cSSam Leffler }
388439beb93cSSam Leffler
388539beb93cSSam Leffler if (tls_cryptoapi_cert(conn->ssl, private_key) == 0) {
388639beb93cSSam Leffler wpa_printf(MSG_DEBUG, "OpenSSL: Using CryptoAPI to "
388739beb93cSSam Leffler "access certificate store --> OK");
388839beb93cSSam Leffler ok = 1;
388939beb93cSSam Leffler break;
389039beb93cSSam Leffler }
389139beb93cSSam Leffler
389239beb93cSSam Leffler break;
389339beb93cSSam Leffler }
389439beb93cSSam Leffler
389539beb93cSSam Leffler if (!ok) {
3896f05cddf9SRui Paulo tls_show_errors(MSG_INFO, __func__,
3897f05cddf9SRui Paulo "Failed to load private key");
389839beb93cSSam Leffler return -1;
389939beb93cSSam Leffler }
390039beb93cSSam Leffler ERR_clear_error();
390139beb93cSSam Leffler
390239beb93cSSam Leffler if (!SSL_check_private_key(conn->ssl)) {
390339beb93cSSam Leffler tls_show_errors(MSG_INFO, __func__, "Private key failed "
390439beb93cSSam Leffler "verification");
390539beb93cSSam Leffler return -1;
390639beb93cSSam Leffler }
390739beb93cSSam Leffler
390839beb93cSSam Leffler wpa_printf(MSG_DEBUG, "SSL: Private key loaded successfully");
390939beb93cSSam Leffler return 0;
391039beb93cSSam Leffler }
391139beb93cSSam Leffler
391239beb93cSSam Leffler
tls_global_private_key(struct tls_data * data,const char * private_key,const char * private_key_passwd)3913325151a3SRui Paulo static int tls_global_private_key(struct tls_data *data,
3914325151a3SRui Paulo const char *private_key,
391539beb93cSSam Leffler const char *private_key_passwd)
391639beb93cSSam Leffler {
3917325151a3SRui Paulo SSL_CTX *ssl_ctx = data->ssl;
391839beb93cSSam Leffler
391939beb93cSSam Leffler if (private_key == NULL)
392039beb93cSSam Leffler return 0;
392139beb93cSSam Leffler
392285732ac8SCy Schubert if (tls_use_private_key_file(data, NULL, private_key,
392385732ac8SCy Schubert private_key_passwd) &&
392485732ac8SCy Schubert tls_read_pkcs12(data, NULL, private_key, private_key_passwd)) {
392539beb93cSSam Leffler tls_show_errors(MSG_INFO, __func__,
392639beb93cSSam Leffler "Failed to load private key");
392739beb93cSSam Leffler ERR_clear_error();
392839beb93cSSam Leffler return -1;
392939beb93cSSam Leffler }
393039beb93cSSam Leffler ERR_clear_error();
393139beb93cSSam Leffler
393239beb93cSSam Leffler if (!SSL_CTX_check_private_key(ssl_ctx)) {
393339beb93cSSam Leffler tls_show_errors(MSG_INFO, __func__,
393439beb93cSSam Leffler "Private key failed verification");
393539beb93cSSam Leffler return -1;
393639beb93cSSam Leffler }
393739beb93cSSam Leffler
393839beb93cSSam Leffler return 0;
393939beb93cSSam Leffler }
394039beb93cSSam Leffler
394139beb93cSSam Leffler
tls_connection_dh(struct tls_connection * conn,const char * dh_file)394239beb93cSSam Leffler static int tls_connection_dh(struct tls_connection *conn, const char *dh_file)
394339beb93cSSam Leffler {
394439beb93cSSam Leffler #ifdef OPENSSL_NO_DH
394539beb93cSSam Leffler if (dh_file == NULL)
394639beb93cSSam Leffler return 0;
394739beb93cSSam Leffler wpa_printf(MSG_ERROR, "TLS: openssl does not include DH support, but "
394839beb93cSSam Leffler "dh_file specified");
394939beb93cSSam Leffler return -1;
395039beb93cSSam Leffler #else /* OPENSSL_NO_DH */
395139beb93cSSam Leffler DH *dh;
395239beb93cSSam Leffler BIO *bio;
395339beb93cSSam Leffler
395439beb93cSSam Leffler /* TODO: add support for dh_blob */
395539beb93cSSam Leffler if (dh_file == NULL)
395639beb93cSSam Leffler return 0;
395739beb93cSSam Leffler if (conn == NULL)
395839beb93cSSam Leffler return -1;
395939beb93cSSam Leffler
396039beb93cSSam Leffler bio = BIO_new_file(dh_file, "r");
396139beb93cSSam Leffler if (bio == NULL) {
396239beb93cSSam Leffler wpa_printf(MSG_INFO, "TLS: Failed to open DH file '%s': %s",
396339beb93cSSam Leffler dh_file, ERR_error_string(ERR_get_error(), NULL));
396439beb93cSSam Leffler return -1;
396539beb93cSSam Leffler }
396639beb93cSSam Leffler dh = PEM_read_bio_DHparams(bio, NULL, NULL, NULL);
396739beb93cSSam Leffler BIO_free(bio);
396839beb93cSSam Leffler #ifndef OPENSSL_NO_DSA
396939beb93cSSam Leffler while (dh == NULL) {
397039beb93cSSam Leffler DSA *dsa;
397139beb93cSSam Leffler wpa_printf(MSG_DEBUG, "TLS: Failed to parse DH file '%s': %s -"
397239beb93cSSam Leffler " trying to parse as DSA params", dh_file,
397339beb93cSSam Leffler ERR_error_string(ERR_get_error(), NULL));
397439beb93cSSam Leffler bio = BIO_new_file(dh_file, "r");
397539beb93cSSam Leffler if (bio == NULL)
397639beb93cSSam Leffler break;
397739beb93cSSam Leffler dsa = PEM_read_bio_DSAparams(bio, NULL, NULL, NULL);
397839beb93cSSam Leffler BIO_free(bio);
397939beb93cSSam Leffler if (!dsa) {
398039beb93cSSam Leffler wpa_printf(MSG_DEBUG, "TLS: Failed to parse DSA file "
398139beb93cSSam Leffler "'%s': %s", dh_file,
398239beb93cSSam Leffler ERR_error_string(ERR_get_error(), NULL));
398339beb93cSSam Leffler break;
398439beb93cSSam Leffler }
398539beb93cSSam Leffler
398639beb93cSSam Leffler wpa_printf(MSG_DEBUG, "TLS: DH file in DSA param format");
398739beb93cSSam Leffler dh = DSA_dup_DH(dsa);
398839beb93cSSam Leffler DSA_free(dsa);
398939beb93cSSam Leffler if (dh == NULL) {
399039beb93cSSam Leffler wpa_printf(MSG_INFO, "TLS: Failed to convert DSA "
399139beb93cSSam Leffler "params into DH params");
399239beb93cSSam Leffler break;
399339beb93cSSam Leffler }
399439beb93cSSam Leffler break;
399539beb93cSSam Leffler }
399639beb93cSSam Leffler #endif /* !OPENSSL_NO_DSA */
399739beb93cSSam Leffler if (dh == NULL) {
399839beb93cSSam Leffler wpa_printf(MSG_INFO, "TLS: Failed to read/parse DH/DSA file "
399939beb93cSSam Leffler "'%s'", dh_file);
400039beb93cSSam Leffler return -1;
400139beb93cSSam Leffler }
400239beb93cSSam Leffler
400339beb93cSSam Leffler if (SSL_set_tmp_dh(conn->ssl, dh) != 1) {
400439beb93cSSam Leffler wpa_printf(MSG_INFO, "TLS: Failed to set DH params from '%s': "
400539beb93cSSam Leffler "%s", dh_file,
400639beb93cSSam Leffler ERR_error_string(ERR_get_error(), NULL));
400739beb93cSSam Leffler DH_free(dh);
400839beb93cSSam Leffler return -1;
400939beb93cSSam Leffler }
401039beb93cSSam Leffler DH_free(dh);
401139beb93cSSam Leffler return 0;
401239beb93cSSam Leffler #endif /* OPENSSL_NO_DH */
401339beb93cSSam Leffler }
401439beb93cSSam Leffler
401539beb93cSSam Leffler
tls_global_dh(struct tls_data * data,const char * dh_file)4016325151a3SRui Paulo static int tls_global_dh(struct tls_data *data, const char *dh_file)
401739beb93cSSam Leffler {
401839beb93cSSam Leffler #ifdef OPENSSL_NO_DH
401939beb93cSSam Leffler if (dh_file == NULL)
402039beb93cSSam Leffler return 0;
402139beb93cSSam Leffler wpa_printf(MSG_ERROR, "TLS: openssl does not include DH support, but "
402239beb93cSSam Leffler "dh_file specified");
402339beb93cSSam Leffler return -1;
402439beb93cSSam Leffler #else /* OPENSSL_NO_DH */
4025325151a3SRui Paulo SSL_CTX *ssl_ctx = data->ssl;
402639beb93cSSam Leffler DH *dh;
402739beb93cSSam Leffler BIO *bio;
402839beb93cSSam Leffler
402939beb93cSSam Leffler /* TODO: add support for dh_blob */
403039beb93cSSam Leffler if (dh_file == NULL)
403139beb93cSSam Leffler return 0;
403239beb93cSSam Leffler if (ssl_ctx == NULL)
403339beb93cSSam Leffler return -1;
403439beb93cSSam Leffler
403539beb93cSSam Leffler bio = BIO_new_file(dh_file, "r");
403639beb93cSSam Leffler if (bio == NULL) {
403739beb93cSSam Leffler wpa_printf(MSG_INFO, "TLS: Failed to open DH file '%s': %s",
403839beb93cSSam Leffler dh_file, ERR_error_string(ERR_get_error(), NULL));
403939beb93cSSam Leffler return -1;
404039beb93cSSam Leffler }
404139beb93cSSam Leffler dh = PEM_read_bio_DHparams(bio, NULL, NULL, NULL);
404239beb93cSSam Leffler BIO_free(bio);
404339beb93cSSam Leffler #ifndef OPENSSL_NO_DSA
404439beb93cSSam Leffler while (dh == NULL) {
404539beb93cSSam Leffler DSA *dsa;
404639beb93cSSam Leffler wpa_printf(MSG_DEBUG, "TLS: Failed to parse DH file '%s': %s -"
404739beb93cSSam Leffler " trying to parse as DSA params", dh_file,
404839beb93cSSam Leffler ERR_error_string(ERR_get_error(), NULL));
404939beb93cSSam Leffler bio = BIO_new_file(dh_file, "r");
405039beb93cSSam Leffler if (bio == NULL)
405139beb93cSSam Leffler break;
405239beb93cSSam Leffler dsa = PEM_read_bio_DSAparams(bio, NULL, NULL, NULL);
405339beb93cSSam Leffler BIO_free(bio);
405439beb93cSSam Leffler if (!dsa) {
405539beb93cSSam Leffler wpa_printf(MSG_DEBUG, "TLS: Failed to parse DSA file "
405639beb93cSSam Leffler "'%s': %s", dh_file,
405739beb93cSSam Leffler ERR_error_string(ERR_get_error(), NULL));
405839beb93cSSam Leffler break;
405939beb93cSSam Leffler }
406039beb93cSSam Leffler
406139beb93cSSam Leffler wpa_printf(MSG_DEBUG, "TLS: DH file in DSA param format");
406239beb93cSSam Leffler dh = DSA_dup_DH(dsa);
406339beb93cSSam Leffler DSA_free(dsa);
406439beb93cSSam Leffler if (dh == NULL) {
406539beb93cSSam Leffler wpa_printf(MSG_INFO, "TLS: Failed to convert DSA "
406639beb93cSSam Leffler "params into DH params");
406739beb93cSSam Leffler break;
406839beb93cSSam Leffler }
406939beb93cSSam Leffler break;
407039beb93cSSam Leffler }
407139beb93cSSam Leffler #endif /* !OPENSSL_NO_DSA */
407239beb93cSSam Leffler if (dh == NULL) {
407339beb93cSSam Leffler wpa_printf(MSG_INFO, "TLS: Failed to read/parse DH/DSA file "
407439beb93cSSam Leffler "'%s'", dh_file);
407539beb93cSSam Leffler return -1;
407639beb93cSSam Leffler }
407739beb93cSSam Leffler
407839beb93cSSam Leffler if (SSL_CTX_set_tmp_dh(ssl_ctx, dh) != 1) {
407939beb93cSSam Leffler wpa_printf(MSG_INFO, "TLS: Failed to set DH params from '%s': "
408039beb93cSSam Leffler "%s", dh_file,
408139beb93cSSam Leffler ERR_error_string(ERR_get_error(), NULL));
408239beb93cSSam Leffler DH_free(dh);
408339beb93cSSam Leffler return -1;
408439beb93cSSam Leffler }
408539beb93cSSam Leffler DH_free(dh);
408639beb93cSSam Leffler return 0;
408739beb93cSSam Leffler #endif /* OPENSSL_NO_DH */
408839beb93cSSam Leffler }
408939beb93cSSam Leffler
409039beb93cSSam Leffler
tls_connection_get_random(void * ssl_ctx,struct tls_connection * conn,struct tls_random * keys)4091325151a3SRui Paulo int tls_connection_get_random(void *ssl_ctx, struct tls_connection *conn,
4092325151a3SRui Paulo struct tls_random *keys)
4093325151a3SRui Paulo {
4094325151a3SRui Paulo SSL *ssl;
4095325151a3SRui Paulo
4096325151a3SRui Paulo if (conn == NULL || keys == NULL)
4097325151a3SRui Paulo return -1;
4098325151a3SRui Paulo ssl = conn->ssl;
4099325151a3SRui Paulo if (ssl == NULL)
4100325151a3SRui Paulo return -1;
4101325151a3SRui Paulo
4102325151a3SRui Paulo os_memset(keys, 0, sizeof(*keys));
4103325151a3SRui Paulo keys->client_random = conn->client_random;
4104325151a3SRui Paulo keys->client_random_len = SSL_get_client_random(
4105325151a3SRui Paulo ssl, conn->client_random, sizeof(conn->client_random));
4106325151a3SRui Paulo keys->server_random = conn->server_random;
4107325151a3SRui Paulo keys->server_random_len = SSL_get_server_random(
4108325151a3SRui Paulo ssl, conn->server_random, sizeof(conn->server_random));
4109325151a3SRui Paulo
4110325151a3SRui Paulo return 0;
4111325151a3SRui Paulo }
4112325151a3SRui Paulo
4113325151a3SRui Paulo
4114780fb4a2SCy Schubert #ifdef OPENSSL_NEED_EAP_FAST_PRF
openssl_get_keyblock_size(SSL * ssl)4115325151a3SRui Paulo static int openssl_get_keyblock_size(SSL *ssl)
4116325151a3SRui Paulo {
411785732ac8SCy Schubert #if OPENSSL_VERSION_NUMBER < 0x10100000L || \
411885732ac8SCy Schubert (defined(LIBRESSL_VERSION_NUMBER) && \
411985732ac8SCy Schubert LIBRESSL_VERSION_NUMBER < 0x20700000L)
4120325151a3SRui Paulo const EVP_CIPHER *c;
4121325151a3SRui Paulo const EVP_MD *h;
4122325151a3SRui Paulo int md_size;
4123325151a3SRui Paulo
4124325151a3SRui Paulo if (ssl->enc_read_ctx == NULL || ssl->enc_read_ctx->cipher == NULL ||
4125325151a3SRui Paulo ssl->read_hash == NULL)
4126325151a3SRui Paulo return -1;
4127325151a3SRui Paulo
4128325151a3SRui Paulo c = ssl->enc_read_ctx->cipher;
4129325151a3SRui Paulo h = EVP_MD_CTX_md(ssl->read_hash);
4130325151a3SRui Paulo if (h)
4131325151a3SRui Paulo md_size = EVP_MD_size(h);
4132325151a3SRui Paulo else if (ssl->s3)
4133325151a3SRui Paulo md_size = ssl->s3->tmp.new_mac_secret_size;
4134325151a3SRui Paulo else
4135325151a3SRui Paulo return -1;
4136325151a3SRui Paulo
4137325151a3SRui Paulo wpa_printf(MSG_DEBUG, "OpenSSL: keyblock size: key_len=%d MD_size=%d "
4138325151a3SRui Paulo "IV_len=%d", EVP_CIPHER_key_length(c), md_size,
4139325151a3SRui Paulo EVP_CIPHER_iv_length(c));
4140325151a3SRui Paulo return 2 * (EVP_CIPHER_key_length(c) +
4141325151a3SRui Paulo md_size +
4142325151a3SRui Paulo EVP_CIPHER_iv_length(c));
4143325151a3SRui Paulo #else
4144325151a3SRui Paulo const SSL_CIPHER *ssl_cipher;
4145325151a3SRui Paulo int cipher, digest;
4146325151a3SRui Paulo const EVP_CIPHER *c;
4147325151a3SRui Paulo const EVP_MD *h;
4148c1d255d3SCy Schubert int mac_key_len, enc_key_len, fixed_iv_len;
4149325151a3SRui Paulo
4150325151a3SRui Paulo ssl_cipher = SSL_get_current_cipher(ssl);
4151325151a3SRui Paulo if (!ssl_cipher)
4152325151a3SRui Paulo return -1;
4153325151a3SRui Paulo cipher = SSL_CIPHER_get_cipher_nid(ssl_cipher);
4154325151a3SRui Paulo digest = SSL_CIPHER_get_digest_nid(ssl_cipher);
4155325151a3SRui Paulo wpa_printf(MSG_DEBUG, "OpenSSL: cipher nid %d digest nid %d",
4156325151a3SRui Paulo cipher, digest);
4157325151a3SRui Paulo if (cipher < 0 || digest < 0)
4158325151a3SRui Paulo return -1;
4159c1d255d3SCy Schubert if (cipher == NID_undef) {
4160c1d255d3SCy Schubert wpa_printf(MSG_DEBUG, "OpenSSL: no cipher in use?!");
4161325151a3SRui Paulo return -1;
4162c1d255d3SCy Schubert }
4163c1d255d3SCy Schubert c = EVP_get_cipherbynid(cipher);
4164c1d255d3SCy Schubert if (!c)
4165c1d255d3SCy Schubert return -1;
4166c1d255d3SCy Schubert enc_key_len = EVP_CIPHER_key_length(c);
4167c1d255d3SCy Schubert if (EVP_CIPHER_mode(c) == EVP_CIPH_GCM_MODE ||
4168c1d255d3SCy Schubert EVP_CIPHER_mode(c) == EVP_CIPH_CCM_MODE)
4169c1d255d3SCy Schubert fixed_iv_len = 4; /* only part of IV from PRF */
4170c1d255d3SCy Schubert else
4171c1d255d3SCy Schubert fixed_iv_len = EVP_CIPHER_iv_length(c);
4172c1d255d3SCy Schubert if (digest == NID_undef) {
4173c1d255d3SCy Schubert wpa_printf(MSG_DEBUG, "OpenSSL: no digest in use (e.g., AEAD)");
4174c1d255d3SCy Schubert mac_key_len = 0;
4175c1d255d3SCy Schubert } else {
4176c1d255d3SCy Schubert h = EVP_get_digestbynid(digest);
4177c1d255d3SCy Schubert if (!h)
4178c1d255d3SCy Schubert return -1;
4179c1d255d3SCy Schubert mac_key_len = EVP_MD_size(h);
4180c1d255d3SCy Schubert }
4181325151a3SRui Paulo
4182325151a3SRui Paulo wpa_printf(MSG_DEBUG,
4183c1d255d3SCy Schubert "OpenSSL: keyblock size: mac_key_len=%d enc_key_len=%d fixed_iv_len=%d",
4184c1d255d3SCy Schubert mac_key_len, enc_key_len, fixed_iv_len);
4185c1d255d3SCy Schubert return 2 * (mac_key_len + enc_key_len + fixed_iv_len);
4186325151a3SRui Paulo #endif
4187325151a3SRui Paulo }
4188780fb4a2SCy Schubert #endif /* OPENSSL_NEED_EAP_FAST_PRF */
4189325151a3SRui Paulo
4190325151a3SRui Paulo
tls_connection_export_key(void * tls_ctx,struct tls_connection * conn,const char * label,const u8 * context,size_t context_len,u8 * out,size_t out_len)4191780fb4a2SCy Schubert int tls_connection_export_key(void *tls_ctx, struct tls_connection *conn,
41924bc52338SCy Schubert const char *label, const u8 *context,
41934bc52338SCy Schubert size_t context_len, u8 *out, size_t out_len)
419439beb93cSSam Leffler {
4195780fb4a2SCy Schubert if (!conn ||
4196780fb4a2SCy Schubert SSL_export_keying_material(conn->ssl, out, out_len, label,
41974bc52338SCy Schubert os_strlen(label), context, context_len,
41984bc52338SCy Schubert context != NULL) != 1)
4199f05cddf9SRui Paulo return -1;
4200780fb4a2SCy Schubert return 0;
4201325151a3SRui Paulo }
4202325151a3SRui Paulo
4203325151a3SRui Paulo
tls_connection_get_eap_fast_key(void * tls_ctx,struct tls_connection * conn,u8 * out,size_t out_len)4204780fb4a2SCy Schubert int tls_connection_get_eap_fast_key(void *tls_ctx, struct tls_connection *conn,
4205780fb4a2SCy Schubert u8 *out, size_t out_len)
4206780fb4a2SCy Schubert {
4207780fb4a2SCy Schubert #ifdef OPENSSL_NEED_EAP_FAST_PRF
4208325151a3SRui Paulo SSL *ssl;
4209325151a3SRui Paulo SSL_SESSION *sess;
4210325151a3SRui Paulo u8 *rnd;
4211325151a3SRui Paulo int ret = -1;
4212325151a3SRui Paulo int skip = 0;
4213325151a3SRui Paulo u8 *tmp_out = NULL;
4214325151a3SRui Paulo u8 *_out = out;
4215325151a3SRui Paulo unsigned char client_random[SSL3_RANDOM_SIZE];
4216325151a3SRui Paulo unsigned char server_random[SSL3_RANDOM_SIZE];
4217325151a3SRui Paulo unsigned char master_key[64];
4218325151a3SRui Paulo size_t master_key_len;
4219325151a3SRui Paulo const char *ver;
4220325151a3SRui Paulo
4221325151a3SRui Paulo /*
4222780fb4a2SCy Schubert * TLS library did not support EAP-FAST key generation, so get the
4223780fb4a2SCy Schubert * needed TLS session parameters and use an internal implementation of
4224780fb4a2SCy Schubert * TLS PRF to derive the key.
4225325151a3SRui Paulo */
4226325151a3SRui Paulo
4227325151a3SRui Paulo if (conn == NULL)
4228325151a3SRui Paulo return -1;
4229325151a3SRui Paulo ssl = conn->ssl;
4230325151a3SRui Paulo if (ssl == NULL)
4231325151a3SRui Paulo return -1;
4232325151a3SRui Paulo ver = SSL_get_version(ssl);
4233325151a3SRui Paulo sess = SSL_get_session(ssl);
4234325151a3SRui Paulo if (!ver || !sess)
423539beb93cSSam Leffler return -1;
423639beb93cSSam Leffler
4237325151a3SRui Paulo skip = openssl_get_keyblock_size(ssl);
4238325151a3SRui Paulo if (skip < 0)
4239325151a3SRui Paulo return -1;
4240325151a3SRui Paulo tmp_out = os_malloc(skip + out_len);
4241325151a3SRui Paulo if (!tmp_out)
4242325151a3SRui Paulo return -1;
4243325151a3SRui Paulo _out = tmp_out;
424439beb93cSSam Leffler
4245325151a3SRui Paulo rnd = os_malloc(2 * SSL3_RANDOM_SIZE);
4246325151a3SRui Paulo if (!rnd) {
4247325151a3SRui Paulo os_free(tmp_out);
4248325151a3SRui Paulo return -1;
4249325151a3SRui Paulo }
4250325151a3SRui Paulo
4251325151a3SRui Paulo SSL_get_client_random(ssl, client_random, sizeof(client_random));
4252325151a3SRui Paulo SSL_get_server_random(ssl, server_random, sizeof(server_random));
4253325151a3SRui Paulo master_key_len = SSL_SESSION_get_master_key(sess, master_key,
4254325151a3SRui Paulo sizeof(master_key));
4255325151a3SRui Paulo
4256325151a3SRui Paulo os_memcpy(rnd, server_random, SSL3_RANDOM_SIZE);
4257780fb4a2SCy Schubert os_memcpy(rnd + SSL3_RANDOM_SIZE, client_random, SSL3_RANDOM_SIZE);
4258325151a3SRui Paulo
4259325151a3SRui Paulo if (os_strcmp(ver, "TLSv1.2") == 0) {
4260325151a3SRui Paulo tls_prf_sha256(master_key, master_key_len,
4261780fb4a2SCy Schubert "key expansion", rnd, 2 * SSL3_RANDOM_SIZE,
4262325151a3SRui Paulo _out, skip + out_len);
4263325151a3SRui Paulo ret = 0;
4264325151a3SRui Paulo } else if (tls_prf_sha1_md5(master_key, master_key_len,
4265780fb4a2SCy Schubert "key expansion", rnd, 2 * SSL3_RANDOM_SIZE,
4266325151a3SRui Paulo _out, skip + out_len) == 0) {
4267325151a3SRui Paulo ret = 0;
4268325151a3SRui Paulo }
4269206b73d0SCy Schubert forced_memzero(master_key, sizeof(master_key));
4270325151a3SRui Paulo os_free(rnd);
4271780fb4a2SCy Schubert if (ret == 0)
4272325151a3SRui Paulo os_memcpy(out, _out + skip, out_len);
4273325151a3SRui Paulo bin_clear_free(tmp_out, skip);
4274325151a3SRui Paulo
4275325151a3SRui Paulo return ret;
4276780fb4a2SCy Schubert #else /* OPENSSL_NEED_EAP_FAST_PRF */
4277780fb4a2SCy Schubert wpa_printf(MSG_ERROR,
4278780fb4a2SCy Schubert "OpenSSL: EAP-FAST keys cannot be exported in FIPS mode");
4279f05cddf9SRui Paulo return -1;
4280780fb4a2SCy Schubert #endif /* OPENSSL_NEED_EAP_FAST_PRF */
428139beb93cSSam Leffler }
428239beb93cSSam Leffler
428339beb93cSSam Leffler
4284e28a4053SRui Paulo static struct wpabuf *
openssl_handshake(struct tls_connection * conn,const struct wpabuf * in_data)428585732ac8SCy Schubert openssl_handshake(struct tls_connection *conn, const struct wpabuf *in_data)
428639beb93cSSam Leffler {
428739beb93cSSam Leffler int res;
4288e28a4053SRui Paulo struct wpabuf *out_data;
428939beb93cSSam Leffler
429039beb93cSSam Leffler /*
429139beb93cSSam Leffler * Give TLS handshake data from the server (if available) to OpenSSL
429239beb93cSSam Leffler * for processing.
429339beb93cSSam Leffler */
4294325151a3SRui Paulo if (in_data && wpabuf_len(in_data) > 0 &&
4295e28a4053SRui Paulo BIO_write(conn->ssl_in, wpabuf_head(in_data), wpabuf_len(in_data))
4296e28a4053SRui Paulo < 0) {
429739beb93cSSam Leffler tls_show_errors(MSG_INFO, __func__,
429839beb93cSSam Leffler "Handshake failed - BIO_write");
429939beb93cSSam Leffler return NULL;
430039beb93cSSam Leffler }
430139beb93cSSam Leffler
430239beb93cSSam Leffler /* Initiate TLS handshake or continue the existing handshake */
430385732ac8SCy Schubert if (conn->server)
4304e28a4053SRui Paulo res = SSL_accept(conn->ssl);
4305e28a4053SRui Paulo else
430639beb93cSSam Leffler res = SSL_connect(conn->ssl);
430739beb93cSSam Leffler if (res != 1) {
430839beb93cSSam Leffler int err = SSL_get_error(conn->ssl, res);
430939beb93cSSam Leffler if (err == SSL_ERROR_WANT_READ)
431039beb93cSSam Leffler wpa_printf(MSG_DEBUG, "SSL: SSL_connect - want "
431139beb93cSSam Leffler "more data");
431239beb93cSSam Leffler else if (err == SSL_ERROR_WANT_WRITE)
431339beb93cSSam Leffler wpa_printf(MSG_DEBUG, "SSL: SSL_connect - want to "
431439beb93cSSam Leffler "write");
431539beb93cSSam Leffler else {
431639beb93cSSam Leffler tls_show_errors(MSG_INFO, __func__, "SSL_connect");
431739beb93cSSam Leffler conn->failed++;
431885732ac8SCy Schubert if (!conn->server && !conn->client_hello_generated) {
431985732ac8SCy Schubert /* The server would not understand TLS Alert
432085732ac8SCy Schubert * before ClientHello, so simply terminate
432185732ac8SCy Schubert * handshake on this type of error case caused
432285732ac8SCy Schubert * by a likely internal error like no ciphers
432385732ac8SCy Schubert * available. */
432485732ac8SCy Schubert wpa_printf(MSG_DEBUG,
432585732ac8SCy Schubert "OpenSSL: Could not generate ClientHello");
432685732ac8SCy Schubert conn->write_alerts++;
432785732ac8SCy Schubert return NULL;
432839beb93cSSam Leffler }
432939beb93cSSam Leffler }
433085732ac8SCy Schubert }
433185732ac8SCy Schubert
433285732ac8SCy Schubert if (!conn->server && !conn->failed)
433385732ac8SCy Schubert conn->client_hello_generated = 1;
433485732ac8SCy Schubert
433585732ac8SCy Schubert #ifdef CONFIG_SUITEB
433685732ac8SCy Schubert if ((conn->flags & TLS_CONN_SUITEB) && !conn->server &&
433785732ac8SCy Schubert os_strncmp(SSL_get_cipher(conn->ssl), "DHE-", 4) == 0 &&
433885732ac8SCy Schubert conn->server_dh_prime_len < 3072) {
433985732ac8SCy Schubert struct tls_context *context = conn->context;
434085732ac8SCy Schubert
434185732ac8SCy Schubert /*
434285732ac8SCy Schubert * This should not be reached since earlier cert_cb should have
434385732ac8SCy Schubert * terminated the handshake. Keep this check here for extra
434485732ac8SCy Schubert * protection if anything goes wrong with the more low-level
434585732ac8SCy Schubert * checks based on having to parse the TLS handshake messages.
434685732ac8SCy Schubert */
434785732ac8SCy Schubert wpa_printf(MSG_DEBUG,
434885732ac8SCy Schubert "OpenSSL: Server DH prime length: %d bits",
434985732ac8SCy Schubert conn->server_dh_prime_len);
435085732ac8SCy Schubert
435185732ac8SCy Schubert if (context->event_cb) {
435285732ac8SCy Schubert union tls_event_data ev;
435385732ac8SCy Schubert
435485732ac8SCy Schubert os_memset(&ev, 0, sizeof(ev));
435585732ac8SCy Schubert ev.alert.is_local = 1;
435685732ac8SCy Schubert ev.alert.type = "fatal";
435785732ac8SCy Schubert ev.alert.description = "insufficient security";
435885732ac8SCy Schubert context->event_cb(context->cb_ctx, TLS_ALERT, &ev);
435985732ac8SCy Schubert }
436085732ac8SCy Schubert /*
436185732ac8SCy Schubert * Could send a TLS Alert to the server, but for now, simply
436285732ac8SCy Schubert * terminate handshake.
436385732ac8SCy Schubert */
436485732ac8SCy Schubert conn->failed++;
436585732ac8SCy Schubert conn->write_alerts++;
436685732ac8SCy Schubert return NULL;
436785732ac8SCy Schubert }
436885732ac8SCy Schubert #endif /* CONFIG_SUITEB */
436939beb93cSSam Leffler
437039beb93cSSam Leffler /* Get the TLS handshake data to be sent to the server */
437139beb93cSSam Leffler res = BIO_ctrl_pending(conn->ssl_out);
437239beb93cSSam Leffler wpa_printf(MSG_DEBUG, "SSL: %d bytes pending from ssl_out", res);
4373e28a4053SRui Paulo out_data = wpabuf_alloc(res);
437439beb93cSSam Leffler if (out_data == NULL) {
437539beb93cSSam Leffler wpa_printf(MSG_DEBUG, "SSL: Failed to allocate memory for "
437639beb93cSSam Leffler "handshake output (%d bytes)", res);
437739beb93cSSam Leffler if (BIO_reset(conn->ssl_out) < 0) {
437839beb93cSSam Leffler tls_show_errors(MSG_INFO, __func__,
437939beb93cSSam Leffler "BIO_reset failed");
438039beb93cSSam Leffler }
438139beb93cSSam Leffler return NULL;
438239beb93cSSam Leffler }
4383e28a4053SRui Paulo res = res == 0 ? 0 : BIO_read(conn->ssl_out, wpabuf_mhead(out_data),
4384e28a4053SRui Paulo res);
438539beb93cSSam Leffler if (res < 0) {
438639beb93cSSam Leffler tls_show_errors(MSG_INFO, __func__,
438739beb93cSSam Leffler "Handshake failed - BIO_read");
438839beb93cSSam Leffler if (BIO_reset(conn->ssl_out) < 0) {
438939beb93cSSam Leffler tls_show_errors(MSG_INFO, __func__,
439039beb93cSSam Leffler "BIO_reset failed");
439139beb93cSSam Leffler }
4392e28a4053SRui Paulo wpabuf_free(out_data);
439339beb93cSSam Leffler return NULL;
439439beb93cSSam Leffler }
4395e28a4053SRui Paulo wpabuf_put(out_data, res);
439639beb93cSSam Leffler
4397e28a4053SRui Paulo return out_data;
4398e28a4053SRui Paulo }
4399e28a4053SRui Paulo
4400e28a4053SRui Paulo
4401e28a4053SRui Paulo static struct wpabuf *
openssl_get_appl_data(struct tls_connection * conn,size_t max_len)4402e28a4053SRui Paulo openssl_get_appl_data(struct tls_connection *conn, size_t max_len)
4403e28a4053SRui Paulo {
4404e28a4053SRui Paulo struct wpabuf *appl_data;
4405e28a4053SRui Paulo int res;
4406e28a4053SRui Paulo
4407e28a4053SRui Paulo appl_data = wpabuf_alloc(max_len + 100);
4408e28a4053SRui Paulo if (appl_data == NULL)
4409e28a4053SRui Paulo return NULL;
4410e28a4053SRui Paulo
4411e28a4053SRui Paulo res = SSL_read(conn->ssl, wpabuf_mhead(appl_data),
4412e28a4053SRui Paulo wpabuf_size(appl_data));
441339beb93cSSam Leffler if (res < 0) {
44143157ba21SRui Paulo int err = SSL_get_error(conn->ssl, res);
44153157ba21SRui Paulo if (err == SSL_ERROR_WANT_READ ||
44163157ba21SRui Paulo err == SSL_ERROR_WANT_WRITE) {
4417e28a4053SRui Paulo wpa_printf(MSG_DEBUG, "SSL: No Application Data "
44183157ba21SRui Paulo "included");
44193157ba21SRui Paulo } else {
442039beb93cSSam Leffler tls_show_errors(MSG_INFO, __func__,
4421e28a4053SRui Paulo "Failed to read possible "
442239beb93cSSam Leffler "Application Data");
44233157ba21SRui Paulo }
4424e28a4053SRui Paulo wpabuf_free(appl_data);
4425e28a4053SRui Paulo return NULL;
4426e28a4053SRui Paulo }
4427e28a4053SRui Paulo
4428e28a4053SRui Paulo wpabuf_put(appl_data, res);
4429e28a4053SRui Paulo wpa_hexdump_buf_key(MSG_MSGDUMP, "SSL: Application Data in Finished "
4430e28a4053SRui Paulo "message", appl_data);
4431e28a4053SRui Paulo
4432e28a4053SRui Paulo return appl_data;
4433e28a4053SRui Paulo }
4434e28a4053SRui Paulo
4435e28a4053SRui Paulo
4436e28a4053SRui Paulo static struct wpabuf *
openssl_connection_handshake(struct tls_connection * conn,const struct wpabuf * in_data,struct wpabuf ** appl_data)4437e28a4053SRui Paulo openssl_connection_handshake(struct tls_connection *conn,
4438e28a4053SRui Paulo const struct wpabuf *in_data,
443985732ac8SCy Schubert struct wpabuf **appl_data)
4440e28a4053SRui Paulo {
4441e28a4053SRui Paulo struct wpabuf *out_data;
4442e28a4053SRui Paulo
4443e28a4053SRui Paulo if (appl_data)
444439beb93cSSam Leffler *appl_data = NULL;
4445e28a4053SRui Paulo
444685732ac8SCy Schubert out_data = openssl_handshake(conn, in_data);
4447e28a4053SRui Paulo if (out_data == NULL)
4448e28a4053SRui Paulo return NULL;
44495b9c547cSRui Paulo if (conn->invalid_hb_used) {
44505b9c547cSRui Paulo wpa_printf(MSG_INFO, "TLS: Heartbeat attack detected - do not send response");
44515b9c547cSRui Paulo wpabuf_free(out_data);
44525b9c547cSRui Paulo return NULL;
44535b9c547cSRui Paulo }
4454e28a4053SRui Paulo
4455325151a3SRui Paulo if (SSL_is_init_finished(conn->ssl)) {
4456325151a3SRui Paulo wpa_printf(MSG_DEBUG,
4457325151a3SRui Paulo "OpenSSL: Handshake finished - resumed=%d",
4458325151a3SRui Paulo tls_connection_resumed(conn->ssl_ctx, conn));
4459206b73d0SCy Schubert if (conn->server) {
4460206b73d0SCy Schubert char *buf;
4461206b73d0SCy Schubert size_t buflen = 2000;
4462206b73d0SCy Schubert
4463206b73d0SCy Schubert buf = os_malloc(buflen);
4464206b73d0SCy Schubert if (buf) {
4465206b73d0SCy Schubert if (SSL_get_shared_ciphers(conn->ssl, buf,
4466206b73d0SCy Schubert buflen)) {
4467206b73d0SCy Schubert buf[buflen - 1] = '\0';
4468206b73d0SCy Schubert wpa_printf(MSG_DEBUG,
4469206b73d0SCy Schubert "OpenSSL: Shared ciphers: %s",
4470206b73d0SCy Schubert buf);
4471206b73d0SCy Schubert }
4472206b73d0SCy Schubert os_free(buf);
4473206b73d0SCy Schubert }
4474206b73d0SCy Schubert }
4475325151a3SRui Paulo if (appl_data && in_data)
4476325151a3SRui Paulo *appl_data = openssl_get_appl_data(conn,
4477325151a3SRui Paulo wpabuf_len(in_data));
4478325151a3SRui Paulo }
447939beb93cSSam Leffler
44805b9c547cSRui Paulo if (conn->invalid_hb_used) {
44815b9c547cSRui Paulo wpa_printf(MSG_INFO, "TLS: Heartbeat attack detected - do not send response");
44825b9c547cSRui Paulo if (appl_data) {
44835b9c547cSRui Paulo wpabuf_free(*appl_data);
44845b9c547cSRui Paulo *appl_data = NULL;
44855b9c547cSRui Paulo }
44865b9c547cSRui Paulo wpabuf_free(out_data);
44875b9c547cSRui Paulo return NULL;
44885b9c547cSRui Paulo }
44895b9c547cSRui Paulo
449039beb93cSSam Leffler return out_data;
449139beb93cSSam Leffler }
449239beb93cSSam Leffler
449339beb93cSSam Leffler
4494e28a4053SRui Paulo struct wpabuf *
tls_connection_handshake(void * ssl_ctx,struct tls_connection * conn,const struct wpabuf * in_data,struct wpabuf ** appl_data)4495e28a4053SRui Paulo tls_connection_handshake(void *ssl_ctx, struct tls_connection *conn,
4496e28a4053SRui Paulo const struct wpabuf *in_data,
4497e28a4053SRui Paulo struct wpabuf **appl_data)
4498e28a4053SRui Paulo {
449985732ac8SCy Schubert return openssl_connection_handshake(conn, in_data, appl_data);
4500e28a4053SRui Paulo }
4501e28a4053SRui Paulo
4502e28a4053SRui Paulo
tls_connection_server_handshake(void * tls_ctx,struct tls_connection * conn,const struct wpabuf * in_data,struct wpabuf ** appl_data)4503e28a4053SRui Paulo struct wpabuf * tls_connection_server_handshake(void *tls_ctx,
450439beb93cSSam Leffler struct tls_connection *conn,
4505e28a4053SRui Paulo const struct wpabuf *in_data,
4506e28a4053SRui Paulo struct wpabuf **appl_data)
4507e28a4053SRui Paulo {
450885732ac8SCy Schubert conn->server = 1;
450985732ac8SCy Schubert return openssl_connection_handshake(conn, in_data, appl_data);
4510e28a4053SRui Paulo }
4511e28a4053SRui Paulo
4512e28a4053SRui Paulo
tls_connection_encrypt(void * tls_ctx,struct tls_connection * conn,const struct wpabuf * in_data)4513e28a4053SRui Paulo struct wpabuf * tls_connection_encrypt(void *tls_ctx,
4514e28a4053SRui Paulo struct tls_connection *conn,
4515e28a4053SRui Paulo const struct wpabuf *in_data)
451639beb93cSSam Leffler {
451739beb93cSSam Leffler int res;
4518e28a4053SRui Paulo struct wpabuf *buf;
451939beb93cSSam Leffler
452039beb93cSSam Leffler if (conn == NULL)
4521e28a4053SRui Paulo return NULL;
452239beb93cSSam Leffler
452339beb93cSSam Leffler /* Give plaintext data for OpenSSL to encrypt into the TLS tunnel. */
452439beb93cSSam Leffler if ((res = BIO_reset(conn->ssl_in)) < 0 ||
452539beb93cSSam Leffler (res = BIO_reset(conn->ssl_out)) < 0) {
452639beb93cSSam Leffler tls_show_errors(MSG_INFO, __func__, "BIO_reset failed");
4527e28a4053SRui Paulo return NULL;
452839beb93cSSam Leffler }
4529e28a4053SRui Paulo res = SSL_write(conn->ssl, wpabuf_head(in_data), wpabuf_len(in_data));
453039beb93cSSam Leffler if (res < 0) {
453139beb93cSSam Leffler tls_show_errors(MSG_INFO, __func__,
453239beb93cSSam Leffler "Encryption failed - SSL_write");
4533e28a4053SRui Paulo return NULL;
453439beb93cSSam Leffler }
453539beb93cSSam Leffler
453639beb93cSSam Leffler /* Read encrypted data to be sent to the server */
4537e28a4053SRui Paulo buf = wpabuf_alloc(wpabuf_len(in_data) + 300);
4538e28a4053SRui Paulo if (buf == NULL)
4539e28a4053SRui Paulo return NULL;
4540e28a4053SRui Paulo res = BIO_read(conn->ssl_out, wpabuf_mhead(buf), wpabuf_size(buf));
454139beb93cSSam Leffler if (res < 0) {
454239beb93cSSam Leffler tls_show_errors(MSG_INFO, __func__,
454339beb93cSSam Leffler "Encryption failed - BIO_read");
4544e28a4053SRui Paulo wpabuf_free(buf);
4545e28a4053SRui Paulo return NULL;
454639beb93cSSam Leffler }
4547e28a4053SRui Paulo wpabuf_put(buf, res);
454839beb93cSSam Leffler
4549e28a4053SRui Paulo return buf;
455039beb93cSSam Leffler }
455139beb93cSSam Leffler
455239beb93cSSam Leffler
tls_connection_decrypt(void * tls_ctx,struct tls_connection * conn,const struct wpabuf * in_data)4553e28a4053SRui Paulo struct wpabuf * tls_connection_decrypt(void *tls_ctx,
4554e28a4053SRui Paulo struct tls_connection *conn,
4555e28a4053SRui Paulo const struct wpabuf *in_data)
455639beb93cSSam Leffler {
455739beb93cSSam Leffler int res;
4558e28a4053SRui Paulo struct wpabuf *buf;
455939beb93cSSam Leffler
456039beb93cSSam Leffler /* Give encrypted data from TLS tunnel for OpenSSL to decrypt. */
4561e28a4053SRui Paulo res = BIO_write(conn->ssl_in, wpabuf_head(in_data),
4562e28a4053SRui Paulo wpabuf_len(in_data));
456339beb93cSSam Leffler if (res < 0) {
456439beb93cSSam Leffler tls_show_errors(MSG_INFO, __func__,
456539beb93cSSam Leffler "Decryption failed - BIO_write");
4566e28a4053SRui Paulo return NULL;
456739beb93cSSam Leffler }
456839beb93cSSam Leffler if (BIO_reset(conn->ssl_out) < 0) {
456939beb93cSSam Leffler tls_show_errors(MSG_INFO, __func__, "BIO_reset failed");
4570e28a4053SRui Paulo return NULL;
457139beb93cSSam Leffler }
457239beb93cSSam Leffler
457339beb93cSSam Leffler /* Read decrypted data for further processing */
4574e28a4053SRui Paulo /*
4575e28a4053SRui Paulo * Even though we try to disable TLS compression, it is possible that
4576e28a4053SRui Paulo * this cannot be done with all TLS libraries. Add extra buffer space
4577e28a4053SRui Paulo * to handle the possibility of the decrypted data being longer than
4578e28a4053SRui Paulo * input data.
4579e28a4053SRui Paulo */
4580e28a4053SRui Paulo buf = wpabuf_alloc((wpabuf_len(in_data) + 500) * 3);
4581e28a4053SRui Paulo if (buf == NULL)
4582e28a4053SRui Paulo return NULL;
4583e28a4053SRui Paulo res = SSL_read(conn->ssl, wpabuf_mhead(buf), wpabuf_size(buf));
458439beb93cSSam Leffler if (res < 0) {
4585c1d255d3SCy Schubert int err = SSL_get_error(conn->ssl, res);
4586c1d255d3SCy Schubert
4587c1d255d3SCy Schubert if (err == SSL_ERROR_WANT_READ) {
4588c1d255d3SCy Schubert wpa_printf(MSG_DEBUG,
4589c1d255d3SCy Schubert "SSL: SSL_connect - want more data");
4590c1d255d3SCy Schubert res = 0;
4591c1d255d3SCy Schubert } else {
459239beb93cSSam Leffler tls_show_errors(MSG_INFO, __func__,
459339beb93cSSam Leffler "Decryption failed - SSL_read");
4594e28a4053SRui Paulo wpabuf_free(buf);
4595e28a4053SRui Paulo return NULL;
459639beb93cSSam Leffler }
4597c1d255d3SCy Schubert }
4598e28a4053SRui Paulo wpabuf_put(buf, res);
459939beb93cSSam Leffler
46005b9c547cSRui Paulo if (conn->invalid_hb_used) {
46015b9c547cSRui Paulo wpa_printf(MSG_INFO, "TLS: Heartbeat attack detected - do not send response");
46025b9c547cSRui Paulo wpabuf_free(buf);
46035b9c547cSRui Paulo return NULL;
46045b9c547cSRui Paulo }
46055b9c547cSRui Paulo
4606e28a4053SRui Paulo return buf;
460739beb93cSSam Leffler }
460839beb93cSSam Leffler
460939beb93cSSam Leffler
tls_connection_resumed(void * ssl_ctx,struct tls_connection * conn)461039beb93cSSam Leffler int tls_connection_resumed(void *ssl_ctx, struct tls_connection *conn)
461139beb93cSSam Leffler {
461285732ac8SCy Schubert return conn ? SSL_session_reused(conn->ssl) : 0;
461339beb93cSSam Leffler }
461439beb93cSSam Leffler
461539beb93cSSam Leffler
tls_connection_set_cipher_list(void * tls_ctx,struct tls_connection * conn,u8 * ciphers)461639beb93cSSam Leffler int tls_connection_set_cipher_list(void *tls_ctx, struct tls_connection *conn,
461739beb93cSSam Leffler u8 *ciphers)
461839beb93cSSam Leffler {
4619780fb4a2SCy Schubert char buf[500], *pos, *end;
462039beb93cSSam Leffler u8 *c;
462139beb93cSSam Leffler int ret;
462239beb93cSSam Leffler
462339beb93cSSam Leffler if (conn == NULL || conn->ssl == NULL || ciphers == NULL)
462439beb93cSSam Leffler return -1;
462539beb93cSSam Leffler
462639beb93cSSam Leffler buf[0] = '\0';
462739beb93cSSam Leffler pos = buf;
462839beb93cSSam Leffler end = pos + sizeof(buf);
462939beb93cSSam Leffler
463039beb93cSSam Leffler c = ciphers;
463139beb93cSSam Leffler while (*c != TLS_CIPHER_NONE) {
463239beb93cSSam Leffler const char *suite;
463339beb93cSSam Leffler
463439beb93cSSam Leffler switch (*c) {
463539beb93cSSam Leffler case TLS_CIPHER_RC4_SHA:
463639beb93cSSam Leffler suite = "RC4-SHA";
463739beb93cSSam Leffler break;
463839beb93cSSam Leffler case TLS_CIPHER_AES128_SHA:
463939beb93cSSam Leffler suite = "AES128-SHA";
464039beb93cSSam Leffler break;
464139beb93cSSam Leffler case TLS_CIPHER_RSA_DHE_AES128_SHA:
464239beb93cSSam Leffler suite = "DHE-RSA-AES128-SHA";
464339beb93cSSam Leffler break;
464439beb93cSSam Leffler case TLS_CIPHER_ANON_DH_AES128_SHA:
464539beb93cSSam Leffler suite = "ADH-AES128-SHA";
464639beb93cSSam Leffler break;
4647780fb4a2SCy Schubert case TLS_CIPHER_RSA_DHE_AES256_SHA:
4648780fb4a2SCy Schubert suite = "DHE-RSA-AES256-SHA";
4649780fb4a2SCy Schubert break;
4650780fb4a2SCy Schubert case TLS_CIPHER_AES256_SHA:
4651780fb4a2SCy Schubert suite = "AES256-SHA";
4652780fb4a2SCy Schubert break;
465339beb93cSSam Leffler default:
465439beb93cSSam Leffler wpa_printf(MSG_DEBUG, "TLS: Unsupported "
465539beb93cSSam Leffler "cipher selection: %d", *c);
465639beb93cSSam Leffler return -1;
465739beb93cSSam Leffler }
465839beb93cSSam Leffler ret = os_snprintf(pos, end - pos, ":%s", suite);
46595b9c547cSRui Paulo if (os_snprintf_error(end - pos, ret))
466039beb93cSSam Leffler break;
466139beb93cSSam Leffler pos += ret;
466239beb93cSSam Leffler
466339beb93cSSam Leffler c++;
466439beb93cSSam Leffler }
4665206b73d0SCy Schubert if (!buf[0]) {
4666206b73d0SCy Schubert wpa_printf(MSG_DEBUG, "OpenSSL: No ciphers listed");
4667206b73d0SCy Schubert return -1;
4668206b73d0SCy Schubert }
466939beb93cSSam Leffler
467039beb93cSSam Leffler wpa_printf(MSG_DEBUG, "OpenSSL: cipher suites: %s", buf + 1);
467139beb93cSSam Leffler
4672780fb4a2SCy Schubert #if OPENSSL_VERSION_NUMBER >= 0x10100000L && !defined(LIBRESSL_VERSION_NUMBER)
4673206b73d0SCy Schubert #ifdef EAP_FAST_OR_TEAP
4674325151a3SRui Paulo if (os_strstr(buf, ":ADH-")) {
4675325151a3SRui Paulo /*
4676325151a3SRui Paulo * Need to drop to security level 0 to allow anonymous
4677325151a3SRui Paulo * cipher suites for EAP-FAST.
4678325151a3SRui Paulo */
4679325151a3SRui Paulo SSL_set_security_level(conn->ssl, 0);
4680325151a3SRui Paulo } else if (SSL_get_security_level(conn->ssl) == 0) {
4681325151a3SRui Paulo /* Force at least security level 1 */
4682325151a3SRui Paulo SSL_set_security_level(conn->ssl, 1);
4683325151a3SRui Paulo }
4684206b73d0SCy Schubert #endif /* EAP_FAST_OR_TEAP */
4685325151a3SRui Paulo #endif
4686325151a3SRui Paulo
468739beb93cSSam Leffler if (SSL_set_cipher_list(conn->ssl, buf + 1) != 1) {
468839beb93cSSam Leffler tls_show_errors(MSG_INFO, __func__,
468939beb93cSSam Leffler "Cipher suite configuration failed");
469039beb93cSSam Leffler return -1;
469139beb93cSSam Leffler }
469239beb93cSSam Leffler
469339beb93cSSam Leffler return 0;
469439beb93cSSam Leffler }
469539beb93cSSam Leffler
469639beb93cSSam Leffler
tls_get_version(void * ssl_ctx,struct tls_connection * conn,char * buf,size_t buflen)4697325151a3SRui Paulo int tls_get_version(void *ssl_ctx, struct tls_connection *conn,
4698325151a3SRui Paulo char *buf, size_t buflen)
4699325151a3SRui Paulo {
4700325151a3SRui Paulo const char *name;
4701325151a3SRui Paulo if (conn == NULL || conn->ssl == NULL)
4702325151a3SRui Paulo return -1;
4703325151a3SRui Paulo
4704325151a3SRui Paulo name = SSL_get_version(conn->ssl);
4705325151a3SRui Paulo if (name == NULL)
4706325151a3SRui Paulo return -1;
4707325151a3SRui Paulo
4708325151a3SRui Paulo os_strlcpy(buf, name, buflen);
4709325151a3SRui Paulo return 0;
4710325151a3SRui Paulo }
4711325151a3SRui Paulo
4712325151a3SRui Paulo
tls_get_cipher(void * ssl_ctx,struct tls_connection * conn,char * buf,size_t buflen)471339beb93cSSam Leffler int tls_get_cipher(void *ssl_ctx, struct tls_connection *conn,
471439beb93cSSam Leffler char *buf, size_t buflen)
471539beb93cSSam Leffler {
471639beb93cSSam Leffler const char *name;
471739beb93cSSam Leffler if (conn == NULL || conn->ssl == NULL)
471839beb93cSSam Leffler return -1;
471939beb93cSSam Leffler
472039beb93cSSam Leffler name = SSL_get_cipher(conn->ssl);
472139beb93cSSam Leffler if (name == NULL)
472239beb93cSSam Leffler return -1;
472339beb93cSSam Leffler
472439beb93cSSam Leffler os_strlcpy(buf, name, buflen);
472539beb93cSSam Leffler return 0;
472639beb93cSSam Leffler }
472739beb93cSSam Leffler
472839beb93cSSam Leffler
tls_connection_enable_workaround(void * ssl_ctx,struct tls_connection * conn)472939beb93cSSam Leffler int tls_connection_enable_workaround(void *ssl_ctx,
473039beb93cSSam Leffler struct tls_connection *conn)
473139beb93cSSam Leffler {
473239beb93cSSam Leffler SSL_set_options(conn->ssl, SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS);
473339beb93cSSam Leffler
473439beb93cSSam Leffler return 0;
473539beb93cSSam Leffler }
473639beb93cSSam Leffler
473739beb93cSSam Leffler
4738206b73d0SCy Schubert #ifdef EAP_FAST_OR_TEAP
473939beb93cSSam Leffler /* ClientHello TLS extensions require a patch to openssl, so this function is
474039beb93cSSam Leffler * commented out unless explicitly needed for EAP-FAST in order to be able to
474139beb93cSSam Leffler * build this file with unmodified openssl. */
tls_connection_client_hello_ext(void * ssl_ctx,struct tls_connection * conn,int ext_type,const u8 * data,size_t data_len)474239beb93cSSam Leffler int tls_connection_client_hello_ext(void *ssl_ctx, struct tls_connection *conn,
474339beb93cSSam Leffler int ext_type, const u8 *data,
474439beb93cSSam Leffler size_t data_len)
474539beb93cSSam Leffler {
474639beb93cSSam Leffler if (conn == NULL || conn->ssl == NULL || ext_type != 35)
474739beb93cSSam Leffler return -1;
474839beb93cSSam Leffler
474939beb93cSSam Leffler if (SSL_set_session_ticket_ext(conn->ssl, (void *) data,
475039beb93cSSam Leffler data_len) != 1)
475139beb93cSSam Leffler return -1;
475239beb93cSSam Leffler
475339beb93cSSam Leffler return 0;
475439beb93cSSam Leffler }
4755206b73d0SCy Schubert #endif /* EAP_FAST_OR_TEAP */
475639beb93cSSam Leffler
475739beb93cSSam Leffler
tls_connection_get_failed(void * ssl_ctx,struct tls_connection * conn)475839beb93cSSam Leffler int tls_connection_get_failed(void *ssl_ctx, struct tls_connection *conn)
475939beb93cSSam Leffler {
476039beb93cSSam Leffler if (conn == NULL)
476139beb93cSSam Leffler return -1;
476239beb93cSSam Leffler return conn->failed;
476339beb93cSSam Leffler }
476439beb93cSSam Leffler
476539beb93cSSam Leffler
tls_connection_get_read_alerts(void * ssl_ctx,struct tls_connection * conn)476639beb93cSSam Leffler int tls_connection_get_read_alerts(void *ssl_ctx, struct tls_connection *conn)
476739beb93cSSam Leffler {
476839beb93cSSam Leffler if (conn == NULL)
476939beb93cSSam Leffler return -1;
477039beb93cSSam Leffler return conn->read_alerts;
477139beb93cSSam Leffler }
477239beb93cSSam Leffler
477339beb93cSSam Leffler
tls_connection_get_write_alerts(void * ssl_ctx,struct tls_connection * conn)477439beb93cSSam Leffler int tls_connection_get_write_alerts(void *ssl_ctx, struct tls_connection *conn)
477539beb93cSSam Leffler {
477639beb93cSSam Leffler if (conn == NULL)
477739beb93cSSam Leffler return -1;
477839beb93cSSam Leffler return conn->write_alerts;
477939beb93cSSam Leffler }
478039beb93cSSam Leffler
478139beb93cSSam Leffler
47825b9c547cSRui Paulo #ifdef HAVE_OCSP
47835b9c547cSRui Paulo
ocsp_debug_print_resp(OCSP_RESPONSE * rsp)47845b9c547cSRui Paulo static void ocsp_debug_print_resp(OCSP_RESPONSE *rsp)
47855b9c547cSRui Paulo {
47865b9c547cSRui Paulo #ifndef CONFIG_NO_STDOUT_DEBUG
47875b9c547cSRui Paulo BIO *out;
47885b9c547cSRui Paulo size_t rlen;
47895b9c547cSRui Paulo char *txt;
47905b9c547cSRui Paulo int res;
47915b9c547cSRui Paulo
47925b9c547cSRui Paulo if (wpa_debug_level > MSG_DEBUG)
47935b9c547cSRui Paulo return;
47945b9c547cSRui Paulo
47955b9c547cSRui Paulo out = BIO_new(BIO_s_mem());
47965b9c547cSRui Paulo if (!out)
47975b9c547cSRui Paulo return;
47985b9c547cSRui Paulo
47995b9c547cSRui Paulo OCSP_RESPONSE_print(out, rsp, 0);
48005b9c547cSRui Paulo rlen = BIO_ctrl_pending(out);
48015b9c547cSRui Paulo txt = os_malloc(rlen + 1);
48025b9c547cSRui Paulo if (!txt) {
48035b9c547cSRui Paulo BIO_free(out);
48045b9c547cSRui Paulo return;
48055b9c547cSRui Paulo }
48065b9c547cSRui Paulo
48075b9c547cSRui Paulo res = BIO_read(out, txt, rlen);
48085b9c547cSRui Paulo if (res > 0) {
48095b9c547cSRui Paulo txt[res] = '\0';
48105b9c547cSRui Paulo wpa_printf(MSG_DEBUG, "OpenSSL: OCSP Response\n%s", txt);
48115b9c547cSRui Paulo }
48125b9c547cSRui Paulo os_free(txt);
48135b9c547cSRui Paulo BIO_free(out);
48145b9c547cSRui Paulo #endif /* CONFIG_NO_STDOUT_DEBUG */
48155b9c547cSRui Paulo }
48165b9c547cSRui Paulo
48175b9c547cSRui Paulo
ocsp_resp_cb(SSL * s,void * arg)48185b9c547cSRui Paulo static int ocsp_resp_cb(SSL *s, void *arg)
48195b9c547cSRui Paulo {
48205b9c547cSRui Paulo struct tls_connection *conn = arg;
48215b9c547cSRui Paulo const unsigned char *p;
482285732ac8SCy Schubert int len, status, reason, res;
48235b9c547cSRui Paulo OCSP_RESPONSE *rsp;
48245b9c547cSRui Paulo OCSP_BASICRESP *basic;
48255b9c547cSRui Paulo OCSP_CERTID *id;
48265b9c547cSRui Paulo ASN1_GENERALIZEDTIME *produced_at, *this_update, *next_update;
48275b9c547cSRui Paulo X509_STORE *store;
48285b9c547cSRui Paulo STACK_OF(X509) *certs = NULL;
48295b9c547cSRui Paulo
48305b9c547cSRui Paulo len = SSL_get_tlsext_status_ocsp_resp(s, &p);
48315b9c547cSRui Paulo if (!p) {
48325b9c547cSRui Paulo wpa_printf(MSG_DEBUG, "OpenSSL: No OCSP response received");
48335b9c547cSRui Paulo return (conn->flags & TLS_CONN_REQUIRE_OCSP) ? 0 : 1;
48345b9c547cSRui Paulo }
48355b9c547cSRui Paulo
48365b9c547cSRui Paulo wpa_hexdump(MSG_DEBUG, "OpenSSL: OCSP response", p, len);
48375b9c547cSRui Paulo
48385b9c547cSRui Paulo rsp = d2i_OCSP_RESPONSE(NULL, &p, len);
48395b9c547cSRui Paulo if (!rsp) {
48405b9c547cSRui Paulo wpa_printf(MSG_INFO, "OpenSSL: Failed to parse OCSP response");
48415b9c547cSRui Paulo return 0;
48425b9c547cSRui Paulo }
48435b9c547cSRui Paulo
48445b9c547cSRui Paulo ocsp_debug_print_resp(rsp);
48455b9c547cSRui Paulo
48465b9c547cSRui Paulo status = OCSP_response_status(rsp);
48475b9c547cSRui Paulo if (status != OCSP_RESPONSE_STATUS_SUCCESSFUL) {
48485b9c547cSRui Paulo wpa_printf(MSG_INFO, "OpenSSL: OCSP responder error %d (%s)",
48495b9c547cSRui Paulo status, OCSP_response_status_str(status));
48505b9c547cSRui Paulo return 0;
48515b9c547cSRui Paulo }
48525b9c547cSRui Paulo
48535b9c547cSRui Paulo basic = OCSP_response_get1_basic(rsp);
48545b9c547cSRui Paulo if (!basic) {
48555b9c547cSRui Paulo wpa_printf(MSG_INFO, "OpenSSL: Could not find BasicOCSPResponse");
48565b9c547cSRui Paulo return 0;
48575b9c547cSRui Paulo }
48585b9c547cSRui Paulo
48595b9c547cSRui Paulo store = SSL_CTX_get_cert_store(conn->ssl_ctx);
48605b9c547cSRui Paulo if (conn->peer_issuer) {
48615b9c547cSRui Paulo debug_print_cert(conn->peer_issuer, "Add OCSP issuer");
48625b9c547cSRui Paulo
48635b9c547cSRui Paulo if (X509_STORE_add_cert(store, conn->peer_issuer) != 1) {
48645b9c547cSRui Paulo tls_show_errors(MSG_INFO, __func__,
48655b9c547cSRui Paulo "OpenSSL: Could not add issuer to certificate store");
48665b9c547cSRui Paulo }
48675b9c547cSRui Paulo certs = sk_X509_new_null();
48685b9c547cSRui Paulo if (certs) {
48695b9c547cSRui Paulo X509 *cert;
48705b9c547cSRui Paulo cert = X509_dup(conn->peer_issuer);
48715b9c547cSRui Paulo if (cert && !sk_X509_push(certs, cert)) {
48725b9c547cSRui Paulo tls_show_errors(
48735b9c547cSRui Paulo MSG_INFO, __func__,
48745b9c547cSRui Paulo "OpenSSL: Could not add issuer to OCSP responder trust store");
48755b9c547cSRui Paulo X509_free(cert);
48765b9c547cSRui Paulo sk_X509_free(certs);
48775b9c547cSRui Paulo certs = NULL;
48785b9c547cSRui Paulo }
48795b9c547cSRui Paulo if (certs && conn->peer_issuer_issuer) {
48805b9c547cSRui Paulo cert = X509_dup(conn->peer_issuer_issuer);
48815b9c547cSRui Paulo if (cert && !sk_X509_push(certs, cert)) {
48825b9c547cSRui Paulo tls_show_errors(
48835b9c547cSRui Paulo MSG_INFO, __func__,
48845b9c547cSRui Paulo "OpenSSL: Could not add issuer's issuer to OCSP responder trust store");
48855b9c547cSRui Paulo X509_free(cert);
48865b9c547cSRui Paulo }
48875b9c547cSRui Paulo }
48885b9c547cSRui Paulo }
48895b9c547cSRui Paulo }
48905b9c547cSRui Paulo
48915b9c547cSRui Paulo status = OCSP_basic_verify(basic, certs, store, OCSP_TRUSTOTHER);
48925b9c547cSRui Paulo sk_X509_pop_free(certs, X509_free);
48935b9c547cSRui Paulo if (status <= 0) {
48945b9c547cSRui Paulo tls_show_errors(MSG_INFO, __func__,
48955b9c547cSRui Paulo "OpenSSL: OCSP response failed verification");
48965b9c547cSRui Paulo OCSP_BASICRESP_free(basic);
48975b9c547cSRui Paulo OCSP_RESPONSE_free(rsp);
48985b9c547cSRui Paulo return 0;
48995b9c547cSRui Paulo }
49005b9c547cSRui Paulo
49015b9c547cSRui Paulo wpa_printf(MSG_DEBUG, "OpenSSL: OCSP response verification succeeded");
49025b9c547cSRui Paulo
49035b9c547cSRui Paulo if (!conn->peer_cert) {
49045b9c547cSRui Paulo wpa_printf(MSG_DEBUG, "OpenSSL: Peer certificate not available for OCSP status check");
49055b9c547cSRui Paulo OCSP_BASICRESP_free(basic);
49065b9c547cSRui Paulo OCSP_RESPONSE_free(rsp);
49075b9c547cSRui Paulo return 0;
49085b9c547cSRui Paulo }
49095b9c547cSRui Paulo
49105b9c547cSRui Paulo if (!conn->peer_issuer) {
49115b9c547cSRui Paulo wpa_printf(MSG_DEBUG, "OpenSSL: Peer issuer certificate not available for OCSP status check");
49125b9c547cSRui Paulo OCSP_BASICRESP_free(basic);
49135b9c547cSRui Paulo OCSP_RESPONSE_free(rsp);
49145b9c547cSRui Paulo return 0;
49155b9c547cSRui Paulo }
49165b9c547cSRui Paulo
491785732ac8SCy Schubert id = OCSP_cert_to_id(EVP_sha256(), conn->peer_cert, conn->peer_issuer);
49185b9c547cSRui Paulo if (!id) {
491985732ac8SCy Schubert wpa_printf(MSG_DEBUG,
492085732ac8SCy Schubert "OpenSSL: Could not create OCSP certificate identifier (SHA256)");
49215b9c547cSRui Paulo OCSP_BASICRESP_free(basic);
49225b9c547cSRui Paulo OCSP_RESPONSE_free(rsp);
49235b9c547cSRui Paulo return 0;
49245b9c547cSRui Paulo }
49255b9c547cSRui Paulo
492685732ac8SCy Schubert res = OCSP_resp_find_status(basic, id, &status, &reason, &produced_at,
492785732ac8SCy Schubert &this_update, &next_update);
492885732ac8SCy Schubert if (!res) {
4929206b73d0SCy Schubert OCSP_CERTID_free(id);
493085732ac8SCy Schubert id = OCSP_cert_to_id(NULL, conn->peer_cert, conn->peer_issuer);
493185732ac8SCy Schubert if (!id) {
493285732ac8SCy Schubert wpa_printf(MSG_DEBUG,
493385732ac8SCy Schubert "OpenSSL: Could not create OCSP certificate identifier (SHA1)");
493485732ac8SCy Schubert OCSP_BASICRESP_free(basic);
493585732ac8SCy Schubert OCSP_RESPONSE_free(rsp);
493685732ac8SCy Schubert return 0;
493785732ac8SCy Schubert }
493885732ac8SCy Schubert
493985732ac8SCy Schubert res = OCSP_resp_find_status(basic, id, &status, &reason,
494085732ac8SCy Schubert &produced_at, &this_update,
494185732ac8SCy Schubert &next_update);
494285732ac8SCy Schubert }
494385732ac8SCy Schubert
494485732ac8SCy Schubert if (!res) {
49455b9c547cSRui Paulo wpa_printf(MSG_INFO, "OpenSSL: Could not find current server certificate from OCSP response%s",
49465b9c547cSRui Paulo (conn->flags & TLS_CONN_REQUIRE_OCSP) ? "" :
49475b9c547cSRui Paulo " (OCSP not required)");
4948780fb4a2SCy Schubert OCSP_CERTID_free(id);
49495b9c547cSRui Paulo OCSP_BASICRESP_free(basic);
49505b9c547cSRui Paulo OCSP_RESPONSE_free(rsp);
49515b9c547cSRui Paulo return (conn->flags & TLS_CONN_REQUIRE_OCSP) ? 0 : 1;
49525b9c547cSRui Paulo }
4953780fb4a2SCy Schubert OCSP_CERTID_free(id);
49545b9c547cSRui Paulo
49555b9c547cSRui Paulo if (!OCSP_check_validity(this_update, next_update, 5 * 60, -1)) {
49565b9c547cSRui Paulo tls_show_errors(MSG_INFO, __func__,
49575b9c547cSRui Paulo "OpenSSL: OCSP status times invalid");
49585b9c547cSRui Paulo OCSP_BASICRESP_free(basic);
49595b9c547cSRui Paulo OCSP_RESPONSE_free(rsp);
49605b9c547cSRui Paulo return 0;
49615b9c547cSRui Paulo }
49625b9c547cSRui Paulo
49635b9c547cSRui Paulo OCSP_BASICRESP_free(basic);
49645b9c547cSRui Paulo OCSP_RESPONSE_free(rsp);
49655b9c547cSRui Paulo
49665b9c547cSRui Paulo wpa_printf(MSG_DEBUG, "OpenSSL: OCSP status for server certificate: %s",
49675b9c547cSRui Paulo OCSP_cert_status_str(status));
49685b9c547cSRui Paulo
49695b9c547cSRui Paulo if (status == V_OCSP_CERTSTATUS_GOOD)
49705b9c547cSRui Paulo return 1;
49715b9c547cSRui Paulo if (status == V_OCSP_CERTSTATUS_REVOKED)
49725b9c547cSRui Paulo return 0;
49735b9c547cSRui Paulo if (conn->flags & TLS_CONN_REQUIRE_OCSP) {
49745b9c547cSRui Paulo wpa_printf(MSG_DEBUG, "OpenSSL: OCSP status unknown, but OCSP required");
49755b9c547cSRui Paulo return 0;
49765b9c547cSRui Paulo }
49775b9c547cSRui Paulo wpa_printf(MSG_DEBUG, "OpenSSL: OCSP status unknown, but OCSP was not required, so allow connection to continue");
49785b9c547cSRui Paulo return 1;
49795b9c547cSRui Paulo }
49805b9c547cSRui Paulo
49815b9c547cSRui Paulo
ocsp_status_cb(SSL * s,void * arg)49825b9c547cSRui Paulo static int ocsp_status_cb(SSL *s, void *arg)
49835b9c547cSRui Paulo {
49845b9c547cSRui Paulo char *tmp;
49855b9c547cSRui Paulo char *resp;
49865b9c547cSRui Paulo size_t len;
49875b9c547cSRui Paulo
49885b9c547cSRui Paulo if (tls_global->ocsp_stapling_response == NULL) {
49895b9c547cSRui Paulo wpa_printf(MSG_DEBUG, "OpenSSL: OCSP status callback - no response configured");
49905b9c547cSRui Paulo return SSL_TLSEXT_ERR_OK;
49915b9c547cSRui Paulo }
49925b9c547cSRui Paulo
49935b9c547cSRui Paulo resp = os_readfile(tls_global->ocsp_stapling_response, &len);
49945b9c547cSRui Paulo if (resp == NULL) {
49955b9c547cSRui Paulo wpa_printf(MSG_DEBUG, "OpenSSL: OCSP status callback - could not read response file");
49965b9c547cSRui Paulo /* TODO: Build OCSPResponse with responseStatus = internalError
49975b9c547cSRui Paulo */
49985b9c547cSRui Paulo return SSL_TLSEXT_ERR_OK;
49995b9c547cSRui Paulo }
50005b9c547cSRui Paulo wpa_printf(MSG_DEBUG, "OpenSSL: OCSP status callback - send cached response");
50015b9c547cSRui Paulo tmp = OPENSSL_malloc(len);
50025b9c547cSRui Paulo if (tmp == NULL) {
50035b9c547cSRui Paulo os_free(resp);
50045b9c547cSRui Paulo return SSL_TLSEXT_ERR_ALERT_FATAL;
50055b9c547cSRui Paulo }
50065b9c547cSRui Paulo
50075b9c547cSRui Paulo os_memcpy(tmp, resp, len);
50085b9c547cSRui Paulo os_free(resp);
50095b9c547cSRui Paulo SSL_set_tlsext_status_ocsp_resp(s, tmp, len);
50105b9c547cSRui Paulo
50115b9c547cSRui Paulo return SSL_TLSEXT_ERR_OK;
50125b9c547cSRui Paulo }
50135b9c547cSRui Paulo
50145b9c547cSRui Paulo #endif /* HAVE_OCSP */
50155b9c547cSRui Paulo
50165b9c547cSRui Paulo
max_str_len(const char ** lines)5017c1d255d3SCy Schubert static size_t max_str_len(const char **lines)
5018c1d255d3SCy Schubert {
5019c1d255d3SCy Schubert const char **p;
5020c1d255d3SCy Schubert size_t max_len = 0;
5021c1d255d3SCy Schubert
5022c1d255d3SCy Schubert for (p = lines; *p; p++) {
5023c1d255d3SCy Schubert size_t len = os_strlen(*p);
5024c1d255d3SCy Schubert
5025c1d255d3SCy Schubert if (len > max_len)
5026c1d255d3SCy Schubert max_len = len;
5027c1d255d3SCy Schubert }
5028c1d255d3SCy Schubert
5029c1d255d3SCy Schubert return max_len;
5030c1d255d3SCy Schubert }
5031c1d255d3SCy Schubert
5032c1d255d3SCy Schubert
match_lines_in_file(const char * path,const char ** lines)5033c1d255d3SCy Schubert static int match_lines_in_file(const char *path, const char **lines)
5034c1d255d3SCy Schubert {
5035c1d255d3SCy Schubert FILE *f;
5036c1d255d3SCy Schubert char *buf;
5037c1d255d3SCy Schubert size_t bufsize;
5038c1d255d3SCy Schubert int found = 0, is_linestart = 1;
5039c1d255d3SCy Schubert
5040c1d255d3SCy Schubert bufsize = max_str_len(lines) + sizeof("\r\n");
5041c1d255d3SCy Schubert buf = os_malloc(bufsize);
5042c1d255d3SCy Schubert if (!buf)
5043c1d255d3SCy Schubert return 0;
5044c1d255d3SCy Schubert
5045c1d255d3SCy Schubert f = fopen(path, "r");
5046c1d255d3SCy Schubert if (!f) {
5047c1d255d3SCy Schubert os_free(buf);
5048c1d255d3SCy Schubert return 0;
5049c1d255d3SCy Schubert }
5050c1d255d3SCy Schubert
5051c1d255d3SCy Schubert while (!found && fgets(buf, bufsize, f)) {
5052c1d255d3SCy Schubert int is_lineend;
5053c1d255d3SCy Schubert size_t len;
5054c1d255d3SCy Schubert const char **p;
5055c1d255d3SCy Schubert
5056c1d255d3SCy Schubert len = strcspn(buf, "\r\n");
5057c1d255d3SCy Schubert is_lineend = buf[len] != '\0';
5058c1d255d3SCy Schubert buf[len] = '\0';
5059c1d255d3SCy Schubert
5060c1d255d3SCy Schubert if (is_linestart && is_lineend) {
5061c1d255d3SCy Schubert for (p = lines; !found && *p; p++)
5062c1d255d3SCy Schubert found = os_strcmp(buf, *p) == 0;
5063c1d255d3SCy Schubert }
5064c1d255d3SCy Schubert is_linestart = is_lineend;
5065c1d255d3SCy Schubert }
5066c1d255d3SCy Schubert
5067c1d255d3SCy Schubert fclose(f);
5068c1d255d3SCy Schubert bin_clear_free(buf, bufsize);
5069c1d255d3SCy Schubert
5070c1d255d3SCy Schubert return found;
5071c1d255d3SCy Schubert }
5072c1d255d3SCy Schubert
5073c1d255d3SCy Schubert
is_tpm2_key(const char * path)5074c1d255d3SCy Schubert static int is_tpm2_key(const char *path)
5075c1d255d3SCy Schubert {
5076c1d255d3SCy Schubert /* Check both new and old format of TPM2 PEM guard tag */
5077c1d255d3SCy Schubert static const char *tpm2_tags[] = {
5078c1d255d3SCy Schubert "-----BEGIN TSS2 PRIVATE KEY-----",
5079c1d255d3SCy Schubert "-----BEGIN TSS2 KEY BLOB-----",
5080c1d255d3SCy Schubert NULL
5081c1d255d3SCy Schubert };
5082c1d255d3SCy Schubert
5083c1d255d3SCy Schubert return match_lines_in_file(path, tpm2_tags);
5084c1d255d3SCy Schubert }
5085c1d255d3SCy Schubert
5086c1d255d3SCy Schubert
tls_connection_set_params(void * tls_ctx,struct tls_connection * conn,const struct tls_connection_params * params)508739beb93cSSam Leffler int tls_connection_set_params(void *tls_ctx, struct tls_connection *conn,
508839beb93cSSam Leffler const struct tls_connection_params *params)
508939beb93cSSam Leffler {
5090325151a3SRui Paulo struct tls_data *data = tls_ctx;
509139beb93cSSam Leffler int ret;
509239beb93cSSam Leffler unsigned long err;
50935b9c547cSRui Paulo int can_pkcs11 = 0;
50945b9c547cSRui Paulo const char *key_id = params->key_id;
50955b9c547cSRui Paulo const char *cert_id = params->cert_id;
50965b9c547cSRui Paulo const char *ca_cert_id = params->ca_cert_id;
50975b9c547cSRui Paulo const char *engine_id = params->engine ? params->engine_id : NULL;
509885732ac8SCy Schubert const char *ciphers;
509939beb93cSSam Leffler
510039beb93cSSam Leffler if (conn == NULL)
510139beb93cSSam Leffler return -1;
510239beb93cSSam Leffler
5103780fb4a2SCy Schubert if (params->flags & TLS_CONN_REQUIRE_OCSP_ALL) {
5104780fb4a2SCy Schubert wpa_printf(MSG_INFO,
5105780fb4a2SCy Schubert "OpenSSL: ocsp=3 not supported");
5106780fb4a2SCy Schubert return -1;
5107780fb4a2SCy Schubert }
5108780fb4a2SCy Schubert
51095b9c547cSRui Paulo /*
51105b9c547cSRui Paulo * If the engine isn't explicitly configured, and any of the
51115b9c547cSRui Paulo * cert/key fields are actually PKCS#11 URIs, then automatically
51125b9c547cSRui Paulo * use the PKCS#11 ENGINE.
51135b9c547cSRui Paulo */
51145b9c547cSRui Paulo if (!engine_id || os_strcmp(engine_id, "pkcs11") == 0)
51155b9c547cSRui Paulo can_pkcs11 = 1;
51165b9c547cSRui Paulo
51175b9c547cSRui Paulo if (!key_id && params->private_key && can_pkcs11 &&
51185b9c547cSRui Paulo os_strncmp(params->private_key, "pkcs11:", 7) == 0) {
51195b9c547cSRui Paulo can_pkcs11 = 2;
51205b9c547cSRui Paulo key_id = params->private_key;
51215b9c547cSRui Paulo }
51225b9c547cSRui Paulo
51235b9c547cSRui Paulo if (!cert_id && params->client_cert && can_pkcs11 &&
51245b9c547cSRui Paulo os_strncmp(params->client_cert, "pkcs11:", 7) == 0) {
51255b9c547cSRui Paulo can_pkcs11 = 2;
51265b9c547cSRui Paulo cert_id = params->client_cert;
51275b9c547cSRui Paulo }
51285b9c547cSRui Paulo
51295b9c547cSRui Paulo if (!ca_cert_id && params->ca_cert && can_pkcs11 &&
51305b9c547cSRui Paulo os_strncmp(params->ca_cert, "pkcs11:", 7) == 0) {
51315b9c547cSRui Paulo can_pkcs11 = 2;
51325b9c547cSRui Paulo ca_cert_id = params->ca_cert;
51335b9c547cSRui Paulo }
51345b9c547cSRui Paulo
51355b9c547cSRui Paulo /* If we need to automatically enable the PKCS#11 ENGINE, do so. */
51365b9c547cSRui Paulo if (can_pkcs11 == 2 && !engine_id)
51375b9c547cSRui Paulo engine_id = "pkcs11";
51385b9c547cSRui Paulo
5139c1d255d3SCy Schubert /* If private_key points to a TPM2-wrapped key, automatically enable
5140c1d255d3SCy Schubert * tpm2 engine and use it to unwrap the key. */
5141c1d255d3SCy Schubert if (params->private_key &&
5142c1d255d3SCy Schubert (!engine_id || os_strcmp(engine_id, "tpm2") == 0) &&
5143c1d255d3SCy Schubert is_tpm2_key(params->private_key)) {
5144c1d255d3SCy Schubert wpa_printf(MSG_DEBUG, "OpenSSL: Found TPM2 wrapped key %s",
5145c1d255d3SCy Schubert params->private_key);
5146c1d255d3SCy Schubert key_id = key_id ? key_id : params->private_key;
5147c1d255d3SCy Schubert engine_id = engine_id ? engine_id : "tpm2";
5148c1d255d3SCy Schubert }
5149c1d255d3SCy Schubert
5150325151a3SRui Paulo #if defined(EAP_FAST) || defined(EAP_FAST_DYNAMIC) || defined(EAP_SERVER_FAST)
515185732ac8SCy Schubert #if OPENSSL_VERSION_NUMBER < 0x10100000L || defined(LIBRESSL_VERSION_NUMBER)
51525b9c547cSRui Paulo if (params->flags & TLS_CONN_EAP_FAST) {
51535b9c547cSRui Paulo wpa_printf(MSG_DEBUG,
51545b9c547cSRui Paulo "OpenSSL: Use TLSv1_method() for EAP-FAST");
51555b9c547cSRui Paulo if (SSL_set_ssl_method(conn->ssl, TLSv1_method()) != 1) {
51565b9c547cSRui Paulo tls_show_errors(MSG_INFO, __func__,
51575b9c547cSRui Paulo "Failed to set TLSv1_method() for EAP-FAST");
51585b9c547cSRui Paulo return -1;
51595b9c547cSRui Paulo }
51605b9c547cSRui Paulo }
5161325151a3SRui Paulo #endif
516285732ac8SCy Schubert #if OPENSSL_VERSION_NUMBER >= 0x10101000L
516385732ac8SCy Schubert #ifdef SSL_OP_NO_TLSv1_3
516485732ac8SCy Schubert if (params->flags & TLS_CONN_EAP_FAST) {
516585732ac8SCy Schubert /* Need to disable TLS v1.3 at least for now since OpenSSL 1.1.1
516685732ac8SCy Schubert * refuses to start the handshake with the modified ciphersuite
516785732ac8SCy Schubert * list (no TLS v1.3 ciphersuites included) for EAP-FAST. */
516885732ac8SCy Schubert wpa_printf(MSG_DEBUG, "OpenSSL: Disable TLSv1.3 for EAP-FAST");
516985732ac8SCy Schubert SSL_set_options(conn->ssl, SSL_OP_NO_TLSv1_3);
517085732ac8SCy Schubert }
517185732ac8SCy Schubert #endif /* SSL_OP_NO_TLSv1_3 */
517285732ac8SCy Schubert #endif
5173325151a3SRui Paulo #endif /* EAP_FAST || EAP_FAST_DYNAMIC || EAP_SERVER_FAST */
51745b9c547cSRui Paulo
517539beb93cSSam Leffler while ((err = ERR_get_error())) {
517639beb93cSSam Leffler wpa_printf(MSG_INFO, "%s: Clearing pending SSL error: %s",
517739beb93cSSam Leffler __func__, ERR_error_string(err, NULL));
517839beb93cSSam Leffler }
517939beb93cSSam Leffler
51805b9c547cSRui Paulo if (engine_id) {
5181c1d255d3SCy Schubert wpa_printf(MSG_DEBUG, "SSL: Initializing TLS engine %s",
5182c1d255d3SCy Schubert engine_id);
51835b9c547cSRui Paulo ret = tls_engine_init(conn, engine_id, params->pin,
51845b9c547cSRui Paulo key_id, cert_id, ca_cert_id);
518539beb93cSSam Leffler if (ret)
518639beb93cSSam Leffler return ret;
518739beb93cSSam Leffler }
518839beb93cSSam Leffler if (tls_connection_set_subject_match(conn,
518939beb93cSSam Leffler params->subject_match,
51905b9c547cSRui Paulo params->altsubject_match,
51915b9c547cSRui Paulo params->suffix_match,
51924bc52338SCy Schubert params->domain_match,
51934bc52338SCy Schubert params->check_cert_subject))
519439beb93cSSam Leffler return -1;
519539beb93cSSam Leffler
51965b9c547cSRui Paulo if (engine_id && ca_cert_id) {
5197325151a3SRui Paulo if (tls_connection_engine_ca_cert(data, conn, ca_cert_id))
519839beb93cSSam Leffler return TLS_SET_PARAMS_ENGINE_PRV_VERIFY_FAILED;
5199325151a3SRui Paulo } else if (tls_connection_ca_cert(data, conn, params->ca_cert,
520039beb93cSSam Leffler params->ca_cert_blob,
520139beb93cSSam Leffler params->ca_cert_blob_len,
520239beb93cSSam Leffler params->ca_path))
520339beb93cSSam Leffler return -1;
520439beb93cSSam Leffler
52055b9c547cSRui Paulo if (engine_id && cert_id) {
52065b9c547cSRui Paulo if (tls_connection_engine_client_cert(conn, cert_id))
520739beb93cSSam Leffler return TLS_SET_PARAMS_ENGINE_PRV_VERIFY_FAILED;
520839beb93cSSam Leffler } else if (tls_connection_client_cert(conn, params->client_cert,
520939beb93cSSam Leffler params->client_cert_blob,
521039beb93cSSam Leffler params->client_cert_blob_len))
521139beb93cSSam Leffler return -1;
521239beb93cSSam Leffler
52135b9c547cSRui Paulo if (engine_id && key_id) {
521439beb93cSSam Leffler wpa_printf(MSG_DEBUG, "TLS: Using private key from engine");
521539beb93cSSam Leffler if (tls_connection_engine_private_key(conn))
521639beb93cSSam Leffler return TLS_SET_PARAMS_ENGINE_PRV_VERIFY_FAILED;
5217325151a3SRui Paulo } else if (tls_connection_private_key(data, conn,
521839beb93cSSam Leffler params->private_key,
521939beb93cSSam Leffler params->private_key_passwd,
522039beb93cSSam Leffler params->private_key_blob,
522139beb93cSSam Leffler params->private_key_blob_len)) {
522239beb93cSSam Leffler wpa_printf(MSG_INFO, "TLS: Failed to load private key '%s'",
522339beb93cSSam Leffler params->private_key);
522439beb93cSSam Leffler return -1;
522539beb93cSSam Leffler }
522639beb93cSSam Leffler
522739beb93cSSam Leffler if (tls_connection_dh(conn, params->dh_file)) {
522839beb93cSSam Leffler wpa_printf(MSG_INFO, "TLS: Failed to load DH file '%s'",
522939beb93cSSam Leffler params->dh_file);
523039beb93cSSam Leffler return -1;
523139beb93cSSam Leffler }
523239beb93cSSam Leffler
523385732ac8SCy Schubert ciphers = params->openssl_ciphers;
523485732ac8SCy Schubert #ifdef CONFIG_SUITEB
523585732ac8SCy Schubert #ifdef OPENSSL_IS_BORINGSSL
523685732ac8SCy Schubert if (ciphers && os_strcmp(ciphers, "SUITEB192") == 0) {
523785732ac8SCy Schubert /* BoringSSL removed support for SUITEB192, so need to handle
523885732ac8SCy Schubert * this with hardcoded ciphersuite and additional checks for
523985732ac8SCy Schubert * other parameters. */
524085732ac8SCy Schubert ciphers = "ECDHE-ECDSA-AES256-GCM-SHA384";
524185732ac8SCy Schubert }
524285732ac8SCy Schubert #endif /* OPENSSL_IS_BORINGSSL */
524385732ac8SCy Schubert #endif /* CONFIG_SUITEB */
524485732ac8SCy Schubert if (ciphers && SSL_set_cipher_list(conn->ssl, ciphers) != 1) {
52455b9c547cSRui Paulo wpa_printf(MSG_INFO,
52465b9c547cSRui Paulo "OpenSSL: Failed to set cipher string '%s'",
524785732ac8SCy Schubert ciphers);
52485b9c547cSRui Paulo return -1;
52495b9c547cSRui Paulo }
52505b9c547cSRui Paulo
52514bc52338SCy Schubert if (!params->openssl_ecdh_curves) {
52524bc52338SCy Schubert #ifndef OPENSSL_IS_BORINGSSL
52534bc52338SCy Schubert #ifndef OPENSSL_NO_EC
52544bc52338SCy Schubert #if (OPENSSL_VERSION_NUMBER >= 0x10002000L) && \
52554bc52338SCy Schubert (OPENSSL_VERSION_NUMBER < 0x10100000L)
52564bc52338SCy Schubert if (SSL_set_ecdh_auto(conn->ssl, 1) != 1) {
52574bc52338SCy Schubert wpa_printf(MSG_INFO,
52584bc52338SCy Schubert "OpenSSL: Failed to set ECDH curves to auto");
52594bc52338SCy Schubert return -1;
52604bc52338SCy Schubert }
52614bc52338SCy Schubert #endif /* >= 1.0.2 && < 1.1.0 */
52624bc52338SCy Schubert #endif /* OPENSSL_NO_EC */
52634bc52338SCy Schubert #endif /* OPENSSL_IS_BORINGSSL */
52644bc52338SCy Schubert } else if (params->openssl_ecdh_curves[0]) {
52654bc52338SCy Schubert #if defined(OPENSSL_IS_BORINGSSL) || (OPENSSL_VERSION_NUMBER < 0x10002000L)
52664bc52338SCy Schubert wpa_printf(MSG_INFO,
52674bc52338SCy Schubert "OpenSSL: ECDH configuration nnot supported");
52684bc52338SCy Schubert return -1;
52694bc52338SCy Schubert #else /* OPENSSL_IS_BORINGSSL || < 1.0.2 */
52704bc52338SCy Schubert #ifndef OPENSSL_NO_EC
52714bc52338SCy Schubert if (SSL_set1_curves_list(conn->ssl,
52724bc52338SCy Schubert params->openssl_ecdh_curves) != 1) {
52734bc52338SCy Schubert wpa_printf(MSG_INFO,
52744bc52338SCy Schubert "OpenSSL: Failed to set ECDH curves '%s'",
52754bc52338SCy Schubert params->openssl_ecdh_curves);
52764bc52338SCy Schubert return -1;
52774bc52338SCy Schubert }
52784bc52338SCy Schubert #else /* OPENSSL_NO_EC */
52794bc52338SCy Schubert wpa_printf(MSG_INFO, "OpenSSL: ECDH not supported");
52804bc52338SCy Schubert return -1;
52814bc52338SCy Schubert #endif /* OPENSSL_NO_EC */
52824bc52338SCy Schubert #endif /* OPENSSL_IS_BORINGSSL */
52834bc52338SCy Schubert }
52844bc52338SCy Schubert
528585732ac8SCy Schubert if (tls_set_conn_flags(conn, params->flags,
528685732ac8SCy Schubert params->openssl_ciphers) < 0)
528785732ac8SCy Schubert return -1;
52885b9c547cSRui Paulo
5289780fb4a2SCy Schubert #ifdef OPENSSL_IS_BORINGSSL
5290780fb4a2SCy Schubert if (params->flags & TLS_CONN_REQUEST_OCSP) {
5291780fb4a2SCy Schubert SSL_enable_ocsp_stapling(conn->ssl);
5292780fb4a2SCy Schubert }
5293780fb4a2SCy Schubert #else /* OPENSSL_IS_BORINGSSL */
52945b9c547cSRui Paulo #ifdef HAVE_OCSP
52955b9c547cSRui Paulo if (params->flags & TLS_CONN_REQUEST_OCSP) {
5296325151a3SRui Paulo SSL_CTX *ssl_ctx = data->ssl;
52975b9c547cSRui Paulo SSL_set_tlsext_status_type(conn->ssl, TLSEXT_STATUSTYPE_ocsp);
52985b9c547cSRui Paulo SSL_CTX_set_tlsext_status_cb(ssl_ctx, ocsp_resp_cb);
52995b9c547cSRui Paulo SSL_CTX_set_tlsext_status_arg(ssl_ctx, conn);
53005b9c547cSRui Paulo }
5301325151a3SRui Paulo #else /* HAVE_OCSP */
5302325151a3SRui Paulo if (params->flags & TLS_CONN_REQUIRE_OCSP) {
5303325151a3SRui Paulo wpa_printf(MSG_INFO,
5304325151a3SRui Paulo "OpenSSL: No OCSP support included - reject configuration");
5305325151a3SRui Paulo return -1;
5306325151a3SRui Paulo }
5307325151a3SRui Paulo if (params->flags & TLS_CONN_REQUEST_OCSP) {
5308325151a3SRui Paulo wpa_printf(MSG_DEBUG,
5309325151a3SRui Paulo "OpenSSL: No OCSP support included - allow optional OCSP case to continue");
5310325151a3SRui Paulo }
53115b9c547cSRui Paulo #endif /* HAVE_OCSP */
5312780fb4a2SCy Schubert #endif /* OPENSSL_IS_BORINGSSL */
53135b9c547cSRui Paulo
5314f05cddf9SRui Paulo conn->flags = params->flags;
5315f05cddf9SRui Paulo
5316325151a3SRui Paulo tls_get_errors(data);
531739beb93cSSam Leffler
531839beb93cSSam Leffler return 0;
531939beb93cSSam Leffler }
532039beb93cSSam Leffler
532139beb93cSSam Leffler
openssl_debug_dump_cipher_list(SSL_CTX * ssl_ctx)5322206b73d0SCy Schubert static void openssl_debug_dump_cipher_list(SSL_CTX *ssl_ctx)
5323206b73d0SCy Schubert {
5324206b73d0SCy Schubert SSL *ssl;
5325206b73d0SCy Schubert int i;
5326206b73d0SCy Schubert
5327206b73d0SCy Schubert ssl = SSL_new(ssl_ctx);
5328206b73d0SCy Schubert if (!ssl)
5329206b73d0SCy Schubert return;
5330206b73d0SCy Schubert
5331206b73d0SCy Schubert wpa_printf(MSG_DEBUG,
5332206b73d0SCy Schubert "OpenSSL: Enabled cipher suites in priority order");
5333206b73d0SCy Schubert for (i = 0; ; i++) {
5334206b73d0SCy Schubert const char *cipher;
5335206b73d0SCy Schubert
5336206b73d0SCy Schubert cipher = SSL_get_cipher_list(ssl, i);
5337206b73d0SCy Schubert if (!cipher)
5338206b73d0SCy Schubert break;
5339206b73d0SCy Schubert wpa_printf(MSG_DEBUG, "Cipher %d: %s", i, cipher);
5340206b73d0SCy Schubert }
5341206b73d0SCy Schubert
5342206b73d0SCy Schubert SSL_free(ssl);
5343206b73d0SCy Schubert }
5344206b73d0SCy Schubert
5345206b73d0SCy Schubert
5346206b73d0SCy Schubert #if !defined(LIBRESSL_VERSION_NUMBER) && !defined(BORINGSSL_API_VERSION)
5347206b73d0SCy Schubert
openssl_pkey_type_str(const EVP_PKEY * pkey)5348206b73d0SCy Schubert static const char * openssl_pkey_type_str(const EVP_PKEY *pkey)
5349206b73d0SCy Schubert {
5350206b73d0SCy Schubert if (!pkey)
5351206b73d0SCy Schubert return "NULL";
5352206b73d0SCy Schubert switch (EVP_PKEY_type(EVP_PKEY_id(pkey))) {
5353206b73d0SCy Schubert case EVP_PKEY_RSA:
5354206b73d0SCy Schubert return "RSA";
5355206b73d0SCy Schubert case EVP_PKEY_DSA:
5356206b73d0SCy Schubert return "DSA";
5357206b73d0SCy Schubert case EVP_PKEY_DH:
5358206b73d0SCy Schubert return "DH";
5359206b73d0SCy Schubert case EVP_PKEY_EC:
5360206b73d0SCy Schubert return "EC";
5361206b73d0SCy Schubert }
5362206b73d0SCy Schubert return "?";
5363206b73d0SCy Schubert }
5364206b73d0SCy Schubert
5365206b73d0SCy Schubert
openssl_debug_dump_certificate(int i,X509 * cert)5366206b73d0SCy Schubert static void openssl_debug_dump_certificate(int i, X509 *cert)
5367206b73d0SCy Schubert {
5368206b73d0SCy Schubert char buf[256];
5369206b73d0SCy Schubert EVP_PKEY *pkey;
5370206b73d0SCy Schubert ASN1_INTEGER *ser;
5371206b73d0SCy Schubert char serial_num[128];
5372206b73d0SCy Schubert
5373c1d255d3SCy Schubert if (!cert)
5374c1d255d3SCy Schubert return;
5375c1d255d3SCy Schubert
5376206b73d0SCy Schubert X509_NAME_oneline(X509_get_subject_name(cert), buf, sizeof(buf));
5377206b73d0SCy Schubert
5378206b73d0SCy Schubert ser = X509_get_serialNumber(cert);
5379206b73d0SCy Schubert if (ser)
5380206b73d0SCy Schubert wpa_snprintf_hex_uppercase(serial_num, sizeof(serial_num),
5381206b73d0SCy Schubert ASN1_STRING_get0_data(ser),
5382206b73d0SCy Schubert ASN1_STRING_length(ser));
5383206b73d0SCy Schubert else
5384206b73d0SCy Schubert serial_num[0] = '\0';
5385206b73d0SCy Schubert
5386206b73d0SCy Schubert pkey = X509_get_pubkey(cert);
5387206b73d0SCy Schubert wpa_printf(MSG_DEBUG, "%d: %s (%s) %s", i, buf,
5388206b73d0SCy Schubert openssl_pkey_type_str(pkey), serial_num);
5389206b73d0SCy Schubert EVP_PKEY_free(pkey);
5390206b73d0SCy Schubert }
5391206b73d0SCy Schubert
5392206b73d0SCy Schubert
openssl_debug_dump_certificates(SSL_CTX * ssl_ctx)5393206b73d0SCy Schubert static void openssl_debug_dump_certificates(SSL_CTX *ssl_ctx)
5394206b73d0SCy Schubert {
5395206b73d0SCy Schubert STACK_OF(X509) *certs;
5396206b73d0SCy Schubert
5397206b73d0SCy Schubert wpa_printf(MSG_DEBUG, "OpenSSL: Configured certificate chain");
5398206b73d0SCy Schubert if (SSL_CTX_get0_chain_certs(ssl_ctx, &certs) == 1) {
5399206b73d0SCy Schubert int i;
5400206b73d0SCy Schubert
5401206b73d0SCy Schubert for (i = sk_X509_num(certs); i > 0; i--)
5402206b73d0SCy Schubert openssl_debug_dump_certificate(i, sk_X509_value(certs,
5403206b73d0SCy Schubert i - 1));
5404206b73d0SCy Schubert }
5405206b73d0SCy Schubert openssl_debug_dump_certificate(0, SSL_CTX_get0_certificate(ssl_ctx));
5406206b73d0SCy Schubert }
5407206b73d0SCy Schubert
5408206b73d0SCy Schubert #endif
5409206b73d0SCy Schubert
5410206b73d0SCy Schubert
openssl_debug_dump_certificate_chains(SSL_CTX * ssl_ctx)5411206b73d0SCy Schubert static void openssl_debug_dump_certificate_chains(SSL_CTX *ssl_ctx)
5412206b73d0SCy Schubert {
5413206b73d0SCy Schubert #if !defined(LIBRESSL_VERSION_NUMBER) && !defined(BORINGSSL_API_VERSION)
5414206b73d0SCy Schubert int res;
5415206b73d0SCy Schubert
5416206b73d0SCy Schubert for (res = SSL_CTX_set_current_cert(ssl_ctx, SSL_CERT_SET_FIRST);
5417206b73d0SCy Schubert res == 1;
5418206b73d0SCy Schubert res = SSL_CTX_set_current_cert(ssl_ctx, SSL_CERT_SET_NEXT))
5419206b73d0SCy Schubert openssl_debug_dump_certificates(ssl_ctx);
5420206b73d0SCy Schubert
5421206b73d0SCy Schubert SSL_CTX_set_current_cert(ssl_ctx, SSL_CERT_SET_FIRST);
5422206b73d0SCy Schubert #endif
5423206b73d0SCy Schubert }
5424206b73d0SCy Schubert
5425206b73d0SCy Schubert
openssl_debug_dump_ctx(SSL_CTX * ssl_ctx)5426206b73d0SCy Schubert static void openssl_debug_dump_ctx(SSL_CTX *ssl_ctx)
5427206b73d0SCy Schubert {
5428206b73d0SCy Schubert openssl_debug_dump_cipher_list(ssl_ctx);
5429206b73d0SCy Schubert openssl_debug_dump_certificate_chains(ssl_ctx);
5430206b73d0SCy Schubert }
5431206b73d0SCy Schubert
5432206b73d0SCy Schubert
tls_global_set_params(void * tls_ctx,const struct tls_connection_params * params)543339beb93cSSam Leffler int tls_global_set_params(void *tls_ctx,
543439beb93cSSam Leffler const struct tls_connection_params *params)
543539beb93cSSam Leffler {
5436325151a3SRui Paulo struct tls_data *data = tls_ctx;
5437325151a3SRui Paulo SSL_CTX *ssl_ctx = data->ssl;
543839beb93cSSam Leffler unsigned long err;
543939beb93cSSam Leffler
544039beb93cSSam Leffler while ((err = ERR_get_error())) {
544139beb93cSSam Leffler wpa_printf(MSG_INFO, "%s: Clearing pending SSL error: %s",
544239beb93cSSam Leffler __func__, ERR_error_string(err, NULL));
544339beb93cSSam Leffler }
544439beb93cSSam Leffler
54454bc52338SCy Schubert os_free(data->check_cert_subject);
54464bc52338SCy Schubert data->check_cert_subject = NULL;
54474bc52338SCy Schubert if (params->check_cert_subject) {
54484bc52338SCy Schubert data->check_cert_subject =
54494bc52338SCy Schubert os_strdup(params->check_cert_subject);
54504bc52338SCy Schubert if (!data->check_cert_subject)
54514bc52338SCy Schubert return -1;
54524bc52338SCy Schubert }
54534bc52338SCy Schubert
5454325151a3SRui Paulo if (tls_global_ca_cert(data, params->ca_cert) ||
5455325151a3SRui Paulo tls_global_client_cert(data, params->client_cert) ||
5456325151a3SRui Paulo tls_global_private_key(data, params->private_key,
5457325151a3SRui Paulo params->private_key_passwd) ||
5458206b73d0SCy Schubert tls_global_client_cert(data, params->client_cert2) ||
5459206b73d0SCy Schubert tls_global_private_key(data, params->private_key2,
5460206b73d0SCy Schubert params->private_key_passwd2) ||
5461325151a3SRui Paulo tls_global_dh(data, params->dh_file)) {
5462325151a3SRui Paulo wpa_printf(MSG_INFO, "TLS: Failed to set global parameters");
546339beb93cSSam Leffler return -1;
546439beb93cSSam Leffler }
546539beb93cSSam Leffler
54665b9c547cSRui Paulo if (params->openssl_ciphers &&
54675b9c547cSRui Paulo SSL_CTX_set_cipher_list(ssl_ctx, params->openssl_ciphers) != 1) {
54685b9c547cSRui Paulo wpa_printf(MSG_INFO,
54695b9c547cSRui Paulo "OpenSSL: Failed to set cipher string '%s'",
54705b9c547cSRui Paulo params->openssl_ciphers);
54715b9c547cSRui Paulo return -1;
54725b9c547cSRui Paulo }
54735b9c547cSRui Paulo
54744bc52338SCy Schubert if (!params->openssl_ecdh_curves) {
54754bc52338SCy Schubert #ifndef OPENSSL_IS_BORINGSSL
54764bc52338SCy Schubert #ifndef OPENSSL_NO_EC
54774bc52338SCy Schubert #if (OPENSSL_VERSION_NUMBER >= 0x10002000L) && \
54784bc52338SCy Schubert (OPENSSL_VERSION_NUMBER < 0x10100000L)
54794bc52338SCy Schubert if (SSL_CTX_set_ecdh_auto(ssl_ctx, 1) != 1) {
54804bc52338SCy Schubert wpa_printf(MSG_INFO,
54814bc52338SCy Schubert "OpenSSL: Failed to set ECDH curves to auto");
54824bc52338SCy Schubert return -1;
54834bc52338SCy Schubert }
54844bc52338SCy Schubert #endif /* >= 1.0.2 && < 1.1.0 */
54854bc52338SCy Schubert #endif /* OPENSSL_NO_EC */
54864bc52338SCy Schubert #endif /* OPENSSL_IS_BORINGSSL */
54874bc52338SCy Schubert } else if (params->openssl_ecdh_curves[0]) {
54884bc52338SCy Schubert #if defined(OPENSSL_IS_BORINGSSL) || (OPENSSL_VERSION_NUMBER < 0x10002000L)
54894bc52338SCy Schubert wpa_printf(MSG_INFO,
54904bc52338SCy Schubert "OpenSSL: ECDH configuration nnot supported");
54914bc52338SCy Schubert return -1;
54924bc52338SCy Schubert #else /* OPENSSL_IS_BORINGSSL || < 1.0.2 */
54934bc52338SCy Schubert #ifndef OPENSSL_NO_EC
54944bc52338SCy Schubert #if OPENSSL_VERSION_NUMBER < 0x10100000L
54954bc52338SCy Schubert SSL_CTX_set_ecdh_auto(ssl_ctx, 1);
54964bc52338SCy Schubert #endif
54974bc52338SCy Schubert if (SSL_CTX_set1_curves_list(ssl_ctx,
54984bc52338SCy Schubert params->openssl_ecdh_curves) !=
54994bc52338SCy Schubert 1) {
55004bc52338SCy Schubert wpa_printf(MSG_INFO,
55014bc52338SCy Schubert "OpenSSL: Failed to set ECDH curves '%s'",
55024bc52338SCy Schubert params->openssl_ecdh_curves);
55034bc52338SCy Schubert return -1;
55044bc52338SCy Schubert }
55054bc52338SCy Schubert #else /* OPENSSL_NO_EC */
55064bc52338SCy Schubert wpa_printf(MSG_INFO, "OpenSSL: ECDH not supported");
55074bc52338SCy Schubert return -1;
55084bc52338SCy Schubert #endif /* OPENSSL_NO_EC */
55094bc52338SCy Schubert #endif /* OPENSSL_IS_BORINGSSL */
55104bc52338SCy Schubert }
55114bc52338SCy Schubert
5512f05cddf9SRui Paulo #ifdef SSL_OP_NO_TICKET
5513f05cddf9SRui Paulo if (params->flags & TLS_CONN_DISABLE_SESSION_TICKET)
5514f05cddf9SRui Paulo SSL_CTX_set_options(ssl_ctx, SSL_OP_NO_TICKET);
5515f05cddf9SRui Paulo else
5516f05cddf9SRui Paulo SSL_CTX_clear_options(ssl_ctx, SSL_OP_NO_TICKET);
5517f05cddf9SRui Paulo #endif /* SSL_OP_NO_TICKET */
5518f05cddf9SRui Paulo
55195b9c547cSRui Paulo #ifdef HAVE_OCSP
55205b9c547cSRui Paulo SSL_CTX_set_tlsext_status_cb(ssl_ctx, ocsp_status_cb);
55215b9c547cSRui Paulo SSL_CTX_set_tlsext_status_arg(ssl_ctx, ssl_ctx);
55225b9c547cSRui Paulo os_free(tls_global->ocsp_stapling_response);
55235b9c547cSRui Paulo if (params->ocsp_stapling_response)
55245b9c547cSRui Paulo tls_global->ocsp_stapling_response =
55255b9c547cSRui Paulo os_strdup(params->ocsp_stapling_response);
55265b9c547cSRui Paulo else
55275b9c547cSRui Paulo tls_global->ocsp_stapling_response = NULL;
55285b9c547cSRui Paulo #endif /* HAVE_OCSP */
55295b9c547cSRui Paulo
5530206b73d0SCy Schubert openssl_debug_dump_ctx(ssl_ctx);
5531206b73d0SCy Schubert
553239beb93cSSam Leffler return 0;
553339beb93cSSam Leffler }
553439beb93cSSam Leffler
553539beb93cSSam Leffler
5536206b73d0SCy Schubert #ifdef EAP_FAST_OR_TEAP
553739beb93cSSam Leffler /* Pre-shared secred requires a patch to openssl, so this function is
553839beb93cSSam Leffler * commented out unless explicitly needed for EAP-FAST in order to be able to
553939beb93cSSam Leffler * build this file with unmodified openssl. */
554039beb93cSSam Leffler
5541780fb4a2SCy Schubert #if (defined(OPENSSL_IS_BORINGSSL) || OPENSSL_VERSION_NUMBER >= 0x10100000L) && !defined(LIBRESSL_VERSION_NUMBER)
tls_sess_sec_cb(SSL * s,void * secret,int * secret_len,STACK_OF (SSL_CIPHER)* peer_ciphers,const SSL_CIPHER ** cipher,void * arg)55425b9c547cSRui Paulo static int tls_sess_sec_cb(SSL *s, void *secret, int *secret_len,
55435b9c547cSRui Paulo STACK_OF(SSL_CIPHER) *peer_ciphers,
55445b9c547cSRui Paulo const SSL_CIPHER **cipher, void *arg)
55455b9c547cSRui Paulo #else /* OPENSSL_IS_BORINGSSL */
554639beb93cSSam Leffler static int tls_sess_sec_cb(SSL *s, void *secret, int *secret_len,
554739beb93cSSam Leffler STACK_OF(SSL_CIPHER) *peer_ciphers,
554839beb93cSSam Leffler SSL_CIPHER **cipher, void *arg)
55495b9c547cSRui Paulo #endif /* OPENSSL_IS_BORINGSSL */
555039beb93cSSam Leffler {
555139beb93cSSam Leffler struct tls_connection *conn = arg;
555239beb93cSSam Leffler int ret;
555339beb93cSSam Leffler
555485732ac8SCy Schubert #if OPENSSL_VERSION_NUMBER < 0x10100000L || \
555585732ac8SCy Schubert (defined(LIBRESSL_VERSION_NUMBER) && \
555685732ac8SCy Schubert LIBRESSL_VERSION_NUMBER < 0x20700000L)
555739beb93cSSam Leffler if (conn == NULL || conn->session_ticket_cb == NULL)
555839beb93cSSam Leffler return 0;
555939beb93cSSam Leffler
556039beb93cSSam Leffler ret = conn->session_ticket_cb(conn->session_ticket_cb_ctx,
556139beb93cSSam Leffler conn->session_ticket,
556239beb93cSSam Leffler conn->session_ticket_len,
556339beb93cSSam Leffler s->s3->client_random,
556439beb93cSSam Leffler s->s3->server_random, secret);
5565325151a3SRui Paulo #else
5566325151a3SRui Paulo unsigned char client_random[SSL3_RANDOM_SIZE];
5567325151a3SRui Paulo unsigned char server_random[SSL3_RANDOM_SIZE];
5568325151a3SRui Paulo
5569325151a3SRui Paulo if (conn == NULL || conn->session_ticket_cb == NULL)
5570325151a3SRui Paulo return 0;
5571325151a3SRui Paulo
5572325151a3SRui Paulo SSL_get_client_random(s, client_random, sizeof(client_random));
5573325151a3SRui Paulo SSL_get_server_random(s, server_random, sizeof(server_random));
5574325151a3SRui Paulo
5575325151a3SRui Paulo ret = conn->session_ticket_cb(conn->session_ticket_cb_ctx,
5576325151a3SRui Paulo conn->session_ticket,
5577325151a3SRui Paulo conn->session_ticket_len,
5578325151a3SRui Paulo client_random,
5579325151a3SRui Paulo server_random, secret);
5580325151a3SRui Paulo #endif
5581325151a3SRui Paulo
558239beb93cSSam Leffler os_free(conn->session_ticket);
558339beb93cSSam Leffler conn->session_ticket = NULL;
558439beb93cSSam Leffler
558539beb93cSSam Leffler if (ret <= 0)
558639beb93cSSam Leffler return 0;
558739beb93cSSam Leffler
558839beb93cSSam Leffler *secret_len = SSL_MAX_MASTER_KEY_LENGTH;
558939beb93cSSam Leffler return 1;
559039beb93cSSam Leffler }
559139beb93cSSam Leffler
559239beb93cSSam Leffler
tls_session_ticket_ext_cb(SSL * s,const unsigned char * data,int len,void * arg)559339beb93cSSam Leffler static int tls_session_ticket_ext_cb(SSL *s, const unsigned char *data,
559439beb93cSSam Leffler int len, void *arg)
559539beb93cSSam Leffler {
559639beb93cSSam Leffler struct tls_connection *conn = arg;
559739beb93cSSam Leffler
559839beb93cSSam Leffler if (conn == NULL || conn->session_ticket_cb == NULL)
559939beb93cSSam Leffler return 0;
560039beb93cSSam Leffler
560139beb93cSSam Leffler wpa_printf(MSG_DEBUG, "OpenSSL: %s: length=%d", __func__, len);
560239beb93cSSam Leffler
560339beb93cSSam Leffler os_free(conn->session_ticket);
560439beb93cSSam Leffler conn->session_ticket = NULL;
560539beb93cSSam Leffler
560639beb93cSSam Leffler wpa_hexdump(MSG_DEBUG, "OpenSSL: ClientHello SessionTicket "
560739beb93cSSam Leffler "extension", data, len);
560839beb93cSSam Leffler
560985732ac8SCy Schubert conn->session_ticket = os_memdup(data, len);
561039beb93cSSam Leffler if (conn->session_ticket == NULL)
561139beb93cSSam Leffler return 0;
561239beb93cSSam Leffler
561339beb93cSSam Leffler conn->session_ticket_len = len;
561439beb93cSSam Leffler
561539beb93cSSam Leffler return 1;
561639beb93cSSam Leffler }
5617206b73d0SCy Schubert #endif /* EAP_FAST_OR_TEAP */
561839beb93cSSam Leffler
561939beb93cSSam Leffler
tls_connection_set_session_ticket_cb(void * tls_ctx,struct tls_connection * conn,tls_session_ticket_cb cb,void * ctx)562039beb93cSSam Leffler int tls_connection_set_session_ticket_cb(void *tls_ctx,
562139beb93cSSam Leffler struct tls_connection *conn,
562239beb93cSSam Leffler tls_session_ticket_cb cb,
562339beb93cSSam Leffler void *ctx)
562439beb93cSSam Leffler {
5625206b73d0SCy Schubert #ifdef EAP_FAST_OR_TEAP
562639beb93cSSam Leffler conn->session_ticket_cb = cb;
562739beb93cSSam Leffler conn->session_ticket_cb_ctx = ctx;
562839beb93cSSam Leffler
562939beb93cSSam Leffler if (cb) {
563039beb93cSSam Leffler if (SSL_set_session_secret_cb(conn->ssl, tls_sess_sec_cb,
563139beb93cSSam Leffler conn) != 1)
563239beb93cSSam Leffler return -1;
563339beb93cSSam Leffler SSL_set_session_ticket_ext_cb(conn->ssl,
563439beb93cSSam Leffler tls_session_ticket_ext_cb, conn);
563539beb93cSSam Leffler } else {
563639beb93cSSam Leffler if (SSL_set_session_secret_cb(conn->ssl, NULL, NULL) != 1)
563739beb93cSSam Leffler return -1;
563839beb93cSSam Leffler SSL_set_session_ticket_ext_cb(conn->ssl, NULL, NULL);
563939beb93cSSam Leffler }
564039beb93cSSam Leffler
564139beb93cSSam Leffler return 0;
5642206b73d0SCy Schubert #else /* EAP_FAST_OR_TEAP */
564339beb93cSSam Leffler return -1;
5644206b73d0SCy Schubert #endif /* EAP_FAST_OR_TEAP */
564539beb93cSSam Leffler }
56465b9c547cSRui Paulo
56475b9c547cSRui Paulo
tls_get_library_version(char * buf,size_t buf_len)56485b9c547cSRui Paulo int tls_get_library_version(char *buf, size_t buf_len)
56495b9c547cSRui Paulo {
5650780fb4a2SCy Schubert #if OPENSSL_VERSION_NUMBER >= 0x10100000L && !defined(LIBRESSL_VERSION_NUMBER)
5651780fb4a2SCy Schubert return os_snprintf(buf, buf_len, "OpenSSL build=%s run=%s",
5652780fb4a2SCy Schubert OPENSSL_VERSION_TEXT,
5653780fb4a2SCy Schubert OpenSSL_version(OPENSSL_VERSION));
5654780fb4a2SCy Schubert #else
56555b9c547cSRui Paulo return os_snprintf(buf, buf_len, "OpenSSL build=%s run=%s",
56565b9c547cSRui Paulo OPENSSL_VERSION_TEXT,
56575b9c547cSRui Paulo SSLeay_version(SSLEAY_VERSION));
5658780fb4a2SCy Schubert #endif
56595b9c547cSRui Paulo }
5660325151a3SRui Paulo
5661325151a3SRui Paulo
tls_connection_set_success_data(struct tls_connection * conn,struct wpabuf * data)5662325151a3SRui Paulo void tls_connection_set_success_data(struct tls_connection *conn,
5663325151a3SRui Paulo struct wpabuf *data)
5664325151a3SRui Paulo {
5665325151a3SRui Paulo SSL_SESSION *sess;
5666325151a3SRui Paulo struct wpabuf *old;
5667325151a3SRui Paulo
5668325151a3SRui Paulo if (tls_ex_idx_session < 0)
5669325151a3SRui Paulo goto fail;
5670325151a3SRui Paulo sess = SSL_get_session(conn->ssl);
5671325151a3SRui Paulo if (!sess)
5672325151a3SRui Paulo goto fail;
5673325151a3SRui Paulo old = SSL_SESSION_get_ex_data(sess, tls_ex_idx_session);
5674325151a3SRui Paulo if (old) {
5675325151a3SRui Paulo wpa_printf(MSG_DEBUG, "OpenSSL: Replacing old success data %p",
5676325151a3SRui Paulo old);
5677325151a3SRui Paulo wpabuf_free(old);
5678325151a3SRui Paulo }
5679325151a3SRui Paulo if (SSL_SESSION_set_ex_data(sess, tls_ex_idx_session, data) != 1)
5680325151a3SRui Paulo goto fail;
5681325151a3SRui Paulo
5682325151a3SRui Paulo wpa_printf(MSG_DEBUG, "OpenSSL: Stored success data %p", data);
5683325151a3SRui Paulo conn->success_data = 1;
5684325151a3SRui Paulo return;
5685325151a3SRui Paulo
5686325151a3SRui Paulo fail:
5687325151a3SRui Paulo wpa_printf(MSG_INFO, "OpenSSL: Failed to store success data");
5688325151a3SRui Paulo wpabuf_free(data);
5689325151a3SRui Paulo }
5690325151a3SRui Paulo
5691325151a3SRui Paulo
tls_connection_set_success_data_resumed(struct tls_connection * conn)5692325151a3SRui Paulo void tls_connection_set_success_data_resumed(struct tls_connection *conn)
5693325151a3SRui Paulo {
5694325151a3SRui Paulo wpa_printf(MSG_DEBUG,
5695325151a3SRui Paulo "OpenSSL: Success data accepted for resumed session");
5696325151a3SRui Paulo conn->success_data = 1;
5697325151a3SRui Paulo }
5698325151a3SRui Paulo
5699325151a3SRui Paulo
5700325151a3SRui Paulo const struct wpabuf *
tls_connection_get_success_data(struct tls_connection * conn)5701325151a3SRui Paulo tls_connection_get_success_data(struct tls_connection *conn)
5702325151a3SRui Paulo {
5703325151a3SRui Paulo SSL_SESSION *sess;
5704325151a3SRui Paulo
5705325151a3SRui Paulo if (tls_ex_idx_session < 0 ||
5706325151a3SRui Paulo !(sess = SSL_get_session(conn->ssl)))
5707325151a3SRui Paulo return NULL;
5708325151a3SRui Paulo return SSL_SESSION_get_ex_data(sess, tls_ex_idx_session);
5709325151a3SRui Paulo }
5710325151a3SRui Paulo
5711325151a3SRui Paulo
tls_connection_remove_session(struct tls_connection * conn)5712325151a3SRui Paulo void tls_connection_remove_session(struct tls_connection *conn)
5713325151a3SRui Paulo {
5714325151a3SRui Paulo SSL_SESSION *sess;
5715325151a3SRui Paulo
5716325151a3SRui Paulo sess = SSL_get_session(conn->ssl);
5717325151a3SRui Paulo if (!sess)
5718325151a3SRui Paulo return;
5719325151a3SRui Paulo
5720325151a3SRui Paulo if (SSL_CTX_remove_session(conn->ssl_ctx, sess) != 1)
5721325151a3SRui Paulo wpa_printf(MSG_DEBUG,
5722325151a3SRui Paulo "OpenSSL: Session was not cached");
5723325151a3SRui Paulo else
5724325151a3SRui Paulo wpa_printf(MSG_DEBUG,
5725325151a3SRui Paulo "OpenSSL: Removed cached session to disable session resumption");
5726325151a3SRui Paulo }
5727206b73d0SCy Schubert
5728206b73d0SCy Schubert
tls_get_tls_unique(struct tls_connection * conn,u8 * buf,size_t max_len)5729206b73d0SCy Schubert int tls_get_tls_unique(struct tls_connection *conn, u8 *buf, size_t max_len)
5730206b73d0SCy Schubert {
5731206b73d0SCy Schubert size_t len;
5732206b73d0SCy Schubert int reused;
5733206b73d0SCy Schubert
5734206b73d0SCy Schubert reused = SSL_session_reused(conn->ssl);
5735206b73d0SCy Schubert if ((conn->server && !reused) || (!conn->server && reused))
5736206b73d0SCy Schubert len = SSL_get_peer_finished(conn->ssl, buf, max_len);
5737206b73d0SCy Schubert else
5738206b73d0SCy Schubert len = SSL_get_finished(conn->ssl, buf, max_len);
5739206b73d0SCy Schubert
5740206b73d0SCy Schubert if (len == 0 || len > max_len)
5741206b73d0SCy Schubert return -1;
5742206b73d0SCy Schubert
5743206b73d0SCy Schubert return len;
5744206b73d0SCy Schubert }
5745206b73d0SCy Schubert
5746206b73d0SCy Schubert
tls_connection_get_cipher_suite(struct tls_connection * conn)5747206b73d0SCy Schubert u16 tls_connection_get_cipher_suite(struct tls_connection *conn)
5748206b73d0SCy Schubert {
5749206b73d0SCy Schubert const SSL_CIPHER *cipher;
5750206b73d0SCy Schubert
5751206b73d0SCy Schubert cipher = SSL_get_current_cipher(conn->ssl);
5752206b73d0SCy Schubert if (!cipher)
5753206b73d0SCy Schubert return 0;
5754206b73d0SCy Schubert #if OPENSSL_VERSION_NUMBER >= 0x10101000L && !defined(LIBRESSL_VERSION_NUMBER)
5755206b73d0SCy Schubert return SSL_CIPHER_get_protocol_id(cipher);
5756206b73d0SCy Schubert #else
5757206b73d0SCy Schubert return SSL_CIPHER_get_id(cipher) & 0xFFFF;
5758206b73d0SCy Schubert #endif
5759206b73d0SCy Schubert }
5760c1d255d3SCy Schubert
5761c1d255d3SCy Schubert
tls_connection_get_peer_subject(struct tls_connection * conn)5762c1d255d3SCy Schubert const char * tls_connection_get_peer_subject(struct tls_connection *conn)
5763c1d255d3SCy Schubert {
5764c1d255d3SCy Schubert if (conn)
5765c1d255d3SCy Schubert return conn->peer_subject;
5766c1d255d3SCy Schubert return NULL;
5767c1d255d3SCy Schubert }
5768c1d255d3SCy Schubert
5769c1d255d3SCy Schubert
tls_connection_get_own_cert_used(struct tls_connection * conn)5770c1d255d3SCy Schubert bool tls_connection_get_own_cert_used(struct tls_connection *conn)
5771c1d255d3SCy Schubert {
5772c1d255d3SCy Schubert if (conn)
5773c1d255d3SCy Schubert return SSL_get_certificate(conn->ssl) != NULL;
5774c1d255d3SCy Schubert return false;
5775c1d255d3SCy Schubert }
5776