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