tls_openssl.c revision 214734
1189251Ssam/* 2214734Srpaulo * SSL/TLS interface functions for OpenSSL 3214734Srpaulo * Copyright (c) 2004-2010, Jouni Malinen <j@w1.fi> 4189251Ssam * 5189251Ssam * This program is free software; you can redistribute it and/or modify 6189251Ssam * it under the terms of the GNU General Public License version 2 as 7189251Ssam * published by the Free Software Foundation. 8189251Ssam * 9189251Ssam * Alternatively, this software may be distributed under the terms of BSD 10189251Ssam * license. 11189251Ssam * 12189251Ssam * See README and COPYING for more details. 13189251Ssam */ 14189251Ssam 15189251Ssam#include "includes.h" 16189251Ssam 17189251Ssam#ifndef CONFIG_SMARTCARD 18189251Ssam#ifndef OPENSSL_NO_ENGINE 19189251Ssam#define OPENSSL_NO_ENGINE 20189251Ssam#endif 21189251Ssam#endif 22189251Ssam 23189251Ssam#include <openssl/ssl.h> 24189251Ssam#include <openssl/err.h> 25189251Ssam#include <openssl/pkcs12.h> 26189251Ssam#include <openssl/x509v3.h> 27189251Ssam#ifndef OPENSSL_NO_ENGINE 28189251Ssam#include <openssl/engine.h> 29189251Ssam#endif /* OPENSSL_NO_ENGINE */ 30189251Ssam 31189251Ssam#include "common.h" 32214734Srpaulo#include "crypto.h" 33189251Ssam#include "tls.h" 34189251Ssam 35189251Ssam#if OPENSSL_VERSION_NUMBER >= 0x0090800fL 36189251Ssam#define OPENSSL_d2i_TYPE const unsigned char ** 37189251Ssam#else 38189251Ssam#define OPENSSL_d2i_TYPE unsigned char ** 39189251Ssam#endif 40189251Ssam 41189251Ssam#ifdef SSL_F_SSL_SET_SESSION_TICKET_EXT 42189251Ssam#ifdef SSL_OP_NO_TICKET 43189251Ssam/* 44189251Ssam * Session ticket override patch was merged into OpenSSL 0.9.9 tree on 45189251Ssam * 2008-11-15. This version uses a bit different API compared to the old patch. 46189251Ssam */ 47189251Ssam#define CONFIG_OPENSSL_TICKET_OVERRIDE 48189251Ssam#endif 49189251Ssam#endif 50189251Ssam 51189251Ssamstatic int tls_openssl_ref_count = 0; 52189251Ssam 53214734Srpaulostruct tls_global { 54214734Srpaulo void (*event_cb)(void *ctx, enum tls_event ev, 55214734Srpaulo union tls_event_data *data); 56214734Srpaulo void *cb_ctx; 57214734Srpaulo}; 58214734Srpaulo 59214734Srpaulostatic struct tls_global *tls_global = NULL; 60214734Srpaulo 61214734Srpaulo 62189251Ssamstruct tls_connection { 63189251Ssam SSL *ssl; 64189251Ssam BIO *ssl_in, *ssl_out; 65189251Ssam#ifndef OPENSSL_NO_ENGINE 66189251Ssam ENGINE *engine; /* functional reference to the engine */ 67189251Ssam EVP_PKEY *private_key; /* the private key if using engine */ 68189251Ssam#endif /* OPENSSL_NO_ENGINE */ 69189251Ssam char *subject_match, *altsubject_match; 70189251Ssam int read_alerts, write_alerts, failed; 71189251Ssam 72189251Ssam tls_session_ticket_cb session_ticket_cb; 73189251Ssam void *session_ticket_cb_ctx; 74189251Ssam 75189251Ssam /* SessionTicket received from OpenSSL hello_extension_cb (server) */ 76189251Ssam u8 *session_ticket; 77189251Ssam size_t session_ticket_len; 78214734Srpaulo 79214734Srpaulo unsigned int ca_cert_verify:1; 80214734Srpaulo unsigned int cert_probe:1; 81214734Srpaulo unsigned int server_cert_only:1; 82214734Srpaulo 83214734Srpaulo u8 srv_cert_hash[32]; 84189251Ssam}; 85189251Ssam 86189251Ssam 87189251Ssam#ifdef CONFIG_NO_STDOUT_DEBUG 88189251Ssam 89189251Ssamstatic void _tls_show_errors(void) 90189251Ssam{ 91189251Ssam unsigned long err; 92189251Ssam 93189251Ssam while ((err = ERR_get_error())) { 94189251Ssam /* Just ignore the errors, since stdout is disabled */ 95189251Ssam } 96189251Ssam} 97189251Ssam#define tls_show_errors(l, f, t) _tls_show_errors() 98189251Ssam 99189251Ssam#else /* CONFIG_NO_STDOUT_DEBUG */ 100189251Ssam 101189251Ssamstatic void tls_show_errors(int level, const char *func, const char *txt) 102189251Ssam{ 103189251Ssam unsigned long err; 104189251Ssam 105189251Ssam wpa_printf(level, "OpenSSL: %s - %s %s", 106189251Ssam func, txt, ERR_error_string(ERR_get_error(), NULL)); 107189251Ssam 108189251Ssam while ((err = ERR_get_error())) { 109189251Ssam wpa_printf(MSG_INFO, "OpenSSL: pending error: %s", 110189251Ssam ERR_error_string(err, NULL)); 111189251Ssam } 112189251Ssam} 113189251Ssam 114189251Ssam#endif /* CONFIG_NO_STDOUT_DEBUG */ 115189251Ssam 116189251Ssam 117189251Ssam#ifdef CONFIG_NATIVE_WINDOWS 118189251Ssam 119189251Ssam/* Windows CryptoAPI and access to certificate stores */ 120189251Ssam#include <wincrypt.h> 121189251Ssam 122189251Ssam#ifdef __MINGW32_VERSION 123189251Ssam/* 124189251Ssam * MinGW does not yet include all the needed definitions for CryptoAPI, so 125189251Ssam * define here whatever extra is needed. 126189251Ssam */ 127189251Ssam#define CERT_SYSTEM_STORE_CURRENT_USER (1 << 16) 128189251Ssam#define CERT_STORE_READONLY_FLAG 0x00008000 129189251Ssam#define CERT_STORE_OPEN_EXISTING_FLAG 0x00004000 130189251Ssam 131189251Ssam#endif /* __MINGW32_VERSION */ 132189251Ssam 133189251Ssam 134189251Ssamstruct cryptoapi_rsa_data { 135189251Ssam const CERT_CONTEXT *cert; 136189251Ssam HCRYPTPROV crypt_prov; 137189251Ssam DWORD key_spec; 138189251Ssam BOOL free_crypt_prov; 139189251Ssam}; 140189251Ssam 141189251Ssam 142189251Ssamstatic void cryptoapi_error(const char *msg) 143189251Ssam{ 144189251Ssam wpa_printf(MSG_INFO, "CryptoAPI: %s; err=%u", 145189251Ssam msg, (unsigned int) GetLastError()); 146189251Ssam} 147189251Ssam 148189251Ssam 149189251Ssamstatic int cryptoapi_rsa_pub_enc(int flen, const unsigned char *from, 150189251Ssam unsigned char *to, RSA *rsa, int padding) 151189251Ssam{ 152189251Ssam wpa_printf(MSG_DEBUG, "%s - not implemented", __func__); 153189251Ssam return 0; 154189251Ssam} 155189251Ssam 156189251Ssam 157189251Ssamstatic int cryptoapi_rsa_pub_dec(int flen, const unsigned char *from, 158189251Ssam unsigned char *to, RSA *rsa, int padding) 159189251Ssam{ 160189251Ssam wpa_printf(MSG_DEBUG, "%s - not implemented", __func__); 161189251Ssam return 0; 162189251Ssam} 163189251Ssam 164189251Ssam 165189251Ssamstatic int cryptoapi_rsa_priv_enc(int flen, const unsigned char *from, 166189251Ssam unsigned char *to, RSA *rsa, int padding) 167189251Ssam{ 168189251Ssam struct cryptoapi_rsa_data *priv = 169189251Ssam (struct cryptoapi_rsa_data *) rsa->meth->app_data; 170189251Ssam HCRYPTHASH hash; 171189251Ssam DWORD hash_size, len, i; 172189251Ssam unsigned char *buf = NULL; 173189251Ssam int ret = 0; 174189251Ssam 175189251Ssam if (priv == NULL) { 176189251Ssam RSAerr(RSA_F_RSA_EAY_PRIVATE_ENCRYPT, 177189251Ssam ERR_R_PASSED_NULL_PARAMETER); 178189251Ssam return 0; 179189251Ssam } 180189251Ssam 181189251Ssam if (padding != RSA_PKCS1_PADDING) { 182189251Ssam RSAerr(RSA_F_RSA_EAY_PRIVATE_ENCRYPT, 183189251Ssam RSA_R_UNKNOWN_PADDING_TYPE); 184189251Ssam return 0; 185189251Ssam } 186189251Ssam 187189251Ssam if (flen != 16 /* MD5 */ + 20 /* SHA-1 */) { 188189251Ssam wpa_printf(MSG_INFO, "%s - only MD5-SHA1 hash supported", 189189251Ssam __func__); 190189251Ssam RSAerr(RSA_F_RSA_EAY_PRIVATE_ENCRYPT, 191189251Ssam RSA_R_INVALID_MESSAGE_LENGTH); 192189251Ssam return 0; 193189251Ssam } 194189251Ssam 195189251Ssam if (!CryptCreateHash(priv->crypt_prov, CALG_SSL3_SHAMD5, 0, 0, &hash)) 196189251Ssam { 197189251Ssam cryptoapi_error("CryptCreateHash failed"); 198189251Ssam return 0; 199189251Ssam } 200189251Ssam 201189251Ssam len = sizeof(hash_size); 202189251Ssam if (!CryptGetHashParam(hash, HP_HASHSIZE, (BYTE *) &hash_size, &len, 203189251Ssam 0)) { 204189251Ssam cryptoapi_error("CryptGetHashParam failed"); 205189251Ssam goto err; 206189251Ssam } 207189251Ssam 208189251Ssam if ((int) hash_size != flen) { 209189251Ssam wpa_printf(MSG_INFO, "CryptoAPI: Invalid hash size (%u != %d)", 210189251Ssam (unsigned) hash_size, flen); 211189251Ssam RSAerr(RSA_F_RSA_EAY_PRIVATE_ENCRYPT, 212189251Ssam RSA_R_INVALID_MESSAGE_LENGTH); 213189251Ssam goto err; 214189251Ssam } 215189251Ssam if (!CryptSetHashParam(hash, HP_HASHVAL, (BYTE * ) from, 0)) { 216189251Ssam cryptoapi_error("CryptSetHashParam failed"); 217189251Ssam goto err; 218189251Ssam } 219189251Ssam 220189251Ssam len = RSA_size(rsa); 221189251Ssam buf = os_malloc(len); 222189251Ssam if (buf == NULL) { 223189251Ssam RSAerr(RSA_F_RSA_EAY_PRIVATE_ENCRYPT, ERR_R_MALLOC_FAILURE); 224189251Ssam goto err; 225189251Ssam } 226189251Ssam 227189251Ssam if (!CryptSignHash(hash, priv->key_spec, NULL, 0, buf, &len)) { 228189251Ssam cryptoapi_error("CryptSignHash failed"); 229189251Ssam goto err; 230189251Ssam } 231189251Ssam 232189251Ssam for (i = 0; i < len; i++) 233189251Ssam to[i] = buf[len - i - 1]; 234189251Ssam ret = len; 235189251Ssam 236189251Ssamerr: 237189251Ssam os_free(buf); 238189251Ssam CryptDestroyHash(hash); 239189251Ssam 240189251Ssam return ret; 241189251Ssam} 242189251Ssam 243189251Ssam 244189251Ssamstatic int cryptoapi_rsa_priv_dec(int flen, const unsigned char *from, 245189251Ssam unsigned char *to, RSA *rsa, int padding) 246189251Ssam{ 247189251Ssam wpa_printf(MSG_DEBUG, "%s - not implemented", __func__); 248189251Ssam return 0; 249189251Ssam} 250189251Ssam 251189251Ssam 252189251Ssamstatic void cryptoapi_free_data(struct cryptoapi_rsa_data *priv) 253189251Ssam{ 254189251Ssam if (priv == NULL) 255189251Ssam return; 256189251Ssam if (priv->crypt_prov && priv->free_crypt_prov) 257189251Ssam CryptReleaseContext(priv->crypt_prov, 0); 258189251Ssam if (priv->cert) 259189251Ssam CertFreeCertificateContext(priv->cert); 260189251Ssam os_free(priv); 261189251Ssam} 262189251Ssam 263189251Ssam 264189251Ssamstatic int cryptoapi_finish(RSA *rsa) 265189251Ssam{ 266189251Ssam cryptoapi_free_data((struct cryptoapi_rsa_data *) rsa->meth->app_data); 267189251Ssam os_free((void *) rsa->meth); 268189251Ssam rsa->meth = NULL; 269189251Ssam return 1; 270189251Ssam} 271189251Ssam 272189251Ssam 273189251Ssamstatic const CERT_CONTEXT * cryptoapi_find_cert(const char *name, DWORD store) 274189251Ssam{ 275189251Ssam HCERTSTORE cs; 276189251Ssam const CERT_CONTEXT *ret = NULL; 277189251Ssam 278189251Ssam cs = CertOpenStore((LPCSTR) CERT_STORE_PROV_SYSTEM, 0, 0, 279189251Ssam store | CERT_STORE_OPEN_EXISTING_FLAG | 280189251Ssam CERT_STORE_READONLY_FLAG, L"MY"); 281189251Ssam if (cs == NULL) { 282189251Ssam cryptoapi_error("Failed to open 'My system store'"); 283189251Ssam return NULL; 284189251Ssam } 285189251Ssam 286189251Ssam if (strncmp(name, "cert://", 7) == 0) { 287189251Ssam unsigned short wbuf[255]; 288189251Ssam MultiByteToWideChar(CP_ACP, 0, name + 7, -1, wbuf, 255); 289189251Ssam ret = CertFindCertificateInStore(cs, X509_ASN_ENCODING | 290189251Ssam PKCS_7_ASN_ENCODING, 291189251Ssam 0, CERT_FIND_SUBJECT_STR, 292189251Ssam wbuf, NULL); 293189251Ssam } else if (strncmp(name, "hash://", 7) == 0) { 294189251Ssam CRYPT_HASH_BLOB blob; 295189251Ssam int len; 296189251Ssam const char *hash = name + 7; 297189251Ssam unsigned char *buf; 298189251Ssam 299189251Ssam len = os_strlen(hash) / 2; 300189251Ssam buf = os_malloc(len); 301189251Ssam if (buf && hexstr2bin(hash, buf, len) == 0) { 302189251Ssam blob.cbData = len; 303189251Ssam blob.pbData = buf; 304189251Ssam ret = CertFindCertificateInStore(cs, 305189251Ssam X509_ASN_ENCODING | 306189251Ssam PKCS_7_ASN_ENCODING, 307189251Ssam 0, CERT_FIND_HASH, 308189251Ssam &blob, NULL); 309189251Ssam } 310189251Ssam os_free(buf); 311189251Ssam } 312189251Ssam 313189251Ssam CertCloseStore(cs, 0); 314189251Ssam 315189251Ssam return ret; 316189251Ssam} 317189251Ssam 318189251Ssam 319189251Ssamstatic int tls_cryptoapi_cert(SSL *ssl, const char *name) 320189251Ssam{ 321189251Ssam X509 *cert = NULL; 322189251Ssam RSA *rsa = NULL, *pub_rsa; 323189251Ssam struct cryptoapi_rsa_data *priv; 324189251Ssam RSA_METHOD *rsa_meth; 325189251Ssam 326189251Ssam if (name == NULL || 327189251Ssam (strncmp(name, "cert://", 7) != 0 && 328189251Ssam strncmp(name, "hash://", 7) != 0)) 329189251Ssam return -1; 330189251Ssam 331189251Ssam priv = os_zalloc(sizeof(*priv)); 332189251Ssam rsa_meth = os_zalloc(sizeof(*rsa_meth)); 333189251Ssam if (priv == NULL || rsa_meth == NULL) { 334189251Ssam wpa_printf(MSG_WARNING, "CryptoAPI: Failed to allocate memory " 335189251Ssam "for CryptoAPI RSA method"); 336189251Ssam os_free(priv); 337189251Ssam os_free(rsa_meth); 338189251Ssam return -1; 339189251Ssam } 340189251Ssam 341189251Ssam priv->cert = cryptoapi_find_cert(name, CERT_SYSTEM_STORE_CURRENT_USER); 342189251Ssam if (priv->cert == NULL) { 343189251Ssam priv->cert = cryptoapi_find_cert( 344189251Ssam name, CERT_SYSTEM_STORE_LOCAL_MACHINE); 345189251Ssam } 346189251Ssam if (priv->cert == NULL) { 347189251Ssam wpa_printf(MSG_INFO, "CryptoAPI: Could not find certificate " 348189251Ssam "'%s'", name); 349189251Ssam goto err; 350189251Ssam } 351189251Ssam 352189251Ssam cert = d2i_X509(NULL, (OPENSSL_d2i_TYPE) &priv->cert->pbCertEncoded, 353189251Ssam priv->cert->cbCertEncoded); 354189251Ssam if (cert == NULL) { 355189251Ssam wpa_printf(MSG_INFO, "CryptoAPI: Could not process X509 DER " 356189251Ssam "encoding"); 357189251Ssam goto err; 358189251Ssam } 359189251Ssam 360189251Ssam if (!CryptAcquireCertificatePrivateKey(priv->cert, 361189251Ssam CRYPT_ACQUIRE_COMPARE_KEY_FLAG, 362189251Ssam NULL, &priv->crypt_prov, 363189251Ssam &priv->key_spec, 364189251Ssam &priv->free_crypt_prov)) { 365189251Ssam cryptoapi_error("Failed to acquire a private key for the " 366189251Ssam "certificate"); 367189251Ssam goto err; 368189251Ssam } 369189251Ssam 370189251Ssam rsa_meth->name = "Microsoft CryptoAPI RSA Method"; 371189251Ssam rsa_meth->rsa_pub_enc = cryptoapi_rsa_pub_enc; 372189251Ssam rsa_meth->rsa_pub_dec = cryptoapi_rsa_pub_dec; 373189251Ssam rsa_meth->rsa_priv_enc = cryptoapi_rsa_priv_enc; 374189251Ssam rsa_meth->rsa_priv_dec = cryptoapi_rsa_priv_dec; 375189251Ssam rsa_meth->finish = cryptoapi_finish; 376189251Ssam rsa_meth->flags = RSA_METHOD_FLAG_NO_CHECK; 377189251Ssam rsa_meth->app_data = (char *) priv; 378189251Ssam 379189251Ssam rsa = RSA_new(); 380189251Ssam if (rsa == NULL) { 381189251Ssam SSLerr(SSL_F_SSL_CTX_USE_CERTIFICATE_FILE, 382189251Ssam ERR_R_MALLOC_FAILURE); 383189251Ssam goto err; 384189251Ssam } 385189251Ssam 386189251Ssam if (!SSL_use_certificate(ssl, cert)) { 387189251Ssam RSA_free(rsa); 388189251Ssam rsa = NULL; 389189251Ssam goto err; 390189251Ssam } 391189251Ssam pub_rsa = cert->cert_info->key->pkey->pkey.rsa; 392189251Ssam X509_free(cert); 393189251Ssam cert = NULL; 394189251Ssam 395189251Ssam rsa->n = BN_dup(pub_rsa->n); 396189251Ssam rsa->e = BN_dup(pub_rsa->e); 397189251Ssam if (!RSA_set_method(rsa, rsa_meth)) 398189251Ssam goto err; 399189251Ssam 400189251Ssam if (!SSL_use_RSAPrivateKey(ssl, rsa)) 401189251Ssam goto err; 402189251Ssam RSA_free(rsa); 403189251Ssam 404189251Ssam return 0; 405189251Ssam 406189251Ssamerr: 407189251Ssam if (cert) 408189251Ssam X509_free(cert); 409189251Ssam if (rsa) 410189251Ssam RSA_free(rsa); 411189251Ssam else { 412189251Ssam os_free(rsa_meth); 413189251Ssam cryptoapi_free_data(priv); 414189251Ssam } 415189251Ssam return -1; 416189251Ssam} 417189251Ssam 418189251Ssam 419189251Ssamstatic int tls_cryptoapi_ca_cert(SSL_CTX *ssl_ctx, SSL *ssl, const char *name) 420189251Ssam{ 421189251Ssam HCERTSTORE cs; 422189251Ssam PCCERT_CONTEXT ctx = NULL; 423189251Ssam X509 *cert; 424189251Ssam char buf[128]; 425189251Ssam const char *store; 426189251Ssam#ifdef UNICODE 427189251Ssam WCHAR *wstore; 428189251Ssam#endif /* UNICODE */ 429189251Ssam 430189251Ssam if (name == NULL || strncmp(name, "cert_store://", 13) != 0) 431189251Ssam return -1; 432189251Ssam 433189251Ssam store = name + 13; 434189251Ssam#ifdef UNICODE 435189251Ssam wstore = os_malloc((os_strlen(store) + 1) * sizeof(WCHAR)); 436189251Ssam if (wstore == NULL) 437189251Ssam return -1; 438189251Ssam wsprintf(wstore, L"%S", store); 439189251Ssam cs = CertOpenSystemStore(0, wstore); 440189251Ssam os_free(wstore); 441189251Ssam#else /* UNICODE */ 442189251Ssam cs = CertOpenSystemStore(0, store); 443189251Ssam#endif /* UNICODE */ 444189251Ssam if (cs == NULL) { 445189251Ssam wpa_printf(MSG_DEBUG, "%s: failed to open system cert store " 446189251Ssam "'%s': error=%d", __func__, store, 447189251Ssam (int) GetLastError()); 448189251Ssam return -1; 449189251Ssam } 450189251Ssam 451189251Ssam while ((ctx = CertEnumCertificatesInStore(cs, ctx))) { 452189251Ssam cert = d2i_X509(NULL, (OPENSSL_d2i_TYPE) &ctx->pbCertEncoded, 453189251Ssam ctx->cbCertEncoded); 454189251Ssam if (cert == NULL) { 455189251Ssam wpa_printf(MSG_INFO, "CryptoAPI: Could not process " 456189251Ssam "X509 DER encoding for CA cert"); 457189251Ssam continue; 458189251Ssam } 459189251Ssam 460189251Ssam X509_NAME_oneline(X509_get_subject_name(cert), buf, 461189251Ssam sizeof(buf)); 462189251Ssam wpa_printf(MSG_DEBUG, "OpenSSL: Loaded CA certificate for " 463189251Ssam "system certificate store: subject='%s'", buf); 464189251Ssam 465189251Ssam if (!X509_STORE_add_cert(ssl_ctx->cert_store, cert)) { 466189251Ssam tls_show_errors(MSG_WARNING, __func__, 467189251Ssam "Failed to add ca_cert to OpenSSL " 468189251Ssam "certificate store"); 469189251Ssam } 470189251Ssam 471189251Ssam X509_free(cert); 472189251Ssam } 473189251Ssam 474189251Ssam if (!CertCloseStore(cs, 0)) { 475189251Ssam wpa_printf(MSG_DEBUG, "%s: failed to close system cert store " 476189251Ssam "'%s': error=%d", __func__, name + 13, 477189251Ssam (int) GetLastError()); 478189251Ssam } 479189251Ssam 480189251Ssam return 0; 481189251Ssam} 482189251Ssam 483189251Ssam 484189251Ssam#else /* CONFIG_NATIVE_WINDOWS */ 485189251Ssam 486189251Ssamstatic int tls_cryptoapi_cert(SSL *ssl, const char *name) 487189251Ssam{ 488189251Ssam return -1; 489189251Ssam} 490189251Ssam 491189251Ssam#endif /* CONFIG_NATIVE_WINDOWS */ 492189251Ssam 493189251Ssam 494189251Ssamstatic void ssl_info_cb(const SSL *ssl, int where, int ret) 495189251Ssam{ 496189251Ssam const char *str; 497189251Ssam int w; 498189251Ssam 499189251Ssam wpa_printf(MSG_DEBUG, "SSL: (where=0x%x ret=0x%x)", where, ret); 500189251Ssam w = where & ~SSL_ST_MASK; 501189251Ssam if (w & SSL_ST_CONNECT) 502189251Ssam str = "SSL_connect"; 503189251Ssam else if (w & SSL_ST_ACCEPT) 504189251Ssam str = "SSL_accept"; 505189251Ssam else 506189251Ssam str = "undefined"; 507189251Ssam 508189251Ssam if (where & SSL_CB_LOOP) { 509189251Ssam wpa_printf(MSG_DEBUG, "SSL: %s:%s", 510189251Ssam str, SSL_state_string_long(ssl)); 511189251Ssam } else if (where & SSL_CB_ALERT) { 512189251Ssam wpa_printf(MSG_INFO, "SSL: SSL3 alert: %s:%s:%s", 513189251Ssam where & SSL_CB_READ ? 514189251Ssam "read (remote end reported an error)" : 515189251Ssam "write (local SSL3 detected an error)", 516189251Ssam SSL_alert_type_string_long(ret), 517189251Ssam SSL_alert_desc_string_long(ret)); 518189251Ssam if ((ret >> 8) == SSL3_AL_FATAL) { 519189251Ssam struct tls_connection *conn = 520189251Ssam SSL_get_app_data((SSL *) ssl); 521189251Ssam if (where & SSL_CB_READ) 522189251Ssam conn->read_alerts++; 523189251Ssam else 524189251Ssam conn->write_alerts++; 525189251Ssam } 526189251Ssam } else if (where & SSL_CB_EXIT && ret <= 0) { 527189251Ssam wpa_printf(MSG_DEBUG, "SSL: %s:%s in %s", 528189251Ssam str, ret == 0 ? "failed" : "error", 529189251Ssam SSL_state_string_long(ssl)); 530189251Ssam } 531189251Ssam} 532189251Ssam 533189251Ssam 534189251Ssam#ifndef OPENSSL_NO_ENGINE 535189251Ssam/** 536189251Ssam * tls_engine_load_dynamic_generic - load any openssl engine 537189251Ssam * @pre: an array of commands and values that load an engine initialized 538189251Ssam * in the engine specific function 539189251Ssam * @post: an array of commands and values that initialize an already loaded 540189251Ssam * engine (or %NULL if not required) 541189251Ssam * @id: the engine id of the engine to load (only required if post is not %NULL 542189251Ssam * 543189251Ssam * This function is a generic function that loads any openssl engine. 544189251Ssam * 545189251Ssam * Returns: 0 on success, -1 on failure 546189251Ssam */ 547189251Ssamstatic int tls_engine_load_dynamic_generic(const char *pre[], 548189251Ssam const char *post[], const char *id) 549189251Ssam{ 550189251Ssam ENGINE *engine; 551189251Ssam const char *dynamic_id = "dynamic"; 552189251Ssam 553189251Ssam engine = ENGINE_by_id(id); 554189251Ssam if (engine) { 555189251Ssam ENGINE_free(engine); 556189251Ssam wpa_printf(MSG_DEBUG, "ENGINE: engine '%s' is already " 557189251Ssam "available", id); 558189251Ssam return 0; 559189251Ssam } 560189251Ssam ERR_clear_error(); 561189251Ssam 562189251Ssam engine = ENGINE_by_id(dynamic_id); 563189251Ssam if (engine == NULL) { 564189251Ssam wpa_printf(MSG_INFO, "ENGINE: Can't find engine %s [%s]", 565189251Ssam dynamic_id, 566189251Ssam ERR_error_string(ERR_get_error(), NULL)); 567189251Ssam return -1; 568189251Ssam } 569189251Ssam 570189251Ssam /* Perform the pre commands. This will load the engine. */ 571189251Ssam while (pre && pre[0]) { 572189251Ssam wpa_printf(MSG_DEBUG, "ENGINE: '%s' '%s'", pre[0], pre[1]); 573189251Ssam if (ENGINE_ctrl_cmd_string(engine, pre[0], pre[1], 0) == 0) { 574189251Ssam wpa_printf(MSG_INFO, "ENGINE: ctrl cmd_string failed: " 575189251Ssam "%s %s [%s]", pre[0], pre[1], 576189251Ssam ERR_error_string(ERR_get_error(), NULL)); 577189251Ssam ENGINE_free(engine); 578189251Ssam return -1; 579189251Ssam } 580189251Ssam pre += 2; 581189251Ssam } 582189251Ssam 583189251Ssam /* 584189251Ssam * Free the reference to the "dynamic" engine. The loaded engine can 585189251Ssam * now be looked up using ENGINE_by_id(). 586189251Ssam */ 587189251Ssam ENGINE_free(engine); 588189251Ssam 589189251Ssam engine = ENGINE_by_id(id); 590189251Ssam if (engine == NULL) { 591189251Ssam wpa_printf(MSG_INFO, "ENGINE: Can't find engine %s [%s]", 592189251Ssam id, ERR_error_string(ERR_get_error(), NULL)); 593189251Ssam return -1; 594189251Ssam } 595189251Ssam 596189251Ssam while (post && post[0]) { 597189251Ssam wpa_printf(MSG_DEBUG, "ENGINE: '%s' '%s'", post[0], post[1]); 598189251Ssam if (ENGINE_ctrl_cmd_string(engine, post[0], post[1], 0) == 0) { 599189251Ssam wpa_printf(MSG_DEBUG, "ENGINE: ctrl cmd_string failed:" 600189251Ssam " %s %s [%s]", post[0], post[1], 601189251Ssam ERR_error_string(ERR_get_error(), NULL)); 602189251Ssam ENGINE_remove(engine); 603189251Ssam ENGINE_free(engine); 604189251Ssam return -1; 605189251Ssam } 606189251Ssam post += 2; 607189251Ssam } 608189251Ssam ENGINE_free(engine); 609189251Ssam 610189251Ssam return 0; 611189251Ssam} 612189251Ssam 613189251Ssam 614189251Ssam/** 615189251Ssam * tls_engine_load_dynamic_pkcs11 - load the pkcs11 engine provided by opensc 616189251Ssam * @pkcs11_so_path: pksc11_so_path from the configuration 617189251Ssam * @pcks11_module_path: pkcs11_module_path from the configuration 618189251Ssam */ 619189251Ssamstatic int tls_engine_load_dynamic_pkcs11(const char *pkcs11_so_path, 620189251Ssam const char *pkcs11_module_path) 621189251Ssam{ 622189251Ssam char *engine_id = "pkcs11"; 623189251Ssam const char *pre_cmd[] = { 624189251Ssam "SO_PATH", NULL /* pkcs11_so_path */, 625189251Ssam "ID", NULL /* engine_id */, 626189251Ssam "LIST_ADD", "1", 627189251Ssam /* "NO_VCHECK", "1", */ 628189251Ssam "LOAD", NULL, 629189251Ssam NULL, NULL 630189251Ssam }; 631189251Ssam const char *post_cmd[] = { 632189251Ssam "MODULE_PATH", NULL /* pkcs11_module_path */, 633189251Ssam NULL, NULL 634189251Ssam }; 635189251Ssam 636189251Ssam if (!pkcs11_so_path || !pkcs11_module_path) 637189251Ssam return 0; 638189251Ssam 639189251Ssam pre_cmd[1] = pkcs11_so_path; 640189251Ssam pre_cmd[3] = engine_id; 641189251Ssam post_cmd[1] = pkcs11_module_path; 642189251Ssam 643189251Ssam wpa_printf(MSG_DEBUG, "ENGINE: Loading pkcs11 Engine from %s", 644189251Ssam pkcs11_so_path); 645189251Ssam 646189251Ssam return tls_engine_load_dynamic_generic(pre_cmd, post_cmd, engine_id); 647189251Ssam} 648189251Ssam 649189251Ssam 650189251Ssam/** 651189251Ssam * tls_engine_load_dynamic_opensc - load the opensc engine provided by opensc 652189251Ssam * @opensc_so_path: opensc_so_path from the configuration 653189251Ssam */ 654189251Ssamstatic int tls_engine_load_dynamic_opensc(const char *opensc_so_path) 655189251Ssam{ 656189251Ssam char *engine_id = "opensc"; 657189251Ssam const char *pre_cmd[] = { 658189251Ssam "SO_PATH", NULL /* opensc_so_path */, 659189251Ssam "ID", NULL /* engine_id */, 660189251Ssam "LIST_ADD", "1", 661189251Ssam "LOAD", NULL, 662189251Ssam NULL, NULL 663189251Ssam }; 664189251Ssam 665189251Ssam if (!opensc_so_path) 666189251Ssam return 0; 667189251Ssam 668189251Ssam pre_cmd[1] = opensc_so_path; 669189251Ssam pre_cmd[3] = engine_id; 670189251Ssam 671189251Ssam wpa_printf(MSG_DEBUG, "ENGINE: Loading OpenSC Engine from %s", 672189251Ssam opensc_so_path); 673189251Ssam 674189251Ssam return tls_engine_load_dynamic_generic(pre_cmd, NULL, engine_id); 675189251Ssam} 676189251Ssam#endif /* OPENSSL_NO_ENGINE */ 677189251Ssam 678189251Ssam 679189251Ssamvoid * tls_init(const struct tls_config *conf) 680189251Ssam{ 681189251Ssam SSL_CTX *ssl; 682189251Ssam 683189251Ssam if (tls_openssl_ref_count == 0) { 684214734Srpaulo tls_global = os_zalloc(sizeof(*tls_global)); 685214734Srpaulo if (tls_global == NULL) 686214734Srpaulo return NULL; 687214734Srpaulo if (conf) { 688214734Srpaulo tls_global->event_cb = conf->event_cb; 689214734Srpaulo tls_global->cb_ctx = conf->cb_ctx; 690214734Srpaulo } 691214734Srpaulo 692214734Srpaulo#ifdef CONFIG_FIPS 693214734Srpaulo#ifdef OPENSSL_FIPS 694214734Srpaulo if (conf && conf->fips_mode) { 695214734Srpaulo if (!FIPS_mode_set(1)) { 696214734Srpaulo wpa_printf(MSG_ERROR, "Failed to enable FIPS " 697214734Srpaulo "mode"); 698214734Srpaulo ERR_load_crypto_strings(); 699214734Srpaulo ERR_print_errors_fp(stderr); 700214734Srpaulo return NULL; 701214734Srpaulo } else 702214734Srpaulo wpa_printf(MSG_INFO, "Running in FIPS mode"); 703214734Srpaulo } 704214734Srpaulo#else /* OPENSSL_FIPS */ 705214734Srpaulo if (conf && conf->fips_mode) { 706214734Srpaulo wpa_printf(MSG_ERROR, "FIPS mode requested, but not " 707214734Srpaulo "supported"); 708214734Srpaulo return NULL; 709214734Srpaulo } 710214734Srpaulo#endif /* OPENSSL_FIPS */ 711214734Srpaulo#endif /* CONFIG_FIPS */ 712189251Ssam SSL_load_error_strings(); 713189251Ssam SSL_library_init(); 714209158Srpaulo#ifndef OPENSSL_NO_SHA256 715209158Srpaulo EVP_add_digest(EVP_sha256()); 716209158Srpaulo#endif /* OPENSSL_NO_SHA256 */ 717189251Ssam /* TODO: if /dev/urandom is available, PRNG is seeded 718189251Ssam * automatically. If this is not the case, random data should 719189251Ssam * be added here. */ 720189251Ssam 721189251Ssam#ifdef PKCS12_FUNCS 722209158Srpaulo#ifndef OPENSSL_NO_RC2 723209158Srpaulo /* 724209158Srpaulo * 40-bit RC2 is commonly used in PKCS#12 files, so enable it. 725209158Srpaulo * This is enabled by PKCS12_PBE_add() in OpenSSL 0.9.8 726209158Srpaulo * versions, but it looks like OpenSSL 1.0.0 does not do that 727209158Srpaulo * anymore. 728209158Srpaulo */ 729209158Srpaulo EVP_add_cipher(EVP_rc2_40_cbc()); 730209158Srpaulo#endif /* OPENSSL_NO_RC2 */ 731189251Ssam PKCS12_PBE_add(); 732189251Ssam#endif /* PKCS12_FUNCS */ 733189251Ssam } 734189251Ssam tls_openssl_ref_count++; 735189251Ssam 736189251Ssam ssl = SSL_CTX_new(TLSv1_method()); 737189251Ssam if (ssl == NULL) 738189251Ssam return NULL; 739189251Ssam 740189251Ssam SSL_CTX_set_info_callback(ssl, ssl_info_cb); 741189251Ssam 742189251Ssam#ifndef OPENSSL_NO_ENGINE 743189251Ssam if (conf && 744189251Ssam (conf->opensc_engine_path || conf->pkcs11_engine_path || 745189251Ssam conf->pkcs11_module_path)) { 746189251Ssam wpa_printf(MSG_DEBUG, "ENGINE: Loading dynamic engine"); 747189251Ssam ERR_load_ENGINE_strings(); 748189251Ssam ENGINE_load_dynamic(); 749189251Ssam 750189251Ssam if (tls_engine_load_dynamic_opensc(conf->opensc_engine_path) || 751189251Ssam tls_engine_load_dynamic_pkcs11(conf->pkcs11_engine_path, 752189251Ssam conf->pkcs11_module_path)) { 753189251Ssam tls_deinit(ssl); 754189251Ssam return NULL; 755189251Ssam } 756189251Ssam } 757189251Ssam#endif /* OPENSSL_NO_ENGINE */ 758189251Ssam 759189251Ssam return ssl; 760189251Ssam} 761189251Ssam 762189251Ssam 763189251Ssamvoid tls_deinit(void *ssl_ctx) 764189251Ssam{ 765189251Ssam SSL_CTX *ssl = ssl_ctx; 766189251Ssam SSL_CTX_free(ssl); 767189251Ssam 768189251Ssam tls_openssl_ref_count--; 769189251Ssam if (tls_openssl_ref_count == 0) { 770189251Ssam#ifndef OPENSSL_NO_ENGINE 771189251Ssam ENGINE_cleanup(); 772189251Ssam#endif /* OPENSSL_NO_ENGINE */ 773189251Ssam CRYPTO_cleanup_all_ex_data(); 774189251Ssam ERR_remove_state(0); 775189251Ssam ERR_free_strings(); 776189251Ssam EVP_cleanup(); 777214734Srpaulo os_free(tls_global); 778214734Srpaulo tls_global = NULL; 779189251Ssam } 780189251Ssam} 781189251Ssam 782189251Ssam 783189251Ssamstatic int tls_engine_init(struct tls_connection *conn, const char *engine_id, 784189251Ssam const char *pin, const char *key_id, 785189251Ssam const char *cert_id, const char *ca_cert_id) 786189251Ssam{ 787189251Ssam#ifndef OPENSSL_NO_ENGINE 788189251Ssam int ret = -1; 789189251Ssam if (engine_id == NULL) { 790189251Ssam wpa_printf(MSG_ERROR, "ENGINE: Engine ID not set"); 791189251Ssam return -1; 792189251Ssam } 793189251Ssam if (pin == NULL) { 794189251Ssam wpa_printf(MSG_ERROR, "ENGINE: Smartcard PIN not set"); 795189251Ssam return -1; 796189251Ssam } 797189251Ssam if (key_id == NULL) { 798189251Ssam wpa_printf(MSG_ERROR, "ENGINE: Key Id not set"); 799189251Ssam return -1; 800189251Ssam } 801189251Ssam 802189251Ssam ERR_clear_error(); 803189251Ssam conn->engine = ENGINE_by_id(engine_id); 804189251Ssam if (!conn->engine) { 805189251Ssam wpa_printf(MSG_ERROR, "ENGINE: engine %s not available [%s]", 806189251Ssam engine_id, ERR_error_string(ERR_get_error(), NULL)); 807189251Ssam goto err; 808189251Ssam } 809189251Ssam if (ENGINE_init(conn->engine) != 1) { 810189251Ssam wpa_printf(MSG_ERROR, "ENGINE: engine init failed " 811189251Ssam "(engine: %s) [%s]", engine_id, 812189251Ssam ERR_error_string(ERR_get_error(), NULL)); 813189251Ssam goto err; 814189251Ssam } 815189251Ssam wpa_printf(MSG_DEBUG, "ENGINE: engine initialized"); 816189251Ssam 817189251Ssam if (ENGINE_ctrl_cmd_string(conn->engine, "PIN", pin, 0) == 0) { 818189251Ssam wpa_printf(MSG_ERROR, "ENGINE: cannot set pin [%s]", 819189251Ssam ERR_error_string(ERR_get_error(), NULL)); 820189251Ssam goto err; 821189251Ssam } 822189251Ssam /* load private key first in-case PIN is required for cert */ 823189251Ssam conn->private_key = ENGINE_load_private_key(conn->engine, 824189251Ssam key_id, NULL, NULL); 825189251Ssam if (!conn->private_key) { 826189251Ssam wpa_printf(MSG_ERROR, "ENGINE: cannot load private key with id" 827189251Ssam " '%s' [%s]", key_id, 828189251Ssam ERR_error_string(ERR_get_error(), NULL)); 829189251Ssam ret = TLS_SET_PARAMS_ENGINE_PRV_INIT_FAILED; 830189251Ssam goto err; 831189251Ssam } 832189251Ssam 833189251Ssam /* handle a certificate and/or CA certificate */ 834189251Ssam if (cert_id || ca_cert_id) { 835189251Ssam const char *cmd_name = "LOAD_CERT_CTRL"; 836189251Ssam 837189251Ssam /* test if the engine supports a LOAD_CERT_CTRL */ 838189251Ssam if (!ENGINE_ctrl(conn->engine, ENGINE_CTRL_GET_CMD_FROM_NAME, 839189251Ssam 0, (void *)cmd_name, NULL)) { 840189251Ssam wpa_printf(MSG_ERROR, "ENGINE: engine does not support" 841189251Ssam " loading certificates"); 842189251Ssam ret = TLS_SET_PARAMS_ENGINE_PRV_INIT_FAILED; 843189251Ssam goto err; 844189251Ssam } 845189251Ssam } 846189251Ssam 847189251Ssam return 0; 848189251Ssam 849189251Ssamerr: 850189251Ssam if (conn->engine) { 851189251Ssam ENGINE_free(conn->engine); 852189251Ssam conn->engine = NULL; 853189251Ssam } 854189251Ssam 855189251Ssam if (conn->private_key) { 856189251Ssam EVP_PKEY_free(conn->private_key); 857189251Ssam conn->private_key = NULL; 858189251Ssam } 859189251Ssam 860189251Ssam return ret; 861189251Ssam#else /* OPENSSL_NO_ENGINE */ 862189251Ssam return 0; 863189251Ssam#endif /* OPENSSL_NO_ENGINE */ 864189251Ssam} 865189251Ssam 866189251Ssam 867189251Ssamstatic void tls_engine_deinit(struct tls_connection *conn) 868189251Ssam{ 869189251Ssam#ifndef OPENSSL_NO_ENGINE 870189251Ssam wpa_printf(MSG_DEBUG, "ENGINE: engine deinit"); 871189251Ssam if (conn->private_key) { 872189251Ssam EVP_PKEY_free(conn->private_key); 873189251Ssam conn->private_key = NULL; 874189251Ssam } 875189251Ssam if (conn->engine) { 876189251Ssam ENGINE_finish(conn->engine); 877189251Ssam conn->engine = NULL; 878189251Ssam } 879189251Ssam#endif /* OPENSSL_NO_ENGINE */ 880189251Ssam} 881189251Ssam 882189251Ssam 883189251Ssamint tls_get_errors(void *ssl_ctx) 884189251Ssam{ 885189251Ssam int count = 0; 886189251Ssam unsigned long err; 887189251Ssam 888189251Ssam while ((err = ERR_get_error())) { 889189251Ssam wpa_printf(MSG_INFO, "TLS - SSL error: %s", 890189251Ssam ERR_error_string(err, NULL)); 891189251Ssam count++; 892189251Ssam } 893189251Ssam 894189251Ssam return count; 895189251Ssam} 896189251Ssam 897189251Ssamstruct tls_connection * tls_connection_init(void *ssl_ctx) 898189251Ssam{ 899189251Ssam SSL_CTX *ssl = ssl_ctx; 900189251Ssam struct tls_connection *conn; 901189251Ssam long options; 902189251Ssam 903189251Ssam conn = os_zalloc(sizeof(*conn)); 904189251Ssam if (conn == NULL) 905189251Ssam return NULL; 906189251Ssam conn->ssl = SSL_new(ssl); 907189251Ssam if (conn->ssl == NULL) { 908189251Ssam tls_show_errors(MSG_INFO, __func__, 909189251Ssam "Failed to initialize new SSL connection"); 910189251Ssam os_free(conn); 911189251Ssam return NULL; 912189251Ssam } 913189251Ssam 914189251Ssam SSL_set_app_data(conn->ssl, conn); 915189251Ssam options = SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3 | 916189251Ssam SSL_OP_SINGLE_DH_USE; 917189251Ssam#ifdef SSL_OP_NO_COMPRESSION 918189251Ssam options |= SSL_OP_NO_COMPRESSION; 919189251Ssam#endif /* SSL_OP_NO_COMPRESSION */ 920189251Ssam SSL_set_options(conn->ssl, options); 921189251Ssam 922189251Ssam conn->ssl_in = BIO_new(BIO_s_mem()); 923189251Ssam if (!conn->ssl_in) { 924189251Ssam tls_show_errors(MSG_INFO, __func__, 925189251Ssam "Failed to create a new BIO for ssl_in"); 926189251Ssam SSL_free(conn->ssl); 927189251Ssam os_free(conn); 928189251Ssam return NULL; 929189251Ssam } 930189251Ssam 931189251Ssam conn->ssl_out = BIO_new(BIO_s_mem()); 932189251Ssam if (!conn->ssl_out) { 933189251Ssam tls_show_errors(MSG_INFO, __func__, 934189251Ssam "Failed to create a new BIO for ssl_out"); 935189251Ssam SSL_free(conn->ssl); 936189251Ssam BIO_free(conn->ssl_in); 937189251Ssam os_free(conn); 938189251Ssam return NULL; 939189251Ssam } 940189251Ssam 941189251Ssam SSL_set_bio(conn->ssl, conn->ssl_in, conn->ssl_out); 942189251Ssam 943189251Ssam return conn; 944189251Ssam} 945189251Ssam 946189251Ssam 947189251Ssamvoid tls_connection_deinit(void *ssl_ctx, struct tls_connection *conn) 948189251Ssam{ 949189251Ssam if (conn == NULL) 950189251Ssam return; 951189251Ssam SSL_free(conn->ssl); 952189251Ssam tls_engine_deinit(conn); 953189251Ssam os_free(conn->subject_match); 954189251Ssam os_free(conn->altsubject_match); 955189251Ssam os_free(conn->session_ticket); 956189251Ssam os_free(conn); 957189251Ssam} 958189251Ssam 959189251Ssam 960189251Ssamint tls_connection_established(void *ssl_ctx, struct tls_connection *conn) 961189251Ssam{ 962189251Ssam return conn ? SSL_is_init_finished(conn->ssl) : 0; 963189251Ssam} 964189251Ssam 965189251Ssam 966189251Ssamint tls_connection_shutdown(void *ssl_ctx, struct tls_connection *conn) 967189251Ssam{ 968189251Ssam if (conn == NULL) 969189251Ssam return -1; 970189251Ssam 971189251Ssam /* Shutdown previous TLS connection without notifying the peer 972189251Ssam * because the connection was already terminated in practice 973189251Ssam * and "close notify" shutdown alert would confuse AS. */ 974189251Ssam SSL_set_quiet_shutdown(conn->ssl, 1); 975189251Ssam SSL_shutdown(conn->ssl); 976189251Ssam return 0; 977189251Ssam} 978189251Ssam 979189251Ssam 980189251Ssamstatic int tls_match_altsubject_component(X509 *cert, int type, 981189251Ssam const char *value, size_t len) 982189251Ssam{ 983189251Ssam GENERAL_NAME *gen; 984189251Ssam void *ext; 985189251Ssam int i, found = 0; 986189251Ssam 987189251Ssam ext = X509_get_ext_d2i(cert, NID_subject_alt_name, NULL, NULL); 988189251Ssam 989189251Ssam for (i = 0; ext && i < sk_GENERAL_NAME_num(ext); i++) { 990189251Ssam gen = sk_GENERAL_NAME_value(ext, i); 991189251Ssam if (gen->type != type) 992189251Ssam continue; 993189251Ssam if (os_strlen((char *) gen->d.ia5->data) == len && 994189251Ssam os_memcmp(value, gen->d.ia5->data, len) == 0) 995189251Ssam found++; 996189251Ssam } 997189251Ssam 998189251Ssam return found; 999189251Ssam} 1000189251Ssam 1001189251Ssam 1002189251Ssamstatic int tls_match_altsubject(X509 *cert, const char *match) 1003189251Ssam{ 1004189251Ssam int type; 1005189251Ssam const char *pos, *end; 1006189251Ssam size_t len; 1007189251Ssam 1008189251Ssam pos = match; 1009189251Ssam do { 1010189251Ssam if (os_strncmp(pos, "EMAIL:", 6) == 0) { 1011189251Ssam type = GEN_EMAIL; 1012189251Ssam pos += 6; 1013189251Ssam } else if (os_strncmp(pos, "DNS:", 4) == 0) { 1014189251Ssam type = GEN_DNS; 1015189251Ssam pos += 4; 1016189251Ssam } else if (os_strncmp(pos, "URI:", 4) == 0) { 1017189251Ssam type = GEN_URI; 1018189251Ssam pos += 4; 1019189251Ssam } else { 1020189251Ssam wpa_printf(MSG_INFO, "TLS: Invalid altSubjectName " 1021189251Ssam "match '%s'", pos); 1022189251Ssam return 0; 1023189251Ssam } 1024189251Ssam end = os_strchr(pos, ';'); 1025189251Ssam while (end) { 1026189251Ssam if (os_strncmp(end + 1, "EMAIL:", 6) == 0 || 1027189251Ssam os_strncmp(end + 1, "DNS:", 4) == 0 || 1028189251Ssam os_strncmp(end + 1, "URI:", 4) == 0) 1029189251Ssam break; 1030189251Ssam end = os_strchr(end + 1, ';'); 1031189251Ssam } 1032189251Ssam if (end) 1033189251Ssam len = end - pos; 1034189251Ssam else 1035189251Ssam len = os_strlen(pos); 1036189251Ssam if (tls_match_altsubject_component(cert, type, pos, len) > 0) 1037189251Ssam return 1; 1038189251Ssam pos = end + 1; 1039189251Ssam } while (end); 1040189251Ssam 1041189251Ssam return 0; 1042189251Ssam} 1043189251Ssam 1044189251Ssam 1045214734Srpaulostatic enum tls_fail_reason openssl_tls_fail_reason(int err) 1046214734Srpaulo{ 1047214734Srpaulo switch (err) { 1048214734Srpaulo case X509_V_ERR_CERT_REVOKED: 1049214734Srpaulo return TLS_FAIL_REVOKED; 1050214734Srpaulo case X509_V_ERR_CERT_NOT_YET_VALID: 1051214734Srpaulo case X509_V_ERR_CRL_NOT_YET_VALID: 1052214734Srpaulo return TLS_FAIL_NOT_YET_VALID; 1053214734Srpaulo case X509_V_ERR_CERT_HAS_EXPIRED: 1054214734Srpaulo case X509_V_ERR_CRL_HAS_EXPIRED: 1055214734Srpaulo return TLS_FAIL_EXPIRED; 1056214734Srpaulo case X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT: 1057214734Srpaulo case X509_V_ERR_UNABLE_TO_GET_CRL: 1058214734Srpaulo case X509_V_ERR_UNABLE_TO_GET_CRL_ISSUER: 1059214734Srpaulo case X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN: 1060214734Srpaulo case X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY: 1061214734Srpaulo case X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT: 1062214734Srpaulo case X509_V_ERR_UNABLE_TO_VERIFY_LEAF_SIGNATURE: 1063214734Srpaulo case X509_V_ERR_CERT_CHAIN_TOO_LONG: 1064214734Srpaulo case X509_V_ERR_PATH_LENGTH_EXCEEDED: 1065214734Srpaulo case X509_V_ERR_INVALID_CA: 1066214734Srpaulo return TLS_FAIL_UNTRUSTED; 1067214734Srpaulo case X509_V_ERR_UNABLE_TO_DECRYPT_CERT_SIGNATURE: 1068214734Srpaulo case X509_V_ERR_UNABLE_TO_DECRYPT_CRL_SIGNATURE: 1069214734Srpaulo case X509_V_ERR_UNABLE_TO_DECODE_ISSUER_PUBLIC_KEY: 1070214734Srpaulo case X509_V_ERR_ERROR_IN_CERT_NOT_BEFORE_FIELD: 1071214734Srpaulo case X509_V_ERR_ERROR_IN_CERT_NOT_AFTER_FIELD: 1072214734Srpaulo case X509_V_ERR_ERROR_IN_CRL_LAST_UPDATE_FIELD: 1073214734Srpaulo case X509_V_ERR_ERROR_IN_CRL_NEXT_UPDATE_FIELD: 1074214734Srpaulo case X509_V_ERR_CERT_UNTRUSTED: 1075214734Srpaulo case X509_V_ERR_CERT_REJECTED: 1076214734Srpaulo return TLS_FAIL_BAD_CERTIFICATE; 1077214734Srpaulo default: 1078214734Srpaulo return TLS_FAIL_UNSPECIFIED; 1079214734Srpaulo } 1080214734Srpaulo} 1081214734Srpaulo 1082214734Srpaulo 1083214734Srpaulostatic struct wpabuf * get_x509_cert(X509 *cert) 1084214734Srpaulo{ 1085214734Srpaulo struct wpabuf *buf; 1086214734Srpaulo u8 *tmp; 1087214734Srpaulo 1088214734Srpaulo int cert_len = i2d_X509(cert, NULL); 1089214734Srpaulo if (cert_len <= 0) 1090214734Srpaulo return NULL; 1091214734Srpaulo 1092214734Srpaulo buf = wpabuf_alloc(cert_len); 1093214734Srpaulo if (buf == NULL) 1094214734Srpaulo return NULL; 1095214734Srpaulo 1096214734Srpaulo tmp = wpabuf_put(buf, cert_len); 1097214734Srpaulo i2d_X509(cert, &tmp); 1098214734Srpaulo return buf; 1099214734Srpaulo} 1100214734Srpaulo 1101214734Srpaulo 1102214734Srpaulostatic void openssl_tls_fail_event(struct tls_connection *conn, 1103214734Srpaulo X509 *err_cert, int err, int depth, 1104214734Srpaulo const char *subject, const char *err_str, 1105214734Srpaulo enum tls_fail_reason reason) 1106214734Srpaulo{ 1107214734Srpaulo union tls_event_data ev; 1108214734Srpaulo struct wpabuf *cert = NULL; 1109214734Srpaulo 1110214734Srpaulo if (tls_global->event_cb == NULL) 1111214734Srpaulo return; 1112214734Srpaulo 1113214734Srpaulo cert = get_x509_cert(err_cert); 1114214734Srpaulo os_memset(&ev, 0, sizeof(ev)); 1115214734Srpaulo ev.cert_fail.reason = reason != TLS_FAIL_UNSPECIFIED ? 1116214734Srpaulo reason : openssl_tls_fail_reason(err); 1117214734Srpaulo ev.cert_fail.depth = depth; 1118214734Srpaulo ev.cert_fail.subject = subject; 1119214734Srpaulo ev.cert_fail.reason_txt = err_str; 1120214734Srpaulo ev.cert_fail.cert = cert; 1121214734Srpaulo tls_global->event_cb(tls_global->cb_ctx, TLS_CERT_CHAIN_FAILURE, &ev); 1122214734Srpaulo wpabuf_free(cert); 1123214734Srpaulo} 1124214734Srpaulo 1125214734Srpaulo 1126214734Srpaulostatic void openssl_tls_cert_event(struct tls_connection *conn, 1127214734Srpaulo X509 *err_cert, int depth, 1128214734Srpaulo const char *subject) 1129214734Srpaulo{ 1130214734Srpaulo struct wpabuf *cert = NULL; 1131214734Srpaulo union tls_event_data ev; 1132214734Srpaulo#ifdef CONFIG_SHA256 1133214734Srpaulo u8 hash[32]; 1134214734Srpaulo#endif /* CONFIG_SHA256 */ 1135214734Srpaulo 1136214734Srpaulo if (tls_global->event_cb == NULL) 1137214734Srpaulo return; 1138214734Srpaulo 1139214734Srpaulo os_memset(&ev, 0, sizeof(ev)); 1140214734Srpaulo if (conn->cert_probe) { 1141214734Srpaulo cert = get_x509_cert(err_cert); 1142214734Srpaulo ev.peer_cert.cert = cert; 1143214734Srpaulo } 1144214734Srpaulo#ifdef CONFIG_SHA256 1145214734Srpaulo if (cert) { 1146214734Srpaulo const u8 *addr[1]; 1147214734Srpaulo size_t len[1]; 1148214734Srpaulo addr[0] = wpabuf_head(cert); 1149214734Srpaulo len[0] = wpabuf_len(cert); 1150214734Srpaulo if (sha256_vector(1, addr, len, hash) == 0) { 1151214734Srpaulo ev.peer_cert.hash = hash; 1152214734Srpaulo ev.peer_cert.hash_len = sizeof(hash); 1153214734Srpaulo } 1154214734Srpaulo } 1155214734Srpaulo#endif /* CONFIG_SHA256 */ 1156214734Srpaulo ev.peer_cert.depth = depth; 1157214734Srpaulo ev.peer_cert.subject = subject; 1158214734Srpaulo tls_global->event_cb(tls_global->cb_ctx, TLS_PEER_CERTIFICATE, &ev); 1159214734Srpaulo wpabuf_free(cert); 1160214734Srpaulo} 1161214734Srpaulo 1162214734Srpaulo 1163189251Ssamstatic int tls_verify_cb(int preverify_ok, X509_STORE_CTX *x509_ctx) 1164189251Ssam{ 1165189251Ssam char buf[256]; 1166189251Ssam X509 *err_cert; 1167189251Ssam int err, depth; 1168189251Ssam SSL *ssl; 1169189251Ssam struct tls_connection *conn; 1170189251Ssam char *match, *altmatch; 1171214734Srpaulo const char *err_str; 1172189251Ssam 1173189251Ssam err_cert = X509_STORE_CTX_get_current_cert(x509_ctx); 1174189251Ssam err = X509_STORE_CTX_get_error(x509_ctx); 1175189251Ssam depth = X509_STORE_CTX_get_error_depth(x509_ctx); 1176189251Ssam ssl = X509_STORE_CTX_get_ex_data(x509_ctx, 1177189251Ssam SSL_get_ex_data_X509_STORE_CTX_idx()); 1178189251Ssam X509_NAME_oneline(X509_get_subject_name(err_cert), buf, sizeof(buf)); 1179189251Ssam 1180189251Ssam conn = SSL_get_app_data(ssl); 1181189251Ssam match = conn ? conn->subject_match : NULL; 1182189251Ssam altmatch = conn ? conn->altsubject_match : NULL; 1183189251Ssam 1184214734Srpaulo if (!preverify_ok && !conn->ca_cert_verify) 1185214734Srpaulo preverify_ok = 1; 1186214734Srpaulo if (!preverify_ok && depth > 0 && conn->server_cert_only) 1187214734Srpaulo preverify_ok = 1; 1188214734Srpaulo 1189214734Srpaulo err_str = X509_verify_cert_error_string(err); 1190214734Srpaulo 1191214734Srpaulo#ifdef CONFIG_SHA256 1192214734Srpaulo if (preverify_ok && depth == 0 && conn->server_cert_only) { 1193214734Srpaulo struct wpabuf *cert; 1194214734Srpaulo cert = get_x509_cert(err_cert); 1195214734Srpaulo if (!cert) { 1196214734Srpaulo wpa_printf(MSG_DEBUG, "OpenSSL: Could not fetch " 1197214734Srpaulo "server certificate data"); 1198189251Ssam preverify_ok = 0; 1199214734Srpaulo } else { 1200214734Srpaulo u8 hash[32]; 1201214734Srpaulo const u8 *addr[1]; 1202214734Srpaulo size_t len[1]; 1203214734Srpaulo addr[0] = wpabuf_head(cert); 1204214734Srpaulo len[0] = wpabuf_len(cert); 1205214734Srpaulo if (sha256_vector(1, addr, len, hash) < 0 || 1206214734Srpaulo os_memcmp(conn->srv_cert_hash, hash, 32) != 0) { 1207214734Srpaulo err_str = "Server certificate mismatch"; 1208214734Srpaulo err = X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN; 1209214734Srpaulo preverify_ok = 0; 1210214734Srpaulo } 1211214734Srpaulo wpabuf_free(cert); 1212189251Ssam } 1213189251Ssam } 1214214734Srpaulo#endif /* CONFIG_SHA256 */ 1215189251Ssam 1216214734Srpaulo if (!preverify_ok) { 1217214734Srpaulo wpa_printf(MSG_WARNING, "TLS: Certificate verification failed," 1218214734Srpaulo " error %d (%s) depth %d for '%s'", err, err_str, 1219214734Srpaulo depth, buf); 1220214734Srpaulo openssl_tls_fail_event(conn, err_cert, err, depth, buf, 1221214734Srpaulo err_str, TLS_FAIL_UNSPECIFIED); 1222214734Srpaulo return preverify_ok; 1223214734Srpaulo } 1224214734Srpaulo 1225214734Srpaulo wpa_printf(MSG_DEBUG, "TLS: tls_verify_cb - preverify_ok=%d " 1226214734Srpaulo "err=%d (%s) ca_cert_verify=%d depth=%d buf='%s'", 1227214734Srpaulo preverify_ok, err, err_str, 1228214734Srpaulo conn->ca_cert_verify, depth, buf); 1229214734Srpaulo if (depth == 0 && match && os_strstr(buf, match) == NULL) { 1230214734Srpaulo wpa_printf(MSG_WARNING, "TLS: Subject '%s' did not " 1231214734Srpaulo "match with '%s'", buf, match); 1232214734Srpaulo preverify_ok = 0; 1233214734Srpaulo openssl_tls_fail_event(conn, err_cert, err, depth, buf, 1234214734Srpaulo "Subject mismatch", 1235214734Srpaulo TLS_FAIL_SUBJECT_MISMATCH); 1236214734Srpaulo } else if (depth == 0 && altmatch && 1237214734Srpaulo !tls_match_altsubject(err_cert, altmatch)) { 1238214734Srpaulo wpa_printf(MSG_WARNING, "TLS: altSubjectName match " 1239214734Srpaulo "'%s' not found", altmatch); 1240214734Srpaulo preverify_ok = 0; 1241214734Srpaulo openssl_tls_fail_event(conn, err_cert, err, depth, buf, 1242214734Srpaulo "AltSubject mismatch", 1243214734Srpaulo TLS_FAIL_ALTSUBJECT_MISMATCH); 1244214734Srpaulo } else 1245214734Srpaulo openssl_tls_cert_event(conn, err_cert, depth, buf); 1246214734Srpaulo 1247214734Srpaulo if (conn->cert_probe && preverify_ok && depth == 0) { 1248214734Srpaulo wpa_printf(MSG_DEBUG, "OpenSSL: Reject server certificate " 1249214734Srpaulo "on probe-only run"); 1250214734Srpaulo preverify_ok = 0; 1251214734Srpaulo openssl_tls_fail_event(conn, err_cert, err, depth, buf, 1252214734Srpaulo "Server certificate chain probe", 1253214734Srpaulo TLS_FAIL_SERVER_CHAIN_PROBE); 1254214734Srpaulo } 1255214734Srpaulo 1256189251Ssam return preverify_ok; 1257189251Ssam} 1258189251Ssam 1259189251Ssam 1260189251Ssam#ifndef OPENSSL_NO_STDIO 1261189251Ssamstatic int tls_load_ca_der(void *_ssl_ctx, const char *ca_cert) 1262189251Ssam{ 1263189251Ssam SSL_CTX *ssl_ctx = _ssl_ctx; 1264189251Ssam X509_LOOKUP *lookup; 1265189251Ssam int ret = 0; 1266189251Ssam 1267189251Ssam lookup = X509_STORE_add_lookup(ssl_ctx->cert_store, 1268189251Ssam X509_LOOKUP_file()); 1269189251Ssam if (lookup == NULL) { 1270189251Ssam tls_show_errors(MSG_WARNING, __func__, 1271189251Ssam "Failed add lookup for X509 store"); 1272189251Ssam return -1; 1273189251Ssam } 1274189251Ssam 1275189251Ssam if (!X509_LOOKUP_load_file(lookup, ca_cert, X509_FILETYPE_ASN1)) { 1276189251Ssam unsigned long err = ERR_peek_error(); 1277189251Ssam tls_show_errors(MSG_WARNING, __func__, 1278189251Ssam "Failed load CA in DER format"); 1279189251Ssam if (ERR_GET_LIB(err) == ERR_LIB_X509 && 1280189251Ssam ERR_GET_REASON(err) == X509_R_CERT_ALREADY_IN_HASH_TABLE) { 1281189251Ssam wpa_printf(MSG_DEBUG, "OpenSSL: %s - ignoring " 1282189251Ssam "cert already in hash table error", 1283189251Ssam __func__); 1284189251Ssam } else 1285189251Ssam ret = -1; 1286189251Ssam } 1287189251Ssam 1288189251Ssam return ret; 1289189251Ssam} 1290189251Ssam#endif /* OPENSSL_NO_STDIO */ 1291189251Ssam 1292189251Ssam 1293189251Ssamstatic int tls_connection_ca_cert(void *_ssl_ctx, struct tls_connection *conn, 1294189251Ssam const char *ca_cert, const u8 *ca_cert_blob, 1295189251Ssam size_t ca_cert_blob_len, const char *ca_path) 1296189251Ssam{ 1297189251Ssam SSL_CTX *ssl_ctx = _ssl_ctx; 1298189251Ssam 1299189251Ssam /* 1300189251Ssam * Remove previously configured trusted CA certificates before adding 1301189251Ssam * new ones. 1302189251Ssam */ 1303189251Ssam X509_STORE_free(ssl_ctx->cert_store); 1304189251Ssam ssl_ctx->cert_store = X509_STORE_new(); 1305189251Ssam if (ssl_ctx->cert_store == NULL) { 1306189251Ssam wpa_printf(MSG_DEBUG, "OpenSSL: %s - failed to allocate new " 1307189251Ssam "certificate store", __func__); 1308189251Ssam return -1; 1309189251Ssam } 1310189251Ssam 1311214734Srpaulo SSL_set_verify(conn->ssl, SSL_VERIFY_PEER, tls_verify_cb); 1312214734Srpaulo conn->ca_cert_verify = 1; 1313214734Srpaulo 1314214734Srpaulo if (ca_cert && os_strncmp(ca_cert, "probe://", 8) == 0) { 1315214734Srpaulo wpa_printf(MSG_DEBUG, "OpenSSL: Probe for server certificate " 1316214734Srpaulo "chain"); 1317214734Srpaulo conn->cert_probe = 1; 1318214734Srpaulo conn->ca_cert_verify = 0; 1319214734Srpaulo return 0; 1320214734Srpaulo } 1321214734Srpaulo 1322214734Srpaulo if (ca_cert && os_strncmp(ca_cert, "hash://", 7) == 0) { 1323214734Srpaulo#ifdef CONFIG_SHA256 1324214734Srpaulo const char *pos = ca_cert + 7; 1325214734Srpaulo if (os_strncmp(pos, "server/sha256/", 14) != 0) { 1326214734Srpaulo wpa_printf(MSG_DEBUG, "OpenSSL: Unsupported ca_cert " 1327214734Srpaulo "hash value '%s'", ca_cert); 1328214734Srpaulo return -1; 1329214734Srpaulo } 1330214734Srpaulo pos += 14; 1331214734Srpaulo if (os_strlen(pos) != 32 * 2) { 1332214734Srpaulo wpa_printf(MSG_DEBUG, "OpenSSL: Unexpected SHA256 " 1333214734Srpaulo "hash length in ca_cert '%s'", ca_cert); 1334214734Srpaulo return -1; 1335214734Srpaulo } 1336214734Srpaulo if (hexstr2bin(pos, conn->srv_cert_hash, 32) < 0) { 1337214734Srpaulo wpa_printf(MSG_DEBUG, "OpenSSL: Invalid SHA256 hash " 1338214734Srpaulo "value in ca_cert '%s'", ca_cert); 1339214734Srpaulo return -1; 1340214734Srpaulo } 1341214734Srpaulo conn->server_cert_only = 1; 1342214734Srpaulo wpa_printf(MSG_DEBUG, "OpenSSL: Checking only server " 1343214734Srpaulo "certificate match"); 1344214734Srpaulo return 0; 1345214734Srpaulo#else /* CONFIG_SHA256 */ 1346214734Srpaulo wpa_printf(MSG_INFO, "No SHA256 included in the build - " 1347214734Srpaulo "cannot validate server certificate hash"); 1348214734Srpaulo return -1; 1349214734Srpaulo#endif /* CONFIG_SHA256 */ 1350214734Srpaulo } 1351214734Srpaulo 1352189251Ssam if (ca_cert_blob) { 1353189251Ssam X509 *cert = d2i_X509(NULL, (OPENSSL_d2i_TYPE) &ca_cert_blob, 1354189251Ssam ca_cert_blob_len); 1355189251Ssam if (cert == NULL) { 1356189251Ssam tls_show_errors(MSG_WARNING, __func__, 1357189251Ssam "Failed to parse ca_cert_blob"); 1358189251Ssam return -1; 1359189251Ssam } 1360189251Ssam 1361189251Ssam if (!X509_STORE_add_cert(ssl_ctx->cert_store, cert)) { 1362189251Ssam unsigned long err = ERR_peek_error(); 1363189251Ssam tls_show_errors(MSG_WARNING, __func__, 1364189251Ssam "Failed to add ca_cert_blob to " 1365189251Ssam "certificate store"); 1366189251Ssam if (ERR_GET_LIB(err) == ERR_LIB_X509 && 1367189251Ssam ERR_GET_REASON(err) == 1368189251Ssam X509_R_CERT_ALREADY_IN_HASH_TABLE) { 1369189251Ssam wpa_printf(MSG_DEBUG, "OpenSSL: %s - ignoring " 1370189251Ssam "cert already in hash table error", 1371189251Ssam __func__); 1372189251Ssam } else { 1373189251Ssam X509_free(cert); 1374189251Ssam return -1; 1375189251Ssam } 1376189251Ssam } 1377189251Ssam X509_free(cert); 1378189251Ssam wpa_printf(MSG_DEBUG, "OpenSSL: %s - added ca_cert_blob " 1379189251Ssam "to certificate store", __func__); 1380189251Ssam return 0; 1381189251Ssam } 1382189251Ssam 1383189251Ssam#ifdef CONFIG_NATIVE_WINDOWS 1384189251Ssam if (ca_cert && tls_cryptoapi_ca_cert(ssl_ctx, conn->ssl, ca_cert) == 1385189251Ssam 0) { 1386189251Ssam wpa_printf(MSG_DEBUG, "OpenSSL: Added CA certificates from " 1387189251Ssam "system certificate store"); 1388189251Ssam return 0; 1389189251Ssam } 1390189251Ssam#endif /* CONFIG_NATIVE_WINDOWS */ 1391189251Ssam 1392189251Ssam if (ca_cert || ca_path) { 1393189251Ssam#ifndef OPENSSL_NO_STDIO 1394189251Ssam if (SSL_CTX_load_verify_locations(ssl_ctx, ca_cert, ca_path) != 1395189251Ssam 1) { 1396189251Ssam tls_show_errors(MSG_WARNING, __func__, 1397189251Ssam "Failed to load root certificates"); 1398189251Ssam if (ca_cert && 1399189251Ssam tls_load_ca_der(ssl_ctx, ca_cert) == 0) { 1400189251Ssam wpa_printf(MSG_DEBUG, "OpenSSL: %s - loaded " 1401189251Ssam "DER format CA certificate", 1402189251Ssam __func__); 1403189251Ssam } else 1404189251Ssam return -1; 1405189251Ssam } else { 1406189251Ssam wpa_printf(MSG_DEBUG, "TLS: Trusted root " 1407189251Ssam "certificate(s) loaded"); 1408189251Ssam tls_get_errors(ssl_ctx); 1409189251Ssam } 1410189251Ssam#else /* OPENSSL_NO_STDIO */ 1411189251Ssam wpa_printf(MSG_DEBUG, "OpenSSL: %s - OPENSSL_NO_STDIO", 1412189251Ssam __func__); 1413189251Ssam return -1; 1414189251Ssam#endif /* OPENSSL_NO_STDIO */ 1415189251Ssam } else { 1416189251Ssam /* No ca_cert configured - do not try to verify server 1417189251Ssam * certificate */ 1418214734Srpaulo conn->ca_cert_verify = 0; 1419189251Ssam } 1420189251Ssam 1421189251Ssam return 0; 1422189251Ssam} 1423189251Ssam 1424189251Ssam 1425189251Ssamstatic int tls_global_ca_cert(SSL_CTX *ssl_ctx, const char *ca_cert) 1426189251Ssam{ 1427189251Ssam if (ca_cert) { 1428189251Ssam if (SSL_CTX_load_verify_locations(ssl_ctx, ca_cert, NULL) != 1) 1429189251Ssam { 1430189251Ssam tls_show_errors(MSG_WARNING, __func__, 1431189251Ssam "Failed to load root certificates"); 1432189251Ssam return -1; 1433189251Ssam } 1434189251Ssam 1435189251Ssam wpa_printf(MSG_DEBUG, "TLS: Trusted root " 1436189251Ssam "certificate(s) loaded"); 1437189251Ssam 1438189251Ssam#ifndef OPENSSL_NO_STDIO 1439189251Ssam /* Add the same CAs to the client certificate requests */ 1440189251Ssam SSL_CTX_set_client_CA_list(ssl_ctx, 1441189251Ssam SSL_load_client_CA_file(ca_cert)); 1442189251Ssam#endif /* OPENSSL_NO_STDIO */ 1443189251Ssam } 1444189251Ssam 1445189251Ssam return 0; 1446189251Ssam} 1447189251Ssam 1448189251Ssam 1449189251Ssamint tls_global_set_verify(void *ssl_ctx, int check_crl) 1450189251Ssam{ 1451189251Ssam int flags; 1452189251Ssam 1453189251Ssam if (check_crl) { 1454189251Ssam X509_STORE *cs = SSL_CTX_get_cert_store(ssl_ctx); 1455189251Ssam if (cs == NULL) { 1456189251Ssam tls_show_errors(MSG_INFO, __func__, "Failed to get " 1457189251Ssam "certificate store when enabling " 1458189251Ssam "check_crl"); 1459189251Ssam return -1; 1460189251Ssam } 1461189251Ssam flags = X509_V_FLAG_CRL_CHECK; 1462189251Ssam if (check_crl == 2) 1463189251Ssam flags |= X509_V_FLAG_CRL_CHECK_ALL; 1464189251Ssam X509_STORE_set_flags(cs, flags); 1465189251Ssam } 1466189251Ssam return 0; 1467189251Ssam} 1468189251Ssam 1469189251Ssam 1470189251Ssamstatic int tls_connection_set_subject_match(struct tls_connection *conn, 1471189251Ssam const char *subject_match, 1472189251Ssam const char *altsubject_match) 1473189251Ssam{ 1474189251Ssam os_free(conn->subject_match); 1475189251Ssam conn->subject_match = NULL; 1476189251Ssam if (subject_match) { 1477189251Ssam conn->subject_match = os_strdup(subject_match); 1478189251Ssam if (conn->subject_match == NULL) 1479189251Ssam return -1; 1480189251Ssam } 1481189251Ssam 1482189251Ssam os_free(conn->altsubject_match); 1483189251Ssam conn->altsubject_match = NULL; 1484189251Ssam if (altsubject_match) { 1485189251Ssam conn->altsubject_match = os_strdup(altsubject_match); 1486189251Ssam if (conn->altsubject_match == NULL) 1487189251Ssam return -1; 1488189251Ssam } 1489189251Ssam 1490189251Ssam return 0; 1491189251Ssam} 1492189251Ssam 1493189251Ssam 1494189251Ssamint tls_connection_set_verify(void *ssl_ctx, struct tls_connection *conn, 1495189251Ssam int verify_peer) 1496189251Ssam{ 1497189251Ssam static int counter = 0; 1498189251Ssam 1499189251Ssam if (conn == NULL) 1500189251Ssam return -1; 1501189251Ssam 1502189251Ssam if (verify_peer) { 1503214734Srpaulo conn->ca_cert_verify = 1; 1504189251Ssam SSL_set_verify(conn->ssl, SSL_VERIFY_PEER | 1505189251Ssam SSL_VERIFY_FAIL_IF_NO_PEER_CERT | 1506189251Ssam SSL_VERIFY_CLIENT_ONCE, tls_verify_cb); 1507189251Ssam } else { 1508214734Srpaulo conn->ca_cert_verify = 0; 1509189251Ssam SSL_set_verify(conn->ssl, SSL_VERIFY_NONE, NULL); 1510189251Ssam } 1511189251Ssam 1512189251Ssam SSL_set_accept_state(conn->ssl); 1513189251Ssam 1514189251Ssam /* 1515189251Ssam * Set session id context in order to avoid fatal errors when client 1516189251Ssam * tries to resume a session. However, set the context to a unique 1517189251Ssam * value in order to effectively disable session resumption for now 1518189251Ssam * since not all areas of the server code are ready for it (e.g., 1519189251Ssam * EAP-TTLS needs special handling for Phase 2 after abbreviated TLS 1520189251Ssam * handshake). 1521189251Ssam */ 1522189251Ssam counter++; 1523189251Ssam SSL_set_session_id_context(conn->ssl, 1524189251Ssam (const unsigned char *) &counter, 1525189251Ssam sizeof(counter)); 1526189251Ssam 1527189251Ssam return 0; 1528189251Ssam} 1529189251Ssam 1530189251Ssam 1531189251Ssamstatic int tls_connection_client_cert(struct tls_connection *conn, 1532189251Ssam const char *client_cert, 1533189251Ssam const u8 *client_cert_blob, 1534189251Ssam size_t client_cert_blob_len) 1535189251Ssam{ 1536189251Ssam if (client_cert == NULL && client_cert_blob == NULL) 1537189251Ssam return 0; 1538189251Ssam 1539189251Ssam if (client_cert_blob && 1540189251Ssam SSL_use_certificate_ASN1(conn->ssl, (u8 *) client_cert_blob, 1541189251Ssam client_cert_blob_len) == 1) { 1542189251Ssam wpa_printf(MSG_DEBUG, "OpenSSL: SSL_use_certificate_ASN1 --> " 1543189251Ssam "OK"); 1544189251Ssam return 0; 1545189251Ssam } else if (client_cert_blob) { 1546189251Ssam tls_show_errors(MSG_DEBUG, __func__, 1547189251Ssam "SSL_use_certificate_ASN1 failed"); 1548189251Ssam } 1549189251Ssam 1550189251Ssam if (client_cert == NULL) 1551189251Ssam return -1; 1552189251Ssam 1553189251Ssam#ifndef OPENSSL_NO_STDIO 1554189251Ssam if (SSL_use_certificate_file(conn->ssl, client_cert, 1555189251Ssam SSL_FILETYPE_ASN1) == 1) { 1556189251Ssam wpa_printf(MSG_DEBUG, "OpenSSL: SSL_use_certificate_file (DER)" 1557189251Ssam " --> OK"); 1558189251Ssam return 0; 1559189251Ssam } else { 1560189251Ssam tls_show_errors(MSG_DEBUG, __func__, 1561189251Ssam "SSL_use_certificate_file (DER) failed"); 1562189251Ssam } 1563189251Ssam 1564189251Ssam if (SSL_use_certificate_file(conn->ssl, client_cert, 1565189251Ssam SSL_FILETYPE_PEM) == 1) { 1566189251Ssam wpa_printf(MSG_DEBUG, "OpenSSL: SSL_use_certificate_file (PEM)" 1567189251Ssam " --> OK"); 1568189251Ssam return 0; 1569189251Ssam } else { 1570189251Ssam tls_show_errors(MSG_DEBUG, __func__, 1571189251Ssam "SSL_use_certificate_file (PEM) failed"); 1572189251Ssam } 1573189251Ssam#else /* OPENSSL_NO_STDIO */ 1574189251Ssam wpa_printf(MSG_DEBUG, "OpenSSL: %s - OPENSSL_NO_STDIO", __func__); 1575189251Ssam#endif /* OPENSSL_NO_STDIO */ 1576189251Ssam 1577189251Ssam return -1; 1578189251Ssam} 1579189251Ssam 1580189251Ssam 1581189251Ssamstatic int tls_global_client_cert(SSL_CTX *ssl_ctx, const char *client_cert) 1582189251Ssam{ 1583189251Ssam#ifndef OPENSSL_NO_STDIO 1584189251Ssam if (client_cert == NULL) 1585189251Ssam return 0; 1586189251Ssam 1587189251Ssam if (SSL_CTX_use_certificate_file(ssl_ctx, client_cert, 1588189251Ssam SSL_FILETYPE_ASN1) != 1 && 1589189251Ssam SSL_CTX_use_certificate_file(ssl_ctx, client_cert, 1590189251Ssam SSL_FILETYPE_PEM) != 1) { 1591189251Ssam tls_show_errors(MSG_INFO, __func__, 1592189251Ssam "Failed to load client certificate"); 1593189251Ssam return -1; 1594189251Ssam } 1595189251Ssam return 0; 1596189251Ssam#else /* OPENSSL_NO_STDIO */ 1597189251Ssam if (client_cert == NULL) 1598189251Ssam return 0; 1599189251Ssam wpa_printf(MSG_DEBUG, "OpenSSL: %s - OPENSSL_NO_STDIO", __func__); 1600189251Ssam return -1; 1601189251Ssam#endif /* OPENSSL_NO_STDIO */ 1602189251Ssam} 1603189251Ssam 1604189251Ssam 1605189251Ssamstatic int tls_passwd_cb(char *buf, int size, int rwflag, void *password) 1606189251Ssam{ 1607189251Ssam if (password == NULL) { 1608189251Ssam return 0; 1609189251Ssam } 1610189251Ssam os_strlcpy(buf, (char *) password, size); 1611189251Ssam return os_strlen(buf); 1612189251Ssam} 1613189251Ssam 1614189251Ssam 1615189251Ssam#ifdef PKCS12_FUNCS 1616189251Ssamstatic int tls_parse_pkcs12(SSL_CTX *ssl_ctx, SSL *ssl, PKCS12 *p12, 1617189251Ssam const char *passwd) 1618189251Ssam{ 1619189251Ssam EVP_PKEY *pkey; 1620189251Ssam X509 *cert; 1621189251Ssam STACK_OF(X509) *certs; 1622189251Ssam int res = 0; 1623189251Ssam char buf[256]; 1624189251Ssam 1625189251Ssam pkey = NULL; 1626189251Ssam cert = NULL; 1627189251Ssam certs = NULL; 1628189251Ssam if (!PKCS12_parse(p12, passwd, &pkey, &cert, &certs)) { 1629189251Ssam tls_show_errors(MSG_DEBUG, __func__, 1630189251Ssam "Failed to parse PKCS12 file"); 1631189251Ssam PKCS12_free(p12); 1632189251Ssam return -1; 1633189251Ssam } 1634189251Ssam wpa_printf(MSG_DEBUG, "TLS: Successfully parsed PKCS12 data"); 1635189251Ssam 1636189251Ssam if (cert) { 1637189251Ssam X509_NAME_oneline(X509_get_subject_name(cert), buf, 1638189251Ssam sizeof(buf)); 1639189251Ssam wpa_printf(MSG_DEBUG, "TLS: Got certificate from PKCS12: " 1640189251Ssam "subject='%s'", buf); 1641189251Ssam if (ssl) { 1642189251Ssam if (SSL_use_certificate(ssl, cert) != 1) 1643189251Ssam res = -1; 1644189251Ssam } else { 1645189251Ssam if (SSL_CTX_use_certificate(ssl_ctx, cert) != 1) 1646189251Ssam res = -1; 1647189251Ssam } 1648189251Ssam X509_free(cert); 1649189251Ssam } 1650189251Ssam 1651189251Ssam if (pkey) { 1652189251Ssam wpa_printf(MSG_DEBUG, "TLS: Got private key from PKCS12"); 1653189251Ssam if (ssl) { 1654189251Ssam if (SSL_use_PrivateKey(ssl, pkey) != 1) 1655189251Ssam res = -1; 1656189251Ssam } else { 1657189251Ssam if (SSL_CTX_use_PrivateKey(ssl_ctx, pkey) != 1) 1658189251Ssam res = -1; 1659189251Ssam } 1660189251Ssam EVP_PKEY_free(pkey); 1661189251Ssam } 1662189251Ssam 1663189251Ssam if (certs) { 1664189251Ssam while ((cert = sk_X509_pop(certs)) != NULL) { 1665189251Ssam X509_NAME_oneline(X509_get_subject_name(cert), buf, 1666189251Ssam sizeof(buf)); 1667189251Ssam wpa_printf(MSG_DEBUG, "TLS: additional certificate" 1668189251Ssam " from PKCS12: subject='%s'", buf); 1669189251Ssam /* 1670189251Ssam * There is no SSL equivalent for the chain cert - so 1671189251Ssam * always add it to the context... 1672189251Ssam */ 1673189251Ssam if (SSL_CTX_add_extra_chain_cert(ssl_ctx, cert) != 1) { 1674189251Ssam res = -1; 1675189251Ssam break; 1676189251Ssam } 1677189251Ssam } 1678189251Ssam sk_X509_free(certs); 1679189251Ssam } 1680189251Ssam 1681189251Ssam PKCS12_free(p12); 1682189251Ssam 1683189251Ssam if (res < 0) 1684189251Ssam tls_get_errors(ssl_ctx); 1685189251Ssam 1686189251Ssam return res; 1687189251Ssam} 1688189251Ssam#endif /* PKCS12_FUNCS */ 1689189251Ssam 1690189251Ssam 1691189251Ssamstatic int tls_read_pkcs12(SSL_CTX *ssl_ctx, SSL *ssl, const char *private_key, 1692189251Ssam const char *passwd) 1693189251Ssam{ 1694189251Ssam#ifdef PKCS12_FUNCS 1695189251Ssam FILE *f; 1696189251Ssam PKCS12 *p12; 1697189251Ssam 1698189251Ssam f = fopen(private_key, "rb"); 1699189251Ssam if (f == NULL) 1700189251Ssam return -1; 1701189251Ssam 1702189251Ssam p12 = d2i_PKCS12_fp(f, NULL); 1703189251Ssam fclose(f); 1704189251Ssam 1705189251Ssam if (p12 == NULL) { 1706189251Ssam tls_show_errors(MSG_INFO, __func__, 1707189251Ssam "Failed to use PKCS#12 file"); 1708189251Ssam return -1; 1709189251Ssam } 1710189251Ssam 1711189251Ssam return tls_parse_pkcs12(ssl_ctx, ssl, p12, passwd); 1712189251Ssam 1713189251Ssam#else /* PKCS12_FUNCS */ 1714189251Ssam wpa_printf(MSG_INFO, "TLS: PKCS12 support disabled - cannot read " 1715189251Ssam "p12/pfx files"); 1716189251Ssam return -1; 1717189251Ssam#endif /* PKCS12_FUNCS */ 1718189251Ssam} 1719189251Ssam 1720189251Ssam 1721189251Ssamstatic int tls_read_pkcs12_blob(SSL_CTX *ssl_ctx, SSL *ssl, 1722189251Ssam const u8 *blob, size_t len, const char *passwd) 1723189251Ssam{ 1724189251Ssam#ifdef PKCS12_FUNCS 1725189251Ssam PKCS12 *p12; 1726189251Ssam 1727189251Ssam p12 = d2i_PKCS12(NULL, (OPENSSL_d2i_TYPE) &blob, len); 1728189251Ssam if (p12 == NULL) { 1729189251Ssam tls_show_errors(MSG_INFO, __func__, 1730189251Ssam "Failed to use PKCS#12 blob"); 1731189251Ssam return -1; 1732189251Ssam } 1733189251Ssam 1734189251Ssam return tls_parse_pkcs12(ssl_ctx, ssl, p12, passwd); 1735189251Ssam 1736189251Ssam#else /* PKCS12_FUNCS */ 1737189251Ssam wpa_printf(MSG_INFO, "TLS: PKCS12 support disabled - cannot parse " 1738189251Ssam "p12/pfx blobs"); 1739189251Ssam return -1; 1740189251Ssam#endif /* PKCS12_FUNCS */ 1741189251Ssam} 1742189251Ssam 1743189251Ssam 1744189251Ssam#ifndef OPENSSL_NO_ENGINE 1745189251Ssamstatic int tls_engine_get_cert(struct tls_connection *conn, 1746189251Ssam const char *cert_id, 1747189251Ssam X509 **cert) 1748189251Ssam{ 1749189251Ssam /* this runs after the private key is loaded so no PIN is required */ 1750189251Ssam struct { 1751189251Ssam const char *cert_id; 1752189251Ssam X509 *cert; 1753189251Ssam } params; 1754189251Ssam params.cert_id = cert_id; 1755189251Ssam params.cert = NULL; 1756189251Ssam 1757189251Ssam if (!ENGINE_ctrl_cmd(conn->engine, "LOAD_CERT_CTRL", 1758189251Ssam 0, ¶ms, NULL, 1)) { 1759189251Ssam wpa_printf(MSG_ERROR, "ENGINE: cannot load client cert with id" 1760189251Ssam " '%s' [%s]", cert_id, 1761189251Ssam ERR_error_string(ERR_get_error(), NULL)); 1762189251Ssam return TLS_SET_PARAMS_ENGINE_PRV_INIT_FAILED; 1763189251Ssam } 1764189251Ssam if (!params.cert) { 1765189251Ssam wpa_printf(MSG_ERROR, "ENGINE: did not properly cert with id" 1766189251Ssam " '%s'", cert_id); 1767189251Ssam return TLS_SET_PARAMS_ENGINE_PRV_INIT_FAILED; 1768189251Ssam } 1769189251Ssam *cert = params.cert; 1770189251Ssam return 0; 1771189251Ssam} 1772189251Ssam#endif /* OPENSSL_NO_ENGINE */ 1773189251Ssam 1774189251Ssam 1775189251Ssamstatic int tls_connection_engine_client_cert(struct tls_connection *conn, 1776189251Ssam const char *cert_id) 1777189251Ssam{ 1778189251Ssam#ifndef OPENSSL_NO_ENGINE 1779189251Ssam X509 *cert; 1780189251Ssam 1781189251Ssam if (tls_engine_get_cert(conn, cert_id, &cert)) 1782189251Ssam return -1; 1783189251Ssam 1784189251Ssam if (!SSL_use_certificate(conn->ssl, cert)) { 1785189251Ssam tls_show_errors(MSG_ERROR, __func__, 1786189251Ssam "SSL_use_certificate failed"); 1787189251Ssam X509_free(cert); 1788189251Ssam return -1; 1789189251Ssam } 1790189251Ssam X509_free(cert); 1791189251Ssam wpa_printf(MSG_DEBUG, "ENGINE: SSL_use_certificate --> " 1792189251Ssam "OK"); 1793189251Ssam return 0; 1794189251Ssam 1795189251Ssam#else /* OPENSSL_NO_ENGINE */ 1796189251Ssam return -1; 1797189251Ssam#endif /* OPENSSL_NO_ENGINE */ 1798189251Ssam} 1799189251Ssam 1800189251Ssam 1801189251Ssamstatic int tls_connection_engine_ca_cert(void *_ssl_ctx, 1802189251Ssam struct tls_connection *conn, 1803189251Ssam const char *ca_cert_id) 1804189251Ssam{ 1805189251Ssam#ifndef OPENSSL_NO_ENGINE 1806189251Ssam X509 *cert; 1807189251Ssam SSL_CTX *ssl_ctx = _ssl_ctx; 1808189251Ssam 1809189251Ssam if (tls_engine_get_cert(conn, ca_cert_id, &cert)) 1810189251Ssam return -1; 1811189251Ssam 1812189251Ssam /* start off the same as tls_connection_ca_cert */ 1813189251Ssam X509_STORE_free(ssl_ctx->cert_store); 1814189251Ssam ssl_ctx->cert_store = X509_STORE_new(); 1815189251Ssam if (ssl_ctx->cert_store == NULL) { 1816189251Ssam wpa_printf(MSG_DEBUG, "OpenSSL: %s - failed to allocate new " 1817189251Ssam "certificate store", __func__); 1818189251Ssam X509_free(cert); 1819189251Ssam return -1; 1820189251Ssam } 1821189251Ssam if (!X509_STORE_add_cert(ssl_ctx->cert_store, cert)) { 1822189251Ssam unsigned long err = ERR_peek_error(); 1823189251Ssam tls_show_errors(MSG_WARNING, __func__, 1824189251Ssam "Failed to add CA certificate from engine " 1825189251Ssam "to certificate store"); 1826189251Ssam if (ERR_GET_LIB(err) == ERR_LIB_X509 && 1827189251Ssam ERR_GET_REASON(err) == X509_R_CERT_ALREADY_IN_HASH_TABLE) { 1828189251Ssam wpa_printf(MSG_DEBUG, "OpenSSL: %s - ignoring cert" 1829189251Ssam " already in hash table error", 1830189251Ssam __func__); 1831189251Ssam } else { 1832189251Ssam X509_free(cert); 1833189251Ssam return -1; 1834189251Ssam } 1835189251Ssam } 1836189251Ssam X509_free(cert); 1837189251Ssam wpa_printf(MSG_DEBUG, "OpenSSL: %s - added CA certificate from engine " 1838189251Ssam "to certificate store", __func__); 1839189251Ssam SSL_set_verify(conn->ssl, SSL_VERIFY_PEER, tls_verify_cb); 1840189251Ssam return 0; 1841189251Ssam 1842189251Ssam#else /* OPENSSL_NO_ENGINE */ 1843189251Ssam return -1; 1844189251Ssam#endif /* OPENSSL_NO_ENGINE */ 1845189251Ssam} 1846189251Ssam 1847189251Ssam 1848189251Ssamstatic int tls_connection_engine_private_key(struct tls_connection *conn) 1849189251Ssam{ 1850189251Ssam#ifndef OPENSSL_NO_ENGINE 1851189251Ssam if (SSL_use_PrivateKey(conn->ssl, conn->private_key) != 1) { 1852189251Ssam tls_show_errors(MSG_ERROR, __func__, 1853189251Ssam "ENGINE: cannot use private key for TLS"); 1854189251Ssam return -1; 1855189251Ssam } 1856189251Ssam if (!SSL_check_private_key(conn->ssl)) { 1857189251Ssam tls_show_errors(MSG_INFO, __func__, 1858189251Ssam "Private key failed verification"); 1859189251Ssam return -1; 1860189251Ssam } 1861189251Ssam return 0; 1862189251Ssam#else /* OPENSSL_NO_ENGINE */ 1863189251Ssam wpa_printf(MSG_ERROR, "SSL: Configuration uses engine, but " 1864189251Ssam "engine support was not compiled in"); 1865189251Ssam return -1; 1866189251Ssam#endif /* OPENSSL_NO_ENGINE */ 1867189251Ssam} 1868189251Ssam 1869189251Ssam 1870189251Ssamstatic int tls_connection_private_key(void *_ssl_ctx, 1871189251Ssam struct tls_connection *conn, 1872189251Ssam const char *private_key, 1873189251Ssam const char *private_key_passwd, 1874189251Ssam const u8 *private_key_blob, 1875189251Ssam size_t private_key_blob_len) 1876189251Ssam{ 1877189251Ssam SSL_CTX *ssl_ctx = _ssl_ctx; 1878189251Ssam char *passwd; 1879189251Ssam int ok; 1880189251Ssam 1881189251Ssam if (private_key == NULL && private_key_blob == NULL) 1882189251Ssam return 0; 1883189251Ssam 1884189251Ssam if (private_key_passwd) { 1885189251Ssam passwd = os_strdup(private_key_passwd); 1886189251Ssam if (passwd == NULL) 1887189251Ssam return -1; 1888189251Ssam } else 1889189251Ssam passwd = NULL; 1890189251Ssam 1891189251Ssam SSL_CTX_set_default_passwd_cb(ssl_ctx, tls_passwd_cb); 1892189251Ssam SSL_CTX_set_default_passwd_cb_userdata(ssl_ctx, passwd); 1893189251Ssam 1894189251Ssam ok = 0; 1895189251Ssam while (private_key_blob) { 1896189251Ssam if (SSL_use_PrivateKey_ASN1(EVP_PKEY_RSA, conn->ssl, 1897189251Ssam (u8 *) private_key_blob, 1898189251Ssam private_key_blob_len) == 1) { 1899189251Ssam wpa_printf(MSG_DEBUG, "OpenSSL: SSL_use_PrivateKey_" 1900189251Ssam "ASN1(EVP_PKEY_RSA) --> OK"); 1901189251Ssam ok = 1; 1902189251Ssam break; 1903189251Ssam } else { 1904189251Ssam tls_show_errors(MSG_DEBUG, __func__, 1905189251Ssam "SSL_use_PrivateKey_ASN1(EVP_PKEY_RSA)" 1906189251Ssam " failed"); 1907189251Ssam } 1908189251Ssam 1909189251Ssam if (SSL_use_PrivateKey_ASN1(EVP_PKEY_DSA, conn->ssl, 1910189251Ssam (u8 *) private_key_blob, 1911189251Ssam private_key_blob_len) == 1) { 1912189251Ssam wpa_printf(MSG_DEBUG, "OpenSSL: SSL_use_PrivateKey_" 1913189251Ssam "ASN1(EVP_PKEY_DSA) --> OK"); 1914189251Ssam ok = 1; 1915189251Ssam break; 1916189251Ssam } else { 1917189251Ssam tls_show_errors(MSG_DEBUG, __func__, 1918189251Ssam "SSL_use_PrivateKey_ASN1(EVP_PKEY_DSA)" 1919189251Ssam " failed"); 1920189251Ssam } 1921189251Ssam 1922189251Ssam if (SSL_use_RSAPrivateKey_ASN1(conn->ssl, 1923189251Ssam (u8 *) private_key_blob, 1924189251Ssam private_key_blob_len) == 1) { 1925189251Ssam wpa_printf(MSG_DEBUG, "OpenSSL: " 1926189251Ssam "SSL_use_RSAPrivateKey_ASN1 --> OK"); 1927189251Ssam ok = 1; 1928189251Ssam break; 1929189251Ssam } else { 1930189251Ssam tls_show_errors(MSG_DEBUG, __func__, 1931189251Ssam "SSL_use_RSAPrivateKey_ASN1 failed"); 1932189251Ssam } 1933189251Ssam 1934189251Ssam if (tls_read_pkcs12_blob(ssl_ctx, conn->ssl, private_key_blob, 1935189251Ssam private_key_blob_len, passwd) == 0) { 1936189251Ssam wpa_printf(MSG_DEBUG, "OpenSSL: PKCS#12 as blob --> " 1937189251Ssam "OK"); 1938189251Ssam ok = 1; 1939189251Ssam break; 1940189251Ssam } 1941189251Ssam 1942189251Ssam break; 1943189251Ssam } 1944189251Ssam 1945189251Ssam while (!ok && private_key) { 1946189251Ssam#ifndef OPENSSL_NO_STDIO 1947189251Ssam if (SSL_use_PrivateKey_file(conn->ssl, private_key, 1948189251Ssam SSL_FILETYPE_ASN1) == 1) { 1949189251Ssam wpa_printf(MSG_DEBUG, "OpenSSL: " 1950189251Ssam "SSL_use_PrivateKey_File (DER) --> OK"); 1951189251Ssam ok = 1; 1952189251Ssam break; 1953189251Ssam } else { 1954189251Ssam tls_show_errors(MSG_DEBUG, __func__, 1955189251Ssam "SSL_use_PrivateKey_File (DER) " 1956189251Ssam "failed"); 1957189251Ssam } 1958189251Ssam 1959189251Ssam if (SSL_use_PrivateKey_file(conn->ssl, private_key, 1960189251Ssam SSL_FILETYPE_PEM) == 1) { 1961189251Ssam wpa_printf(MSG_DEBUG, "OpenSSL: " 1962189251Ssam "SSL_use_PrivateKey_File (PEM) --> OK"); 1963189251Ssam ok = 1; 1964189251Ssam break; 1965189251Ssam } else { 1966189251Ssam tls_show_errors(MSG_DEBUG, __func__, 1967189251Ssam "SSL_use_PrivateKey_File (PEM) " 1968189251Ssam "failed"); 1969189251Ssam } 1970189251Ssam#else /* OPENSSL_NO_STDIO */ 1971189251Ssam wpa_printf(MSG_DEBUG, "OpenSSL: %s - OPENSSL_NO_STDIO", 1972189251Ssam __func__); 1973189251Ssam#endif /* OPENSSL_NO_STDIO */ 1974189251Ssam 1975189251Ssam if (tls_read_pkcs12(ssl_ctx, conn->ssl, private_key, passwd) 1976189251Ssam == 0) { 1977189251Ssam wpa_printf(MSG_DEBUG, "OpenSSL: Reading PKCS#12 file " 1978189251Ssam "--> OK"); 1979189251Ssam ok = 1; 1980189251Ssam break; 1981189251Ssam } 1982189251Ssam 1983189251Ssam if (tls_cryptoapi_cert(conn->ssl, private_key) == 0) { 1984189251Ssam wpa_printf(MSG_DEBUG, "OpenSSL: Using CryptoAPI to " 1985189251Ssam "access certificate store --> OK"); 1986189251Ssam ok = 1; 1987189251Ssam break; 1988189251Ssam } 1989189251Ssam 1990189251Ssam break; 1991189251Ssam } 1992189251Ssam 1993189251Ssam if (!ok) { 1994189251Ssam wpa_printf(MSG_INFO, "OpenSSL: Failed to load private key"); 1995189251Ssam os_free(passwd); 1996189251Ssam ERR_clear_error(); 1997189251Ssam return -1; 1998189251Ssam } 1999189251Ssam ERR_clear_error(); 2000189251Ssam SSL_CTX_set_default_passwd_cb(ssl_ctx, NULL); 2001189251Ssam os_free(passwd); 2002189251Ssam 2003189251Ssam if (!SSL_check_private_key(conn->ssl)) { 2004189251Ssam tls_show_errors(MSG_INFO, __func__, "Private key failed " 2005189251Ssam "verification"); 2006189251Ssam return -1; 2007189251Ssam } 2008189251Ssam 2009189251Ssam wpa_printf(MSG_DEBUG, "SSL: Private key loaded successfully"); 2010189251Ssam return 0; 2011189251Ssam} 2012189251Ssam 2013189251Ssam 2014189251Ssamstatic int tls_global_private_key(SSL_CTX *ssl_ctx, const char *private_key, 2015189251Ssam const char *private_key_passwd) 2016189251Ssam{ 2017189251Ssam char *passwd; 2018189251Ssam 2019189251Ssam if (private_key == NULL) 2020189251Ssam return 0; 2021189251Ssam 2022189251Ssam if (private_key_passwd) { 2023189251Ssam passwd = os_strdup(private_key_passwd); 2024189251Ssam if (passwd == NULL) 2025189251Ssam return -1; 2026189251Ssam } else 2027189251Ssam passwd = NULL; 2028189251Ssam 2029189251Ssam SSL_CTX_set_default_passwd_cb(ssl_ctx, tls_passwd_cb); 2030189251Ssam SSL_CTX_set_default_passwd_cb_userdata(ssl_ctx, passwd); 2031189251Ssam if ( 2032189251Ssam#ifndef OPENSSL_NO_STDIO 2033189251Ssam SSL_CTX_use_PrivateKey_file(ssl_ctx, private_key, 2034189251Ssam SSL_FILETYPE_ASN1) != 1 && 2035189251Ssam SSL_CTX_use_PrivateKey_file(ssl_ctx, private_key, 2036189251Ssam SSL_FILETYPE_PEM) != 1 && 2037189251Ssam#endif /* OPENSSL_NO_STDIO */ 2038189251Ssam tls_read_pkcs12(ssl_ctx, NULL, private_key, passwd)) { 2039189251Ssam tls_show_errors(MSG_INFO, __func__, 2040189251Ssam "Failed to load private key"); 2041189251Ssam os_free(passwd); 2042189251Ssam ERR_clear_error(); 2043189251Ssam return -1; 2044189251Ssam } 2045189251Ssam os_free(passwd); 2046189251Ssam ERR_clear_error(); 2047189251Ssam SSL_CTX_set_default_passwd_cb(ssl_ctx, NULL); 2048189251Ssam 2049189251Ssam if (!SSL_CTX_check_private_key(ssl_ctx)) { 2050189251Ssam tls_show_errors(MSG_INFO, __func__, 2051189251Ssam "Private key failed verification"); 2052189251Ssam return -1; 2053189251Ssam } 2054189251Ssam 2055189251Ssam return 0; 2056189251Ssam} 2057189251Ssam 2058189251Ssam 2059189251Ssamstatic int tls_connection_dh(struct tls_connection *conn, const char *dh_file) 2060189251Ssam{ 2061189251Ssam#ifdef OPENSSL_NO_DH 2062189251Ssam if (dh_file == NULL) 2063189251Ssam return 0; 2064189251Ssam wpa_printf(MSG_ERROR, "TLS: openssl does not include DH support, but " 2065189251Ssam "dh_file specified"); 2066189251Ssam return -1; 2067189251Ssam#else /* OPENSSL_NO_DH */ 2068189251Ssam DH *dh; 2069189251Ssam BIO *bio; 2070189251Ssam 2071189251Ssam /* TODO: add support for dh_blob */ 2072189251Ssam if (dh_file == NULL) 2073189251Ssam return 0; 2074189251Ssam if (conn == NULL) 2075189251Ssam return -1; 2076189251Ssam 2077189251Ssam bio = BIO_new_file(dh_file, "r"); 2078189251Ssam if (bio == NULL) { 2079189251Ssam wpa_printf(MSG_INFO, "TLS: Failed to open DH file '%s': %s", 2080189251Ssam dh_file, ERR_error_string(ERR_get_error(), NULL)); 2081189251Ssam return -1; 2082189251Ssam } 2083189251Ssam dh = PEM_read_bio_DHparams(bio, NULL, NULL, NULL); 2084189251Ssam BIO_free(bio); 2085189251Ssam#ifndef OPENSSL_NO_DSA 2086189251Ssam while (dh == NULL) { 2087189251Ssam DSA *dsa; 2088189251Ssam wpa_printf(MSG_DEBUG, "TLS: Failed to parse DH file '%s': %s -" 2089189251Ssam " trying to parse as DSA params", dh_file, 2090189251Ssam ERR_error_string(ERR_get_error(), NULL)); 2091189251Ssam bio = BIO_new_file(dh_file, "r"); 2092189251Ssam if (bio == NULL) 2093189251Ssam break; 2094189251Ssam dsa = PEM_read_bio_DSAparams(bio, NULL, NULL, NULL); 2095189251Ssam BIO_free(bio); 2096189251Ssam if (!dsa) { 2097189251Ssam wpa_printf(MSG_DEBUG, "TLS: Failed to parse DSA file " 2098189251Ssam "'%s': %s", dh_file, 2099189251Ssam ERR_error_string(ERR_get_error(), NULL)); 2100189251Ssam break; 2101189251Ssam } 2102189251Ssam 2103189251Ssam wpa_printf(MSG_DEBUG, "TLS: DH file in DSA param format"); 2104189251Ssam dh = DSA_dup_DH(dsa); 2105189251Ssam DSA_free(dsa); 2106189251Ssam if (dh == NULL) { 2107189251Ssam wpa_printf(MSG_INFO, "TLS: Failed to convert DSA " 2108189251Ssam "params into DH params"); 2109189251Ssam break; 2110189251Ssam } 2111189251Ssam break; 2112189251Ssam } 2113189251Ssam#endif /* !OPENSSL_NO_DSA */ 2114189251Ssam if (dh == NULL) { 2115189251Ssam wpa_printf(MSG_INFO, "TLS: Failed to read/parse DH/DSA file " 2116189251Ssam "'%s'", dh_file); 2117189251Ssam return -1; 2118189251Ssam } 2119189251Ssam 2120189251Ssam if (SSL_set_tmp_dh(conn->ssl, dh) != 1) { 2121189251Ssam wpa_printf(MSG_INFO, "TLS: Failed to set DH params from '%s': " 2122189251Ssam "%s", dh_file, 2123189251Ssam ERR_error_string(ERR_get_error(), NULL)); 2124189251Ssam DH_free(dh); 2125189251Ssam return -1; 2126189251Ssam } 2127189251Ssam DH_free(dh); 2128189251Ssam return 0; 2129189251Ssam#endif /* OPENSSL_NO_DH */ 2130189251Ssam} 2131189251Ssam 2132189251Ssam 2133189251Ssamstatic int tls_global_dh(SSL_CTX *ssl_ctx, const char *dh_file) 2134189251Ssam{ 2135189251Ssam#ifdef OPENSSL_NO_DH 2136189251Ssam if (dh_file == NULL) 2137189251Ssam return 0; 2138189251Ssam wpa_printf(MSG_ERROR, "TLS: openssl does not include DH support, but " 2139189251Ssam "dh_file specified"); 2140189251Ssam return -1; 2141189251Ssam#else /* OPENSSL_NO_DH */ 2142189251Ssam DH *dh; 2143189251Ssam BIO *bio; 2144189251Ssam 2145189251Ssam /* TODO: add support for dh_blob */ 2146189251Ssam if (dh_file == NULL) 2147189251Ssam return 0; 2148189251Ssam if (ssl_ctx == NULL) 2149189251Ssam return -1; 2150189251Ssam 2151189251Ssam bio = BIO_new_file(dh_file, "r"); 2152189251Ssam if (bio == NULL) { 2153189251Ssam wpa_printf(MSG_INFO, "TLS: Failed to open DH file '%s': %s", 2154189251Ssam dh_file, ERR_error_string(ERR_get_error(), NULL)); 2155189251Ssam return -1; 2156189251Ssam } 2157189251Ssam dh = PEM_read_bio_DHparams(bio, NULL, NULL, NULL); 2158189251Ssam BIO_free(bio); 2159189251Ssam#ifndef OPENSSL_NO_DSA 2160189251Ssam while (dh == NULL) { 2161189251Ssam DSA *dsa; 2162189251Ssam wpa_printf(MSG_DEBUG, "TLS: Failed to parse DH file '%s': %s -" 2163189251Ssam " trying to parse as DSA params", dh_file, 2164189251Ssam ERR_error_string(ERR_get_error(), NULL)); 2165189251Ssam bio = BIO_new_file(dh_file, "r"); 2166189251Ssam if (bio == NULL) 2167189251Ssam break; 2168189251Ssam dsa = PEM_read_bio_DSAparams(bio, NULL, NULL, NULL); 2169189251Ssam BIO_free(bio); 2170189251Ssam if (!dsa) { 2171189251Ssam wpa_printf(MSG_DEBUG, "TLS: Failed to parse DSA file " 2172189251Ssam "'%s': %s", dh_file, 2173189251Ssam ERR_error_string(ERR_get_error(), NULL)); 2174189251Ssam break; 2175189251Ssam } 2176189251Ssam 2177189251Ssam wpa_printf(MSG_DEBUG, "TLS: DH file in DSA param format"); 2178189251Ssam dh = DSA_dup_DH(dsa); 2179189251Ssam DSA_free(dsa); 2180189251Ssam if (dh == NULL) { 2181189251Ssam wpa_printf(MSG_INFO, "TLS: Failed to convert DSA " 2182189251Ssam "params into DH params"); 2183189251Ssam break; 2184189251Ssam } 2185189251Ssam break; 2186189251Ssam } 2187189251Ssam#endif /* !OPENSSL_NO_DSA */ 2188189251Ssam if (dh == NULL) { 2189189251Ssam wpa_printf(MSG_INFO, "TLS: Failed to read/parse DH/DSA file " 2190189251Ssam "'%s'", dh_file); 2191189251Ssam return -1; 2192189251Ssam } 2193189251Ssam 2194189251Ssam if (SSL_CTX_set_tmp_dh(ssl_ctx, dh) != 1) { 2195189251Ssam wpa_printf(MSG_INFO, "TLS: Failed to set DH params from '%s': " 2196189251Ssam "%s", dh_file, 2197189251Ssam ERR_error_string(ERR_get_error(), NULL)); 2198189251Ssam DH_free(dh); 2199189251Ssam return -1; 2200189251Ssam } 2201189251Ssam DH_free(dh); 2202189251Ssam return 0; 2203189251Ssam#endif /* OPENSSL_NO_DH */ 2204189251Ssam} 2205189251Ssam 2206189251Ssam 2207189251Ssamint tls_connection_get_keys(void *ssl_ctx, struct tls_connection *conn, 2208189251Ssam struct tls_keys *keys) 2209189251Ssam{ 2210189251Ssam SSL *ssl; 2211189251Ssam 2212189251Ssam if (conn == NULL || keys == NULL) 2213189251Ssam return -1; 2214189251Ssam ssl = conn->ssl; 2215189251Ssam if (ssl == NULL || ssl->s3 == NULL || ssl->session == NULL) 2216189251Ssam return -1; 2217189251Ssam 2218189251Ssam os_memset(keys, 0, sizeof(*keys)); 2219189251Ssam keys->master_key = ssl->session->master_key; 2220189251Ssam keys->master_key_len = ssl->session->master_key_length; 2221189251Ssam keys->client_random = ssl->s3->client_random; 2222189251Ssam keys->client_random_len = SSL3_RANDOM_SIZE; 2223189251Ssam keys->server_random = ssl->s3->server_random; 2224189251Ssam keys->server_random_len = SSL3_RANDOM_SIZE; 2225189251Ssam 2226189251Ssam return 0; 2227189251Ssam} 2228189251Ssam 2229189251Ssam 2230189251Ssamint tls_connection_prf(void *tls_ctx, struct tls_connection *conn, 2231189251Ssam const char *label, int server_random_first, 2232189251Ssam u8 *out, size_t out_len) 2233189251Ssam{ 2234189251Ssam return -1; 2235189251Ssam} 2236189251Ssam 2237189251Ssam 2238214734Srpaulostatic struct wpabuf * 2239214734Srpauloopenssl_handshake(struct tls_connection *conn, const struct wpabuf *in_data, 2240214734Srpaulo int server) 2241189251Ssam{ 2242189251Ssam int res; 2243214734Srpaulo struct wpabuf *out_data; 2244189251Ssam 2245189251Ssam /* 2246189251Ssam * Give TLS handshake data from the server (if available) to OpenSSL 2247189251Ssam * for processing. 2248189251Ssam */ 2249189251Ssam if (in_data && 2250214734Srpaulo BIO_write(conn->ssl_in, wpabuf_head(in_data), wpabuf_len(in_data)) 2251214734Srpaulo < 0) { 2252189251Ssam tls_show_errors(MSG_INFO, __func__, 2253189251Ssam "Handshake failed - BIO_write"); 2254189251Ssam return NULL; 2255189251Ssam } 2256189251Ssam 2257189251Ssam /* Initiate TLS handshake or continue the existing handshake */ 2258214734Srpaulo if (server) 2259214734Srpaulo res = SSL_accept(conn->ssl); 2260214734Srpaulo else 2261214734Srpaulo res = SSL_connect(conn->ssl); 2262189251Ssam if (res != 1) { 2263189251Ssam int err = SSL_get_error(conn->ssl, res); 2264189251Ssam if (err == SSL_ERROR_WANT_READ) 2265189251Ssam wpa_printf(MSG_DEBUG, "SSL: SSL_connect - want " 2266189251Ssam "more data"); 2267189251Ssam else if (err == SSL_ERROR_WANT_WRITE) 2268189251Ssam wpa_printf(MSG_DEBUG, "SSL: SSL_connect - want to " 2269189251Ssam "write"); 2270189251Ssam else { 2271189251Ssam tls_show_errors(MSG_INFO, __func__, "SSL_connect"); 2272189251Ssam conn->failed++; 2273189251Ssam } 2274189251Ssam } 2275189251Ssam 2276189251Ssam /* Get the TLS handshake data to be sent to the server */ 2277189251Ssam res = BIO_ctrl_pending(conn->ssl_out); 2278189251Ssam wpa_printf(MSG_DEBUG, "SSL: %d bytes pending from ssl_out", res); 2279214734Srpaulo out_data = wpabuf_alloc(res); 2280189251Ssam if (out_data == NULL) { 2281189251Ssam wpa_printf(MSG_DEBUG, "SSL: Failed to allocate memory for " 2282189251Ssam "handshake output (%d bytes)", res); 2283189251Ssam if (BIO_reset(conn->ssl_out) < 0) { 2284189251Ssam tls_show_errors(MSG_INFO, __func__, 2285189251Ssam "BIO_reset failed"); 2286189251Ssam } 2287189251Ssam return NULL; 2288189251Ssam } 2289214734Srpaulo res = res == 0 ? 0 : BIO_read(conn->ssl_out, wpabuf_mhead(out_data), 2290214734Srpaulo res); 2291189251Ssam if (res < 0) { 2292189251Ssam tls_show_errors(MSG_INFO, __func__, 2293189251Ssam "Handshake failed - BIO_read"); 2294189251Ssam if (BIO_reset(conn->ssl_out) < 0) { 2295189251Ssam tls_show_errors(MSG_INFO, __func__, 2296189251Ssam "BIO_reset failed"); 2297189251Ssam } 2298214734Srpaulo wpabuf_free(out_data); 2299189251Ssam return NULL; 2300189251Ssam } 2301214734Srpaulo wpabuf_put(out_data, res); 2302189251Ssam 2303189251Ssam return out_data; 2304189251Ssam} 2305189251Ssam 2306189251Ssam 2307214734Srpaulostatic struct wpabuf * 2308214734Srpauloopenssl_get_appl_data(struct tls_connection *conn, size_t max_len) 2309189251Ssam{ 2310214734Srpaulo struct wpabuf *appl_data; 2311189251Ssam int res; 2312189251Ssam 2313214734Srpaulo appl_data = wpabuf_alloc(max_len + 100); 2314214734Srpaulo if (appl_data == NULL) 2315189251Ssam return NULL; 2316189251Ssam 2317214734Srpaulo res = SSL_read(conn->ssl, wpabuf_mhead(appl_data), 2318214734Srpaulo wpabuf_size(appl_data)); 2319214734Srpaulo if (res < 0) { 2320189251Ssam int err = SSL_get_error(conn->ssl, res); 2321214734Srpaulo if (err == SSL_ERROR_WANT_READ || 2322214734Srpaulo err == SSL_ERROR_WANT_WRITE) { 2323214734Srpaulo wpa_printf(MSG_DEBUG, "SSL: No Application Data " 2324214734Srpaulo "included"); 2325214734Srpaulo } else { 2326189251Ssam tls_show_errors(MSG_INFO, __func__, 2327214734Srpaulo "Failed to read possible " 2328214734Srpaulo "Application Data"); 2329189251Ssam } 2330214734Srpaulo wpabuf_free(appl_data); 2331189251Ssam return NULL; 2332189251Ssam } 2333214734Srpaulo 2334214734Srpaulo wpabuf_put(appl_data, res); 2335214734Srpaulo wpa_hexdump_buf_key(MSG_MSGDUMP, "SSL: Application Data in Finished " 2336214734Srpaulo "message", appl_data); 2337214734Srpaulo 2338214734Srpaulo return appl_data; 2339214734Srpaulo} 2340214734Srpaulo 2341214734Srpaulo 2342214734Srpaulostatic struct wpabuf * 2343214734Srpauloopenssl_connection_handshake(struct tls_connection *conn, 2344214734Srpaulo const struct wpabuf *in_data, 2345214734Srpaulo struct wpabuf **appl_data, int server) 2346214734Srpaulo{ 2347214734Srpaulo struct wpabuf *out_data; 2348214734Srpaulo 2349214734Srpaulo if (appl_data) 2350214734Srpaulo *appl_data = NULL; 2351214734Srpaulo 2352214734Srpaulo out_data = openssl_handshake(conn, in_data, server); 2353214734Srpaulo if (out_data == NULL) 2354189251Ssam return NULL; 2355214734Srpaulo 2356214734Srpaulo if (SSL_is_init_finished(conn->ssl) && appl_data && in_data) 2357214734Srpaulo *appl_data = openssl_get_appl_data(conn, wpabuf_len(in_data)); 2358214734Srpaulo 2359189251Ssam return out_data; 2360189251Ssam} 2361189251Ssam 2362189251Ssam 2363214734Srpaulostruct wpabuf * 2364214734Srpaulotls_connection_handshake(void *ssl_ctx, struct tls_connection *conn, 2365214734Srpaulo const struct wpabuf *in_data, 2366214734Srpaulo struct wpabuf **appl_data) 2367189251Ssam{ 2368214734Srpaulo return openssl_connection_handshake(conn, in_data, appl_data, 0); 2369214734Srpaulo} 2370214734Srpaulo 2371214734Srpaulo 2372214734Srpaulostruct wpabuf * tls_connection_server_handshake(void *tls_ctx, 2373214734Srpaulo struct tls_connection *conn, 2374214734Srpaulo const struct wpabuf *in_data, 2375214734Srpaulo struct wpabuf **appl_data) 2376214734Srpaulo{ 2377214734Srpaulo return openssl_connection_handshake(conn, in_data, appl_data, 1); 2378214734Srpaulo} 2379214734Srpaulo 2380214734Srpaulo 2381214734Srpaulostruct wpabuf * tls_connection_encrypt(void *tls_ctx, 2382214734Srpaulo struct tls_connection *conn, 2383214734Srpaulo const struct wpabuf *in_data) 2384214734Srpaulo{ 2385189251Ssam int res; 2386214734Srpaulo struct wpabuf *buf; 2387189251Ssam 2388189251Ssam if (conn == NULL) 2389214734Srpaulo return NULL; 2390189251Ssam 2391189251Ssam /* Give plaintext data for OpenSSL to encrypt into the TLS tunnel. */ 2392189251Ssam if ((res = BIO_reset(conn->ssl_in)) < 0 || 2393189251Ssam (res = BIO_reset(conn->ssl_out)) < 0) { 2394189251Ssam tls_show_errors(MSG_INFO, __func__, "BIO_reset failed"); 2395214734Srpaulo return NULL; 2396189251Ssam } 2397214734Srpaulo res = SSL_write(conn->ssl, wpabuf_head(in_data), wpabuf_len(in_data)); 2398189251Ssam if (res < 0) { 2399189251Ssam tls_show_errors(MSG_INFO, __func__, 2400189251Ssam "Encryption failed - SSL_write"); 2401214734Srpaulo return NULL; 2402189251Ssam } 2403189251Ssam 2404189251Ssam /* Read encrypted data to be sent to the server */ 2405214734Srpaulo buf = wpabuf_alloc(wpabuf_len(in_data) + 300); 2406214734Srpaulo if (buf == NULL) 2407214734Srpaulo return NULL; 2408214734Srpaulo res = BIO_read(conn->ssl_out, wpabuf_mhead(buf), wpabuf_size(buf)); 2409189251Ssam if (res < 0) { 2410189251Ssam tls_show_errors(MSG_INFO, __func__, 2411189251Ssam "Encryption failed - BIO_read"); 2412214734Srpaulo wpabuf_free(buf); 2413214734Srpaulo return NULL; 2414189251Ssam } 2415214734Srpaulo wpabuf_put(buf, res); 2416189251Ssam 2417214734Srpaulo return buf; 2418189251Ssam} 2419189251Ssam 2420189251Ssam 2421214734Srpaulostruct wpabuf * tls_connection_decrypt(void *tls_ctx, 2422214734Srpaulo struct tls_connection *conn, 2423214734Srpaulo const struct wpabuf *in_data) 2424189251Ssam{ 2425189251Ssam int res; 2426214734Srpaulo struct wpabuf *buf; 2427189251Ssam 2428189251Ssam /* Give encrypted data from TLS tunnel for OpenSSL to decrypt. */ 2429214734Srpaulo res = BIO_write(conn->ssl_in, wpabuf_head(in_data), 2430214734Srpaulo wpabuf_len(in_data)); 2431189251Ssam if (res < 0) { 2432189251Ssam tls_show_errors(MSG_INFO, __func__, 2433189251Ssam "Decryption failed - BIO_write"); 2434214734Srpaulo return NULL; 2435189251Ssam } 2436189251Ssam if (BIO_reset(conn->ssl_out) < 0) { 2437189251Ssam tls_show_errors(MSG_INFO, __func__, "BIO_reset failed"); 2438214734Srpaulo return NULL; 2439189251Ssam } 2440189251Ssam 2441189251Ssam /* Read decrypted data for further processing */ 2442214734Srpaulo /* 2443214734Srpaulo * Even though we try to disable TLS compression, it is possible that 2444214734Srpaulo * this cannot be done with all TLS libraries. Add extra buffer space 2445214734Srpaulo * to handle the possibility of the decrypted data being longer than 2446214734Srpaulo * input data. 2447214734Srpaulo */ 2448214734Srpaulo buf = wpabuf_alloc((wpabuf_len(in_data) + 500) * 3); 2449214734Srpaulo if (buf == NULL) 2450214734Srpaulo return NULL; 2451214734Srpaulo res = SSL_read(conn->ssl, wpabuf_mhead(buf), wpabuf_size(buf)); 2452189251Ssam if (res < 0) { 2453189251Ssam tls_show_errors(MSG_INFO, __func__, 2454189251Ssam "Decryption failed - SSL_read"); 2455214734Srpaulo wpabuf_free(buf); 2456214734Srpaulo return NULL; 2457189251Ssam } 2458214734Srpaulo wpabuf_put(buf, res); 2459189251Ssam 2460214734Srpaulo return buf; 2461189251Ssam} 2462189251Ssam 2463189251Ssam 2464189251Ssamint tls_connection_resumed(void *ssl_ctx, struct tls_connection *conn) 2465189251Ssam{ 2466189251Ssam return conn ? conn->ssl->hit : 0; 2467189251Ssam} 2468189251Ssam 2469189251Ssam 2470189251Ssamint tls_connection_set_cipher_list(void *tls_ctx, struct tls_connection *conn, 2471189251Ssam u8 *ciphers) 2472189251Ssam{ 2473189251Ssam char buf[100], *pos, *end; 2474189251Ssam u8 *c; 2475189251Ssam int ret; 2476189251Ssam 2477189251Ssam if (conn == NULL || conn->ssl == NULL || ciphers == NULL) 2478189251Ssam return -1; 2479189251Ssam 2480189251Ssam buf[0] = '\0'; 2481189251Ssam pos = buf; 2482189251Ssam end = pos + sizeof(buf); 2483189251Ssam 2484189251Ssam c = ciphers; 2485189251Ssam while (*c != TLS_CIPHER_NONE) { 2486189251Ssam const char *suite; 2487189251Ssam 2488189251Ssam switch (*c) { 2489189251Ssam case TLS_CIPHER_RC4_SHA: 2490189251Ssam suite = "RC4-SHA"; 2491189251Ssam break; 2492189251Ssam case TLS_CIPHER_AES128_SHA: 2493189251Ssam suite = "AES128-SHA"; 2494189251Ssam break; 2495189251Ssam case TLS_CIPHER_RSA_DHE_AES128_SHA: 2496189251Ssam suite = "DHE-RSA-AES128-SHA"; 2497189251Ssam break; 2498189251Ssam case TLS_CIPHER_ANON_DH_AES128_SHA: 2499189251Ssam suite = "ADH-AES128-SHA"; 2500189251Ssam break; 2501189251Ssam default: 2502189251Ssam wpa_printf(MSG_DEBUG, "TLS: Unsupported " 2503189251Ssam "cipher selection: %d", *c); 2504189251Ssam return -1; 2505189251Ssam } 2506189251Ssam ret = os_snprintf(pos, end - pos, ":%s", suite); 2507189251Ssam if (ret < 0 || ret >= end - pos) 2508189251Ssam break; 2509189251Ssam pos += ret; 2510189251Ssam 2511189251Ssam c++; 2512189251Ssam } 2513189251Ssam 2514189251Ssam wpa_printf(MSG_DEBUG, "OpenSSL: cipher suites: %s", buf + 1); 2515189251Ssam 2516189251Ssam if (SSL_set_cipher_list(conn->ssl, buf + 1) != 1) { 2517189251Ssam tls_show_errors(MSG_INFO, __func__, 2518189251Ssam "Cipher suite configuration failed"); 2519189251Ssam return -1; 2520189251Ssam } 2521189251Ssam 2522189251Ssam return 0; 2523189251Ssam} 2524189251Ssam 2525189251Ssam 2526189251Ssamint tls_get_cipher(void *ssl_ctx, struct tls_connection *conn, 2527189251Ssam char *buf, size_t buflen) 2528189251Ssam{ 2529189251Ssam const char *name; 2530189251Ssam if (conn == NULL || conn->ssl == NULL) 2531189251Ssam return -1; 2532189251Ssam 2533189251Ssam name = SSL_get_cipher(conn->ssl); 2534189251Ssam if (name == NULL) 2535189251Ssam return -1; 2536189251Ssam 2537189251Ssam os_strlcpy(buf, name, buflen); 2538189251Ssam return 0; 2539189251Ssam} 2540189251Ssam 2541189251Ssam 2542189251Ssamint tls_connection_enable_workaround(void *ssl_ctx, 2543189251Ssam struct tls_connection *conn) 2544189251Ssam{ 2545189251Ssam SSL_set_options(conn->ssl, SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS); 2546189251Ssam 2547189251Ssam return 0; 2548189251Ssam} 2549189251Ssam 2550189251Ssam 2551214734Srpaulo#if defined(EAP_FAST) || defined(EAP_FAST_DYNAMIC) || defined(EAP_SERVER_FAST) 2552189251Ssam/* ClientHello TLS extensions require a patch to openssl, so this function is 2553189251Ssam * commented out unless explicitly needed for EAP-FAST in order to be able to 2554189251Ssam * build this file with unmodified openssl. */ 2555189251Ssamint tls_connection_client_hello_ext(void *ssl_ctx, struct tls_connection *conn, 2556189251Ssam int ext_type, const u8 *data, 2557189251Ssam size_t data_len) 2558189251Ssam{ 2559189251Ssam if (conn == NULL || conn->ssl == NULL || ext_type != 35) 2560189251Ssam return -1; 2561189251Ssam 2562189251Ssam#ifdef CONFIG_OPENSSL_TICKET_OVERRIDE 2563189251Ssam if (SSL_set_session_ticket_ext(conn->ssl, (void *) data, 2564189251Ssam data_len) != 1) 2565189251Ssam return -1; 2566189251Ssam#else /* CONFIG_OPENSSL_TICKET_OVERRIDE */ 2567189251Ssam if (SSL_set_hello_extension(conn->ssl, ext_type, (void *) data, 2568189251Ssam data_len) != 1) 2569189251Ssam return -1; 2570189251Ssam#endif /* CONFIG_OPENSSL_TICKET_OVERRIDE */ 2571189251Ssam 2572189251Ssam return 0; 2573189251Ssam} 2574214734Srpaulo#endif /* EAP_FAST || EAP_FAST_DYNAMIC || EAP_SERVER_FAST */ 2575189251Ssam 2576189251Ssam 2577189251Ssamint tls_connection_get_failed(void *ssl_ctx, struct tls_connection *conn) 2578189251Ssam{ 2579189251Ssam if (conn == NULL) 2580189251Ssam return -1; 2581189251Ssam return conn->failed; 2582189251Ssam} 2583189251Ssam 2584189251Ssam 2585189251Ssamint tls_connection_get_read_alerts(void *ssl_ctx, struct tls_connection *conn) 2586189251Ssam{ 2587189251Ssam if (conn == NULL) 2588189251Ssam return -1; 2589189251Ssam return conn->read_alerts; 2590189251Ssam} 2591189251Ssam 2592189251Ssam 2593189251Ssamint tls_connection_get_write_alerts(void *ssl_ctx, struct tls_connection *conn) 2594189251Ssam{ 2595189251Ssam if (conn == NULL) 2596189251Ssam return -1; 2597189251Ssam return conn->write_alerts; 2598189251Ssam} 2599189251Ssam 2600189251Ssam 2601189251Ssamint tls_connection_set_params(void *tls_ctx, struct tls_connection *conn, 2602189251Ssam const struct tls_connection_params *params) 2603189251Ssam{ 2604189251Ssam int ret; 2605189251Ssam unsigned long err; 2606189251Ssam 2607189251Ssam if (conn == NULL) 2608189251Ssam return -1; 2609189251Ssam 2610189251Ssam while ((err = ERR_get_error())) { 2611189251Ssam wpa_printf(MSG_INFO, "%s: Clearing pending SSL error: %s", 2612189251Ssam __func__, ERR_error_string(err, NULL)); 2613189251Ssam } 2614189251Ssam 2615189251Ssam if (params->engine) { 2616189251Ssam wpa_printf(MSG_DEBUG, "SSL: Initializing TLS engine"); 2617189251Ssam ret = tls_engine_init(conn, params->engine_id, params->pin, 2618189251Ssam params->key_id, params->cert_id, 2619189251Ssam params->ca_cert_id); 2620189251Ssam if (ret) 2621189251Ssam return ret; 2622189251Ssam } 2623189251Ssam if (tls_connection_set_subject_match(conn, 2624189251Ssam params->subject_match, 2625189251Ssam params->altsubject_match)) 2626189251Ssam return -1; 2627189251Ssam 2628189251Ssam if (params->engine && params->ca_cert_id) { 2629189251Ssam if (tls_connection_engine_ca_cert(tls_ctx, conn, 2630189251Ssam params->ca_cert_id)) 2631189251Ssam return TLS_SET_PARAMS_ENGINE_PRV_VERIFY_FAILED; 2632189251Ssam } else if (tls_connection_ca_cert(tls_ctx, conn, params->ca_cert, 2633189251Ssam params->ca_cert_blob, 2634189251Ssam params->ca_cert_blob_len, 2635189251Ssam params->ca_path)) 2636189251Ssam return -1; 2637189251Ssam 2638189251Ssam if (params->engine && params->cert_id) { 2639189251Ssam if (tls_connection_engine_client_cert(conn, params->cert_id)) 2640189251Ssam return TLS_SET_PARAMS_ENGINE_PRV_VERIFY_FAILED; 2641189251Ssam } else if (tls_connection_client_cert(conn, params->client_cert, 2642189251Ssam params->client_cert_blob, 2643189251Ssam params->client_cert_blob_len)) 2644189251Ssam return -1; 2645189251Ssam 2646189251Ssam if (params->engine && params->key_id) { 2647189251Ssam wpa_printf(MSG_DEBUG, "TLS: Using private key from engine"); 2648189251Ssam if (tls_connection_engine_private_key(conn)) 2649189251Ssam return TLS_SET_PARAMS_ENGINE_PRV_VERIFY_FAILED; 2650189251Ssam } else if (tls_connection_private_key(tls_ctx, conn, 2651189251Ssam params->private_key, 2652189251Ssam params->private_key_passwd, 2653189251Ssam params->private_key_blob, 2654189251Ssam params->private_key_blob_len)) { 2655189251Ssam wpa_printf(MSG_INFO, "TLS: Failed to load private key '%s'", 2656189251Ssam params->private_key); 2657189251Ssam return -1; 2658189251Ssam } 2659189251Ssam 2660189251Ssam if (tls_connection_dh(conn, params->dh_file)) { 2661189251Ssam wpa_printf(MSG_INFO, "TLS: Failed to load DH file '%s'", 2662189251Ssam params->dh_file); 2663189251Ssam return -1; 2664189251Ssam } 2665189251Ssam 2666189251Ssam tls_get_errors(tls_ctx); 2667189251Ssam 2668189251Ssam return 0; 2669189251Ssam} 2670189251Ssam 2671189251Ssam 2672189251Ssamint tls_global_set_params(void *tls_ctx, 2673189251Ssam const struct tls_connection_params *params) 2674189251Ssam{ 2675189251Ssam SSL_CTX *ssl_ctx = tls_ctx; 2676189251Ssam unsigned long err; 2677189251Ssam 2678189251Ssam while ((err = ERR_get_error())) { 2679189251Ssam wpa_printf(MSG_INFO, "%s: Clearing pending SSL error: %s", 2680189251Ssam __func__, ERR_error_string(err, NULL)); 2681189251Ssam } 2682189251Ssam 2683189251Ssam if (tls_global_ca_cert(ssl_ctx, params->ca_cert)) 2684189251Ssam return -1; 2685189251Ssam 2686189251Ssam if (tls_global_client_cert(ssl_ctx, params->client_cert)) 2687189251Ssam return -1; 2688189251Ssam 2689189251Ssam if (tls_global_private_key(ssl_ctx, params->private_key, 2690189251Ssam params->private_key_passwd)) 2691189251Ssam return -1; 2692189251Ssam 2693189251Ssam if (tls_global_dh(ssl_ctx, params->dh_file)) { 2694189251Ssam wpa_printf(MSG_INFO, "TLS: Failed to load DH file '%s'", 2695189251Ssam params->dh_file); 2696189251Ssam return -1; 2697189251Ssam } 2698189251Ssam 2699189251Ssam return 0; 2700189251Ssam} 2701189251Ssam 2702189251Ssam 2703189251Ssamint tls_connection_get_keyblock_size(void *tls_ctx, 2704189251Ssam struct tls_connection *conn) 2705189251Ssam{ 2706189251Ssam const EVP_CIPHER *c; 2707189251Ssam const EVP_MD *h; 2708189251Ssam 2709189251Ssam if (conn == NULL || conn->ssl == NULL || 2710189251Ssam conn->ssl->enc_read_ctx == NULL || 2711189251Ssam conn->ssl->enc_read_ctx->cipher == NULL || 2712189251Ssam conn->ssl->read_hash == NULL) 2713189251Ssam return -1; 2714189251Ssam 2715189251Ssam c = conn->ssl->enc_read_ctx->cipher; 2716189251Ssam#if OPENSSL_VERSION_NUMBER >= 0x00909000L 2717189251Ssam h = EVP_MD_CTX_md(conn->ssl->read_hash); 2718189251Ssam#else 2719189251Ssam h = conn->ssl->read_hash; 2720189251Ssam#endif 2721189251Ssam 2722189251Ssam return 2 * (EVP_CIPHER_key_length(c) + 2723189251Ssam EVP_MD_size(h) + 2724189251Ssam EVP_CIPHER_iv_length(c)); 2725189251Ssam} 2726189251Ssam 2727189251Ssam 2728189251Ssamunsigned int tls_capabilities(void *tls_ctx) 2729189251Ssam{ 2730189251Ssam return 0; 2731189251Ssam} 2732189251Ssam 2733189251Ssam 2734189251Ssamint tls_connection_set_ia(void *tls_ctx, struct tls_connection *conn, 2735189251Ssam int tls_ia) 2736189251Ssam{ 2737189251Ssam return -1; 2738189251Ssam} 2739189251Ssam 2740189251Ssam 2741214734Srpaulostruct wpabuf * tls_connection_ia_send_phase_finished( 2742214734Srpaulo void *tls_ctx, struct tls_connection *conn, int final) 2743189251Ssam{ 2744214734Srpaulo return NULL; 2745189251Ssam} 2746189251Ssam 2747189251Ssam 2748189251Ssamint tls_connection_ia_final_phase_finished(void *tls_ctx, 2749189251Ssam struct tls_connection *conn) 2750189251Ssam{ 2751189251Ssam return -1; 2752189251Ssam} 2753189251Ssam 2754189251Ssam 2755189251Ssamint tls_connection_ia_permute_inner_secret(void *tls_ctx, 2756189251Ssam struct tls_connection *conn, 2757189251Ssam const u8 *key, size_t key_len) 2758189251Ssam{ 2759189251Ssam return -1; 2760189251Ssam} 2761189251Ssam 2762189251Ssam 2763214734Srpaulo#if defined(EAP_FAST) || defined(EAP_FAST_DYNAMIC) || defined(EAP_SERVER_FAST) 2764189251Ssam/* Pre-shared secred requires a patch to openssl, so this function is 2765189251Ssam * commented out unless explicitly needed for EAP-FAST in order to be able to 2766189251Ssam * build this file with unmodified openssl. */ 2767189251Ssam 2768189251Ssamstatic int tls_sess_sec_cb(SSL *s, void *secret, int *secret_len, 2769189251Ssam STACK_OF(SSL_CIPHER) *peer_ciphers, 2770189251Ssam SSL_CIPHER **cipher, void *arg) 2771189251Ssam{ 2772189251Ssam struct tls_connection *conn = arg; 2773189251Ssam int ret; 2774189251Ssam 2775189251Ssam if (conn == NULL || conn->session_ticket_cb == NULL) 2776189251Ssam return 0; 2777189251Ssam 2778189251Ssam ret = conn->session_ticket_cb(conn->session_ticket_cb_ctx, 2779189251Ssam conn->session_ticket, 2780189251Ssam conn->session_ticket_len, 2781189251Ssam s->s3->client_random, 2782189251Ssam s->s3->server_random, secret); 2783189251Ssam os_free(conn->session_ticket); 2784189251Ssam conn->session_ticket = NULL; 2785189251Ssam 2786189251Ssam if (ret <= 0) 2787189251Ssam return 0; 2788189251Ssam 2789189251Ssam *secret_len = SSL_MAX_MASTER_KEY_LENGTH; 2790189251Ssam return 1; 2791189251Ssam} 2792189251Ssam 2793189251Ssam 2794189251Ssam#ifdef CONFIG_OPENSSL_TICKET_OVERRIDE 2795189251Ssamstatic int tls_session_ticket_ext_cb(SSL *s, const unsigned char *data, 2796189251Ssam int len, void *arg) 2797189251Ssam{ 2798189251Ssam struct tls_connection *conn = arg; 2799189251Ssam 2800189251Ssam if (conn == NULL || conn->session_ticket_cb == NULL) 2801189251Ssam return 0; 2802189251Ssam 2803189251Ssam wpa_printf(MSG_DEBUG, "OpenSSL: %s: length=%d", __func__, len); 2804189251Ssam 2805189251Ssam os_free(conn->session_ticket); 2806189251Ssam conn->session_ticket = NULL; 2807189251Ssam 2808189251Ssam wpa_hexdump(MSG_DEBUG, "OpenSSL: ClientHello SessionTicket " 2809189251Ssam "extension", data, len); 2810189251Ssam 2811189251Ssam conn->session_ticket = os_malloc(len); 2812189251Ssam if (conn->session_ticket == NULL) 2813189251Ssam return 0; 2814189251Ssam 2815189251Ssam os_memcpy(conn->session_ticket, data, len); 2816189251Ssam conn->session_ticket_len = len; 2817189251Ssam 2818189251Ssam return 1; 2819189251Ssam} 2820189251Ssam#else /* CONFIG_OPENSSL_TICKET_OVERRIDE */ 2821189251Ssam#ifdef SSL_OP_NO_TICKET 2822189251Ssamstatic void tls_hello_ext_cb(SSL *s, int client_server, int type, 2823189251Ssam unsigned char *data, int len, void *arg) 2824189251Ssam{ 2825189251Ssam struct tls_connection *conn = arg; 2826189251Ssam 2827189251Ssam if (conn == NULL || conn->session_ticket_cb == NULL) 2828189251Ssam return; 2829189251Ssam 2830189251Ssam wpa_printf(MSG_DEBUG, "OpenSSL: %s: type=%d length=%d", __func__, 2831189251Ssam type, len); 2832189251Ssam 2833189251Ssam if (type == TLSEXT_TYPE_session_ticket && !client_server) { 2834189251Ssam os_free(conn->session_ticket); 2835189251Ssam conn->session_ticket = NULL; 2836189251Ssam 2837189251Ssam wpa_hexdump(MSG_DEBUG, "OpenSSL: ClientHello SessionTicket " 2838189251Ssam "extension", data, len); 2839189251Ssam conn->session_ticket = os_malloc(len); 2840189251Ssam if (conn->session_ticket == NULL) 2841189251Ssam return; 2842189251Ssam 2843189251Ssam os_memcpy(conn->session_ticket, data, len); 2844189251Ssam conn->session_ticket_len = len; 2845189251Ssam } 2846189251Ssam} 2847189251Ssam#else /* SSL_OP_NO_TICKET */ 2848189251Ssamstatic int tls_hello_ext_cb(SSL *s, TLS_EXTENSION *ext, void *arg) 2849189251Ssam{ 2850189251Ssam struct tls_connection *conn = arg; 2851189251Ssam 2852189251Ssam if (conn == NULL || conn->session_ticket_cb == NULL) 2853189251Ssam return 0; 2854189251Ssam 2855189251Ssam wpa_printf(MSG_DEBUG, "OpenSSL: %s: type=%d length=%d", __func__, 2856189251Ssam ext->type, ext->length); 2857189251Ssam 2858189251Ssam os_free(conn->session_ticket); 2859189251Ssam conn->session_ticket = NULL; 2860189251Ssam 2861189251Ssam if (ext->type == 35) { 2862189251Ssam wpa_hexdump(MSG_DEBUG, "OpenSSL: ClientHello SessionTicket " 2863189251Ssam "extension", ext->data, ext->length); 2864189251Ssam conn->session_ticket = os_malloc(ext->length); 2865189251Ssam if (conn->session_ticket == NULL) 2866189251Ssam return SSL_AD_INTERNAL_ERROR; 2867189251Ssam 2868189251Ssam os_memcpy(conn->session_ticket, ext->data, ext->length); 2869189251Ssam conn->session_ticket_len = ext->length; 2870189251Ssam } 2871189251Ssam 2872189251Ssam return 0; 2873189251Ssam} 2874189251Ssam#endif /* SSL_OP_NO_TICKET */ 2875189251Ssam#endif /* CONFIG_OPENSSL_TICKET_OVERRIDE */ 2876214734Srpaulo#endif /* EAP_FAST || EAP_FAST_DYNAMIC || EAP_SERVER_FAST */ 2877189251Ssam 2878189251Ssam 2879189251Ssamint tls_connection_set_session_ticket_cb(void *tls_ctx, 2880189251Ssam struct tls_connection *conn, 2881189251Ssam tls_session_ticket_cb cb, 2882189251Ssam void *ctx) 2883189251Ssam{ 2884214734Srpaulo#if defined(EAP_FAST) || defined(EAP_FAST_DYNAMIC) || defined(EAP_SERVER_FAST) 2885189251Ssam conn->session_ticket_cb = cb; 2886189251Ssam conn->session_ticket_cb_ctx = ctx; 2887189251Ssam 2888189251Ssam if (cb) { 2889189251Ssam if (SSL_set_session_secret_cb(conn->ssl, tls_sess_sec_cb, 2890189251Ssam conn) != 1) 2891189251Ssam return -1; 2892189251Ssam#ifdef CONFIG_OPENSSL_TICKET_OVERRIDE 2893189251Ssam SSL_set_session_ticket_ext_cb(conn->ssl, 2894189251Ssam tls_session_ticket_ext_cb, conn); 2895189251Ssam#else /* CONFIG_OPENSSL_TICKET_OVERRIDE */ 2896189251Ssam#ifdef SSL_OP_NO_TICKET 2897189251Ssam SSL_set_tlsext_debug_callback(conn->ssl, tls_hello_ext_cb); 2898189251Ssam SSL_set_tlsext_debug_arg(conn->ssl, conn); 2899189251Ssam#else /* SSL_OP_NO_TICKET */ 2900189251Ssam if (SSL_set_hello_extension_cb(conn->ssl, tls_hello_ext_cb, 2901189251Ssam conn) != 1) 2902189251Ssam return -1; 2903189251Ssam#endif /* SSL_OP_NO_TICKET */ 2904189251Ssam#endif /* CONFIG_OPENSSL_TICKET_OVERRIDE */ 2905189251Ssam } else { 2906189251Ssam if (SSL_set_session_secret_cb(conn->ssl, NULL, NULL) != 1) 2907189251Ssam return -1; 2908189251Ssam#ifdef CONFIG_OPENSSL_TICKET_OVERRIDE 2909189251Ssam SSL_set_session_ticket_ext_cb(conn->ssl, NULL, NULL); 2910189251Ssam#else /* CONFIG_OPENSSL_TICKET_OVERRIDE */ 2911189251Ssam#ifdef SSL_OP_NO_TICKET 2912189251Ssam SSL_set_tlsext_debug_callback(conn->ssl, NULL); 2913189251Ssam SSL_set_tlsext_debug_arg(conn->ssl, conn); 2914189251Ssam#else /* SSL_OP_NO_TICKET */ 2915189251Ssam if (SSL_set_hello_extension_cb(conn->ssl, NULL, NULL) != 1) 2916189251Ssam return -1; 2917189251Ssam#endif /* SSL_OP_NO_TICKET */ 2918189251Ssam#endif /* CONFIG_OPENSSL_TICKET_OVERRIDE */ 2919189251Ssam } 2920189251Ssam 2921189251Ssam return 0; 2922214734Srpaulo#else /* EAP_FAST || EAP_FAST_DYNAMIC || EAP_SERVER_FAST */ 2923189251Ssam return -1; 2924214734Srpaulo#endif /* EAP_FAST || EAP_FAST_DYNAMIC || EAP_SERVER_FAST */ 2925189251Ssam} 2926