1189251Ssam/* 2214734Srpaulo * SSL/TLS interface functions for OpenSSL 3252726Srpaulo * Copyright (c) 2004-2011, Jouni Malinen <j@w1.fi> 4189251Ssam * 5252726Srpaulo * This software may be distributed under the terms of the BSD license. 6252726Srpaulo * See README for more details. 7189251Ssam */ 8189251Ssam 9189251Ssam#include "includes.h" 10189251Ssam 11189251Ssam#ifndef CONFIG_SMARTCARD 12189251Ssam#ifndef OPENSSL_NO_ENGINE 13189251Ssam#define OPENSSL_NO_ENGINE 14189251Ssam#endif 15189251Ssam#endif 16189251Ssam 17189251Ssam#include <openssl/ssl.h> 18189251Ssam#include <openssl/err.h> 19189251Ssam#include <openssl/pkcs12.h> 20189251Ssam#include <openssl/x509v3.h> 21189251Ssam#ifndef OPENSSL_NO_ENGINE 22189251Ssam#include <openssl/engine.h> 23189251Ssam#endif /* OPENSSL_NO_ENGINE */ 24189251Ssam 25252726Srpaulo#ifdef ANDROID 26252726Srpaulo#include <openssl/pem.h> 27252726Srpaulo#include "keystore_get.h" 28252726Srpaulo#endif /* ANDROID */ 29252726Srpaulo 30189251Ssam#include "common.h" 31214734Srpaulo#include "crypto.h" 32189251Ssam#include "tls.h" 33189251Ssam 34189251Ssam#if OPENSSL_VERSION_NUMBER >= 0x0090800fL 35189251Ssam#define OPENSSL_d2i_TYPE const unsigned char ** 36189251Ssam#else 37189251Ssam#define OPENSSL_d2i_TYPE unsigned char ** 38189251Ssam#endif 39189251Ssam 40189251Ssam#ifdef SSL_F_SSL_SET_SESSION_TICKET_EXT 41189251Ssam#ifdef SSL_OP_NO_TICKET 42189251Ssam/* 43189251Ssam * Session ticket override patch was merged into OpenSSL 0.9.9 tree on 44189251Ssam * 2008-11-15. This version uses a bit different API compared to the old patch. 45189251Ssam */ 46189251Ssam#define CONFIG_OPENSSL_TICKET_OVERRIDE 47189251Ssam#endif 48189251Ssam#endif 49189251Ssam 50189251Ssamstatic int tls_openssl_ref_count = 0; 51189251Ssam 52214734Srpaulostruct tls_global { 53214734Srpaulo void (*event_cb)(void *ctx, enum tls_event ev, 54214734Srpaulo union tls_event_data *data); 55214734Srpaulo void *cb_ctx; 56252726Srpaulo int cert_in_cb; 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]; 84252726Srpaulo 85252726Srpaulo unsigned int flags; 86189251Ssam}; 87189251Ssam 88189251Ssam 89189251Ssam#ifdef CONFIG_NO_STDOUT_DEBUG 90189251Ssam 91189251Ssamstatic void _tls_show_errors(void) 92189251Ssam{ 93189251Ssam unsigned long err; 94189251Ssam 95189251Ssam while ((err = ERR_get_error())) { 96189251Ssam /* Just ignore the errors, since stdout is disabled */ 97189251Ssam } 98189251Ssam} 99189251Ssam#define tls_show_errors(l, f, t) _tls_show_errors() 100189251Ssam 101189251Ssam#else /* CONFIG_NO_STDOUT_DEBUG */ 102189251Ssam 103189251Ssamstatic void tls_show_errors(int level, const char *func, const char *txt) 104189251Ssam{ 105189251Ssam unsigned long err; 106189251Ssam 107189251Ssam wpa_printf(level, "OpenSSL: %s - %s %s", 108189251Ssam func, txt, ERR_error_string(ERR_get_error(), NULL)); 109189251Ssam 110189251Ssam while ((err = ERR_get_error())) { 111189251Ssam wpa_printf(MSG_INFO, "OpenSSL: pending error: %s", 112189251Ssam ERR_error_string(err, NULL)); 113189251Ssam } 114189251Ssam} 115189251Ssam 116189251Ssam#endif /* CONFIG_NO_STDOUT_DEBUG */ 117189251Ssam 118189251Ssam 119189251Ssam#ifdef CONFIG_NATIVE_WINDOWS 120189251Ssam 121189251Ssam/* Windows CryptoAPI and access to certificate stores */ 122189251Ssam#include <wincrypt.h> 123189251Ssam 124189251Ssam#ifdef __MINGW32_VERSION 125189251Ssam/* 126189251Ssam * MinGW does not yet include all the needed definitions for CryptoAPI, so 127189251Ssam * define here whatever extra is needed. 128189251Ssam */ 129189251Ssam#define CERT_SYSTEM_STORE_CURRENT_USER (1 << 16) 130189251Ssam#define CERT_STORE_READONLY_FLAG 0x00008000 131189251Ssam#define CERT_STORE_OPEN_EXISTING_FLAG 0x00004000 132189251Ssam 133189251Ssam#endif /* __MINGW32_VERSION */ 134189251Ssam 135189251Ssam 136189251Ssamstruct cryptoapi_rsa_data { 137189251Ssam const CERT_CONTEXT *cert; 138189251Ssam HCRYPTPROV crypt_prov; 139189251Ssam DWORD key_spec; 140189251Ssam BOOL free_crypt_prov; 141189251Ssam}; 142189251Ssam 143189251Ssam 144189251Ssamstatic void cryptoapi_error(const char *msg) 145189251Ssam{ 146189251Ssam wpa_printf(MSG_INFO, "CryptoAPI: %s; err=%u", 147189251Ssam msg, (unsigned int) GetLastError()); 148189251Ssam} 149189251Ssam 150189251Ssam 151189251Ssamstatic int cryptoapi_rsa_pub_enc(int flen, const unsigned char *from, 152189251Ssam unsigned char *to, RSA *rsa, int padding) 153189251Ssam{ 154189251Ssam wpa_printf(MSG_DEBUG, "%s - not implemented", __func__); 155189251Ssam return 0; 156189251Ssam} 157189251Ssam 158189251Ssam 159189251Ssamstatic int cryptoapi_rsa_pub_dec(int flen, const unsigned char *from, 160189251Ssam unsigned char *to, RSA *rsa, int padding) 161189251Ssam{ 162189251Ssam wpa_printf(MSG_DEBUG, "%s - not implemented", __func__); 163189251Ssam return 0; 164189251Ssam} 165189251Ssam 166189251Ssam 167189251Ssamstatic int cryptoapi_rsa_priv_enc(int flen, const unsigned char *from, 168189251Ssam unsigned char *to, RSA *rsa, int padding) 169189251Ssam{ 170189251Ssam struct cryptoapi_rsa_data *priv = 171189251Ssam (struct cryptoapi_rsa_data *) rsa->meth->app_data; 172189251Ssam HCRYPTHASH hash; 173189251Ssam DWORD hash_size, len, i; 174189251Ssam unsigned char *buf = NULL; 175189251Ssam int ret = 0; 176189251Ssam 177189251Ssam if (priv == NULL) { 178189251Ssam RSAerr(RSA_F_RSA_EAY_PRIVATE_ENCRYPT, 179189251Ssam ERR_R_PASSED_NULL_PARAMETER); 180189251Ssam return 0; 181189251Ssam } 182189251Ssam 183189251Ssam if (padding != RSA_PKCS1_PADDING) { 184189251Ssam RSAerr(RSA_F_RSA_EAY_PRIVATE_ENCRYPT, 185189251Ssam RSA_R_UNKNOWN_PADDING_TYPE); 186189251Ssam return 0; 187189251Ssam } 188189251Ssam 189189251Ssam if (flen != 16 /* MD5 */ + 20 /* SHA-1 */) { 190189251Ssam wpa_printf(MSG_INFO, "%s - only MD5-SHA1 hash supported", 191189251Ssam __func__); 192189251Ssam RSAerr(RSA_F_RSA_EAY_PRIVATE_ENCRYPT, 193189251Ssam RSA_R_INVALID_MESSAGE_LENGTH); 194189251Ssam return 0; 195189251Ssam } 196189251Ssam 197189251Ssam if (!CryptCreateHash(priv->crypt_prov, CALG_SSL3_SHAMD5, 0, 0, &hash)) 198189251Ssam { 199189251Ssam cryptoapi_error("CryptCreateHash failed"); 200189251Ssam return 0; 201189251Ssam } 202189251Ssam 203189251Ssam len = sizeof(hash_size); 204189251Ssam if (!CryptGetHashParam(hash, HP_HASHSIZE, (BYTE *) &hash_size, &len, 205189251Ssam 0)) { 206189251Ssam cryptoapi_error("CryptGetHashParam failed"); 207189251Ssam goto err; 208189251Ssam } 209189251Ssam 210189251Ssam if ((int) hash_size != flen) { 211189251Ssam wpa_printf(MSG_INFO, "CryptoAPI: Invalid hash size (%u != %d)", 212189251Ssam (unsigned) hash_size, flen); 213189251Ssam RSAerr(RSA_F_RSA_EAY_PRIVATE_ENCRYPT, 214189251Ssam RSA_R_INVALID_MESSAGE_LENGTH); 215189251Ssam goto err; 216189251Ssam } 217189251Ssam if (!CryptSetHashParam(hash, HP_HASHVAL, (BYTE * ) from, 0)) { 218189251Ssam cryptoapi_error("CryptSetHashParam failed"); 219189251Ssam goto err; 220189251Ssam } 221189251Ssam 222189251Ssam len = RSA_size(rsa); 223189251Ssam buf = os_malloc(len); 224189251Ssam if (buf == NULL) { 225189251Ssam RSAerr(RSA_F_RSA_EAY_PRIVATE_ENCRYPT, ERR_R_MALLOC_FAILURE); 226189251Ssam goto err; 227189251Ssam } 228189251Ssam 229189251Ssam if (!CryptSignHash(hash, priv->key_spec, NULL, 0, buf, &len)) { 230189251Ssam cryptoapi_error("CryptSignHash failed"); 231189251Ssam goto err; 232189251Ssam } 233189251Ssam 234189251Ssam for (i = 0; i < len; i++) 235189251Ssam to[i] = buf[len - i - 1]; 236189251Ssam ret = len; 237189251Ssam 238189251Ssamerr: 239189251Ssam os_free(buf); 240189251Ssam CryptDestroyHash(hash); 241189251Ssam 242189251Ssam return ret; 243189251Ssam} 244189251Ssam 245189251Ssam 246189251Ssamstatic int cryptoapi_rsa_priv_dec(int flen, const unsigned char *from, 247189251Ssam unsigned char *to, RSA *rsa, int padding) 248189251Ssam{ 249189251Ssam wpa_printf(MSG_DEBUG, "%s - not implemented", __func__); 250189251Ssam return 0; 251189251Ssam} 252189251Ssam 253189251Ssam 254189251Ssamstatic void cryptoapi_free_data(struct cryptoapi_rsa_data *priv) 255189251Ssam{ 256189251Ssam if (priv == NULL) 257189251Ssam return; 258189251Ssam if (priv->crypt_prov && priv->free_crypt_prov) 259189251Ssam CryptReleaseContext(priv->crypt_prov, 0); 260189251Ssam if (priv->cert) 261189251Ssam CertFreeCertificateContext(priv->cert); 262189251Ssam os_free(priv); 263189251Ssam} 264189251Ssam 265189251Ssam 266189251Ssamstatic int cryptoapi_finish(RSA *rsa) 267189251Ssam{ 268189251Ssam cryptoapi_free_data((struct cryptoapi_rsa_data *) rsa->meth->app_data); 269189251Ssam os_free((void *) rsa->meth); 270189251Ssam rsa->meth = NULL; 271189251Ssam return 1; 272189251Ssam} 273189251Ssam 274189251Ssam 275189251Ssamstatic const CERT_CONTEXT * cryptoapi_find_cert(const char *name, DWORD store) 276189251Ssam{ 277189251Ssam HCERTSTORE cs; 278189251Ssam const CERT_CONTEXT *ret = NULL; 279189251Ssam 280189251Ssam cs = CertOpenStore((LPCSTR) CERT_STORE_PROV_SYSTEM, 0, 0, 281189251Ssam store | CERT_STORE_OPEN_EXISTING_FLAG | 282189251Ssam CERT_STORE_READONLY_FLAG, L"MY"); 283189251Ssam if (cs == NULL) { 284189251Ssam cryptoapi_error("Failed to open 'My system store'"); 285189251Ssam return NULL; 286189251Ssam } 287189251Ssam 288189251Ssam if (strncmp(name, "cert://", 7) == 0) { 289189251Ssam unsigned short wbuf[255]; 290189251Ssam MultiByteToWideChar(CP_ACP, 0, name + 7, -1, wbuf, 255); 291189251Ssam ret = CertFindCertificateInStore(cs, X509_ASN_ENCODING | 292189251Ssam PKCS_7_ASN_ENCODING, 293189251Ssam 0, CERT_FIND_SUBJECT_STR, 294189251Ssam wbuf, NULL); 295189251Ssam } else if (strncmp(name, "hash://", 7) == 0) { 296189251Ssam CRYPT_HASH_BLOB blob; 297189251Ssam int len; 298189251Ssam const char *hash = name + 7; 299189251Ssam unsigned char *buf; 300189251Ssam 301189251Ssam len = os_strlen(hash) / 2; 302189251Ssam buf = os_malloc(len); 303189251Ssam if (buf && hexstr2bin(hash, buf, len) == 0) { 304189251Ssam blob.cbData = len; 305189251Ssam blob.pbData = buf; 306189251Ssam ret = CertFindCertificateInStore(cs, 307189251Ssam X509_ASN_ENCODING | 308189251Ssam PKCS_7_ASN_ENCODING, 309189251Ssam 0, CERT_FIND_HASH, 310189251Ssam &blob, NULL); 311189251Ssam } 312189251Ssam os_free(buf); 313189251Ssam } 314189251Ssam 315189251Ssam CertCloseStore(cs, 0); 316189251Ssam 317189251Ssam return ret; 318189251Ssam} 319189251Ssam 320189251Ssam 321189251Ssamstatic int tls_cryptoapi_cert(SSL *ssl, const char *name) 322189251Ssam{ 323189251Ssam X509 *cert = NULL; 324189251Ssam RSA *rsa = NULL, *pub_rsa; 325189251Ssam struct cryptoapi_rsa_data *priv; 326189251Ssam RSA_METHOD *rsa_meth; 327189251Ssam 328189251Ssam if (name == NULL || 329189251Ssam (strncmp(name, "cert://", 7) != 0 && 330189251Ssam strncmp(name, "hash://", 7) != 0)) 331189251Ssam return -1; 332189251Ssam 333189251Ssam priv = os_zalloc(sizeof(*priv)); 334189251Ssam rsa_meth = os_zalloc(sizeof(*rsa_meth)); 335189251Ssam if (priv == NULL || rsa_meth == NULL) { 336189251Ssam wpa_printf(MSG_WARNING, "CryptoAPI: Failed to allocate memory " 337189251Ssam "for CryptoAPI RSA method"); 338189251Ssam os_free(priv); 339189251Ssam os_free(rsa_meth); 340189251Ssam return -1; 341189251Ssam } 342189251Ssam 343189251Ssam priv->cert = cryptoapi_find_cert(name, CERT_SYSTEM_STORE_CURRENT_USER); 344189251Ssam if (priv->cert == NULL) { 345189251Ssam priv->cert = cryptoapi_find_cert( 346189251Ssam name, CERT_SYSTEM_STORE_LOCAL_MACHINE); 347189251Ssam } 348189251Ssam if (priv->cert == NULL) { 349189251Ssam wpa_printf(MSG_INFO, "CryptoAPI: Could not find certificate " 350189251Ssam "'%s'", name); 351189251Ssam goto err; 352189251Ssam } 353189251Ssam 354189251Ssam cert = d2i_X509(NULL, (OPENSSL_d2i_TYPE) &priv->cert->pbCertEncoded, 355189251Ssam priv->cert->cbCertEncoded); 356189251Ssam if (cert == NULL) { 357189251Ssam wpa_printf(MSG_INFO, "CryptoAPI: Could not process X509 DER " 358189251Ssam "encoding"); 359189251Ssam goto err; 360189251Ssam } 361189251Ssam 362189251Ssam if (!CryptAcquireCertificatePrivateKey(priv->cert, 363189251Ssam CRYPT_ACQUIRE_COMPARE_KEY_FLAG, 364189251Ssam NULL, &priv->crypt_prov, 365189251Ssam &priv->key_spec, 366189251Ssam &priv->free_crypt_prov)) { 367189251Ssam cryptoapi_error("Failed to acquire a private key for the " 368189251Ssam "certificate"); 369189251Ssam goto err; 370189251Ssam } 371189251Ssam 372189251Ssam rsa_meth->name = "Microsoft CryptoAPI RSA Method"; 373189251Ssam rsa_meth->rsa_pub_enc = cryptoapi_rsa_pub_enc; 374189251Ssam rsa_meth->rsa_pub_dec = cryptoapi_rsa_pub_dec; 375189251Ssam rsa_meth->rsa_priv_enc = cryptoapi_rsa_priv_enc; 376189251Ssam rsa_meth->rsa_priv_dec = cryptoapi_rsa_priv_dec; 377189251Ssam rsa_meth->finish = cryptoapi_finish; 378189251Ssam rsa_meth->flags = RSA_METHOD_FLAG_NO_CHECK; 379189251Ssam rsa_meth->app_data = (char *) priv; 380189251Ssam 381189251Ssam rsa = RSA_new(); 382189251Ssam if (rsa == NULL) { 383189251Ssam SSLerr(SSL_F_SSL_CTX_USE_CERTIFICATE_FILE, 384189251Ssam ERR_R_MALLOC_FAILURE); 385189251Ssam goto err; 386189251Ssam } 387189251Ssam 388189251Ssam if (!SSL_use_certificate(ssl, cert)) { 389189251Ssam RSA_free(rsa); 390189251Ssam rsa = NULL; 391189251Ssam goto err; 392189251Ssam } 393189251Ssam pub_rsa = cert->cert_info->key->pkey->pkey.rsa; 394189251Ssam X509_free(cert); 395189251Ssam cert = NULL; 396189251Ssam 397189251Ssam rsa->n = BN_dup(pub_rsa->n); 398189251Ssam rsa->e = BN_dup(pub_rsa->e); 399189251Ssam if (!RSA_set_method(rsa, rsa_meth)) 400189251Ssam goto err; 401189251Ssam 402189251Ssam if (!SSL_use_RSAPrivateKey(ssl, rsa)) 403189251Ssam goto err; 404189251Ssam RSA_free(rsa); 405189251Ssam 406189251Ssam return 0; 407189251Ssam 408189251Ssamerr: 409189251Ssam if (cert) 410189251Ssam X509_free(cert); 411189251Ssam if (rsa) 412189251Ssam RSA_free(rsa); 413189251Ssam else { 414189251Ssam os_free(rsa_meth); 415189251Ssam cryptoapi_free_data(priv); 416189251Ssam } 417189251Ssam return -1; 418189251Ssam} 419189251Ssam 420189251Ssam 421189251Ssamstatic int tls_cryptoapi_ca_cert(SSL_CTX *ssl_ctx, SSL *ssl, const char *name) 422189251Ssam{ 423189251Ssam HCERTSTORE cs; 424189251Ssam PCCERT_CONTEXT ctx = NULL; 425189251Ssam X509 *cert; 426189251Ssam char buf[128]; 427189251Ssam const char *store; 428189251Ssam#ifdef UNICODE 429189251Ssam WCHAR *wstore; 430189251Ssam#endif /* UNICODE */ 431189251Ssam 432189251Ssam if (name == NULL || strncmp(name, "cert_store://", 13) != 0) 433189251Ssam return -1; 434189251Ssam 435189251Ssam store = name + 13; 436189251Ssam#ifdef UNICODE 437189251Ssam wstore = os_malloc((os_strlen(store) + 1) * sizeof(WCHAR)); 438189251Ssam if (wstore == NULL) 439189251Ssam return -1; 440189251Ssam wsprintf(wstore, L"%S", store); 441189251Ssam cs = CertOpenSystemStore(0, wstore); 442189251Ssam os_free(wstore); 443189251Ssam#else /* UNICODE */ 444189251Ssam cs = CertOpenSystemStore(0, store); 445189251Ssam#endif /* UNICODE */ 446189251Ssam if (cs == NULL) { 447189251Ssam wpa_printf(MSG_DEBUG, "%s: failed to open system cert store " 448189251Ssam "'%s': error=%d", __func__, store, 449189251Ssam (int) GetLastError()); 450189251Ssam return -1; 451189251Ssam } 452189251Ssam 453189251Ssam while ((ctx = CertEnumCertificatesInStore(cs, ctx))) { 454189251Ssam cert = d2i_X509(NULL, (OPENSSL_d2i_TYPE) &ctx->pbCertEncoded, 455189251Ssam ctx->cbCertEncoded); 456189251Ssam if (cert == NULL) { 457189251Ssam wpa_printf(MSG_INFO, "CryptoAPI: Could not process " 458189251Ssam "X509 DER encoding for CA cert"); 459189251Ssam continue; 460189251Ssam } 461189251Ssam 462189251Ssam X509_NAME_oneline(X509_get_subject_name(cert), buf, 463189251Ssam sizeof(buf)); 464189251Ssam wpa_printf(MSG_DEBUG, "OpenSSL: Loaded CA certificate for " 465189251Ssam "system certificate store: subject='%s'", buf); 466189251Ssam 467189251Ssam if (!X509_STORE_add_cert(ssl_ctx->cert_store, cert)) { 468189251Ssam tls_show_errors(MSG_WARNING, __func__, 469189251Ssam "Failed to add ca_cert to OpenSSL " 470189251Ssam "certificate store"); 471189251Ssam } 472189251Ssam 473189251Ssam X509_free(cert); 474189251Ssam } 475189251Ssam 476189251Ssam if (!CertCloseStore(cs, 0)) { 477189251Ssam wpa_printf(MSG_DEBUG, "%s: failed to close system cert store " 478189251Ssam "'%s': error=%d", __func__, name + 13, 479189251Ssam (int) GetLastError()); 480189251Ssam } 481189251Ssam 482189251Ssam return 0; 483189251Ssam} 484189251Ssam 485189251Ssam 486189251Ssam#else /* CONFIG_NATIVE_WINDOWS */ 487189251Ssam 488189251Ssamstatic int tls_cryptoapi_cert(SSL *ssl, const char *name) 489189251Ssam{ 490189251Ssam return -1; 491189251Ssam} 492189251Ssam 493189251Ssam#endif /* CONFIG_NATIVE_WINDOWS */ 494189251Ssam 495189251Ssam 496189251Ssamstatic void ssl_info_cb(const SSL *ssl, int where, int ret) 497189251Ssam{ 498189251Ssam const char *str; 499189251Ssam int w; 500189251Ssam 501189251Ssam wpa_printf(MSG_DEBUG, "SSL: (where=0x%x ret=0x%x)", where, ret); 502189251Ssam w = where & ~SSL_ST_MASK; 503189251Ssam if (w & SSL_ST_CONNECT) 504189251Ssam str = "SSL_connect"; 505189251Ssam else if (w & SSL_ST_ACCEPT) 506189251Ssam str = "SSL_accept"; 507189251Ssam else 508189251Ssam str = "undefined"; 509189251Ssam 510189251Ssam if (where & SSL_CB_LOOP) { 511189251Ssam wpa_printf(MSG_DEBUG, "SSL: %s:%s", 512189251Ssam str, SSL_state_string_long(ssl)); 513189251Ssam } else if (where & SSL_CB_ALERT) { 514189251Ssam wpa_printf(MSG_INFO, "SSL: SSL3 alert: %s:%s:%s", 515189251Ssam where & SSL_CB_READ ? 516189251Ssam "read (remote end reported an error)" : 517189251Ssam "write (local SSL3 detected an error)", 518189251Ssam SSL_alert_type_string_long(ret), 519189251Ssam SSL_alert_desc_string_long(ret)); 520189251Ssam if ((ret >> 8) == SSL3_AL_FATAL) { 521189251Ssam struct tls_connection *conn = 522189251Ssam SSL_get_app_data((SSL *) ssl); 523189251Ssam if (where & SSL_CB_READ) 524189251Ssam conn->read_alerts++; 525189251Ssam else 526189251Ssam conn->write_alerts++; 527189251Ssam } 528252726Srpaulo if (tls_global->event_cb != NULL) { 529252726Srpaulo union tls_event_data ev; 530252726Srpaulo os_memset(&ev, 0, sizeof(ev)); 531252726Srpaulo ev.alert.is_local = !(where & SSL_CB_READ); 532252726Srpaulo ev.alert.type = SSL_alert_type_string_long(ret); 533252726Srpaulo ev.alert.description = SSL_alert_desc_string_long(ret); 534252726Srpaulo tls_global->event_cb(tls_global->cb_ctx, TLS_ALERT, 535252726Srpaulo &ev); 536252726Srpaulo } 537189251Ssam } else if (where & SSL_CB_EXIT && ret <= 0) { 538189251Ssam wpa_printf(MSG_DEBUG, "SSL: %s:%s in %s", 539189251Ssam str, ret == 0 ? "failed" : "error", 540189251Ssam SSL_state_string_long(ssl)); 541189251Ssam } 542189251Ssam} 543189251Ssam 544189251Ssam 545189251Ssam#ifndef OPENSSL_NO_ENGINE 546189251Ssam/** 547189251Ssam * tls_engine_load_dynamic_generic - load any openssl engine 548189251Ssam * @pre: an array of commands and values that load an engine initialized 549189251Ssam * in the engine specific function 550189251Ssam * @post: an array of commands and values that initialize an already loaded 551189251Ssam * engine (or %NULL if not required) 552189251Ssam * @id: the engine id of the engine to load (only required if post is not %NULL 553189251Ssam * 554189251Ssam * This function is a generic function that loads any openssl engine. 555189251Ssam * 556189251Ssam * Returns: 0 on success, -1 on failure 557189251Ssam */ 558189251Ssamstatic int tls_engine_load_dynamic_generic(const char *pre[], 559189251Ssam const char *post[], const char *id) 560189251Ssam{ 561189251Ssam ENGINE *engine; 562189251Ssam const char *dynamic_id = "dynamic"; 563189251Ssam 564189251Ssam engine = ENGINE_by_id(id); 565189251Ssam if (engine) { 566189251Ssam ENGINE_free(engine); 567189251Ssam wpa_printf(MSG_DEBUG, "ENGINE: engine '%s' is already " 568189251Ssam "available", id); 569189251Ssam return 0; 570189251Ssam } 571189251Ssam ERR_clear_error(); 572189251Ssam 573189251Ssam engine = ENGINE_by_id(dynamic_id); 574189251Ssam if (engine == NULL) { 575189251Ssam wpa_printf(MSG_INFO, "ENGINE: Can't find engine %s [%s]", 576189251Ssam dynamic_id, 577189251Ssam ERR_error_string(ERR_get_error(), NULL)); 578189251Ssam return -1; 579189251Ssam } 580189251Ssam 581189251Ssam /* Perform the pre commands. This will load the engine. */ 582189251Ssam while (pre && pre[0]) { 583189251Ssam wpa_printf(MSG_DEBUG, "ENGINE: '%s' '%s'", pre[0], pre[1]); 584189251Ssam if (ENGINE_ctrl_cmd_string(engine, pre[0], pre[1], 0) == 0) { 585189251Ssam wpa_printf(MSG_INFO, "ENGINE: ctrl cmd_string failed: " 586189251Ssam "%s %s [%s]", pre[0], pre[1], 587189251Ssam ERR_error_string(ERR_get_error(), NULL)); 588189251Ssam ENGINE_free(engine); 589189251Ssam return -1; 590189251Ssam } 591189251Ssam pre += 2; 592189251Ssam } 593189251Ssam 594189251Ssam /* 595189251Ssam * Free the reference to the "dynamic" engine. The loaded engine can 596189251Ssam * now be looked up using ENGINE_by_id(). 597189251Ssam */ 598189251Ssam ENGINE_free(engine); 599189251Ssam 600189251Ssam engine = ENGINE_by_id(id); 601189251Ssam if (engine == NULL) { 602189251Ssam wpa_printf(MSG_INFO, "ENGINE: Can't find engine %s [%s]", 603189251Ssam id, ERR_error_string(ERR_get_error(), NULL)); 604189251Ssam return -1; 605189251Ssam } 606189251Ssam 607189251Ssam while (post && post[0]) { 608189251Ssam wpa_printf(MSG_DEBUG, "ENGINE: '%s' '%s'", post[0], post[1]); 609189251Ssam if (ENGINE_ctrl_cmd_string(engine, post[0], post[1], 0) == 0) { 610189251Ssam wpa_printf(MSG_DEBUG, "ENGINE: ctrl cmd_string failed:" 611189251Ssam " %s %s [%s]", post[0], post[1], 612189251Ssam ERR_error_string(ERR_get_error(), NULL)); 613189251Ssam ENGINE_remove(engine); 614189251Ssam ENGINE_free(engine); 615189251Ssam return -1; 616189251Ssam } 617189251Ssam post += 2; 618189251Ssam } 619189251Ssam ENGINE_free(engine); 620189251Ssam 621189251Ssam return 0; 622189251Ssam} 623189251Ssam 624189251Ssam 625189251Ssam/** 626189251Ssam * tls_engine_load_dynamic_pkcs11 - load the pkcs11 engine provided by opensc 627189251Ssam * @pkcs11_so_path: pksc11_so_path from the configuration 628189251Ssam * @pcks11_module_path: pkcs11_module_path from the configuration 629189251Ssam */ 630189251Ssamstatic int tls_engine_load_dynamic_pkcs11(const char *pkcs11_so_path, 631189251Ssam const char *pkcs11_module_path) 632189251Ssam{ 633189251Ssam char *engine_id = "pkcs11"; 634189251Ssam const char *pre_cmd[] = { 635189251Ssam "SO_PATH", NULL /* pkcs11_so_path */, 636189251Ssam "ID", NULL /* engine_id */, 637189251Ssam "LIST_ADD", "1", 638189251Ssam /* "NO_VCHECK", "1", */ 639189251Ssam "LOAD", NULL, 640189251Ssam NULL, NULL 641189251Ssam }; 642189251Ssam const char *post_cmd[] = { 643189251Ssam "MODULE_PATH", NULL /* pkcs11_module_path */, 644189251Ssam NULL, NULL 645189251Ssam }; 646189251Ssam 647189251Ssam if (!pkcs11_so_path || !pkcs11_module_path) 648189251Ssam return 0; 649189251Ssam 650189251Ssam pre_cmd[1] = pkcs11_so_path; 651189251Ssam pre_cmd[3] = engine_id; 652189251Ssam post_cmd[1] = pkcs11_module_path; 653189251Ssam 654189251Ssam wpa_printf(MSG_DEBUG, "ENGINE: Loading pkcs11 Engine from %s", 655189251Ssam pkcs11_so_path); 656189251Ssam 657189251Ssam return tls_engine_load_dynamic_generic(pre_cmd, post_cmd, engine_id); 658189251Ssam} 659189251Ssam 660189251Ssam 661189251Ssam/** 662189251Ssam * tls_engine_load_dynamic_opensc - load the opensc engine provided by opensc 663189251Ssam * @opensc_so_path: opensc_so_path from the configuration 664189251Ssam */ 665189251Ssamstatic int tls_engine_load_dynamic_opensc(const char *opensc_so_path) 666189251Ssam{ 667189251Ssam char *engine_id = "opensc"; 668189251Ssam const char *pre_cmd[] = { 669189251Ssam "SO_PATH", NULL /* opensc_so_path */, 670189251Ssam "ID", NULL /* engine_id */, 671189251Ssam "LIST_ADD", "1", 672189251Ssam "LOAD", NULL, 673189251Ssam NULL, NULL 674189251Ssam }; 675189251Ssam 676189251Ssam if (!opensc_so_path) 677189251Ssam return 0; 678189251Ssam 679189251Ssam pre_cmd[1] = opensc_so_path; 680189251Ssam pre_cmd[3] = engine_id; 681189251Ssam 682189251Ssam wpa_printf(MSG_DEBUG, "ENGINE: Loading OpenSC Engine from %s", 683189251Ssam opensc_so_path); 684189251Ssam 685189251Ssam return tls_engine_load_dynamic_generic(pre_cmd, NULL, engine_id); 686189251Ssam} 687189251Ssam#endif /* OPENSSL_NO_ENGINE */ 688189251Ssam 689189251Ssam 690189251Ssamvoid * tls_init(const struct tls_config *conf) 691189251Ssam{ 692189251Ssam SSL_CTX *ssl; 693189251Ssam 694189251Ssam if (tls_openssl_ref_count == 0) { 695214734Srpaulo tls_global = os_zalloc(sizeof(*tls_global)); 696214734Srpaulo if (tls_global == NULL) 697214734Srpaulo return NULL; 698214734Srpaulo if (conf) { 699214734Srpaulo tls_global->event_cb = conf->event_cb; 700214734Srpaulo tls_global->cb_ctx = conf->cb_ctx; 701252726Srpaulo tls_global->cert_in_cb = conf->cert_in_cb; 702214734Srpaulo } 703214734Srpaulo 704214734Srpaulo#ifdef CONFIG_FIPS 705214734Srpaulo#ifdef OPENSSL_FIPS 706214734Srpaulo if (conf && conf->fips_mode) { 707214734Srpaulo if (!FIPS_mode_set(1)) { 708214734Srpaulo wpa_printf(MSG_ERROR, "Failed to enable FIPS " 709214734Srpaulo "mode"); 710214734Srpaulo ERR_load_crypto_strings(); 711214734Srpaulo ERR_print_errors_fp(stderr); 712252726Srpaulo os_free(tls_global); 713252726Srpaulo tls_global = NULL; 714214734Srpaulo return NULL; 715214734Srpaulo } else 716214734Srpaulo wpa_printf(MSG_INFO, "Running in FIPS mode"); 717214734Srpaulo } 718214734Srpaulo#else /* OPENSSL_FIPS */ 719214734Srpaulo if (conf && conf->fips_mode) { 720214734Srpaulo wpa_printf(MSG_ERROR, "FIPS mode requested, but not " 721214734Srpaulo "supported"); 722252726Srpaulo os_free(tls_global); 723252726Srpaulo tls_global = NULL; 724214734Srpaulo return NULL; 725214734Srpaulo } 726214734Srpaulo#endif /* OPENSSL_FIPS */ 727214734Srpaulo#endif /* CONFIG_FIPS */ 728189251Ssam SSL_load_error_strings(); 729189251Ssam SSL_library_init(); 730252726Srpaulo#if (OPENSSL_VERSION_NUMBER >= 0x0090800fL) && !defined(OPENSSL_NO_SHA256) 731209158Srpaulo EVP_add_digest(EVP_sha256()); 732209158Srpaulo#endif /* OPENSSL_NO_SHA256 */ 733189251Ssam /* TODO: if /dev/urandom is available, PRNG is seeded 734189251Ssam * automatically. If this is not the case, random data should 735189251Ssam * be added here. */ 736189251Ssam 737189251Ssam#ifdef PKCS12_FUNCS 738209158Srpaulo#ifndef OPENSSL_NO_RC2 739209158Srpaulo /* 740209158Srpaulo * 40-bit RC2 is commonly used in PKCS#12 files, so enable it. 741209158Srpaulo * This is enabled by PKCS12_PBE_add() in OpenSSL 0.9.8 742209158Srpaulo * versions, but it looks like OpenSSL 1.0.0 does not do that 743209158Srpaulo * anymore. 744209158Srpaulo */ 745209158Srpaulo EVP_add_cipher(EVP_rc2_40_cbc()); 746209158Srpaulo#endif /* OPENSSL_NO_RC2 */ 747189251Ssam PKCS12_PBE_add(); 748189251Ssam#endif /* PKCS12_FUNCS */ 749189251Ssam } 750189251Ssam tls_openssl_ref_count++; 751189251Ssam 752189251Ssam ssl = SSL_CTX_new(TLSv1_method()); 753189251Ssam if (ssl == NULL) 754189251Ssam return NULL; 755189251Ssam 756189251Ssam SSL_CTX_set_info_callback(ssl, ssl_info_cb); 757189251Ssam 758189251Ssam#ifndef OPENSSL_NO_ENGINE 759189251Ssam if (conf && 760189251Ssam (conf->opensc_engine_path || conf->pkcs11_engine_path || 761189251Ssam conf->pkcs11_module_path)) { 762189251Ssam wpa_printf(MSG_DEBUG, "ENGINE: Loading dynamic engine"); 763189251Ssam ERR_load_ENGINE_strings(); 764189251Ssam ENGINE_load_dynamic(); 765189251Ssam 766189251Ssam if (tls_engine_load_dynamic_opensc(conf->opensc_engine_path) || 767189251Ssam tls_engine_load_dynamic_pkcs11(conf->pkcs11_engine_path, 768189251Ssam conf->pkcs11_module_path)) { 769189251Ssam tls_deinit(ssl); 770189251Ssam return NULL; 771189251Ssam } 772189251Ssam } 773189251Ssam#endif /* OPENSSL_NO_ENGINE */ 774189251Ssam 775189251Ssam return ssl; 776189251Ssam} 777189251Ssam 778189251Ssam 779189251Ssamvoid tls_deinit(void *ssl_ctx) 780189251Ssam{ 781189251Ssam SSL_CTX *ssl = ssl_ctx; 782189251Ssam SSL_CTX_free(ssl); 783189251Ssam 784189251Ssam tls_openssl_ref_count--; 785189251Ssam if (tls_openssl_ref_count == 0) { 786189251Ssam#ifndef OPENSSL_NO_ENGINE 787189251Ssam ENGINE_cleanup(); 788189251Ssam#endif /* OPENSSL_NO_ENGINE */ 789189251Ssam CRYPTO_cleanup_all_ex_data(); 790189251Ssam ERR_remove_state(0); 791189251Ssam ERR_free_strings(); 792189251Ssam EVP_cleanup(); 793214734Srpaulo os_free(tls_global); 794214734Srpaulo tls_global = NULL; 795189251Ssam } 796189251Ssam} 797189251Ssam 798189251Ssam 799189251Ssamstatic int tls_engine_init(struct tls_connection *conn, const char *engine_id, 800189251Ssam const char *pin, const char *key_id, 801189251Ssam const char *cert_id, const char *ca_cert_id) 802189251Ssam{ 803189251Ssam#ifndef OPENSSL_NO_ENGINE 804189251Ssam int ret = -1; 805189251Ssam if (engine_id == NULL) { 806189251Ssam wpa_printf(MSG_ERROR, "ENGINE: Engine ID not set"); 807189251Ssam return -1; 808189251Ssam } 809189251Ssam if (pin == NULL) { 810189251Ssam wpa_printf(MSG_ERROR, "ENGINE: Smartcard PIN not set"); 811189251Ssam return -1; 812189251Ssam } 813189251Ssam if (key_id == NULL) { 814189251Ssam wpa_printf(MSG_ERROR, "ENGINE: Key Id not set"); 815189251Ssam return -1; 816189251Ssam } 817189251Ssam 818189251Ssam ERR_clear_error(); 819189251Ssam conn->engine = ENGINE_by_id(engine_id); 820189251Ssam if (!conn->engine) { 821189251Ssam wpa_printf(MSG_ERROR, "ENGINE: engine %s not available [%s]", 822189251Ssam engine_id, ERR_error_string(ERR_get_error(), NULL)); 823189251Ssam goto err; 824189251Ssam } 825189251Ssam if (ENGINE_init(conn->engine) != 1) { 826189251Ssam wpa_printf(MSG_ERROR, "ENGINE: engine init failed " 827189251Ssam "(engine: %s) [%s]", engine_id, 828189251Ssam ERR_error_string(ERR_get_error(), NULL)); 829189251Ssam goto err; 830189251Ssam } 831189251Ssam wpa_printf(MSG_DEBUG, "ENGINE: engine initialized"); 832189251Ssam 833189251Ssam if (ENGINE_ctrl_cmd_string(conn->engine, "PIN", pin, 0) == 0) { 834189251Ssam wpa_printf(MSG_ERROR, "ENGINE: cannot set pin [%s]", 835189251Ssam ERR_error_string(ERR_get_error(), NULL)); 836189251Ssam goto err; 837189251Ssam } 838189251Ssam /* load private key first in-case PIN is required for cert */ 839189251Ssam conn->private_key = ENGINE_load_private_key(conn->engine, 840189251Ssam key_id, NULL, NULL); 841189251Ssam if (!conn->private_key) { 842189251Ssam wpa_printf(MSG_ERROR, "ENGINE: cannot load private key with id" 843189251Ssam " '%s' [%s]", key_id, 844189251Ssam ERR_error_string(ERR_get_error(), NULL)); 845189251Ssam ret = TLS_SET_PARAMS_ENGINE_PRV_INIT_FAILED; 846189251Ssam goto err; 847189251Ssam } 848189251Ssam 849189251Ssam /* handle a certificate and/or CA certificate */ 850189251Ssam if (cert_id || ca_cert_id) { 851189251Ssam const char *cmd_name = "LOAD_CERT_CTRL"; 852189251Ssam 853189251Ssam /* test if the engine supports a LOAD_CERT_CTRL */ 854189251Ssam if (!ENGINE_ctrl(conn->engine, ENGINE_CTRL_GET_CMD_FROM_NAME, 855189251Ssam 0, (void *)cmd_name, NULL)) { 856189251Ssam wpa_printf(MSG_ERROR, "ENGINE: engine does not support" 857189251Ssam " loading certificates"); 858189251Ssam ret = TLS_SET_PARAMS_ENGINE_PRV_INIT_FAILED; 859189251Ssam goto err; 860189251Ssam } 861189251Ssam } 862189251Ssam 863189251Ssam return 0; 864189251Ssam 865189251Ssamerr: 866189251Ssam if (conn->engine) { 867189251Ssam ENGINE_free(conn->engine); 868189251Ssam conn->engine = NULL; 869189251Ssam } 870189251Ssam 871189251Ssam if (conn->private_key) { 872189251Ssam EVP_PKEY_free(conn->private_key); 873189251Ssam conn->private_key = NULL; 874189251Ssam } 875189251Ssam 876189251Ssam return ret; 877189251Ssam#else /* OPENSSL_NO_ENGINE */ 878189251Ssam return 0; 879189251Ssam#endif /* OPENSSL_NO_ENGINE */ 880189251Ssam} 881189251Ssam 882189251Ssam 883189251Ssamstatic void tls_engine_deinit(struct tls_connection *conn) 884189251Ssam{ 885189251Ssam#ifndef OPENSSL_NO_ENGINE 886189251Ssam wpa_printf(MSG_DEBUG, "ENGINE: engine deinit"); 887189251Ssam if (conn->private_key) { 888189251Ssam EVP_PKEY_free(conn->private_key); 889189251Ssam conn->private_key = NULL; 890189251Ssam } 891189251Ssam if (conn->engine) { 892189251Ssam ENGINE_finish(conn->engine); 893189251Ssam conn->engine = NULL; 894189251Ssam } 895189251Ssam#endif /* OPENSSL_NO_ENGINE */ 896189251Ssam} 897189251Ssam 898189251Ssam 899189251Ssamint tls_get_errors(void *ssl_ctx) 900189251Ssam{ 901189251Ssam int count = 0; 902189251Ssam unsigned long err; 903189251Ssam 904189251Ssam while ((err = ERR_get_error())) { 905189251Ssam wpa_printf(MSG_INFO, "TLS - SSL error: %s", 906189251Ssam ERR_error_string(err, NULL)); 907189251Ssam count++; 908189251Ssam } 909189251Ssam 910189251Ssam return count; 911189251Ssam} 912189251Ssam 913189251Ssamstruct tls_connection * tls_connection_init(void *ssl_ctx) 914189251Ssam{ 915189251Ssam SSL_CTX *ssl = ssl_ctx; 916189251Ssam struct tls_connection *conn; 917189251Ssam long options; 918189251Ssam 919189251Ssam conn = os_zalloc(sizeof(*conn)); 920189251Ssam if (conn == NULL) 921189251Ssam return NULL; 922189251Ssam conn->ssl = SSL_new(ssl); 923189251Ssam if (conn->ssl == NULL) { 924189251Ssam tls_show_errors(MSG_INFO, __func__, 925189251Ssam "Failed to initialize new SSL connection"); 926189251Ssam os_free(conn); 927189251Ssam return NULL; 928189251Ssam } 929189251Ssam 930189251Ssam SSL_set_app_data(conn->ssl, conn); 931189251Ssam options = SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3 | 932189251Ssam SSL_OP_SINGLE_DH_USE; 933189251Ssam#ifdef SSL_OP_NO_COMPRESSION 934189251Ssam options |= SSL_OP_NO_COMPRESSION; 935189251Ssam#endif /* SSL_OP_NO_COMPRESSION */ 936189251Ssam SSL_set_options(conn->ssl, options); 937189251Ssam 938189251Ssam conn->ssl_in = BIO_new(BIO_s_mem()); 939189251Ssam if (!conn->ssl_in) { 940189251Ssam tls_show_errors(MSG_INFO, __func__, 941189251Ssam "Failed to create a new BIO for ssl_in"); 942189251Ssam SSL_free(conn->ssl); 943189251Ssam os_free(conn); 944189251Ssam return NULL; 945189251Ssam } 946189251Ssam 947189251Ssam conn->ssl_out = BIO_new(BIO_s_mem()); 948189251Ssam if (!conn->ssl_out) { 949189251Ssam tls_show_errors(MSG_INFO, __func__, 950189251Ssam "Failed to create a new BIO for ssl_out"); 951189251Ssam SSL_free(conn->ssl); 952189251Ssam BIO_free(conn->ssl_in); 953189251Ssam os_free(conn); 954189251Ssam return NULL; 955189251Ssam } 956189251Ssam 957189251Ssam SSL_set_bio(conn->ssl, conn->ssl_in, conn->ssl_out); 958189251Ssam 959189251Ssam return conn; 960189251Ssam} 961189251Ssam 962189251Ssam 963189251Ssamvoid tls_connection_deinit(void *ssl_ctx, struct tls_connection *conn) 964189251Ssam{ 965189251Ssam if (conn == NULL) 966189251Ssam return; 967189251Ssam SSL_free(conn->ssl); 968189251Ssam tls_engine_deinit(conn); 969189251Ssam os_free(conn->subject_match); 970189251Ssam os_free(conn->altsubject_match); 971189251Ssam os_free(conn->session_ticket); 972189251Ssam os_free(conn); 973189251Ssam} 974189251Ssam 975189251Ssam 976189251Ssamint tls_connection_established(void *ssl_ctx, struct tls_connection *conn) 977189251Ssam{ 978189251Ssam return conn ? SSL_is_init_finished(conn->ssl) : 0; 979189251Ssam} 980189251Ssam 981189251Ssam 982189251Ssamint tls_connection_shutdown(void *ssl_ctx, struct tls_connection *conn) 983189251Ssam{ 984189251Ssam if (conn == NULL) 985189251Ssam return -1; 986189251Ssam 987189251Ssam /* Shutdown previous TLS connection without notifying the peer 988189251Ssam * because the connection was already terminated in practice 989189251Ssam * and "close notify" shutdown alert would confuse AS. */ 990189251Ssam SSL_set_quiet_shutdown(conn->ssl, 1); 991189251Ssam SSL_shutdown(conn->ssl); 992189251Ssam return 0; 993189251Ssam} 994189251Ssam 995189251Ssam 996189251Ssamstatic int tls_match_altsubject_component(X509 *cert, int type, 997189251Ssam const char *value, size_t len) 998189251Ssam{ 999189251Ssam GENERAL_NAME *gen; 1000189251Ssam void *ext; 1001189251Ssam int i, found = 0; 1002189251Ssam 1003189251Ssam ext = X509_get_ext_d2i(cert, NID_subject_alt_name, NULL, NULL); 1004189251Ssam 1005189251Ssam for (i = 0; ext && i < sk_GENERAL_NAME_num(ext); i++) { 1006189251Ssam gen = sk_GENERAL_NAME_value(ext, i); 1007189251Ssam if (gen->type != type) 1008189251Ssam continue; 1009189251Ssam if (os_strlen((char *) gen->d.ia5->data) == len && 1010189251Ssam os_memcmp(value, gen->d.ia5->data, len) == 0) 1011189251Ssam found++; 1012189251Ssam } 1013189251Ssam 1014189251Ssam return found; 1015189251Ssam} 1016189251Ssam 1017189251Ssam 1018189251Ssamstatic int tls_match_altsubject(X509 *cert, const char *match) 1019189251Ssam{ 1020189251Ssam int type; 1021189251Ssam const char *pos, *end; 1022189251Ssam size_t len; 1023189251Ssam 1024189251Ssam pos = match; 1025189251Ssam do { 1026189251Ssam if (os_strncmp(pos, "EMAIL:", 6) == 0) { 1027189251Ssam type = GEN_EMAIL; 1028189251Ssam pos += 6; 1029189251Ssam } else if (os_strncmp(pos, "DNS:", 4) == 0) { 1030189251Ssam type = GEN_DNS; 1031189251Ssam pos += 4; 1032189251Ssam } else if (os_strncmp(pos, "URI:", 4) == 0) { 1033189251Ssam type = GEN_URI; 1034189251Ssam pos += 4; 1035189251Ssam } else { 1036189251Ssam wpa_printf(MSG_INFO, "TLS: Invalid altSubjectName " 1037189251Ssam "match '%s'", pos); 1038189251Ssam return 0; 1039189251Ssam } 1040189251Ssam end = os_strchr(pos, ';'); 1041189251Ssam while (end) { 1042189251Ssam if (os_strncmp(end + 1, "EMAIL:", 6) == 0 || 1043189251Ssam os_strncmp(end + 1, "DNS:", 4) == 0 || 1044189251Ssam os_strncmp(end + 1, "URI:", 4) == 0) 1045189251Ssam break; 1046189251Ssam end = os_strchr(end + 1, ';'); 1047189251Ssam } 1048189251Ssam if (end) 1049189251Ssam len = end - pos; 1050189251Ssam else 1051189251Ssam len = os_strlen(pos); 1052189251Ssam if (tls_match_altsubject_component(cert, type, pos, len) > 0) 1053189251Ssam return 1; 1054189251Ssam pos = end + 1; 1055189251Ssam } while (end); 1056189251Ssam 1057189251Ssam return 0; 1058189251Ssam} 1059189251Ssam 1060189251Ssam 1061214734Srpaulostatic enum tls_fail_reason openssl_tls_fail_reason(int err) 1062214734Srpaulo{ 1063214734Srpaulo switch (err) { 1064214734Srpaulo case X509_V_ERR_CERT_REVOKED: 1065214734Srpaulo return TLS_FAIL_REVOKED; 1066214734Srpaulo case X509_V_ERR_CERT_NOT_YET_VALID: 1067214734Srpaulo case X509_V_ERR_CRL_NOT_YET_VALID: 1068214734Srpaulo return TLS_FAIL_NOT_YET_VALID; 1069214734Srpaulo case X509_V_ERR_CERT_HAS_EXPIRED: 1070214734Srpaulo case X509_V_ERR_CRL_HAS_EXPIRED: 1071214734Srpaulo return TLS_FAIL_EXPIRED; 1072214734Srpaulo case X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT: 1073214734Srpaulo case X509_V_ERR_UNABLE_TO_GET_CRL: 1074214734Srpaulo case X509_V_ERR_UNABLE_TO_GET_CRL_ISSUER: 1075214734Srpaulo case X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN: 1076214734Srpaulo case X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY: 1077214734Srpaulo case X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT: 1078214734Srpaulo case X509_V_ERR_UNABLE_TO_VERIFY_LEAF_SIGNATURE: 1079214734Srpaulo case X509_V_ERR_CERT_CHAIN_TOO_LONG: 1080214734Srpaulo case X509_V_ERR_PATH_LENGTH_EXCEEDED: 1081214734Srpaulo case X509_V_ERR_INVALID_CA: 1082214734Srpaulo return TLS_FAIL_UNTRUSTED; 1083214734Srpaulo case X509_V_ERR_UNABLE_TO_DECRYPT_CERT_SIGNATURE: 1084214734Srpaulo case X509_V_ERR_UNABLE_TO_DECRYPT_CRL_SIGNATURE: 1085214734Srpaulo case X509_V_ERR_UNABLE_TO_DECODE_ISSUER_PUBLIC_KEY: 1086214734Srpaulo case X509_V_ERR_ERROR_IN_CERT_NOT_BEFORE_FIELD: 1087214734Srpaulo case X509_V_ERR_ERROR_IN_CERT_NOT_AFTER_FIELD: 1088214734Srpaulo case X509_V_ERR_ERROR_IN_CRL_LAST_UPDATE_FIELD: 1089214734Srpaulo case X509_V_ERR_ERROR_IN_CRL_NEXT_UPDATE_FIELD: 1090214734Srpaulo case X509_V_ERR_CERT_UNTRUSTED: 1091214734Srpaulo case X509_V_ERR_CERT_REJECTED: 1092214734Srpaulo return TLS_FAIL_BAD_CERTIFICATE; 1093214734Srpaulo default: 1094214734Srpaulo return TLS_FAIL_UNSPECIFIED; 1095214734Srpaulo } 1096214734Srpaulo} 1097214734Srpaulo 1098214734Srpaulo 1099214734Srpaulostatic struct wpabuf * get_x509_cert(X509 *cert) 1100214734Srpaulo{ 1101214734Srpaulo struct wpabuf *buf; 1102214734Srpaulo u8 *tmp; 1103214734Srpaulo 1104214734Srpaulo int cert_len = i2d_X509(cert, NULL); 1105214734Srpaulo if (cert_len <= 0) 1106214734Srpaulo return NULL; 1107214734Srpaulo 1108214734Srpaulo buf = wpabuf_alloc(cert_len); 1109214734Srpaulo if (buf == NULL) 1110214734Srpaulo return NULL; 1111214734Srpaulo 1112214734Srpaulo tmp = wpabuf_put(buf, cert_len); 1113214734Srpaulo i2d_X509(cert, &tmp); 1114214734Srpaulo return buf; 1115214734Srpaulo} 1116214734Srpaulo 1117214734Srpaulo 1118214734Srpaulostatic void openssl_tls_fail_event(struct tls_connection *conn, 1119214734Srpaulo X509 *err_cert, int err, int depth, 1120214734Srpaulo const char *subject, const char *err_str, 1121214734Srpaulo enum tls_fail_reason reason) 1122214734Srpaulo{ 1123214734Srpaulo union tls_event_data ev; 1124214734Srpaulo struct wpabuf *cert = NULL; 1125214734Srpaulo 1126214734Srpaulo if (tls_global->event_cb == NULL) 1127214734Srpaulo return; 1128214734Srpaulo 1129214734Srpaulo cert = get_x509_cert(err_cert); 1130214734Srpaulo os_memset(&ev, 0, sizeof(ev)); 1131214734Srpaulo ev.cert_fail.reason = reason != TLS_FAIL_UNSPECIFIED ? 1132214734Srpaulo reason : openssl_tls_fail_reason(err); 1133214734Srpaulo ev.cert_fail.depth = depth; 1134214734Srpaulo ev.cert_fail.subject = subject; 1135214734Srpaulo ev.cert_fail.reason_txt = err_str; 1136214734Srpaulo ev.cert_fail.cert = cert; 1137214734Srpaulo tls_global->event_cb(tls_global->cb_ctx, TLS_CERT_CHAIN_FAILURE, &ev); 1138214734Srpaulo wpabuf_free(cert); 1139214734Srpaulo} 1140214734Srpaulo 1141214734Srpaulo 1142214734Srpaulostatic void openssl_tls_cert_event(struct tls_connection *conn, 1143214734Srpaulo X509 *err_cert, int depth, 1144214734Srpaulo const char *subject) 1145214734Srpaulo{ 1146214734Srpaulo struct wpabuf *cert = NULL; 1147214734Srpaulo union tls_event_data ev; 1148214734Srpaulo#ifdef CONFIG_SHA256 1149214734Srpaulo u8 hash[32]; 1150214734Srpaulo#endif /* CONFIG_SHA256 */ 1151214734Srpaulo 1152214734Srpaulo if (tls_global->event_cb == NULL) 1153214734Srpaulo return; 1154214734Srpaulo 1155214734Srpaulo os_memset(&ev, 0, sizeof(ev)); 1156252726Srpaulo if (conn->cert_probe || tls_global->cert_in_cb) { 1157214734Srpaulo cert = get_x509_cert(err_cert); 1158214734Srpaulo ev.peer_cert.cert = cert; 1159214734Srpaulo } 1160214734Srpaulo#ifdef CONFIG_SHA256 1161214734Srpaulo if (cert) { 1162214734Srpaulo const u8 *addr[1]; 1163214734Srpaulo size_t len[1]; 1164214734Srpaulo addr[0] = wpabuf_head(cert); 1165214734Srpaulo len[0] = wpabuf_len(cert); 1166214734Srpaulo if (sha256_vector(1, addr, len, hash) == 0) { 1167214734Srpaulo ev.peer_cert.hash = hash; 1168214734Srpaulo ev.peer_cert.hash_len = sizeof(hash); 1169214734Srpaulo } 1170214734Srpaulo } 1171214734Srpaulo#endif /* CONFIG_SHA256 */ 1172214734Srpaulo ev.peer_cert.depth = depth; 1173214734Srpaulo ev.peer_cert.subject = subject; 1174214734Srpaulo tls_global->event_cb(tls_global->cb_ctx, TLS_PEER_CERTIFICATE, &ev); 1175214734Srpaulo wpabuf_free(cert); 1176214734Srpaulo} 1177214734Srpaulo 1178214734Srpaulo 1179189251Ssamstatic int tls_verify_cb(int preverify_ok, X509_STORE_CTX *x509_ctx) 1180189251Ssam{ 1181189251Ssam char buf[256]; 1182189251Ssam X509 *err_cert; 1183189251Ssam int err, depth; 1184189251Ssam SSL *ssl; 1185189251Ssam struct tls_connection *conn; 1186189251Ssam char *match, *altmatch; 1187214734Srpaulo const char *err_str; 1188189251Ssam 1189189251Ssam err_cert = X509_STORE_CTX_get_current_cert(x509_ctx); 1190189251Ssam err = X509_STORE_CTX_get_error(x509_ctx); 1191189251Ssam depth = X509_STORE_CTX_get_error_depth(x509_ctx); 1192189251Ssam ssl = X509_STORE_CTX_get_ex_data(x509_ctx, 1193189251Ssam SSL_get_ex_data_X509_STORE_CTX_idx()); 1194189251Ssam X509_NAME_oneline(X509_get_subject_name(err_cert), buf, sizeof(buf)); 1195189251Ssam 1196189251Ssam conn = SSL_get_app_data(ssl); 1197252726Srpaulo if (conn == NULL) 1198252726Srpaulo return 0; 1199252726Srpaulo match = conn->subject_match; 1200252726Srpaulo altmatch = conn->altsubject_match; 1201189251Ssam 1202214734Srpaulo if (!preverify_ok && !conn->ca_cert_verify) 1203214734Srpaulo preverify_ok = 1; 1204214734Srpaulo if (!preverify_ok && depth > 0 && conn->server_cert_only) 1205214734Srpaulo preverify_ok = 1; 1206252726Srpaulo if (!preverify_ok && (conn->flags & TLS_CONN_DISABLE_TIME_CHECKS) && 1207252726Srpaulo (err == X509_V_ERR_CERT_HAS_EXPIRED || 1208252726Srpaulo err == X509_V_ERR_CERT_NOT_YET_VALID)) { 1209252726Srpaulo wpa_printf(MSG_DEBUG, "OpenSSL: Ignore certificate validity " 1210252726Srpaulo "time mismatch"); 1211252726Srpaulo preverify_ok = 1; 1212252726Srpaulo } 1213214734Srpaulo 1214214734Srpaulo err_str = X509_verify_cert_error_string(err); 1215214734Srpaulo 1216214734Srpaulo#ifdef CONFIG_SHA256 1217214734Srpaulo if (preverify_ok && depth == 0 && conn->server_cert_only) { 1218214734Srpaulo struct wpabuf *cert; 1219214734Srpaulo cert = get_x509_cert(err_cert); 1220214734Srpaulo if (!cert) { 1221214734Srpaulo wpa_printf(MSG_DEBUG, "OpenSSL: Could not fetch " 1222214734Srpaulo "server certificate data"); 1223189251Ssam preverify_ok = 0; 1224214734Srpaulo } else { 1225214734Srpaulo u8 hash[32]; 1226214734Srpaulo const u8 *addr[1]; 1227214734Srpaulo size_t len[1]; 1228214734Srpaulo addr[0] = wpabuf_head(cert); 1229214734Srpaulo len[0] = wpabuf_len(cert); 1230214734Srpaulo if (sha256_vector(1, addr, len, hash) < 0 || 1231214734Srpaulo os_memcmp(conn->srv_cert_hash, hash, 32) != 0) { 1232214734Srpaulo err_str = "Server certificate mismatch"; 1233214734Srpaulo err = X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN; 1234214734Srpaulo preverify_ok = 0; 1235214734Srpaulo } 1236214734Srpaulo wpabuf_free(cert); 1237189251Ssam } 1238189251Ssam } 1239214734Srpaulo#endif /* CONFIG_SHA256 */ 1240189251Ssam 1241214734Srpaulo if (!preverify_ok) { 1242214734Srpaulo wpa_printf(MSG_WARNING, "TLS: Certificate verification failed," 1243214734Srpaulo " error %d (%s) depth %d for '%s'", err, err_str, 1244214734Srpaulo depth, buf); 1245214734Srpaulo openssl_tls_fail_event(conn, err_cert, err, depth, buf, 1246214734Srpaulo err_str, TLS_FAIL_UNSPECIFIED); 1247214734Srpaulo return preverify_ok; 1248214734Srpaulo } 1249214734Srpaulo 1250214734Srpaulo wpa_printf(MSG_DEBUG, "TLS: tls_verify_cb - preverify_ok=%d " 1251214734Srpaulo "err=%d (%s) ca_cert_verify=%d depth=%d buf='%s'", 1252214734Srpaulo preverify_ok, err, err_str, 1253214734Srpaulo conn->ca_cert_verify, depth, buf); 1254214734Srpaulo if (depth == 0 && match && os_strstr(buf, match) == NULL) { 1255214734Srpaulo wpa_printf(MSG_WARNING, "TLS: Subject '%s' did not " 1256214734Srpaulo "match with '%s'", buf, match); 1257214734Srpaulo preverify_ok = 0; 1258214734Srpaulo openssl_tls_fail_event(conn, err_cert, err, depth, buf, 1259214734Srpaulo "Subject mismatch", 1260214734Srpaulo TLS_FAIL_SUBJECT_MISMATCH); 1261214734Srpaulo } else if (depth == 0 && altmatch && 1262214734Srpaulo !tls_match_altsubject(err_cert, altmatch)) { 1263214734Srpaulo wpa_printf(MSG_WARNING, "TLS: altSubjectName match " 1264214734Srpaulo "'%s' not found", altmatch); 1265214734Srpaulo preverify_ok = 0; 1266214734Srpaulo openssl_tls_fail_event(conn, err_cert, err, depth, buf, 1267214734Srpaulo "AltSubject mismatch", 1268214734Srpaulo TLS_FAIL_ALTSUBJECT_MISMATCH); 1269214734Srpaulo } else 1270214734Srpaulo openssl_tls_cert_event(conn, err_cert, depth, buf); 1271214734Srpaulo 1272214734Srpaulo if (conn->cert_probe && preverify_ok && depth == 0) { 1273214734Srpaulo wpa_printf(MSG_DEBUG, "OpenSSL: Reject server certificate " 1274214734Srpaulo "on probe-only run"); 1275214734Srpaulo preverify_ok = 0; 1276214734Srpaulo openssl_tls_fail_event(conn, err_cert, err, depth, buf, 1277214734Srpaulo "Server certificate chain probe", 1278214734Srpaulo TLS_FAIL_SERVER_CHAIN_PROBE); 1279214734Srpaulo } 1280214734Srpaulo 1281252726Srpaulo if (preverify_ok && tls_global->event_cb != NULL) 1282252726Srpaulo tls_global->event_cb(tls_global->cb_ctx, 1283252726Srpaulo TLS_CERT_CHAIN_SUCCESS, NULL); 1284252726Srpaulo 1285189251Ssam return preverify_ok; 1286189251Ssam} 1287189251Ssam 1288189251Ssam 1289189251Ssam#ifndef OPENSSL_NO_STDIO 1290189251Ssamstatic int tls_load_ca_der(void *_ssl_ctx, const char *ca_cert) 1291189251Ssam{ 1292189251Ssam SSL_CTX *ssl_ctx = _ssl_ctx; 1293189251Ssam X509_LOOKUP *lookup; 1294189251Ssam int ret = 0; 1295189251Ssam 1296189251Ssam lookup = X509_STORE_add_lookup(ssl_ctx->cert_store, 1297189251Ssam X509_LOOKUP_file()); 1298189251Ssam if (lookup == NULL) { 1299189251Ssam tls_show_errors(MSG_WARNING, __func__, 1300189251Ssam "Failed add lookup for X509 store"); 1301189251Ssam return -1; 1302189251Ssam } 1303189251Ssam 1304189251Ssam if (!X509_LOOKUP_load_file(lookup, ca_cert, X509_FILETYPE_ASN1)) { 1305189251Ssam unsigned long err = ERR_peek_error(); 1306189251Ssam tls_show_errors(MSG_WARNING, __func__, 1307189251Ssam "Failed load CA in DER format"); 1308189251Ssam if (ERR_GET_LIB(err) == ERR_LIB_X509 && 1309189251Ssam ERR_GET_REASON(err) == X509_R_CERT_ALREADY_IN_HASH_TABLE) { 1310189251Ssam wpa_printf(MSG_DEBUG, "OpenSSL: %s - ignoring " 1311189251Ssam "cert already in hash table error", 1312189251Ssam __func__); 1313189251Ssam } else 1314189251Ssam ret = -1; 1315189251Ssam } 1316189251Ssam 1317189251Ssam return ret; 1318189251Ssam} 1319189251Ssam#endif /* OPENSSL_NO_STDIO */ 1320189251Ssam 1321189251Ssam 1322252726Srpaulo#ifdef ANDROID 1323252726Srpaulostatic BIO * BIO_from_keystore(const char *key) 1324252726Srpaulo{ 1325252726Srpaulo BIO *bio = NULL; 1326252726Srpaulo char value[KEYSTORE_MESSAGE_SIZE]; 1327252726Srpaulo int length = keystore_get(key, strlen(key), value); 1328252726Srpaulo if (length != -1 && (bio = BIO_new(BIO_s_mem())) != NULL) 1329252726Srpaulo BIO_write(bio, value, length); 1330252726Srpaulo return bio; 1331252726Srpaulo} 1332252726Srpaulo#endif /* ANDROID */ 1333252726Srpaulo 1334252726Srpaulo 1335189251Ssamstatic int tls_connection_ca_cert(void *_ssl_ctx, struct tls_connection *conn, 1336189251Ssam const char *ca_cert, const u8 *ca_cert_blob, 1337189251Ssam size_t ca_cert_blob_len, const char *ca_path) 1338189251Ssam{ 1339189251Ssam SSL_CTX *ssl_ctx = _ssl_ctx; 1340189251Ssam 1341189251Ssam /* 1342189251Ssam * Remove previously configured trusted CA certificates before adding 1343189251Ssam * new ones. 1344189251Ssam */ 1345189251Ssam X509_STORE_free(ssl_ctx->cert_store); 1346189251Ssam ssl_ctx->cert_store = X509_STORE_new(); 1347189251Ssam if (ssl_ctx->cert_store == NULL) { 1348189251Ssam wpa_printf(MSG_DEBUG, "OpenSSL: %s - failed to allocate new " 1349189251Ssam "certificate store", __func__); 1350189251Ssam return -1; 1351189251Ssam } 1352189251Ssam 1353214734Srpaulo SSL_set_verify(conn->ssl, SSL_VERIFY_PEER, tls_verify_cb); 1354214734Srpaulo conn->ca_cert_verify = 1; 1355214734Srpaulo 1356214734Srpaulo if (ca_cert && os_strncmp(ca_cert, "probe://", 8) == 0) { 1357214734Srpaulo wpa_printf(MSG_DEBUG, "OpenSSL: Probe for server certificate " 1358214734Srpaulo "chain"); 1359214734Srpaulo conn->cert_probe = 1; 1360214734Srpaulo conn->ca_cert_verify = 0; 1361214734Srpaulo return 0; 1362214734Srpaulo } 1363214734Srpaulo 1364214734Srpaulo if (ca_cert && os_strncmp(ca_cert, "hash://", 7) == 0) { 1365214734Srpaulo#ifdef CONFIG_SHA256 1366214734Srpaulo const char *pos = ca_cert + 7; 1367214734Srpaulo if (os_strncmp(pos, "server/sha256/", 14) != 0) { 1368214734Srpaulo wpa_printf(MSG_DEBUG, "OpenSSL: Unsupported ca_cert " 1369214734Srpaulo "hash value '%s'", ca_cert); 1370214734Srpaulo return -1; 1371214734Srpaulo } 1372214734Srpaulo pos += 14; 1373214734Srpaulo if (os_strlen(pos) != 32 * 2) { 1374214734Srpaulo wpa_printf(MSG_DEBUG, "OpenSSL: Unexpected SHA256 " 1375214734Srpaulo "hash length in ca_cert '%s'", ca_cert); 1376214734Srpaulo return -1; 1377214734Srpaulo } 1378214734Srpaulo if (hexstr2bin(pos, conn->srv_cert_hash, 32) < 0) { 1379214734Srpaulo wpa_printf(MSG_DEBUG, "OpenSSL: Invalid SHA256 hash " 1380214734Srpaulo "value in ca_cert '%s'", ca_cert); 1381214734Srpaulo return -1; 1382214734Srpaulo } 1383214734Srpaulo conn->server_cert_only = 1; 1384214734Srpaulo wpa_printf(MSG_DEBUG, "OpenSSL: Checking only server " 1385214734Srpaulo "certificate match"); 1386214734Srpaulo return 0; 1387214734Srpaulo#else /* CONFIG_SHA256 */ 1388214734Srpaulo wpa_printf(MSG_INFO, "No SHA256 included in the build - " 1389214734Srpaulo "cannot validate server certificate hash"); 1390214734Srpaulo return -1; 1391214734Srpaulo#endif /* CONFIG_SHA256 */ 1392214734Srpaulo } 1393214734Srpaulo 1394189251Ssam if (ca_cert_blob) { 1395189251Ssam X509 *cert = d2i_X509(NULL, (OPENSSL_d2i_TYPE) &ca_cert_blob, 1396189251Ssam ca_cert_blob_len); 1397189251Ssam if (cert == NULL) { 1398189251Ssam tls_show_errors(MSG_WARNING, __func__, 1399189251Ssam "Failed to parse ca_cert_blob"); 1400189251Ssam return -1; 1401189251Ssam } 1402189251Ssam 1403189251Ssam if (!X509_STORE_add_cert(ssl_ctx->cert_store, cert)) { 1404189251Ssam unsigned long err = ERR_peek_error(); 1405189251Ssam tls_show_errors(MSG_WARNING, __func__, 1406189251Ssam "Failed to add ca_cert_blob to " 1407189251Ssam "certificate store"); 1408189251Ssam if (ERR_GET_LIB(err) == ERR_LIB_X509 && 1409189251Ssam ERR_GET_REASON(err) == 1410189251Ssam X509_R_CERT_ALREADY_IN_HASH_TABLE) { 1411189251Ssam wpa_printf(MSG_DEBUG, "OpenSSL: %s - ignoring " 1412189251Ssam "cert already in hash table error", 1413189251Ssam __func__); 1414189251Ssam } else { 1415189251Ssam X509_free(cert); 1416189251Ssam return -1; 1417189251Ssam } 1418189251Ssam } 1419189251Ssam X509_free(cert); 1420189251Ssam wpa_printf(MSG_DEBUG, "OpenSSL: %s - added ca_cert_blob " 1421189251Ssam "to certificate store", __func__); 1422189251Ssam return 0; 1423189251Ssam } 1424189251Ssam 1425252726Srpaulo#ifdef ANDROID 1426252726Srpaulo if (ca_cert && os_strncmp("keystore://", ca_cert, 11) == 0) { 1427252726Srpaulo BIO *bio = BIO_from_keystore(&ca_cert[11]); 1428252726Srpaulo STACK_OF(X509_INFO) *stack = NULL; 1429252726Srpaulo int i; 1430252726Srpaulo 1431252726Srpaulo if (bio) { 1432252726Srpaulo stack = PEM_X509_INFO_read_bio(bio, NULL, NULL, NULL); 1433252726Srpaulo BIO_free(bio); 1434252726Srpaulo } 1435252726Srpaulo if (!stack) 1436252726Srpaulo return -1; 1437252726Srpaulo 1438252726Srpaulo for (i = 0; i < sk_X509_INFO_num(stack); ++i) { 1439252726Srpaulo X509_INFO *info = sk_X509_INFO_value(stack, i); 1440252726Srpaulo if (info->x509) { 1441252726Srpaulo X509_STORE_add_cert(ssl_ctx->cert_store, 1442252726Srpaulo info->x509); 1443252726Srpaulo } 1444252726Srpaulo if (info->crl) { 1445252726Srpaulo X509_STORE_add_crl(ssl_ctx->cert_store, 1446252726Srpaulo info->crl); 1447252726Srpaulo } 1448252726Srpaulo } 1449252726Srpaulo sk_X509_INFO_pop_free(stack, X509_INFO_free); 1450252726Srpaulo SSL_set_verify(conn->ssl, SSL_VERIFY_PEER, tls_verify_cb); 1451252726Srpaulo return 0; 1452252726Srpaulo } 1453252726Srpaulo#endif /* ANDROID */ 1454252726Srpaulo 1455189251Ssam#ifdef CONFIG_NATIVE_WINDOWS 1456189251Ssam if (ca_cert && tls_cryptoapi_ca_cert(ssl_ctx, conn->ssl, ca_cert) == 1457189251Ssam 0) { 1458189251Ssam wpa_printf(MSG_DEBUG, "OpenSSL: Added CA certificates from " 1459189251Ssam "system certificate store"); 1460189251Ssam return 0; 1461189251Ssam } 1462189251Ssam#endif /* CONFIG_NATIVE_WINDOWS */ 1463189251Ssam 1464189251Ssam if (ca_cert || ca_path) { 1465189251Ssam#ifndef OPENSSL_NO_STDIO 1466189251Ssam if (SSL_CTX_load_verify_locations(ssl_ctx, ca_cert, ca_path) != 1467189251Ssam 1) { 1468189251Ssam tls_show_errors(MSG_WARNING, __func__, 1469189251Ssam "Failed to load root certificates"); 1470189251Ssam if (ca_cert && 1471189251Ssam tls_load_ca_der(ssl_ctx, ca_cert) == 0) { 1472189251Ssam wpa_printf(MSG_DEBUG, "OpenSSL: %s - loaded " 1473189251Ssam "DER format CA certificate", 1474189251Ssam __func__); 1475189251Ssam } else 1476189251Ssam return -1; 1477189251Ssam } else { 1478189251Ssam wpa_printf(MSG_DEBUG, "TLS: Trusted root " 1479189251Ssam "certificate(s) loaded"); 1480189251Ssam tls_get_errors(ssl_ctx); 1481189251Ssam } 1482189251Ssam#else /* OPENSSL_NO_STDIO */ 1483189251Ssam wpa_printf(MSG_DEBUG, "OpenSSL: %s - OPENSSL_NO_STDIO", 1484189251Ssam __func__); 1485189251Ssam return -1; 1486189251Ssam#endif /* OPENSSL_NO_STDIO */ 1487189251Ssam } else { 1488189251Ssam /* No ca_cert configured - do not try to verify server 1489189251Ssam * certificate */ 1490214734Srpaulo conn->ca_cert_verify = 0; 1491189251Ssam } 1492189251Ssam 1493189251Ssam return 0; 1494189251Ssam} 1495189251Ssam 1496189251Ssam 1497189251Ssamstatic int tls_global_ca_cert(SSL_CTX *ssl_ctx, const char *ca_cert) 1498189251Ssam{ 1499189251Ssam if (ca_cert) { 1500189251Ssam if (SSL_CTX_load_verify_locations(ssl_ctx, ca_cert, NULL) != 1) 1501189251Ssam { 1502189251Ssam tls_show_errors(MSG_WARNING, __func__, 1503189251Ssam "Failed to load root certificates"); 1504189251Ssam return -1; 1505189251Ssam } 1506189251Ssam 1507189251Ssam wpa_printf(MSG_DEBUG, "TLS: Trusted root " 1508189251Ssam "certificate(s) loaded"); 1509189251Ssam 1510189251Ssam#ifndef OPENSSL_NO_STDIO 1511189251Ssam /* Add the same CAs to the client certificate requests */ 1512189251Ssam SSL_CTX_set_client_CA_list(ssl_ctx, 1513189251Ssam SSL_load_client_CA_file(ca_cert)); 1514189251Ssam#endif /* OPENSSL_NO_STDIO */ 1515189251Ssam } 1516189251Ssam 1517189251Ssam return 0; 1518189251Ssam} 1519189251Ssam 1520189251Ssam 1521189251Ssamint tls_global_set_verify(void *ssl_ctx, int check_crl) 1522189251Ssam{ 1523189251Ssam int flags; 1524189251Ssam 1525189251Ssam if (check_crl) { 1526189251Ssam X509_STORE *cs = SSL_CTX_get_cert_store(ssl_ctx); 1527189251Ssam if (cs == NULL) { 1528189251Ssam tls_show_errors(MSG_INFO, __func__, "Failed to get " 1529189251Ssam "certificate store when enabling " 1530189251Ssam "check_crl"); 1531189251Ssam return -1; 1532189251Ssam } 1533189251Ssam flags = X509_V_FLAG_CRL_CHECK; 1534189251Ssam if (check_crl == 2) 1535189251Ssam flags |= X509_V_FLAG_CRL_CHECK_ALL; 1536189251Ssam X509_STORE_set_flags(cs, flags); 1537189251Ssam } 1538189251Ssam return 0; 1539189251Ssam} 1540189251Ssam 1541189251Ssam 1542189251Ssamstatic int tls_connection_set_subject_match(struct tls_connection *conn, 1543189251Ssam const char *subject_match, 1544189251Ssam const char *altsubject_match) 1545189251Ssam{ 1546189251Ssam os_free(conn->subject_match); 1547189251Ssam conn->subject_match = NULL; 1548189251Ssam if (subject_match) { 1549189251Ssam conn->subject_match = os_strdup(subject_match); 1550189251Ssam if (conn->subject_match == NULL) 1551189251Ssam return -1; 1552189251Ssam } 1553189251Ssam 1554189251Ssam os_free(conn->altsubject_match); 1555189251Ssam conn->altsubject_match = NULL; 1556189251Ssam if (altsubject_match) { 1557189251Ssam conn->altsubject_match = os_strdup(altsubject_match); 1558189251Ssam if (conn->altsubject_match == NULL) 1559189251Ssam return -1; 1560189251Ssam } 1561189251Ssam 1562189251Ssam return 0; 1563189251Ssam} 1564189251Ssam 1565189251Ssam 1566189251Ssamint tls_connection_set_verify(void *ssl_ctx, struct tls_connection *conn, 1567189251Ssam int verify_peer) 1568189251Ssam{ 1569189251Ssam static int counter = 0; 1570189251Ssam 1571189251Ssam if (conn == NULL) 1572189251Ssam return -1; 1573189251Ssam 1574189251Ssam if (verify_peer) { 1575214734Srpaulo conn->ca_cert_verify = 1; 1576189251Ssam SSL_set_verify(conn->ssl, SSL_VERIFY_PEER | 1577189251Ssam SSL_VERIFY_FAIL_IF_NO_PEER_CERT | 1578189251Ssam SSL_VERIFY_CLIENT_ONCE, tls_verify_cb); 1579189251Ssam } else { 1580214734Srpaulo conn->ca_cert_verify = 0; 1581189251Ssam SSL_set_verify(conn->ssl, SSL_VERIFY_NONE, NULL); 1582189251Ssam } 1583189251Ssam 1584189251Ssam SSL_set_accept_state(conn->ssl); 1585189251Ssam 1586189251Ssam /* 1587189251Ssam * Set session id context in order to avoid fatal errors when client 1588189251Ssam * tries to resume a session. However, set the context to a unique 1589189251Ssam * value in order to effectively disable session resumption for now 1590189251Ssam * since not all areas of the server code are ready for it (e.g., 1591189251Ssam * EAP-TTLS needs special handling for Phase 2 after abbreviated TLS 1592189251Ssam * handshake). 1593189251Ssam */ 1594189251Ssam counter++; 1595189251Ssam SSL_set_session_id_context(conn->ssl, 1596189251Ssam (const unsigned char *) &counter, 1597189251Ssam sizeof(counter)); 1598189251Ssam 1599189251Ssam return 0; 1600189251Ssam} 1601189251Ssam 1602189251Ssam 1603189251Ssamstatic int tls_connection_client_cert(struct tls_connection *conn, 1604189251Ssam const char *client_cert, 1605189251Ssam const u8 *client_cert_blob, 1606189251Ssam size_t client_cert_blob_len) 1607189251Ssam{ 1608189251Ssam if (client_cert == NULL && client_cert_blob == NULL) 1609189251Ssam return 0; 1610189251Ssam 1611189251Ssam if (client_cert_blob && 1612189251Ssam SSL_use_certificate_ASN1(conn->ssl, (u8 *) client_cert_blob, 1613189251Ssam client_cert_blob_len) == 1) { 1614189251Ssam wpa_printf(MSG_DEBUG, "OpenSSL: SSL_use_certificate_ASN1 --> " 1615189251Ssam "OK"); 1616189251Ssam return 0; 1617189251Ssam } else if (client_cert_blob) { 1618189251Ssam tls_show_errors(MSG_DEBUG, __func__, 1619189251Ssam "SSL_use_certificate_ASN1 failed"); 1620189251Ssam } 1621189251Ssam 1622189251Ssam if (client_cert == NULL) 1623189251Ssam return -1; 1624189251Ssam 1625252726Srpaulo#ifdef ANDROID 1626252726Srpaulo if (os_strncmp("keystore://", client_cert, 11) == 0) { 1627252726Srpaulo BIO *bio = BIO_from_keystore(&client_cert[11]); 1628252726Srpaulo X509 *x509 = NULL; 1629252726Srpaulo int ret = -1; 1630252726Srpaulo if (bio) { 1631252726Srpaulo x509 = PEM_read_bio_X509(bio, NULL, NULL, NULL); 1632252726Srpaulo BIO_free(bio); 1633252726Srpaulo } 1634252726Srpaulo if (x509) { 1635252726Srpaulo if (SSL_use_certificate(conn->ssl, x509) == 1) 1636252726Srpaulo ret = 0; 1637252726Srpaulo X509_free(x509); 1638252726Srpaulo } 1639252726Srpaulo return ret; 1640252726Srpaulo } 1641252726Srpaulo#endif /* ANDROID */ 1642252726Srpaulo 1643189251Ssam#ifndef OPENSSL_NO_STDIO 1644189251Ssam if (SSL_use_certificate_file(conn->ssl, client_cert, 1645189251Ssam SSL_FILETYPE_ASN1) == 1) { 1646189251Ssam wpa_printf(MSG_DEBUG, "OpenSSL: SSL_use_certificate_file (DER)" 1647189251Ssam " --> OK"); 1648189251Ssam return 0; 1649189251Ssam } 1650189251Ssam 1651189251Ssam if (SSL_use_certificate_file(conn->ssl, client_cert, 1652189251Ssam SSL_FILETYPE_PEM) == 1) { 1653252726Srpaulo ERR_clear_error(); 1654189251Ssam wpa_printf(MSG_DEBUG, "OpenSSL: SSL_use_certificate_file (PEM)" 1655189251Ssam " --> OK"); 1656189251Ssam return 0; 1657189251Ssam } 1658252726Srpaulo 1659252726Srpaulo tls_show_errors(MSG_DEBUG, __func__, 1660252726Srpaulo "SSL_use_certificate_file failed"); 1661189251Ssam#else /* OPENSSL_NO_STDIO */ 1662189251Ssam wpa_printf(MSG_DEBUG, "OpenSSL: %s - OPENSSL_NO_STDIO", __func__); 1663189251Ssam#endif /* OPENSSL_NO_STDIO */ 1664189251Ssam 1665189251Ssam return -1; 1666189251Ssam} 1667189251Ssam 1668189251Ssam 1669189251Ssamstatic int tls_global_client_cert(SSL_CTX *ssl_ctx, const char *client_cert) 1670189251Ssam{ 1671189251Ssam#ifndef OPENSSL_NO_STDIO 1672189251Ssam if (client_cert == NULL) 1673189251Ssam return 0; 1674189251Ssam 1675189251Ssam if (SSL_CTX_use_certificate_file(ssl_ctx, client_cert, 1676189251Ssam SSL_FILETYPE_ASN1) != 1 && 1677252726Srpaulo SSL_CTX_use_certificate_chain_file(ssl_ctx, client_cert) != 1 && 1678189251Ssam SSL_CTX_use_certificate_file(ssl_ctx, client_cert, 1679189251Ssam SSL_FILETYPE_PEM) != 1) { 1680189251Ssam tls_show_errors(MSG_INFO, __func__, 1681189251Ssam "Failed to load client certificate"); 1682189251Ssam return -1; 1683189251Ssam } 1684189251Ssam return 0; 1685189251Ssam#else /* OPENSSL_NO_STDIO */ 1686189251Ssam if (client_cert == NULL) 1687189251Ssam return 0; 1688189251Ssam wpa_printf(MSG_DEBUG, "OpenSSL: %s - OPENSSL_NO_STDIO", __func__); 1689189251Ssam return -1; 1690189251Ssam#endif /* OPENSSL_NO_STDIO */ 1691189251Ssam} 1692189251Ssam 1693189251Ssam 1694189251Ssamstatic int tls_passwd_cb(char *buf, int size, int rwflag, void *password) 1695189251Ssam{ 1696189251Ssam if (password == NULL) { 1697189251Ssam return 0; 1698189251Ssam } 1699189251Ssam os_strlcpy(buf, (char *) password, size); 1700189251Ssam return os_strlen(buf); 1701189251Ssam} 1702189251Ssam 1703189251Ssam 1704189251Ssam#ifdef PKCS12_FUNCS 1705189251Ssamstatic int tls_parse_pkcs12(SSL_CTX *ssl_ctx, SSL *ssl, PKCS12 *p12, 1706189251Ssam const char *passwd) 1707189251Ssam{ 1708189251Ssam EVP_PKEY *pkey; 1709189251Ssam X509 *cert; 1710189251Ssam STACK_OF(X509) *certs; 1711189251Ssam int res = 0; 1712189251Ssam char buf[256]; 1713189251Ssam 1714189251Ssam pkey = NULL; 1715189251Ssam cert = NULL; 1716189251Ssam certs = NULL; 1717189251Ssam if (!PKCS12_parse(p12, passwd, &pkey, &cert, &certs)) { 1718189251Ssam tls_show_errors(MSG_DEBUG, __func__, 1719189251Ssam "Failed to parse PKCS12 file"); 1720189251Ssam PKCS12_free(p12); 1721189251Ssam return -1; 1722189251Ssam } 1723189251Ssam wpa_printf(MSG_DEBUG, "TLS: Successfully parsed PKCS12 data"); 1724189251Ssam 1725189251Ssam if (cert) { 1726189251Ssam X509_NAME_oneline(X509_get_subject_name(cert), buf, 1727189251Ssam sizeof(buf)); 1728189251Ssam wpa_printf(MSG_DEBUG, "TLS: Got certificate from PKCS12: " 1729189251Ssam "subject='%s'", buf); 1730189251Ssam if (ssl) { 1731189251Ssam if (SSL_use_certificate(ssl, cert) != 1) 1732189251Ssam res = -1; 1733189251Ssam } else { 1734189251Ssam if (SSL_CTX_use_certificate(ssl_ctx, cert) != 1) 1735189251Ssam res = -1; 1736189251Ssam } 1737189251Ssam X509_free(cert); 1738189251Ssam } 1739189251Ssam 1740189251Ssam if (pkey) { 1741189251Ssam wpa_printf(MSG_DEBUG, "TLS: Got private key from PKCS12"); 1742189251Ssam if (ssl) { 1743189251Ssam if (SSL_use_PrivateKey(ssl, pkey) != 1) 1744189251Ssam res = -1; 1745189251Ssam } else { 1746189251Ssam if (SSL_CTX_use_PrivateKey(ssl_ctx, pkey) != 1) 1747189251Ssam res = -1; 1748189251Ssam } 1749189251Ssam EVP_PKEY_free(pkey); 1750189251Ssam } 1751189251Ssam 1752189251Ssam if (certs) { 1753189251Ssam while ((cert = sk_X509_pop(certs)) != NULL) { 1754189251Ssam X509_NAME_oneline(X509_get_subject_name(cert), buf, 1755189251Ssam sizeof(buf)); 1756189251Ssam wpa_printf(MSG_DEBUG, "TLS: additional certificate" 1757189251Ssam " from PKCS12: subject='%s'", buf); 1758189251Ssam /* 1759189251Ssam * There is no SSL equivalent for the chain cert - so 1760189251Ssam * always add it to the context... 1761189251Ssam */ 1762189251Ssam if (SSL_CTX_add_extra_chain_cert(ssl_ctx, cert) != 1) { 1763189251Ssam res = -1; 1764189251Ssam break; 1765189251Ssam } 1766189251Ssam } 1767189251Ssam sk_X509_free(certs); 1768189251Ssam } 1769189251Ssam 1770189251Ssam PKCS12_free(p12); 1771189251Ssam 1772189251Ssam if (res < 0) 1773189251Ssam tls_get_errors(ssl_ctx); 1774189251Ssam 1775189251Ssam return res; 1776189251Ssam} 1777189251Ssam#endif /* PKCS12_FUNCS */ 1778189251Ssam 1779189251Ssam 1780189251Ssamstatic int tls_read_pkcs12(SSL_CTX *ssl_ctx, SSL *ssl, const char *private_key, 1781189251Ssam const char *passwd) 1782189251Ssam{ 1783189251Ssam#ifdef PKCS12_FUNCS 1784189251Ssam FILE *f; 1785189251Ssam PKCS12 *p12; 1786189251Ssam 1787189251Ssam f = fopen(private_key, "rb"); 1788189251Ssam if (f == NULL) 1789189251Ssam return -1; 1790189251Ssam 1791189251Ssam p12 = d2i_PKCS12_fp(f, NULL); 1792189251Ssam fclose(f); 1793189251Ssam 1794189251Ssam if (p12 == NULL) { 1795189251Ssam tls_show_errors(MSG_INFO, __func__, 1796189251Ssam "Failed to use PKCS#12 file"); 1797189251Ssam return -1; 1798189251Ssam } 1799189251Ssam 1800189251Ssam return tls_parse_pkcs12(ssl_ctx, ssl, p12, passwd); 1801189251Ssam 1802189251Ssam#else /* PKCS12_FUNCS */ 1803189251Ssam wpa_printf(MSG_INFO, "TLS: PKCS12 support disabled - cannot read " 1804189251Ssam "p12/pfx files"); 1805189251Ssam return -1; 1806189251Ssam#endif /* PKCS12_FUNCS */ 1807189251Ssam} 1808189251Ssam 1809189251Ssam 1810189251Ssamstatic int tls_read_pkcs12_blob(SSL_CTX *ssl_ctx, SSL *ssl, 1811189251Ssam const u8 *blob, size_t len, const char *passwd) 1812189251Ssam{ 1813189251Ssam#ifdef PKCS12_FUNCS 1814189251Ssam PKCS12 *p12; 1815189251Ssam 1816189251Ssam p12 = d2i_PKCS12(NULL, (OPENSSL_d2i_TYPE) &blob, len); 1817189251Ssam if (p12 == NULL) { 1818189251Ssam tls_show_errors(MSG_INFO, __func__, 1819189251Ssam "Failed to use PKCS#12 blob"); 1820189251Ssam return -1; 1821189251Ssam } 1822189251Ssam 1823189251Ssam return tls_parse_pkcs12(ssl_ctx, ssl, p12, passwd); 1824189251Ssam 1825189251Ssam#else /* PKCS12_FUNCS */ 1826189251Ssam wpa_printf(MSG_INFO, "TLS: PKCS12 support disabled - cannot parse " 1827189251Ssam "p12/pfx blobs"); 1828189251Ssam return -1; 1829189251Ssam#endif /* PKCS12_FUNCS */ 1830189251Ssam} 1831189251Ssam 1832189251Ssam 1833189251Ssam#ifndef OPENSSL_NO_ENGINE 1834189251Ssamstatic int tls_engine_get_cert(struct tls_connection *conn, 1835189251Ssam const char *cert_id, 1836189251Ssam X509 **cert) 1837189251Ssam{ 1838189251Ssam /* this runs after the private key is loaded so no PIN is required */ 1839189251Ssam struct { 1840189251Ssam const char *cert_id; 1841189251Ssam X509 *cert; 1842189251Ssam } params; 1843189251Ssam params.cert_id = cert_id; 1844189251Ssam params.cert = NULL; 1845189251Ssam 1846189251Ssam if (!ENGINE_ctrl_cmd(conn->engine, "LOAD_CERT_CTRL", 1847189251Ssam 0, ¶ms, NULL, 1)) { 1848189251Ssam wpa_printf(MSG_ERROR, "ENGINE: cannot load client cert with id" 1849189251Ssam " '%s' [%s]", cert_id, 1850189251Ssam ERR_error_string(ERR_get_error(), NULL)); 1851189251Ssam return TLS_SET_PARAMS_ENGINE_PRV_INIT_FAILED; 1852189251Ssam } 1853189251Ssam if (!params.cert) { 1854189251Ssam wpa_printf(MSG_ERROR, "ENGINE: did not properly cert with id" 1855189251Ssam " '%s'", cert_id); 1856189251Ssam return TLS_SET_PARAMS_ENGINE_PRV_INIT_FAILED; 1857189251Ssam } 1858189251Ssam *cert = params.cert; 1859189251Ssam return 0; 1860189251Ssam} 1861189251Ssam#endif /* OPENSSL_NO_ENGINE */ 1862189251Ssam 1863189251Ssam 1864189251Ssamstatic int tls_connection_engine_client_cert(struct tls_connection *conn, 1865189251Ssam const char *cert_id) 1866189251Ssam{ 1867189251Ssam#ifndef OPENSSL_NO_ENGINE 1868189251Ssam X509 *cert; 1869189251Ssam 1870189251Ssam if (tls_engine_get_cert(conn, cert_id, &cert)) 1871189251Ssam return -1; 1872189251Ssam 1873189251Ssam if (!SSL_use_certificate(conn->ssl, cert)) { 1874189251Ssam tls_show_errors(MSG_ERROR, __func__, 1875189251Ssam "SSL_use_certificate failed"); 1876189251Ssam X509_free(cert); 1877189251Ssam return -1; 1878189251Ssam } 1879189251Ssam X509_free(cert); 1880189251Ssam wpa_printf(MSG_DEBUG, "ENGINE: SSL_use_certificate --> " 1881189251Ssam "OK"); 1882189251Ssam return 0; 1883189251Ssam 1884189251Ssam#else /* OPENSSL_NO_ENGINE */ 1885189251Ssam return -1; 1886189251Ssam#endif /* OPENSSL_NO_ENGINE */ 1887189251Ssam} 1888189251Ssam 1889189251Ssam 1890189251Ssamstatic int tls_connection_engine_ca_cert(void *_ssl_ctx, 1891189251Ssam struct tls_connection *conn, 1892189251Ssam const char *ca_cert_id) 1893189251Ssam{ 1894189251Ssam#ifndef OPENSSL_NO_ENGINE 1895189251Ssam X509 *cert; 1896189251Ssam SSL_CTX *ssl_ctx = _ssl_ctx; 1897189251Ssam 1898189251Ssam if (tls_engine_get_cert(conn, ca_cert_id, &cert)) 1899189251Ssam return -1; 1900189251Ssam 1901189251Ssam /* start off the same as tls_connection_ca_cert */ 1902189251Ssam X509_STORE_free(ssl_ctx->cert_store); 1903189251Ssam ssl_ctx->cert_store = X509_STORE_new(); 1904189251Ssam if (ssl_ctx->cert_store == NULL) { 1905189251Ssam wpa_printf(MSG_DEBUG, "OpenSSL: %s - failed to allocate new " 1906189251Ssam "certificate store", __func__); 1907189251Ssam X509_free(cert); 1908189251Ssam return -1; 1909189251Ssam } 1910189251Ssam if (!X509_STORE_add_cert(ssl_ctx->cert_store, cert)) { 1911189251Ssam unsigned long err = ERR_peek_error(); 1912189251Ssam tls_show_errors(MSG_WARNING, __func__, 1913189251Ssam "Failed to add CA certificate from engine " 1914189251Ssam "to certificate store"); 1915189251Ssam if (ERR_GET_LIB(err) == ERR_LIB_X509 && 1916189251Ssam ERR_GET_REASON(err) == X509_R_CERT_ALREADY_IN_HASH_TABLE) { 1917189251Ssam wpa_printf(MSG_DEBUG, "OpenSSL: %s - ignoring cert" 1918189251Ssam " already in hash table error", 1919189251Ssam __func__); 1920189251Ssam } else { 1921189251Ssam X509_free(cert); 1922189251Ssam return -1; 1923189251Ssam } 1924189251Ssam } 1925189251Ssam X509_free(cert); 1926189251Ssam wpa_printf(MSG_DEBUG, "OpenSSL: %s - added CA certificate from engine " 1927189251Ssam "to certificate store", __func__); 1928189251Ssam SSL_set_verify(conn->ssl, SSL_VERIFY_PEER, tls_verify_cb); 1929252726Srpaulo conn->ca_cert_verify = 1; 1930252726Srpaulo 1931189251Ssam return 0; 1932189251Ssam 1933189251Ssam#else /* OPENSSL_NO_ENGINE */ 1934189251Ssam return -1; 1935189251Ssam#endif /* OPENSSL_NO_ENGINE */ 1936189251Ssam} 1937189251Ssam 1938189251Ssam 1939189251Ssamstatic int tls_connection_engine_private_key(struct tls_connection *conn) 1940189251Ssam{ 1941189251Ssam#ifndef OPENSSL_NO_ENGINE 1942189251Ssam if (SSL_use_PrivateKey(conn->ssl, conn->private_key) != 1) { 1943189251Ssam tls_show_errors(MSG_ERROR, __func__, 1944189251Ssam "ENGINE: cannot use private key for TLS"); 1945189251Ssam return -1; 1946189251Ssam } 1947189251Ssam if (!SSL_check_private_key(conn->ssl)) { 1948189251Ssam tls_show_errors(MSG_INFO, __func__, 1949189251Ssam "Private key failed verification"); 1950189251Ssam return -1; 1951189251Ssam } 1952189251Ssam return 0; 1953189251Ssam#else /* OPENSSL_NO_ENGINE */ 1954189251Ssam wpa_printf(MSG_ERROR, "SSL: Configuration uses engine, but " 1955189251Ssam "engine support was not compiled in"); 1956189251Ssam return -1; 1957189251Ssam#endif /* OPENSSL_NO_ENGINE */ 1958189251Ssam} 1959189251Ssam 1960189251Ssam 1961189251Ssamstatic int tls_connection_private_key(void *_ssl_ctx, 1962189251Ssam struct tls_connection *conn, 1963189251Ssam const char *private_key, 1964189251Ssam const char *private_key_passwd, 1965189251Ssam const u8 *private_key_blob, 1966189251Ssam size_t private_key_blob_len) 1967189251Ssam{ 1968189251Ssam SSL_CTX *ssl_ctx = _ssl_ctx; 1969189251Ssam char *passwd; 1970189251Ssam int ok; 1971189251Ssam 1972189251Ssam if (private_key == NULL && private_key_blob == NULL) 1973189251Ssam return 0; 1974189251Ssam 1975189251Ssam if (private_key_passwd) { 1976189251Ssam passwd = os_strdup(private_key_passwd); 1977189251Ssam if (passwd == NULL) 1978189251Ssam return -1; 1979189251Ssam } else 1980189251Ssam passwd = NULL; 1981189251Ssam 1982189251Ssam SSL_CTX_set_default_passwd_cb(ssl_ctx, tls_passwd_cb); 1983189251Ssam SSL_CTX_set_default_passwd_cb_userdata(ssl_ctx, passwd); 1984189251Ssam 1985189251Ssam ok = 0; 1986189251Ssam while (private_key_blob) { 1987189251Ssam if (SSL_use_PrivateKey_ASN1(EVP_PKEY_RSA, conn->ssl, 1988189251Ssam (u8 *) private_key_blob, 1989189251Ssam private_key_blob_len) == 1) { 1990189251Ssam wpa_printf(MSG_DEBUG, "OpenSSL: SSL_use_PrivateKey_" 1991189251Ssam "ASN1(EVP_PKEY_RSA) --> OK"); 1992189251Ssam ok = 1; 1993189251Ssam break; 1994189251Ssam } 1995189251Ssam 1996189251Ssam if (SSL_use_PrivateKey_ASN1(EVP_PKEY_DSA, conn->ssl, 1997189251Ssam (u8 *) private_key_blob, 1998189251Ssam private_key_blob_len) == 1) { 1999189251Ssam wpa_printf(MSG_DEBUG, "OpenSSL: SSL_use_PrivateKey_" 2000189251Ssam "ASN1(EVP_PKEY_DSA) --> OK"); 2001189251Ssam ok = 1; 2002189251Ssam break; 2003189251Ssam } 2004189251Ssam 2005189251Ssam if (SSL_use_RSAPrivateKey_ASN1(conn->ssl, 2006189251Ssam (u8 *) private_key_blob, 2007189251Ssam private_key_blob_len) == 1) { 2008189251Ssam wpa_printf(MSG_DEBUG, "OpenSSL: " 2009189251Ssam "SSL_use_RSAPrivateKey_ASN1 --> OK"); 2010189251Ssam ok = 1; 2011189251Ssam break; 2012189251Ssam } 2013189251Ssam 2014189251Ssam if (tls_read_pkcs12_blob(ssl_ctx, conn->ssl, private_key_blob, 2015189251Ssam private_key_blob_len, passwd) == 0) { 2016189251Ssam wpa_printf(MSG_DEBUG, "OpenSSL: PKCS#12 as blob --> " 2017189251Ssam "OK"); 2018189251Ssam ok = 1; 2019189251Ssam break; 2020189251Ssam } 2021189251Ssam 2022189251Ssam break; 2023189251Ssam } 2024189251Ssam 2025252726Srpaulo#ifdef ANDROID 2026252726Srpaulo if (!ok && private_key && 2027252726Srpaulo os_strncmp("keystore://", private_key, 11) == 0) { 2028252726Srpaulo BIO *bio = BIO_from_keystore(&private_key[11]); 2029252726Srpaulo EVP_PKEY *pkey = NULL; 2030252726Srpaulo if (bio) { 2031252726Srpaulo pkey = PEM_read_bio_PrivateKey(bio, NULL, NULL, NULL); 2032252726Srpaulo BIO_free(bio); 2033252726Srpaulo } 2034252726Srpaulo if (pkey) { 2035252726Srpaulo if (SSL_use_PrivateKey(conn->ssl, pkey) == 1) { 2036252726Srpaulo wpa_printf(MSG_DEBUG, "OpenSSL: Private key " 2037252726Srpaulo "from keystore"); 2038252726Srpaulo ok = 1; 2039252726Srpaulo } 2040252726Srpaulo EVP_PKEY_free(pkey); 2041252726Srpaulo } 2042252726Srpaulo } 2043252726Srpaulo#endif /* ANDROID */ 2044252726Srpaulo 2045189251Ssam while (!ok && private_key) { 2046189251Ssam#ifndef OPENSSL_NO_STDIO 2047189251Ssam if (SSL_use_PrivateKey_file(conn->ssl, private_key, 2048189251Ssam SSL_FILETYPE_ASN1) == 1) { 2049189251Ssam wpa_printf(MSG_DEBUG, "OpenSSL: " 2050189251Ssam "SSL_use_PrivateKey_File (DER) --> OK"); 2051189251Ssam ok = 1; 2052189251Ssam break; 2053189251Ssam } 2054189251Ssam 2055189251Ssam if (SSL_use_PrivateKey_file(conn->ssl, private_key, 2056189251Ssam SSL_FILETYPE_PEM) == 1) { 2057189251Ssam wpa_printf(MSG_DEBUG, "OpenSSL: " 2058189251Ssam "SSL_use_PrivateKey_File (PEM) --> OK"); 2059189251Ssam ok = 1; 2060189251Ssam break; 2061189251Ssam } 2062189251Ssam#else /* OPENSSL_NO_STDIO */ 2063189251Ssam wpa_printf(MSG_DEBUG, "OpenSSL: %s - OPENSSL_NO_STDIO", 2064189251Ssam __func__); 2065189251Ssam#endif /* OPENSSL_NO_STDIO */ 2066189251Ssam 2067189251Ssam if (tls_read_pkcs12(ssl_ctx, conn->ssl, private_key, passwd) 2068189251Ssam == 0) { 2069189251Ssam wpa_printf(MSG_DEBUG, "OpenSSL: Reading PKCS#12 file " 2070189251Ssam "--> OK"); 2071189251Ssam ok = 1; 2072189251Ssam break; 2073189251Ssam } 2074189251Ssam 2075189251Ssam if (tls_cryptoapi_cert(conn->ssl, private_key) == 0) { 2076189251Ssam wpa_printf(MSG_DEBUG, "OpenSSL: Using CryptoAPI to " 2077189251Ssam "access certificate store --> OK"); 2078189251Ssam ok = 1; 2079189251Ssam break; 2080189251Ssam } 2081189251Ssam 2082189251Ssam break; 2083189251Ssam } 2084189251Ssam 2085189251Ssam if (!ok) { 2086252726Srpaulo tls_show_errors(MSG_INFO, __func__, 2087252726Srpaulo "Failed to load private key"); 2088189251Ssam os_free(passwd); 2089189251Ssam return -1; 2090189251Ssam } 2091189251Ssam ERR_clear_error(); 2092189251Ssam SSL_CTX_set_default_passwd_cb(ssl_ctx, NULL); 2093189251Ssam os_free(passwd); 2094252726Srpaulo 2095189251Ssam if (!SSL_check_private_key(conn->ssl)) { 2096189251Ssam tls_show_errors(MSG_INFO, __func__, "Private key failed " 2097189251Ssam "verification"); 2098189251Ssam return -1; 2099189251Ssam } 2100189251Ssam 2101189251Ssam wpa_printf(MSG_DEBUG, "SSL: Private key loaded successfully"); 2102189251Ssam return 0; 2103189251Ssam} 2104189251Ssam 2105189251Ssam 2106189251Ssamstatic int tls_global_private_key(SSL_CTX *ssl_ctx, const char *private_key, 2107189251Ssam const char *private_key_passwd) 2108189251Ssam{ 2109189251Ssam char *passwd; 2110189251Ssam 2111189251Ssam if (private_key == NULL) 2112189251Ssam return 0; 2113189251Ssam 2114189251Ssam if (private_key_passwd) { 2115189251Ssam passwd = os_strdup(private_key_passwd); 2116189251Ssam if (passwd == NULL) 2117189251Ssam return -1; 2118189251Ssam } else 2119189251Ssam passwd = NULL; 2120189251Ssam 2121189251Ssam SSL_CTX_set_default_passwd_cb(ssl_ctx, tls_passwd_cb); 2122189251Ssam SSL_CTX_set_default_passwd_cb_userdata(ssl_ctx, passwd); 2123189251Ssam if ( 2124189251Ssam#ifndef OPENSSL_NO_STDIO 2125189251Ssam SSL_CTX_use_PrivateKey_file(ssl_ctx, private_key, 2126189251Ssam SSL_FILETYPE_ASN1) != 1 && 2127189251Ssam SSL_CTX_use_PrivateKey_file(ssl_ctx, private_key, 2128189251Ssam SSL_FILETYPE_PEM) != 1 && 2129189251Ssam#endif /* OPENSSL_NO_STDIO */ 2130189251Ssam tls_read_pkcs12(ssl_ctx, NULL, private_key, passwd)) { 2131189251Ssam tls_show_errors(MSG_INFO, __func__, 2132189251Ssam "Failed to load private key"); 2133189251Ssam os_free(passwd); 2134189251Ssam ERR_clear_error(); 2135189251Ssam return -1; 2136189251Ssam } 2137189251Ssam os_free(passwd); 2138189251Ssam ERR_clear_error(); 2139189251Ssam SSL_CTX_set_default_passwd_cb(ssl_ctx, NULL); 2140252726Srpaulo 2141189251Ssam if (!SSL_CTX_check_private_key(ssl_ctx)) { 2142189251Ssam tls_show_errors(MSG_INFO, __func__, 2143189251Ssam "Private key failed verification"); 2144189251Ssam return -1; 2145189251Ssam } 2146189251Ssam 2147189251Ssam return 0; 2148189251Ssam} 2149189251Ssam 2150189251Ssam 2151189251Ssamstatic int tls_connection_dh(struct tls_connection *conn, const char *dh_file) 2152189251Ssam{ 2153189251Ssam#ifdef OPENSSL_NO_DH 2154189251Ssam if (dh_file == NULL) 2155189251Ssam return 0; 2156189251Ssam wpa_printf(MSG_ERROR, "TLS: openssl does not include DH support, but " 2157189251Ssam "dh_file specified"); 2158189251Ssam return -1; 2159189251Ssam#else /* OPENSSL_NO_DH */ 2160189251Ssam DH *dh; 2161189251Ssam BIO *bio; 2162189251Ssam 2163189251Ssam /* TODO: add support for dh_blob */ 2164189251Ssam if (dh_file == NULL) 2165189251Ssam return 0; 2166189251Ssam if (conn == NULL) 2167189251Ssam return -1; 2168189251Ssam 2169189251Ssam bio = BIO_new_file(dh_file, "r"); 2170189251Ssam if (bio == NULL) { 2171189251Ssam wpa_printf(MSG_INFO, "TLS: Failed to open DH file '%s': %s", 2172189251Ssam dh_file, ERR_error_string(ERR_get_error(), NULL)); 2173189251Ssam return -1; 2174189251Ssam } 2175189251Ssam dh = PEM_read_bio_DHparams(bio, NULL, NULL, NULL); 2176189251Ssam BIO_free(bio); 2177189251Ssam#ifndef OPENSSL_NO_DSA 2178189251Ssam while (dh == NULL) { 2179189251Ssam DSA *dsa; 2180189251Ssam wpa_printf(MSG_DEBUG, "TLS: Failed to parse DH file '%s': %s -" 2181189251Ssam " trying to parse as DSA params", dh_file, 2182189251Ssam ERR_error_string(ERR_get_error(), NULL)); 2183189251Ssam bio = BIO_new_file(dh_file, "r"); 2184189251Ssam if (bio == NULL) 2185189251Ssam break; 2186189251Ssam dsa = PEM_read_bio_DSAparams(bio, NULL, NULL, NULL); 2187189251Ssam BIO_free(bio); 2188189251Ssam if (!dsa) { 2189189251Ssam wpa_printf(MSG_DEBUG, "TLS: Failed to parse DSA file " 2190189251Ssam "'%s': %s", dh_file, 2191189251Ssam ERR_error_string(ERR_get_error(), NULL)); 2192189251Ssam break; 2193189251Ssam } 2194189251Ssam 2195189251Ssam wpa_printf(MSG_DEBUG, "TLS: DH file in DSA param format"); 2196189251Ssam dh = DSA_dup_DH(dsa); 2197189251Ssam DSA_free(dsa); 2198189251Ssam if (dh == NULL) { 2199189251Ssam wpa_printf(MSG_INFO, "TLS: Failed to convert DSA " 2200189251Ssam "params into DH params"); 2201189251Ssam break; 2202189251Ssam } 2203189251Ssam break; 2204189251Ssam } 2205189251Ssam#endif /* !OPENSSL_NO_DSA */ 2206189251Ssam if (dh == NULL) { 2207189251Ssam wpa_printf(MSG_INFO, "TLS: Failed to read/parse DH/DSA file " 2208189251Ssam "'%s'", dh_file); 2209189251Ssam return -1; 2210189251Ssam } 2211189251Ssam 2212189251Ssam if (SSL_set_tmp_dh(conn->ssl, dh) != 1) { 2213189251Ssam wpa_printf(MSG_INFO, "TLS: Failed to set DH params from '%s': " 2214189251Ssam "%s", dh_file, 2215189251Ssam ERR_error_string(ERR_get_error(), NULL)); 2216189251Ssam DH_free(dh); 2217189251Ssam return -1; 2218189251Ssam } 2219189251Ssam DH_free(dh); 2220189251Ssam return 0; 2221189251Ssam#endif /* OPENSSL_NO_DH */ 2222189251Ssam} 2223189251Ssam 2224189251Ssam 2225189251Ssamstatic int tls_global_dh(SSL_CTX *ssl_ctx, const char *dh_file) 2226189251Ssam{ 2227189251Ssam#ifdef OPENSSL_NO_DH 2228189251Ssam if (dh_file == NULL) 2229189251Ssam return 0; 2230189251Ssam wpa_printf(MSG_ERROR, "TLS: openssl does not include DH support, but " 2231189251Ssam "dh_file specified"); 2232189251Ssam return -1; 2233189251Ssam#else /* OPENSSL_NO_DH */ 2234189251Ssam DH *dh; 2235189251Ssam BIO *bio; 2236189251Ssam 2237189251Ssam /* TODO: add support for dh_blob */ 2238189251Ssam if (dh_file == NULL) 2239189251Ssam return 0; 2240189251Ssam if (ssl_ctx == NULL) 2241189251Ssam return -1; 2242189251Ssam 2243189251Ssam bio = BIO_new_file(dh_file, "r"); 2244189251Ssam if (bio == NULL) { 2245189251Ssam wpa_printf(MSG_INFO, "TLS: Failed to open DH file '%s': %s", 2246189251Ssam dh_file, ERR_error_string(ERR_get_error(), NULL)); 2247189251Ssam return -1; 2248189251Ssam } 2249189251Ssam dh = PEM_read_bio_DHparams(bio, NULL, NULL, NULL); 2250189251Ssam BIO_free(bio); 2251189251Ssam#ifndef OPENSSL_NO_DSA 2252189251Ssam while (dh == NULL) { 2253189251Ssam DSA *dsa; 2254189251Ssam wpa_printf(MSG_DEBUG, "TLS: Failed to parse DH file '%s': %s -" 2255189251Ssam " trying to parse as DSA params", dh_file, 2256189251Ssam ERR_error_string(ERR_get_error(), NULL)); 2257189251Ssam bio = BIO_new_file(dh_file, "r"); 2258189251Ssam if (bio == NULL) 2259189251Ssam break; 2260189251Ssam dsa = PEM_read_bio_DSAparams(bio, NULL, NULL, NULL); 2261189251Ssam BIO_free(bio); 2262189251Ssam if (!dsa) { 2263189251Ssam wpa_printf(MSG_DEBUG, "TLS: Failed to parse DSA file " 2264189251Ssam "'%s': %s", dh_file, 2265189251Ssam ERR_error_string(ERR_get_error(), NULL)); 2266189251Ssam break; 2267189251Ssam } 2268189251Ssam 2269189251Ssam wpa_printf(MSG_DEBUG, "TLS: DH file in DSA param format"); 2270189251Ssam dh = DSA_dup_DH(dsa); 2271189251Ssam DSA_free(dsa); 2272189251Ssam if (dh == NULL) { 2273189251Ssam wpa_printf(MSG_INFO, "TLS: Failed to convert DSA " 2274189251Ssam "params into DH params"); 2275189251Ssam break; 2276189251Ssam } 2277189251Ssam break; 2278189251Ssam } 2279189251Ssam#endif /* !OPENSSL_NO_DSA */ 2280189251Ssam if (dh == NULL) { 2281189251Ssam wpa_printf(MSG_INFO, "TLS: Failed to read/parse DH/DSA file " 2282189251Ssam "'%s'", dh_file); 2283189251Ssam return -1; 2284189251Ssam } 2285189251Ssam 2286189251Ssam if (SSL_CTX_set_tmp_dh(ssl_ctx, dh) != 1) { 2287189251Ssam wpa_printf(MSG_INFO, "TLS: Failed to set DH params from '%s': " 2288189251Ssam "%s", dh_file, 2289189251Ssam ERR_error_string(ERR_get_error(), NULL)); 2290189251Ssam DH_free(dh); 2291189251Ssam return -1; 2292189251Ssam } 2293189251Ssam DH_free(dh); 2294189251Ssam return 0; 2295189251Ssam#endif /* OPENSSL_NO_DH */ 2296189251Ssam} 2297189251Ssam 2298189251Ssam 2299189251Ssamint tls_connection_get_keys(void *ssl_ctx, struct tls_connection *conn, 2300189251Ssam struct tls_keys *keys) 2301189251Ssam{ 2302252726Srpaulo#ifdef CONFIG_FIPS 2303252726Srpaulo wpa_printf(MSG_ERROR, "OpenSSL: TLS keys cannot be exported in FIPS " 2304252726Srpaulo "mode"); 2305252726Srpaulo return -1; 2306252726Srpaulo#else /* CONFIG_FIPS */ 2307189251Ssam SSL *ssl; 2308189251Ssam 2309189251Ssam if (conn == NULL || keys == NULL) 2310189251Ssam return -1; 2311189251Ssam ssl = conn->ssl; 2312189251Ssam if (ssl == NULL || ssl->s3 == NULL || ssl->session == NULL) 2313189251Ssam return -1; 2314189251Ssam 2315189251Ssam os_memset(keys, 0, sizeof(*keys)); 2316189251Ssam keys->master_key = ssl->session->master_key; 2317189251Ssam keys->master_key_len = ssl->session->master_key_length; 2318189251Ssam keys->client_random = ssl->s3->client_random; 2319189251Ssam keys->client_random_len = SSL3_RANDOM_SIZE; 2320189251Ssam keys->server_random = ssl->s3->server_random; 2321189251Ssam keys->server_random_len = SSL3_RANDOM_SIZE; 2322189251Ssam 2323189251Ssam return 0; 2324252726Srpaulo#endif /* CONFIG_FIPS */ 2325189251Ssam} 2326189251Ssam 2327189251Ssam 2328189251Ssamint tls_connection_prf(void *tls_ctx, struct tls_connection *conn, 2329189251Ssam const char *label, int server_random_first, 2330189251Ssam u8 *out, size_t out_len) 2331189251Ssam{ 2332252726Srpaulo#if OPENSSL_VERSION_NUMBER >= 0x10001000L 2333252726Srpaulo SSL *ssl; 2334252726Srpaulo if (conn == NULL) 2335252726Srpaulo return -1; 2336252726Srpaulo if (server_random_first) 2337252726Srpaulo return -1; 2338252726Srpaulo ssl = conn->ssl; 2339252726Srpaulo if (SSL_export_keying_material(ssl, out, out_len, label, 2340252726Srpaulo os_strlen(label), NULL, 0, 0) == 1) { 2341252726Srpaulo wpa_printf(MSG_DEBUG, "OpenSSL: Using internal PRF"); 2342252726Srpaulo return 0; 2343252726Srpaulo } 2344252726Srpaulo#endif 2345189251Ssam return -1; 2346189251Ssam} 2347189251Ssam 2348189251Ssam 2349214734Srpaulostatic struct wpabuf * 2350214734Srpauloopenssl_handshake(struct tls_connection *conn, const struct wpabuf *in_data, 2351214734Srpaulo int server) 2352189251Ssam{ 2353189251Ssam int res; 2354214734Srpaulo struct wpabuf *out_data; 2355189251Ssam 2356189251Ssam /* 2357189251Ssam * Give TLS handshake data from the server (if available) to OpenSSL 2358189251Ssam * for processing. 2359189251Ssam */ 2360189251Ssam if (in_data && 2361214734Srpaulo BIO_write(conn->ssl_in, wpabuf_head(in_data), wpabuf_len(in_data)) 2362214734Srpaulo < 0) { 2363189251Ssam tls_show_errors(MSG_INFO, __func__, 2364189251Ssam "Handshake failed - BIO_write"); 2365189251Ssam return NULL; 2366189251Ssam } 2367189251Ssam 2368189251Ssam /* Initiate TLS handshake or continue the existing handshake */ 2369214734Srpaulo if (server) 2370214734Srpaulo res = SSL_accept(conn->ssl); 2371214734Srpaulo else 2372214734Srpaulo res = SSL_connect(conn->ssl); 2373189251Ssam if (res != 1) { 2374189251Ssam int err = SSL_get_error(conn->ssl, res); 2375189251Ssam if (err == SSL_ERROR_WANT_READ) 2376189251Ssam wpa_printf(MSG_DEBUG, "SSL: SSL_connect - want " 2377189251Ssam "more data"); 2378189251Ssam else if (err == SSL_ERROR_WANT_WRITE) 2379189251Ssam wpa_printf(MSG_DEBUG, "SSL: SSL_connect - want to " 2380189251Ssam "write"); 2381189251Ssam else { 2382189251Ssam tls_show_errors(MSG_INFO, __func__, "SSL_connect"); 2383189251Ssam conn->failed++; 2384189251Ssam } 2385189251Ssam } 2386189251Ssam 2387189251Ssam /* Get the TLS handshake data to be sent to the server */ 2388189251Ssam res = BIO_ctrl_pending(conn->ssl_out); 2389189251Ssam wpa_printf(MSG_DEBUG, "SSL: %d bytes pending from ssl_out", res); 2390214734Srpaulo out_data = wpabuf_alloc(res); 2391189251Ssam if (out_data == NULL) { 2392189251Ssam wpa_printf(MSG_DEBUG, "SSL: Failed to allocate memory for " 2393189251Ssam "handshake output (%d bytes)", res); 2394189251Ssam if (BIO_reset(conn->ssl_out) < 0) { 2395189251Ssam tls_show_errors(MSG_INFO, __func__, 2396189251Ssam "BIO_reset failed"); 2397189251Ssam } 2398189251Ssam return NULL; 2399189251Ssam } 2400214734Srpaulo res = res == 0 ? 0 : BIO_read(conn->ssl_out, wpabuf_mhead(out_data), 2401214734Srpaulo res); 2402189251Ssam if (res < 0) { 2403189251Ssam tls_show_errors(MSG_INFO, __func__, 2404189251Ssam "Handshake failed - BIO_read"); 2405189251Ssam if (BIO_reset(conn->ssl_out) < 0) { 2406189251Ssam tls_show_errors(MSG_INFO, __func__, 2407189251Ssam "BIO_reset failed"); 2408189251Ssam } 2409214734Srpaulo wpabuf_free(out_data); 2410189251Ssam return NULL; 2411189251Ssam } 2412214734Srpaulo wpabuf_put(out_data, res); 2413189251Ssam 2414189251Ssam return out_data; 2415189251Ssam} 2416189251Ssam 2417189251Ssam 2418214734Srpaulostatic struct wpabuf * 2419214734Srpauloopenssl_get_appl_data(struct tls_connection *conn, size_t max_len) 2420189251Ssam{ 2421214734Srpaulo struct wpabuf *appl_data; 2422189251Ssam int res; 2423189251Ssam 2424214734Srpaulo appl_data = wpabuf_alloc(max_len + 100); 2425214734Srpaulo if (appl_data == NULL) 2426189251Ssam return NULL; 2427189251Ssam 2428214734Srpaulo res = SSL_read(conn->ssl, wpabuf_mhead(appl_data), 2429214734Srpaulo wpabuf_size(appl_data)); 2430214734Srpaulo if (res < 0) { 2431189251Ssam int err = SSL_get_error(conn->ssl, res); 2432214734Srpaulo if (err == SSL_ERROR_WANT_READ || 2433214734Srpaulo err == SSL_ERROR_WANT_WRITE) { 2434214734Srpaulo wpa_printf(MSG_DEBUG, "SSL: No Application Data " 2435214734Srpaulo "included"); 2436214734Srpaulo } else { 2437189251Ssam tls_show_errors(MSG_INFO, __func__, 2438214734Srpaulo "Failed to read possible " 2439214734Srpaulo "Application Data"); 2440189251Ssam } 2441214734Srpaulo wpabuf_free(appl_data); 2442189251Ssam return NULL; 2443189251Ssam } 2444214734Srpaulo 2445214734Srpaulo wpabuf_put(appl_data, res); 2446214734Srpaulo wpa_hexdump_buf_key(MSG_MSGDUMP, "SSL: Application Data in Finished " 2447214734Srpaulo "message", appl_data); 2448214734Srpaulo 2449214734Srpaulo return appl_data; 2450214734Srpaulo} 2451214734Srpaulo 2452214734Srpaulo 2453214734Srpaulostatic struct wpabuf * 2454214734Srpauloopenssl_connection_handshake(struct tls_connection *conn, 2455214734Srpaulo const struct wpabuf *in_data, 2456214734Srpaulo struct wpabuf **appl_data, int server) 2457214734Srpaulo{ 2458214734Srpaulo struct wpabuf *out_data; 2459214734Srpaulo 2460214734Srpaulo if (appl_data) 2461214734Srpaulo *appl_data = NULL; 2462214734Srpaulo 2463214734Srpaulo out_data = openssl_handshake(conn, in_data, server); 2464214734Srpaulo if (out_data == NULL) 2465189251Ssam return NULL; 2466214734Srpaulo 2467214734Srpaulo if (SSL_is_init_finished(conn->ssl) && appl_data && in_data) 2468214734Srpaulo *appl_data = openssl_get_appl_data(conn, wpabuf_len(in_data)); 2469214734Srpaulo 2470189251Ssam return out_data; 2471189251Ssam} 2472189251Ssam 2473189251Ssam 2474214734Srpaulostruct wpabuf * 2475214734Srpaulotls_connection_handshake(void *ssl_ctx, struct tls_connection *conn, 2476214734Srpaulo const struct wpabuf *in_data, 2477214734Srpaulo struct wpabuf **appl_data) 2478189251Ssam{ 2479214734Srpaulo return openssl_connection_handshake(conn, in_data, appl_data, 0); 2480214734Srpaulo} 2481214734Srpaulo 2482214734Srpaulo 2483214734Srpaulostruct wpabuf * tls_connection_server_handshake(void *tls_ctx, 2484214734Srpaulo struct tls_connection *conn, 2485214734Srpaulo const struct wpabuf *in_data, 2486214734Srpaulo struct wpabuf **appl_data) 2487214734Srpaulo{ 2488214734Srpaulo return openssl_connection_handshake(conn, in_data, appl_data, 1); 2489214734Srpaulo} 2490214734Srpaulo 2491214734Srpaulo 2492214734Srpaulostruct wpabuf * tls_connection_encrypt(void *tls_ctx, 2493214734Srpaulo struct tls_connection *conn, 2494214734Srpaulo const struct wpabuf *in_data) 2495214734Srpaulo{ 2496189251Ssam int res; 2497214734Srpaulo struct wpabuf *buf; 2498189251Ssam 2499189251Ssam if (conn == NULL) 2500214734Srpaulo return NULL; 2501189251Ssam 2502189251Ssam /* Give plaintext data for OpenSSL to encrypt into the TLS tunnel. */ 2503189251Ssam if ((res = BIO_reset(conn->ssl_in)) < 0 || 2504189251Ssam (res = BIO_reset(conn->ssl_out)) < 0) { 2505189251Ssam tls_show_errors(MSG_INFO, __func__, "BIO_reset failed"); 2506214734Srpaulo return NULL; 2507189251Ssam } 2508214734Srpaulo res = SSL_write(conn->ssl, wpabuf_head(in_data), wpabuf_len(in_data)); 2509189251Ssam if (res < 0) { 2510189251Ssam tls_show_errors(MSG_INFO, __func__, 2511189251Ssam "Encryption failed - SSL_write"); 2512214734Srpaulo return NULL; 2513189251Ssam } 2514189251Ssam 2515189251Ssam /* Read encrypted data to be sent to the server */ 2516214734Srpaulo buf = wpabuf_alloc(wpabuf_len(in_data) + 300); 2517214734Srpaulo if (buf == NULL) 2518214734Srpaulo return NULL; 2519214734Srpaulo res = BIO_read(conn->ssl_out, wpabuf_mhead(buf), wpabuf_size(buf)); 2520189251Ssam if (res < 0) { 2521189251Ssam tls_show_errors(MSG_INFO, __func__, 2522189251Ssam "Encryption failed - BIO_read"); 2523214734Srpaulo wpabuf_free(buf); 2524214734Srpaulo return NULL; 2525189251Ssam } 2526214734Srpaulo wpabuf_put(buf, res); 2527189251Ssam 2528214734Srpaulo return buf; 2529189251Ssam} 2530189251Ssam 2531189251Ssam 2532214734Srpaulostruct wpabuf * tls_connection_decrypt(void *tls_ctx, 2533214734Srpaulo struct tls_connection *conn, 2534214734Srpaulo const struct wpabuf *in_data) 2535189251Ssam{ 2536189251Ssam int res; 2537214734Srpaulo struct wpabuf *buf; 2538189251Ssam 2539189251Ssam /* Give encrypted data from TLS tunnel for OpenSSL to decrypt. */ 2540214734Srpaulo res = BIO_write(conn->ssl_in, wpabuf_head(in_data), 2541214734Srpaulo wpabuf_len(in_data)); 2542189251Ssam if (res < 0) { 2543189251Ssam tls_show_errors(MSG_INFO, __func__, 2544189251Ssam "Decryption failed - BIO_write"); 2545214734Srpaulo return NULL; 2546189251Ssam } 2547189251Ssam if (BIO_reset(conn->ssl_out) < 0) { 2548189251Ssam tls_show_errors(MSG_INFO, __func__, "BIO_reset failed"); 2549214734Srpaulo return NULL; 2550189251Ssam } 2551189251Ssam 2552189251Ssam /* Read decrypted data for further processing */ 2553214734Srpaulo /* 2554214734Srpaulo * Even though we try to disable TLS compression, it is possible that 2555214734Srpaulo * this cannot be done with all TLS libraries. Add extra buffer space 2556214734Srpaulo * to handle the possibility of the decrypted data being longer than 2557214734Srpaulo * input data. 2558214734Srpaulo */ 2559214734Srpaulo buf = wpabuf_alloc((wpabuf_len(in_data) + 500) * 3); 2560214734Srpaulo if (buf == NULL) 2561214734Srpaulo return NULL; 2562214734Srpaulo res = SSL_read(conn->ssl, wpabuf_mhead(buf), wpabuf_size(buf)); 2563189251Ssam if (res < 0) { 2564189251Ssam tls_show_errors(MSG_INFO, __func__, 2565189251Ssam "Decryption failed - SSL_read"); 2566214734Srpaulo wpabuf_free(buf); 2567214734Srpaulo return NULL; 2568189251Ssam } 2569214734Srpaulo wpabuf_put(buf, res); 2570189251Ssam 2571214734Srpaulo return buf; 2572189251Ssam} 2573189251Ssam 2574189251Ssam 2575189251Ssamint tls_connection_resumed(void *ssl_ctx, struct tls_connection *conn) 2576189251Ssam{ 2577189251Ssam return conn ? conn->ssl->hit : 0; 2578189251Ssam} 2579189251Ssam 2580189251Ssam 2581189251Ssamint tls_connection_set_cipher_list(void *tls_ctx, struct tls_connection *conn, 2582189251Ssam u8 *ciphers) 2583189251Ssam{ 2584189251Ssam char buf[100], *pos, *end; 2585189251Ssam u8 *c; 2586189251Ssam int ret; 2587189251Ssam 2588189251Ssam if (conn == NULL || conn->ssl == NULL || ciphers == NULL) 2589189251Ssam return -1; 2590189251Ssam 2591189251Ssam buf[0] = '\0'; 2592189251Ssam pos = buf; 2593189251Ssam end = pos + sizeof(buf); 2594189251Ssam 2595189251Ssam c = ciphers; 2596189251Ssam while (*c != TLS_CIPHER_NONE) { 2597189251Ssam const char *suite; 2598189251Ssam 2599189251Ssam switch (*c) { 2600189251Ssam case TLS_CIPHER_RC4_SHA: 2601189251Ssam suite = "RC4-SHA"; 2602189251Ssam break; 2603189251Ssam case TLS_CIPHER_AES128_SHA: 2604189251Ssam suite = "AES128-SHA"; 2605189251Ssam break; 2606189251Ssam case TLS_CIPHER_RSA_DHE_AES128_SHA: 2607189251Ssam suite = "DHE-RSA-AES128-SHA"; 2608189251Ssam break; 2609189251Ssam case TLS_CIPHER_ANON_DH_AES128_SHA: 2610189251Ssam suite = "ADH-AES128-SHA"; 2611189251Ssam break; 2612189251Ssam default: 2613189251Ssam wpa_printf(MSG_DEBUG, "TLS: Unsupported " 2614189251Ssam "cipher selection: %d", *c); 2615189251Ssam return -1; 2616189251Ssam } 2617189251Ssam ret = os_snprintf(pos, end - pos, ":%s", suite); 2618189251Ssam if (ret < 0 || ret >= end - pos) 2619189251Ssam break; 2620189251Ssam pos += ret; 2621189251Ssam 2622189251Ssam c++; 2623189251Ssam } 2624189251Ssam 2625189251Ssam wpa_printf(MSG_DEBUG, "OpenSSL: cipher suites: %s", buf + 1); 2626189251Ssam 2627189251Ssam if (SSL_set_cipher_list(conn->ssl, buf + 1) != 1) { 2628189251Ssam tls_show_errors(MSG_INFO, __func__, 2629189251Ssam "Cipher suite configuration failed"); 2630189251Ssam return -1; 2631189251Ssam } 2632189251Ssam 2633189251Ssam return 0; 2634189251Ssam} 2635189251Ssam 2636189251Ssam 2637189251Ssamint tls_get_cipher(void *ssl_ctx, struct tls_connection *conn, 2638189251Ssam char *buf, size_t buflen) 2639189251Ssam{ 2640189251Ssam const char *name; 2641189251Ssam if (conn == NULL || conn->ssl == NULL) 2642189251Ssam return -1; 2643189251Ssam 2644189251Ssam name = SSL_get_cipher(conn->ssl); 2645189251Ssam if (name == NULL) 2646189251Ssam return -1; 2647189251Ssam 2648189251Ssam os_strlcpy(buf, name, buflen); 2649189251Ssam return 0; 2650189251Ssam} 2651189251Ssam 2652189251Ssam 2653189251Ssamint tls_connection_enable_workaround(void *ssl_ctx, 2654189251Ssam struct tls_connection *conn) 2655189251Ssam{ 2656189251Ssam SSL_set_options(conn->ssl, SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS); 2657189251Ssam 2658189251Ssam return 0; 2659189251Ssam} 2660189251Ssam 2661189251Ssam 2662214734Srpaulo#if defined(EAP_FAST) || defined(EAP_FAST_DYNAMIC) || defined(EAP_SERVER_FAST) 2663189251Ssam/* ClientHello TLS extensions require a patch to openssl, so this function is 2664189251Ssam * commented out unless explicitly needed for EAP-FAST in order to be able to 2665189251Ssam * build this file with unmodified openssl. */ 2666189251Ssamint tls_connection_client_hello_ext(void *ssl_ctx, struct tls_connection *conn, 2667189251Ssam int ext_type, const u8 *data, 2668189251Ssam size_t data_len) 2669189251Ssam{ 2670189251Ssam if (conn == NULL || conn->ssl == NULL || ext_type != 35) 2671189251Ssam return -1; 2672189251Ssam 2673189251Ssam#ifdef CONFIG_OPENSSL_TICKET_OVERRIDE 2674189251Ssam if (SSL_set_session_ticket_ext(conn->ssl, (void *) data, 2675189251Ssam data_len) != 1) 2676189251Ssam return -1; 2677189251Ssam#else /* CONFIG_OPENSSL_TICKET_OVERRIDE */ 2678189251Ssam if (SSL_set_hello_extension(conn->ssl, ext_type, (void *) data, 2679189251Ssam data_len) != 1) 2680189251Ssam return -1; 2681189251Ssam#endif /* CONFIG_OPENSSL_TICKET_OVERRIDE */ 2682189251Ssam 2683189251Ssam return 0; 2684189251Ssam} 2685214734Srpaulo#endif /* EAP_FAST || EAP_FAST_DYNAMIC || EAP_SERVER_FAST */ 2686189251Ssam 2687189251Ssam 2688189251Ssamint tls_connection_get_failed(void *ssl_ctx, struct tls_connection *conn) 2689189251Ssam{ 2690189251Ssam if (conn == NULL) 2691189251Ssam return -1; 2692189251Ssam return conn->failed; 2693189251Ssam} 2694189251Ssam 2695189251Ssam 2696189251Ssamint tls_connection_get_read_alerts(void *ssl_ctx, struct tls_connection *conn) 2697189251Ssam{ 2698189251Ssam if (conn == NULL) 2699189251Ssam return -1; 2700189251Ssam return conn->read_alerts; 2701189251Ssam} 2702189251Ssam 2703189251Ssam 2704189251Ssamint tls_connection_get_write_alerts(void *ssl_ctx, struct tls_connection *conn) 2705189251Ssam{ 2706189251Ssam if (conn == NULL) 2707189251Ssam return -1; 2708189251Ssam return conn->write_alerts; 2709189251Ssam} 2710189251Ssam 2711189251Ssam 2712189251Ssamint tls_connection_set_params(void *tls_ctx, struct tls_connection *conn, 2713189251Ssam const struct tls_connection_params *params) 2714189251Ssam{ 2715189251Ssam int ret; 2716189251Ssam unsigned long err; 2717189251Ssam 2718189251Ssam if (conn == NULL) 2719189251Ssam return -1; 2720189251Ssam 2721189251Ssam while ((err = ERR_get_error())) { 2722189251Ssam wpa_printf(MSG_INFO, "%s: Clearing pending SSL error: %s", 2723189251Ssam __func__, ERR_error_string(err, NULL)); 2724189251Ssam } 2725189251Ssam 2726189251Ssam if (params->engine) { 2727189251Ssam wpa_printf(MSG_DEBUG, "SSL: Initializing TLS engine"); 2728189251Ssam ret = tls_engine_init(conn, params->engine_id, params->pin, 2729189251Ssam params->key_id, params->cert_id, 2730189251Ssam params->ca_cert_id); 2731189251Ssam if (ret) 2732189251Ssam return ret; 2733189251Ssam } 2734189251Ssam if (tls_connection_set_subject_match(conn, 2735189251Ssam params->subject_match, 2736189251Ssam params->altsubject_match)) 2737189251Ssam return -1; 2738189251Ssam 2739189251Ssam if (params->engine && params->ca_cert_id) { 2740189251Ssam if (tls_connection_engine_ca_cert(tls_ctx, conn, 2741189251Ssam params->ca_cert_id)) 2742189251Ssam return TLS_SET_PARAMS_ENGINE_PRV_VERIFY_FAILED; 2743189251Ssam } else if (tls_connection_ca_cert(tls_ctx, conn, params->ca_cert, 2744189251Ssam params->ca_cert_blob, 2745189251Ssam params->ca_cert_blob_len, 2746189251Ssam params->ca_path)) 2747189251Ssam return -1; 2748189251Ssam 2749189251Ssam if (params->engine && params->cert_id) { 2750189251Ssam if (tls_connection_engine_client_cert(conn, params->cert_id)) 2751189251Ssam return TLS_SET_PARAMS_ENGINE_PRV_VERIFY_FAILED; 2752189251Ssam } else if (tls_connection_client_cert(conn, params->client_cert, 2753189251Ssam params->client_cert_blob, 2754189251Ssam params->client_cert_blob_len)) 2755189251Ssam return -1; 2756189251Ssam 2757189251Ssam if (params->engine && params->key_id) { 2758189251Ssam wpa_printf(MSG_DEBUG, "TLS: Using private key from engine"); 2759189251Ssam if (tls_connection_engine_private_key(conn)) 2760189251Ssam return TLS_SET_PARAMS_ENGINE_PRV_VERIFY_FAILED; 2761189251Ssam } else if (tls_connection_private_key(tls_ctx, conn, 2762189251Ssam params->private_key, 2763189251Ssam params->private_key_passwd, 2764189251Ssam params->private_key_blob, 2765189251Ssam params->private_key_blob_len)) { 2766189251Ssam wpa_printf(MSG_INFO, "TLS: Failed to load private key '%s'", 2767189251Ssam params->private_key); 2768189251Ssam return -1; 2769189251Ssam } 2770189251Ssam 2771189251Ssam if (tls_connection_dh(conn, params->dh_file)) { 2772189251Ssam wpa_printf(MSG_INFO, "TLS: Failed to load DH file '%s'", 2773189251Ssam params->dh_file); 2774189251Ssam return -1; 2775189251Ssam } 2776189251Ssam 2777252726Srpaulo#ifdef SSL_OP_NO_TICKET 2778252726Srpaulo if (params->flags & TLS_CONN_DISABLE_SESSION_TICKET) 2779252726Srpaulo SSL_set_options(conn->ssl, SSL_OP_NO_TICKET); 2780252726Srpaulo else 2781252726Srpaulo SSL_clear_options(conn->ssl, SSL_OP_NO_TICKET); 2782252726Srpaulo#endif /* SSL_OP_NO_TICKET */ 2783252726Srpaulo 2784252726Srpaulo conn->flags = params->flags; 2785252726Srpaulo 2786189251Ssam tls_get_errors(tls_ctx); 2787189251Ssam 2788189251Ssam return 0; 2789189251Ssam} 2790189251Ssam 2791189251Ssam 2792189251Ssamint tls_global_set_params(void *tls_ctx, 2793189251Ssam const struct tls_connection_params *params) 2794189251Ssam{ 2795189251Ssam SSL_CTX *ssl_ctx = tls_ctx; 2796189251Ssam unsigned long err; 2797189251Ssam 2798189251Ssam while ((err = ERR_get_error())) { 2799189251Ssam wpa_printf(MSG_INFO, "%s: Clearing pending SSL error: %s", 2800189251Ssam __func__, ERR_error_string(err, NULL)); 2801189251Ssam } 2802189251Ssam 2803189251Ssam if (tls_global_ca_cert(ssl_ctx, params->ca_cert)) 2804189251Ssam return -1; 2805189251Ssam 2806189251Ssam if (tls_global_client_cert(ssl_ctx, params->client_cert)) 2807189251Ssam return -1; 2808189251Ssam 2809189251Ssam if (tls_global_private_key(ssl_ctx, params->private_key, 2810189251Ssam params->private_key_passwd)) 2811189251Ssam return -1; 2812189251Ssam 2813189251Ssam if (tls_global_dh(ssl_ctx, params->dh_file)) { 2814189251Ssam wpa_printf(MSG_INFO, "TLS: Failed to load DH file '%s'", 2815189251Ssam params->dh_file); 2816189251Ssam return -1; 2817189251Ssam } 2818189251Ssam 2819252726Srpaulo#ifdef SSL_OP_NO_TICKET 2820252726Srpaulo if (params->flags & TLS_CONN_DISABLE_SESSION_TICKET) 2821252726Srpaulo SSL_CTX_set_options(ssl_ctx, SSL_OP_NO_TICKET); 2822252726Srpaulo else 2823252726Srpaulo SSL_CTX_clear_options(ssl_ctx, SSL_OP_NO_TICKET); 2824252726Srpaulo#endif /* SSL_OP_NO_TICKET */ 2825252726Srpaulo 2826189251Ssam return 0; 2827189251Ssam} 2828189251Ssam 2829189251Ssam 2830189251Ssamint tls_connection_get_keyblock_size(void *tls_ctx, 2831189251Ssam struct tls_connection *conn) 2832189251Ssam{ 2833189251Ssam const EVP_CIPHER *c; 2834189251Ssam const EVP_MD *h; 2835252726Srpaulo int md_size; 2836189251Ssam 2837189251Ssam if (conn == NULL || conn->ssl == NULL || 2838189251Ssam conn->ssl->enc_read_ctx == NULL || 2839189251Ssam conn->ssl->enc_read_ctx->cipher == NULL || 2840189251Ssam conn->ssl->read_hash == NULL) 2841189251Ssam return -1; 2842189251Ssam 2843189251Ssam c = conn->ssl->enc_read_ctx->cipher; 2844189251Ssam#if OPENSSL_VERSION_NUMBER >= 0x00909000L 2845189251Ssam h = EVP_MD_CTX_md(conn->ssl->read_hash); 2846189251Ssam#else 2847189251Ssam h = conn->ssl->read_hash; 2848189251Ssam#endif 2849252726Srpaulo if (h) 2850252726Srpaulo md_size = EVP_MD_size(h); 2851252726Srpaulo#if OPENSSL_VERSION_NUMBER >= 0x10000000L 2852252726Srpaulo else if (conn->ssl->s3) 2853252726Srpaulo md_size = conn->ssl->s3->tmp.new_mac_secret_size; 2854252726Srpaulo#endif 2855252726Srpaulo else 2856252726Srpaulo return -1; 2857189251Ssam 2858252726Srpaulo wpa_printf(MSG_DEBUG, "OpenSSL: keyblock size: key_len=%d MD_size=%d " 2859252726Srpaulo "IV_len=%d", EVP_CIPHER_key_length(c), md_size, 2860252726Srpaulo EVP_CIPHER_iv_length(c)); 2861189251Ssam return 2 * (EVP_CIPHER_key_length(c) + 2862252726Srpaulo md_size + 2863189251Ssam EVP_CIPHER_iv_length(c)); 2864189251Ssam} 2865189251Ssam 2866189251Ssam 2867189251Ssamunsigned int tls_capabilities(void *tls_ctx) 2868189251Ssam{ 2869189251Ssam return 0; 2870189251Ssam} 2871189251Ssam 2872189251Ssam 2873214734Srpaulo#if defined(EAP_FAST) || defined(EAP_FAST_DYNAMIC) || defined(EAP_SERVER_FAST) 2874189251Ssam/* Pre-shared secred requires a patch to openssl, so this function is 2875189251Ssam * commented out unless explicitly needed for EAP-FAST in order to be able to 2876189251Ssam * build this file with unmodified openssl. */ 2877189251Ssam 2878189251Ssamstatic int tls_sess_sec_cb(SSL *s, void *secret, int *secret_len, 2879189251Ssam STACK_OF(SSL_CIPHER) *peer_ciphers, 2880189251Ssam SSL_CIPHER **cipher, void *arg) 2881189251Ssam{ 2882189251Ssam struct tls_connection *conn = arg; 2883189251Ssam int ret; 2884189251Ssam 2885189251Ssam if (conn == NULL || conn->session_ticket_cb == NULL) 2886189251Ssam return 0; 2887189251Ssam 2888189251Ssam ret = conn->session_ticket_cb(conn->session_ticket_cb_ctx, 2889189251Ssam conn->session_ticket, 2890189251Ssam conn->session_ticket_len, 2891189251Ssam s->s3->client_random, 2892189251Ssam s->s3->server_random, secret); 2893189251Ssam os_free(conn->session_ticket); 2894189251Ssam conn->session_ticket = NULL; 2895189251Ssam 2896189251Ssam if (ret <= 0) 2897189251Ssam return 0; 2898189251Ssam 2899189251Ssam *secret_len = SSL_MAX_MASTER_KEY_LENGTH; 2900189251Ssam return 1; 2901189251Ssam} 2902189251Ssam 2903189251Ssam 2904189251Ssam#ifdef CONFIG_OPENSSL_TICKET_OVERRIDE 2905189251Ssamstatic int tls_session_ticket_ext_cb(SSL *s, const unsigned char *data, 2906189251Ssam int len, void *arg) 2907189251Ssam{ 2908189251Ssam struct tls_connection *conn = arg; 2909189251Ssam 2910189251Ssam if (conn == NULL || conn->session_ticket_cb == NULL) 2911189251Ssam return 0; 2912189251Ssam 2913189251Ssam wpa_printf(MSG_DEBUG, "OpenSSL: %s: length=%d", __func__, len); 2914189251Ssam 2915189251Ssam os_free(conn->session_ticket); 2916189251Ssam conn->session_ticket = NULL; 2917189251Ssam 2918189251Ssam wpa_hexdump(MSG_DEBUG, "OpenSSL: ClientHello SessionTicket " 2919189251Ssam "extension", data, len); 2920189251Ssam 2921189251Ssam conn->session_ticket = os_malloc(len); 2922189251Ssam if (conn->session_ticket == NULL) 2923189251Ssam return 0; 2924189251Ssam 2925189251Ssam os_memcpy(conn->session_ticket, data, len); 2926189251Ssam conn->session_ticket_len = len; 2927189251Ssam 2928189251Ssam return 1; 2929189251Ssam} 2930189251Ssam#else /* CONFIG_OPENSSL_TICKET_OVERRIDE */ 2931189251Ssam#ifdef SSL_OP_NO_TICKET 2932189251Ssamstatic void tls_hello_ext_cb(SSL *s, int client_server, int type, 2933189251Ssam unsigned char *data, int len, void *arg) 2934189251Ssam{ 2935189251Ssam struct tls_connection *conn = arg; 2936189251Ssam 2937189251Ssam if (conn == NULL || conn->session_ticket_cb == NULL) 2938189251Ssam return; 2939189251Ssam 2940189251Ssam wpa_printf(MSG_DEBUG, "OpenSSL: %s: type=%d length=%d", __func__, 2941189251Ssam type, len); 2942189251Ssam 2943189251Ssam if (type == TLSEXT_TYPE_session_ticket && !client_server) { 2944189251Ssam os_free(conn->session_ticket); 2945189251Ssam conn->session_ticket = NULL; 2946189251Ssam 2947189251Ssam wpa_hexdump(MSG_DEBUG, "OpenSSL: ClientHello SessionTicket " 2948189251Ssam "extension", data, len); 2949189251Ssam conn->session_ticket = os_malloc(len); 2950189251Ssam if (conn->session_ticket == NULL) 2951189251Ssam return; 2952189251Ssam 2953189251Ssam os_memcpy(conn->session_ticket, data, len); 2954189251Ssam conn->session_ticket_len = len; 2955189251Ssam } 2956189251Ssam} 2957189251Ssam#else /* SSL_OP_NO_TICKET */ 2958189251Ssamstatic int tls_hello_ext_cb(SSL *s, TLS_EXTENSION *ext, void *arg) 2959189251Ssam{ 2960189251Ssam struct tls_connection *conn = arg; 2961189251Ssam 2962189251Ssam if (conn == NULL || conn->session_ticket_cb == NULL) 2963189251Ssam return 0; 2964189251Ssam 2965189251Ssam wpa_printf(MSG_DEBUG, "OpenSSL: %s: type=%d length=%d", __func__, 2966189251Ssam ext->type, ext->length); 2967189251Ssam 2968189251Ssam os_free(conn->session_ticket); 2969189251Ssam conn->session_ticket = NULL; 2970189251Ssam 2971189251Ssam if (ext->type == 35) { 2972189251Ssam wpa_hexdump(MSG_DEBUG, "OpenSSL: ClientHello SessionTicket " 2973189251Ssam "extension", ext->data, ext->length); 2974189251Ssam conn->session_ticket = os_malloc(ext->length); 2975189251Ssam if (conn->session_ticket == NULL) 2976189251Ssam return SSL_AD_INTERNAL_ERROR; 2977189251Ssam 2978189251Ssam os_memcpy(conn->session_ticket, ext->data, ext->length); 2979189251Ssam conn->session_ticket_len = ext->length; 2980189251Ssam } 2981189251Ssam 2982189251Ssam return 0; 2983189251Ssam} 2984189251Ssam#endif /* SSL_OP_NO_TICKET */ 2985189251Ssam#endif /* CONFIG_OPENSSL_TICKET_OVERRIDE */ 2986214734Srpaulo#endif /* EAP_FAST || EAP_FAST_DYNAMIC || EAP_SERVER_FAST */ 2987189251Ssam 2988189251Ssam 2989189251Ssamint tls_connection_set_session_ticket_cb(void *tls_ctx, 2990189251Ssam struct tls_connection *conn, 2991189251Ssam tls_session_ticket_cb cb, 2992189251Ssam void *ctx) 2993189251Ssam{ 2994214734Srpaulo#if defined(EAP_FAST) || defined(EAP_FAST_DYNAMIC) || defined(EAP_SERVER_FAST) 2995189251Ssam conn->session_ticket_cb = cb; 2996189251Ssam conn->session_ticket_cb_ctx = ctx; 2997189251Ssam 2998189251Ssam if (cb) { 2999189251Ssam if (SSL_set_session_secret_cb(conn->ssl, tls_sess_sec_cb, 3000189251Ssam conn) != 1) 3001189251Ssam return -1; 3002189251Ssam#ifdef CONFIG_OPENSSL_TICKET_OVERRIDE 3003189251Ssam SSL_set_session_ticket_ext_cb(conn->ssl, 3004189251Ssam tls_session_ticket_ext_cb, conn); 3005189251Ssam#else /* CONFIG_OPENSSL_TICKET_OVERRIDE */ 3006189251Ssam#ifdef SSL_OP_NO_TICKET 3007189251Ssam SSL_set_tlsext_debug_callback(conn->ssl, tls_hello_ext_cb); 3008189251Ssam SSL_set_tlsext_debug_arg(conn->ssl, conn); 3009189251Ssam#else /* SSL_OP_NO_TICKET */ 3010189251Ssam if (SSL_set_hello_extension_cb(conn->ssl, tls_hello_ext_cb, 3011189251Ssam conn) != 1) 3012189251Ssam return -1; 3013189251Ssam#endif /* SSL_OP_NO_TICKET */ 3014189251Ssam#endif /* CONFIG_OPENSSL_TICKET_OVERRIDE */ 3015189251Ssam } else { 3016189251Ssam if (SSL_set_session_secret_cb(conn->ssl, NULL, NULL) != 1) 3017189251Ssam return -1; 3018189251Ssam#ifdef CONFIG_OPENSSL_TICKET_OVERRIDE 3019189251Ssam SSL_set_session_ticket_ext_cb(conn->ssl, NULL, NULL); 3020189251Ssam#else /* CONFIG_OPENSSL_TICKET_OVERRIDE */ 3021189251Ssam#ifdef SSL_OP_NO_TICKET 3022189251Ssam SSL_set_tlsext_debug_callback(conn->ssl, NULL); 3023189251Ssam SSL_set_tlsext_debug_arg(conn->ssl, conn); 3024189251Ssam#else /* SSL_OP_NO_TICKET */ 3025189251Ssam if (SSL_set_hello_extension_cb(conn->ssl, NULL, NULL) != 1) 3026189251Ssam return -1; 3027189251Ssam#endif /* SSL_OP_NO_TICKET */ 3028189251Ssam#endif /* CONFIG_OPENSSL_TICKET_OVERRIDE */ 3029189251Ssam } 3030189251Ssam 3031189251Ssam return 0; 3032214734Srpaulo#else /* EAP_FAST || EAP_FAST_DYNAMIC || EAP_SERVER_FAST */ 3033189251Ssam return -1; 3034214734Srpaulo#endif /* EAP_FAST || EAP_FAST_DYNAMIC || EAP_SERVER_FAST */ 3035189251Ssam} 3036