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