blob: f5d734d4123d61259a2b527ada568317454f61c3 [file] [log] [blame]
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001/*
2 * SSL/TLS interface functions for OpenSSL
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08003 * Copyright (c) 2004-2015, Jouni Malinen <j@w1.fi>
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004 *
Dmitry Shmidtc5ec7f52012-03-06 16:33:24 -08005 * This software may be distributed under the terms of the BSD license.
6 * See README for more details.
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007 */
8
9#include "includes.h"
Sunil Ravia04bd252022-05-02 22:54:18 -070010#ifdef CONFIG_TESTING_OPTIONS
11#include <fcntl.h>
12#endif /* CONFIG_TESTING_OPTIONS */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070013
14#ifndef CONFIG_SMARTCARD
15#ifndef OPENSSL_NO_ENGINE
Kenny Rootdb3c5a42012-03-20 17:00:47 -070016#ifndef ANDROID
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070017#define OPENSSL_NO_ENGINE
18#endif
19#endif
Kenny Rootdb3c5a42012-03-20 17:00:47 -070020#endif
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070021
Sunil Ravib0ac25f2024-07-12 01:42:03 +000022#ifndef OPENSSL_NO_ENGINE
23/* OpenSSL 3.0 has moved away from the engine API */
24#define OPENSSL_SUPPRESS_DEPRECATED
25#include <openssl/engine.h>
26#endif /* OPENSSL_NO_ENGINE */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070027#include <openssl/ssl.h>
28#include <openssl/err.h>
Dmitry Shmidt849734c2016-05-27 09:59:01 -070029#include <openssl/opensslv.h>
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070030#include <openssl/pkcs12.h>
31#include <openssl/x509v3.h>
Sunil Ravia04bd252022-05-02 22:54:18 -070032#if OPENSSL_VERSION_NUMBER >= 0x30000000L
33#include <openssl/core_names.h>
34#include <openssl/decoder.h>
35#include <openssl/param_build.h>
36#else /* OpenSSL version >= 3.0 */
Dmitry Shmidtd80a4012015-11-05 16:35:40 -080037#ifndef OPENSSL_NO_DSA
38#include <openssl/dsa.h>
39#endif
40#ifndef OPENSSL_NO_DH
41#include <openssl/dh.h>
42#endif
Sunil Ravia04bd252022-05-02 22:54:18 -070043#endif /* OpenSSL version >= 3.0 */
Dmitry Shmidtd80a4012015-11-05 16:35:40 -080044
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070045#include "common.h"
Sunil Ravia04bd252022-05-02 22:54:18 -070046#include "utils/list.h"
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070047#include "crypto.h"
Dmitry Shmidtaf9da312015-04-03 10:03:11 -070048#include "sha1.h"
Dmitry Shmidtd80a4012015-11-05 16:35:40 -080049#include "sha256.h"
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070050#include "tls.h"
Dmitry Shmidtd7ff03d2015-12-04 14:49:35 -080051#include "tls_openssl.h"
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070052
Dmitry Shmidt849734c2016-05-27 09:59:01 -070053#if !defined(CONFIG_FIPS) && \
54 (defined(EAP_FAST) || defined(EAP_FAST_DYNAMIC) || \
55 defined(EAP_SERVER_FAST))
56#define OPENSSL_NEED_EAP_FAST_PRF
57#endif
58
Hai Shalom81f62d82019-07-22 12:10:00 -070059#if defined(EAP_FAST) || defined(EAP_FAST_DYNAMIC) || \
60 defined(EAP_SERVER_FAST) || defined(EAP_TEAP) || \
61 defined(EAP_SERVER_TEAP)
62#define EAP_FAST_OR_TEAP
63#endif
64
65
Dmitry Shmidt9ead16e2014-10-07 13:15:23 -070066#if defined(OPENSSL_IS_BORINGSSL)
67/* stack_index_t is the return type of OpenSSL's sk_XXX_num() functions. */
68typedef size_t stack_index_t;
69#else
70typedef int stack_index_t;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070071#endif
72
Dmitry Shmidt34af3062013-07-11 10:46:32 -070073#ifdef SSL_set_tlsext_status_type
74#ifndef OPENSSL_NO_TLSEXT
75#define HAVE_OCSP
76#include <openssl/ocsp.h>
77#endif /* OPENSSL_NO_TLSEXT */
78#endif /* SSL_set_tlsext_status_type */
79
Sunil Ravia04bd252022-05-02 22:54:18 -070080#if OPENSSL_VERSION_NUMBER < 0x10100000L && \
Dmitry Shmidt849734c2016-05-27 09:59:01 -070081 !defined(BORINGSSL_API_VERSION)
Dmitry Shmidtde47be72016-01-07 12:52:55 -080082/*
83 * SSL_get_client_random() and SSL_get_server_random() were added in OpenSSL
Dmitry Shmidt849734c2016-05-27 09:59:01 -070084 * 1.1.0 and newer BoringSSL revisions. Provide compatibility wrappers for
85 * older versions.
Dmitry Shmidtde47be72016-01-07 12:52:55 -080086 */
87
88static size_t SSL_get_client_random(const SSL *ssl, unsigned char *out,
89 size_t outlen)
90{
91 if (!ssl->s3 || outlen < SSL3_RANDOM_SIZE)
92 return 0;
93 os_memcpy(out, ssl->s3->client_random, SSL3_RANDOM_SIZE);
94 return SSL3_RANDOM_SIZE;
95}
96
97
98static size_t SSL_get_server_random(const SSL *ssl, unsigned char *out,
99 size_t outlen)
100{
101 if (!ssl->s3 || outlen < SSL3_RANDOM_SIZE)
102 return 0;
103 os_memcpy(out, ssl->s3->server_random, SSL3_RANDOM_SIZE);
104 return SSL3_RANDOM_SIZE;
105}
106
107
Dmitry Shmidt849734c2016-05-27 09:59:01 -0700108#ifdef OPENSSL_NEED_EAP_FAST_PRF
Dmitry Shmidtde47be72016-01-07 12:52:55 -0800109static size_t SSL_SESSION_get_master_key(const SSL_SESSION *session,
110 unsigned char *out, size_t outlen)
111{
112 if (!session || session->master_key_length < 0 ||
113 (size_t) session->master_key_length > outlen)
114 return 0;
115 if ((size_t) session->master_key_length < outlen)
116 outlen = session->master_key_length;
117 os_memcpy(out, session->master_key, outlen);
118 return outlen;
119}
Dmitry Shmidt849734c2016-05-27 09:59:01 -0700120#endif /* OPENSSL_NEED_EAP_FAST_PRF */
Dmitry Shmidtde47be72016-01-07 12:52:55 -0800121
122#endif
123
Sunil Ravia04bd252022-05-02 22:54:18 -0700124#if OPENSSL_VERSION_NUMBER < 0x10100000L
Hai Shalom39ba6fc2019-01-22 12:40:38 -0800125static const unsigned char * ASN1_STRING_get0_data(const ASN1_STRING *x)
126{
127 return ASN1_STRING_data((ASN1_STRING *) x);
128}
Dmitry Shmidtd2986c22017-10-23 14:22:09 -0700129#endif
130
Gabriel Birena5bdf372022-12-15 20:54:33 +0000131static int tls_openssl_ref_count = 0;
132static int tls_ex_idx_session = -1;
133
134struct tls_session_data {
135 struct dl_list list;
136 struct wpabuf *buf;
137};
138
139struct tls_context {
140 void (*event_cb)(void *ctx, enum tls_event ev,
141 union tls_event_data *data);
142 void *cb_ctx;
143 int cert_in_cb;
144 char *ocsp_stapling_response;
145 struct dl_list sessions; /* struct tls_session_data */
146};
147
Gabriel Birencd0cb1c2023-04-17 18:16:23 +0000148struct tls_data {
149 SSL_CTX *ssl;
150 unsigned int tls_session_lifetime;
151 int check_crl;
152 int check_crl_strict;
153 char *ca_cert;
154 unsigned int crl_reload_interval;
155 struct os_reltime crl_last_reload;
156 char *check_cert_subject;
Sunil Ravib0ac25f2024-07-12 01:42:03 +0000157 char *openssl_ciphers;
Gabriel Birencd0cb1c2023-04-17 18:16:23 +0000158};
159
160struct tls_connection {
161 struct tls_context *context;
162 struct tls_data *data;
163 SSL_CTX *ssl_ctx;
164 SSL *ssl;
165 BIO *ssl_in, *ssl_out;
166#if defined(ANDROID) || !defined(OPENSSL_NO_ENGINE)
167 ENGINE *engine; /* functional reference to the engine */
168 EVP_PKEY *private_key; /* the private key if using engine */
169#endif /* OPENSSL_NO_ENGINE */
170 char *subject_match, *altsubject_match, *suffix_match, *domain_match;
171 char *check_cert_subject;
172 int read_alerts, write_alerts, failed;
173
174 tls_session_ticket_cb session_ticket_cb;
175 void *session_ticket_cb_ctx;
176
177 /* SessionTicket received from OpenSSL hello_extension_cb (server) */
178 u8 *session_ticket;
179 size_t session_ticket_len;
180
181 unsigned int ca_cert_verify:1;
182 unsigned int cert_probe:1;
183 unsigned int server_cert_only:1;
184 unsigned int invalid_hb_used:1;
185 unsigned int success_data:1;
186 unsigned int client_hello_generated:1;
187 unsigned int server:1;
188
189 u8 srv_cert_hash[32];
190
191 unsigned int flags;
192
193 X509 *peer_cert;
194 X509 *peer_issuer;
195 X509 *peer_issuer_issuer;
196 char *peer_subject; /* peer subject info for authenticated peer */
197
198 unsigned char client_random[SSL3_RANDOM_SIZE];
199 unsigned char server_random[SSL3_RANDOM_SIZE];
200
201 u16 cipher_suite;
202 int server_dh_prime_len;
203};
204
Gabriel Birena5bdf372022-12-15 20:54:33 +0000205static struct tls_context *tls_global = NULL;
206static tls_get_certificate_cb certificate_callback_global = NULL;
Gabriel Biren60ae0682023-11-01 22:04:12 +0000207static tls_openssl_failure_cb openssl_failure_callback_global = NULL;
Gabriel Birena5bdf372022-12-15 20:54:33 +0000208
Dmitry Shmidtff079172013-11-08 14:10:30 -0800209#ifdef ANDROID
210#include <openssl/pem.h>
Dmitry Shmidtff079172013-11-08 14:10:30 -0800211
Pavel Grafov4d8552e2018-02-06 11:28:29 +0000212#include <log/log.h>
213#include <log/log_event_list.h>
214
215#define CERT_VALIDATION_FAILURE 210033
Hai Shalom7ad2a872021-08-02 18:56:55 -0700216#define ANDROID_KEYSTORE_PREFIX "keystore://"
217#define ANDROID_KEYSTORE_PREFIX_LEN os_strlen(ANDROID_KEYSTORE_PREFIX)
218#define ANDROID_KEYSTORE_ENCODED_PREFIX "keystores://"
219#define ANDROID_KEYSTORE_ENCODED_PREFIX_LEN os_strlen(ANDROID_KEYSTORE_ENCODED_PREFIX)
Pavel Grafov4d8552e2018-02-06 11:28:29 +0000220
221static void log_cert_validation_failure(const char *reason)
222{
223 android_log_context ctx = create_android_logger(CERT_VALIDATION_FAILURE);
224 android_log_write_string8(ctx, reason);
225 android_log_write_list(ctx, LOG_ID_SECURITY);
226 android_log_destroy(&ctx);
227}
228
229
Gabriel Birenff4f8382023-04-06 20:14:39 +0000230static BIO* BIO_from_keystore(const char *alias, struct tls_connection *conn)
Dmitry Shmidtff079172013-11-08 14:10:30 -0800231{
232 BIO *bio = NULL;
233 uint8_t *value = NULL;
Gabriel Birenff4f8382023-04-06 20:14:39 +0000234
235 void *cb_ctx = NULL;
236 if (conn != NULL && conn->context != NULL) {
237 cb_ctx = conn->context->cb_ctx;
238 }
239
240 if (cb_ctx != NULL && certificate_callback_global != NULL) {
Gabriel Biren980c48a2023-03-27 21:49:21 +0000241 wpa_printf(MSG_INFO, "Retrieving certificate using callback");
Gabriel Birenff4f8382023-04-06 20:14:39 +0000242 int length = (*certificate_callback_global)(cb_ctx, alias, &value);
Gabriel Birena5bdf372022-12-15 20:54:33 +0000243 if (length != -1 && (bio = BIO_new(BIO_s_mem())) != NULL)
244 BIO_write(bio, value, length);
Gabriel Birenff4f8382023-04-06 20:14:39 +0000245 free(value);
Gabriel Birena5bdf372022-12-15 20:54:33 +0000246 }
Dmitry Shmidtff079172013-11-08 14:10:30 -0800247 return bio;
248}
Dmitry Shmidtb97e4282016-02-08 10:16:07 -0800249
Gabriel Birenff4f8382023-04-06 20:14:39 +0000250static int tls_add_ca_from_keystore(X509_STORE *ctx, const char *alias, struct tls_connection *conn)
Dmitry Shmidtb97e4282016-02-08 10:16:07 -0800251{
Gabriel Birenff4f8382023-04-06 20:14:39 +0000252 BIO *bio = BIO_from_keystore(alias, conn);
Dmitry Shmidtb97e4282016-02-08 10:16:07 -0800253 STACK_OF(X509_INFO) *stack = NULL;
254 stack_index_t i;
Hai Shalom22171592021-04-02 16:05:23 -0700255 int ret = 0;
Dmitry Shmidtb97e4282016-02-08 10:16:07 -0800256
Hai Shalom22171592021-04-02 16:05:23 -0700257 if (!bio) {
Hai Shalom7ad2a872021-08-02 18:56:55 -0700258 wpa_printf(MSG_ERROR, "OpenSSL: Failed to parse certificate: %s",
259 alias);
Hai Shalom22171592021-04-02 16:05:23 -0700260 return -1;
Dmitry Shmidtb97e4282016-02-08 10:16:07 -0800261 }
262
Hai Shalom7ad2a872021-08-02 18:56:55 -0700263 // Keystore returns X.509 certificates in PEM encoding
Hai Shalom22171592021-04-02 16:05:23 -0700264 stack = PEM_X509_INFO_read_bio(bio, NULL, NULL, NULL);
265 BIO_free(bio);
266
Dmitry Shmidtb97e4282016-02-08 10:16:07 -0800267 if (!stack) {
Hai Shalom7ad2a872021-08-02 18:56:55 -0700268 wpa_printf(MSG_ERROR, "OpenSSL: Failed to parse certificate: %s",
269 alias);
Dmitry Shmidtb97e4282016-02-08 10:16:07 -0800270 return -1;
271 }
272
273 for (i = 0; i < sk_X509_INFO_num(stack); ++i) {
274 X509_INFO *info = sk_X509_INFO_value(stack, i);
275
276 if (info->x509)
Hai Shalom22171592021-04-02 16:05:23 -0700277 if (!X509_STORE_add_cert(ctx, info->x509)) {
Hai Shalom7ad2a872021-08-02 18:56:55 -0700278 wpa_printf(MSG_ERROR,
279 "OpenSSL: Failed to add Root CA certificate");
Hai Shalom22171592021-04-02 16:05:23 -0700280 ret = -1;
281 break;
282 }
Dmitry Shmidtb97e4282016-02-08 10:16:07 -0800283 if (info->crl)
284 X509_STORE_add_crl(ctx, info->crl);
285 }
286
287 sk_X509_INFO_pop_free(stack, X509_INFO_free);
Hai Shalom22171592021-04-02 16:05:23 -0700288 return ret;
Dmitry Shmidtb97e4282016-02-08 10:16:07 -0800289}
290
291
292static int tls_add_ca_from_keystore_encoded(X509_STORE *ctx,
Gabriel Birenff4f8382023-04-06 20:14:39 +0000293 const char *encoded_alias,
294 struct tls_connection *conn)
Dmitry Shmidtb97e4282016-02-08 10:16:07 -0800295{
296 int rc = -1;
Hai Shalom7ad2a872021-08-02 18:56:55 -0700297 int len = os_strlen(encoded_alias);
Dmitry Shmidtb97e4282016-02-08 10:16:07 -0800298 unsigned char *decoded_alias;
299
300 if (len & 1) {
301 wpa_printf(MSG_WARNING, "Invalid hex-encoded alias: %s",
Hai Shalom7ad2a872021-08-02 18:56:55 -0700302 encoded_alias);
Dmitry Shmidtb97e4282016-02-08 10:16:07 -0800303 return rc;
304 }
305
306 decoded_alias = os_malloc(len / 2 + 1);
307 if (decoded_alias) {
Hai Shalom7ad2a872021-08-02 18:56:55 -0700308 if (!hexstr2bin(encoded_alias, decoded_alias, len / 2)) {
Dmitry Shmidtb97e4282016-02-08 10:16:07 -0800309 decoded_alias[len / 2] = '\0';
310 rc = tls_add_ca_from_keystore(
Gabriel Birenff4f8382023-04-06 20:14:39 +0000311 ctx, (const char *) decoded_alias, conn);
Dmitry Shmidtb97e4282016-02-08 10:16:07 -0800312 }
313 os_free(decoded_alias);
314 }
315
316 return rc;
317}
318
Dmitry Shmidtff079172013-11-08 14:10:30 -0800319#endif /* ANDROID */
320
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700321
Dmitry Shmidtea69e842013-05-13 14:52:28 -0700322static struct tls_context * tls_context_new(const struct tls_config *conf)
323{
324 struct tls_context *context = os_zalloc(sizeof(*context));
325 if (context == NULL)
326 return NULL;
Sunil Ravia04bd252022-05-02 22:54:18 -0700327 dl_list_init(&context->sessions);
Dmitry Shmidtea69e842013-05-13 14:52:28 -0700328 if (conf) {
329 context->event_cb = conf->event_cb;
330 context->cb_ctx = conf->cb_ctx;
331 context->cert_in_cb = conf->cert_in_cb;
332 }
333 return context;
334}
335
336
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700337#ifdef CONFIG_NO_STDOUT_DEBUG
338
339static void _tls_show_errors(void)
340{
341 unsigned long err;
342
343 while ((err = ERR_get_error())) {
344 /* Just ignore the errors, since stdout is disabled */
345 }
346}
347#define tls_show_errors(l, f, t) _tls_show_errors()
348
349#else /* CONFIG_NO_STDOUT_DEBUG */
350
351static void tls_show_errors(int level, const char *func, const char *txt)
352{
353 unsigned long err;
354
355 wpa_printf(level, "OpenSSL: %s - %s %s",
356 func, txt, ERR_error_string(ERR_get_error(), NULL));
357
358 while ((err = ERR_get_error())) {
359 wpa_printf(MSG_INFO, "OpenSSL: pending error: %s",
360 ERR_error_string(err, NULL));
361 }
362}
363
364#endif /* CONFIG_NO_STDOUT_DEBUG */
365
366
Hai Shalom74f70d42019-02-11 14:42:39 -0800367static X509_STORE * tls_crl_cert_reload(const char *ca_cert, int check_crl)
368{
369 int flags;
370 X509_STORE *store;
371
372 store = X509_STORE_new();
373 if (!store) {
374 wpa_printf(MSG_DEBUG,
375 "OpenSSL: %s - failed to allocate new certificate store",
376 __func__);
377 return NULL;
378 }
379
380 if (ca_cert && X509_STORE_load_locations(store, ca_cert, NULL) != 1) {
381 tls_show_errors(MSG_WARNING, __func__,
382 "Failed to load root certificates");
383 X509_STORE_free(store);
384 return NULL;
385 }
386
387 flags = check_crl ? X509_V_FLAG_CRL_CHECK : 0;
388 if (check_crl == 2)
389 flags |= X509_V_FLAG_CRL_CHECK_ALL;
390
391 X509_STORE_set_flags(store, flags);
392
393 return store;
394}
395
396
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700397#ifdef CONFIG_NATIVE_WINDOWS
398
399/* Windows CryptoAPI and access to certificate stores */
400#include <wincrypt.h>
401
402#ifdef __MINGW32_VERSION
403/*
404 * MinGW does not yet include all the needed definitions for CryptoAPI, so
405 * define here whatever extra is needed.
406 */
407#define CERT_SYSTEM_STORE_CURRENT_USER (1 << 16)
408#define CERT_STORE_READONLY_FLAG 0x00008000
409#define CERT_STORE_OPEN_EXISTING_FLAG 0x00004000
410
411#endif /* __MINGW32_VERSION */
412
413
414struct cryptoapi_rsa_data {
415 const CERT_CONTEXT *cert;
416 HCRYPTPROV crypt_prov;
417 DWORD key_spec;
418 BOOL free_crypt_prov;
419};
420
421
422static void cryptoapi_error(const char *msg)
423{
424 wpa_printf(MSG_INFO, "CryptoAPI: %s; err=%u",
425 msg, (unsigned int) GetLastError());
426}
427
428
429static int cryptoapi_rsa_pub_enc(int flen, const unsigned char *from,
430 unsigned char *to, RSA *rsa, int padding)
431{
432 wpa_printf(MSG_DEBUG, "%s - not implemented", __func__);
433 return 0;
434}
435
436
437static int cryptoapi_rsa_pub_dec(int flen, const unsigned char *from,
438 unsigned char *to, RSA *rsa, int padding)
439{
440 wpa_printf(MSG_DEBUG, "%s - not implemented", __func__);
441 return 0;
442}
443
444
445static int cryptoapi_rsa_priv_enc(int flen, const unsigned char *from,
446 unsigned char *to, RSA *rsa, int padding)
447{
448 struct cryptoapi_rsa_data *priv =
449 (struct cryptoapi_rsa_data *) rsa->meth->app_data;
450 HCRYPTHASH hash;
451 DWORD hash_size, len, i;
452 unsigned char *buf = NULL;
453 int ret = 0;
454
455 if (priv == NULL) {
456 RSAerr(RSA_F_RSA_EAY_PRIVATE_ENCRYPT,
457 ERR_R_PASSED_NULL_PARAMETER);
458 return 0;
459 }
460
461 if (padding != RSA_PKCS1_PADDING) {
462 RSAerr(RSA_F_RSA_EAY_PRIVATE_ENCRYPT,
463 RSA_R_UNKNOWN_PADDING_TYPE);
464 return 0;
465 }
466
467 if (flen != 16 /* MD5 */ + 20 /* SHA-1 */) {
468 wpa_printf(MSG_INFO, "%s - only MD5-SHA1 hash supported",
469 __func__);
470 RSAerr(RSA_F_RSA_EAY_PRIVATE_ENCRYPT,
471 RSA_R_INVALID_MESSAGE_LENGTH);
472 return 0;
473 }
474
475 if (!CryptCreateHash(priv->crypt_prov, CALG_SSL3_SHAMD5, 0, 0, &hash))
476 {
477 cryptoapi_error("CryptCreateHash failed");
478 return 0;
479 }
480
481 len = sizeof(hash_size);
482 if (!CryptGetHashParam(hash, HP_HASHSIZE, (BYTE *) &hash_size, &len,
483 0)) {
484 cryptoapi_error("CryptGetHashParam failed");
485 goto err;
486 }
487
488 if ((int) hash_size != flen) {
489 wpa_printf(MSG_INFO, "CryptoAPI: Invalid hash size (%u != %d)",
490 (unsigned) hash_size, flen);
491 RSAerr(RSA_F_RSA_EAY_PRIVATE_ENCRYPT,
492 RSA_R_INVALID_MESSAGE_LENGTH);
493 goto err;
494 }
495 if (!CryptSetHashParam(hash, HP_HASHVAL, (BYTE * ) from, 0)) {
496 cryptoapi_error("CryptSetHashParam failed");
497 goto err;
498 }
499
500 len = RSA_size(rsa);
501 buf = os_malloc(len);
502 if (buf == NULL) {
503 RSAerr(RSA_F_RSA_EAY_PRIVATE_ENCRYPT, ERR_R_MALLOC_FAILURE);
504 goto err;
505 }
506
507 if (!CryptSignHash(hash, priv->key_spec, NULL, 0, buf, &len)) {
508 cryptoapi_error("CryptSignHash failed");
509 goto err;
510 }
511
512 for (i = 0; i < len; i++)
513 to[i] = buf[len - i - 1];
514 ret = len;
515
516err:
517 os_free(buf);
518 CryptDestroyHash(hash);
519
520 return ret;
521}
522
523
524static int cryptoapi_rsa_priv_dec(int flen, const unsigned char *from,
525 unsigned char *to, RSA *rsa, int padding)
526{
527 wpa_printf(MSG_DEBUG, "%s - not implemented", __func__);
528 return 0;
529}
530
531
532static void cryptoapi_free_data(struct cryptoapi_rsa_data *priv)
533{
534 if (priv == NULL)
535 return;
536 if (priv->crypt_prov && priv->free_crypt_prov)
537 CryptReleaseContext(priv->crypt_prov, 0);
538 if (priv->cert)
539 CertFreeCertificateContext(priv->cert);
540 os_free(priv);
541}
542
543
544static int cryptoapi_finish(RSA *rsa)
545{
546 cryptoapi_free_data((struct cryptoapi_rsa_data *) rsa->meth->app_data);
547 os_free((void *) rsa->meth);
548 rsa->meth = NULL;
549 return 1;
550}
551
552
553static const CERT_CONTEXT * cryptoapi_find_cert(const char *name, DWORD store)
554{
555 HCERTSTORE cs;
556 const CERT_CONTEXT *ret = NULL;
557
558 cs = CertOpenStore((LPCSTR) CERT_STORE_PROV_SYSTEM, 0, 0,
559 store | CERT_STORE_OPEN_EXISTING_FLAG |
560 CERT_STORE_READONLY_FLAG, L"MY");
561 if (cs == NULL) {
562 cryptoapi_error("Failed to open 'My system store'");
563 return NULL;
564 }
565
566 if (strncmp(name, "cert://", 7) == 0) {
567 unsigned short wbuf[255];
568 MultiByteToWideChar(CP_ACP, 0, name + 7, -1, wbuf, 255);
569 ret = CertFindCertificateInStore(cs, X509_ASN_ENCODING |
570 PKCS_7_ASN_ENCODING,
571 0, CERT_FIND_SUBJECT_STR,
572 wbuf, NULL);
573 } else if (strncmp(name, "hash://", 7) == 0) {
574 CRYPT_HASH_BLOB blob;
575 int len;
576 const char *hash = name + 7;
577 unsigned char *buf;
578
579 len = os_strlen(hash) / 2;
580 buf = os_malloc(len);
581 if (buf && hexstr2bin(hash, buf, len) == 0) {
582 blob.cbData = len;
583 blob.pbData = buf;
584 ret = CertFindCertificateInStore(cs,
585 X509_ASN_ENCODING |
586 PKCS_7_ASN_ENCODING,
587 0, CERT_FIND_HASH,
588 &blob, NULL);
589 }
590 os_free(buf);
591 }
592
593 CertCloseStore(cs, 0);
594
595 return ret;
596}
597
598
599static int tls_cryptoapi_cert(SSL *ssl, const char *name)
600{
601 X509 *cert = NULL;
602 RSA *rsa = NULL, *pub_rsa;
603 struct cryptoapi_rsa_data *priv;
604 RSA_METHOD *rsa_meth;
605
606 if (name == NULL ||
607 (strncmp(name, "cert://", 7) != 0 &&
608 strncmp(name, "hash://", 7) != 0))
609 return -1;
610
611 priv = os_zalloc(sizeof(*priv));
612 rsa_meth = os_zalloc(sizeof(*rsa_meth));
613 if (priv == NULL || rsa_meth == NULL) {
614 wpa_printf(MSG_WARNING, "CryptoAPI: Failed to allocate memory "
615 "for CryptoAPI RSA method");
616 os_free(priv);
617 os_free(rsa_meth);
618 return -1;
619 }
620
621 priv->cert = cryptoapi_find_cert(name, CERT_SYSTEM_STORE_CURRENT_USER);
622 if (priv->cert == NULL) {
623 priv->cert = cryptoapi_find_cert(
624 name, CERT_SYSTEM_STORE_LOCAL_MACHINE);
625 }
626 if (priv->cert == NULL) {
627 wpa_printf(MSG_INFO, "CryptoAPI: Could not find certificate "
628 "'%s'", name);
629 goto err;
630 }
631
Dmitry Shmidt216983b2015-02-06 10:50:36 -0800632 cert = d2i_X509(NULL,
633 (const unsigned char **) &priv->cert->pbCertEncoded,
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700634 priv->cert->cbCertEncoded);
635 if (cert == NULL) {
636 wpa_printf(MSG_INFO, "CryptoAPI: Could not process X509 DER "
637 "encoding");
638 goto err;
639 }
640
641 if (!CryptAcquireCertificatePrivateKey(priv->cert,
642 CRYPT_ACQUIRE_COMPARE_KEY_FLAG,
643 NULL, &priv->crypt_prov,
644 &priv->key_spec,
645 &priv->free_crypt_prov)) {
646 cryptoapi_error("Failed to acquire a private key for the "
647 "certificate");
648 goto err;
649 }
650
651 rsa_meth->name = "Microsoft CryptoAPI RSA Method";
652 rsa_meth->rsa_pub_enc = cryptoapi_rsa_pub_enc;
653 rsa_meth->rsa_pub_dec = cryptoapi_rsa_pub_dec;
654 rsa_meth->rsa_priv_enc = cryptoapi_rsa_priv_enc;
655 rsa_meth->rsa_priv_dec = cryptoapi_rsa_priv_dec;
656 rsa_meth->finish = cryptoapi_finish;
657 rsa_meth->flags = RSA_METHOD_FLAG_NO_CHECK;
658 rsa_meth->app_data = (char *) priv;
659
660 rsa = RSA_new();
661 if (rsa == NULL) {
662 SSLerr(SSL_F_SSL_CTX_USE_CERTIFICATE_FILE,
663 ERR_R_MALLOC_FAILURE);
664 goto err;
665 }
666
667 if (!SSL_use_certificate(ssl, cert)) {
668 RSA_free(rsa);
669 rsa = NULL;
670 goto err;
671 }
672 pub_rsa = cert->cert_info->key->pkey->pkey.rsa;
673 X509_free(cert);
674 cert = NULL;
675
676 rsa->n = BN_dup(pub_rsa->n);
677 rsa->e = BN_dup(pub_rsa->e);
678 if (!RSA_set_method(rsa, rsa_meth))
679 goto err;
680
681 if (!SSL_use_RSAPrivateKey(ssl, rsa))
682 goto err;
683 RSA_free(rsa);
684
685 return 0;
686
687err:
688 if (cert)
689 X509_free(cert);
690 if (rsa)
691 RSA_free(rsa);
692 else {
693 os_free(rsa_meth);
694 cryptoapi_free_data(priv);
695 }
696 return -1;
697}
698
699
700static int tls_cryptoapi_ca_cert(SSL_CTX *ssl_ctx, SSL *ssl, const char *name)
701{
702 HCERTSTORE cs;
703 PCCERT_CONTEXT ctx = NULL;
704 X509 *cert;
705 char buf[128];
706 const char *store;
707#ifdef UNICODE
708 WCHAR *wstore;
709#endif /* UNICODE */
710
711 if (name == NULL || strncmp(name, "cert_store://", 13) != 0)
712 return -1;
713
714 store = name + 13;
715#ifdef UNICODE
716 wstore = os_malloc((os_strlen(store) + 1) * sizeof(WCHAR));
717 if (wstore == NULL)
718 return -1;
719 wsprintf(wstore, L"%S", store);
720 cs = CertOpenSystemStore(0, wstore);
721 os_free(wstore);
722#else /* UNICODE */
723 cs = CertOpenSystemStore(0, store);
724#endif /* UNICODE */
725 if (cs == NULL) {
726 wpa_printf(MSG_DEBUG, "%s: failed to open system cert store "
727 "'%s': error=%d", __func__, store,
728 (int) GetLastError());
729 return -1;
730 }
731
732 while ((ctx = CertEnumCertificatesInStore(cs, ctx))) {
Dmitry Shmidt216983b2015-02-06 10:50:36 -0800733 cert = d2i_X509(NULL,
734 (const unsigned char **) &ctx->pbCertEncoded,
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700735 ctx->cbCertEncoded);
736 if (cert == NULL) {
737 wpa_printf(MSG_INFO, "CryptoAPI: Could not process "
738 "X509 DER encoding for CA cert");
739 continue;
740 }
741
742 X509_NAME_oneline(X509_get_subject_name(cert), buf,
743 sizeof(buf));
744 wpa_printf(MSG_DEBUG, "OpenSSL: Loaded CA certificate for "
745 "system certificate store: subject='%s'", buf);
746
Dmitry Shmidt849734c2016-05-27 09:59:01 -0700747 if (!X509_STORE_add_cert(SSL_CTX_get_cert_store(ssl_ctx),
748 cert)) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700749 tls_show_errors(MSG_WARNING, __func__,
750 "Failed to add ca_cert to OpenSSL "
751 "certificate store");
752 }
753
754 X509_free(cert);
755 }
756
757 if (!CertCloseStore(cs, 0)) {
758 wpa_printf(MSG_DEBUG, "%s: failed to close system cert store "
759 "'%s': error=%d", __func__, name + 13,
760 (int) GetLastError());
761 }
762
763 return 0;
764}
765
766
767#else /* CONFIG_NATIVE_WINDOWS */
768
769static int tls_cryptoapi_cert(SSL *ssl, const char *name)
770{
771 return -1;
772}
773
774#endif /* CONFIG_NATIVE_WINDOWS */
775
776
777static void ssl_info_cb(const SSL *ssl, int where, int ret)
778{
779 const char *str;
780 int w;
781
782 wpa_printf(MSG_DEBUG, "SSL: (where=0x%x ret=0x%x)", where, ret);
783 w = where & ~SSL_ST_MASK;
784 if (w & SSL_ST_CONNECT)
785 str = "SSL_connect";
786 else if (w & SSL_ST_ACCEPT)
787 str = "SSL_accept";
788 else
789 str = "undefined";
790
791 if (where & SSL_CB_LOOP) {
792 wpa_printf(MSG_DEBUG, "SSL: %s:%s",
793 str, SSL_state_string_long(ssl));
794 } else if (where & SSL_CB_ALERT) {
Dmitry Shmidtea69e842013-05-13 14:52:28 -0700795 struct tls_connection *conn = SSL_get_app_data((SSL *) ssl);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700796 wpa_printf(MSG_INFO, "SSL: SSL3 alert: %s:%s:%s",
797 where & SSL_CB_READ ?
798 "read (remote end reported an error)" :
799 "write (local SSL3 detected an error)",
800 SSL_alert_type_string_long(ret),
801 SSL_alert_desc_string_long(ret));
802 if ((ret >> 8) == SSL3_AL_FATAL) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700803 if (where & SSL_CB_READ)
804 conn->read_alerts++;
805 else
806 conn->write_alerts++;
807 }
Dmitry Shmidtea69e842013-05-13 14:52:28 -0700808 if (conn->context->event_cb != NULL) {
Dmitry Shmidt04949592012-07-19 12:16:46 -0700809 union tls_event_data ev;
Dmitry Shmidtea69e842013-05-13 14:52:28 -0700810 struct tls_context *context = conn->context;
Dmitry Shmidt04949592012-07-19 12:16:46 -0700811 os_memset(&ev, 0, sizeof(ev));
812 ev.alert.is_local = !(where & SSL_CB_READ);
813 ev.alert.type = SSL_alert_type_string_long(ret);
814 ev.alert.description = SSL_alert_desc_string_long(ret);
Dmitry Shmidtea69e842013-05-13 14:52:28 -0700815 context->event_cb(context->cb_ctx, TLS_ALERT, &ev);
Dmitry Shmidt04949592012-07-19 12:16:46 -0700816 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700817 } else if (where & SSL_CB_EXIT && ret <= 0) {
818 wpa_printf(MSG_DEBUG, "SSL: %s:%s in %s",
819 str, ret == 0 ? "failed" : "error",
820 SSL_state_string_long(ssl));
821 }
822}
823
824
825#ifndef OPENSSL_NO_ENGINE
826/**
827 * tls_engine_load_dynamic_generic - load any openssl engine
828 * @pre: an array of commands and values that load an engine initialized
829 * in the engine specific function
830 * @post: an array of commands and values that initialize an already loaded
831 * engine (or %NULL if not required)
832 * @id: the engine id of the engine to load (only required if post is not %NULL
833 *
834 * This function is a generic function that loads any openssl engine.
835 *
836 * Returns: 0 on success, -1 on failure
837 */
838static int tls_engine_load_dynamic_generic(const char *pre[],
839 const char *post[], const char *id)
840{
841 ENGINE *engine;
842 const char *dynamic_id = "dynamic";
843
844 engine = ENGINE_by_id(id);
845 if (engine) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700846 wpa_printf(MSG_DEBUG, "ENGINE: engine '%s' is already "
847 "available", id);
Dmitry Shmidtd5ab1b52016-06-21 12:38:41 -0700848 /*
849 * If it was auto-loaded by ENGINE_by_id() we might still
850 * need to tell it which PKCS#11 module to use in legacy
851 * (non-p11-kit) environments. Do so now; even if it was
852 * properly initialised before, setting it again will be
853 * harmless.
854 */
855 goto found;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700856 }
857 ERR_clear_error();
858
859 engine = ENGINE_by_id(dynamic_id);
860 if (engine == NULL) {
861 wpa_printf(MSG_INFO, "ENGINE: Can't find engine %s [%s]",
862 dynamic_id,
863 ERR_error_string(ERR_get_error(), NULL));
864 return -1;
865 }
866
867 /* Perform the pre commands. This will load the engine. */
868 while (pre && pre[0]) {
869 wpa_printf(MSG_DEBUG, "ENGINE: '%s' '%s'", pre[0], pre[1]);
870 if (ENGINE_ctrl_cmd_string(engine, pre[0], pre[1], 0) == 0) {
871 wpa_printf(MSG_INFO, "ENGINE: ctrl cmd_string failed: "
872 "%s %s [%s]", pre[0], pre[1],
873 ERR_error_string(ERR_get_error(), NULL));
874 ENGINE_free(engine);
875 return -1;
876 }
877 pre += 2;
878 }
879
880 /*
881 * Free the reference to the "dynamic" engine. The loaded engine can
882 * now be looked up using ENGINE_by_id().
883 */
884 ENGINE_free(engine);
885
886 engine = ENGINE_by_id(id);
887 if (engine == NULL) {
888 wpa_printf(MSG_INFO, "ENGINE: Can't find engine %s [%s]",
889 id, ERR_error_string(ERR_get_error(), NULL));
890 return -1;
891 }
Dmitry Shmidtd5ab1b52016-06-21 12:38:41 -0700892 found:
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700893 while (post && post[0]) {
894 wpa_printf(MSG_DEBUG, "ENGINE: '%s' '%s'", post[0], post[1]);
895 if (ENGINE_ctrl_cmd_string(engine, post[0], post[1], 0) == 0) {
896 wpa_printf(MSG_DEBUG, "ENGINE: ctrl cmd_string failed:"
897 " %s %s [%s]", post[0], post[1],
898 ERR_error_string(ERR_get_error(), NULL));
899 ENGINE_remove(engine);
900 ENGINE_free(engine);
901 return -1;
902 }
903 post += 2;
904 }
905 ENGINE_free(engine);
906
907 return 0;
908}
909
910
911/**
912 * tls_engine_load_dynamic_pkcs11 - load the pkcs11 engine provided by opensc
913 * @pkcs11_so_path: pksc11_so_path from the configuration
914 * @pcks11_module_path: pkcs11_module_path from the configuration
915 */
916static int tls_engine_load_dynamic_pkcs11(const char *pkcs11_so_path,
917 const char *pkcs11_module_path)
918{
919 char *engine_id = "pkcs11";
920 const char *pre_cmd[] = {
921 "SO_PATH", NULL /* pkcs11_so_path */,
922 "ID", NULL /* engine_id */,
923 "LIST_ADD", "1",
924 /* "NO_VCHECK", "1", */
925 "LOAD", NULL,
926 NULL, NULL
927 };
928 const char *post_cmd[] = {
929 "MODULE_PATH", NULL /* pkcs11_module_path */,
930 NULL, NULL
931 };
932
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800933 if (!pkcs11_so_path)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700934 return 0;
935
936 pre_cmd[1] = pkcs11_so_path;
937 pre_cmd[3] = engine_id;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800938 if (pkcs11_module_path)
939 post_cmd[1] = pkcs11_module_path;
940 else
941 post_cmd[0] = NULL;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700942
943 wpa_printf(MSG_DEBUG, "ENGINE: Loading pkcs11 Engine from %s",
944 pkcs11_so_path);
945
946 return tls_engine_load_dynamic_generic(pre_cmd, post_cmd, engine_id);
947}
948
949
950/**
951 * tls_engine_load_dynamic_opensc - load the opensc engine provided by opensc
952 * @opensc_so_path: opensc_so_path from the configuration
953 */
954static int tls_engine_load_dynamic_opensc(const char *opensc_so_path)
955{
956 char *engine_id = "opensc";
957 const char *pre_cmd[] = {
958 "SO_PATH", NULL /* opensc_so_path */,
959 "ID", NULL /* engine_id */,
960 "LIST_ADD", "1",
961 "LOAD", NULL,
962 NULL, NULL
963 };
964
965 if (!opensc_so_path)
966 return 0;
967
968 pre_cmd[1] = opensc_so_path;
969 pre_cmd[3] = engine_id;
970
971 wpa_printf(MSG_DEBUG, "ENGINE: Loading OpenSC Engine from %s",
972 opensc_so_path);
973
974 return tls_engine_load_dynamic_generic(pre_cmd, NULL, engine_id);
975}
976#endif /* OPENSSL_NO_ENGINE */
977
978
Sunil Ravia04bd252022-05-02 22:54:18 -0700979static struct tls_session_data * get_session_data(struct tls_context *context,
980 const struct wpabuf *buf)
981{
982 struct tls_session_data *data;
983
984 dl_list_for_each(data, &context->sessions, struct tls_session_data,
985 list) {
986 if (data->buf == buf)
987 return data;
988 }
989
990 return NULL;
991}
992
993
Dmitry Shmidtd80a4012015-11-05 16:35:40 -0800994static void remove_session_cb(SSL_CTX *ctx, SSL_SESSION *sess)
995{
996 struct wpabuf *buf;
Sunil Ravia04bd252022-05-02 22:54:18 -0700997 struct tls_context *context;
998 struct tls_session_data *found;
999
1000 wpa_printf(MSG_DEBUG,
1001 "OpenSSL: Remove session %p (tls_ex_idx_session=%d)", sess,
1002 tls_ex_idx_session);
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08001003
1004 if (tls_ex_idx_session < 0)
1005 return;
1006 buf = SSL_SESSION_get_ex_data(sess, tls_ex_idx_session);
1007 if (!buf)
1008 return;
Sunil Ravia04bd252022-05-02 22:54:18 -07001009
1010 context = SSL_CTX_get_app_data(ctx);
1011 SSL_SESSION_set_ex_data(sess, tls_ex_idx_session, NULL);
1012 found = get_session_data(context, buf);
1013 if (!found) {
1014 wpa_printf(MSG_DEBUG,
1015 "OpenSSL: Do not free application session data %p (sess %p)",
1016 buf, sess);
1017 return;
1018 }
1019
1020 dl_list_del(&found->list);
1021 os_free(found);
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08001022 wpa_printf(MSG_DEBUG,
1023 "OpenSSL: Free application session data %p (sess %p)",
1024 buf, sess);
1025 wpabuf_free(buf);
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08001026}
1027
1028
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001029void * tls_init(const struct tls_config *conf)
1030{
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08001031 struct tls_data *data;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001032 SSL_CTX *ssl;
Dmitry Shmidtea69e842013-05-13 14:52:28 -07001033 struct tls_context *context;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001034 const char *ciphers;
Sunil Ravi2a14cf12023-11-21 00:54:38 +00001035#ifndef OPENSSL_NO_ENGINE
1036#ifdef CONFIG_OPENSC_ENGINE_PATH
1037 char const * const opensc_engine_path = CONFIG_OPENSC_ENGINE_PATH;
1038#else /* CONFIG_OPENSC_ENGINE_PATH */
1039 char const * const opensc_engine_path =
1040 conf ? conf->opensc_engine_path : NULL;
1041#endif /* CONFIG_OPENSC_ENGINE_PATH */
1042#ifdef CONFIG_PKCS11_ENGINE_PATH
1043 char const * const pkcs11_engine_path = CONFIG_PKCS11_ENGINE_PATH;
1044#else /* CONFIG_PKCS11_ENGINE_PATH */
1045 char const * const pkcs11_engine_path =
1046 conf ? conf->pkcs11_engine_path : NULL;
1047#endif /* CONFIG_PKCS11_ENGINE_PATH */
1048#ifdef CONFIG_PKCS11_MODULE_PATH
1049 char const * const pkcs11_module_path = CONFIG_PKCS11_MODULE_PATH;
1050#else /* CONFIG_PKCS11_MODULE_PATH */
1051 char const * const pkcs11_module_path =
1052 conf ? conf->pkcs11_module_path : NULL;
1053#endif /* CONFIG_PKCS11_MODULE_PATH */
1054#endif /* OPENSSL_NO_ENGINE */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001055
1056 if (tls_openssl_ref_count == 0) {
Hai Shaloma20dcd72022-02-04 13:43:00 -08001057 void openssl_load_legacy_provider(void);
1058
1059 openssl_load_legacy_provider();
1060
Dmitry Shmidtea69e842013-05-13 14:52:28 -07001061 tls_global = context = tls_context_new(conf);
1062 if (context == NULL)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001063 return NULL;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001064#ifdef CONFIG_FIPS
1065#ifdef OPENSSL_FIPS
1066 if (conf && conf->fips_mode) {
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08001067 static int fips_enabled = 0;
1068
1069 if (!fips_enabled && !FIPS_mode_set(1)) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001070 wpa_printf(MSG_ERROR, "Failed to enable FIPS "
1071 "mode");
1072 ERR_load_crypto_strings();
1073 ERR_print_errors_fp(stderr);
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07001074 os_free(tls_global);
1075 tls_global = NULL;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001076 return NULL;
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08001077 } else {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001078 wpa_printf(MSG_INFO, "Running in FIPS mode");
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08001079 fips_enabled = 1;
1080 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001081 }
1082#else /* OPENSSL_FIPS */
1083 if (conf && conf->fips_mode) {
1084 wpa_printf(MSG_ERROR, "FIPS mode requested, but not "
1085 "supported");
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07001086 os_free(tls_global);
1087 tls_global = NULL;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001088 return NULL;
1089 }
1090#endif /* OPENSSL_FIPS */
1091#endif /* CONFIG_FIPS */
Sunil Ravia04bd252022-05-02 22:54:18 -07001092#if OPENSSL_VERSION_NUMBER < 0x10100000L
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001093 SSL_load_error_strings();
1094 SSL_library_init();
Dmitry Shmidt216983b2015-02-06 10:50:36 -08001095#ifndef OPENSSL_NO_SHA256
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001096 EVP_add_digest(EVP_sha256());
1097#endif /* OPENSSL_NO_SHA256 */
1098 /* TODO: if /dev/urandom is available, PRNG is seeded
1099 * automatically. If this is not the case, random data should
1100 * be added here. */
1101
1102#ifdef PKCS12_FUNCS
1103#ifndef OPENSSL_NO_RC2
1104 /*
1105 * 40-bit RC2 is commonly used in PKCS#12 files, so enable it.
1106 * This is enabled by PKCS12_PBE_add() in OpenSSL 0.9.8
1107 * versions, but it looks like OpenSSL 1.0.0 does not do that
1108 * anymore.
1109 */
1110 EVP_add_cipher(EVP_rc2_40_cbc());
1111#endif /* OPENSSL_NO_RC2 */
1112 PKCS12_PBE_add();
1113#endif /* PKCS12_FUNCS */
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08001114#endif /* < 1.1.0 */
Dmitry Shmidtea69e842013-05-13 14:52:28 -07001115 } else {
Dmitry Shmidtea69e842013-05-13 14:52:28 -07001116 context = tls_context_new(conf);
1117 if (context == NULL)
1118 return NULL;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001119 }
1120 tls_openssl_ref_count++;
1121
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08001122 data = os_zalloc(sizeof(*data));
1123 if (data)
1124 ssl = SSL_CTX_new(SSLv23_method());
1125 else
1126 ssl = NULL;
Dmitry Shmidtea69e842013-05-13 14:52:28 -07001127 if (ssl == NULL) {
1128 tls_openssl_ref_count--;
Dmitry Shmidt68d0e3e2013-10-28 17:59:21 -07001129 if (context != tls_global)
1130 os_free(context);
Dmitry Shmidtea69e842013-05-13 14:52:28 -07001131 if (tls_openssl_ref_count == 0) {
1132 os_free(tls_global);
1133 tls_global = NULL;
Dmitry Shmidtea69e842013-05-13 14:52:28 -07001134 }
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08001135 os_free(data);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001136 return NULL;
Dmitry Shmidtea69e842013-05-13 14:52:28 -07001137 }
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08001138 data->ssl = ssl;
Hai Shalom74f70d42019-02-11 14:42:39 -08001139 if (conf) {
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08001140 data->tls_session_lifetime = conf->tls_session_lifetime;
Hai Shalom74f70d42019-02-11 14:42:39 -08001141 data->crl_reload_interval = conf->crl_reload_interval;
1142 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001143
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001144 SSL_CTX_set_options(ssl, SSL_OP_NO_SSLv2);
1145 SSL_CTX_set_options(ssl, SSL_OP_NO_SSLv3);
1146
Hai Shalom60840252021-02-19 19:02:11 -08001147 SSL_CTX_set_mode(ssl, SSL_MODE_AUTO_RETRY);
1148
Dmitry Shmidt29333592017-01-09 12:27:11 -08001149#ifdef SSL_MODE_NO_AUTO_CHAIN
1150 /* Number of deployed use cases assume the default OpenSSL behavior of
1151 * auto chaining the local certificate is in use. BoringSSL removed this
1152 * functionality by default, so we need to restore it here to avoid
1153 * breaking existing use cases. */
1154 SSL_CTX_clear_mode(ssl, SSL_MODE_NO_AUTO_CHAIN);
1155#endif /* SSL_MODE_NO_AUTO_CHAIN */
1156
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001157 SSL_CTX_set_info_callback(ssl, ssl_info_cb);
Dmitry Shmidtea69e842013-05-13 14:52:28 -07001158 SSL_CTX_set_app_data(ssl, context);
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08001159 if (data->tls_session_lifetime > 0) {
1160 SSL_CTX_set_quiet_shutdown(ssl, 1);
1161 /*
1162 * Set default context here. In practice, this will be replaced
1163 * by the per-EAP method context in tls_connection_set_verify().
1164 */
1165 SSL_CTX_set_session_id_context(ssl, (u8 *) "hostapd", 7);
1166 SSL_CTX_set_session_cache_mode(ssl, SSL_SESS_CACHE_SERVER);
1167 SSL_CTX_set_timeout(ssl, data->tls_session_lifetime);
1168 SSL_CTX_sess_set_remove_cb(ssl, remove_session_cb);
Sunil Ravia04bd252022-05-02 22:54:18 -07001169#if OPENSSL_VERSION_NUMBER >= 0x10101000L && \
1170 !defined(LIBRESSL_VERSION_NUMBER) && \
1171 !defined(OPENSSL_IS_BORINGSSL)
1172 /* One session ticket is sufficient for EAP-TLS */
1173 SSL_CTX_set_num_tickets(ssl, 1);
1174#endif
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08001175 } else {
1176 SSL_CTX_set_session_cache_mode(ssl, SSL_SESS_CACHE_OFF);
Sunil Ravia04bd252022-05-02 22:54:18 -07001177#if OPENSSL_VERSION_NUMBER >= 0x10101000L && \
1178 !defined(LIBRESSL_VERSION_NUMBER) && \
1179 !defined(OPENSSL_IS_BORINGSSL)
1180 SSL_CTX_set_num_tickets(ssl, 0);
1181#endif
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08001182 }
1183
1184 if (tls_ex_idx_session < 0) {
1185 tls_ex_idx_session = SSL_SESSION_get_ex_new_index(
1186 0, NULL, NULL, NULL, NULL);
1187 if (tls_ex_idx_session < 0) {
1188 tls_deinit(data);
1189 return NULL;
1190 }
1191 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001192
1193#ifndef OPENSSL_NO_ENGINE
Hai Shalom81f62d82019-07-22 12:10:00 -07001194 wpa_printf(MSG_DEBUG, "ENGINE: Loading builtin engines");
1195 ENGINE_load_builtin_engines();
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001196
Sunil Ravi2a14cf12023-11-21 00:54:38 +00001197 if (opensc_engine_path || pkcs11_engine_path || pkcs11_module_path) {
1198 if (tls_engine_load_dynamic_opensc(opensc_engine_path) ||
1199 tls_engine_load_dynamic_pkcs11(pkcs11_engine_path,
1200 pkcs11_module_path)) {
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08001201 tls_deinit(data);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001202 return NULL;
1203 }
1204 }
1205#endif /* OPENSSL_NO_ENGINE */
1206
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001207 if (conf && conf->openssl_ciphers)
1208 ciphers = conf->openssl_ciphers;
1209 else
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001210 ciphers = TLS_DEFAULT_CIPHERS;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001211 if (SSL_CTX_set_cipher_list(ssl, ciphers) != 1) {
1212 wpa_printf(MSG_ERROR,
1213 "OpenSSL: Failed to set cipher string '%s'",
1214 ciphers);
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08001215 tls_deinit(data);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001216 return NULL;
1217 }
1218
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08001219 return data;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001220}
1221
1222
1223void tls_deinit(void *ssl_ctx)
1224{
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08001225 struct tls_data *data = ssl_ctx;
1226 SSL_CTX *ssl = data->ssl;
Dmitry Shmidtea69e842013-05-13 14:52:28 -07001227 struct tls_context *context = SSL_CTX_get_app_data(ssl);
Sunil Ravia04bd252022-05-02 22:54:18 -07001228 struct tls_session_data *sess_data;
1229
1230 if (data->tls_session_lifetime > 0) {
1231 wpa_printf(MSG_DEBUG, "OpenSSL: Flush sessions");
1232 SSL_CTX_flush_sessions(ssl, 0);
1233 wpa_printf(MSG_DEBUG, "OpenSSL: Flush sessions - done");
1234 }
1235 while ((sess_data = dl_list_first(&context->sessions,
1236 struct tls_session_data, list))) {
1237 wpa_printf(MSG_DEBUG,
1238 "OpenSSL: Freeing not-flushed session data %p",
1239 sess_data->buf);
1240 wpabuf_free(sess_data->buf);
1241 dl_list_del(&sess_data->list);
1242 os_free(sess_data);
1243 }
Dmitry Shmidtea69e842013-05-13 14:52:28 -07001244 if (context != tls_global)
1245 os_free(context);
Hai Shalom74f70d42019-02-11 14:42:39 -08001246 os_free(data->ca_cert);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001247 SSL_CTX_free(ssl);
1248
1249 tls_openssl_ref_count--;
1250 if (tls_openssl_ref_count == 0) {
Sunil Ravia04bd252022-05-02 22:54:18 -07001251#if OPENSSL_VERSION_NUMBER < 0x10100000L
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001252#ifndef OPENSSL_NO_ENGINE
1253 ENGINE_cleanup();
1254#endif /* OPENSSL_NO_ENGINE */
1255 CRYPTO_cleanup_all_ex_data();
Dmitry Shmidt9ead16e2014-10-07 13:15:23 -07001256 ERR_remove_thread_state(NULL);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001257 ERR_free_strings();
1258 EVP_cleanup();
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08001259#endif /* < 1.1.0 */
Dmitry Shmidt34af3062013-07-11 10:46:32 -07001260 os_free(tls_global->ocsp_stapling_response);
1261 tls_global->ocsp_stapling_response = NULL;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001262 os_free(tls_global);
1263 tls_global = NULL;
1264 }
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08001265
Hai Shalom021b0b52019-04-10 11:17:58 -07001266 os_free(data->check_cert_subject);
Sunil Ravib0ac25f2024-07-12 01:42:03 +00001267 os_free(data->openssl_ciphers);
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08001268 os_free(data);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001269}
1270
1271
Dmitry Shmidt1d755d02015-04-28 10:34:29 -07001272#ifndef OPENSSL_NO_ENGINE
1273
1274/* Cryptoki return values */
1275#define CKR_PIN_INCORRECT 0x000000a0
1276#define CKR_PIN_INVALID 0x000000a1
1277#define CKR_PIN_LEN_RANGE 0x000000a2
1278
1279/* libp11 */
1280#define ERR_LIB_PKCS11 ERR_LIB_USER
1281
1282static int tls_is_pin_error(unsigned int err)
1283{
1284 return ERR_GET_LIB(err) == ERR_LIB_PKCS11 &&
1285 (ERR_GET_REASON(err) == CKR_PIN_INCORRECT ||
1286 ERR_GET_REASON(err) == CKR_PIN_INVALID ||
1287 ERR_GET_REASON(err) == CKR_PIN_LEN_RANGE);
1288}
1289
1290#endif /* OPENSSL_NO_ENGINE */
1291
1292
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08001293#ifdef ANDROID
1294/* EVP_PKEY_from_keystore comes from system/security/keystore-engine. */
1295EVP_PKEY * EVP_PKEY_from_keystore(const char *key_id);
1296#endif /* ANDROID */
1297
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001298static int tls_engine_init(struct tls_connection *conn, const char *engine_id,
1299 const char *pin, const char *key_id,
1300 const char *cert_id, const char *ca_cert_id)
1301{
Adam Langley1eb02ed2015-04-21 19:00:05 -07001302#if defined(ANDROID) && defined(OPENSSL_IS_BORINGSSL)
1303#if !defined(OPENSSL_NO_ENGINE)
1304#error "This code depends on OPENSSL_NO_ENGINE being defined by BoringSSL."
1305#endif
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08001306 if (!key_id)
1307 return TLS_SET_PARAMS_ENGINE_PRV_INIT_FAILED;
Adam Langley1eb02ed2015-04-21 19:00:05 -07001308 conn->engine = NULL;
1309 conn->private_key = EVP_PKEY_from_keystore(key_id);
1310 if (!conn->private_key) {
1311 wpa_printf(MSG_ERROR,
1312 "ENGINE: cannot load private key with id '%s' [%s]",
1313 key_id,
1314 ERR_error_string(ERR_get_error(), NULL));
1315 return TLS_SET_PARAMS_ENGINE_PRV_INIT_FAILED;
1316 }
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08001317#endif /* ANDROID && OPENSSL_IS_BORINGSSL */
Adam Langley1eb02ed2015-04-21 19:00:05 -07001318
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001319#ifndef OPENSSL_NO_ENGINE
1320 int ret = -1;
1321 if (engine_id == NULL) {
1322 wpa_printf(MSG_ERROR, "ENGINE: Engine ID not set");
1323 return -1;
1324 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001325
1326 ERR_clear_error();
Kenny Rootdb3c5a42012-03-20 17:00:47 -07001327#ifdef ANDROID
1328 ENGINE_load_dynamic();
1329#endif
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001330 conn->engine = ENGINE_by_id(engine_id);
1331 if (!conn->engine) {
1332 wpa_printf(MSG_ERROR, "ENGINE: engine %s not available [%s]",
1333 engine_id, ERR_error_string(ERR_get_error(), NULL));
1334 goto err;
1335 }
1336 if (ENGINE_init(conn->engine) != 1) {
1337 wpa_printf(MSG_ERROR, "ENGINE: engine init failed "
1338 "(engine: %s) [%s]", engine_id,
1339 ERR_error_string(ERR_get_error(), NULL));
1340 goto err;
1341 }
1342 wpa_printf(MSG_DEBUG, "ENGINE: engine initialized");
1343
Kenny Rootdb3c5a42012-03-20 17:00:47 -07001344#ifndef ANDROID
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001345 if (pin && ENGINE_ctrl_cmd_string(conn->engine, "PIN", pin, 0) == 0) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001346 wpa_printf(MSG_ERROR, "ENGINE: cannot set pin [%s]",
1347 ERR_error_string(ERR_get_error(), NULL));
1348 goto err;
1349 }
Kenny Rootdb3c5a42012-03-20 17:00:47 -07001350#endif
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001351 if (key_id) {
1352 /*
1353 * Ensure that the ENGINE does not attempt to use the OpenSSL
1354 * UI system to obtain a PIN, if we didn't provide one.
1355 */
1356 struct {
1357 const void *password;
1358 const char *prompt_info;
1359 } key_cb = { "", NULL };
1360
1361 /* load private key first in-case PIN is required for cert */
1362 conn->private_key = ENGINE_load_private_key(conn->engine,
1363 key_id, NULL,
1364 &key_cb);
1365 if (!conn->private_key) {
Dmitry Shmidt1d755d02015-04-28 10:34:29 -07001366 unsigned long err = ERR_get_error();
1367
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001368 wpa_printf(MSG_ERROR,
1369 "ENGINE: cannot load private key with id '%s' [%s]",
1370 key_id,
Dmitry Shmidt1d755d02015-04-28 10:34:29 -07001371 ERR_error_string(err, NULL));
1372 if (tls_is_pin_error(err))
1373 ret = TLS_SET_PARAMS_ENGINE_PRV_BAD_PIN;
1374 else
1375 ret = TLS_SET_PARAMS_ENGINE_PRV_INIT_FAILED;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001376 goto err;
1377 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001378 }
1379
1380 /* handle a certificate and/or CA certificate */
1381 if (cert_id || ca_cert_id) {
1382 const char *cmd_name = "LOAD_CERT_CTRL";
1383
1384 /* test if the engine supports a LOAD_CERT_CTRL */
1385 if (!ENGINE_ctrl(conn->engine, ENGINE_CTRL_GET_CMD_FROM_NAME,
1386 0, (void *)cmd_name, NULL)) {
1387 wpa_printf(MSG_ERROR, "ENGINE: engine does not support"
1388 " loading certificates");
1389 ret = TLS_SET_PARAMS_ENGINE_PRV_INIT_FAILED;
1390 goto err;
1391 }
1392 }
1393
1394 return 0;
1395
1396err:
1397 if (conn->engine) {
1398 ENGINE_free(conn->engine);
1399 conn->engine = NULL;
1400 }
1401
1402 if (conn->private_key) {
1403 EVP_PKEY_free(conn->private_key);
1404 conn->private_key = NULL;
1405 }
1406
1407 return ret;
1408#else /* OPENSSL_NO_ENGINE */
1409 return 0;
1410#endif /* OPENSSL_NO_ENGINE */
1411}
1412
1413
1414static void tls_engine_deinit(struct tls_connection *conn)
1415{
Adam Langley1eb02ed2015-04-21 19:00:05 -07001416#if defined(ANDROID) || !defined(OPENSSL_NO_ENGINE)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001417 wpa_printf(MSG_DEBUG, "ENGINE: engine deinit");
1418 if (conn->private_key) {
1419 EVP_PKEY_free(conn->private_key);
1420 conn->private_key = NULL;
1421 }
1422 if (conn->engine) {
Adam Langley1eb02ed2015-04-21 19:00:05 -07001423#if !defined(OPENSSL_IS_BORINGSSL)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001424 ENGINE_finish(conn->engine);
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08001425#endif /* !OPENSSL_IS_BORINGSSL */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001426 conn->engine = NULL;
1427 }
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08001428#endif /* ANDROID || !OPENSSL_NO_ENGINE */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001429}
1430
1431
1432int tls_get_errors(void *ssl_ctx)
1433{
1434 int count = 0;
1435 unsigned long err;
1436
1437 while ((err = ERR_get_error())) {
1438 wpa_printf(MSG_INFO, "TLS - SSL error: %s",
1439 ERR_error_string(err, NULL));
1440 count++;
1441 }
1442
1443 return count;
1444}
1445
Jouni Malinen26af48b2014-04-09 13:02:53 +03001446
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08001447static const char * openssl_content_type(int content_type)
1448{
1449 switch (content_type) {
1450 case 20:
1451 return "change cipher spec";
1452 case 21:
1453 return "alert";
1454 case 22:
1455 return "handshake";
1456 case 23:
1457 return "application data";
1458 case 24:
1459 return "heartbeat";
1460 case 256:
1461 return "TLS header info"; /* pseudo content type */
Hai Shalom81f62d82019-07-22 12:10:00 -07001462 case 257:
1463 return "inner content type"; /* pseudo content type */
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08001464 default:
1465 return "?";
1466 }
1467}
1468
1469
1470static const char * openssl_handshake_type(int content_type, const u8 *buf,
1471 size_t len)
1472{
Hai Shalom81f62d82019-07-22 12:10:00 -07001473 if (content_type == 257 && buf && len == 1)
1474 return openssl_content_type(buf[0]);
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08001475 if (content_type != 22 || !buf || len == 0)
1476 return "";
1477 switch (buf[0]) {
1478 case 0:
1479 return "hello request";
1480 case 1:
1481 return "client hello";
1482 case 2:
1483 return "server hello";
Hai Shalom74f70d42019-02-11 14:42:39 -08001484 case 3:
1485 return "hello verify request";
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08001486 case 4:
1487 return "new session ticket";
Hai Shalom74f70d42019-02-11 14:42:39 -08001488 case 5:
1489 return "end of early data";
1490 case 6:
1491 return "hello retry request";
1492 case 8:
1493 return "encrypted extensions";
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08001494 case 11:
1495 return "certificate";
1496 case 12:
1497 return "server key exchange";
1498 case 13:
1499 return "certificate request";
1500 case 14:
1501 return "server hello done";
1502 case 15:
1503 return "certificate verify";
1504 case 16:
1505 return "client key exchange";
1506 case 20:
1507 return "finished";
1508 case 21:
1509 return "certificate url";
1510 case 22:
1511 return "certificate status";
Hai Shalom74f70d42019-02-11 14:42:39 -08001512 case 23:
1513 return "supplemental data";
1514 case 24:
1515 return "key update";
1516 case 254:
1517 return "message hash";
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08001518 default:
1519 return "?";
1520 }
1521}
1522
1523
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001524#ifdef CONFIG_SUITEB
1525
1526static void check_server_hello(struct tls_connection *conn,
1527 const u8 *pos, const u8 *end)
1528{
1529 size_t payload_len, id_len;
1530
1531 /*
1532 * Parse ServerHello to get the selected cipher suite since OpenSSL does
1533 * not make it cleanly available during handshake and we need to know
1534 * whether DHE was selected.
1535 */
1536
1537 if (end - pos < 3)
1538 return;
1539 payload_len = WPA_GET_BE24(pos);
1540 pos += 3;
1541
1542 if ((size_t) (end - pos) < payload_len)
1543 return;
1544 end = pos + payload_len;
1545
1546 /* Skip Version and Random */
1547 if (end - pos < 2 + SSL3_RANDOM_SIZE)
1548 return;
1549 pos += 2 + SSL3_RANDOM_SIZE;
1550
1551 /* Skip Session ID */
1552 if (end - pos < 1)
1553 return;
1554 id_len = *pos++;
1555 if ((size_t) (end - pos) < id_len)
1556 return;
1557 pos += id_len;
1558
1559 if (end - pos < 2)
1560 return;
1561 conn->cipher_suite = WPA_GET_BE16(pos);
1562 wpa_printf(MSG_DEBUG, "OpenSSL: Server selected cipher suite 0x%x",
1563 conn->cipher_suite);
1564}
1565
1566
1567static void check_server_key_exchange(SSL *ssl, struct tls_connection *conn,
1568 const u8 *pos, const u8 *end)
1569{
1570 size_t payload_len;
1571 u16 dh_len;
1572 BIGNUM *p;
1573 int bits;
1574
1575 if (!(conn->flags & TLS_CONN_SUITEB))
1576 return;
1577
1578 /* DHE is enabled only with DHE-RSA-AES256-GCM-SHA384 */
1579 if (conn->cipher_suite != 0x9f)
1580 return;
1581
1582 if (end - pos < 3)
1583 return;
1584 payload_len = WPA_GET_BE24(pos);
1585 pos += 3;
1586
1587 if ((size_t) (end - pos) < payload_len)
1588 return;
1589 end = pos + payload_len;
1590
1591 if (end - pos < 2)
1592 return;
1593 dh_len = WPA_GET_BE16(pos);
1594 pos += 2;
1595
1596 if ((size_t) (end - pos) < dh_len)
1597 return;
1598 p = BN_bin2bn(pos, dh_len, NULL);
1599 if (!p)
1600 return;
1601
1602 bits = BN_num_bits(p);
1603 BN_free(p);
1604
1605 conn->server_dh_prime_len = bits;
1606 wpa_printf(MSG_DEBUG, "OpenSSL: Server DH prime length: %d bits",
1607 conn->server_dh_prime_len);
1608}
1609
1610#endif /* CONFIG_SUITEB */
1611
1612
Jouni Malinen26af48b2014-04-09 13:02:53 +03001613static void tls_msg_cb(int write_p, int version, int content_type,
1614 const void *buf, size_t len, SSL *ssl, void *arg)
1615{
1616 struct tls_connection *conn = arg;
1617 const u8 *pos = buf;
1618
Sunil8cd6f4d2022-06-28 18:40:46 +00001619#if OPENSSL_VERSION_NUMBER >= 0x30000000L
1620 if ((SSL_version(ssl) == TLS1_VERSION ||
1621 SSL_version(ssl) == TLS1_1_VERSION) &&
1622 SSL_get_security_level(ssl) > 0) {
1623 wpa_printf(MSG_DEBUG,
1624 "OpenSSL: Drop security level to 0 to allow TLS 1.0/1.1 use of MD5-SHA1 signature algorithm");
1625 SSL_set_security_level(ssl, 0);
1626 }
1627#endif /* OpenSSL version >= 3.0 */
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08001628 if (write_p == 2) {
1629 wpa_printf(MSG_DEBUG,
1630 "OpenSSL: session ver=0x%x content_type=%d",
1631 version, content_type);
1632 wpa_hexdump_key(MSG_MSGDUMP, "OpenSSL: Data", buf, len);
1633 return;
1634 }
1635
1636 wpa_printf(MSG_DEBUG, "OpenSSL: %s ver=0x%x content_type=%d (%s/%s)",
1637 write_p ? "TX" : "RX", version, content_type,
1638 openssl_content_type(content_type),
1639 openssl_handshake_type(content_type, buf, len));
Jouni Malinen26af48b2014-04-09 13:02:53 +03001640 wpa_hexdump_key(MSG_MSGDUMP, "OpenSSL: Message", buf, len);
1641 if (content_type == 24 && len >= 3 && pos[0] == 1) {
1642 size_t payload_len = WPA_GET_BE16(pos + 1);
1643 if (payload_len + 3 > len) {
1644 wpa_printf(MSG_ERROR, "OpenSSL: Heartbeat attack detected");
1645 conn->invalid_hb_used = 1;
1646 }
1647 }
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001648
1649#ifdef CONFIG_SUITEB
1650 /*
1651 * Need to parse these handshake messages to be able to check DH prime
1652 * length since OpenSSL does not expose the new cipher suite and DH
1653 * parameters during handshake (e.g., for cert_cb() callback).
1654 */
1655 if (content_type == 22 && pos && len > 0 && pos[0] == 2)
1656 check_server_hello(conn, pos + 1, pos + len);
1657 if (content_type == 22 && pos && len > 0 && pos[0] == 12)
1658 check_server_key_exchange(ssl, conn, pos + 1, pos + len);
1659#endif /* CONFIG_SUITEB */
Jouni Malinen26af48b2014-04-09 13:02:53 +03001660}
1661
1662
Sunil Ravia04bd252022-05-02 22:54:18 -07001663#ifdef CONFIG_TESTING_OPTIONS
1664#if OPENSSL_VERSION_NUMBER >= 0x10101000L && !defined(LIBRESSL_VERSION_NUMBER)
1665/*
1666 * By setting the environment variable SSLKEYLOGFILE to a filename keying
1667 * material will be exported that you may use with Wireshark to decode any
1668 * TLS flows. Please see the following for more details:
1669 *
1670 * https://gitlab.com/wireshark/wireshark/-/wikis/TLS#tls-decryption
1671 *
1672 * Example logging sessions are (you should delete the file on each run):
1673 *
1674 * rm -f /tmp/sslkey.log
1675 * env SSLKEYLOGFILE=/tmp/sslkey.log hostapd ...
1676 *
1677 * rm -f /tmp/sslkey.log
1678 * env SSLKEYLOGFILE=/tmp/sslkey.log wpa_supplicant ...
1679 *
1680 * rm -f /tmp/sslkey.log
1681 * env SSLKEYLOGFILE=/tmp/sslkey.log eapol_test ...
1682 */
1683static void tls_keylog_cb(const SSL *ssl, const char *line)
1684{
1685 int fd;
1686 const char *filename;
1687 struct iovec iov[2];
1688
1689 filename = getenv("SSLKEYLOGFILE");
1690 if (!filename)
1691 return;
1692
1693 fd = open(filename, O_WRONLY | O_CREAT | O_APPEND, S_IRUSR | S_IWUSR);
1694 if (fd < 0) {
1695 wpa_printf(MSG_ERROR,
1696 "OpenSSL: Failed to open keylog file %s: %s",
1697 filename, strerror(errno));
1698 return;
1699 }
1700
1701 /* Assume less than _POSIX_PIPE_BUF (512) where writes are guaranteed
1702 * to be atomic for O_APPEND. */
1703 iov[0].iov_base = (void *) line;
1704 iov[0].iov_len = os_strlen(line);
1705 iov[1].iov_base = "\n";
1706 iov[1].iov_len = 1;
1707
1708 if (writev(fd, iov, ARRAY_SIZE(iov)) < 01) {
1709 wpa_printf(MSG_DEBUG,
1710 "OpenSSL: Failed to write to keylog file %s: %s",
1711 filename, strerror(errno));
1712 }
1713
1714 close(fd);
1715}
1716#endif
1717#endif /* CONFIG_TESTING_OPTIONS */
1718
1719
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001720struct tls_connection * tls_connection_init(void *ssl_ctx)
1721{
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08001722 struct tls_data *data = ssl_ctx;
1723 SSL_CTX *ssl = data->ssl;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001724 struct tls_connection *conn;
1725 long options;
Hai Shalom74f70d42019-02-11 14:42:39 -08001726 X509_STORE *new_cert_store;
1727 struct os_reltime now;
Dmitry Shmidt7d5c8f22014-03-03 13:53:28 -08001728 struct tls_context *context = SSL_CTX_get_app_data(ssl);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001729
Hai Shalom74f70d42019-02-11 14:42:39 -08001730 /* Replace X509 store if it is time to update CRL. */
1731 if (data->crl_reload_interval > 0 && os_get_reltime(&now) == 0 &&
1732 os_reltime_expired(&now, &data->crl_last_reload,
1733 data->crl_reload_interval)) {
1734 wpa_printf(MSG_INFO,
1735 "OpenSSL: Flushing X509 store with ca_cert file");
1736 new_cert_store = tls_crl_cert_reload(data->ca_cert,
1737 data->check_crl);
1738 if (!new_cert_store) {
1739 wpa_printf(MSG_ERROR,
1740 "OpenSSL: Error replacing X509 store with ca_cert file");
1741 } else {
1742 /* Replace old store */
1743 SSL_CTX_set_cert_store(ssl, new_cert_store);
1744 data->crl_last_reload = now;
1745 }
1746 }
1747
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001748 conn = os_zalloc(sizeof(*conn));
1749 if (conn == NULL)
1750 return NULL;
Hai Shalom74f70d42019-02-11 14:42:39 -08001751 conn->data = data;
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08001752 conn->ssl_ctx = ssl;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001753 conn->ssl = SSL_new(ssl);
1754 if (conn->ssl == NULL) {
1755 tls_show_errors(MSG_INFO, __func__,
1756 "Failed to initialize new SSL connection");
1757 os_free(conn);
1758 return NULL;
1759 }
1760
Dmitry Shmidtea69e842013-05-13 14:52:28 -07001761 conn->context = context;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001762 SSL_set_app_data(conn->ssl, conn);
Jouni Malinen26af48b2014-04-09 13:02:53 +03001763 SSL_set_msg_callback(conn->ssl, tls_msg_cb);
1764 SSL_set_msg_callback_arg(conn->ssl, conn);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001765 options = SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3 |
1766 SSL_OP_SINGLE_DH_USE;
1767#ifdef SSL_OP_NO_COMPRESSION
1768 options |= SSL_OP_NO_COMPRESSION;
1769#endif /* SSL_OP_NO_COMPRESSION */
1770 SSL_set_options(conn->ssl, options);
Hai Shalom81f62d82019-07-22 12:10:00 -07001771#ifdef SSL_OP_ENABLE_MIDDLEBOX_COMPAT
1772 /* Hopefully there is no need for middlebox compatibility mechanisms
1773 * when going through EAP authentication. */
1774 SSL_clear_options(conn->ssl, SSL_OP_ENABLE_MIDDLEBOX_COMPAT);
1775#endif
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001776
Sunil Ravia04bd252022-05-02 22:54:18 -07001777#ifdef CONFIG_TESTING_OPTIONS
1778#if OPENSSL_VERSION_NUMBER >= 0x10101000L && !defined(LIBRESSL_VERSION_NUMBER)
1779 /* Set the keylog file if the admin requested it. */
1780 if (getenv("SSLKEYLOGFILE"))
1781 SSL_CTX_set_keylog_callback(conn->ssl_ctx, tls_keylog_cb);
1782#endif
1783#endif /* CONFIG_TESTING_OPTIONS */
1784
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001785 conn->ssl_in = BIO_new(BIO_s_mem());
1786 if (!conn->ssl_in) {
1787 tls_show_errors(MSG_INFO, __func__,
1788 "Failed to create a new BIO for ssl_in");
1789 SSL_free(conn->ssl);
1790 os_free(conn);
1791 return NULL;
1792 }
1793
1794 conn->ssl_out = BIO_new(BIO_s_mem());
1795 if (!conn->ssl_out) {
1796 tls_show_errors(MSG_INFO, __func__,
1797 "Failed to create a new BIO for ssl_out");
1798 SSL_free(conn->ssl);
1799 BIO_free(conn->ssl_in);
1800 os_free(conn);
1801 return NULL;
1802 }
1803
1804 SSL_set_bio(conn->ssl, conn->ssl_in, conn->ssl_out);
1805
1806 return conn;
1807}
1808
1809
1810void tls_connection_deinit(void *ssl_ctx, struct tls_connection *conn)
1811{
1812 if (conn == NULL)
1813 return;
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08001814 if (conn->success_data) {
1815 /*
1816 * Make sure ssl_clear_bad_session() does not remove this
1817 * session.
1818 */
1819 SSL_set_quiet_shutdown(conn->ssl, 1);
1820 SSL_shutdown(conn->ssl);
1821 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001822 SSL_free(conn->ssl);
1823 tls_engine_deinit(conn);
1824 os_free(conn->subject_match);
1825 os_free(conn->altsubject_match);
Dmitry Shmidt051af732013-10-22 13:52:46 -07001826 os_free(conn->suffix_match);
Dmitry Shmidt2f74e362015-01-21 13:19:05 -08001827 os_free(conn->domain_match);
Hai Shalom021b0b52019-04-10 11:17:58 -07001828 os_free(conn->check_cert_subject);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001829 os_free(conn->session_ticket);
Hai Shalom899fcc72020-10-19 14:38:18 -07001830 os_free(conn->peer_subject);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001831 os_free(conn);
1832}
1833
1834
1835int tls_connection_established(void *ssl_ctx, struct tls_connection *conn)
1836{
1837 return conn ? SSL_is_init_finished(conn->ssl) : 0;
1838}
1839
1840
Hai Shalom39ba6fc2019-01-22 12:40:38 -08001841char * tls_connection_peer_serial_num(void *tls_ctx,
1842 struct tls_connection *conn)
1843{
1844 ASN1_INTEGER *ser;
1845 char *serial_num;
1846 size_t len;
1847
1848 if (!conn->peer_cert)
1849 return NULL;
1850
1851 ser = X509_get_serialNumber(conn->peer_cert);
1852 if (!ser)
1853 return NULL;
1854
1855 len = ASN1_STRING_length(ser) * 2 + 1;
1856 serial_num = os_malloc(len);
1857 if (!serial_num)
1858 return NULL;
1859 wpa_snprintf_hex_uppercase(serial_num, len,
1860 ASN1_STRING_get0_data(ser),
1861 ASN1_STRING_length(ser));
1862 return serial_num;
1863}
1864
1865
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001866int tls_connection_shutdown(void *ssl_ctx, struct tls_connection *conn)
1867{
1868 if (conn == NULL)
1869 return -1;
1870
1871 /* Shutdown previous TLS connection without notifying the peer
1872 * because the connection was already terminated in practice
1873 * and "close notify" shutdown alert would confuse AS. */
1874 SSL_set_quiet_shutdown(conn->ssl, 1);
1875 SSL_shutdown(conn->ssl);
Jouni Malinenf291c682015-08-17 22:50:41 +03001876 return SSL_clear(conn->ssl) == 1 ? 0 : -1;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001877}
1878
1879
1880static int tls_match_altsubject_component(X509 *cert, int type,
1881 const char *value, size_t len)
1882{
1883 GENERAL_NAME *gen;
1884 void *ext;
Dmitry Shmidt9ead16e2014-10-07 13:15:23 -07001885 int found = 0;
1886 stack_index_t i;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001887
1888 ext = X509_get_ext_d2i(cert, NID_subject_alt_name, NULL, NULL);
1889
1890 for (i = 0; ext && i < sk_GENERAL_NAME_num(ext); i++) {
1891 gen = sk_GENERAL_NAME_value(ext, i);
1892 if (gen->type != type)
1893 continue;
1894 if (os_strlen((char *) gen->d.ia5->data) == len &&
1895 os_memcmp(value, gen->d.ia5->data, len) == 0)
1896 found++;
1897 }
1898
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08001899 sk_GENERAL_NAME_pop_free(ext, GENERAL_NAME_free);
1900
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001901 return found;
1902}
1903
1904
1905static int tls_match_altsubject(X509 *cert, const char *match)
1906{
1907 int type;
1908 const char *pos, *end;
1909 size_t len;
1910
1911 pos = match;
1912 do {
1913 if (os_strncmp(pos, "EMAIL:", 6) == 0) {
1914 type = GEN_EMAIL;
1915 pos += 6;
1916 } else if (os_strncmp(pos, "DNS:", 4) == 0) {
1917 type = GEN_DNS;
1918 pos += 4;
1919 } else if (os_strncmp(pos, "URI:", 4) == 0) {
1920 type = GEN_URI;
1921 pos += 4;
1922 } else {
1923 wpa_printf(MSG_INFO, "TLS: Invalid altSubjectName "
1924 "match '%s'", pos);
1925 return 0;
1926 }
1927 end = os_strchr(pos, ';');
1928 while (end) {
1929 if (os_strncmp(end + 1, "EMAIL:", 6) == 0 ||
1930 os_strncmp(end + 1, "DNS:", 4) == 0 ||
1931 os_strncmp(end + 1, "URI:", 4) == 0)
1932 break;
1933 end = os_strchr(end + 1, ';');
1934 }
1935 if (end)
1936 len = end - pos;
1937 else
1938 len = os_strlen(pos);
1939 if (tls_match_altsubject_component(cert, type, pos, len) > 0)
1940 return 1;
1941 pos = end + 1;
1942 } while (end);
1943
1944 return 0;
1945}
1946
1947
Dmitry Shmidtfa3fc4a2013-11-21 13:34:38 -08001948#ifndef CONFIG_NATIVE_WINDOWS
Dmitry Shmidt2f74e362015-01-21 13:19:05 -08001949static int domain_suffix_match(const u8 *val, size_t len, const char *match,
Hai Shalom021b0b52019-04-10 11:17:58 -07001950 size_t match_len, int full)
Dmitry Shmidt051af732013-10-22 13:52:46 -07001951{
Hai Shalom021b0b52019-04-10 11:17:58 -07001952 size_t i;
Dmitry Shmidt051af732013-10-22 13:52:46 -07001953
1954 /* Check for embedded nuls that could mess up suffix matching */
1955 for (i = 0; i < len; i++) {
1956 if (val[i] == '\0') {
1957 wpa_printf(MSG_DEBUG, "TLS: Embedded null in a string - reject");
1958 return 0;
1959 }
1960 }
1961
Dmitry Shmidt2f74e362015-01-21 13:19:05 -08001962 if (match_len > len || (full && match_len != len))
Dmitry Shmidt051af732013-10-22 13:52:46 -07001963 return 0;
1964
1965 if (os_strncasecmp((const char *) val + len - match_len, match,
1966 match_len) != 0)
1967 return 0; /* no match */
1968
1969 if (match_len == len)
1970 return 1; /* exact match */
1971
1972 if (val[len - match_len - 1] == '.')
1973 return 1; /* full label match completes suffix match */
1974
1975 wpa_printf(MSG_DEBUG, "TLS: Reject due to incomplete label match");
1976 return 0;
1977}
Dmitry Shmidtfa3fc4a2013-11-21 13:34:38 -08001978#endif /* CONFIG_NATIVE_WINDOWS */
Dmitry Shmidt051af732013-10-22 13:52:46 -07001979
1980
Hai Shalom021b0b52019-04-10 11:17:58 -07001981struct tls_dn_field_order_cnt {
1982 u8 cn;
1983 u8 c;
1984 u8 l;
1985 u8 st;
1986 u8 o;
1987 u8 ou;
1988 u8 email;
1989};
1990
1991
1992static int get_dn_field_index(const struct tls_dn_field_order_cnt *dn_cnt,
1993 int nid)
Dmitry Shmidt051af732013-10-22 13:52:46 -07001994{
Hai Shalom021b0b52019-04-10 11:17:58 -07001995 switch (nid) {
1996 case NID_commonName:
1997 return dn_cnt->cn;
1998 case NID_countryName:
1999 return dn_cnt->c;
2000 case NID_localityName:
2001 return dn_cnt->l;
2002 case NID_stateOrProvinceName:
2003 return dn_cnt->st;
2004 case NID_organizationName:
2005 return dn_cnt->o;
2006 case NID_organizationalUnitName:
2007 return dn_cnt->ou;
2008 case NID_pkcs9_emailAddress:
2009 return dn_cnt->email;
2010 default:
2011 wpa_printf(MSG_ERROR,
2012 "TLS: Unknown NID '%d' in check_cert_subject",
2013 nid);
2014 return -1;
2015 }
2016}
2017
2018
2019/**
2020 * match_dn_field - Match configuration DN field against Certificate DN field
2021 * @cert: Certificate
2022 * @nid: NID of DN field
2023 * @field: Field name
2024 * @value DN field value which is passed from configuration
2025 * e.g., if configuration have C=US and this argument will point to US.
2026 * @dn_cnt: DN matching context
2027 * Returns: 1 on success and 0 on failure
2028 */
2029static int match_dn_field(const X509 *cert, int nid, const char *field,
2030 const char *value,
2031 const struct tls_dn_field_order_cnt *dn_cnt)
2032{
2033 int i, ret = 0, len, config_dn_field_index, match_index = 0;
2034 X509_NAME *name;
2035
2036 len = os_strlen(value);
2037 name = X509_get_subject_name((X509 *) cert);
2038
2039 /* Assign incremented cnt for every field of DN to check DN field in
2040 * right order */
2041 config_dn_field_index = get_dn_field_index(dn_cnt, nid);
2042 if (config_dn_field_index < 0)
2043 return 0;
2044
2045 /* Fetch value based on NID */
2046 for (i = -1; (i = X509_NAME_get_index_by_NID(name, nid, i)) > -1;) {
2047 X509_NAME_ENTRY *e;
2048 ASN1_STRING *cn;
2049
2050 e = X509_NAME_get_entry(name, i);
2051 if (!e)
2052 continue;
2053
2054 cn = X509_NAME_ENTRY_get_data(e);
2055 if (!cn)
2056 continue;
2057
2058 match_index++;
2059
2060 /* check for more than one DN field with same name */
2061 if (match_index != config_dn_field_index)
2062 continue;
2063
2064 /* Check wildcard at the right end side */
2065 /* E.g., if OU=develop* mentioned in configuration, allow 'OU'
2066 * of the subject in the client certificate to start with
2067 * 'develop' */
2068 if (len > 0 && value[len - 1] == '*') {
2069 /* Compare actual certificate DN field value with
2070 * configuration DN field value up to the specified
2071 * length. */
2072 ret = ASN1_STRING_length(cn) >= len - 1 &&
2073 os_memcmp(ASN1_STRING_get0_data(cn), value,
2074 len - 1) == 0;
2075 } else {
2076 /* Compare actual certificate DN field value with
2077 * configuration DN field value */
2078 ret = ASN1_STRING_length(cn) == len &&
2079 os_memcmp(ASN1_STRING_get0_data(cn), value,
2080 len) == 0;
2081 }
2082 if (!ret) {
2083 wpa_printf(MSG_ERROR,
2084 "OpenSSL: Failed to match %s '%s' with certificate DN field value '%s'",
2085 field, value, ASN1_STRING_get0_data(cn));
2086 }
2087 break;
2088 }
2089
2090 return ret;
2091}
2092
2093
2094/**
2095 * get_value_from_field - Get value from DN field
2096 * @cert: Certificate
2097 * @field_str: DN field string which is passed from configuration file (e.g.,
2098 * C=US)
2099 * @dn_cnt: DN matching context
2100 * Returns: 1 on success and 0 on failure
2101 */
2102static int get_value_from_field(const X509 *cert, char *field_str,
2103 struct tls_dn_field_order_cnt *dn_cnt)
2104{
2105 int nid;
2106 char *context = NULL, *name, *value;
2107
2108 if (os_strcmp(field_str, "*") == 0)
2109 return 1; /* wildcard matches everything */
2110
2111 name = str_token(field_str, "=", &context);
2112 if (!name)
2113 return 0;
2114
2115 /* Compare all configured DN fields and assign nid based on that to
2116 * fetch correct value from certificate subject */
2117 if (os_strcmp(name, "CN") == 0) {
2118 nid = NID_commonName;
2119 dn_cnt->cn++;
2120 } else if(os_strcmp(name, "C") == 0) {
2121 nid = NID_countryName;
2122 dn_cnt->c++;
2123 } else if (os_strcmp(name, "L") == 0) {
2124 nid = NID_localityName;
2125 dn_cnt->l++;
2126 } else if (os_strcmp(name, "ST") == 0) {
2127 nid = NID_stateOrProvinceName;
2128 dn_cnt->st++;
2129 } else if (os_strcmp(name, "O") == 0) {
2130 nid = NID_organizationName;
2131 dn_cnt->o++;
2132 } else if (os_strcmp(name, "OU") == 0) {
2133 nid = NID_organizationalUnitName;
2134 dn_cnt->ou++;
2135 } else if (os_strcmp(name, "emailAddress") == 0) {
2136 nid = NID_pkcs9_emailAddress;
2137 dn_cnt->email++;
2138 } else {
2139 wpa_printf(MSG_ERROR,
2140 "TLS: Unknown field '%s' in check_cert_subject", name);
2141 return 0;
2142 }
2143
2144 value = str_token(field_str, "=", &context);
2145 if (!value) {
2146 wpa_printf(MSG_ERROR,
2147 "TLS: Distinguished Name field '%s' value is not defined in check_cert_subject",
2148 name);
2149 return 0;
2150 }
2151
2152 return match_dn_field(cert, nid, name, value, dn_cnt);
2153}
2154
2155
2156/**
2157 * tls_match_dn_field - Match subject DN field with check_cert_subject
2158 * @cert: Certificate
2159 * @match: check_cert_subject string
2160 * Returns: Return 1 on success and 0 on failure
2161*/
2162static int tls_match_dn_field(X509 *cert, const char *match)
2163{
2164 const char *token, *last = NULL;
2165 char field[256];
2166 struct tls_dn_field_order_cnt dn_cnt;
2167
2168 os_memset(&dn_cnt, 0, sizeof(dn_cnt));
2169
2170 /* Maximum length of each DN field is 255 characters */
2171
2172 /* Process each '/' delimited field */
2173 while ((token = cstr_token(match, "/", &last))) {
2174 if (last - token >= (int) sizeof(field)) {
2175 wpa_printf(MSG_ERROR,
2176 "OpenSSL: Too long DN matching field value in '%s'",
2177 match);
2178 return 0;
2179 }
2180 os_memcpy(field, token, last - token);
2181 field[last - token] = '\0';
2182
2183 if (!get_value_from_field(cert, field, &dn_cnt)) {
2184 wpa_printf(MSG_DEBUG, "OpenSSL: No match for DN '%s'",
2185 field);
2186 return 0;
2187 }
2188 }
2189
2190 return 1;
2191}
2192
2193
2194#ifndef CONFIG_NATIVE_WINDOWS
2195static int tls_match_suffix_helper(X509 *cert, const char *match,
2196 size_t match_len, int full)
2197{
Dmitry Shmidt051af732013-10-22 13:52:46 -07002198 GENERAL_NAME *gen;
2199 void *ext;
2200 int i;
Dmitry Shmidt9ead16e2014-10-07 13:15:23 -07002201 stack_index_t j;
Dmitry Shmidt051af732013-10-22 13:52:46 -07002202 int dns_name = 0;
2203 X509_NAME *name;
2204
Dmitry Shmidt2f74e362015-01-21 13:19:05 -08002205 wpa_printf(MSG_DEBUG, "TLS: Match domain against %s%s",
2206 full ? "": "suffix ", match);
Dmitry Shmidt051af732013-10-22 13:52:46 -07002207
2208 ext = X509_get_ext_d2i(cert, NID_subject_alt_name, NULL, NULL);
2209
Dmitry Shmidt9ead16e2014-10-07 13:15:23 -07002210 for (j = 0; ext && j < sk_GENERAL_NAME_num(ext); j++) {
2211 gen = sk_GENERAL_NAME_value(ext, j);
Dmitry Shmidt051af732013-10-22 13:52:46 -07002212 if (gen->type != GEN_DNS)
2213 continue;
2214 dns_name++;
2215 wpa_hexdump_ascii(MSG_DEBUG, "TLS: Certificate dNSName",
2216 gen->d.dNSName->data,
2217 gen->d.dNSName->length);
2218 if (domain_suffix_match(gen->d.dNSName->data,
Hai Shalom021b0b52019-04-10 11:17:58 -07002219 gen->d.dNSName->length,
2220 match, match_len, full) == 1) {
Dmitry Shmidt2f74e362015-01-21 13:19:05 -08002221 wpa_printf(MSG_DEBUG, "TLS: %s in dNSName found",
2222 full ? "Match" : "Suffix match");
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08002223 sk_GENERAL_NAME_pop_free(ext, GENERAL_NAME_free);
Dmitry Shmidt051af732013-10-22 13:52:46 -07002224 return 1;
2225 }
2226 }
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08002227 sk_GENERAL_NAME_pop_free(ext, GENERAL_NAME_free);
Dmitry Shmidt051af732013-10-22 13:52:46 -07002228
2229 if (dns_name) {
2230 wpa_printf(MSG_DEBUG, "TLS: None of the dNSName(s) matched");
2231 return 0;
2232 }
2233
2234 name = X509_get_subject_name(cert);
2235 i = -1;
2236 for (;;) {
2237 X509_NAME_ENTRY *e;
2238 ASN1_STRING *cn;
2239
2240 i = X509_NAME_get_index_by_NID(name, NID_commonName, i);
2241 if (i == -1)
2242 break;
2243 e = X509_NAME_get_entry(name, i);
2244 if (e == NULL)
2245 continue;
2246 cn = X509_NAME_ENTRY_get_data(e);
2247 if (cn == NULL)
2248 continue;
2249 wpa_hexdump_ascii(MSG_DEBUG, "TLS: Certificate commonName",
2250 cn->data, cn->length);
Hai Shalom021b0b52019-04-10 11:17:58 -07002251 if (domain_suffix_match(cn->data, cn->length,
2252 match, match_len, full) == 1) {
Dmitry Shmidt2f74e362015-01-21 13:19:05 -08002253 wpa_printf(MSG_DEBUG, "TLS: %s in commonName found",
2254 full ? "Match" : "Suffix match");
Dmitry Shmidt051af732013-10-22 13:52:46 -07002255 return 1;
2256 }
2257 }
2258
Dmitry Shmidt2f74e362015-01-21 13:19:05 -08002259 wpa_printf(MSG_DEBUG, "TLS: No CommonName %smatch found",
2260 full ? "": "suffix ");
Dmitry Shmidt051af732013-10-22 13:52:46 -07002261 return 0;
Hai Shalom021b0b52019-04-10 11:17:58 -07002262}
2263#endif /* CONFIG_NATIVE_WINDOWS */
2264
2265
2266static int tls_match_suffix(X509 *cert, const char *match, int full)
2267{
2268#ifdef CONFIG_NATIVE_WINDOWS
2269 /* wincrypt.h has conflicting X509_NAME definition */
2270 return -1;
2271#else /* CONFIG_NATIVE_WINDOWS */
2272 const char *token, *last = NULL;
2273
2274 /* Process each match alternative separately until a match is found */
2275 while ((token = cstr_token(match, ";", &last))) {
2276 if (tls_match_suffix_helper(cert, token, last - token, full))
2277 return 1;
2278 }
2279
2280 return 0;
Dmitry Shmidtfa3fc4a2013-11-21 13:34:38 -08002281#endif /* CONFIG_NATIVE_WINDOWS */
Dmitry Shmidt051af732013-10-22 13:52:46 -07002282}
2283
2284
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002285static enum tls_fail_reason openssl_tls_fail_reason(int err)
2286{
2287 switch (err) {
2288 case X509_V_ERR_CERT_REVOKED:
2289 return TLS_FAIL_REVOKED;
2290 case X509_V_ERR_CERT_NOT_YET_VALID:
2291 case X509_V_ERR_CRL_NOT_YET_VALID:
2292 return TLS_FAIL_NOT_YET_VALID;
2293 case X509_V_ERR_CERT_HAS_EXPIRED:
2294 case X509_V_ERR_CRL_HAS_EXPIRED:
2295 return TLS_FAIL_EXPIRED;
2296 case X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT:
2297 case X509_V_ERR_UNABLE_TO_GET_CRL:
2298 case X509_V_ERR_UNABLE_TO_GET_CRL_ISSUER:
2299 case X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN:
2300 case X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY:
2301 case X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT:
2302 case X509_V_ERR_UNABLE_TO_VERIFY_LEAF_SIGNATURE:
2303 case X509_V_ERR_CERT_CHAIN_TOO_LONG:
2304 case X509_V_ERR_PATH_LENGTH_EXCEEDED:
2305 case X509_V_ERR_INVALID_CA:
2306 return TLS_FAIL_UNTRUSTED;
2307 case X509_V_ERR_UNABLE_TO_DECRYPT_CERT_SIGNATURE:
2308 case X509_V_ERR_UNABLE_TO_DECRYPT_CRL_SIGNATURE:
2309 case X509_V_ERR_UNABLE_TO_DECODE_ISSUER_PUBLIC_KEY:
2310 case X509_V_ERR_ERROR_IN_CERT_NOT_BEFORE_FIELD:
2311 case X509_V_ERR_ERROR_IN_CERT_NOT_AFTER_FIELD:
2312 case X509_V_ERR_ERROR_IN_CRL_LAST_UPDATE_FIELD:
2313 case X509_V_ERR_ERROR_IN_CRL_NEXT_UPDATE_FIELD:
2314 case X509_V_ERR_CERT_UNTRUSTED:
2315 case X509_V_ERR_CERT_REJECTED:
2316 return TLS_FAIL_BAD_CERTIFICATE;
2317 default:
2318 return TLS_FAIL_UNSPECIFIED;
2319 }
2320}
2321
2322
2323static struct wpabuf * get_x509_cert(X509 *cert)
2324{
2325 struct wpabuf *buf;
2326 u8 *tmp;
2327
2328 int cert_len = i2d_X509(cert, NULL);
2329 if (cert_len <= 0)
2330 return NULL;
2331
2332 buf = wpabuf_alloc(cert_len);
2333 if (buf == NULL)
2334 return NULL;
2335
2336 tmp = wpabuf_put(buf, cert_len);
2337 i2d_X509(cert, &tmp);
2338 return buf;
2339}
2340
2341
2342static void openssl_tls_fail_event(struct tls_connection *conn,
2343 X509 *err_cert, int err, int depth,
2344 const char *subject, const char *err_str,
2345 enum tls_fail_reason reason)
2346{
2347 union tls_event_data ev;
2348 struct wpabuf *cert = NULL;
Dmitry Shmidtea69e842013-05-13 14:52:28 -07002349 struct tls_context *context = conn->context;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002350
Pavel Grafov4d8552e2018-02-06 11:28:29 +00002351#ifdef ANDROID
2352 log_cert_validation_failure(err_str);
2353#endif
2354
Dmitry Shmidtea69e842013-05-13 14:52:28 -07002355 if (context->event_cb == NULL)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002356 return;
2357
2358 cert = get_x509_cert(err_cert);
2359 os_memset(&ev, 0, sizeof(ev));
2360 ev.cert_fail.reason = reason != TLS_FAIL_UNSPECIFIED ?
2361 reason : openssl_tls_fail_reason(err);
2362 ev.cert_fail.depth = depth;
2363 ev.cert_fail.subject = subject;
2364 ev.cert_fail.reason_txt = err_str;
2365 ev.cert_fail.cert = cert;
Dmitry Shmidtea69e842013-05-13 14:52:28 -07002366 context->event_cb(context->cb_ctx, TLS_CERT_CHAIN_FAILURE, &ev);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002367 wpabuf_free(cert);
2368}
2369
2370
Hai Shalom81f62d82019-07-22 12:10:00 -07002371static int openssl_cert_tod(X509 *cert)
2372{
2373 CERTIFICATEPOLICIES *ext;
2374 stack_index_t i;
2375 char buf[100];
2376 int res;
2377 int tod = 0;
2378
2379 ext = X509_get_ext_d2i(cert, NID_certificate_policies, NULL, NULL);
2380 if (!ext)
2381 return 0;
2382
2383 for (i = 0; i < sk_POLICYINFO_num(ext); i++) {
2384 POLICYINFO *policy;
2385
2386 policy = sk_POLICYINFO_value(ext, i);
2387 res = OBJ_obj2txt(buf, sizeof(buf), policy->policyid, 0);
2388 if (res < 0 || (size_t) res >= sizeof(buf))
2389 continue;
2390 wpa_printf(MSG_DEBUG, "OpenSSL: Certificate Policy %s", buf);
2391 if (os_strcmp(buf, "1.3.6.1.4.1.40808.1.3.1") == 0)
Hai Shalomc3565922019-10-28 11:58:20 -07002392 tod = 1; /* TOD-STRICT */
2393 else if (os_strcmp(buf, "1.3.6.1.4.1.40808.1.3.2") == 0 && !tod)
2394 tod = 2; /* TOD-TOFU */
Hai Shalom81f62d82019-07-22 12:10:00 -07002395 }
Hai Shalomfdcde762020-04-02 11:19:20 -07002396 sk_POLICYINFO_pop_free(ext, POLICYINFO_free);
Hai Shalom81f62d82019-07-22 12:10:00 -07002397
2398 return tod;
2399}
2400
2401
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002402static void openssl_tls_cert_event(struct tls_connection *conn,
2403 X509 *err_cert, int depth,
2404 const char *subject)
2405{
2406 struct wpabuf *cert = NULL;
2407 union tls_event_data ev;
Dmitry Shmidtea69e842013-05-13 14:52:28 -07002408 struct tls_context *context = conn->context;
Dmitry Shmidt2f74e362015-01-21 13:19:05 -08002409 char *altsubject[TLS_MAX_ALT_SUBJECT];
2410 int alt, num_altsubject = 0;
2411 GENERAL_NAME *gen;
2412 void *ext;
2413 stack_index_t i;
Hai Shalom39ba6fc2019-01-22 12:40:38 -08002414 ASN1_INTEGER *ser;
2415 char serial_num[128];
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002416#ifdef CONFIG_SHA256
2417 u8 hash[32];
2418#endif /* CONFIG_SHA256 */
2419
Dmitry Shmidtea69e842013-05-13 14:52:28 -07002420 if (context->event_cb == NULL)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002421 return;
2422
2423 os_memset(&ev, 0, sizeof(ev));
Dmitry Shmidt55840ad2015-12-14 12:45:46 -08002424 if (conn->cert_probe || (conn->flags & TLS_CONN_EXT_CERT_CHECK) ||
2425 context->cert_in_cb) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002426 cert = get_x509_cert(err_cert);
2427 ev.peer_cert.cert = cert;
2428 }
2429#ifdef CONFIG_SHA256
2430 if (cert) {
2431 const u8 *addr[1];
2432 size_t len[1];
2433 addr[0] = wpabuf_head(cert);
2434 len[0] = wpabuf_len(cert);
2435 if (sha256_vector(1, addr, len, hash) == 0) {
2436 ev.peer_cert.hash = hash;
2437 ev.peer_cert.hash_len = sizeof(hash);
2438 }
2439 }
2440#endif /* CONFIG_SHA256 */
2441 ev.peer_cert.depth = depth;
2442 ev.peer_cert.subject = subject;
Dmitry Shmidt2f74e362015-01-21 13:19:05 -08002443
Hai Shalom39ba6fc2019-01-22 12:40:38 -08002444 ser = X509_get_serialNumber(err_cert);
2445 if (ser) {
2446 wpa_snprintf_hex_uppercase(serial_num, sizeof(serial_num),
2447 ASN1_STRING_get0_data(ser),
2448 ASN1_STRING_length(ser));
2449 ev.peer_cert.serial_num = serial_num;
2450 }
2451
Dmitry Shmidt2f74e362015-01-21 13:19:05 -08002452 ext = X509_get_ext_d2i(err_cert, NID_subject_alt_name, NULL, NULL);
2453 for (i = 0; ext && i < sk_GENERAL_NAME_num(ext); i++) {
2454 char *pos;
2455
2456 if (num_altsubject == TLS_MAX_ALT_SUBJECT)
2457 break;
2458 gen = sk_GENERAL_NAME_value(ext, i);
2459 if (gen->type != GEN_EMAIL &&
2460 gen->type != GEN_DNS &&
2461 gen->type != GEN_URI)
2462 continue;
2463
2464 pos = os_malloc(10 + gen->d.ia5->length + 1);
2465 if (pos == NULL)
2466 break;
2467 altsubject[num_altsubject++] = pos;
2468
2469 switch (gen->type) {
2470 case GEN_EMAIL:
2471 os_memcpy(pos, "EMAIL:", 6);
2472 pos += 6;
2473 break;
2474 case GEN_DNS:
2475 os_memcpy(pos, "DNS:", 4);
2476 pos += 4;
2477 break;
2478 case GEN_URI:
2479 os_memcpy(pos, "URI:", 4);
2480 pos += 4;
2481 break;
2482 }
2483
2484 os_memcpy(pos, gen->d.ia5->data, gen->d.ia5->length);
2485 pos += gen->d.ia5->length;
2486 *pos = '\0';
2487 }
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08002488 sk_GENERAL_NAME_pop_free(ext, GENERAL_NAME_free);
Dmitry Shmidt2f74e362015-01-21 13:19:05 -08002489
2490 for (alt = 0; alt < num_altsubject; alt++)
2491 ev.peer_cert.altsubject[alt] = altsubject[alt];
2492 ev.peer_cert.num_altsubject = num_altsubject;
2493
Hai Shalom81f62d82019-07-22 12:10:00 -07002494 ev.peer_cert.tod = openssl_cert_tod(err_cert);
2495
Dmitry Shmidtea69e842013-05-13 14:52:28 -07002496 context->event_cb(context->cb_ctx, TLS_PEER_CERTIFICATE, &ev);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002497 wpabuf_free(cert);
Dmitry Shmidt2f74e362015-01-21 13:19:05 -08002498 for (alt = 0; alt < num_altsubject; alt++)
2499 os_free(altsubject[alt]);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002500}
2501
2502
Hai Shalomc3565922019-10-28 11:58:20 -07002503static void debug_print_cert(X509 *cert, const char *title)
2504{
2505#ifndef CONFIG_NO_STDOUT_DEBUG
2506 BIO *out;
2507 size_t rlen;
2508 char *txt;
2509 int res;
2510
2511 if (wpa_debug_level > MSG_DEBUG)
2512 return;
2513
2514 out = BIO_new(BIO_s_mem());
2515 if (!out)
2516 return;
2517
2518 X509_print(out, cert);
2519 rlen = BIO_ctrl_pending(out);
2520 txt = os_malloc(rlen + 1);
2521 if (txt) {
2522 res = BIO_read(out, txt, rlen);
2523 if (res > 0) {
2524 txt[res] = '\0';
2525 wpa_printf(MSG_DEBUG, "OpenSSL: %s\n%s", title, txt);
2526 }
2527 os_free(txt);
2528 }
2529
2530 BIO_free(out);
2531#endif /* CONFIG_NO_STDOUT_DEBUG */
2532}
2533
2534
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002535static int tls_verify_cb(int preverify_ok, X509_STORE_CTX *x509_ctx)
2536{
2537 char buf[256];
2538 X509 *err_cert;
2539 int err, depth;
2540 SSL *ssl;
2541 struct tls_connection *conn;
Dmitry Shmidtea69e842013-05-13 14:52:28 -07002542 struct tls_context *context;
Dmitry Shmidt2f74e362015-01-21 13:19:05 -08002543 char *match, *altmatch, *suffix_match, *domain_match;
Hai Shalom021b0b52019-04-10 11:17:58 -07002544 const char *check_cert_subject;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002545 const char *err_str;
2546
2547 err_cert = X509_STORE_CTX_get_current_cert(x509_ctx);
Dmitry Shmidt96be6222014-02-13 10:16:51 -08002548 if (!err_cert)
2549 return 0;
2550
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002551 err = X509_STORE_CTX_get_error(x509_ctx);
2552 depth = X509_STORE_CTX_get_error_depth(x509_ctx);
2553 ssl = X509_STORE_CTX_get_ex_data(x509_ctx,
2554 SSL_get_ex_data_X509_STORE_CTX_idx());
Hai Shalomc3565922019-10-28 11:58:20 -07002555 os_snprintf(buf, sizeof(buf), "Peer certificate - depth %d", depth);
2556 debug_print_cert(err_cert, buf);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002557 X509_NAME_oneline(X509_get_subject_name(err_cert), buf, sizeof(buf));
2558
2559 conn = SSL_get_app_data(ssl);
2560 if (conn == NULL)
2561 return 0;
Dmitry Shmidt34af3062013-07-11 10:46:32 -07002562
2563 if (depth == 0)
2564 conn->peer_cert = err_cert;
2565 else if (depth == 1)
2566 conn->peer_issuer = err_cert;
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08002567 else if (depth == 2)
2568 conn->peer_issuer_issuer = err_cert;
Dmitry Shmidt34af3062013-07-11 10:46:32 -07002569
Dmitry Shmidtea69e842013-05-13 14:52:28 -07002570 context = conn->context;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002571 match = conn->subject_match;
2572 altmatch = conn->altsubject_match;
Dmitry Shmidt051af732013-10-22 13:52:46 -07002573 suffix_match = conn->suffix_match;
Dmitry Shmidt2f74e362015-01-21 13:19:05 -08002574 domain_match = conn->domain_match;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002575
2576 if (!preverify_ok && !conn->ca_cert_verify)
2577 preverify_ok = 1;
2578 if (!preverify_ok && depth > 0 && conn->server_cert_only)
2579 preverify_ok = 1;
Dmitry Shmidtc55524a2011-07-07 11:18:38 -07002580 if (!preverify_ok && (conn->flags & TLS_CONN_DISABLE_TIME_CHECKS) &&
2581 (err == X509_V_ERR_CERT_HAS_EXPIRED ||
2582 err == X509_V_ERR_CERT_NOT_YET_VALID)) {
2583 wpa_printf(MSG_DEBUG, "OpenSSL: Ignore certificate validity "
2584 "time mismatch");
2585 preverify_ok = 1;
2586 }
Hai Shalom74f70d42019-02-11 14:42:39 -08002587 if (!preverify_ok && !conn->data->check_crl_strict &&
2588 (err == X509_V_ERR_CRL_HAS_EXPIRED ||
2589 err == X509_V_ERR_CRL_NOT_YET_VALID)) {
2590 wpa_printf(MSG_DEBUG,
2591 "OpenSSL: Ignore certificate validity CRL time mismatch");
2592 preverify_ok = 1;
2593 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002594
2595 err_str = X509_verify_cert_error_string(err);
2596
2597#ifdef CONFIG_SHA256
Dmitry Shmidt4dd28dc2015-03-10 11:21:43 -07002598 /*
2599 * Do not require preverify_ok so we can explicity allow otherwise
2600 * invalid pinned server certificates.
2601 */
2602 if (depth == 0 && conn->server_cert_only) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002603 struct wpabuf *cert;
2604 cert = get_x509_cert(err_cert);
2605 if (!cert) {
2606 wpa_printf(MSG_DEBUG, "OpenSSL: Could not fetch "
2607 "server certificate data");
2608 preverify_ok = 0;
2609 } else {
2610 u8 hash[32];
2611 const u8 *addr[1];
2612 size_t len[1];
Hai Shalomae89c832023-04-19 15:42:17 -07002613
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002614 addr[0] = wpabuf_head(cert);
2615 len[0] = wpabuf_len(cert);
2616 if (sha256_vector(1, addr, len, hash) < 0 ||
2617 os_memcmp(conn->srv_cert_hash, hash, 32) != 0) {
2618 err_str = "Server certificate mismatch";
2619 err = X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN;
2620 preverify_ok = 0;
Dmitry Shmidt4dd28dc2015-03-10 11:21:43 -07002621 } else if (!preverify_ok) {
2622 /*
2623 * Certificate matches pinned certificate, allow
2624 * regardless of other problems.
2625 */
2626 wpa_printf(MSG_DEBUG,
2627 "OpenSSL: Ignore validation issues for a pinned server certificate");
2628 preverify_ok = 1;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002629 }
2630 wpabuf_free(cert);
2631 }
2632 }
2633#endif /* CONFIG_SHA256 */
2634
2635 if (!preverify_ok) {
Hai Shalomae89c832023-04-19 15:42:17 -07002636 /* Send cert events for the peer certificate chain so that
2637 * the upper layers get information about it even if
2638 * validation of a CA certificate fails. */
2639 STACK_OF(X509) *chain;
2640 int num_of_certs;
Hai Shalom81f62d82019-07-22 12:10:00 -07002641
Hai Shalomae89c832023-04-19 15:42:17 -07002642 chain = X509_STORE_CTX_get1_chain(x509_ctx);
2643 num_of_certs = sk_X509_num(chain);
2644 if (chain && num_of_certs > 0) {
2645 char buf2[256];
2646 X509 *cert;
2647 int cur_depth;
Hai Shalom81f62d82019-07-22 12:10:00 -07002648
Hai Shalomae89c832023-04-19 15:42:17 -07002649 for (cur_depth = num_of_certs - 1; cur_depth >= 0; cur_depth--) {
2650 cert = sk_X509_value(chain, cur_depth);
Hai Shalom81f62d82019-07-22 12:10:00 -07002651 X509_NAME_oneline(X509_get_subject_name(cert),
2652 buf2, sizeof(buf2));
2653
Hai Shalomae89c832023-04-19 15:42:17 -07002654 openssl_tls_cert_event(conn, cert, cur_depth, buf2);
Hai Shalom81f62d82019-07-22 12:10:00 -07002655 }
Hai Shalom81f62d82019-07-22 12:10:00 -07002656 }
Hai Shalomae89c832023-04-19 15:42:17 -07002657 if (chain)
2658 sk_X509_pop_free(chain, X509_free);
Hai Shalom81f62d82019-07-22 12:10:00 -07002659
Gabriel Biren60ae0682023-11-01 22:04:12 +00002660 char *format_str = "TLS: Certificate verification failed,"
2661 " error %d (%s) depth %d for '%s'";
2662 int msg_len = snprintf(NULL, 0, format_str, err, err_str, depth, buf) + 1;
2663 char *msg = os_malloc(msg_len);
2664 snprintf(msg, msg_len, format_str, err, err_str, depth, buf);
2665
2666 wpa_printf(MSG_WARNING, "%s", msg);
2667 if (conn != NULL && conn->context != NULL
2668 && openssl_failure_callback_global != NULL) {
2669 (*openssl_failure_callback_global)(conn->context->cb_ctx, msg);
2670 }
2671 os_free(msg);
2672
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002673 openssl_tls_fail_event(conn, err_cert, err, depth, buf,
2674 err_str, TLS_FAIL_UNSPECIFIED);
2675 return preverify_ok;
2676 }
2677
Hai Shalomae89c832023-04-19 15:42:17 -07002678 openssl_tls_cert_event(conn, err_cert, depth, buf);
2679
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002680 wpa_printf(MSG_DEBUG, "TLS: tls_verify_cb - preverify_ok=%d "
2681 "err=%d (%s) ca_cert_verify=%d depth=%d buf='%s'",
2682 preverify_ok, err, err_str,
2683 conn->ca_cert_verify, depth, buf);
Hai Shalom021b0b52019-04-10 11:17:58 -07002684 check_cert_subject = conn->check_cert_subject;
2685 if (!check_cert_subject)
2686 check_cert_subject = conn->data->check_cert_subject;
2687 if (check_cert_subject) {
2688 if (depth == 0 &&
2689 !tls_match_dn_field(err_cert, check_cert_subject)) {
2690 preverify_ok = 0;
2691 openssl_tls_fail_event(conn, err_cert, err, depth, buf,
2692 "Distinguished Name",
2693 TLS_FAIL_DN_MISMATCH);
2694 }
2695 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002696 if (depth == 0 && match && os_strstr(buf, match) == NULL) {
2697 wpa_printf(MSG_WARNING, "TLS: Subject '%s' did not "
2698 "match with '%s'", buf, match);
2699 preverify_ok = 0;
2700 openssl_tls_fail_event(conn, err_cert, err, depth, buf,
2701 "Subject mismatch",
2702 TLS_FAIL_SUBJECT_MISMATCH);
2703 } else if (depth == 0 && altmatch &&
2704 !tls_match_altsubject(err_cert, altmatch)) {
2705 wpa_printf(MSG_WARNING, "TLS: altSubjectName match "
2706 "'%s' not found", altmatch);
2707 preverify_ok = 0;
2708 openssl_tls_fail_event(conn, err_cert, err, depth, buf,
2709 "AltSubject mismatch",
2710 TLS_FAIL_ALTSUBJECT_MISMATCH);
Dmitry Shmidt051af732013-10-22 13:52:46 -07002711 } else if (depth == 0 && suffix_match &&
Dmitry Shmidt2f74e362015-01-21 13:19:05 -08002712 !tls_match_suffix(err_cert, suffix_match, 0)) {
Dmitry Shmidt051af732013-10-22 13:52:46 -07002713 wpa_printf(MSG_WARNING, "TLS: Domain suffix match '%s' not found",
2714 suffix_match);
2715 preverify_ok = 0;
2716 openssl_tls_fail_event(conn, err_cert, err, depth, buf,
2717 "Domain suffix mismatch",
2718 TLS_FAIL_DOMAIN_SUFFIX_MISMATCH);
Dmitry Shmidt2f74e362015-01-21 13:19:05 -08002719 } else if (depth == 0 && domain_match &&
2720 !tls_match_suffix(err_cert, domain_match, 1)) {
2721 wpa_printf(MSG_WARNING, "TLS: Domain match '%s' not found",
2722 domain_match);
2723 preverify_ok = 0;
2724 openssl_tls_fail_event(conn, err_cert, err, depth, buf,
2725 "Domain mismatch",
2726 TLS_FAIL_DOMAIN_MISMATCH);
Hai Shalom81f62d82019-07-22 12:10:00 -07002727 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002728
2729 if (conn->cert_probe && preverify_ok && depth == 0) {
2730 wpa_printf(MSG_DEBUG, "OpenSSL: Reject server certificate "
2731 "on probe-only run");
2732 preverify_ok = 0;
2733 openssl_tls_fail_event(conn, err_cert, err, depth, buf,
2734 "Server certificate chain probe",
2735 TLS_FAIL_SERVER_CHAIN_PROBE);
2736 }
2737
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002738#ifdef CONFIG_SUITEB
2739 if (conn->flags & TLS_CONN_SUITEB) {
2740 EVP_PKEY *pk;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002741 int len = -1;
2742
2743 pk = X509_get_pubkey(err_cert);
2744 if (pk) {
Sunil Ravia04bd252022-05-02 22:54:18 -07002745 len = EVP_PKEY_bits(pk);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002746 EVP_PKEY_free(pk);
2747 }
2748
2749 if (len >= 0) {
2750 wpa_printf(MSG_DEBUG,
2751 "OpenSSL: RSA modulus size: %d bits", len);
2752 if (len < 3072) {
2753 preverify_ok = 0;
2754 openssl_tls_fail_event(
2755 conn, err_cert, err,
2756 depth, buf,
2757 "Insufficient RSA modulus size",
2758 TLS_FAIL_INSUFFICIENT_KEY_LEN);
2759 }
2760 }
2761 }
2762#endif /* CONFIG_SUITEB */
2763
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08002764#ifdef OPENSSL_IS_BORINGSSL
Dmitry Shmidtd7ff03d2015-12-04 14:49:35 -08002765 if (depth == 0 && (conn->flags & TLS_CONN_REQUEST_OCSP) &&
2766 preverify_ok) {
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08002767 enum ocsp_result res;
2768
Dmitry Shmidtd7ff03d2015-12-04 14:49:35 -08002769 res = check_ocsp_resp(conn->ssl_ctx, conn->ssl, err_cert,
2770 conn->peer_issuer,
2771 conn->peer_issuer_issuer);
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08002772 if (res == OCSP_REVOKED) {
2773 preverify_ok = 0;
2774 openssl_tls_fail_event(conn, err_cert, err, depth, buf,
2775 "certificate revoked",
2776 TLS_FAIL_REVOKED);
2777 if (err == X509_V_OK)
2778 X509_STORE_CTX_set_error(
2779 x509_ctx, X509_V_ERR_CERT_REVOKED);
2780 } else if (res != OCSP_GOOD &&
2781 (conn->flags & TLS_CONN_REQUIRE_OCSP)) {
2782 preverify_ok = 0;
2783 openssl_tls_fail_event(conn, err_cert, err, depth, buf,
2784 "bad certificate status response",
2785 TLS_FAIL_UNSPECIFIED);
2786 }
2787 }
2788#endif /* OPENSSL_IS_BORINGSSL */
2789
Dmitry Shmidt55840ad2015-12-14 12:45:46 -08002790 if (depth == 0 && preverify_ok && context->event_cb != NULL)
Dmitry Shmidtea69e842013-05-13 14:52:28 -07002791 context->event_cb(context->cb_ctx,
2792 TLS_CERT_CHAIN_SUCCESS, NULL);
Dmitry Shmidt04949592012-07-19 12:16:46 -07002793
Hai Shalom899fcc72020-10-19 14:38:18 -07002794 if (depth == 0 && preverify_ok) {
2795 os_free(conn->peer_subject);
2796 conn->peer_subject = os_strdup(buf);
2797 }
2798
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002799 return preverify_ok;
2800}
2801
2802
2803#ifndef OPENSSL_NO_STDIO
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08002804static int tls_load_ca_der(struct tls_data *data, const char *ca_cert)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002805{
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08002806 SSL_CTX *ssl_ctx = data->ssl;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002807 X509_LOOKUP *lookup;
2808 int ret = 0;
2809
Dmitry Shmidt216983b2015-02-06 10:50:36 -08002810 lookup = X509_STORE_add_lookup(SSL_CTX_get_cert_store(ssl_ctx),
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002811 X509_LOOKUP_file());
2812 if (lookup == NULL) {
2813 tls_show_errors(MSG_WARNING, __func__,
2814 "Failed add lookup for X509 store");
2815 return -1;
2816 }
2817
2818 if (!X509_LOOKUP_load_file(lookup, ca_cert, X509_FILETYPE_ASN1)) {
2819 unsigned long err = ERR_peek_error();
2820 tls_show_errors(MSG_WARNING, __func__,
2821 "Failed load CA in DER format");
2822 if (ERR_GET_LIB(err) == ERR_LIB_X509 &&
2823 ERR_GET_REASON(err) == X509_R_CERT_ALREADY_IN_HASH_TABLE) {
2824 wpa_printf(MSG_DEBUG, "OpenSSL: %s - ignoring "
2825 "cert already in hash table error",
2826 __func__);
2827 } else
2828 ret = -1;
2829 }
2830
2831 return ret;
2832}
2833#endif /* OPENSSL_NO_STDIO */
2834
2835
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08002836static int tls_connection_ca_cert(struct tls_data *data,
2837 struct tls_connection *conn,
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002838 const char *ca_cert, const u8 *ca_cert_blob,
2839 size_t ca_cert_blob_len, const char *ca_path)
2840{
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08002841 SSL_CTX *ssl_ctx = data->ssl;
Dmitry Shmidt216983b2015-02-06 10:50:36 -08002842 X509_STORE *store;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002843
2844 /*
2845 * Remove previously configured trusted CA certificates before adding
2846 * new ones.
2847 */
Dmitry Shmidt216983b2015-02-06 10:50:36 -08002848 store = X509_STORE_new();
2849 if (store == NULL) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002850 wpa_printf(MSG_DEBUG, "OpenSSL: %s - failed to allocate new "
2851 "certificate store", __func__);
2852 return -1;
2853 }
Dmitry Shmidt216983b2015-02-06 10:50:36 -08002854 SSL_CTX_set_cert_store(ssl_ctx, store);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002855
2856 SSL_set_verify(conn->ssl, SSL_VERIFY_PEER, tls_verify_cb);
2857 conn->ca_cert_verify = 1;
2858
2859 if (ca_cert && os_strncmp(ca_cert, "probe://", 8) == 0) {
2860 wpa_printf(MSG_DEBUG, "OpenSSL: Probe for server certificate "
2861 "chain");
2862 conn->cert_probe = 1;
2863 conn->ca_cert_verify = 0;
2864 return 0;
2865 }
2866
2867 if (ca_cert && os_strncmp(ca_cert, "hash://", 7) == 0) {
2868#ifdef CONFIG_SHA256
2869 const char *pos = ca_cert + 7;
2870 if (os_strncmp(pos, "server/sha256/", 14) != 0) {
2871 wpa_printf(MSG_DEBUG, "OpenSSL: Unsupported ca_cert "
2872 "hash value '%s'", ca_cert);
2873 return -1;
2874 }
2875 pos += 14;
2876 if (os_strlen(pos) != 32 * 2) {
2877 wpa_printf(MSG_DEBUG, "OpenSSL: Unexpected SHA256 "
2878 "hash length in ca_cert '%s'", ca_cert);
2879 return -1;
2880 }
2881 if (hexstr2bin(pos, conn->srv_cert_hash, 32) < 0) {
2882 wpa_printf(MSG_DEBUG, "OpenSSL: Invalid SHA256 hash "
2883 "value in ca_cert '%s'", ca_cert);
2884 return -1;
2885 }
2886 conn->server_cert_only = 1;
2887 wpa_printf(MSG_DEBUG, "OpenSSL: Checking only server "
2888 "certificate match");
2889 return 0;
2890#else /* CONFIG_SHA256 */
2891 wpa_printf(MSG_INFO, "No SHA256 included in the build - "
2892 "cannot validate server certificate hash");
2893 return -1;
2894#endif /* CONFIG_SHA256 */
2895 }
2896
2897 if (ca_cert_blob) {
Dmitry Shmidt216983b2015-02-06 10:50:36 -08002898 X509 *cert = d2i_X509(NULL,
2899 (const unsigned char **) &ca_cert_blob,
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002900 ca_cert_blob_len);
2901 if (cert == NULL) {
Hai Shalom81f62d82019-07-22 12:10:00 -07002902 BIO *bio = BIO_new_mem_buf(ca_cert_blob,
2903 ca_cert_blob_len);
2904
2905 if (bio) {
2906 cert = PEM_read_bio_X509(bio, NULL, NULL, NULL);
2907 BIO_free(bio);
2908 }
2909
2910 if (!cert) {
2911 tls_show_errors(MSG_WARNING, __func__,
2912 "Failed to parse ca_cert_blob");
2913 return -1;
2914 }
2915
2916 while (ERR_get_error()) {
2917 /* Ignore errors from DER conversion. */
2918 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002919 }
2920
Dmitry Shmidt216983b2015-02-06 10:50:36 -08002921 if (!X509_STORE_add_cert(SSL_CTX_get_cert_store(ssl_ctx),
2922 cert)) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002923 unsigned long err = ERR_peek_error();
2924 tls_show_errors(MSG_WARNING, __func__,
2925 "Failed to add ca_cert_blob to "
2926 "certificate store");
2927 if (ERR_GET_LIB(err) == ERR_LIB_X509 &&
2928 ERR_GET_REASON(err) ==
2929 X509_R_CERT_ALREADY_IN_HASH_TABLE) {
2930 wpa_printf(MSG_DEBUG, "OpenSSL: %s - ignoring "
2931 "cert already in hash table error",
2932 __func__);
2933 } else {
2934 X509_free(cert);
2935 return -1;
2936 }
2937 }
2938 X509_free(cert);
2939 wpa_printf(MSG_DEBUG, "OpenSSL: %s - added ca_cert_blob "
2940 "to certificate store", __func__);
2941 return 0;
2942 }
2943
2944#ifdef ANDROID
Dmitry Shmidtb97e4282016-02-08 10:16:07 -08002945 /* Single alias */
Hai Shalom7ad2a872021-08-02 18:56:55 -07002946 if (ca_cert && os_strncmp(ANDROID_KEYSTORE_PREFIX, ca_cert,
2947 ANDROID_KEYSTORE_PREFIX_LEN) == 0) {
Dmitry Shmidt849734c2016-05-27 09:59:01 -07002948 if (tls_add_ca_from_keystore(SSL_CTX_get_cert_store(ssl_ctx),
Gabriel Birenff4f8382023-04-06 20:14:39 +00002949 &ca_cert[ANDROID_KEYSTORE_PREFIX_LEN], conn) < 0)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002950 return -1;
Dmitry Shmidtb97e4282016-02-08 10:16:07 -08002951 SSL_set_verify(conn->ssl, SSL_VERIFY_PEER, tls_verify_cb);
2952 return 0;
2953 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002954
Dmitry Shmidtb97e4282016-02-08 10:16:07 -08002955 /* Multiple aliases separated by space */
Hai Shalom7ad2a872021-08-02 18:56:55 -07002956 if (ca_cert && os_strncmp(ANDROID_KEYSTORE_ENCODED_PREFIX, ca_cert,
2957 ANDROID_KEYSTORE_ENCODED_PREFIX_LEN) == 0) {
2958 char *aliases = os_strdup(
2959 &ca_cert[ANDROID_KEYSTORE_ENCODED_PREFIX_LEN]);
Dmitry Shmidtb97e4282016-02-08 10:16:07 -08002960 const char *delim = " ";
2961 int rc = 0;
2962 char *savedptr;
2963 char *alias;
2964
2965 if (!aliases)
2966 return -1;
2967 alias = strtok_r(aliases, delim, &savedptr);
2968 for (; alias; alias = strtok_r(NULL, delim, &savedptr)) {
2969 if (tls_add_ca_from_keystore_encoded(
Gabriel Birenff4f8382023-04-06 20:14:39 +00002970 SSL_CTX_get_cert_store(ssl_ctx), alias, conn)) {
Hai Shalom7ad2a872021-08-02 18:56:55 -07002971 wpa_printf(MSG_ERROR,
2972 "OpenSSL: Failed to add ca_cert %s from keystore",
2973 alias);
Dmitry Shmidtb97e4282016-02-08 10:16:07 -08002974 rc = -1;
2975 break;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002976 }
2977 }
Dmitry Shmidtb97e4282016-02-08 10:16:07 -08002978 os_free(aliases);
2979 if (rc)
2980 return rc;
2981
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002982 SSL_set_verify(conn->ssl, SSL_VERIFY_PEER, tls_verify_cb);
2983 return 0;
2984 }
2985#endif /* ANDROID */
2986
2987#ifdef CONFIG_NATIVE_WINDOWS
2988 if (ca_cert && tls_cryptoapi_ca_cert(ssl_ctx, conn->ssl, ca_cert) ==
2989 0) {
2990 wpa_printf(MSG_DEBUG, "OpenSSL: Added CA certificates from "
2991 "system certificate store");
2992 return 0;
2993 }
2994#endif /* CONFIG_NATIVE_WINDOWS */
2995
2996 if (ca_cert || ca_path) {
2997#ifndef OPENSSL_NO_STDIO
2998 if (SSL_CTX_load_verify_locations(ssl_ctx, ca_cert, ca_path) !=
2999 1) {
3000 tls_show_errors(MSG_WARNING, __func__,
3001 "Failed to load root certificates");
3002 if (ca_cert &&
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08003003 tls_load_ca_der(data, ca_cert) == 0) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003004 wpa_printf(MSG_DEBUG, "OpenSSL: %s - loaded "
3005 "DER format CA certificate",
3006 __func__);
3007 } else
3008 return -1;
3009 } else {
3010 wpa_printf(MSG_DEBUG, "TLS: Trusted root "
3011 "certificate(s) loaded");
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08003012 tls_get_errors(data);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003013 }
3014#else /* OPENSSL_NO_STDIO */
3015 wpa_printf(MSG_DEBUG, "OpenSSL: %s - OPENSSL_NO_STDIO",
3016 __func__);
3017 return -1;
3018#endif /* OPENSSL_NO_STDIO */
3019 } else {
3020 /* No ca_cert configured - do not try to verify server
3021 * certificate */
3022 conn->ca_cert_verify = 0;
3023 }
3024
3025 return 0;
3026}
3027
3028
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08003029static int tls_global_ca_cert(struct tls_data *data, const char *ca_cert)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003030{
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08003031 SSL_CTX *ssl_ctx = data->ssl;
3032
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003033 if (ca_cert) {
3034 if (SSL_CTX_load_verify_locations(ssl_ctx, ca_cert, NULL) != 1)
3035 {
3036 tls_show_errors(MSG_WARNING, __func__,
3037 "Failed to load root certificates");
3038 return -1;
3039 }
3040
3041 wpa_printf(MSG_DEBUG, "TLS: Trusted root "
3042 "certificate(s) loaded");
3043
3044#ifndef OPENSSL_NO_STDIO
3045 /* Add the same CAs to the client certificate requests */
3046 SSL_CTX_set_client_CA_list(ssl_ctx,
3047 SSL_load_client_CA_file(ca_cert));
3048#endif /* OPENSSL_NO_STDIO */
Hai Shalom74f70d42019-02-11 14:42:39 -08003049
3050 os_free(data->ca_cert);
3051 data->ca_cert = os_strdup(ca_cert);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003052 }
3053
3054 return 0;
3055}
3056
3057
Hai Shalom74f70d42019-02-11 14:42:39 -08003058int tls_global_set_verify(void *ssl_ctx, int check_crl, int strict)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003059{
3060 int flags;
3061
3062 if (check_crl) {
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08003063 struct tls_data *data = ssl_ctx;
3064 X509_STORE *cs = SSL_CTX_get_cert_store(data->ssl);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003065 if (cs == NULL) {
3066 tls_show_errors(MSG_INFO, __func__, "Failed to get "
3067 "certificate store when enabling "
3068 "check_crl");
3069 return -1;
3070 }
3071 flags = X509_V_FLAG_CRL_CHECK;
3072 if (check_crl == 2)
3073 flags |= X509_V_FLAG_CRL_CHECK_ALL;
3074 X509_STORE_set_flags(cs, flags);
Hai Shalom74f70d42019-02-11 14:42:39 -08003075
3076 data->check_crl = check_crl;
3077 data->check_crl_strict = strict;
3078 os_get_reltime(&data->crl_last_reload);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003079 }
3080 return 0;
3081}
3082
3083
3084static int tls_connection_set_subject_match(struct tls_connection *conn,
3085 const char *subject_match,
Dmitry Shmidt051af732013-10-22 13:52:46 -07003086 const char *altsubject_match,
Dmitry Shmidt2f74e362015-01-21 13:19:05 -08003087 const char *suffix_match,
Hai Shalom021b0b52019-04-10 11:17:58 -07003088 const char *domain_match,
3089 const char *check_cert_subject)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003090{
3091 os_free(conn->subject_match);
3092 conn->subject_match = NULL;
3093 if (subject_match) {
3094 conn->subject_match = os_strdup(subject_match);
3095 if (conn->subject_match == NULL)
3096 return -1;
3097 }
3098
3099 os_free(conn->altsubject_match);
3100 conn->altsubject_match = NULL;
3101 if (altsubject_match) {
3102 conn->altsubject_match = os_strdup(altsubject_match);
3103 if (conn->altsubject_match == NULL)
3104 return -1;
3105 }
3106
Dmitry Shmidt051af732013-10-22 13:52:46 -07003107 os_free(conn->suffix_match);
3108 conn->suffix_match = NULL;
3109 if (suffix_match) {
3110 conn->suffix_match = os_strdup(suffix_match);
3111 if (conn->suffix_match == NULL)
3112 return -1;
3113 }
3114
Dmitry Shmidt2f74e362015-01-21 13:19:05 -08003115 os_free(conn->domain_match);
3116 conn->domain_match = NULL;
3117 if (domain_match) {
3118 conn->domain_match = os_strdup(domain_match);
3119 if (conn->domain_match == NULL)
3120 return -1;
3121 }
3122
Hai Shalom021b0b52019-04-10 11:17:58 -07003123 os_free(conn->check_cert_subject);
3124 conn->check_cert_subject = NULL;
3125 if (check_cert_subject) {
3126 conn->check_cert_subject = os_strdup(check_cert_subject);
3127 if (!conn->check_cert_subject)
3128 return -1;
3129 }
3130
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003131 return 0;
3132}
3133
3134
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003135#ifdef CONFIG_SUITEB
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003136static int suiteb_cert_cb(SSL *ssl, void *arg)
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08003137{
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003138 struct tls_connection *conn = arg;
3139
3140 /*
3141 * This cert_cb() is not really the best location for doing a
3142 * constraint check for the ServerKeyExchange message, but this seems to
3143 * be the only place where the current OpenSSL sequence can be
3144 * terminated cleanly with an TLS alert going out to the server.
3145 */
3146
3147 if (!(conn->flags & TLS_CONN_SUITEB))
3148 return 1;
3149
3150 /* DHE is enabled only with DHE-RSA-AES256-GCM-SHA384 */
3151 if (conn->cipher_suite != 0x9f)
3152 return 1;
3153
3154 if (conn->server_dh_prime_len >= 3072)
3155 return 1;
3156
3157 wpa_printf(MSG_DEBUG,
3158 "OpenSSL: Server DH prime length (%d bits) not sufficient for Suite B RSA - reject handshake",
3159 conn->server_dh_prime_len);
3160 return 0;
3161}
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003162#endif /* CONFIG_SUITEB */
3163
3164
Roshan Pius3a1667e2018-07-03 15:17:14 -07003165static int tls_set_conn_flags(struct tls_connection *conn, unsigned int flags,
3166 const char *openssl_ciphers)
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003167{
3168 SSL *ssl = conn->ssl;
3169
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08003170#ifdef SSL_OP_NO_TICKET
3171 if (flags & TLS_CONN_DISABLE_SESSION_TICKET)
3172 SSL_set_options(ssl, SSL_OP_NO_TICKET);
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08003173 else
3174 SSL_clear_options(ssl, SSL_OP_NO_TICKET);
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08003175#endif /* SSL_OP_NO_TICKET */
3176
Sunil Ravia04bd252022-05-02 22:54:18 -07003177#ifdef SSL_OP_LEGACY_SERVER_CONNECT
3178 if (flags & TLS_CONN_ALLOW_UNSAFE_RENEGOTIATION)
3179 SSL_set_options(ssl, SSL_OP_LEGACY_SERVER_CONNECT);
3180#endif /* SSL_OP_LEGACY_SERVER_CONNECT */
3181
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08003182#ifdef SSL_OP_NO_TLSv1
3183 if (flags & TLS_CONN_DISABLE_TLSv1_0)
3184 SSL_set_options(ssl, SSL_OP_NO_TLSv1);
3185 else
3186 SSL_clear_options(ssl, SSL_OP_NO_TLSv1);
3187#endif /* SSL_OP_NO_TLSv1 */
3188#ifdef SSL_OP_NO_TLSv1_1
3189 if (flags & TLS_CONN_DISABLE_TLSv1_1)
3190 SSL_set_options(ssl, SSL_OP_NO_TLSv1_1);
3191 else
3192 SSL_clear_options(ssl, SSL_OP_NO_TLSv1_1);
3193#endif /* SSL_OP_NO_TLSv1_1 */
3194#ifdef SSL_OP_NO_TLSv1_2
3195 if (flags & TLS_CONN_DISABLE_TLSv1_2)
3196 SSL_set_options(ssl, SSL_OP_NO_TLSv1_2);
3197 else
3198 SSL_clear_options(ssl, SSL_OP_NO_TLSv1_2);
3199#endif /* SSL_OP_NO_TLSv1_2 */
Roshan Pius3a1667e2018-07-03 15:17:14 -07003200#ifdef SSL_OP_NO_TLSv1_3
3201 if (flags & TLS_CONN_DISABLE_TLSv1_3)
3202 SSL_set_options(ssl, SSL_OP_NO_TLSv1_3);
3203 else
3204 SSL_clear_options(ssl, SSL_OP_NO_TLSv1_3);
3205#endif /* SSL_OP_NO_TLSv1_3 */
Hai Shalom74f70d42019-02-11 14:42:39 -08003206#if OPENSSL_VERSION_NUMBER >= 0x10100000L
3207 if (flags & (TLS_CONN_ENABLE_TLSv1_0 |
3208 TLS_CONN_ENABLE_TLSv1_1 |
3209 TLS_CONN_ENABLE_TLSv1_2)) {
3210 int version = 0;
3211
3212 /* Explicit request to enable TLS versions even if needing to
3213 * override systemwide policies. */
Hai Shalom899fcc72020-10-19 14:38:18 -07003214 if (flags & TLS_CONN_ENABLE_TLSv1_0)
Hai Shalom74f70d42019-02-11 14:42:39 -08003215 version = TLS1_VERSION;
Hai Shalom899fcc72020-10-19 14:38:18 -07003216 else if (flags & TLS_CONN_ENABLE_TLSv1_1)
3217 version = TLS1_1_VERSION;
3218 else if (flags & TLS_CONN_ENABLE_TLSv1_2)
3219 version = TLS1_2_VERSION;
Hai Shalom74f70d42019-02-11 14:42:39 -08003220 if (!version) {
3221 wpa_printf(MSG_DEBUG,
3222 "OpenSSL: Invalid TLS version configuration");
3223 return -1;
3224 }
3225
3226 if (SSL_set_min_proto_version(ssl, version) != 1) {
3227 wpa_printf(MSG_DEBUG,
3228 "OpenSSL: Failed to set minimum TLS version");
3229 return -1;
3230 }
3231 }
3232#endif /* >= 1.1.0 */
Hai Shalom899fcc72020-10-19 14:38:18 -07003233#if OPENSSL_VERSION_NUMBER >= 0x10100000L && \
3234 !defined(LIBRESSL_VERSION_NUMBER) && \
3235 !defined(OPENSSL_IS_BORINGSSL)
Hai Shaloma20dcd72022-02-04 13:43:00 -08003236 {
3237#if OPENSSL_VERSION_NUMBER >= 0x30000000L
3238 int need_level = 0;
3239#else
3240 int need_level = 1;
3241#endif
3242
3243 if ((flags &
3244 (TLS_CONN_ENABLE_TLSv1_0 | TLS_CONN_ENABLE_TLSv1_1)) &&
3245 SSL_get_security_level(ssl) > need_level) {
3246 /*
3247 * Need to drop to security level 1 (or 0 with OpenSSL
3248 * 3.0) to allow TLS versions older than 1.2 to be used
3249 * when explicitly enabled in configuration.
3250 */
3251 SSL_set_security_level(conn->ssl, need_level);
3252 }
Hai Shalom899fcc72020-10-19 14:38:18 -07003253 }
3254#endif
Hai Shalom74f70d42019-02-11 14:42:39 -08003255
Sunil Ravib0ac25f2024-07-12 01:42:03 +00003256 if (!openssl_ciphers)
3257 openssl_ciphers = conn->data->openssl_ciphers;
3258
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003259#ifdef CONFIG_SUITEB
Roshan Pius3a1667e2018-07-03 15:17:14 -07003260#ifdef OPENSSL_IS_BORINGSSL
3261 /* Start with defaults from BoringSSL */
Jimmy Chen916e0a72022-01-11 15:19:46 +08003262 SSL_set_verify_algorithm_prefs(conn->ssl, NULL, 0);
Roshan Pius3a1667e2018-07-03 15:17:14 -07003263#endif /* OPENSSL_IS_BORINGSSL */
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003264 if (flags & TLS_CONN_SUITEB_NO_ECDH) {
3265 const char *ciphers = "DHE-RSA-AES256-GCM-SHA384";
3266
Roshan Pius3a1667e2018-07-03 15:17:14 -07003267 if (openssl_ciphers) {
3268 wpa_printf(MSG_DEBUG,
3269 "OpenSSL: Override ciphers for Suite B (no ECDH): %s",
3270 openssl_ciphers);
3271 ciphers = openssl_ciphers;
3272 }
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003273 if (SSL_set_cipher_list(ssl, ciphers) != 1) {
3274 wpa_printf(MSG_INFO,
3275 "OpenSSL: Failed to set Suite B ciphers");
3276 return -1;
3277 }
3278 } else if (flags & TLS_CONN_SUITEB) {
Sunil Ravia04bd252022-05-02 22:54:18 -07003279#if OPENSSL_VERSION_NUMBER < 0x30000000L
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003280 EC_KEY *ecdh;
Sunil Ravia04bd252022-05-02 22:54:18 -07003281#endif
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003282 const char *ciphers =
3283 "ECDHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES256-GCM-SHA384";
Roshan Pius3a1667e2018-07-03 15:17:14 -07003284 int nid[1] = { NID_secp384r1 };
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003285
Roshan Pius3a1667e2018-07-03 15:17:14 -07003286 if (openssl_ciphers) {
3287 wpa_printf(MSG_DEBUG,
3288 "OpenSSL: Override ciphers for Suite B: %s",
3289 openssl_ciphers);
3290 ciphers = openssl_ciphers;
3291 }
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003292 if (SSL_set_cipher_list(ssl, ciphers) != 1) {
3293 wpa_printf(MSG_INFO,
3294 "OpenSSL: Failed to set Suite B ciphers");
3295 return -1;
3296 }
3297
Sunil Ravia04bd252022-05-02 22:54:18 -07003298#if OPENSSL_VERSION_NUMBER >= 0x30000000L
3299 if (SSL_set1_groups(ssl, nid, 1) != 1) {
3300 wpa_printf(MSG_INFO,
3301 "OpenSSL: Failed to set Suite B groups");
3302 return -1;
3303 }
3304
3305#else
Roshan Pius3a1667e2018-07-03 15:17:14 -07003306 if (SSL_set1_curves(ssl, nid, 1) != 1) {
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003307 wpa_printf(MSG_INFO,
3308 "OpenSSL: Failed to set Suite B curves");
3309 return -1;
3310 }
3311
3312 ecdh = EC_KEY_new_by_curve_name(NID_secp384r1);
3313 if (!ecdh || SSL_set_tmp_ecdh(ssl, ecdh) != 1) {
3314 EC_KEY_free(ecdh);
3315 wpa_printf(MSG_INFO,
3316 "OpenSSL: Failed to set ECDH parameter");
3317 return -1;
3318 }
3319 EC_KEY_free(ecdh);
Sunil Ravia04bd252022-05-02 22:54:18 -07003320#endif
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003321 }
Hai Shalom0f94b7a2023-03-13 13:22:35 -07003322 if ((flags & (TLS_CONN_SUITEB | TLS_CONN_SUITEB_NO_ECDH))
3323#ifdef EAP_TLSV1_3
3324 && (flags & TLS_CONN_DISABLE_TLSv1_3)
3325#endif
3326 ) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07003327#ifdef OPENSSL_IS_BORINGSSL
3328 uint16_t sigalgs[1] = { SSL_SIGN_RSA_PKCS1_SHA384 };
3329
Jimmy Chen916e0a72022-01-11 15:19:46 +08003330 if (SSL_set_verify_algorithm_prefs(conn->ssl, sigalgs,
Roshan Pius3a1667e2018-07-03 15:17:14 -07003331 1) != 1) {
3332 wpa_printf(MSG_INFO,
3333 "OpenSSL: Failed to set Suite B sigalgs");
3334 return -1;
3335 }
3336#else /* OPENSSL_IS_BORINGSSL */
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003337 /* ECDSA+SHA384 if need to add EC support here */
3338 if (SSL_set1_sigalgs_list(ssl, "RSA+SHA384") != 1) {
3339 wpa_printf(MSG_INFO,
3340 "OpenSSL: Failed to set Suite B sigalgs");
3341 return -1;
3342 }
Roshan Pius3a1667e2018-07-03 15:17:14 -07003343#endif /* OPENSSL_IS_BORINGSSL */
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003344
3345 SSL_set_options(ssl, SSL_OP_NO_TLSv1);
3346 SSL_set_options(ssl, SSL_OP_NO_TLSv1_1);
3347 SSL_set_cert_cb(ssl, suiteb_cert_cb, conn);
3348 }
Roshan Pius3a1667e2018-07-03 15:17:14 -07003349
3350#ifdef OPENSSL_IS_BORINGSSL
3351 if (openssl_ciphers && os_strcmp(openssl_ciphers, "SUITEB192") == 0) {
3352 uint16_t sigalgs[1] = { SSL_SIGN_ECDSA_SECP384R1_SHA384 };
3353 int nid[1] = { NID_secp384r1 };
3354
3355 if (SSL_set1_curves(ssl, nid, 1) != 1) {
3356 wpa_printf(MSG_INFO,
3357 "OpenSSL: Failed to set Suite B curves");
3358 return -1;
3359 }
3360
Jimmy Chen916e0a72022-01-11 15:19:46 +08003361 if (SSL_set_verify_algorithm_prefs(conn->ssl, sigalgs,
Roshan Pius3a1667e2018-07-03 15:17:14 -07003362 1) != 1) {
3363 wpa_printf(MSG_INFO,
3364 "OpenSSL: Failed to set Suite B sigalgs");
3365 return -1;
3366 }
3367 }
Hai Shalom74f70d42019-02-11 14:42:39 -08003368#else /* OPENSSL_IS_BORINGSSL */
3369 if (!(flags & (TLS_CONN_SUITEB | TLS_CONN_SUITEB_NO_ECDH)) &&
3370 openssl_ciphers && SSL_set_cipher_list(ssl, openssl_ciphers) != 1) {
3371 wpa_printf(MSG_INFO,
3372 "OpenSSL: Failed to set openssl_ciphers '%s'",
3373 openssl_ciphers);
3374 return -1;
3375 }
Roshan Pius3a1667e2018-07-03 15:17:14 -07003376#endif /* OPENSSL_IS_BORINGSSL */
Hai Shalom74f70d42019-02-11 14:42:39 -08003377#else /* CONFIG_SUITEB */
3378 if (openssl_ciphers && SSL_set_cipher_list(ssl, openssl_ciphers) != 1) {
3379 wpa_printf(MSG_INFO,
3380 "OpenSSL: Failed to set openssl_ciphers '%s'",
3381 openssl_ciphers);
3382 return -1;
3383 }
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003384#endif /* CONFIG_SUITEB */
3385
Hai Shalom81f62d82019-07-22 12:10:00 -07003386 if (flags & TLS_CONN_TEAP_ANON_DH) {
3387#ifndef TEAP_DH_ANON_CS
3388#define TEAP_DH_ANON_CS \
3389 "ECDHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES128-GCM-SHA256:" \
3390 "ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES128-SHA256:" \
3391 "ECDHE-RSA-AES256-SHA:ECDHE-RSA-AES128-SHA:" \
3392 "DHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:" \
3393 "DHE-RSA-AES256-SHA256:DHE-RSA-AES128-SHA256:" \
3394 "DHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA:" \
3395 "ADH-AES256-GCM-SHA384:ADH-AES128-GCM-SHA256:" \
3396 "ADH-AES256-SHA256:ADH-AES128-SHA256:ADH-AES256-SHA:ADH-AES128-SHA"
3397#endif
3398 static const char *cs = TEAP_DH_ANON_CS;
3399
3400#if OPENSSL_VERSION_NUMBER >= 0x10100000L && \
3401 !defined(LIBRESSL_VERSION_NUMBER) && \
3402 !defined(OPENSSL_IS_BORINGSSL)
3403 /*
3404 * Need to drop to security level 0 to allow anonymous
3405 * cipher suites for EAP-TEAP.
3406 */
3407 SSL_set_security_level(conn->ssl, 0);
3408#endif
3409
3410 wpa_printf(MSG_DEBUG,
3411 "OpenSSL: Enable cipher suites for anonymous EAP-TEAP provisioning: %s",
3412 cs);
3413 if (SSL_set_cipher_list(conn->ssl, cs) != 1) {
3414 tls_show_errors(MSG_INFO, __func__,
3415 "Cipher suite configuration failed");
3416 return -1;
3417 }
3418 }
3419
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003420 return 0;
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08003421}
3422
3423
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003424int tls_connection_set_verify(void *ssl_ctx, struct tls_connection *conn,
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08003425 int verify_peer, unsigned int flags,
3426 const u8 *session_ctx, size_t session_ctx_len)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003427{
3428 static int counter = 0;
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08003429 struct tls_data *data = ssl_ctx;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003430
3431 if (conn == NULL)
3432 return -1;
3433
Hai Shalom899fcc72020-10-19 14:38:18 -07003434 if (verify_peer == 2) {
3435 conn->ca_cert_verify = 1;
3436 SSL_set_verify(conn->ssl, SSL_VERIFY_PEER |
3437 SSL_VERIFY_CLIENT_ONCE, tls_verify_cb);
3438 } else if (verify_peer) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003439 conn->ca_cert_verify = 1;
3440 SSL_set_verify(conn->ssl, SSL_VERIFY_PEER |
3441 SSL_VERIFY_FAIL_IF_NO_PEER_CERT |
3442 SSL_VERIFY_CLIENT_ONCE, tls_verify_cb);
3443 } else {
3444 conn->ca_cert_verify = 0;
3445 SSL_set_verify(conn->ssl, SSL_VERIFY_NONE, NULL);
3446 }
3447
Roshan Pius3a1667e2018-07-03 15:17:14 -07003448 if (tls_set_conn_flags(conn, flags, NULL) < 0)
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003449 return -1;
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08003450 conn->flags = flags;
3451
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003452 SSL_set_accept_state(conn->ssl);
3453
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08003454 if (data->tls_session_lifetime == 0) {
3455 /*
3456 * Set session id context to a unique value to make sure
3457 * session resumption cannot be used either through session
3458 * caching or TLS ticket extension.
3459 */
3460 counter++;
3461 SSL_set_session_id_context(conn->ssl,
3462 (const unsigned char *) &counter,
3463 sizeof(counter));
3464 } else if (session_ctx) {
3465 SSL_set_session_id_context(conn->ssl, session_ctx,
3466 session_ctx_len);
3467 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003468
3469 return 0;
3470}
3471
3472
3473static int tls_connection_client_cert(struct tls_connection *conn,
3474 const char *client_cert,
3475 const u8 *client_cert_blob,
3476 size_t client_cert_blob_len)
3477{
3478 if (client_cert == NULL && client_cert_blob == NULL)
3479 return 0;
3480
Dmitry Shmidtde47be72016-01-07 12:52:55 -08003481#ifdef PKCS12_FUNCS
Sunil Ravia04bd252022-05-02 22:54:18 -07003482#ifdef LIBRESSL_VERSION_NUMBER
Dmitry Shmidtde47be72016-01-07 12:52:55 -08003483 /*
3484 * Clear previously set extra chain certificates, if any, from PKCS#12
Sunil Ravia04bd252022-05-02 22:54:18 -07003485 * processing in tls_parse_pkcs12() to allow LibreSSL to build a new
Dmitry Shmidtde47be72016-01-07 12:52:55 -08003486 * chain properly.
3487 */
3488 SSL_CTX_clear_extra_chain_certs(conn->ssl_ctx);
Sunil Ravia04bd252022-05-02 22:54:18 -07003489#endif /* LIBRESSL_VERSION_NUMBER */
Dmitry Shmidtde47be72016-01-07 12:52:55 -08003490#endif /* PKCS12_FUNCS */
3491
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003492 if (client_cert_blob &&
3493 SSL_use_certificate_ASN1(conn->ssl, (u8 *) client_cert_blob,
3494 client_cert_blob_len) == 1) {
3495 wpa_printf(MSG_DEBUG, "OpenSSL: SSL_use_certificate_ASN1 --> "
3496 "OK");
3497 return 0;
3498 } else if (client_cert_blob) {
Hai Shalom899fcc72020-10-19 14:38:18 -07003499#if defined(LIBRESSL_VERSION_NUMBER) && LIBRESSL_VERSION_NUMBER < 0x20901000L
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003500 tls_show_errors(MSG_DEBUG, __func__,
3501 "SSL_use_certificate_ASN1 failed");
Hai Shalom899fcc72020-10-19 14:38:18 -07003502#else
3503 BIO *bio;
3504 X509 *x509;
3505
3506 tls_show_errors(MSG_DEBUG, __func__,
3507 "SSL_use_certificate_ASN1 failed");
3508 bio = BIO_new(BIO_s_mem());
3509 if (!bio)
3510 return -1;
3511 BIO_write(bio, client_cert_blob, client_cert_blob_len);
3512 x509 = PEM_read_bio_X509(bio, NULL, NULL, NULL);
3513 if (!x509 || SSL_use_certificate(conn->ssl, x509) != 1) {
3514 X509_free(x509);
3515 BIO_free(bio);
3516 return -1;
3517 }
3518 X509_free(x509);
3519 wpa_printf(MSG_DEBUG,
3520 "OpenSSL: Found PEM encoded certificate from blob");
3521 while ((x509 = PEM_read_bio_X509(bio, NULL, NULL, NULL))) {
3522 wpa_printf(MSG_DEBUG,
3523 "OpenSSL: Added an additional certificate into the chain");
3524 SSL_add0_chain_cert(conn->ssl, x509);
3525 }
3526 BIO_free(bio);
3527 return 0;
3528#endif
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003529 }
3530
3531 if (client_cert == NULL)
3532 return -1;
3533
3534#ifdef ANDROID
Hai Shalom7ad2a872021-08-02 18:56:55 -07003535 if (os_strncmp(ANDROID_KEYSTORE_PREFIX, client_cert,
3536 ANDROID_KEYSTORE_PREFIX_LEN) == 0) {
Gabriel Birenff4f8382023-04-06 20:14:39 +00003537 BIO *bio = BIO_from_keystore(&client_cert[ANDROID_KEYSTORE_PREFIX_LEN], conn);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003538 X509 *x509 = NULL;
Hai Shalom7ad2a872021-08-02 18:56:55 -07003539 if (!bio) {
3540 return -1;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003541 }
Hai Shalom7ad2a872021-08-02 18:56:55 -07003542 // Keystore returns X.509 certificates in PEM encoding
3543 x509 = PEM_read_bio_X509(bio, NULL, NULL, NULL);
3544 if (!x509 || SSL_use_certificate(conn->ssl, x509) != 1) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003545 X509_free(x509);
Hai Shalom7ad2a872021-08-02 18:56:55 -07003546 BIO_free(bio);
3547 wpa_printf(MSG_ERROR, "OpenSSL: Unknown certificate encoding");
3548 return -1;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003549 }
Hai Shalom7ad2a872021-08-02 18:56:55 -07003550 X509_free(x509);
3551 wpa_printf(MSG_DEBUG,
3552 "OpenSSL: Found PEM encoded certificate from keystore: %s",
3553 client_cert);
Paul Stewart50772e82017-01-25 13:59:16 -08003554
Hai Shalom7ad2a872021-08-02 18:56:55 -07003555 // Read additional certificates into the chain
3556 while ((x509 = PEM_read_bio_X509(bio, NULL, NULL, NULL))) {
3557 wpa_printf(MSG_DEBUG,
3558 "OpenSSL: Added an additional certificate into the chain");
3559 // Takes ownership of x509, no need to free it here
3560 SSL_add0_chain_cert(conn->ssl, x509);
Paul Stewart50772e82017-01-25 13:59:16 -08003561 }
Hai Shalom7ad2a872021-08-02 18:56:55 -07003562 BIO_free(bio);
3563 return 0;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003564 }
3565#endif /* ANDROID */
3566
3567#ifndef OPENSSL_NO_STDIO
3568 if (SSL_use_certificate_file(conn->ssl, client_cert,
3569 SSL_FILETYPE_ASN1) == 1) {
3570 wpa_printf(MSG_DEBUG, "OpenSSL: SSL_use_certificate_file (DER)"
3571 " --> OK");
3572 return 0;
3573 }
3574
Hai Shalom021b0b52019-04-10 11:17:58 -07003575#if OPENSSL_VERSION_NUMBER >= 0x10100000L && \
3576 !defined(LIBRESSL_VERSION_NUMBER) && !defined(OPENSSL_IS_BORINGSSL)
Hai Shalom74f70d42019-02-11 14:42:39 -08003577 if (SSL_use_certificate_chain_file(conn->ssl, client_cert) == 1) {
3578 ERR_clear_error();
3579 wpa_printf(MSG_DEBUG, "OpenSSL: SSL_use_certificate_chain_file"
3580 " --> OK");
3581 return 0;
3582 }
3583#else
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003584 if (SSL_use_certificate_file(conn->ssl, client_cert,
3585 SSL_FILETYPE_PEM) == 1) {
3586 ERR_clear_error();
3587 wpa_printf(MSG_DEBUG, "OpenSSL: SSL_use_certificate_file (PEM)"
3588 " --> OK");
3589 return 0;
3590 }
Hai Shalom74f70d42019-02-11 14:42:39 -08003591#endif
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003592
3593 tls_show_errors(MSG_DEBUG, __func__,
3594 "SSL_use_certificate_file failed");
3595#else /* OPENSSL_NO_STDIO */
3596 wpa_printf(MSG_DEBUG, "OpenSSL: %s - OPENSSL_NO_STDIO", __func__);
3597#endif /* OPENSSL_NO_STDIO */
3598
3599 return -1;
3600}
3601
3602
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08003603static int tls_global_client_cert(struct tls_data *data,
3604 const char *client_cert)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003605{
3606#ifndef OPENSSL_NO_STDIO
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08003607 SSL_CTX *ssl_ctx = data->ssl;
3608
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003609 if (client_cert == NULL)
3610 return 0;
3611
3612 if (SSL_CTX_use_certificate_file(ssl_ctx, client_cert,
3613 SSL_FILETYPE_ASN1) != 1 &&
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08003614 SSL_CTX_use_certificate_chain_file(ssl_ctx, client_cert) != 1 &&
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003615 SSL_CTX_use_certificate_file(ssl_ctx, client_cert,
3616 SSL_FILETYPE_PEM) != 1) {
3617 tls_show_errors(MSG_INFO, __func__,
3618 "Failed to load client certificate");
3619 return -1;
3620 }
3621 return 0;
3622#else /* OPENSSL_NO_STDIO */
3623 if (client_cert == NULL)
3624 return 0;
3625 wpa_printf(MSG_DEBUG, "OpenSSL: %s - OPENSSL_NO_STDIO", __func__);
3626 return -1;
3627#endif /* OPENSSL_NO_STDIO */
3628}
3629
3630
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003631#ifdef PKCS12_FUNCS
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08003632static int tls_parse_pkcs12(struct tls_data *data, SSL *ssl, PKCS12 *p12,
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003633 const char *passwd)
3634{
3635 EVP_PKEY *pkey;
3636 X509 *cert;
3637 STACK_OF(X509) *certs;
3638 int res = 0;
3639 char buf[256];
3640
3641 pkey = NULL;
3642 cert = NULL;
3643 certs = NULL;
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08003644 if (!passwd)
3645 passwd = "";
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003646 if (!PKCS12_parse(p12, passwd, &pkey, &cert, &certs)) {
3647 tls_show_errors(MSG_DEBUG, __func__,
3648 "Failed to parse PKCS12 file");
3649 PKCS12_free(p12);
3650 return -1;
3651 }
3652 wpa_printf(MSG_DEBUG, "TLS: Successfully parsed PKCS12 data");
3653
3654 if (cert) {
3655 X509_NAME_oneline(X509_get_subject_name(cert), buf,
3656 sizeof(buf));
3657 wpa_printf(MSG_DEBUG, "TLS: Got certificate from PKCS12: "
3658 "subject='%s'", buf);
3659 if (ssl) {
3660 if (SSL_use_certificate(ssl, cert) != 1)
3661 res = -1;
3662 } else {
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08003663 if (SSL_CTX_use_certificate(data->ssl, cert) != 1)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003664 res = -1;
3665 }
3666 X509_free(cert);
3667 }
3668
3669 if (pkey) {
3670 wpa_printf(MSG_DEBUG, "TLS: Got private key from PKCS12");
3671 if (ssl) {
3672 if (SSL_use_PrivateKey(ssl, pkey) != 1)
3673 res = -1;
3674 } else {
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08003675 if (SSL_CTX_use_PrivateKey(data->ssl, pkey) != 1)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003676 res = -1;
3677 }
3678 EVP_PKEY_free(pkey);
3679 }
3680
3681 if (certs) {
Sunil Ravia04bd252022-05-02 22:54:18 -07003682#ifndef LIBRESSL_VERSION_NUMBER
Dmitry Shmidtb97e4282016-02-08 10:16:07 -08003683 if (ssl)
3684 SSL_clear_chain_certs(ssl);
3685 else
3686 SSL_CTX_clear_chain_certs(data->ssl);
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08003687 while ((cert = sk_X509_pop(certs)) != NULL) {
3688 X509_NAME_oneline(X509_get_subject_name(cert), buf,
3689 sizeof(buf));
3690 wpa_printf(MSG_DEBUG, "TLS: additional certificate"
3691 " from PKCS12: subject='%s'", buf);
Dmitry Shmidtb97e4282016-02-08 10:16:07 -08003692 if ((ssl && SSL_add1_chain_cert(ssl, cert) != 1) ||
3693 (!ssl && SSL_CTX_add1_chain_cert(data->ssl,
3694 cert) != 1)) {
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08003695 tls_show_errors(MSG_DEBUG, __func__,
3696 "Failed to add additional certificate");
3697 res = -1;
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08003698 X509_free(cert);
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08003699 break;
3700 }
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08003701 X509_free(cert);
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08003702 }
3703 if (!res) {
3704 /* Try to continue anyway */
3705 }
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08003706 sk_X509_pop_free(certs, X509_free);
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08003707#ifndef OPENSSL_IS_BORINGSSL
Dmitry Shmidtb97e4282016-02-08 10:16:07 -08003708 if (ssl)
3709 res = SSL_build_cert_chain(
3710 ssl,
3711 SSL_BUILD_CHAIN_FLAG_CHECK |
3712 SSL_BUILD_CHAIN_FLAG_IGNORE_ERROR);
3713 else
3714 res = SSL_CTX_build_cert_chain(
3715 data->ssl,
3716 SSL_BUILD_CHAIN_FLAG_CHECK |
3717 SSL_BUILD_CHAIN_FLAG_IGNORE_ERROR);
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08003718 if (!res) {
3719 tls_show_errors(MSG_DEBUG, __func__,
3720 "Failed to build certificate chain");
3721 } else if (res == 2) {
3722 wpa_printf(MSG_DEBUG,
3723 "TLS: Ignore certificate chain verification error when building chain with PKCS#12 extra certificates");
3724 }
3725#endif /* OPENSSL_IS_BORINGSSL */
3726 /*
3727 * Try to continue regardless of result since it is possible for
3728 * the extra certificates not to be required.
3729 */
3730 res = 0;
Sunil Ravia04bd252022-05-02 22:54:18 -07003731#else /* LIBRESSL_VERSION_NUMBER */
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08003732 SSL_CTX_clear_extra_chain_certs(data->ssl);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003733 while ((cert = sk_X509_pop(certs)) != NULL) {
3734 X509_NAME_oneline(X509_get_subject_name(cert), buf,
3735 sizeof(buf));
3736 wpa_printf(MSG_DEBUG, "TLS: additional certificate"
3737 " from PKCS12: subject='%s'", buf);
3738 /*
3739 * There is no SSL equivalent for the chain cert - so
3740 * always add it to the context...
3741 */
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08003742 if (SSL_CTX_add_extra_chain_cert(data->ssl, cert) != 1)
3743 {
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08003744 X509_free(cert);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003745 res = -1;
3746 break;
3747 }
3748 }
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08003749 sk_X509_pop_free(certs, X509_free);
Sunil Ravia04bd252022-05-02 22:54:18 -07003750#endif /* LIBRSESSL_VERSION_NUMBER */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003751 }
3752
3753 PKCS12_free(p12);
3754
3755 if (res < 0)
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08003756 tls_get_errors(data);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003757
3758 return res;
3759}
3760#endif /* PKCS12_FUNCS */
3761
3762
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08003763static int tls_read_pkcs12(struct tls_data *data, SSL *ssl,
3764 const char *private_key, const char *passwd)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003765{
3766#ifdef PKCS12_FUNCS
3767 FILE *f;
3768 PKCS12 *p12;
3769
3770 f = fopen(private_key, "rb");
3771 if (f == NULL)
3772 return -1;
3773
3774 p12 = d2i_PKCS12_fp(f, NULL);
3775 fclose(f);
3776
3777 if (p12 == NULL) {
3778 tls_show_errors(MSG_INFO, __func__,
3779 "Failed to use PKCS#12 file");
3780 return -1;
3781 }
3782
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08003783 return tls_parse_pkcs12(data, ssl, p12, passwd);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003784
3785#else /* PKCS12_FUNCS */
3786 wpa_printf(MSG_INFO, "TLS: PKCS12 support disabled - cannot read "
3787 "p12/pfx files");
3788 return -1;
3789#endif /* PKCS12_FUNCS */
3790}
3791
3792
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08003793static int tls_read_pkcs12_blob(struct tls_data *data, SSL *ssl,
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003794 const u8 *blob, size_t len, const char *passwd)
3795{
3796#ifdef PKCS12_FUNCS
3797 PKCS12 *p12;
3798
Dmitry Shmidt216983b2015-02-06 10:50:36 -08003799 p12 = d2i_PKCS12(NULL, (const unsigned char **) &blob, len);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003800 if (p12 == NULL) {
3801 tls_show_errors(MSG_INFO, __func__,
3802 "Failed to use PKCS#12 blob");
3803 return -1;
3804 }
3805
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08003806 return tls_parse_pkcs12(data, ssl, p12, passwd);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003807
3808#else /* PKCS12_FUNCS */
3809 wpa_printf(MSG_INFO, "TLS: PKCS12 support disabled - cannot parse "
3810 "p12/pfx blobs");
3811 return -1;
3812#endif /* PKCS12_FUNCS */
3813}
3814
3815
3816#ifndef OPENSSL_NO_ENGINE
3817static int tls_engine_get_cert(struct tls_connection *conn,
3818 const char *cert_id,
3819 X509 **cert)
3820{
3821 /* this runs after the private key is loaded so no PIN is required */
3822 struct {
3823 const char *cert_id;
3824 X509 *cert;
3825 } params;
3826 params.cert_id = cert_id;
3827 params.cert = NULL;
3828
3829 if (!ENGINE_ctrl_cmd(conn->engine, "LOAD_CERT_CTRL",
3830 0, &params, NULL, 1)) {
Dmitry Shmidt1d755d02015-04-28 10:34:29 -07003831 unsigned long err = ERR_get_error();
3832
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003833 wpa_printf(MSG_ERROR, "ENGINE: cannot load client cert with id"
3834 " '%s' [%s]", cert_id,
Dmitry Shmidt1d755d02015-04-28 10:34:29 -07003835 ERR_error_string(err, NULL));
3836 if (tls_is_pin_error(err))
3837 return TLS_SET_PARAMS_ENGINE_PRV_BAD_PIN;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003838 return TLS_SET_PARAMS_ENGINE_PRV_INIT_FAILED;
3839 }
3840 if (!params.cert) {
3841 wpa_printf(MSG_ERROR, "ENGINE: did not properly cert with id"
3842 " '%s'", cert_id);
3843 return TLS_SET_PARAMS_ENGINE_PRV_INIT_FAILED;
3844 }
3845 *cert = params.cert;
3846 return 0;
3847}
3848#endif /* OPENSSL_NO_ENGINE */
3849
3850
3851static int tls_connection_engine_client_cert(struct tls_connection *conn,
3852 const char *cert_id)
3853{
3854#ifndef OPENSSL_NO_ENGINE
3855 X509 *cert;
3856
3857 if (tls_engine_get_cert(conn, cert_id, &cert))
3858 return -1;
3859
3860 if (!SSL_use_certificate(conn->ssl, cert)) {
3861 tls_show_errors(MSG_ERROR, __func__,
3862 "SSL_use_certificate failed");
3863 X509_free(cert);
3864 return -1;
3865 }
3866 X509_free(cert);
3867 wpa_printf(MSG_DEBUG, "ENGINE: SSL_use_certificate --> "
3868 "OK");
3869 return 0;
3870
3871#else /* OPENSSL_NO_ENGINE */
3872 return -1;
3873#endif /* OPENSSL_NO_ENGINE */
3874}
3875
3876
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08003877static int tls_connection_engine_ca_cert(struct tls_data *data,
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003878 struct tls_connection *conn,
3879 const char *ca_cert_id)
3880{
3881#ifndef OPENSSL_NO_ENGINE
3882 X509 *cert;
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08003883 SSL_CTX *ssl_ctx = data->ssl;
Dmitry Shmidt216983b2015-02-06 10:50:36 -08003884 X509_STORE *store;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003885
3886 if (tls_engine_get_cert(conn, ca_cert_id, &cert))
3887 return -1;
3888
3889 /* start off the same as tls_connection_ca_cert */
Dmitry Shmidt216983b2015-02-06 10:50:36 -08003890 store = X509_STORE_new();
3891 if (store == NULL) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003892 wpa_printf(MSG_DEBUG, "OpenSSL: %s - failed to allocate new "
3893 "certificate store", __func__);
3894 X509_free(cert);
3895 return -1;
3896 }
Dmitry Shmidt216983b2015-02-06 10:50:36 -08003897 SSL_CTX_set_cert_store(ssl_ctx, store);
3898 if (!X509_STORE_add_cert(store, cert)) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003899 unsigned long err = ERR_peek_error();
3900 tls_show_errors(MSG_WARNING, __func__,
3901 "Failed to add CA certificate from engine "
3902 "to certificate store");
3903 if (ERR_GET_LIB(err) == ERR_LIB_X509 &&
3904 ERR_GET_REASON(err) == X509_R_CERT_ALREADY_IN_HASH_TABLE) {
3905 wpa_printf(MSG_DEBUG, "OpenSSL: %s - ignoring cert"
3906 " already in hash table error",
3907 __func__);
3908 } else {
3909 X509_free(cert);
3910 return -1;
3911 }
3912 }
3913 X509_free(cert);
3914 wpa_printf(MSG_DEBUG, "OpenSSL: %s - added CA certificate from engine "
3915 "to certificate store", __func__);
3916 SSL_set_verify(conn->ssl, SSL_VERIFY_PEER, tls_verify_cb);
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07003917 conn->ca_cert_verify = 1;
3918
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003919 return 0;
3920
3921#else /* OPENSSL_NO_ENGINE */
3922 return -1;
3923#endif /* OPENSSL_NO_ENGINE */
3924}
3925
3926
3927static int tls_connection_engine_private_key(struct tls_connection *conn)
3928{
Adam Langley1eb02ed2015-04-21 19:00:05 -07003929#if defined(ANDROID) || !defined(OPENSSL_NO_ENGINE)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003930 if (SSL_use_PrivateKey(conn->ssl, conn->private_key) != 1) {
3931 tls_show_errors(MSG_ERROR, __func__,
3932 "ENGINE: cannot use private key for TLS");
3933 return -1;
3934 }
3935 if (!SSL_check_private_key(conn->ssl)) {
3936 tls_show_errors(MSG_INFO, __func__,
3937 "Private key failed verification");
3938 return -1;
3939 }
3940 return 0;
3941#else /* OPENSSL_NO_ENGINE */
3942 wpa_printf(MSG_ERROR, "SSL: Configuration uses engine, but "
3943 "engine support was not compiled in");
3944 return -1;
3945#endif /* OPENSSL_NO_ENGINE */
3946}
3947
3948
Roshan Pius3a1667e2018-07-03 15:17:14 -07003949#ifndef OPENSSL_NO_STDIO
3950static int tls_passwd_cb(char *buf, int size, int rwflag, void *password)
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003951{
Roshan Pius3a1667e2018-07-03 15:17:14 -07003952 if (!password)
3953 return 0;
3954 os_strlcpy(buf, (const char *) password, size);
3955 return os_strlen(buf);
3956}
3957#endif /* OPENSSL_NO_STDIO */
3958
3959
3960static int tls_use_private_key_file(struct tls_data *data, SSL *ssl,
3961 const char *private_key,
3962 const char *private_key_passwd)
3963{
3964#ifndef OPENSSL_NO_STDIO
3965 BIO *bio;
3966 EVP_PKEY *pkey;
3967 int ret;
3968
3969 /* First try ASN.1 (DER). */
3970 bio = BIO_new_file(private_key, "r");
3971 if (!bio)
3972 return -1;
3973 pkey = d2i_PrivateKey_bio(bio, NULL);
3974 BIO_free(bio);
3975
3976 if (pkey) {
3977 wpa_printf(MSG_DEBUG, "OpenSSL: %s (DER) --> loaded", __func__);
3978 } else {
3979 /* Try PEM with the provided password. */
3980 bio = BIO_new_file(private_key, "r");
3981 if (!bio)
3982 return -1;
3983 pkey = PEM_read_bio_PrivateKey(bio, NULL, tls_passwd_cb,
3984 (void *) private_key_passwd);
3985 BIO_free(bio);
3986 if (!pkey)
3987 return -1;
3988 wpa_printf(MSG_DEBUG, "OpenSSL: %s (PEM) --> loaded", __func__);
3989 /* Clear errors from the previous failed load. */
3990 ERR_clear_error();
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003991 }
Roshan Pius3a1667e2018-07-03 15:17:14 -07003992
3993 if (ssl)
3994 ret = SSL_use_PrivateKey(ssl, pkey);
3995 else
3996 ret = SSL_CTX_use_PrivateKey(data->ssl, pkey);
3997
3998 EVP_PKEY_free(pkey);
3999 return ret == 1 ? 0 : -1;
4000#else /* OPENSSL_NO_STDIO */
4001 wpa_printf(MSG_DEBUG, "OpenSSL: %s - OPENSSL_NO_STDIO", __func__);
4002 return -1;
4003#endif /* OPENSSL_NO_STDIO */
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004004}
4005
4006
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08004007static int tls_connection_private_key(struct tls_data *data,
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004008 struct tls_connection *conn,
4009 const char *private_key,
4010 const char *private_key_passwd,
4011 const u8 *private_key_blob,
4012 size_t private_key_blob_len)
4013{
Hai Shaloma20dcd72022-02-04 13:43:00 -08004014 BIO *bio;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004015 int ok;
4016
4017 if (private_key == NULL && private_key_blob == NULL)
4018 return 0;
4019
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004020 ok = 0;
4021 while (private_key_blob) {
4022 if (SSL_use_PrivateKey_ASN1(EVP_PKEY_RSA, conn->ssl,
4023 (u8 *) private_key_blob,
4024 private_key_blob_len) == 1) {
4025 wpa_printf(MSG_DEBUG, "OpenSSL: SSL_use_PrivateKey_"
4026 "ASN1(EVP_PKEY_RSA) --> OK");
4027 ok = 1;
4028 break;
4029 }
4030
4031 if (SSL_use_PrivateKey_ASN1(EVP_PKEY_DSA, conn->ssl,
4032 (u8 *) private_key_blob,
4033 private_key_blob_len) == 1) {
4034 wpa_printf(MSG_DEBUG, "OpenSSL: SSL_use_PrivateKey_"
4035 "ASN1(EVP_PKEY_DSA) --> OK");
4036 ok = 1;
4037 break;
4038 }
4039
Hai Shalom899fcc72020-10-19 14:38:18 -07004040#ifndef OPENSSL_NO_EC
4041 if (SSL_use_PrivateKey_ASN1(EVP_PKEY_EC, conn->ssl,
4042 (u8 *) private_key_blob,
4043 private_key_blob_len) == 1) {
4044 wpa_printf(MSG_DEBUG,
4045 "OpenSSL: SSL_use_PrivateKey_ASN1(EVP_PKEY_EC) --> OK");
4046 ok = 1;
4047 break;
4048 }
4049#endif /* OPENSSL_NO_EC */
4050
Sunil Ravia04bd252022-05-02 22:54:18 -07004051#if OPENSSL_VERSION_NUMBER < 0x30000000L
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004052 if (SSL_use_RSAPrivateKey_ASN1(conn->ssl,
4053 (u8 *) private_key_blob,
4054 private_key_blob_len) == 1) {
4055 wpa_printf(MSG_DEBUG, "OpenSSL: "
4056 "SSL_use_RSAPrivateKey_ASN1 --> OK");
4057 ok = 1;
4058 break;
4059 }
Sunil Ravia04bd252022-05-02 22:54:18 -07004060#endif
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004061
Hai Shaloma20dcd72022-02-04 13:43:00 -08004062 bio = BIO_new_mem_buf((u8 *) private_key_blob,
4063 private_key_blob_len);
4064 if (bio) {
4065 EVP_PKEY *pkey;
4066
4067 pkey = PEM_read_bio_PrivateKey(
4068 bio, NULL, tls_passwd_cb,
4069 (void *) private_key_passwd);
4070 if (pkey) {
4071 if (SSL_use_PrivateKey(conn->ssl, pkey) == 1) {
4072 wpa_printf(MSG_DEBUG,
4073 "OpenSSL: SSL_use_PrivateKey --> OK");
4074 ok = 1;
4075 EVP_PKEY_free(pkey);
4076 BIO_free(bio);
4077 break;
4078 }
4079 EVP_PKEY_free(pkey);
4080 }
4081 BIO_free(bio);
4082 }
4083
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08004084 if (tls_read_pkcs12_blob(data, conn->ssl, private_key_blob,
Roshan Pius3a1667e2018-07-03 15:17:14 -07004085 private_key_blob_len,
4086 private_key_passwd) == 0) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004087 wpa_printf(MSG_DEBUG, "OpenSSL: PKCS#12 as blob --> "
4088 "OK");
4089 ok = 1;
4090 break;
4091 }
4092
4093 break;
4094 }
4095
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004096 while (!ok && private_key) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07004097 if (tls_use_private_key_file(data, conn->ssl, private_key,
4098 private_key_passwd) == 0) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004099 ok = 1;
4100 break;
4101 }
4102
Roshan Pius3a1667e2018-07-03 15:17:14 -07004103 if (tls_read_pkcs12(data, conn->ssl, private_key,
4104 private_key_passwd) == 0) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004105 wpa_printf(MSG_DEBUG, "OpenSSL: Reading PKCS#12 file "
4106 "--> OK");
4107 ok = 1;
4108 break;
4109 }
4110
4111 if (tls_cryptoapi_cert(conn->ssl, private_key) == 0) {
4112 wpa_printf(MSG_DEBUG, "OpenSSL: Using CryptoAPI to "
4113 "access certificate store --> OK");
4114 ok = 1;
4115 break;
4116 }
4117
4118 break;
4119 }
4120
4121 if (!ok) {
4122 tls_show_errors(MSG_INFO, __func__,
4123 "Failed to load private key");
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004124 return -1;
4125 }
4126 ERR_clear_error();
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07004127
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004128 if (!SSL_check_private_key(conn->ssl)) {
4129 tls_show_errors(MSG_INFO, __func__, "Private key failed "
4130 "verification");
4131 return -1;
4132 }
4133
4134 wpa_printf(MSG_DEBUG, "SSL: Private key loaded successfully");
4135 return 0;
4136}
4137
4138
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08004139static int tls_global_private_key(struct tls_data *data,
4140 const char *private_key,
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004141 const char *private_key_passwd)
4142{
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08004143 SSL_CTX *ssl_ctx = data->ssl;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004144
4145 if (private_key == NULL)
4146 return 0;
4147
Roshan Pius3a1667e2018-07-03 15:17:14 -07004148 if (tls_use_private_key_file(data, NULL, private_key,
4149 private_key_passwd) &&
4150 tls_read_pkcs12(data, NULL, private_key, private_key_passwd)) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004151 tls_show_errors(MSG_INFO, __func__,
4152 "Failed to load private key");
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004153 ERR_clear_error();
4154 return -1;
4155 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004156 ERR_clear_error();
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07004157
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004158 if (!SSL_CTX_check_private_key(ssl_ctx)) {
4159 tls_show_errors(MSG_INFO, __func__,
4160 "Private key failed verification");
4161 return -1;
4162 }
4163
4164 return 0;
4165}
4166
4167
Sunil Ravia04bd252022-05-02 22:54:18 -07004168#if OPENSSL_VERSION_NUMBER >= 0x30000000L
4169#ifndef OPENSSL_NO_DH
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004170#ifndef OPENSSL_NO_DSA
Sunil Ravia04bd252022-05-02 22:54:18 -07004171/* This is needed to replace the deprecated DSA_dup_DH() function */
4172static EVP_PKEY * openssl_dsa_to_dh(EVP_PKEY *dsa)
4173{
4174 OSSL_PARAM_BLD *bld = NULL;
4175 OSSL_PARAM *params = NULL;
4176 BIGNUM *p = NULL, *q = NULL, *g = NULL;
4177 EVP_PKEY_CTX *ctx = NULL;
4178 EVP_PKEY *pkey = NULL;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004179
Sunil Ravia04bd252022-05-02 22:54:18 -07004180 if (!EVP_PKEY_get_bn_param(dsa, OSSL_PKEY_PARAM_FFC_P, &p) ||
4181 !EVP_PKEY_get_bn_param(dsa, OSSL_PKEY_PARAM_FFC_Q, &q) ||
4182 !EVP_PKEY_get_bn_param(dsa, OSSL_PKEY_PARAM_FFC_G, &g) ||
4183 !(bld = OSSL_PARAM_BLD_new()) ||
4184 !OSSL_PARAM_BLD_push_BN(bld, OSSL_PKEY_PARAM_FFC_P, p) ||
4185 !OSSL_PARAM_BLD_push_BN(bld, OSSL_PKEY_PARAM_FFC_Q, q) ||
4186 !OSSL_PARAM_BLD_push_BN(bld, OSSL_PKEY_PARAM_FFC_G, g) ||
4187 !(params = OSSL_PARAM_BLD_to_param(bld)) ||
4188 !(ctx = EVP_PKEY_CTX_new_from_name(NULL, "DHX", NULL)) ||
4189 EVP_PKEY_fromdata_init(ctx) != 1 ||
4190 EVP_PKEY_fromdata(ctx, &pkey, EVP_PKEY_KEY_PARAMETERS,
4191 params) != 1)
4192 wpa_printf(MSG_INFO,
4193 "TLS: Failed to convert DSA parameters to DH parameters");
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004194
Sunil Ravia04bd252022-05-02 22:54:18 -07004195 EVP_PKEY_CTX_free(ctx);
4196 OSSL_PARAM_free(params);
4197 OSSL_PARAM_BLD_free(bld);
4198 BN_free(p);
4199 BN_free(q);
4200 BN_free(g);
4201 return pkey;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004202}
Sunil Ravia04bd252022-05-02 22:54:18 -07004203#endif /* !OPENSSL_NO_DSA */
4204#endif /* OPENSSL_NO_DH */
4205#endif /* OpenSSL version >= 3.0 */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004206
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08004207static int tls_global_dh(struct tls_data *data, const char *dh_file)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004208{
4209#ifdef OPENSSL_NO_DH
4210 if (dh_file == NULL)
4211 return 0;
4212 wpa_printf(MSG_ERROR, "TLS: openssl does not include DH support, but "
4213 "dh_file specified");
4214 return -1;
4215#else /* OPENSSL_NO_DH */
Sunil Ravia04bd252022-05-02 22:54:18 -07004216#if OPENSSL_VERSION_NUMBER >= 0x30000000L
4217 SSL_CTX *ssl_ctx = data->ssl;
4218 BIO *bio;
4219 OSSL_DECODER_CTX *ctx = NULL;
4220 EVP_PKEY *pkey = NULL, *tmpkey = NULL;
4221 bool dsa = false;
4222
4223 if (!ssl_ctx)
4224 return -1;
4225 if (!dh_file) {
4226 SSL_CTX_set_dh_auto(ssl_ctx, 1);
4227 return 0;
4228 }
4229
4230 bio = BIO_new_file(dh_file, "r");
4231 if (!bio) {
4232 wpa_printf(MSG_INFO, "TLS: Failed to open DH file '%s': %s",
4233 dh_file, ERR_error_string(ERR_get_error(), NULL));
4234 return -1;
4235 }
4236 ctx = OSSL_DECODER_CTX_new_for_pkey(
4237 &tmpkey, "PEM", NULL, NULL,
4238 OSSL_KEYMGMT_SELECT_DOMAIN_PARAMETERS, NULL, NULL);
4239 if (!ctx ||
4240 OSSL_DECODER_from_bio(ctx, bio) != 1) {
4241 wpa_printf(MSG_INFO,
4242 "TLS: Failed to decode domain parameters from '%s': %s",
4243 dh_file, ERR_error_string(ERR_get_error(), NULL));
4244 BIO_free(bio);
Sunil8cd6f4d2022-06-28 18:40:46 +00004245 OSSL_DECODER_CTX_free(ctx);
Sunil Ravia04bd252022-05-02 22:54:18 -07004246 return -1;
4247 }
Sunil8cd6f4d2022-06-28 18:40:46 +00004248 OSSL_DECODER_CTX_free(ctx);
Sunil Ravia04bd252022-05-02 22:54:18 -07004249 BIO_free(bio);
4250
4251 if (!tmpkey) {
4252 wpa_printf(MSG_INFO, "TLS: Failed to load domain parameters");
4253 return -1;
4254 }
4255
4256#ifndef OPENSSL_NO_DSA
4257 if (EVP_PKEY_is_a(tmpkey, "DSA")) {
4258 pkey = openssl_dsa_to_dh(tmpkey);
4259 EVP_PKEY_free(tmpkey);
4260 if (!pkey)
4261 return -1;
4262 dsa = true;
4263 }
4264#endif /* !OPENSSL_NO_DSA */
4265 if (!dsa) {
4266 if (EVP_PKEY_is_a(tmpkey, "DH") ||
4267 EVP_PKEY_is_a(tmpkey, "DHX")) {
4268 } else {
4269 wpa_printf(MSG_INFO,
4270 "TLS: No DH parameters found in %s",
4271 dh_file);
4272 EVP_PKEY_free(tmpkey);
4273 return -1;
4274 }
4275 pkey = tmpkey;
4276 tmpkey = NULL;
4277 }
4278
4279 if (SSL_CTX_set0_tmp_dh_pkey(ssl_ctx, pkey) != 1) {
4280 wpa_printf(MSG_INFO,
4281 "TLS: Failed to set DH params from '%s': %s",
4282 dh_file, ERR_error_string(ERR_get_error(), NULL));
4283 EVP_PKEY_free(pkey);
4284 return -1;
4285 }
4286 return 0;
4287#else /* OpenSSL version >= 3.0 */
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08004288 SSL_CTX *ssl_ctx = data->ssl;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004289 DH *dh;
4290 BIO *bio;
4291
Sunil Ravia04bd252022-05-02 22:54:18 -07004292 if (!ssl_ctx)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004293 return -1;
Sunil Ravia04bd252022-05-02 22:54:18 -07004294 if (!dh_file) {
4295#if OPENSSL_VERSION_NUMBER >= 0x10100000L && !defined(OPENSSL_IS_BORINGSSL)
4296 SSL_CTX_set_dh_auto(ssl_ctx, 1);
4297#endif
4298 return 0;
4299 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004300
4301 bio = BIO_new_file(dh_file, "r");
4302 if (bio == NULL) {
4303 wpa_printf(MSG_INFO, "TLS: Failed to open DH file '%s': %s",
4304 dh_file, ERR_error_string(ERR_get_error(), NULL));
4305 return -1;
4306 }
4307 dh = PEM_read_bio_DHparams(bio, NULL, NULL, NULL);
4308 BIO_free(bio);
4309#ifndef OPENSSL_NO_DSA
4310 while (dh == NULL) {
4311 DSA *dsa;
4312 wpa_printf(MSG_DEBUG, "TLS: Failed to parse DH file '%s': %s -"
4313 " trying to parse as DSA params", dh_file,
4314 ERR_error_string(ERR_get_error(), NULL));
4315 bio = BIO_new_file(dh_file, "r");
4316 if (bio == NULL)
4317 break;
4318 dsa = PEM_read_bio_DSAparams(bio, NULL, NULL, NULL);
4319 BIO_free(bio);
4320 if (!dsa) {
4321 wpa_printf(MSG_DEBUG, "TLS: Failed to parse DSA file "
4322 "'%s': %s", dh_file,
4323 ERR_error_string(ERR_get_error(), NULL));
4324 break;
4325 }
4326
4327 wpa_printf(MSG_DEBUG, "TLS: DH file in DSA param format");
4328 dh = DSA_dup_DH(dsa);
4329 DSA_free(dsa);
4330 if (dh == NULL) {
4331 wpa_printf(MSG_INFO, "TLS: Failed to convert DSA "
4332 "params into DH params");
4333 break;
4334 }
4335 break;
4336 }
4337#endif /* !OPENSSL_NO_DSA */
4338 if (dh == NULL) {
4339 wpa_printf(MSG_INFO, "TLS: Failed to read/parse DH/DSA file "
4340 "'%s'", dh_file);
4341 return -1;
4342 }
4343
4344 if (SSL_CTX_set_tmp_dh(ssl_ctx, dh) != 1) {
4345 wpa_printf(MSG_INFO, "TLS: Failed to set DH params from '%s': "
4346 "%s", dh_file,
4347 ERR_error_string(ERR_get_error(), NULL));
4348 DH_free(dh);
4349 return -1;
4350 }
4351 DH_free(dh);
4352 return 0;
Sunil Ravia04bd252022-05-02 22:54:18 -07004353#endif /* OpenSSL version >= 3.0 */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004354#endif /* OPENSSL_NO_DH */
4355}
4356
4357
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08004358int tls_connection_get_random(void *ssl_ctx, struct tls_connection *conn,
4359 struct tls_random *keys)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004360{
4361 SSL *ssl;
4362
4363 if (conn == NULL || keys == NULL)
4364 return -1;
4365 ssl = conn->ssl;
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08004366 if (ssl == NULL)
4367 return -1;
4368
4369 os_memset(keys, 0, sizeof(*keys));
4370 keys->client_random = conn->client_random;
4371 keys->client_random_len = SSL_get_client_random(
4372 ssl, conn->client_random, sizeof(conn->client_random));
4373 keys->server_random = conn->server_random;
4374 keys->server_random_len = SSL_get_server_random(
4375 ssl, conn->server_random, sizeof(conn->server_random));
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004376
4377 return 0;
4378}
4379
4380
Dmitry Shmidt849734c2016-05-27 09:59:01 -07004381#ifdef OPENSSL_NEED_EAP_FAST_PRF
Dmitry Shmidtaf9da312015-04-03 10:03:11 -07004382static int openssl_get_keyblock_size(SSL *ssl)
4383{
Sunil Ravia04bd252022-05-02 22:54:18 -07004384#if OPENSSL_VERSION_NUMBER < 0x10100000L
Dmitry Shmidtaf9da312015-04-03 10:03:11 -07004385 const EVP_CIPHER *c;
4386 const EVP_MD *h;
4387 int md_size;
4388
4389 if (ssl->enc_read_ctx == NULL || ssl->enc_read_ctx->cipher == NULL ||
4390 ssl->read_hash == NULL)
4391 return -1;
4392
4393 c = ssl->enc_read_ctx->cipher;
Dmitry Shmidtaf9da312015-04-03 10:03:11 -07004394 h = EVP_MD_CTX_md(ssl->read_hash);
Dmitry Shmidtaf9da312015-04-03 10:03:11 -07004395 if (h)
4396 md_size = EVP_MD_size(h);
Dmitry Shmidtaf9da312015-04-03 10:03:11 -07004397 else if (ssl->s3)
4398 md_size = ssl->s3->tmp.new_mac_secret_size;
Dmitry Shmidtaf9da312015-04-03 10:03:11 -07004399 else
4400 return -1;
4401
4402 wpa_printf(MSG_DEBUG, "OpenSSL: keyblock size: key_len=%d MD_size=%d "
4403 "IV_len=%d", EVP_CIPHER_key_length(c), md_size,
4404 EVP_CIPHER_iv_length(c));
4405 return 2 * (EVP_CIPHER_key_length(c) +
4406 md_size +
4407 EVP_CIPHER_iv_length(c));
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08004408#else
4409 const SSL_CIPHER *ssl_cipher;
4410 int cipher, digest;
4411 const EVP_CIPHER *c;
4412 const EVP_MD *h;
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -08004413 int mac_key_len, enc_key_len, fixed_iv_len;
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08004414
4415 ssl_cipher = SSL_get_current_cipher(ssl);
4416 if (!ssl_cipher)
4417 return -1;
4418 cipher = SSL_CIPHER_get_cipher_nid(ssl_cipher);
4419 digest = SSL_CIPHER_get_digest_nid(ssl_cipher);
4420 wpa_printf(MSG_DEBUG, "OpenSSL: cipher nid %d digest nid %d",
4421 cipher, digest);
4422 if (cipher < 0 || digest < 0)
4423 return -1;
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -08004424 if (cipher == NID_undef) {
4425 wpa_printf(MSG_DEBUG, "OpenSSL: no cipher in use?!");
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08004426 return -1;
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -08004427 }
4428 c = EVP_get_cipherbynid(cipher);
4429 if (!c)
4430 return -1;
4431 enc_key_len = EVP_CIPHER_key_length(c);
4432 if (EVP_CIPHER_mode(c) == EVP_CIPH_GCM_MODE ||
4433 EVP_CIPHER_mode(c) == EVP_CIPH_CCM_MODE)
4434 fixed_iv_len = 4; /* only part of IV from PRF */
4435 else
4436 fixed_iv_len = EVP_CIPHER_iv_length(c);
4437 if (digest == NID_undef) {
4438 wpa_printf(MSG_DEBUG, "OpenSSL: no digest in use (e.g., AEAD)");
4439 mac_key_len = 0;
4440 } else {
4441 h = EVP_get_digestbynid(digest);
4442 if (!h)
4443 return -1;
4444 mac_key_len = EVP_MD_size(h);
4445 }
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08004446
4447 wpa_printf(MSG_DEBUG,
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -08004448 "OpenSSL: keyblock size: mac_key_len=%d enc_key_len=%d fixed_iv_len=%d",
4449 mac_key_len, enc_key_len, fixed_iv_len);
4450 return 2 * (mac_key_len + enc_key_len + fixed_iv_len);
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08004451#endif
Dmitry Shmidtaf9da312015-04-03 10:03:11 -07004452}
Dmitry Shmidt849734c2016-05-27 09:59:01 -07004453#endif /* OPENSSL_NEED_EAP_FAST_PRF */
Dmitry Shmidtaf9da312015-04-03 10:03:11 -07004454
4455
Dmitry Shmidt849734c2016-05-27 09:59:01 -07004456int tls_connection_export_key(void *tls_ctx, struct tls_connection *conn,
Hai Shalom021b0b52019-04-10 11:17:58 -07004457 const char *label, const u8 *context,
4458 size_t context_len, u8 *out, size_t out_len)
Dmitry Shmidtaf9da312015-04-03 10:03:11 -07004459{
Dmitry Shmidt849734c2016-05-27 09:59:01 -07004460 if (!conn ||
4461 SSL_export_keying_material(conn->ssl, out, out_len, label,
Hai Shalom021b0b52019-04-10 11:17:58 -07004462 os_strlen(label), context, context_len,
4463 context != NULL) != 1)
Dmitry Shmidt849734c2016-05-27 09:59:01 -07004464 return -1;
4465 return 0;
4466}
4467
4468
4469int tls_connection_get_eap_fast_key(void *tls_ctx, struct tls_connection *conn,
4470 u8 *out, size_t out_len)
4471{
4472#ifdef OPENSSL_NEED_EAP_FAST_PRF
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08004473 SSL *ssl;
4474 SSL_SESSION *sess;
4475 u8 *rnd;
4476 int ret = -1;
4477 int skip = 0;
4478 u8 *tmp_out = NULL;
4479 u8 *_out = out;
4480 unsigned char client_random[SSL3_RANDOM_SIZE];
4481 unsigned char server_random[SSL3_RANDOM_SIZE];
4482 unsigned char master_key[64];
4483 size_t master_key_len;
4484 const char *ver;
4485
4486 /*
Dmitry Shmidt849734c2016-05-27 09:59:01 -07004487 * TLS library did not support EAP-FAST key generation, so get the
4488 * needed TLS session parameters and use an internal implementation of
4489 * TLS PRF to derive the key.
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08004490 */
4491
4492 if (conn == NULL)
4493 return -1;
4494 ssl = conn->ssl;
4495 if (ssl == NULL)
4496 return -1;
4497 ver = SSL_get_version(ssl);
4498 sess = SSL_get_session(ssl);
4499 if (!ver || !sess)
4500 return -1;
4501
Dmitry Shmidt849734c2016-05-27 09:59:01 -07004502 skip = openssl_get_keyblock_size(ssl);
4503 if (skip < 0)
4504 return -1;
4505 tmp_out = os_malloc(skip + out_len);
4506 if (!tmp_out)
4507 return -1;
4508 _out = tmp_out;
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08004509
4510 rnd = os_malloc(2 * SSL3_RANDOM_SIZE);
4511 if (!rnd) {
4512 os_free(tmp_out);
4513 return -1;
4514 }
4515
4516 SSL_get_client_random(ssl, client_random, sizeof(client_random));
4517 SSL_get_server_random(ssl, server_random, sizeof(server_random));
4518 master_key_len = SSL_SESSION_get_master_key(sess, master_key,
4519 sizeof(master_key));
4520
Dmitry Shmidt849734c2016-05-27 09:59:01 -07004521 os_memcpy(rnd, server_random, SSL3_RANDOM_SIZE);
4522 os_memcpy(rnd + SSL3_RANDOM_SIZE, client_random, SSL3_RANDOM_SIZE);
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08004523
4524 if (os_strcmp(ver, "TLSv1.2") == 0) {
4525 tls_prf_sha256(master_key, master_key_len,
Dmitry Shmidt849734c2016-05-27 09:59:01 -07004526 "key expansion", rnd, 2 * SSL3_RANDOM_SIZE,
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08004527 _out, skip + out_len);
4528 ret = 0;
4529 } else if (tls_prf_sha1_md5(master_key, master_key_len,
Dmitry Shmidt849734c2016-05-27 09:59:01 -07004530 "key expansion", rnd, 2 * SSL3_RANDOM_SIZE,
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08004531 _out, skip + out_len) == 0) {
4532 ret = 0;
4533 }
Hai Shalom81f62d82019-07-22 12:10:00 -07004534 forced_memzero(master_key, sizeof(master_key));
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08004535 os_free(rnd);
Dmitry Shmidt849734c2016-05-27 09:59:01 -07004536 if (ret == 0)
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08004537 os_memcpy(out, _out + skip, out_len);
4538 bin_clear_free(tmp_out, skip);
4539
4540 return ret;
Dmitry Shmidt849734c2016-05-27 09:59:01 -07004541#else /* OPENSSL_NEED_EAP_FAST_PRF */
4542 wpa_printf(MSG_ERROR,
4543 "OpenSSL: EAP-FAST keys cannot be exported in FIPS mode");
4544 return -1;
4545#endif /* OPENSSL_NEED_EAP_FAST_PRF */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004546}
4547
4548
4549static struct wpabuf *
Roshan Pius3a1667e2018-07-03 15:17:14 -07004550openssl_handshake(struct tls_connection *conn, const struct wpabuf *in_data)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004551{
Sunil Ravia04bd252022-05-02 22:54:18 -07004552 struct tls_context *context = conn->context;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004553 int res;
4554 struct wpabuf *out_data;
4555
4556 /*
4557 * Give TLS handshake data from the server (if available) to OpenSSL
4558 * for processing.
4559 */
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08004560 if (in_data && wpabuf_len(in_data) > 0 &&
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004561 BIO_write(conn->ssl_in, wpabuf_head(in_data), wpabuf_len(in_data))
4562 < 0) {
4563 tls_show_errors(MSG_INFO, __func__,
4564 "Handshake failed - BIO_write");
4565 return NULL;
4566 }
4567
4568 /* Initiate TLS handshake or continue the existing handshake */
Roshan Pius3a1667e2018-07-03 15:17:14 -07004569 if (conn->server)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004570 res = SSL_accept(conn->ssl);
4571 else
4572 res = SSL_connect(conn->ssl);
4573 if (res != 1) {
4574 int err = SSL_get_error(conn->ssl, res);
4575 if (err == SSL_ERROR_WANT_READ)
4576 wpa_printf(MSG_DEBUG, "SSL: SSL_connect - want "
4577 "more data");
4578 else if (err == SSL_ERROR_WANT_WRITE)
4579 wpa_printf(MSG_DEBUG, "SSL: SSL_connect - want to "
4580 "write");
4581 else {
Sunil Ravia04bd252022-05-02 22:54:18 -07004582 unsigned long error = ERR_peek_last_error();
4583
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004584 tls_show_errors(MSG_INFO, __func__, "SSL_connect");
Sunil Ravia04bd252022-05-02 22:54:18 -07004585
4586 if (context->event_cb &&
4587 ERR_GET_LIB(error) == ERR_LIB_SSL &&
4588 ERR_GET_REASON(error) ==
4589 SSL_R_UNSAFE_LEGACY_RENEGOTIATION_DISABLED) {
4590 context->event_cb(
4591 context->cb_ctx,
4592 TLS_UNSAFE_RENEGOTIATION_DISABLED,
4593 NULL);
4594 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004595 conn->failed++;
Roshan Pius3a1667e2018-07-03 15:17:14 -07004596 if (!conn->server && !conn->client_hello_generated) {
4597 /* The server would not understand TLS Alert
4598 * before ClientHello, so simply terminate
4599 * handshake on this type of error case caused
4600 * by a likely internal error like no ciphers
4601 * available. */
4602 wpa_printf(MSG_DEBUG,
4603 "OpenSSL: Could not generate ClientHello");
4604 conn->write_alerts++;
4605 return NULL;
4606 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004607 }
4608 }
4609
Roshan Pius3a1667e2018-07-03 15:17:14 -07004610 if (!conn->server && !conn->failed)
4611 conn->client_hello_generated = 1;
4612
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004613#ifdef CONFIG_SUITEB
Roshan Pius3a1667e2018-07-03 15:17:14 -07004614 if ((conn->flags & TLS_CONN_SUITEB) && !conn->server &&
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004615 os_strncmp(SSL_get_cipher(conn->ssl), "DHE-", 4) == 0 &&
4616 conn->server_dh_prime_len < 3072) {
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004617 /*
4618 * This should not be reached since earlier cert_cb should have
4619 * terminated the handshake. Keep this check here for extra
4620 * protection if anything goes wrong with the more low-level
4621 * checks based on having to parse the TLS handshake messages.
4622 */
4623 wpa_printf(MSG_DEBUG,
4624 "OpenSSL: Server DH prime length: %d bits",
4625 conn->server_dh_prime_len);
4626
4627 if (context->event_cb) {
4628 union tls_event_data ev;
4629
4630 os_memset(&ev, 0, sizeof(ev));
4631 ev.alert.is_local = 1;
4632 ev.alert.type = "fatal";
4633 ev.alert.description = "insufficient security";
4634 context->event_cb(context->cb_ctx, TLS_ALERT, &ev);
4635 }
4636 /*
4637 * Could send a TLS Alert to the server, but for now, simply
4638 * terminate handshake.
4639 */
4640 conn->failed++;
4641 conn->write_alerts++;
4642 return NULL;
4643 }
4644#endif /* CONFIG_SUITEB */
4645
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004646 /* Get the TLS handshake data to be sent to the server */
4647 res = BIO_ctrl_pending(conn->ssl_out);
4648 wpa_printf(MSG_DEBUG, "SSL: %d bytes pending from ssl_out", res);
4649 out_data = wpabuf_alloc(res);
4650 if (out_data == NULL) {
4651 wpa_printf(MSG_DEBUG, "SSL: Failed to allocate memory for "
4652 "handshake output (%d bytes)", res);
4653 if (BIO_reset(conn->ssl_out) < 0) {
4654 tls_show_errors(MSG_INFO, __func__,
4655 "BIO_reset failed");
4656 }
4657 return NULL;
4658 }
4659 res = res == 0 ? 0 : BIO_read(conn->ssl_out, wpabuf_mhead(out_data),
4660 res);
4661 if (res < 0) {
4662 tls_show_errors(MSG_INFO, __func__,
4663 "Handshake failed - BIO_read");
4664 if (BIO_reset(conn->ssl_out) < 0) {
4665 tls_show_errors(MSG_INFO, __func__,
4666 "BIO_reset failed");
4667 }
4668 wpabuf_free(out_data);
4669 return NULL;
4670 }
4671 wpabuf_put(out_data, res);
4672
4673 return out_data;
4674}
4675
4676
4677static struct wpabuf *
4678openssl_get_appl_data(struct tls_connection *conn, size_t max_len)
4679{
4680 struct wpabuf *appl_data;
4681 int res;
4682
4683 appl_data = wpabuf_alloc(max_len + 100);
4684 if (appl_data == NULL)
4685 return NULL;
4686
4687 res = SSL_read(conn->ssl, wpabuf_mhead(appl_data),
4688 wpabuf_size(appl_data));
4689 if (res < 0) {
4690 int err = SSL_get_error(conn->ssl, res);
4691 if (err == SSL_ERROR_WANT_READ ||
4692 err == SSL_ERROR_WANT_WRITE) {
4693 wpa_printf(MSG_DEBUG, "SSL: No Application Data "
4694 "included");
4695 } else {
4696 tls_show_errors(MSG_INFO, __func__,
4697 "Failed to read possible "
4698 "Application Data");
4699 }
4700 wpabuf_free(appl_data);
4701 return NULL;
4702 }
4703
4704 wpabuf_put(appl_data, res);
4705 wpa_hexdump_buf_key(MSG_MSGDUMP, "SSL: Application Data in Finished "
4706 "message", appl_data);
4707
4708 return appl_data;
4709}
4710
4711
4712static struct wpabuf *
4713openssl_connection_handshake(struct tls_connection *conn,
4714 const struct wpabuf *in_data,
Roshan Pius3a1667e2018-07-03 15:17:14 -07004715 struct wpabuf **appl_data)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004716{
4717 struct wpabuf *out_data;
4718
4719 if (appl_data)
4720 *appl_data = NULL;
4721
Roshan Pius3a1667e2018-07-03 15:17:14 -07004722 out_data = openssl_handshake(conn, in_data);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004723 if (out_data == NULL)
4724 return NULL;
Jouni Malinen26af48b2014-04-09 13:02:53 +03004725 if (conn->invalid_hb_used) {
4726 wpa_printf(MSG_INFO, "TLS: Heartbeat attack detected - do not send response");
4727 wpabuf_free(out_data);
4728 return NULL;
4729 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004730
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08004731 if (SSL_is_init_finished(conn->ssl)) {
4732 wpa_printf(MSG_DEBUG,
4733 "OpenSSL: Handshake finished - resumed=%d",
4734 tls_connection_resumed(conn->ssl_ctx, conn));
Hai Shalom81f62d82019-07-22 12:10:00 -07004735 if (conn->server) {
4736 char *buf;
4737 size_t buflen = 2000;
4738
4739 buf = os_malloc(buflen);
4740 if (buf) {
4741 if (SSL_get_shared_ciphers(conn->ssl, buf,
4742 buflen)) {
4743 buf[buflen - 1] = '\0';
4744 wpa_printf(MSG_DEBUG,
4745 "OpenSSL: Shared ciphers: %s",
4746 buf);
4747 }
4748 os_free(buf);
4749 }
4750 }
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08004751 if (appl_data && in_data)
4752 *appl_data = openssl_get_appl_data(conn,
4753 wpabuf_len(in_data));
4754 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004755
Jouni Malinen26af48b2014-04-09 13:02:53 +03004756 if (conn->invalid_hb_used) {
4757 wpa_printf(MSG_INFO, "TLS: Heartbeat attack detected - do not send response");
4758 if (appl_data) {
4759 wpabuf_free(*appl_data);
4760 *appl_data = NULL;
4761 }
4762 wpabuf_free(out_data);
4763 return NULL;
4764 }
4765
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004766 return out_data;
4767}
4768
4769
4770struct wpabuf *
4771tls_connection_handshake(void *ssl_ctx, struct tls_connection *conn,
4772 const struct wpabuf *in_data,
4773 struct wpabuf **appl_data)
4774{
Roshan Pius3a1667e2018-07-03 15:17:14 -07004775 return openssl_connection_handshake(conn, in_data, appl_data);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004776}
4777
4778
4779struct wpabuf * tls_connection_server_handshake(void *tls_ctx,
4780 struct tls_connection *conn,
4781 const struct wpabuf *in_data,
4782 struct wpabuf **appl_data)
4783{
Roshan Pius3a1667e2018-07-03 15:17:14 -07004784 conn->server = 1;
4785 return openssl_connection_handshake(conn, in_data, appl_data);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004786}
4787
4788
4789struct wpabuf * tls_connection_encrypt(void *tls_ctx,
4790 struct tls_connection *conn,
4791 const struct wpabuf *in_data)
4792{
4793 int res;
4794 struct wpabuf *buf;
4795
4796 if (conn == NULL)
4797 return NULL;
4798
4799 /* Give plaintext data for OpenSSL to encrypt into the TLS tunnel. */
4800 if ((res = BIO_reset(conn->ssl_in)) < 0 ||
4801 (res = BIO_reset(conn->ssl_out)) < 0) {
4802 tls_show_errors(MSG_INFO, __func__, "BIO_reset failed");
4803 return NULL;
4804 }
4805 res = SSL_write(conn->ssl, wpabuf_head(in_data), wpabuf_len(in_data));
4806 if (res < 0) {
4807 tls_show_errors(MSG_INFO, __func__,
4808 "Encryption failed - SSL_write");
4809 return NULL;
4810 }
4811
4812 /* Read encrypted data to be sent to the server */
4813 buf = wpabuf_alloc(wpabuf_len(in_data) + 300);
4814 if (buf == NULL)
4815 return NULL;
4816 res = BIO_read(conn->ssl_out, wpabuf_mhead(buf), wpabuf_size(buf));
4817 if (res < 0) {
4818 tls_show_errors(MSG_INFO, __func__,
4819 "Encryption failed - BIO_read");
4820 wpabuf_free(buf);
4821 return NULL;
4822 }
4823 wpabuf_put(buf, res);
4824
4825 return buf;
4826}
4827
4828
4829struct wpabuf * tls_connection_decrypt(void *tls_ctx,
4830 struct tls_connection *conn,
4831 const struct wpabuf *in_data)
4832{
4833 int res;
4834 struct wpabuf *buf;
4835
4836 /* Give encrypted data from TLS tunnel for OpenSSL to decrypt. */
4837 res = BIO_write(conn->ssl_in, wpabuf_head(in_data),
4838 wpabuf_len(in_data));
4839 if (res < 0) {
4840 tls_show_errors(MSG_INFO, __func__,
4841 "Decryption failed - BIO_write");
4842 return NULL;
4843 }
4844 if (BIO_reset(conn->ssl_out) < 0) {
4845 tls_show_errors(MSG_INFO, __func__, "BIO_reset failed");
4846 return NULL;
4847 }
4848
4849 /* Read decrypted data for further processing */
4850 /*
4851 * Even though we try to disable TLS compression, it is possible that
4852 * this cannot be done with all TLS libraries. Add extra buffer space
4853 * to handle the possibility of the decrypted data being longer than
4854 * input data.
4855 */
4856 buf = wpabuf_alloc((wpabuf_len(in_data) + 500) * 3);
4857 if (buf == NULL)
4858 return NULL;
4859 res = SSL_read(conn->ssl, wpabuf_mhead(buf), wpabuf_size(buf));
4860 if (res < 0) {
Hai Shalom60840252021-02-19 19:02:11 -08004861 int err = SSL_get_error(conn->ssl, res);
4862
4863 if (err == SSL_ERROR_WANT_READ) {
4864 wpa_printf(MSG_DEBUG,
4865 "SSL: SSL_connect - want more data");
4866 res = 0;
4867 } else {
4868 tls_show_errors(MSG_INFO, __func__,
4869 "Decryption failed - SSL_read");
4870 wpabuf_free(buf);
4871 return NULL;
4872 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004873 }
4874 wpabuf_put(buf, res);
4875
Jouni Malinen26af48b2014-04-09 13:02:53 +03004876 if (conn->invalid_hb_used) {
4877 wpa_printf(MSG_INFO, "TLS: Heartbeat attack detected - do not send response");
4878 wpabuf_free(buf);
4879 return NULL;
4880 }
4881
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004882 return buf;
4883}
4884
4885
4886int tls_connection_resumed(void *ssl_ctx, struct tls_connection *conn)
4887{
Hai Shalomce48b4a2018-09-05 11:41:35 -07004888 return conn ? SSL_session_reused(conn->ssl) : 0;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004889}
4890
4891
4892int tls_connection_set_cipher_list(void *tls_ctx, struct tls_connection *conn,
4893 u8 *ciphers)
4894{
Dmitry Shmidtde47be72016-01-07 12:52:55 -08004895 char buf[500], *pos, *end;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004896 u8 *c;
4897 int ret;
4898
4899 if (conn == NULL || conn->ssl == NULL || ciphers == NULL)
4900 return -1;
4901
4902 buf[0] = '\0';
4903 pos = buf;
4904 end = pos + sizeof(buf);
4905
4906 c = ciphers;
4907 while (*c != TLS_CIPHER_NONE) {
4908 const char *suite;
4909
4910 switch (*c) {
4911 case TLS_CIPHER_RC4_SHA:
4912 suite = "RC4-SHA";
4913 break;
4914 case TLS_CIPHER_AES128_SHA:
4915 suite = "AES128-SHA";
4916 break;
4917 case TLS_CIPHER_RSA_DHE_AES128_SHA:
4918 suite = "DHE-RSA-AES128-SHA";
4919 break;
4920 case TLS_CIPHER_ANON_DH_AES128_SHA:
4921 suite = "ADH-AES128-SHA";
4922 break;
Dmitry Shmidtde47be72016-01-07 12:52:55 -08004923 case TLS_CIPHER_RSA_DHE_AES256_SHA:
4924 suite = "DHE-RSA-AES256-SHA";
4925 break;
4926 case TLS_CIPHER_AES256_SHA:
4927 suite = "AES256-SHA";
4928 break;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004929 default:
4930 wpa_printf(MSG_DEBUG, "TLS: Unsupported "
4931 "cipher selection: %d", *c);
4932 return -1;
4933 }
4934 ret = os_snprintf(pos, end - pos, ":%s", suite);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08004935 if (os_snprintf_error(end - pos, ret))
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004936 break;
4937 pos += ret;
4938
4939 c++;
4940 }
Hai Shalom81f62d82019-07-22 12:10:00 -07004941 if (!buf[0]) {
4942 wpa_printf(MSG_DEBUG, "OpenSSL: No ciphers listed");
4943 return -1;
4944 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004945
4946 wpa_printf(MSG_DEBUG, "OpenSSL: cipher suites: %s", buf + 1);
4947
Dmitry Shmidtd7ff03d2015-12-04 14:49:35 -08004948#if OPENSSL_VERSION_NUMBER >= 0x10100000L && !defined(LIBRESSL_VERSION_NUMBER)
Hai Shalom81f62d82019-07-22 12:10:00 -07004949#ifdef EAP_FAST_OR_TEAP
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08004950 if (os_strstr(buf, ":ADH-")) {
4951 /*
4952 * Need to drop to security level 0 to allow anonymous
4953 * cipher suites for EAP-FAST.
4954 */
4955 SSL_set_security_level(conn->ssl, 0);
4956 } else if (SSL_get_security_level(conn->ssl) == 0) {
4957 /* Force at least security level 1 */
4958 SSL_set_security_level(conn->ssl, 1);
4959 }
Hai Shalom81f62d82019-07-22 12:10:00 -07004960#endif /* EAP_FAST_OR_TEAP */
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08004961#endif
4962
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004963 if (SSL_set_cipher_list(conn->ssl, buf + 1) != 1) {
4964 tls_show_errors(MSG_INFO, __func__,
4965 "Cipher suite configuration failed");
4966 return -1;
4967 }
4968
4969 return 0;
4970}
4971
4972
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08004973int tls_get_version(void *ssl_ctx, struct tls_connection *conn,
4974 char *buf, size_t buflen)
4975{
4976 const char *name;
4977 if (conn == NULL || conn->ssl == NULL)
4978 return -1;
4979
4980 name = SSL_get_version(conn->ssl);
4981 if (name == NULL)
4982 return -1;
4983
4984 os_strlcpy(buf, name, buflen);
4985 return 0;
4986}
4987
4988
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004989int tls_get_cipher(void *ssl_ctx, struct tls_connection *conn,
4990 char *buf, size_t buflen)
4991{
4992 const char *name;
4993 if (conn == NULL || conn->ssl == NULL)
4994 return -1;
4995
4996 name = SSL_get_cipher(conn->ssl);
4997 if (name == NULL)
4998 return -1;
4999
5000 os_strlcpy(buf, name, buflen);
5001 return 0;
5002}
5003
5004
5005int tls_connection_enable_workaround(void *ssl_ctx,
5006 struct tls_connection *conn)
5007{
5008 SSL_set_options(conn->ssl, SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS);
5009
5010 return 0;
5011}
5012
5013
Hai Shalom81f62d82019-07-22 12:10:00 -07005014#ifdef EAP_FAST_OR_TEAP
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005015/* ClientHello TLS extensions require a patch to openssl, so this function is
5016 * commented out unless explicitly needed for EAP-FAST in order to be able to
5017 * build this file with unmodified openssl. */
5018int tls_connection_client_hello_ext(void *ssl_ctx, struct tls_connection *conn,
5019 int ext_type, const u8 *data,
5020 size_t data_len)
5021{
5022 if (conn == NULL || conn->ssl == NULL || ext_type != 35)
5023 return -1;
5024
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005025 if (SSL_set_session_ticket_ext(conn->ssl, (void *) data,
5026 data_len) != 1)
5027 return -1;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005028
5029 return 0;
5030}
Hai Shalom81f62d82019-07-22 12:10:00 -07005031#endif /* EAP_FAST_OR_TEAP */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005032
5033
5034int tls_connection_get_failed(void *ssl_ctx, struct tls_connection *conn)
5035{
5036 if (conn == NULL)
5037 return -1;
5038 return conn->failed;
5039}
5040
5041
5042int tls_connection_get_read_alerts(void *ssl_ctx, struct tls_connection *conn)
5043{
5044 if (conn == NULL)
5045 return -1;
5046 return conn->read_alerts;
5047}
5048
5049
5050int tls_connection_get_write_alerts(void *ssl_ctx, struct tls_connection *conn)
5051{
5052 if (conn == NULL)
5053 return -1;
5054 return conn->write_alerts;
5055}
5056
5057
Dmitry Shmidt34af3062013-07-11 10:46:32 -07005058#ifdef HAVE_OCSP
5059
5060static void ocsp_debug_print_resp(OCSP_RESPONSE *rsp)
5061{
5062#ifndef CONFIG_NO_STDOUT_DEBUG
Dmitry Shmidt34af3062013-07-11 10:46:32 -07005063 BIO *out;
5064 size_t rlen;
5065 char *txt;
5066 int res;
5067
5068 if (wpa_debug_level > MSG_DEBUG)
5069 return;
5070
5071 out = BIO_new(BIO_s_mem());
5072 if (!out)
5073 return;
5074
5075 OCSP_RESPONSE_print(out, rsp, 0);
5076 rlen = BIO_ctrl_pending(out);
5077 txt = os_malloc(rlen + 1);
5078 if (!txt) {
5079 BIO_free(out);
5080 return;
5081 }
5082
5083 res = BIO_read(out, txt, rlen);
5084 if (res > 0) {
5085 txt[res] = '\0';
5086 wpa_printf(MSG_DEBUG, "OpenSSL: OCSP Response\n%s", txt);
5087 }
5088 os_free(txt);
5089 BIO_free(out);
5090#endif /* CONFIG_NO_STDOUT_DEBUG */
5091}
5092
5093
5094static int ocsp_resp_cb(SSL *s, void *arg)
5095{
5096 struct tls_connection *conn = arg;
5097 const unsigned char *p;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07005098 int len, status, reason, res;
Dmitry Shmidt34af3062013-07-11 10:46:32 -07005099 OCSP_RESPONSE *rsp;
5100 OCSP_BASICRESP *basic;
5101 OCSP_CERTID *id;
5102 ASN1_GENERALIZEDTIME *produced_at, *this_update, *next_update;
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08005103 X509_STORE *store;
5104 STACK_OF(X509) *certs = NULL;
Dmitry Shmidt34af3062013-07-11 10:46:32 -07005105
5106 len = SSL_get_tlsext_status_ocsp_resp(s, &p);
5107 if (!p) {
Sunil Ravia04bd252022-05-02 22:54:18 -07005108#if OPENSSL_VERSION_NUMBER >= 0x10101000L
5109#if !defined(LIBRESSL_VERSION_NUMBER) || LIBRESSL_VERSION_NUMBER >= 0x30400000L
5110 if (SSL_version(s) == TLS1_3_VERSION && SSL_session_reused(s)) {
5111 /* TLS 1.3 sends the OCSP response with the server
5112 * Certificate message. Since that Certificate message
5113 * is not sent when resuming a session, there can be no
5114 * new OCSP response. Allow this since the OCSP response
5115 * was validated when checking the initial certificate
5116 * exchange. */
5117 wpa_printf(MSG_DEBUG,
5118 "OpenSSL: Allow no OCSP response when using TLS 1.3 and a resumed session");
5119 return 1;
5120 }
5121#endif
5122#endif
Dmitry Shmidt34af3062013-07-11 10:46:32 -07005123 wpa_printf(MSG_DEBUG, "OpenSSL: No OCSP response received");
5124 return (conn->flags & TLS_CONN_REQUIRE_OCSP) ? 0 : 1;
5125 }
5126
5127 wpa_hexdump(MSG_DEBUG, "OpenSSL: OCSP response", p, len);
5128
5129 rsp = d2i_OCSP_RESPONSE(NULL, &p, len);
5130 if (!rsp) {
5131 wpa_printf(MSG_INFO, "OpenSSL: Failed to parse OCSP response");
5132 return 0;
5133 }
5134
5135 ocsp_debug_print_resp(rsp);
5136
5137 status = OCSP_response_status(rsp);
5138 if (status != OCSP_RESPONSE_STATUS_SUCCESSFUL) {
5139 wpa_printf(MSG_INFO, "OpenSSL: OCSP responder error %d (%s)",
5140 status, OCSP_response_status_str(status));
5141 return 0;
5142 }
5143
5144 basic = OCSP_response_get1_basic(rsp);
5145 if (!basic) {
5146 wpa_printf(MSG_INFO, "OpenSSL: Could not find BasicOCSPResponse");
5147 return 0;
5148 }
5149
Dmitry Shmidt216983b2015-02-06 10:50:36 -08005150 store = SSL_CTX_get_cert_store(conn->ssl_ctx);
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08005151 if (conn->peer_issuer) {
Dmitry Shmidt71757432014-06-02 13:50:35 -07005152 debug_print_cert(conn->peer_issuer, "Add OCSP issuer");
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08005153
5154 if (X509_STORE_add_cert(store, conn->peer_issuer) != 1) {
5155 tls_show_errors(MSG_INFO, __func__,
Dmitry Shmidt7f656022015-02-25 14:36:37 -08005156 "OpenSSL: Could not add issuer to certificate store");
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08005157 }
5158 certs = sk_X509_new_null();
5159 if (certs) {
5160 X509 *cert;
5161 cert = X509_dup(conn->peer_issuer);
5162 if (cert && !sk_X509_push(certs, cert)) {
5163 tls_show_errors(
5164 MSG_INFO, __func__,
Dmitry Shmidt7f656022015-02-25 14:36:37 -08005165 "OpenSSL: Could not add issuer to OCSP responder trust store");
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08005166 X509_free(cert);
5167 sk_X509_free(certs);
5168 certs = NULL;
5169 }
Dmitry Shmidt7f656022015-02-25 14:36:37 -08005170 if (certs && conn->peer_issuer_issuer) {
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08005171 cert = X509_dup(conn->peer_issuer_issuer);
5172 if (cert && !sk_X509_push(certs, cert)) {
5173 tls_show_errors(
5174 MSG_INFO, __func__,
Dmitry Shmidt7f656022015-02-25 14:36:37 -08005175 "OpenSSL: Could not add issuer's issuer to OCSP responder trust store");
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08005176 X509_free(cert);
5177 }
5178 }
5179 }
5180 }
5181
5182 status = OCSP_basic_verify(basic, certs, store, OCSP_TRUSTOTHER);
5183 sk_X509_pop_free(certs, X509_free);
Dmitry Shmidt34af3062013-07-11 10:46:32 -07005184 if (status <= 0) {
5185 tls_show_errors(MSG_INFO, __func__,
5186 "OpenSSL: OCSP response failed verification");
5187 OCSP_BASICRESP_free(basic);
5188 OCSP_RESPONSE_free(rsp);
5189 return 0;
5190 }
5191
5192 wpa_printf(MSG_DEBUG, "OpenSSL: OCSP response verification succeeded");
5193
Dmitry Shmidt56052862013-10-04 10:23:25 -07005194 if (!conn->peer_cert) {
5195 wpa_printf(MSG_DEBUG, "OpenSSL: Peer certificate not available for OCSP status check");
5196 OCSP_BASICRESP_free(basic);
5197 OCSP_RESPONSE_free(rsp);
5198 return 0;
5199 }
5200
5201 if (!conn->peer_issuer) {
5202 wpa_printf(MSG_DEBUG, "OpenSSL: Peer issuer certificate not available for OCSP status check");
Dmitry Shmidt34af3062013-07-11 10:46:32 -07005203 OCSP_BASICRESP_free(basic);
5204 OCSP_RESPONSE_free(rsp);
5205 return 0;
5206 }
5207
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07005208 id = OCSP_cert_to_id(EVP_sha256(), conn->peer_cert, conn->peer_issuer);
Dmitry Shmidt34af3062013-07-11 10:46:32 -07005209 if (!id) {
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07005210 wpa_printf(MSG_DEBUG,
5211 "OpenSSL: Could not create OCSP certificate identifier (SHA256)");
Dmitry Shmidt34af3062013-07-11 10:46:32 -07005212 OCSP_BASICRESP_free(basic);
5213 OCSP_RESPONSE_free(rsp);
5214 return 0;
5215 }
5216
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07005217 res = OCSP_resp_find_status(basic, id, &status, &reason, &produced_at,
5218 &this_update, &next_update);
5219 if (!res) {
Hai Shalom81f62d82019-07-22 12:10:00 -07005220 OCSP_CERTID_free(id);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07005221 id = OCSP_cert_to_id(NULL, conn->peer_cert, conn->peer_issuer);
5222 if (!id) {
5223 wpa_printf(MSG_DEBUG,
5224 "OpenSSL: Could not create OCSP certificate identifier (SHA1)");
5225 OCSP_BASICRESP_free(basic);
5226 OCSP_RESPONSE_free(rsp);
5227 return 0;
5228 }
5229
5230 res = OCSP_resp_find_status(basic, id, &status, &reason,
5231 &produced_at, &this_update,
5232 &next_update);
5233 }
5234
5235 if (!res) {
Dmitry Shmidt34af3062013-07-11 10:46:32 -07005236 wpa_printf(MSG_INFO, "OpenSSL: Could not find current server certificate from OCSP response%s",
5237 (conn->flags & TLS_CONN_REQUIRE_OCSP) ? "" :
5238 " (OCSP not required)");
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08005239 OCSP_CERTID_free(id);
Dmitry Shmidt34af3062013-07-11 10:46:32 -07005240 OCSP_BASICRESP_free(basic);
5241 OCSP_RESPONSE_free(rsp);
5242 return (conn->flags & TLS_CONN_REQUIRE_OCSP) ? 0 : 1;
5243 }
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08005244 OCSP_CERTID_free(id);
Dmitry Shmidt34af3062013-07-11 10:46:32 -07005245
5246 if (!OCSP_check_validity(this_update, next_update, 5 * 60, -1)) {
5247 tls_show_errors(MSG_INFO, __func__,
5248 "OpenSSL: OCSP status times invalid");
5249 OCSP_BASICRESP_free(basic);
5250 OCSP_RESPONSE_free(rsp);
5251 return 0;
5252 }
5253
5254 OCSP_BASICRESP_free(basic);
5255 OCSP_RESPONSE_free(rsp);
5256
5257 wpa_printf(MSG_DEBUG, "OpenSSL: OCSP status for server certificate: %s",
5258 OCSP_cert_status_str(status));
5259
5260 if (status == V_OCSP_CERTSTATUS_GOOD)
5261 return 1;
5262 if (status == V_OCSP_CERTSTATUS_REVOKED)
5263 return 0;
5264 if (conn->flags & TLS_CONN_REQUIRE_OCSP) {
5265 wpa_printf(MSG_DEBUG, "OpenSSL: OCSP status unknown, but OCSP required");
5266 return 0;
5267 }
Dmitry Shmidt051af732013-10-22 13:52:46 -07005268 wpa_printf(MSG_DEBUG, "OpenSSL: OCSP status unknown, but OCSP was not required, so allow connection to continue");
Dmitry Shmidt34af3062013-07-11 10:46:32 -07005269 return 1;
5270}
5271
5272
5273static int ocsp_status_cb(SSL *s, void *arg)
5274{
5275 char *tmp;
5276 char *resp;
5277 size_t len;
5278
5279 if (tls_global->ocsp_stapling_response == NULL) {
5280 wpa_printf(MSG_DEBUG, "OpenSSL: OCSP status callback - no response configured");
5281 return SSL_TLSEXT_ERR_OK;
5282 }
5283
5284 resp = os_readfile(tls_global->ocsp_stapling_response, &len);
5285 if (resp == NULL) {
5286 wpa_printf(MSG_DEBUG, "OpenSSL: OCSP status callback - could not read response file");
5287 /* TODO: Build OCSPResponse with responseStatus = internalError
5288 */
5289 return SSL_TLSEXT_ERR_OK;
5290 }
5291 wpa_printf(MSG_DEBUG, "OpenSSL: OCSP status callback - send cached response");
5292 tmp = OPENSSL_malloc(len);
5293 if (tmp == NULL) {
5294 os_free(resp);
5295 return SSL_TLSEXT_ERR_ALERT_FATAL;
5296 }
5297
5298 os_memcpy(tmp, resp, len);
5299 os_free(resp);
5300 SSL_set_tlsext_status_ocsp_resp(s, tmp, len);
5301
5302 return SSL_TLSEXT_ERR_OK;
5303}
5304
5305#endif /* HAVE_OCSP */
5306
5307
Hai Shalomfdcde762020-04-02 11:19:20 -07005308static size_t max_str_len(const char **lines)
5309{
5310 const char **p;
5311 size_t max_len = 0;
5312
5313 for (p = lines; *p; p++) {
5314 size_t len = os_strlen(*p);
5315
5316 if (len > max_len)
5317 max_len = len;
5318 }
5319
5320 return max_len;
5321}
5322
5323
5324static int match_lines_in_file(const char *path, const char **lines)
5325{
5326 FILE *f;
5327 char *buf;
5328 size_t bufsize;
5329 int found = 0, is_linestart = 1;
5330
5331 bufsize = max_str_len(lines) + sizeof("\r\n");
5332 buf = os_malloc(bufsize);
5333 if (!buf)
5334 return 0;
5335
5336 f = fopen(path, "r");
5337 if (!f) {
5338 os_free(buf);
5339 return 0;
5340 }
5341
5342 while (!found && fgets(buf, bufsize, f)) {
5343 int is_lineend;
5344 size_t len;
5345 const char **p;
5346
5347 len = strcspn(buf, "\r\n");
5348 is_lineend = buf[len] != '\0';
5349 buf[len] = '\0';
5350
5351 if (is_linestart && is_lineend) {
5352 for (p = lines; !found && *p; p++)
5353 found = os_strcmp(buf, *p) == 0;
5354 }
5355 is_linestart = is_lineend;
5356 }
5357
5358 fclose(f);
5359 bin_clear_free(buf, bufsize);
5360
5361 return found;
5362}
5363
5364
5365static int is_tpm2_key(const char *path)
5366{
5367 /* Check both new and old format of TPM2 PEM guard tag */
5368 static const char *tpm2_tags[] = {
5369 "-----BEGIN TSS2 PRIVATE KEY-----",
5370 "-----BEGIN TSS2 KEY BLOB-----",
5371 NULL
5372 };
5373
5374 return match_lines_in_file(path, tpm2_tags);
5375}
5376
5377
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005378int tls_connection_set_params(void *tls_ctx, struct tls_connection *conn,
5379 const struct tls_connection_params *params)
5380{
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08005381 struct tls_data *data = tls_ctx;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005382 int ret;
5383 unsigned long err;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08005384 int can_pkcs11 = 0;
5385 const char *key_id = params->key_id;
5386 const char *cert_id = params->cert_id;
5387 const char *ca_cert_id = params->ca_cert_id;
5388 const char *engine_id = params->engine ? params->engine_id : NULL;
Roshan Pius3a1667e2018-07-03 15:17:14 -07005389 const char *ciphers;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005390
5391 if (conn == NULL)
5392 return -1;
5393
Dmitry Shmidt014a3ff2015-12-28 13:27:49 -08005394 if (params->flags & TLS_CONN_REQUIRE_OCSP_ALL) {
5395 wpa_printf(MSG_INFO,
5396 "OpenSSL: ocsp=3 not supported");
5397 return -1;
5398 }
5399
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08005400 /*
5401 * If the engine isn't explicitly configured, and any of the
5402 * cert/key fields are actually PKCS#11 URIs, then automatically
5403 * use the PKCS#11 ENGINE.
5404 */
5405 if (!engine_id || os_strcmp(engine_id, "pkcs11") == 0)
5406 can_pkcs11 = 1;
5407
5408 if (!key_id && params->private_key && can_pkcs11 &&
5409 os_strncmp(params->private_key, "pkcs11:", 7) == 0) {
5410 can_pkcs11 = 2;
5411 key_id = params->private_key;
5412 }
5413
5414 if (!cert_id && params->client_cert && can_pkcs11 &&
5415 os_strncmp(params->client_cert, "pkcs11:", 7) == 0) {
5416 can_pkcs11 = 2;
5417 cert_id = params->client_cert;
5418 }
5419
5420 if (!ca_cert_id && params->ca_cert && can_pkcs11 &&
5421 os_strncmp(params->ca_cert, "pkcs11:", 7) == 0) {
5422 can_pkcs11 = 2;
5423 ca_cert_id = params->ca_cert;
5424 }
5425
5426 /* If we need to automatically enable the PKCS#11 ENGINE, do so. */
5427 if (can_pkcs11 == 2 && !engine_id)
5428 engine_id = "pkcs11";
5429
Hai Shalomfdcde762020-04-02 11:19:20 -07005430 /* If private_key points to a TPM2-wrapped key, automatically enable
5431 * tpm2 engine and use it to unwrap the key. */
5432 if (params->private_key &&
5433 (!engine_id || os_strcmp(engine_id, "tpm2") == 0) &&
5434 is_tpm2_key(params->private_key)) {
5435 wpa_printf(MSG_DEBUG, "OpenSSL: Found TPM2 wrapped key %s",
5436 params->private_key);
5437 key_id = key_id ? key_id : params->private_key;
5438 engine_id = engine_id ? engine_id : "tpm2";
5439 }
5440
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08005441#if defined(EAP_FAST) || defined(EAP_FAST_DYNAMIC) || defined(EAP_SERVER_FAST)
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08005442#if OPENSSL_VERSION_NUMBER < 0x10100000L || defined(LIBRESSL_VERSION_NUMBER)
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08005443 if (params->flags & TLS_CONN_EAP_FAST) {
5444 wpa_printf(MSG_DEBUG,
5445 "OpenSSL: Use TLSv1_method() for EAP-FAST");
5446 if (SSL_set_ssl_method(conn->ssl, TLSv1_method()) != 1) {
5447 tls_show_errors(MSG_INFO, __func__,
5448 "Failed to set TLSv1_method() for EAP-FAST");
5449 return -1;
5450 }
5451 }
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08005452#endif
Roshan Pius3a1667e2018-07-03 15:17:14 -07005453#if OPENSSL_VERSION_NUMBER >= 0x10101000L
5454#ifdef SSL_OP_NO_TLSv1_3
5455 if (params->flags & TLS_CONN_EAP_FAST) {
5456 /* Need to disable TLS v1.3 at least for now since OpenSSL 1.1.1
5457 * refuses to start the handshake with the modified ciphersuite
5458 * list (no TLS v1.3 ciphersuites included) for EAP-FAST. */
5459 wpa_printf(MSG_DEBUG, "OpenSSL: Disable TLSv1.3 for EAP-FAST");
5460 SSL_set_options(conn->ssl, SSL_OP_NO_TLSv1_3);
5461 }
5462#endif /* SSL_OP_NO_TLSv1_3 */
5463#endif
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08005464#endif /* EAP_FAST || EAP_FAST_DYNAMIC || EAP_SERVER_FAST */
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08005465
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005466 while ((err = ERR_get_error())) {
5467 wpa_printf(MSG_INFO, "%s: Clearing pending SSL error: %s",
5468 __func__, ERR_error_string(err, NULL));
5469 }
5470
Sunil Ravi77d572f2023-01-17 23:58:31 +00005471 if (tls_set_conn_flags(conn, params->flags,
5472 params->openssl_ciphers) < 0) {
5473 wpa_printf(MSG_ERROR, "TLS: Failed to set connection flags");
5474 return -1;
5475 }
5476
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08005477 if (engine_id) {
Hai Shalomfdcde762020-04-02 11:19:20 -07005478 wpa_printf(MSG_DEBUG, "SSL: Initializing TLS engine %s",
5479 engine_id);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08005480 ret = tls_engine_init(conn, engine_id, params->pin,
5481 key_id, cert_id, ca_cert_id);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005482 if (ret)
5483 return ret;
5484 }
5485 if (tls_connection_set_subject_match(conn,
5486 params->subject_match,
Dmitry Shmidt051af732013-10-22 13:52:46 -07005487 params->altsubject_match,
Dmitry Shmidt2f74e362015-01-21 13:19:05 -08005488 params->suffix_match,
Hai Shalom021b0b52019-04-10 11:17:58 -07005489 params->domain_match,
Hai Shalom22171592021-04-02 16:05:23 -07005490 params->check_cert_subject)) {
5491 wpa_printf(MSG_ERROR, "TLS: Failed to set subject match");
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005492 return -1;
Hai Shalom22171592021-04-02 16:05:23 -07005493 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005494
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08005495 if (engine_id && ca_cert_id) {
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08005496 if (tls_connection_engine_ca_cert(data, conn, ca_cert_id))
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005497 return TLS_SET_PARAMS_ENGINE_PRV_VERIFY_FAILED;
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08005498 } else if (tls_connection_ca_cert(data, conn, params->ca_cert,
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005499 params->ca_cert_blob,
5500 params->ca_cert_blob_len,
Hai Shalom22171592021-04-02 16:05:23 -07005501 params->ca_path)) {
5502 wpa_printf(MSG_ERROR, "TLS: Failed to parse Root CA certificate");
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005503 return -1;
Hai Shalom22171592021-04-02 16:05:23 -07005504 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005505
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08005506 if (engine_id && cert_id) {
5507 if (tls_connection_engine_client_cert(conn, cert_id))
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005508 return TLS_SET_PARAMS_ENGINE_PRV_VERIFY_FAILED;
5509 } else if (tls_connection_client_cert(conn, params->client_cert,
5510 params->client_cert_blob,
Hai Shalom22171592021-04-02 16:05:23 -07005511 params->client_cert_blob_len)) {
5512 wpa_printf(MSG_ERROR, "TLS: Failed to parse client certificate");
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005513 return -1;
Hai Shalom22171592021-04-02 16:05:23 -07005514 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005515
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08005516 if (engine_id && key_id) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005517 wpa_printf(MSG_DEBUG, "TLS: Using private key from engine");
5518 if (tls_connection_engine_private_key(conn))
5519 return TLS_SET_PARAMS_ENGINE_PRV_VERIFY_FAILED;
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08005520 } else if (tls_connection_private_key(data, conn,
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005521 params->private_key,
5522 params->private_key_passwd,
5523 params->private_key_blob,
5524 params->private_key_blob_len)) {
5525 wpa_printf(MSG_INFO, "TLS: Failed to load private key '%s'",
5526 params->private_key);
5527 return -1;
5528 }
5529
Roshan Pius3a1667e2018-07-03 15:17:14 -07005530 ciphers = params->openssl_ciphers;
5531#ifdef CONFIG_SUITEB
5532#ifdef OPENSSL_IS_BORINGSSL
5533 if (ciphers && os_strcmp(ciphers, "SUITEB192") == 0) {
5534 /* BoringSSL removed support for SUITEB192, so need to handle
5535 * this with hardcoded ciphersuite and additional checks for
5536 * other parameters. */
5537 ciphers = "ECDHE-ECDSA-AES256-GCM-SHA384";
5538 }
5539#endif /* OPENSSL_IS_BORINGSSL */
5540#endif /* CONFIG_SUITEB */
5541 if (ciphers && SSL_set_cipher_list(conn->ssl, ciphers) != 1) {
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08005542 wpa_printf(MSG_INFO,
5543 "OpenSSL: Failed to set cipher string '%s'",
Roshan Pius3a1667e2018-07-03 15:17:14 -07005544 ciphers);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08005545 return -1;
5546 }
5547
Hai Shalom74f70d42019-02-11 14:42:39 -08005548 if (!params->openssl_ecdh_curves) {
5549#ifndef OPENSSL_IS_BORINGSSL
5550#ifndef OPENSSL_NO_EC
Sunil Ravia04bd252022-05-02 22:54:18 -07005551#if OPENSSL_VERSION_NUMBER < 0x10100000L
Hai Shalom74f70d42019-02-11 14:42:39 -08005552 if (SSL_set_ecdh_auto(conn->ssl, 1) != 1) {
5553 wpa_printf(MSG_INFO,
5554 "OpenSSL: Failed to set ECDH curves to auto");
5555 return -1;
5556 }
Sunil Ravia04bd252022-05-02 22:54:18 -07005557#endif /* < 1.1.0 */
Hai Shalom74f70d42019-02-11 14:42:39 -08005558#endif /* OPENSSL_NO_EC */
5559#endif /* OPENSSL_IS_BORINGSSL */
5560 } else if (params->openssl_ecdh_curves[0]) {
Sunil Ravia04bd252022-05-02 22:54:18 -07005561#ifdef OPENSSL_IS_BORINGSSL
Hai Shalom74f70d42019-02-11 14:42:39 -08005562 wpa_printf(MSG_INFO,
Sunil Ravia04bd252022-05-02 22:54:18 -07005563 "OpenSSL: ECDH configuration not supported");
Hai Shalom74f70d42019-02-11 14:42:39 -08005564 return -1;
Sunil Ravia04bd252022-05-02 22:54:18 -07005565#else /* !OPENSSL_IS_BORINGSSL */
Hai Shalom74f70d42019-02-11 14:42:39 -08005566#ifndef OPENSSL_NO_EC
5567 if (SSL_set1_curves_list(conn->ssl,
5568 params->openssl_ecdh_curves) != 1) {
5569 wpa_printf(MSG_INFO,
5570 "OpenSSL: Failed to set ECDH curves '%s'",
5571 params->openssl_ecdh_curves);
5572 return -1;
5573 }
5574#else /* OPENSSL_NO_EC */
5575 wpa_printf(MSG_INFO, "OpenSSL: ECDH not supported");
5576 return -1;
5577#endif /* OPENSSL_NO_EC */
5578#endif /* OPENSSL_IS_BORINGSSL */
5579 }
5580
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08005581#ifdef OPENSSL_IS_BORINGSSL
5582 if (params->flags & TLS_CONN_REQUEST_OCSP) {
5583 SSL_enable_ocsp_stapling(conn->ssl);
5584 }
5585#else /* OPENSSL_IS_BORINGSSL */
Dmitry Shmidt34af3062013-07-11 10:46:32 -07005586#ifdef HAVE_OCSP
5587 if (params->flags & TLS_CONN_REQUEST_OCSP) {
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08005588 SSL_CTX *ssl_ctx = data->ssl;
Dmitry Shmidt34af3062013-07-11 10:46:32 -07005589 SSL_set_tlsext_status_type(conn->ssl, TLSEXT_STATUSTYPE_ocsp);
5590 SSL_CTX_set_tlsext_status_cb(ssl_ctx, ocsp_resp_cb);
5591 SSL_CTX_set_tlsext_status_arg(ssl_ctx, conn);
5592 }
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08005593#else /* HAVE_OCSP */
5594 if (params->flags & TLS_CONN_REQUIRE_OCSP) {
5595 wpa_printf(MSG_INFO,
5596 "OpenSSL: No OCSP support included - reject configuration");
5597 return -1;
5598 }
5599 if (params->flags & TLS_CONN_REQUEST_OCSP) {
5600 wpa_printf(MSG_DEBUG,
5601 "OpenSSL: No OCSP support included - allow optional OCSP case to continue");
5602 }
Dmitry Shmidt34af3062013-07-11 10:46:32 -07005603#endif /* HAVE_OCSP */
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08005604#endif /* OPENSSL_IS_BORINGSSL */
Dmitry Shmidt34af3062013-07-11 10:46:32 -07005605
Dmitry Shmidtc55524a2011-07-07 11:18:38 -07005606 conn->flags = params->flags;
5607
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08005608 tls_get_errors(data);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005609
5610 return 0;
5611}
5612
5613
Hai Shalom81f62d82019-07-22 12:10:00 -07005614static void openssl_debug_dump_cipher_list(SSL_CTX *ssl_ctx)
5615{
5616 SSL *ssl;
5617 int i;
5618
5619 ssl = SSL_new(ssl_ctx);
5620 if (!ssl)
5621 return;
5622
5623 wpa_printf(MSG_DEBUG,
5624 "OpenSSL: Enabled cipher suites in priority order");
5625 for (i = 0; ; i++) {
5626 const char *cipher;
5627
5628 cipher = SSL_get_cipher_list(ssl, i);
5629 if (!cipher)
5630 break;
5631 wpa_printf(MSG_DEBUG, "Cipher %d: %s", i, cipher);
5632 }
5633
5634 SSL_free(ssl);
5635}
5636
5637
5638#if !defined(LIBRESSL_VERSION_NUMBER) && !defined(BORINGSSL_API_VERSION)
5639
5640static const char * openssl_pkey_type_str(const EVP_PKEY *pkey)
5641{
5642 if (!pkey)
5643 return "NULL";
5644 switch (EVP_PKEY_type(EVP_PKEY_id(pkey))) {
5645 case EVP_PKEY_RSA:
5646 return "RSA";
5647 case EVP_PKEY_DSA:
5648 return "DSA";
5649 case EVP_PKEY_DH:
5650 return "DH";
5651 case EVP_PKEY_EC:
5652 return "EC";
Sunil Ravi77d572f2023-01-17 23:58:31 +00005653 default:
5654 return "?";
Hai Shalom81f62d82019-07-22 12:10:00 -07005655 }
Hai Shalom81f62d82019-07-22 12:10:00 -07005656}
5657
5658
5659static void openssl_debug_dump_certificate(int i, X509 *cert)
5660{
5661 char buf[256];
5662 EVP_PKEY *pkey;
5663 ASN1_INTEGER *ser;
5664 char serial_num[128];
5665
Hai Shalom60840252021-02-19 19:02:11 -08005666 if (!cert)
5667 return;
5668
Hai Shalom81f62d82019-07-22 12:10:00 -07005669 X509_NAME_oneline(X509_get_subject_name(cert), buf, sizeof(buf));
5670
5671 ser = X509_get_serialNumber(cert);
5672 if (ser)
5673 wpa_snprintf_hex_uppercase(serial_num, sizeof(serial_num),
5674 ASN1_STRING_get0_data(ser),
5675 ASN1_STRING_length(ser));
5676 else
5677 serial_num[0] = '\0';
5678
5679 pkey = X509_get_pubkey(cert);
5680 wpa_printf(MSG_DEBUG, "%d: %s (%s) %s", i, buf,
5681 openssl_pkey_type_str(pkey), serial_num);
5682 EVP_PKEY_free(pkey);
5683}
5684
5685
5686static void openssl_debug_dump_certificates(SSL_CTX *ssl_ctx)
5687{
5688 STACK_OF(X509) *certs;
5689
5690 wpa_printf(MSG_DEBUG, "OpenSSL: Configured certificate chain");
5691 if (SSL_CTX_get0_chain_certs(ssl_ctx, &certs) == 1) {
5692 int i;
5693
5694 for (i = sk_X509_num(certs); i > 0; i--)
5695 openssl_debug_dump_certificate(i, sk_X509_value(certs,
5696 i - 1));
5697 }
5698 openssl_debug_dump_certificate(0, SSL_CTX_get0_certificate(ssl_ctx));
5699}
5700
5701#endif
5702
5703
5704static void openssl_debug_dump_certificate_chains(SSL_CTX *ssl_ctx)
5705{
5706#if !defined(LIBRESSL_VERSION_NUMBER) && !defined(BORINGSSL_API_VERSION)
5707 int res;
5708
5709 for (res = SSL_CTX_set_current_cert(ssl_ctx, SSL_CERT_SET_FIRST);
5710 res == 1;
5711 res = SSL_CTX_set_current_cert(ssl_ctx, SSL_CERT_SET_NEXT))
5712 openssl_debug_dump_certificates(ssl_ctx);
5713
5714 SSL_CTX_set_current_cert(ssl_ctx, SSL_CERT_SET_FIRST);
5715#endif
5716}
5717
5718
5719static void openssl_debug_dump_ctx(SSL_CTX *ssl_ctx)
5720{
5721 openssl_debug_dump_cipher_list(ssl_ctx);
5722 openssl_debug_dump_certificate_chains(ssl_ctx);
5723}
5724
5725
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005726int tls_global_set_params(void *tls_ctx,
5727 const struct tls_connection_params *params)
5728{
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08005729 struct tls_data *data = tls_ctx;
5730 SSL_CTX *ssl_ctx = data->ssl;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005731 unsigned long err;
5732
5733 while ((err = ERR_get_error())) {
5734 wpa_printf(MSG_INFO, "%s: Clearing pending SSL error: %s",
5735 __func__, ERR_error_string(err, NULL));
5736 }
5737
Hai Shalom021b0b52019-04-10 11:17:58 -07005738 os_free(data->check_cert_subject);
5739 data->check_cert_subject = NULL;
5740 if (params->check_cert_subject) {
5741 data->check_cert_subject =
5742 os_strdup(params->check_cert_subject);
5743 if (!data->check_cert_subject)
5744 return -1;
5745 }
5746
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08005747 if (tls_global_ca_cert(data, params->ca_cert) ||
5748 tls_global_client_cert(data, params->client_cert) ||
5749 tls_global_private_key(data, params->private_key,
5750 params->private_key_passwd) ||
Hai Shalom81f62d82019-07-22 12:10:00 -07005751 tls_global_client_cert(data, params->client_cert2) ||
5752 tls_global_private_key(data, params->private_key2,
5753 params->private_key_passwd2) ||
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08005754 tls_global_dh(data, params->dh_file)) {
5755 wpa_printf(MSG_INFO, "TLS: Failed to set global parameters");
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005756 return -1;
5757 }
5758
Sunil Ravib0ac25f2024-07-12 01:42:03 +00005759 os_free(data->openssl_ciphers);
5760 if (params->openssl_ciphers) {
5761 data->openssl_ciphers = os_strdup(params->openssl_ciphers);
5762 if (!data->openssl_ciphers)
5763 return -1;
5764 } else {
5765 data->openssl_ciphers = NULL;
5766 }
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08005767 if (params->openssl_ciphers &&
5768 SSL_CTX_set_cipher_list(ssl_ctx, params->openssl_ciphers) != 1) {
5769 wpa_printf(MSG_INFO,
5770 "OpenSSL: Failed to set cipher string '%s'",
5771 params->openssl_ciphers);
5772 return -1;
5773 }
5774
Hai Shalom74f70d42019-02-11 14:42:39 -08005775 if (!params->openssl_ecdh_curves) {
5776#ifndef OPENSSL_IS_BORINGSSL
5777#ifndef OPENSSL_NO_EC
Sunil Ravia04bd252022-05-02 22:54:18 -07005778#if OPENSSL_VERSION_NUMBER < 0x10100000L
Hai Shalom74f70d42019-02-11 14:42:39 -08005779 if (SSL_CTX_set_ecdh_auto(ssl_ctx, 1) != 1) {
5780 wpa_printf(MSG_INFO,
5781 "OpenSSL: Failed to set ECDH curves to auto");
5782 return -1;
5783 }
Sunil Ravia04bd252022-05-02 22:54:18 -07005784#endif /* < 1.1.0 */
Hai Shalom74f70d42019-02-11 14:42:39 -08005785#endif /* OPENSSL_NO_EC */
5786#endif /* OPENSSL_IS_BORINGSSL */
5787 } else if (params->openssl_ecdh_curves[0]) {
Sunil Ravia04bd252022-05-02 22:54:18 -07005788#ifdef OPENSSL_IS_BORINGSSL
Hai Shalom74f70d42019-02-11 14:42:39 -08005789 wpa_printf(MSG_INFO,
Sunil Ravia04bd252022-05-02 22:54:18 -07005790 "OpenSSL: ECDH configuration not supported");
Hai Shalom74f70d42019-02-11 14:42:39 -08005791 return -1;
Sunil Ravia04bd252022-05-02 22:54:18 -07005792#else /* !OPENSSL_IS_BORINGSSL */
Hai Shalom74f70d42019-02-11 14:42:39 -08005793#ifndef OPENSSL_NO_EC
Hai Shalom5f92bc92019-04-18 11:54:11 -07005794#if OPENSSL_VERSION_NUMBER < 0x10100000L
5795 SSL_CTX_set_ecdh_auto(ssl_ctx, 1);
5796#endif
Hai Shalom74f70d42019-02-11 14:42:39 -08005797 if (SSL_CTX_set1_curves_list(ssl_ctx,
5798 params->openssl_ecdh_curves) !=
5799 1) {
5800 wpa_printf(MSG_INFO,
5801 "OpenSSL: Failed to set ECDH curves '%s'",
5802 params->openssl_ecdh_curves);
5803 return -1;
5804 }
5805#else /* OPENSSL_NO_EC */
5806 wpa_printf(MSG_INFO, "OpenSSL: ECDH not supported");
5807 return -1;
5808#endif /* OPENSSL_NO_EC */
5809#endif /* OPENSSL_IS_BORINGSSL */
5810 }
5811
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07005812#ifdef SSL_OP_NO_TICKET
5813 if (params->flags & TLS_CONN_DISABLE_SESSION_TICKET)
5814 SSL_CTX_set_options(ssl_ctx, SSL_OP_NO_TICKET);
5815 else
5816 SSL_CTX_clear_options(ssl_ctx, SSL_OP_NO_TICKET);
5817#endif /* SSL_OP_NO_TICKET */
5818
Dmitry Shmidt34af3062013-07-11 10:46:32 -07005819#ifdef HAVE_OCSP
5820 SSL_CTX_set_tlsext_status_cb(ssl_ctx, ocsp_status_cb);
5821 SSL_CTX_set_tlsext_status_arg(ssl_ctx, ssl_ctx);
5822 os_free(tls_global->ocsp_stapling_response);
5823 if (params->ocsp_stapling_response)
5824 tls_global->ocsp_stapling_response =
5825 os_strdup(params->ocsp_stapling_response);
5826 else
5827 tls_global->ocsp_stapling_response = NULL;
5828#endif /* HAVE_OCSP */
5829
Hai Shalom81f62d82019-07-22 12:10:00 -07005830 openssl_debug_dump_ctx(ssl_ctx);
5831
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005832 return 0;
5833}
5834
5835
Hai Shalom81f62d82019-07-22 12:10:00 -07005836#ifdef EAP_FAST_OR_TEAP
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005837/* Pre-shared secred requires a patch to openssl, so this function is
5838 * commented out unless explicitly needed for EAP-FAST in order to be able to
5839 * build this file with unmodified openssl. */
5840
Dmitry Shmidt1d6bf422016-01-19 15:51:35 -08005841#if (defined(OPENSSL_IS_BORINGSSL) || OPENSSL_VERSION_NUMBER >= 0x10100000L) && !defined(LIBRESSL_VERSION_NUMBER)
Dmitry Shmidt9ead16e2014-10-07 13:15:23 -07005842static int tls_sess_sec_cb(SSL *s, void *secret, int *secret_len,
5843 STACK_OF(SSL_CIPHER) *peer_ciphers,
5844 const SSL_CIPHER **cipher, void *arg)
5845#else /* OPENSSL_IS_BORINGSSL */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005846static int tls_sess_sec_cb(SSL *s, void *secret, int *secret_len,
5847 STACK_OF(SSL_CIPHER) *peer_ciphers,
5848 SSL_CIPHER **cipher, void *arg)
Dmitry Shmidt9ead16e2014-10-07 13:15:23 -07005849#endif /* OPENSSL_IS_BORINGSSL */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005850{
5851 struct tls_connection *conn = arg;
5852 int ret;
5853
Sunil Ravia04bd252022-05-02 22:54:18 -07005854#if OPENSSL_VERSION_NUMBER < 0x10100000L
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005855 if (conn == NULL || conn->session_ticket_cb == NULL)
5856 return 0;
5857
5858 ret = conn->session_ticket_cb(conn->session_ticket_cb_ctx,
5859 conn->session_ticket,
5860 conn->session_ticket_len,
5861 s->s3->client_random,
5862 s->s3->server_random, secret);
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08005863#else
5864 unsigned char client_random[SSL3_RANDOM_SIZE];
5865 unsigned char server_random[SSL3_RANDOM_SIZE];
5866
5867 if (conn == NULL || conn->session_ticket_cb == NULL)
5868 return 0;
5869
5870 SSL_get_client_random(s, client_random, sizeof(client_random));
5871 SSL_get_server_random(s, server_random, sizeof(server_random));
5872
5873 ret = conn->session_ticket_cb(conn->session_ticket_cb_ctx,
5874 conn->session_ticket,
5875 conn->session_ticket_len,
5876 client_random,
5877 server_random, secret);
5878#endif
5879
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005880 os_free(conn->session_ticket);
5881 conn->session_ticket = NULL;
5882
5883 if (ret <= 0)
5884 return 0;
5885
5886 *secret_len = SSL_MAX_MASTER_KEY_LENGTH;
5887 return 1;
5888}
5889
5890
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005891static int tls_session_ticket_ext_cb(SSL *s, const unsigned char *data,
5892 int len, void *arg)
5893{
5894 struct tls_connection *conn = arg;
5895
5896 if (conn == NULL || conn->session_ticket_cb == NULL)
5897 return 0;
5898
5899 wpa_printf(MSG_DEBUG, "OpenSSL: %s: length=%d", __func__, len);
5900
5901 os_free(conn->session_ticket);
5902 conn->session_ticket = NULL;
5903
5904 wpa_hexdump(MSG_DEBUG, "OpenSSL: ClientHello SessionTicket "
5905 "extension", data, len);
5906
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07005907 conn->session_ticket = os_memdup(data, len);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005908 if (conn->session_ticket == NULL)
5909 return 0;
5910
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005911 conn->session_ticket_len = len;
5912
5913 return 1;
5914}
Hai Shalom81f62d82019-07-22 12:10:00 -07005915#endif /* EAP_FAST_OR_TEAP */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005916
5917
5918int tls_connection_set_session_ticket_cb(void *tls_ctx,
5919 struct tls_connection *conn,
5920 tls_session_ticket_cb cb,
5921 void *ctx)
5922{
Hai Shalom81f62d82019-07-22 12:10:00 -07005923#ifdef EAP_FAST_OR_TEAP
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005924 conn->session_ticket_cb = cb;
5925 conn->session_ticket_cb_ctx = ctx;
5926
5927 if (cb) {
5928 if (SSL_set_session_secret_cb(conn->ssl, tls_sess_sec_cb,
5929 conn) != 1)
5930 return -1;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005931 SSL_set_session_ticket_ext_cb(conn->ssl,
5932 tls_session_ticket_ext_cb, conn);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005933 } else {
5934 if (SSL_set_session_secret_cb(conn->ssl, NULL, NULL) != 1)
5935 return -1;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005936 SSL_set_session_ticket_ext_cb(conn->ssl, NULL, NULL);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005937 }
5938
5939 return 0;
Hai Shalom81f62d82019-07-22 12:10:00 -07005940#else /* EAP_FAST_OR_TEAP */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005941 return -1;
Hai Shalom81f62d82019-07-22 12:10:00 -07005942#endif /* EAP_FAST_OR_TEAP */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005943}
Dmitry Shmidtff787d52015-01-12 13:01:47 -08005944
5945
5946int tls_get_library_version(char *buf, size_t buf_len)
5947{
Dmitry Shmidt1d6bf422016-01-19 15:51:35 -08005948#if OPENSSL_VERSION_NUMBER >= 0x10100000L && !defined(LIBRESSL_VERSION_NUMBER)
Dmitry Shmidtd7ff03d2015-12-04 14:49:35 -08005949 return os_snprintf(buf, buf_len, "OpenSSL build=%s run=%s",
5950 OPENSSL_VERSION_TEXT,
5951 OpenSSL_version(OPENSSL_VERSION));
5952#else
Dmitry Shmidtff787d52015-01-12 13:01:47 -08005953 return os_snprintf(buf, buf_len, "OpenSSL build=%s run=%s",
5954 OPENSSL_VERSION_TEXT,
5955 SSLeay_version(SSLEAY_VERSION));
Dmitry Shmidtd7ff03d2015-12-04 14:49:35 -08005956#endif
Dmitry Shmidtff787d52015-01-12 13:01:47 -08005957}
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08005958
5959
5960void tls_connection_set_success_data(struct tls_connection *conn,
5961 struct wpabuf *data)
5962{
5963 SSL_SESSION *sess;
5964 struct wpabuf *old;
Sunil Ravia04bd252022-05-02 22:54:18 -07005965 struct tls_session_data *sess_data = NULL;
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08005966
5967 if (tls_ex_idx_session < 0)
5968 goto fail;
5969 sess = SSL_get_session(conn->ssl);
5970 if (!sess)
5971 goto fail;
5972 old = SSL_SESSION_get_ex_data(sess, tls_ex_idx_session);
5973 if (old) {
Sunil Ravia04bd252022-05-02 22:54:18 -07005974 struct tls_session_data *found;
5975
5976 found = get_session_data(conn->context, old);
5977 wpa_printf(MSG_DEBUG,
5978 "OpenSSL: Replacing old success data %p (sess %p)%s",
5979 old, sess, found ? "" : " (not freeing)");
5980 if (found) {
5981 dl_list_del(&found->list);
5982 os_free(found);
5983 wpabuf_free(old);
5984 }
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08005985 }
Sunil Ravia04bd252022-05-02 22:54:18 -07005986
5987 sess_data = os_zalloc(sizeof(*sess_data));
5988 if (!sess_data ||
5989 SSL_SESSION_set_ex_data(sess, tls_ex_idx_session, data) != 1)
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08005990 goto fail;
5991
Sunil Ravia04bd252022-05-02 22:54:18 -07005992 sess_data->buf = data;
5993 dl_list_add(&conn->context->sessions, &sess_data->list);
5994 wpa_printf(MSG_DEBUG, "OpenSSL: Stored success data %p (sess %p)",
5995 data, sess);
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08005996 conn->success_data = 1;
5997 return;
5998
5999fail:
6000 wpa_printf(MSG_INFO, "OpenSSL: Failed to store success data");
6001 wpabuf_free(data);
Sunil Ravia04bd252022-05-02 22:54:18 -07006002 os_free(sess_data);
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08006003}
6004
6005
6006void tls_connection_set_success_data_resumed(struct tls_connection *conn)
6007{
6008 wpa_printf(MSG_DEBUG,
6009 "OpenSSL: Success data accepted for resumed session");
6010 conn->success_data = 1;
6011}
6012
6013
6014const struct wpabuf *
6015tls_connection_get_success_data(struct tls_connection *conn)
6016{
6017 SSL_SESSION *sess;
6018
6019 if (tls_ex_idx_session < 0 ||
6020 !(sess = SSL_get_session(conn->ssl)))
6021 return NULL;
6022 return SSL_SESSION_get_ex_data(sess, tls_ex_idx_session);
6023}
6024
6025
6026void tls_connection_remove_session(struct tls_connection *conn)
6027{
6028 SSL_SESSION *sess;
6029
6030 sess = SSL_get_session(conn->ssl);
6031 if (!sess)
6032 return;
6033
6034 if (SSL_CTX_remove_session(conn->ssl_ctx, sess) != 1)
6035 wpa_printf(MSG_DEBUG,
6036 "OpenSSL: Session was not cached");
6037 else
6038 wpa_printf(MSG_DEBUG,
6039 "OpenSSL: Removed cached session to disable session resumption");
6040}
Hai Shalom81f62d82019-07-22 12:10:00 -07006041
6042
6043int tls_get_tls_unique(struct tls_connection *conn, u8 *buf, size_t max_len)
6044{
6045 size_t len;
6046 int reused;
6047
6048 reused = SSL_session_reused(conn->ssl);
6049 if ((conn->server && !reused) || (!conn->server && reused))
6050 len = SSL_get_peer_finished(conn->ssl, buf, max_len);
6051 else
6052 len = SSL_get_finished(conn->ssl, buf, max_len);
6053
6054 if (len == 0 || len > max_len)
6055 return -1;
6056
6057 return len;
6058}
6059
6060
6061u16 tls_connection_get_cipher_suite(struct tls_connection *conn)
6062{
6063 const SSL_CIPHER *cipher;
6064
6065 cipher = SSL_get_current_cipher(conn->ssl);
6066 if (!cipher)
6067 return 0;
6068#if OPENSSL_VERSION_NUMBER >= 0x10101000L && !defined(LIBRESSL_VERSION_NUMBER)
6069 return SSL_CIPHER_get_protocol_id(cipher);
6070#else
6071 return SSL_CIPHER_get_id(cipher) & 0xFFFF;
6072#endif
6073}
Hai Shalom899fcc72020-10-19 14:38:18 -07006074
6075
6076const char * tls_connection_get_peer_subject(struct tls_connection *conn)
6077{
6078 if (conn)
6079 return conn->peer_subject;
6080 return NULL;
6081}
6082
6083
6084bool tls_connection_get_own_cert_used(struct tls_connection *conn)
6085{
6086 if (conn)
6087 return SSL_get_certificate(conn->ssl) != NULL;
6088 return false;
6089}
Gabriel Birena5bdf372022-12-15 20:54:33 +00006090
6091void tls_register_cert_callback(tls_get_certificate_cb cb)
6092{
6093 certificate_callback_global = cb;
6094}
Gabriel Biren60ae0682023-11-01 22:04:12 +00006095
6096void tls_register_openssl_failure_callback(tls_openssl_failure_cb cb)
6097{
6098 openssl_failure_callback_global = cb;
6099}