tls_openssl.c revision 209158
1189251Ssam/* 2189251Ssam * WPA Supplicant / SSL/TLS interface functions for openssl 3189251Ssam * Copyright (c) 2004-2008, Jouni Malinen <j@w1.fi> 4189251Ssam * 5189251Ssam * This program is free software; you can redistribute it and/or modify 6189251Ssam * it under the terms of the GNU General Public License version 2 as 7189251Ssam * published by the Free Software Foundation. 8189251Ssam * 9189251Ssam * Alternatively, this software may be distributed under the terms of BSD 10189251Ssam * license. 11189251Ssam * 12189251Ssam * See README and COPYING for more details. 13189251Ssam */ 14189251Ssam 15189251Ssam#include "includes.h" 16189251Ssam 17189251Ssam#ifndef CONFIG_SMARTCARD 18189251Ssam#ifndef OPENSSL_NO_ENGINE 19189251Ssam#define OPENSSL_NO_ENGINE 20189251Ssam#endif 21189251Ssam#endif 22189251Ssam 23189251Ssam#include <openssl/ssl.h> 24189251Ssam#include <openssl/err.h> 25189251Ssam#include <openssl/pkcs12.h> 26189251Ssam#include <openssl/x509v3.h> 27189251Ssam#ifndef OPENSSL_NO_ENGINE 28189251Ssam#include <openssl/engine.h> 29189251Ssam#endif /* OPENSSL_NO_ENGINE */ 30189251Ssam 31189251Ssam#include "common.h" 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 52189251Ssamstruct tls_connection { 53189251Ssam SSL *ssl; 54189251Ssam BIO *ssl_in, *ssl_out; 55189251Ssam#ifndef OPENSSL_NO_ENGINE 56189251Ssam ENGINE *engine; /* functional reference to the engine */ 57189251Ssam EVP_PKEY *private_key; /* the private key if using engine */ 58189251Ssam#endif /* OPENSSL_NO_ENGINE */ 59189251Ssam char *subject_match, *altsubject_match; 60189251Ssam int read_alerts, write_alerts, failed; 61189251Ssam 62189251Ssam tls_session_ticket_cb session_ticket_cb; 63189251Ssam void *session_ticket_cb_ctx; 64189251Ssam 65189251Ssam /* SessionTicket received from OpenSSL hello_extension_cb (server) */ 66189251Ssam u8 *session_ticket; 67189251Ssam size_t session_ticket_len; 68189251Ssam}; 69189251Ssam 70189251Ssam 71189251Ssam#ifdef CONFIG_NO_STDOUT_DEBUG 72189251Ssam 73189251Ssamstatic void _tls_show_errors(void) 74189251Ssam{ 75189251Ssam unsigned long err; 76189251Ssam 77189251Ssam while ((err = ERR_get_error())) { 78189251Ssam /* Just ignore the errors, since stdout is disabled */ 79189251Ssam } 80189251Ssam} 81189251Ssam#define tls_show_errors(l, f, t) _tls_show_errors() 82189251Ssam 83189251Ssam#else /* CONFIG_NO_STDOUT_DEBUG */ 84189251Ssam 85189251Ssamstatic void tls_show_errors(int level, const char *func, const char *txt) 86189251Ssam{ 87189251Ssam unsigned long err; 88189251Ssam 89189251Ssam wpa_printf(level, "OpenSSL: %s - %s %s", 90189251Ssam func, txt, ERR_error_string(ERR_get_error(), NULL)); 91189251Ssam 92189251Ssam while ((err = ERR_get_error())) { 93189251Ssam wpa_printf(MSG_INFO, "OpenSSL: pending error: %s", 94189251Ssam ERR_error_string(err, NULL)); 95189251Ssam } 96189251Ssam} 97189251Ssam 98189251Ssam#endif /* CONFIG_NO_STDOUT_DEBUG */ 99189251Ssam 100189251Ssam 101189251Ssam#ifdef CONFIG_NATIVE_WINDOWS 102189251Ssam 103189251Ssam/* Windows CryptoAPI and access to certificate stores */ 104189251Ssam#include <wincrypt.h> 105189251Ssam 106189251Ssam#ifdef __MINGW32_VERSION 107189251Ssam/* 108189251Ssam * MinGW does not yet include all the needed definitions for CryptoAPI, so 109189251Ssam * define here whatever extra is needed. 110189251Ssam */ 111189251Ssam#define CERT_SYSTEM_STORE_CURRENT_USER (1 << 16) 112189251Ssam#define CERT_STORE_READONLY_FLAG 0x00008000 113189251Ssam#define CERT_STORE_OPEN_EXISTING_FLAG 0x00004000 114189251Ssam 115189251Ssam#endif /* __MINGW32_VERSION */ 116189251Ssam 117189251Ssam 118189251Ssamstruct cryptoapi_rsa_data { 119189251Ssam const CERT_CONTEXT *cert; 120189251Ssam HCRYPTPROV crypt_prov; 121189251Ssam DWORD key_spec; 122189251Ssam BOOL free_crypt_prov; 123189251Ssam}; 124189251Ssam 125189251Ssam 126189251Ssamstatic void cryptoapi_error(const char *msg) 127189251Ssam{ 128189251Ssam wpa_printf(MSG_INFO, "CryptoAPI: %s; err=%u", 129189251Ssam msg, (unsigned int) GetLastError()); 130189251Ssam} 131189251Ssam 132189251Ssam 133189251Ssamstatic int cryptoapi_rsa_pub_enc(int flen, const unsigned char *from, 134189251Ssam unsigned char *to, RSA *rsa, int padding) 135189251Ssam{ 136189251Ssam wpa_printf(MSG_DEBUG, "%s - not implemented", __func__); 137189251Ssam return 0; 138189251Ssam} 139189251Ssam 140189251Ssam 141189251Ssamstatic int cryptoapi_rsa_pub_dec(int flen, const unsigned char *from, 142189251Ssam unsigned char *to, RSA *rsa, int padding) 143189251Ssam{ 144189251Ssam wpa_printf(MSG_DEBUG, "%s - not implemented", __func__); 145189251Ssam return 0; 146189251Ssam} 147189251Ssam 148189251Ssam 149189251Ssamstatic int cryptoapi_rsa_priv_enc(int flen, const unsigned char *from, 150189251Ssam unsigned char *to, RSA *rsa, int padding) 151189251Ssam{ 152189251Ssam struct cryptoapi_rsa_data *priv = 153189251Ssam (struct cryptoapi_rsa_data *) rsa->meth->app_data; 154189251Ssam HCRYPTHASH hash; 155189251Ssam DWORD hash_size, len, i; 156189251Ssam unsigned char *buf = NULL; 157189251Ssam int ret = 0; 158189251Ssam 159189251Ssam if (priv == NULL) { 160189251Ssam RSAerr(RSA_F_RSA_EAY_PRIVATE_ENCRYPT, 161189251Ssam ERR_R_PASSED_NULL_PARAMETER); 162189251Ssam return 0; 163189251Ssam } 164189251Ssam 165189251Ssam if (padding != RSA_PKCS1_PADDING) { 166189251Ssam RSAerr(RSA_F_RSA_EAY_PRIVATE_ENCRYPT, 167189251Ssam RSA_R_UNKNOWN_PADDING_TYPE); 168189251Ssam return 0; 169189251Ssam } 170189251Ssam 171189251Ssam if (flen != 16 /* MD5 */ + 20 /* SHA-1 */) { 172189251Ssam wpa_printf(MSG_INFO, "%s - only MD5-SHA1 hash supported", 173189251Ssam __func__); 174189251Ssam RSAerr(RSA_F_RSA_EAY_PRIVATE_ENCRYPT, 175189251Ssam RSA_R_INVALID_MESSAGE_LENGTH); 176189251Ssam return 0; 177189251Ssam } 178189251Ssam 179189251Ssam if (!CryptCreateHash(priv->crypt_prov, CALG_SSL3_SHAMD5, 0, 0, &hash)) 180189251Ssam { 181189251Ssam cryptoapi_error("CryptCreateHash failed"); 182189251Ssam return 0; 183189251Ssam } 184189251Ssam 185189251Ssam len = sizeof(hash_size); 186189251Ssam if (!CryptGetHashParam(hash, HP_HASHSIZE, (BYTE *) &hash_size, &len, 187189251Ssam 0)) { 188189251Ssam cryptoapi_error("CryptGetHashParam failed"); 189189251Ssam goto err; 190189251Ssam } 191189251Ssam 192189251Ssam if ((int) hash_size != flen) { 193189251Ssam wpa_printf(MSG_INFO, "CryptoAPI: Invalid hash size (%u != %d)", 194189251Ssam (unsigned) hash_size, flen); 195189251Ssam RSAerr(RSA_F_RSA_EAY_PRIVATE_ENCRYPT, 196189251Ssam RSA_R_INVALID_MESSAGE_LENGTH); 197189251Ssam goto err; 198189251Ssam } 199189251Ssam if (!CryptSetHashParam(hash, HP_HASHVAL, (BYTE * ) from, 0)) { 200189251Ssam cryptoapi_error("CryptSetHashParam failed"); 201189251Ssam goto err; 202189251Ssam } 203189251Ssam 204189251Ssam len = RSA_size(rsa); 205189251Ssam buf = os_malloc(len); 206189251Ssam if (buf == NULL) { 207189251Ssam RSAerr(RSA_F_RSA_EAY_PRIVATE_ENCRYPT, ERR_R_MALLOC_FAILURE); 208189251Ssam goto err; 209189251Ssam } 210189251Ssam 211189251Ssam if (!CryptSignHash(hash, priv->key_spec, NULL, 0, buf, &len)) { 212189251Ssam cryptoapi_error("CryptSignHash failed"); 213189251Ssam goto err; 214189251Ssam } 215189251Ssam 216189251Ssam for (i = 0; i < len; i++) 217189251Ssam to[i] = buf[len - i - 1]; 218189251Ssam ret = len; 219189251Ssam 220189251Ssamerr: 221189251Ssam os_free(buf); 222189251Ssam CryptDestroyHash(hash); 223189251Ssam 224189251Ssam return ret; 225189251Ssam} 226189251Ssam 227189251Ssam 228189251Ssamstatic int cryptoapi_rsa_priv_dec(int flen, const unsigned char *from, 229189251Ssam unsigned char *to, RSA *rsa, int padding) 230189251Ssam{ 231189251Ssam wpa_printf(MSG_DEBUG, "%s - not implemented", __func__); 232189251Ssam return 0; 233189251Ssam} 234189251Ssam 235189251Ssam 236189251Ssamstatic void cryptoapi_free_data(struct cryptoapi_rsa_data *priv) 237189251Ssam{ 238189251Ssam if (priv == NULL) 239189251Ssam return; 240189251Ssam if (priv->crypt_prov && priv->free_crypt_prov) 241189251Ssam CryptReleaseContext(priv->crypt_prov, 0); 242189251Ssam if (priv->cert) 243189251Ssam CertFreeCertificateContext(priv->cert); 244189251Ssam os_free(priv); 245189251Ssam} 246189251Ssam 247189251Ssam 248189251Ssamstatic int cryptoapi_finish(RSA *rsa) 249189251Ssam{ 250189251Ssam cryptoapi_free_data((struct cryptoapi_rsa_data *) rsa->meth->app_data); 251189251Ssam os_free((void *) rsa->meth); 252189251Ssam rsa->meth = NULL; 253189251Ssam return 1; 254189251Ssam} 255189251Ssam 256189251Ssam 257189251Ssamstatic const CERT_CONTEXT * cryptoapi_find_cert(const char *name, DWORD store) 258189251Ssam{ 259189251Ssam HCERTSTORE cs; 260189251Ssam const CERT_CONTEXT *ret = NULL; 261189251Ssam 262189251Ssam cs = CertOpenStore((LPCSTR) CERT_STORE_PROV_SYSTEM, 0, 0, 263189251Ssam store | CERT_STORE_OPEN_EXISTING_FLAG | 264189251Ssam CERT_STORE_READONLY_FLAG, L"MY"); 265189251Ssam if (cs == NULL) { 266189251Ssam cryptoapi_error("Failed to open 'My system store'"); 267189251Ssam return NULL; 268189251Ssam } 269189251Ssam 270189251Ssam if (strncmp(name, "cert://", 7) == 0) { 271189251Ssam unsigned short wbuf[255]; 272189251Ssam MultiByteToWideChar(CP_ACP, 0, name + 7, -1, wbuf, 255); 273189251Ssam ret = CertFindCertificateInStore(cs, X509_ASN_ENCODING | 274189251Ssam PKCS_7_ASN_ENCODING, 275189251Ssam 0, CERT_FIND_SUBJECT_STR, 276189251Ssam wbuf, NULL); 277189251Ssam } else if (strncmp(name, "hash://", 7) == 0) { 278189251Ssam CRYPT_HASH_BLOB blob; 279189251Ssam int len; 280189251Ssam const char *hash = name + 7; 281189251Ssam unsigned char *buf; 282189251Ssam 283189251Ssam len = os_strlen(hash) / 2; 284189251Ssam buf = os_malloc(len); 285189251Ssam if (buf && hexstr2bin(hash, buf, len) == 0) { 286189251Ssam blob.cbData = len; 287189251Ssam blob.pbData = buf; 288189251Ssam ret = CertFindCertificateInStore(cs, 289189251Ssam X509_ASN_ENCODING | 290189251Ssam PKCS_7_ASN_ENCODING, 291189251Ssam 0, CERT_FIND_HASH, 292189251Ssam &blob, NULL); 293189251Ssam } 294189251Ssam os_free(buf); 295189251Ssam } 296189251Ssam 297189251Ssam CertCloseStore(cs, 0); 298189251Ssam 299189251Ssam return ret; 300189251Ssam} 301189251Ssam 302189251Ssam 303189251Ssamstatic int tls_cryptoapi_cert(SSL *ssl, const char *name) 304189251Ssam{ 305189251Ssam X509 *cert = NULL; 306189251Ssam RSA *rsa = NULL, *pub_rsa; 307189251Ssam struct cryptoapi_rsa_data *priv; 308189251Ssam RSA_METHOD *rsa_meth; 309189251Ssam 310189251Ssam if (name == NULL || 311189251Ssam (strncmp(name, "cert://", 7) != 0 && 312189251Ssam strncmp(name, "hash://", 7) != 0)) 313189251Ssam return -1; 314189251Ssam 315189251Ssam priv = os_zalloc(sizeof(*priv)); 316189251Ssam rsa_meth = os_zalloc(sizeof(*rsa_meth)); 317189251Ssam if (priv == NULL || rsa_meth == NULL) { 318189251Ssam wpa_printf(MSG_WARNING, "CryptoAPI: Failed to allocate memory " 319189251Ssam "for CryptoAPI RSA method"); 320189251Ssam os_free(priv); 321189251Ssam os_free(rsa_meth); 322189251Ssam return -1; 323189251Ssam } 324189251Ssam 325189251Ssam priv->cert = cryptoapi_find_cert(name, CERT_SYSTEM_STORE_CURRENT_USER); 326189251Ssam if (priv->cert == NULL) { 327189251Ssam priv->cert = cryptoapi_find_cert( 328189251Ssam name, CERT_SYSTEM_STORE_LOCAL_MACHINE); 329189251Ssam } 330189251Ssam if (priv->cert == NULL) { 331189251Ssam wpa_printf(MSG_INFO, "CryptoAPI: Could not find certificate " 332189251Ssam "'%s'", name); 333189251Ssam goto err; 334189251Ssam } 335189251Ssam 336189251Ssam cert = d2i_X509(NULL, (OPENSSL_d2i_TYPE) &priv->cert->pbCertEncoded, 337189251Ssam priv->cert->cbCertEncoded); 338189251Ssam if (cert == NULL) { 339189251Ssam wpa_printf(MSG_INFO, "CryptoAPI: Could not process X509 DER " 340189251Ssam "encoding"); 341189251Ssam goto err; 342189251Ssam } 343189251Ssam 344189251Ssam if (!CryptAcquireCertificatePrivateKey(priv->cert, 345189251Ssam CRYPT_ACQUIRE_COMPARE_KEY_FLAG, 346189251Ssam NULL, &priv->crypt_prov, 347189251Ssam &priv->key_spec, 348189251Ssam &priv->free_crypt_prov)) { 349189251Ssam cryptoapi_error("Failed to acquire a private key for the " 350189251Ssam "certificate"); 351189251Ssam goto err; 352189251Ssam } 353189251Ssam 354189251Ssam rsa_meth->name = "Microsoft CryptoAPI RSA Method"; 355189251Ssam rsa_meth->rsa_pub_enc = cryptoapi_rsa_pub_enc; 356189251Ssam rsa_meth->rsa_pub_dec = cryptoapi_rsa_pub_dec; 357189251Ssam rsa_meth->rsa_priv_enc = cryptoapi_rsa_priv_enc; 358189251Ssam rsa_meth->rsa_priv_dec = cryptoapi_rsa_priv_dec; 359189251Ssam rsa_meth->finish = cryptoapi_finish; 360189251Ssam rsa_meth->flags = RSA_METHOD_FLAG_NO_CHECK; 361189251Ssam rsa_meth->app_data = (char *) priv; 362189251Ssam 363189251Ssam rsa = RSA_new(); 364189251Ssam if (rsa == NULL) { 365189251Ssam SSLerr(SSL_F_SSL_CTX_USE_CERTIFICATE_FILE, 366189251Ssam ERR_R_MALLOC_FAILURE); 367189251Ssam goto err; 368189251Ssam } 369189251Ssam 370189251Ssam if (!SSL_use_certificate(ssl, cert)) { 371189251Ssam RSA_free(rsa); 372189251Ssam rsa = NULL; 373189251Ssam goto err; 374189251Ssam } 375189251Ssam pub_rsa = cert->cert_info->key->pkey->pkey.rsa; 376189251Ssam X509_free(cert); 377189251Ssam cert = NULL; 378189251Ssam 379189251Ssam rsa->n = BN_dup(pub_rsa->n); 380189251Ssam rsa->e = BN_dup(pub_rsa->e); 381189251Ssam if (!RSA_set_method(rsa, rsa_meth)) 382189251Ssam goto err; 383189251Ssam 384189251Ssam if (!SSL_use_RSAPrivateKey(ssl, rsa)) 385189251Ssam goto err; 386189251Ssam RSA_free(rsa); 387189251Ssam 388189251Ssam return 0; 389189251Ssam 390189251Ssamerr: 391189251Ssam if (cert) 392189251Ssam X509_free(cert); 393189251Ssam if (rsa) 394189251Ssam RSA_free(rsa); 395189251Ssam else { 396189251Ssam os_free(rsa_meth); 397189251Ssam cryptoapi_free_data(priv); 398189251Ssam } 399189251Ssam return -1; 400189251Ssam} 401189251Ssam 402189251Ssam 403189251Ssamstatic int tls_cryptoapi_ca_cert(SSL_CTX *ssl_ctx, SSL *ssl, const char *name) 404189251Ssam{ 405189251Ssam HCERTSTORE cs; 406189251Ssam PCCERT_CONTEXT ctx = NULL; 407189251Ssam X509 *cert; 408189251Ssam char buf[128]; 409189251Ssam const char *store; 410189251Ssam#ifdef UNICODE 411189251Ssam WCHAR *wstore; 412189251Ssam#endif /* UNICODE */ 413189251Ssam 414189251Ssam if (name == NULL || strncmp(name, "cert_store://", 13) != 0) 415189251Ssam return -1; 416189251Ssam 417189251Ssam store = name + 13; 418189251Ssam#ifdef UNICODE 419189251Ssam wstore = os_malloc((os_strlen(store) + 1) * sizeof(WCHAR)); 420189251Ssam if (wstore == NULL) 421189251Ssam return -1; 422189251Ssam wsprintf(wstore, L"%S", store); 423189251Ssam cs = CertOpenSystemStore(0, wstore); 424189251Ssam os_free(wstore); 425189251Ssam#else /* UNICODE */ 426189251Ssam cs = CertOpenSystemStore(0, store); 427189251Ssam#endif /* UNICODE */ 428189251Ssam if (cs == NULL) { 429189251Ssam wpa_printf(MSG_DEBUG, "%s: failed to open system cert store " 430189251Ssam "'%s': error=%d", __func__, store, 431189251Ssam (int) GetLastError()); 432189251Ssam return -1; 433189251Ssam } 434189251Ssam 435189251Ssam while ((ctx = CertEnumCertificatesInStore(cs, ctx))) { 436189251Ssam cert = d2i_X509(NULL, (OPENSSL_d2i_TYPE) &ctx->pbCertEncoded, 437189251Ssam ctx->cbCertEncoded); 438189251Ssam if (cert == NULL) { 439189251Ssam wpa_printf(MSG_INFO, "CryptoAPI: Could not process " 440189251Ssam "X509 DER encoding for CA cert"); 441189251Ssam continue; 442189251Ssam } 443189251Ssam 444189251Ssam X509_NAME_oneline(X509_get_subject_name(cert), buf, 445189251Ssam sizeof(buf)); 446189251Ssam wpa_printf(MSG_DEBUG, "OpenSSL: Loaded CA certificate for " 447189251Ssam "system certificate store: subject='%s'", buf); 448189251Ssam 449189251Ssam if (!X509_STORE_add_cert(ssl_ctx->cert_store, cert)) { 450189251Ssam tls_show_errors(MSG_WARNING, __func__, 451189251Ssam "Failed to add ca_cert to OpenSSL " 452189251Ssam "certificate store"); 453189251Ssam } 454189251Ssam 455189251Ssam X509_free(cert); 456189251Ssam } 457189251Ssam 458189251Ssam if (!CertCloseStore(cs, 0)) { 459189251Ssam wpa_printf(MSG_DEBUG, "%s: failed to close system cert store " 460189251Ssam "'%s': error=%d", __func__, name + 13, 461189251Ssam (int) GetLastError()); 462189251Ssam } 463189251Ssam 464189251Ssam return 0; 465189251Ssam} 466189251Ssam 467189251Ssam 468189251Ssam#else /* CONFIG_NATIVE_WINDOWS */ 469189251Ssam 470189251Ssamstatic int tls_cryptoapi_cert(SSL *ssl, const char *name) 471189251Ssam{ 472189251Ssam return -1; 473189251Ssam} 474189251Ssam 475189251Ssam#endif /* CONFIG_NATIVE_WINDOWS */ 476189251Ssam 477189251Ssam 478189251Ssamstatic void ssl_info_cb(const SSL *ssl, int where, int ret) 479189251Ssam{ 480189251Ssam const char *str; 481189251Ssam int w; 482189251Ssam 483189251Ssam wpa_printf(MSG_DEBUG, "SSL: (where=0x%x ret=0x%x)", where, ret); 484189251Ssam w = where & ~SSL_ST_MASK; 485189251Ssam if (w & SSL_ST_CONNECT) 486189251Ssam str = "SSL_connect"; 487189251Ssam else if (w & SSL_ST_ACCEPT) 488189251Ssam str = "SSL_accept"; 489189251Ssam else 490189251Ssam str = "undefined"; 491189251Ssam 492189251Ssam if (where & SSL_CB_LOOP) { 493189251Ssam wpa_printf(MSG_DEBUG, "SSL: %s:%s", 494189251Ssam str, SSL_state_string_long(ssl)); 495189251Ssam } else if (where & SSL_CB_ALERT) { 496189251Ssam wpa_printf(MSG_INFO, "SSL: SSL3 alert: %s:%s:%s", 497189251Ssam where & SSL_CB_READ ? 498189251Ssam "read (remote end reported an error)" : 499189251Ssam "write (local SSL3 detected an error)", 500189251Ssam SSL_alert_type_string_long(ret), 501189251Ssam SSL_alert_desc_string_long(ret)); 502189251Ssam if ((ret >> 8) == SSL3_AL_FATAL) { 503189251Ssam struct tls_connection *conn = 504189251Ssam SSL_get_app_data((SSL *) ssl); 505189251Ssam if (where & SSL_CB_READ) 506189251Ssam conn->read_alerts++; 507189251Ssam else 508189251Ssam conn->write_alerts++; 509189251Ssam } 510189251Ssam } else if (where & SSL_CB_EXIT && ret <= 0) { 511189251Ssam wpa_printf(MSG_DEBUG, "SSL: %s:%s in %s", 512189251Ssam str, ret == 0 ? "failed" : "error", 513189251Ssam SSL_state_string_long(ssl)); 514189251Ssam } 515189251Ssam} 516189251Ssam 517189251Ssam 518189251Ssam#ifndef OPENSSL_NO_ENGINE 519189251Ssam/** 520189251Ssam * tls_engine_load_dynamic_generic - load any openssl engine 521189251Ssam * @pre: an array of commands and values that load an engine initialized 522189251Ssam * in the engine specific function 523189251Ssam * @post: an array of commands and values that initialize an already loaded 524189251Ssam * engine (or %NULL if not required) 525189251Ssam * @id: the engine id of the engine to load (only required if post is not %NULL 526189251Ssam * 527189251Ssam * This function is a generic function that loads any openssl engine. 528189251Ssam * 529189251Ssam * Returns: 0 on success, -1 on failure 530189251Ssam */ 531189251Ssamstatic int tls_engine_load_dynamic_generic(const char *pre[], 532189251Ssam const char *post[], const char *id) 533189251Ssam{ 534189251Ssam ENGINE *engine; 535189251Ssam const char *dynamic_id = "dynamic"; 536189251Ssam 537189251Ssam engine = ENGINE_by_id(id); 538189251Ssam if (engine) { 539189251Ssam ENGINE_free(engine); 540189251Ssam wpa_printf(MSG_DEBUG, "ENGINE: engine '%s' is already " 541189251Ssam "available", id); 542189251Ssam return 0; 543189251Ssam } 544189251Ssam ERR_clear_error(); 545189251Ssam 546189251Ssam engine = ENGINE_by_id(dynamic_id); 547189251Ssam if (engine == NULL) { 548189251Ssam wpa_printf(MSG_INFO, "ENGINE: Can't find engine %s [%s]", 549189251Ssam dynamic_id, 550189251Ssam ERR_error_string(ERR_get_error(), NULL)); 551189251Ssam return -1; 552189251Ssam } 553189251Ssam 554189251Ssam /* Perform the pre commands. This will load the engine. */ 555189251Ssam while (pre && pre[0]) { 556189251Ssam wpa_printf(MSG_DEBUG, "ENGINE: '%s' '%s'", pre[0], pre[1]); 557189251Ssam if (ENGINE_ctrl_cmd_string(engine, pre[0], pre[1], 0) == 0) { 558189251Ssam wpa_printf(MSG_INFO, "ENGINE: ctrl cmd_string failed: " 559189251Ssam "%s %s [%s]", pre[0], pre[1], 560189251Ssam ERR_error_string(ERR_get_error(), NULL)); 561189251Ssam ENGINE_free(engine); 562189251Ssam return -1; 563189251Ssam } 564189251Ssam pre += 2; 565189251Ssam } 566189251Ssam 567189251Ssam /* 568189251Ssam * Free the reference to the "dynamic" engine. The loaded engine can 569189251Ssam * now be looked up using ENGINE_by_id(). 570189251Ssam */ 571189251Ssam ENGINE_free(engine); 572189251Ssam 573189251Ssam engine = ENGINE_by_id(id); 574189251Ssam if (engine == NULL) { 575189251Ssam wpa_printf(MSG_INFO, "ENGINE: Can't find engine %s [%s]", 576189251Ssam id, ERR_error_string(ERR_get_error(), NULL)); 577189251Ssam return -1; 578189251Ssam } 579189251Ssam 580189251Ssam while (post && post[0]) { 581189251Ssam wpa_printf(MSG_DEBUG, "ENGINE: '%s' '%s'", post[0], post[1]); 582189251Ssam if (ENGINE_ctrl_cmd_string(engine, post[0], post[1], 0) == 0) { 583189251Ssam wpa_printf(MSG_DEBUG, "ENGINE: ctrl cmd_string failed:" 584189251Ssam " %s %s [%s]", post[0], post[1], 585189251Ssam ERR_error_string(ERR_get_error(), NULL)); 586189251Ssam ENGINE_remove(engine); 587189251Ssam ENGINE_free(engine); 588189251Ssam return -1; 589189251Ssam } 590189251Ssam post += 2; 591189251Ssam } 592189251Ssam ENGINE_free(engine); 593189251Ssam 594189251Ssam return 0; 595189251Ssam} 596189251Ssam 597189251Ssam 598189251Ssam/** 599189251Ssam * tls_engine_load_dynamic_pkcs11 - load the pkcs11 engine provided by opensc 600189251Ssam * @pkcs11_so_path: pksc11_so_path from the configuration 601189251Ssam * @pcks11_module_path: pkcs11_module_path from the configuration 602189251Ssam */ 603189251Ssamstatic int tls_engine_load_dynamic_pkcs11(const char *pkcs11_so_path, 604189251Ssam const char *pkcs11_module_path) 605189251Ssam{ 606189251Ssam char *engine_id = "pkcs11"; 607189251Ssam const char *pre_cmd[] = { 608189251Ssam "SO_PATH", NULL /* pkcs11_so_path */, 609189251Ssam "ID", NULL /* engine_id */, 610189251Ssam "LIST_ADD", "1", 611189251Ssam /* "NO_VCHECK", "1", */ 612189251Ssam "LOAD", NULL, 613189251Ssam NULL, NULL 614189251Ssam }; 615189251Ssam const char *post_cmd[] = { 616189251Ssam "MODULE_PATH", NULL /* pkcs11_module_path */, 617189251Ssam NULL, NULL 618189251Ssam }; 619189251Ssam 620189251Ssam if (!pkcs11_so_path || !pkcs11_module_path) 621189251Ssam return 0; 622189251Ssam 623189251Ssam pre_cmd[1] = pkcs11_so_path; 624189251Ssam pre_cmd[3] = engine_id; 625189251Ssam post_cmd[1] = pkcs11_module_path; 626189251Ssam 627189251Ssam wpa_printf(MSG_DEBUG, "ENGINE: Loading pkcs11 Engine from %s", 628189251Ssam pkcs11_so_path); 629189251Ssam 630189251Ssam return tls_engine_load_dynamic_generic(pre_cmd, post_cmd, engine_id); 631189251Ssam} 632189251Ssam 633189251Ssam 634189251Ssam/** 635189251Ssam * tls_engine_load_dynamic_opensc - load the opensc engine provided by opensc 636189251Ssam * @opensc_so_path: opensc_so_path from the configuration 637189251Ssam */ 638189251Ssamstatic int tls_engine_load_dynamic_opensc(const char *opensc_so_path) 639189251Ssam{ 640189251Ssam char *engine_id = "opensc"; 641189251Ssam const char *pre_cmd[] = { 642189251Ssam "SO_PATH", NULL /* opensc_so_path */, 643189251Ssam "ID", NULL /* engine_id */, 644189251Ssam "LIST_ADD", "1", 645189251Ssam "LOAD", NULL, 646189251Ssam NULL, NULL 647189251Ssam }; 648189251Ssam 649189251Ssam if (!opensc_so_path) 650189251Ssam return 0; 651189251Ssam 652189251Ssam pre_cmd[1] = opensc_so_path; 653189251Ssam pre_cmd[3] = engine_id; 654189251Ssam 655189251Ssam wpa_printf(MSG_DEBUG, "ENGINE: Loading OpenSC Engine from %s", 656189251Ssam opensc_so_path); 657189251Ssam 658189251Ssam return tls_engine_load_dynamic_generic(pre_cmd, NULL, engine_id); 659189251Ssam} 660189251Ssam#endif /* OPENSSL_NO_ENGINE */ 661189251Ssam 662189251Ssam 663189251Ssamvoid * tls_init(const struct tls_config *conf) 664189251Ssam{ 665189251Ssam SSL_CTX *ssl; 666189251Ssam 667189251Ssam if (tls_openssl_ref_count == 0) { 668189251Ssam SSL_load_error_strings(); 669189251Ssam SSL_library_init(); 670209158Srpaulo#ifndef OPENSSL_NO_SHA256 671209158Srpaulo EVP_add_digest(EVP_sha256()); 672209158Srpaulo#endif /* OPENSSL_NO_SHA256 */ 673189251Ssam /* TODO: if /dev/urandom is available, PRNG is seeded 674189251Ssam * automatically. If this is not the case, random data should 675189251Ssam * be added here. */ 676189251Ssam 677189251Ssam#ifdef PKCS12_FUNCS 678209158Srpaulo#ifndef OPENSSL_NO_RC2 679209158Srpaulo /* 680209158Srpaulo * 40-bit RC2 is commonly used in PKCS#12 files, so enable it. 681209158Srpaulo * This is enabled by PKCS12_PBE_add() in OpenSSL 0.9.8 682209158Srpaulo * versions, but it looks like OpenSSL 1.0.0 does not do that 683209158Srpaulo * anymore. 684209158Srpaulo */ 685209158Srpaulo EVP_add_cipher(EVP_rc2_40_cbc()); 686209158Srpaulo#endif /* OPENSSL_NO_RC2 */ 687189251Ssam PKCS12_PBE_add(); 688189251Ssam#endif /* PKCS12_FUNCS */ 689189251Ssam } 690189251Ssam tls_openssl_ref_count++; 691189251Ssam 692189251Ssam ssl = SSL_CTX_new(TLSv1_method()); 693189251Ssam if (ssl == NULL) 694189251Ssam return NULL; 695189251Ssam 696189251Ssam SSL_CTX_set_info_callback(ssl, ssl_info_cb); 697189251Ssam 698189251Ssam#ifndef OPENSSL_NO_ENGINE 699189251Ssam if (conf && 700189251Ssam (conf->opensc_engine_path || conf->pkcs11_engine_path || 701189251Ssam conf->pkcs11_module_path)) { 702189251Ssam wpa_printf(MSG_DEBUG, "ENGINE: Loading dynamic engine"); 703189251Ssam ERR_load_ENGINE_strings(); 704189251Ssam ENGINE_load_dynamic(); 705189251Ssam 706189251Ssam if (tls_engine_load_dynamic_opensc(conf->opensc_engine_path) || 707189251Ssam tls_engine_load_dynamic_pkcs11(conf->pkcs11_engine_path, 708189251Ssam conf->pkcs11_module_path)) { 709189251Ssam tls_deinit(ssl); 710189251Ssam return NULL; 711189251Ssam } 712189251Ssam } 713189251Ssam#endif /* OPENSSL_NO_ENGINE */ 714189251Ssam 715189251Ssam return ssl; 716189251Ssam} 717189251Ssam 718189251Ssam 719189251Ssamvoid tls_deinit(void *ssl_ctx) 720189251Ssam{ 721189251Ssam SSL_CTX *ssl = ssl_ctx; 722189251Ssam SSL_CTX_free(ssl); 723189251Ssam 724189251Ssam tls_openssl_ref_count--; 725189251Ssam if (tls_openssl_ref_count == 0) { 726189251Ssam#ifndef OPENSSL_NO_ENGINE 727189251Ssam ENGINE_cleanup(); 728189251Ssam#endif /* OPENSSL_NO_ENGINE */ 729189251Ssam CRYPTO_cleanup_all_ex_data(); 730189251Ssam ERR_remove_state(0); 731189251Ssam ERR_free_strings(); 732189251Ssam EVP_cleanup(); 733189251Ssam } 734189251Ssam} 735189251Ssam 736189251Ssam 737189251Ssamstatic int tls_engine_init(struct tls_connection *conn, const char *engine_id, 738189251Ssam const char *pin, const char *key_id, 739189251Ssam const char *cert_id, const char *ca_cert_id) 740189251Ssam{ 741189251Ssam#ifndef OPENSSL_NO_ENGINE 742189251Ssam int ret = -1; 743189251Ssam if (engine_id == NULL) { 744189251Ssam wpa_printf(MSG_ERROR, "ENGINE: Engine ID not set"); 745189251Ssam return -1; 746189251Ssam } 747189251Ssam if (pin == NULL) { 748189251Ssam wpa_printf(MSG_ERROR, "ENGINE: Smartcard PIN not set"); 749189251Ssam return -1; 750189251Ssam } 751189251Ssam if (key_id == NULL) { 752189251Ssam wpa_printf(MSG_ERROR, "ENGINE: Key Id not set"); 753189251Ssam return -1; 754189251Ssam } 755189251Ssam 756189251Ssam ERR_clear_error(); 757189251Ssam conn->engine = ENGINE_by_id(engine_id); 758189251Ssam if (!conn->engine) { 759189251Ssam wpa_printf(MSG_ERROR, "ENGINE: engine %s not available [%s]", 760189251Ssam engine_id, ERR_error_string(ERR_get_error(), NULL)); 761189251Ssam goto err; 762189251Ssam } 763189251Ssam if (ENGINE_init(conn->engine) != 1) { 764189251Ssam wpa_printf(MSG_ERROR, "ENGINE: engine init failed " 765189251Ssam "(engine: %s) [%s]", engine_id, 766189251Ssam ERR_error_string(ERR_get_error(), NULL)); 767189251Ssam goto err; 768189251Ssam } 769189251Ssam wpa_printf(MSG_DEBUG, "ENGINE: engine initialized"); 770189251Ssam 771189251Ssam if (ENGINE_ctrl_cmd_string(conn->engine, "PIN", pin, 0) == 0) { 772189251Ssam wpa_printf(MSG_ERROR, "ENGINE: cannot set pin [%s]", 773189251Ssam ERR_error_string(ERR_get_error(), NULL)); 774189251Ssam goto err; 775189251Ssam } 776189251Ssam /* load private key first in-case PIN is required for cert */ 777189251Ssam conn->private_key = ENGINE_load_private_key(conn->engine, 778189251Ssam key_id, NULL, NULL); 779189251Ssam if (!conn->private_key) { 780189251Ssam wpa_printf(MSG_ERROR, "ENGINE: cannot load private key with id" 781189251Ssam " '%s' [%s]", key_id, 782189251Ssam ERR_error_string(ERR_get_error(), NULL)); 783189251Ssam ret = TLS_SET_PARAMS_ENGINE_PRV_INIT_FAILED; 784189251Ssam goto err; 785189251Ssam } 786189251Ssam 787189251Ssam /* handle a certificate and/or CA certificate */ 788189251Ssam if (cert_id || ca_cert_id) { 789189251Ssam const char *cmd_name = "LOAD_CERT_CTRL"; 790189251Ssam 791189251Ssam /* test if the engine supports a LOAD_CERT_CTRL */ 792189251Ssam if (!ENGINE_ctrl(conn->engine, ENGINE_CTRL_GET_CMD_FROM_NAME, 793189251Ssam 0, (void *)cmd_name, NULL)) { 794189251Ssam wpa_printf(MSG_ERROR, "ENGINE: engine does not support" 795189251Ssam " loading certificates"); 796189251Ssam ret = TLS_SET_PARAMS_ENGINE_PRV_INIT_FAILED; 797189251Ssam goto err; 798189251Ssam } 799189251Ssam } 800189251Ssam 801189251Ssam return 0; 802189251Ssam 803189251Ssamerr: 804189251Ssam if (conn->engine) { 805189251Ssam ENGINE_free(conn->engine); 806189251Ssam conn->engine = NULL; 807189251Ssam } 808189251Ssam 809189251Ssam if (conn->private_key) { 810189251Ssam EVP_PKEY_free(conn->private_key); 811189251Ssam conn->private_key = NULL; 812189251Ssam } 813189251Ssam 814189251Ssam return ret; 815189251Ssam#else /* OPENSSL_NO_ENGINE */ 816189251Ssam return 0; 817189251Ssam#endif /* OPENSSL_NO_ENGINE */ 818189251Ssam} 819189251Ssam 820189251Ssam 821189251Ssamstatic void tls_engine_deinit(struct tls_connection *conn) 822189251Ssam{ 823189251Ssam#ifndef OPENSSL_NO_ENGINE 824189251Ssam wpa_printf(MSG_DEBUG, "ENGINE: engine deinit"); 825189251Ssam if (conn->private_key) { 826189251Ssam EVP_PKEY_free(conn->private_key); 827189251Ssam conn->private_key = NULL; 828189251Ssam } 829189251Ssam if (conn->engine) { 830189251Ssam ENGINE_finish(conn->engine); 831189251Ssam conn->engine = NULL; 832189251Ssam } 833189251Ssam#endif /* OPENSSL_NO_ENGINE */ 834189251Ssam} 835189251Ssam 836189251Ssam 837189251Ssamint tls_get_errors(void *ssl_ctx) 838189251Ssam{ 839189251Ssam int count = 0; 840189251Ssam unsigned long err; 841189251Ssam 842189251Ssam while ((err = ERR_get_error())) { 843189251Ssam wpa_printf(MSG_INFO, "TLS - SSL error: %s", 844189251Ssam ERR_error_string(err, NULL)); 845189251Ssam count++; 846189251Ssam } 847189251Ssam 848189251Ssam return count; 849189251Ssam} 850189251Ssam 851189251Ssamstruct tls_connection * tls_connection_init(void *ssl_ctx) 852189251Ssam{ 853189251Ssam SSL_CTX *ssl = ssl_ctx; 854189251Ssam struct tls_connection *conn; 855189251Ssam long options; 856189251Ssam 857189251Ssam conn = os_zalloc(sizeof(*conn)); 858189251Ssam if (conn == NULL) 859189251Ssam return NULL; 860189251Ssam conn->ssl = SSL_new(ssl); 861189251Ssam if (conn->ssl == NULL) { 862189251Ssam tls_show_errors(MSG_INFO, __func__, 863189251Ssam "Failed to initialize new SSL connection"); 864189251Ssam os_free(conn); 865189251Ssam return NULL; 866189251Ssam } 867189251Ssam 868189251Ssam SSL_set_app_data(conn->ssl, conn); 869189251Ssam options = SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3 | 870189251Ssam SSL_OP_SINGLE_DH_USE; 871189251Ssam#ifdef SSL_OP_NO_COMPRESSION 872189251Ssam options |= SSL_OP_NO_COMPRESSION; 873189251Ssam#endif /* SSL_OP_NO_COMPRESSION */ 874189251Ssam SSL_set_options(conn->ssl, options); 875189251Ssam 876189251Ssam conn->ssl_in = BIO_new(BIO_s_mem()); 877189251Ssam if (!conn->ssl_in) { 878189251Ssam tls_show_errors(MSG_INFO, __func__, 879189251Ssam "Failed to create a new BIO for ssl_in"); 880189251Ssam SSL_free(conn->ssl); 881189251Ssam os_free(conn); 882189251Ssam return NULL; 883189251Ssam } 884189251Ssam 885189251Ssam conn->ssl_out = BIO_new(BIO_s_mem()); 886189251Ssam if (!conn->ssl_out) { 887189251Ssam tls_show_errors(MSG_INFO, __func__, 888189251Ssam "Failed to create a new BIO for ssl_out"); 889189251Ssam SSL_free(conn->ssl); 890189251Ssam BIO_free(conn->ssl_in); 891189251Ssam os_free(conn); 892189251Ssam return NULL; 893189251Ssam } 894189251Ssam 895189251Ssam SSL_set_bio(conn->ssl, conn->ssl_in, conn->ssl_out); 896189251Ssam 897189251Ssam return conn; 898189251Ssam} 899189251Ssam 900189251Ssam 901189251Ssamvoid tls_connection_deinit(void *ssl_ctx, struct tls_connection *conn) 902189251Ssam{ 903189251Ssam if (conn == NULL) 904189251Ssam return; 905189251Ssam SSL_free(conn->ssl); 906189251Ssam tls_engine_deinit(conn); 907189251Ssam os_free(conn->subject_match); 908189251Ssam os_free(conn->altsubject_match); 909189251Ssam os_free(conn->session_ticket); 910189251Ssam os_free(conn); 911189251Ssam} 912189251Ssam 913189251Ssam 914189251Ssamint tls_connection_established(void *ssl_ctx, struct tls_connection *conn) 915189251Ssam{ 916189251Ssam return conn ? SSL_is_init_finished(conn->ssl) : 0; 917189251Ssam} 918189251Ssam 919189251Ssam 920189251Ssamint tls_connection_shutdown(void *ssl_ctx, struct tls_connection *conn) 921189251Ssam{ 922189251Ssam if (conn == NULL) 923189251Ssam return -1; 924189251Ssam 925189251Ssam /* Shutdown previous TLS connection without notifying the peer 926189251Ssam * because the connection was already terminated in practice 927189251Ssam * and "close notify" shutdown alert would confuse AS. */ 928189251Ssam SSL_set_quiet_shutdown(conn->ssl, 1); 929189251Ssam SSL_shutdown(conn->ssl); 930189251Ssam return 0; 931189251Ssam} 932189251Ssam 933189251Ssam 934189251Ssamstatic int tls_match_altsubject_component(X509 *cert, int type, 935189251Ssam const char *value, size_t len) 936189251Ssam{ 937189251Ssam GENERAL_NAME *gen; 938189251Ssam void *ext; 939189251Ssam int i, found = 0; 940189251Ssam 941189251Ssam ext = X509_get_ext_d2i(cert, NID_subject_alt_name, NULL, NULL); 942189251Ssam 943189251Ssam for (i = 0; ext && i < sk_GENERAL_NAME_num(ext); i++) { 944189251Ssam gen = sk_GENERAL_NAME_value(ext, i); 945189251Ssam if (gen->type != type) 946189251Ssam continue; 947189251Ssam if (os_strlen((char *) gen->d.ia5->data) == len && 948189251Ssam os_memcmp(value, gen->d.ia5->data, len) == 0) 949189251Ssam found++; 950189251Ssam } 951189251Ssam 952189251Ssam return found; 953189251Ssam} 954189251Ssam 955189251Ssam 956189251Ssamstatic int tls_match_altsubject(X509 *cert, const char *match) 957189251Ssam{ 958189251Ssam int type; 959189251Ssam const char *pos, *end; 960189251Ssam size_t len; 961189251Ssam 962189251Ssam pos = match; 963189251Ssam do { 964189251Ssam if (os_strncmp(pos, "EMAIL:", 6) == 0) { 965189251Ssam type = GEN_EMAIL; 966189251Ssam pos += 6; 967189251Ssam } else if (os_strncmp(pos, "DNS:", 4) == 0) { 968189251Ssam type = GEN_DNS; 969189251Ssam pos += 4; 970189251Ssam } else if (os_strncmp(pos, "URI:", 4) == 0) { 971189251Ssam type = GEN_URI; 972189251Ssam pos += 4; 973189251Ssam } else { 974189251Ssam wpa_printf(MSG_INFO, "TLS: Invalid altSubjectName " 975189251Ssam "match '%s'", pos); 976189251Ssam return 0; 977189251Ssam } 978189251Ssam end = os_strchr(pos, ';'); 979189251Ssam while (end) { 980189251Ssam if (os_strncmp(end + 1, "EMAIL:", 6) == 0 || 981189251Ssam os_strncmp(end + 1, "DNS:", 4) == 0 || 982189251Ssam os_strncmp(end + 1, "URI:", 4) == 0) 983189251Ssam break; 984189251Ssam end = os_strchr(end + 1, ';'); 985189251Ssam } 986189251Ssam if (end) 987189251Ssam len = end - pos; 988189251Ssam else 989189251Ssam len = os_strlen(pos); 990189251Ssam if (tls_match_altsubject_component(cert, type, pos, len) > 0) 991189251Ssam return 1; 992189251Ssam pos = end + 1; 993189251Ssam } while (end); 994189251Ssam 995189251Ssam return 0; 996189251Ssam} 997189251Ssam 998189251Ssam 999189251Ssamstatic int tls_verify_cb(int preverify_ok, X509_STORE_CTX *x509_ctx) 1000189251Ssam{ 1001189251Ssam char buf[256]; 1002189251Ssam X509 *err_cert; 1003189251Ssam int err, depth; 1004189251Ssam SSL *ssl; 1005189251Ssam struct tls_connection *conn; 1006189251Ssam char *match, *altmatch; 1007189251Ssam 1008189251Ssam err_cert = X509_STORE_CTX_get_current_cert(x509_ctx); 1009189251Ssam err = X509_STORE_CTX_get_error(x509_ctx); 1010189251Ssam depth = X509_STORE_CTX_get_error_depth(x509_ctx); 1011189251Ssam ssl = X509_STORE_CTX_get_ex_data(x509_ctx, 1012189251Ssam SSL_get_ex_data_X509_STORE_CTX_idx()); 1013189251Ssam X509_NAME_oneline(X509_get_subject_name(err_cert), buf, sizeof(buf)); 1014189251Ssam 1015189251Ssam conn = SSL_get_app_data(ssl); 1016189251Ssam match = conn ? conn->subject_match : NULL; 1017189251Ssam altmatch = conn ? conn->altsubject_match : NULL; 1018189251Ssam 1019189251Ssam if (!preverify_ok) { 1020189251Ssam wpa_printf(MSG_WARNING, "TLS: Certificate verification failed," 1021189251Ssam " error %d (%s) depth %d for '%s'", err, 1022189251Ssam X509_verify_cert_error_string(err), depth, buf); 1023189251Ssam } else { 1024189251Ssam wpa_printf(MSG_DEBUG, "TLS: tls_verify_cb - " 1025189251Ssam "preverify_ok=%d err=%d (%s) depth=%d buf='%s'", 1026189251Ssam preverify_ok, err, 1027189251Ssam X509_verify_cert_error_string(err), depth, buf); 1028189251Ssam if (depth == 0 && match && os_strstr(buf, match) == NULL) { 1029189251Ssam wpa_printf(MSG_WARNING, "TLS: Subject '%s' did not " 1030189251Ssam "match with '%s'", buf, match); 1031189251Ssam preverify_ok = 0; 1032189251Ssam } else if (depth == 0 && altmatch && 1033189251Ssam !tls_match_altsubject(err_cert, altmatch)) { 1034189251Ssam wpa_printf(MSG_WARNING, "TLS: altSubjectName match " 1035189251Ssam "'%s' not found", altmatch); 1036189251Ssam preverify_ok = 0; 1037189251Ssam } 1038189251Ssam } 1039189251Ssam 1040189251Ssam return preverify_ok; 1041189251Ssam} 1042189251Ssam 1043189251Ssam 1044189251Ssam#ifndef OPENSSL_NO_STDIO 1045189251Ssamstatic int tls_load_ca_der(void *_ssl_ctx, const char *ca_cert) 1046189251Ssam{ 1047189251Ssam SSL_CTX *ssl_ctx = _ssl_ctx; 1048189251Ssam X509_LOOKUP *lookup; 1049189251Ssam int ret = 0; 1050189251Ssam 1051189251Ssam lookup = X509_STORE_add_lookup(ssl_ctx->cert_store, 1052189251Ssam X509_LOOKUP_file()); 1053189251Ssam if (lookup == NULL) { 1054189251Ssam tls_show_errors(MSG_WARNING, __func__, 1055189251Ssam "Failed add lookup for X509 store"); 1056189251Ssam return -1; 1057189251Ssam } 1058189251Ssam 1059189251Ssam if (!X509_LOOKUP_load_file(lookup, ca_cert, X509_FILETYPE_ASN1)) { 1060189251Ssam unsigned long err = ERR_peek_error(); 1061189251Ssam tls_show_errors(MSG_WARNING, __func__, 1062189251Ssam "Failed load CA in DER format"); 1063189251Ssam if (ERR_GET_LIB(err) == ERR_LIB_X509 && 1064189251Ssam ERR_GET_REASON(err) == X509_R_CERT_ALREADY_IN_HASH_TABLE) { 1065189251Ssam wpa_printf(MSG_DEBUG, "OpenSSL: %s - ignoring " 1066189251Ssam "cert already in hash table error", 1067189251Ssam __func__); 1068189251Ssam } else 1069189251Ssam ret = -1; 1070189251Ssam } 1071189251Ssam 1072189251Ssam return ret; 1073189251Ssam} 1074189251Ssam#endif /* OPENSSL_NO_STDIO */ 1075189251Ssam 1076189251Ssam 1077189251Ssamstatic int tls_connection_ca_cert(void *_ssl_ctx, struct tls_connection *conn, 1078189251Ssam const char *ca_cert, const u8 *ca_cert_blob, 1079189251Ssam size_t ca_cert_blob_len, const char *ca_path) 1080189251Ssam{ 1081189251Ssam SSL_CTX *ssl_ctx = _ssl_ctx; 1082189251Ssam 1083189251Ssam /* 1084189251Ssam * Remove previously configured trusted CA certificates before adding 1085189251Ssam * new ones. 1086189251Ssam */ 1087189251Ssam X509_STORE_free(ssl_ctx->cert_store); 1088189251Ssam ssl_ctx->cert_store = X509_STORE_new(); 1089189251Ssam if (ssl_ctx->cert_store == NULL) { 1090189251Ssam wpa_printf(MSG_DEBUG, "OpenSSL: %s - failed to allocate new " 1091189251Ssam "certificate store", __func__); 1092189251Ssam return -1; 1093189251Ssam } 1094189251Ssam 1095189251Ssam if (ca_cert_blob) { 1096189251Ssam X509 *cert = d2i_X509(NULL, (OPENSSL_d2i_TYPE) &ca_cert_blob, 1097189251Ssam ca_cert_blob_len); 1098189251Ssam if (cert == NULL) { 1099189251Ssam tls_show_errors(MSG_WARNING, __func__, 1100189251Ssam "Failed to parse ca_cert_blob"); 1101189251Ssam return -1; 1102189251Ssam } 1103189251Ssam 1104189251Ssam if (!X509_STORE_add_cert(ssl_ctx->cert_store, cert)) { 1105189251Ssam unsigned long err = ERR_peek_error(); 1106189251Ssam tls_show_errors(MSG_WARNING, __func__, 1107189251Ssam "Failed to add ca_cert_blob to " 1108189251Ssam "certificate store"); 1109189251Ssam if (ERR_GET_LIB(err) == ERR_LIB_X509 && 1110189251Ssam ERR_GET_REASON(err) == 1111189251Ssam X509_R_CERT_ALREADY_IN_HASH_TABLE) { 1112189251Ssam wpa_printf(MSG_DEBUG, "OpenSSL: %s - ignoring " 1113189251Ssam "cert already in hash table error", 1114189251Ssam __func__); 1115189251Ssam } else { 1116189251Ssam X509_free(cert); 1117189251Ssam return -1; 1118189251Ssam } 1119189251Ssam } 1120189251Ssam X509_free(cert); 1121189251Ssam wpa_printf(MSG_DEBUG, "OpenSSL: %s - added ca_cert_blob " 1122189251Ssam "to certificate store", __func__); 1123189251Ssam SSL_set_verify(conn->ssl, SSL_VERIFY_PEER, tls_verify_cb); 1124189251Ssam return 0; 1125189251Ssam } 1126189251Ssam 1127189251Ssam#ifdef CONFIG_NATIVE_WINDOWS 1128189251Ssam if (ca_cert && tls_cryptoapi_ca_cert(ssl_ctx, conn->ssl, ca_cert) == 1129189251Ssam 0) { 1130189251Ssam wpa_printf(MSG_DEBUG, "OpenSSL: Added CA certificates from " 1131189251Ssam "system certificate store"); 1132189251Ssam SSL_set_verify(conn->ssl, SSL_VERIFY_PEER, tls_verify_cb); 1133189251Ssam return 0; 1134189251Ssam } 1135189251Ssam#endif /* CONFIG_NATIVE_WINDOWS */ 1136189251Ssam 1137189251Ssam if (ca_cert || ca_path) { 1138189251Ssam#ifndef OPENSSL_NO_STDIO 1139189251Ssam if (SSL_CTX_load_verify_locations(ssl_ctx, ca_cert, ca_path) != 1140189251Ssam 1) { 1141189251Ssam tls_show_errors(MSG_WARNING, __func__, 1142189251Ssam "Failed to load root certificates"); 1143189251Ssam if (ca_cert && 1144189251Ssam tls_load_ca_der(ssl_ctx, ca_cert) == 0) { 1145189251Ssam wpa_printf(MSG_DEBUG, "OpenSSL: %s - loaded " 1146189251Ssam "DER format CA certificate", 1147189251Ssam __func__); 1148189251Ssam } else 1149189251Ssam return -1; 1150189251Ssam } else { 1151189251Ssam wpa_printf(MSG_DEBUG, "TLS: Trusted root " 1152189251Ssam "certificate(s) loaded"); 1153189251Ssam tls_get_errors(ssl_ctx); 1154189251Ssam } 1155189251Ssam SSL_set_verify(conn->ssl, SSL_VERIFY_PEER, tls_verify_cb); 1156189251Ssam#else /* OPENSSL_NO_STDIO */ 1157189251Ssam wpa_printf(MSG_DEBUG, "OpenSSL: %s - OPENSSL_NO_STDIO", 1158189251Ssam __func__); 1159189251Ssam return -1; 1160189251Ssam#endif /* OPENSSL_NO_STDIO */ 1161189251Ssam } else { 1162189251Ssam /* No ca_cert configured - do not try to verify server 1163189251Ssam * certificate */ 1164189251Ssam SSL_set_verify(conn->ssl, SSL_VERIFY_NONE, NULL); 1165189251Ssam } 1166189251Ssam 1167189251Ssam return 0; 1168189251Ssam} 1169189251Ssam 1170189251Ssam 1171189251Ssamstatic int tls_global_ca_cert(SSL_CTX *ssl_ctx, const char *ca_cert) 1172189251Ssam{ 1173189251Ssam if (ca_cert) { 1174189251Ssam if (SSL_CTX_load_verify_locations(ssl_ctx, ca_cert, NULL) != 1) 1175189251Ssam { 1176189251Ssam tls_show_errors(MSG_WARNING, __func__, 1177189251Ssam "Failed to load root certificates"); 1178189251Ssam return -1; 1179189251Ssam } 1180189251Ssam 1181189251Ssam wpa_printf(MSG_DEBUG, "TLS: Trusted root " 1182189251Ssam "certificate(s) loaded"); 1183189251Ssam 1184189251Ssam#ifndef OPENSSL_NO_STDIO 1185189251Ssam /* Add the same CAs to the client certificate requests */ 1186189251Ssam SSL_CTX_set_client_CA_list(ssl_ctx, 1187189251Ssam SSL_load_client_CA_file(ca_cert)); 1188189251Ssam#endif /* OPENSSL_NO_STDIO */ 1189189251Ssam } 1190189251Ssam 1191189251Ssam return 0; 1192189251Ssam} 1193189251Ssam 1194189251Ssam 1195189251Ssamint tls_global_set_verify(void *ssl_ctx, int check_crl) 1196189251Ssam{ 1197189251Ssam int flags; 1198189251Ssam 1199189251Ssam if (check_crl) { 1200189251Ssam X509_STORE *cs = SSL_CTX_get_cert_store(ssl_ctx); 1201189251Ssam if (cs == NULL) { 1202189251Ssam tls_show_errors(MSG_INFO, __func__, "Failed to get " 1203189251Ssam "certificate store when enabling " 1204189251Ssam "check_crl"); 1205189251Ssam return -1; 1206189251Ssam } 1207189251Ssam flags = X509_V_FLAG_CRL_CHECK; 1208189251Ssam if (check_crl == 2) 1209189251Ssam flags |= X509_V_FLAG_CRL_CHECK_ALL; 1210189251Ssam X509_STORE_set_flags(cs, flags); 1211189251Ssam } 1212189251Ssam return 0; 1213189251Ssam} 1214189251Ssam 1215189251Ssam 1216189251Ssamstatic int tls_connection_set_subject_match(struct tls_connection *conn, 1217189251Ssam const char *subject_match, 1218189251Ssam const char *altsubject_match) 1219189251Ssam{ 1220189251Ssam os_free(conn->subject_match); 1221189251Ssam conn->subject_match = NULL; 1222189251Ssam if (subject_match) { 1223189251Ssam conn->subject_match = os_strdup(subject_match); 1224189251Ssam if (conn->subject_match == NULL) 1225189251Ssam return -1; 1226189251Ssam } 1227189251Ssam 1228189251Ssam os_free(conn->altsubject_match); 1229189251Ssam conn->altsubject_match = NULL; 1230189251Ssam if (altsubject_match) { 1231189251Ssam conn->altsubject_match = os_strdup(altsubject_match); 1232189251Ssam if (conn->altsubject_match == NULL) 1233189251Ssam return -1; 1234189251Ssam } 1235189251Ssam 1236189251Ssam return 0; 1237189251Ssam} 1238189251Ssam 1239189251Ssam 1240189251Ssamint tls_connection_set_verify(void *ssl_ctx, struct tls_connection *conn, 1241189251Ssam int verify_peer) 1242189251Ssam{ 1243189251Ssam static int counter = 0; 1244189251Ssam 1245189251Ssam if (conn == NULL) 1246189251Ssam return -1; 1247189251Ssam 1248189251Ssam if (verify_peer) { 1249189251Ssam SSL_set_verify(conn->ssl, SSL_VERIFY_PEER | 1250189251Ssam SSL_VERIFY_FAIL_IF_NO_PEER_CERT | 1251189251Ssam SSL_VERIFY_CLIENT_ONCE, tls_verify_cb); 1252189251Ssam } else { 1253189251Ssam SSL_set_verify(conn->ssl, SSL_VERIFY_NONE, NULL); 1254189251Ssam } 1255189251Ssam 1256189251Ssam SSL_set_accept_state(conn->ssl); 1257189251Ssam 1258189251Ssam /* 1259189251Ssam * Set session id context in order to avoid fatal errors when client 1260189251Ssam * tries to resume a session. However, set the context to a unique 1261189251Ssam * value in order to effectively disable session resumption for now 1262189251Ssam * since not all areas of the server code are ready for it (e.g., 1263189251Ssam * EAP-TTLS needs special handling for Phase 2 after abbreviated TLS 1264189251Ssam * handshake). 1265189251Ssam */ 1266189251Ssam counter++; 1267189251Ssam SSL_set_session_id_context(conn->ssl, 1268189251Ssam (const unsigned char *) &counter, 1269189251Ssam sizeof(counter)); 1270189251Ssam 1271189251Ssam return 0; 1272189251Ssam} 1273189251Ssam 1274189251Ssam 1275189251Ssamstatic int tls_connection_client_cert(struct tls_connection *conn, 1276189251Ssam const char *client_cert, 1277189251Ssam const u8 *client_cert_blob, 1278189251Ssam size_t client_cert_blob_len) 1279189251Ssam{ 1280189251Ssam if (client_cert == NULL && client_cert_blob == NULL) 1281189251Ssam return 0; 1282189251Ssam 1283189251Ssam if (client_cert_blob && 1284189251Ssam SSL_use_certificate_ASN1(conn->ssl, (u8 *) client_cert_blob, 1285189251Ssam client_cert_blob_len) == 1) { 1286189251Ssam wpa_printf(MSG_DEBUG, "OpenSSL: SSL_use_certificate_ASN1 --> " 1287189251Ssam "OK"); 1288189251Ssam return 0; 1289189251Ssam } else if (client_cert_blob) { 1290189251Ssam tls_show_errors(MSG_DEBUG, __func__, 1291189251Ssam "SSL_use_certificate_ASN1 failed"); 1292189251Ssam } 1293189251Ssam 1294189251Ssam if (client_cert == NULL) 1295189251Ssam return -1; 1296189251Ssam 1297189251Ssam#ifndef OPENSSL_NO_STDIO 1298189251Ssam if (SSL_use_certificate_file(conn->ssl, client_cert, 1299189251Ssam SSL_FILETYPE_ASN1) == 1) { 1300189251Ssam wpa_printf(MSG_DEBUG, "OpenSSL: SSL_use_certificate_file (DER)" 1301189251Ssam " --> OK"); 1302189251Ssam return 0; 1303189251Ssam } else { 1304189251Ssam tls_show_errors(MSG_DEBUG, __func__, 1305189251Ssam "SSL_use_certificate_file (DER) failed"); 1306189251Ssam } 1307189251Ssam 1308189251Ssam if (SSL_use_certificate_file(conn->ssl, client_cert, 1309189251Ssam SSL_FILETYPE_PEM) == 1) { 1310189251Ssam wpa_printf(MSG_DEBUG, "OpenSSL: SSL_use_certificate_file (PEM)" 1311189251Ssam " --> OK"); 1312189251Ssam return 0; 1313189251Ssam } else { 1314189251Ssam tls_show_errors(MSG_DEBUG, __func__, 1315189251Ssam "SSL_use_certificate_file (PEM) failed"); 1316189251Ssam } 1317189251Ssam#else /* OPENSSL_NO_STDIO */ 1318189251Ssam wpa_printf(MSG_DEBUG, "OpenSSL: %s - OPENSSL_NO_STDIO", __func__); 1319189251Ssam#endif /* OPENSSL_NO_STDIO */ 1320189251Ssam 1321189251Ssam return -1; 1322189251Ssam} 1323189251Ssam 1324189251Ssam 1325189251Ssamstatic int tls_global_client_cert(SSL_CTX *ssl_ctx, const char *client_cert) 1326189251Ssam{ 1327189251Ssam#ifndef OPENSSL_NO_STDIO 1328189251Ssam if (client_cert == NULL) 1329189251Ssam return 0; 1330189251Ssam 1331189251Ssam if (SSL_CTX_use_certificate_file(ssl_ctx, client_cert, 1332189251Ssam SSL_FILETYPE_ASN1) != 1 && 1333189251Ssam SSL_CTX_use_certificate_file(ssl_ctx, client_cert, 1334189251Ssam SSL_FILETYPE_PEM) != 1) { 1335189251Ssam tls_show_errors(MSG_INFO, __func__, 1336189251Ssam "Failed to load client certificate"); 1337189251Ssam return -1; 1338189251Ssam } 1339189251Ssam return 0; 1340189251Ssam#else /* OPENSSL_NO_STDIO */ 1341189251Ssam if (client_cert == NULL) 1342189251Ssam return 0; 1343189251Ssam wpa_printf(MSG_DEBUG, "OpenSSL: %s - OPENSSL_NO_STDIO", __func__); 1344189251Ssam return -1; 1345189251Ssam#endif /* OPENSSL_NO_STDIO */ 1346189251Ssam} 1347189251Ssam 1348189251Ssam 1349189251Ssamstatic int tls_passwd_cb(char *buf, int size, int rwflag, void *password) 1350189251Ssam{ 1351189251Ssam if (password == NULL) { 1352189251Ssam return 0; 1353189251Ssam } 1354189251Ssam os_strlcpy(buf, (char *) password, size); 1355189251Ssam return os_strlen(buf); 1356189251Ssam} 1357189251Ssam 1358189251Ssam 1359189251Ssam#ifdef PKCS12_FUNCS 1360189251Ssamstatic int tls_parse_pkcs12(SSL_CTX *ssl_ctx, SSL *ssl, PKCS12 *p12, 1361189251Ssam const char *passwd) 1362189251Ssam{ 1363189251Ssam EVP_PKEY *pkey; 1364189251Ssam X509 *cert; 1365189251Ssam STACK_OF(X509) *certs; 1366189251Ssam int res = 0; 1367189251Ssam char buf[256]; 1368189251Ssam 1369189251Ssam pkey = NULL; 1370189251Ssam cert = NULL; 1371189251Ssam certs = NULL; 1372189251Ssam if (!PKCS12_parse(p12, passwd, &pkey, &cert, &certs)) { 1373189251Ssam tls_show_errors(MSG_DEBUG, __func__, 1374189251Ssam "Failed to parse PKCS12 file"); 1375189251Ssam PKCS12_free(p12); 1376189251Ssam return -1; 1377189251Ssam } 1378189251Ssam wpa_printf(MSG_DEBUG, "TLS: Successfully parsed PKCS12 data"); 1379189251Ssam 1380189251Ssam if (cert) { 1381189251Ssam X509_NAME_oneline(X509_get_subject_name(cert), buf, 1382189251Ssam sizeof(buf)); 1383189251Ssam wpa_printf(MSG_DEBUG, "TLS: Got certificate from PKCS12: " 1384189251Ssam "subject='%s'", buf); 1385189251Ssam if (ssl) { 1386189251Ssam if (SSL_use_certificate(ssl, cert) != 1) 1387189251Ssam res = -1; 1388189251Ssam } else { 1389189251Ssam if (SSL_CTX_use_certificate(ssl_ctx, cert) != 1) 1390189251Ssam res = -1; 1391189251Ssam } 1392189251Ssam X509_free(cert); 1393189251Ssam } 1394189251Ssam 1395189251Ssam if (pkey) { 1396189251Ssam wpa_printf(MSG_DEBUG, "TLS: Got private key from PKCS12"); 1397189251Ssam if (ssl) { 1398189251Ssam if (SSL_use_PrivateKey(ssl, pkey) != 1) 1399189251Ssam res = -1; 1400189251Ssam } else { 1401189251Ssam if (SSL_CTX_use_PrivateKey(ssl_ctx, pkey) != 1) 1402189251Ssam res = -1; 1403189251Ssam } 1404189251Ssam EVP_PKEY_free(pkey); 1405189251Ssam } 1406189251Ssam 1407189251Ssam if (certs) { 1408189251Ssam while ((cert = sk_X509_pop(certs)) != NULL) { 1409189251Ssam X509_NAME_oneline(X509_get_subject_name(cert), buf, 1410189251Ssam sizeof(buf)); 1411189251Ssam wpa_printf(MSG_DEBUG, "TLS: additional certificate" 1412189251Ssam " from PKCS12: subject='%s'", buf); 1413189251Ssam /* 1414189251Ssam * There is no SSL equivalent for the chain cert - so 1415189251Ssam * always add it to the context... 1416189251Ssam */ 1417189251Ssam if (SSL_CTX_add_extra_chain_cert(ssl_ctx, cert) != 1) { 1418189251Ssam res = -1; 1419189251Ssam break; 1420189251Ssam } 1421189251Ssam } 1422189251Ssam sk_X509_free(certs); 1423189251Ssam } 1424189251Ssam 1425189251Ssam PKCS12_free(p12); 1426189251Ssam 1427189251Ssam if (res < 0) 1428189251Ssam tls_get_errors(ssl_ctx); 1429189251Ssam 1430189251Ssam return res; 1431189251Ssam} 1432189251Ssam#endif /* PKCS12_FUNCS */ 1433189251Ssam 1434189251Ssam 1435189251Ssamstatic int tls_read_pkcs12(SSL_CTX *ssl_ctx, SSL *ssl, const char *private_key, 1436189251Ssam const char *passwd) 1437189251Ssam{ 1438189251Ssam#ifdef PKCS12_FUNCS 1439189251Ssam FILE *f; 1440189251Ssam PKCS12 *p12; 1441189251Ssam 1442189251Ssam f = fopen(private_key, "rb"); 1443189251Ssam if (f == NULL) 1444189251Ssam return -1; 1445189251Ssam 1446189251Ssam p12 = d2i_PKCS12_fp(f, NULL); 1447189251Ssam fclose(f); 1448189251Ssam 1449189251Ssam if (p12 == NULL) { 1450189251Ssam tls_show_errors(MSG_INFO, __func__, 1451189251Ssam "Failed to use PKCS#12 file"); 1452189251Ssam return -1; 1453189251Ssam } 1454189251Ssam 1455189251Ssam return tls_parse_pkcs12(ssl_ctx, ssl, p12, passwd); 1456189251Ssam 1457189251Ssam#else /* PKCS12_FUNCS */ 1458189251Ssam wpa_printf(MSG_INFO, "TLS: PKCS12 support disabled - cannot read " 1459189251Ssam "p12/pfx files"); 1460189251Ssam return -1; 1461189251Ssam#endif /* PKCS12_FUNCS */ 1462189251Ssam} 1463189251Ssam 1464189251Ssam 1465189251Ssamstatic int tls_read_pkcs12_blob(SSL_CTX *ssl_ctx, SSL *ssl, 1466189251Ssam const u8 *blob, size_t len, const char *passwd) 1467189251Ssam{ 1468189251Ssam#ifdef PKCS12_FUNCS 1469189251Ssam PKCS12 *p12; 1470189251Ssam 1471189251Ssam p12 = d2i_PKCS12(NULL, (OPENSSL_d2i_TYPE) &blob, len); 1472189251Ssam if (p12 == NULL) { 1473189251Ssam tls_show_errors(MSG_INFO, __func__, 1474189251Ssam "Failed to use PKCS#12 blob"); 1475189251Ssam return -1; 1476189251Ssam } 1477189251Ssam 1478189251Ssam return tls_parse_pkcs12(ssl_ctx, ssl, p12, passwd); 1479189251Ssam 1480189251Ssam#else /* PKCS12_FUNCS */ 1481189251Ssam wpa_printf(MSG_INFO, "TLS: PKCS12 support disabled - cannot parse " 1482189251Ssam "p12/pfx blobs"); 1483189251Ssam return -1; 1484189251Ssam#endif /* PKCS12_FUNCS */ 1485189251Ssam} 1486189251Ssam 1487189251Ssam 1488189251Ssam#ifndef OPENSSL_NO_ENGINE 1489189251Ssamstatic int tls_engine_get_cert(struct tls_connection *conn, 1490189251Ssam const char *cert_id, 1491189251Ssam X509 **cert) 1492189251Ssam{ 1493189251Ssam /* this runs after the private key is loaded so no PIN is required */ 1494189251Ssam struct { 1495189251Ssam const char *cert_id; 1496189251Ssam X509 *cert; 1497189251Ssam } params; 1498189251Ssam params.cert_id = cert_id; 1499189251Ssam params.cert = NULL; 1500189251Ssam 1501189251Ssam if (!ENGINE_ctrl_cmd(conn->engine, "LOAD_CERT_CTRL", 1502189251Ssam 0, ¶ms, NULL, 1)) { 1503189251Ssam wpa_printf(MSG_ERROR, "ENGINE: cannot load client cert with id" 1504189251Ssam " '%s' [%s]", cert_id, 1505189251Ssam ERR_error_string(ERR_get_error(), NULL)); 1506189251Ssam return TLS_SET_PARAMS_ENGINE_PRV_INIT_FAILED; 1507189251Ssam } 1508189251Ssam if (!params.cert) { 1509189251Ssam wpa_printf(MSG_ERROR, "ENGINE: did not properly cert with id" 1510189251Ssam " '%s'", cert_id); 1511189251Ssam return TLS_SET_PARAMS_ENGINE_PRV_INIT_FAILED; 1512189251Ssam } 1513189251Ssam *cert = params.cert; 1514189251Ssam return 0; 1515189251Ssam} 1516189251Ssam#endif /* OPENSSL_NO_ENGINE */ 1517189251Ssam 1518189251Ssam 1519189251Ssamstatic int tls_connection_engine_client_cert(struct tls_connection *conn, 1520189251Ssam const char *cert_id) 1521189251Ssam{ 1522189251Ssam#ifndef OPENSSL_NO_ENGINE 1523189251Ssam X509 *cert; 1524189251Ssam 1525189251Ssam if (tls_engine_get_cert(conn, cert_id, &cert)) 1526189251Ssam return -1; 1527189251Ssam 1528189251Ssam if (!SSL_use_certificate(conn->ssl, cert)) { 1529189251Ssam tls_show_errors(MSG_ERROR, __func__, 1530189251Ssam "SSL_use_certificate failed"); 1531189251Ssam X509_free(cert); 1532189251Ssam return -1; 1533189251Ssam } 1534189251Ssam X509_free(cert); 1535189251Ssam wpa_printf(MSG_DEBUG, "ENGINE: SSL_use_certificate --> " 1536189251Ssam "OK"); 1537189251Ssam return 0; 1538189251Ssam 1539189251Ssam#else /* OPENSSL_NO_ENGINE */ 1540189251Ssam return -1; 1541189251Ssam#endif /* OPENSSL_NO_ENGINE */ 1542189251Ssam} 1543189251Ssam 1544189251Ssam 1545189251Ssamstatic int tls_connection_engine_ca_cert(void *_ssl_ctx, 1546189251Ssam struct tls_connection *conn, 1547189251Ssam const char *ca_cert_id) 1548189251Ssam{ 1549189251Ssam#ifndef OPENSSL_NO_ENGINE 1550189251Ssam X509 *cert; 1551189251Ssam SSL_CTX *ssl_ctx = _ssl_ctx; 1552189251Ssam 1553189251Ssam if (tls_engine_get_cert(conn, ca_cert_id, &cert)) 1554189251Ssam return -1; 1555189251Ssam 1556189251Ssam /* start off the same as tls_connection_ca_cert */ 1557189251Ssam X509_STORE_free(ssl_ctx->cert_store); 1558189251Ssam ssl_ctx->cert_store = X509_STORE_new(); 1559189251Ssam if (ssl_ctx->cert_store == NULL) { 1560189251Ssam wpa_printf(MSG_DEBUG, "OpenSSL: %s - failed to allocate new " 1561189251Ssam "certificate store", __func__); 1562189251Ssam X509_free(cert); 1563189251Ssam return -1; 1564189251Ssam } 1565189251Ssam if (!X509_STORE_add_cert(ssl_ctx->cert_store, cert)) { 1566189251Ssam unsigned long err = ERR_peek_error(); 1567189251Ssam tls_show_errors(MSG_WARNING, __func__, 1568189251Ssam "Failed to add CA certificate from engine " 1569189251Ssam "to certificate store"); 1570189251Ssam if (ERR_GET_LIB(err) == ERR_LIB_X509 && 1571189251Ssam ERR_GET_REASON(err) == X509_R_CERT_ALREADY_IN_HASH_TABLE) { 1572189251Ssam wpa_printf(MSG_DEBUG, "OpenSSL: %s - ignoring cert" 1573189251Ssam " already in hash table error", 1574189251Ssam __func__); 1575189251Ssam } else { 1576189251Ssam X509_free(cert); 1577189251Ssam return -1; 1578189251Ssam } 1579189251Ssam } 1580189251Ssam X509_free(cert); 1581189251Ssam wpa_printf(MSG_DEBUG, "OpenSSL: %s - added CA certificate from engine " 1582189251Ssam "to certificate store", __func__); 1583189251Ssam SSL_set_verify(conn->ssl, SSL_VERIFY_PEER, tls_verify_cb); 1584189251Ssam return 0; 1585189251Ssam 1586189251Ssam#else /* OPENSSL_NO_ENGINE */ 1587189251Ssam return -1; 1588189251Ssam#endif /* OPENSSL_NO_ENGINE */ 1589189251Ssam} 1590189251Ssam 1591189251Ssam 1592189251Ssamstatic int tls_connection_engine_private_key(struct tls_connection *conn) 1593189251Ssam{ 1594189251Ssam#ifndef OPENSSL_NO_ENGINE 1595189251Ssam if (SSL_use_PrivateKey(conn->ssl, conn->private_key) != 1) { 1596189251Ssam tls_show_errors(MSG_ERROR, __func__, 1597189251Ssam "ENGINE: cannot use private key for TLS"); 1598189251Ssam return -1; 1599189251Ssam } 1600189251Ssam if (!SSL_check_private_key(conn->ssl)) { 1601189251Ssam tls_show_errors(MSG_INFO, __func__, 1602189251Ssam "Private key failed verification"); 1603189251Ssam return -1; 1604189251Ssam } 1605189251Ssam return 0; 1606189251Ssam#else /* OPENSSL_NO_ENGINE */ 1607189251Ssam wpa_printf(MSG_ERROR, "SSL: Configuration uses engine, but " 1608189251Ssam "engine support was not compiled in"); 1609189251Ssam return -1; 1610189251Ssam#endif /* OPENSSL_NO_ENGINE */ 1611189251Ssam} 1612189251Ssam 1613189251Ssam 1614189251Ssamstatic int tls_connection_private_key(void *_ssl_ctx, 1615189251Ssam struct tls_connection *conn, 1616189251Ssam const char *private_key, 1617189251Ssam const char *private_key_passwd, 1618189251Ssam const u8 *private_key_blob, 1619189251Ssam size_t private_key_blob_len) 1620189251Ssam{ 1621189251Ssam SSL_CTX *ssl_ctx = _ssl_ctx; 1622189251Ssam char *passwd; 1623189251Ssam int ok; 1624189251Ssam 1625189251Ssam if (private_key == NULL && private_key_blob == NULL) 1626189251Ssam return 0; 1627189251Ssam 1628189251Ssam if (private_key_passwd) { 1629189251Ssam passwd = os_strdup(private_key_passwd); 1630189251Ssam if (passwd == NULL) 1631189251Ssam return -1; 1632189251Ssam } else 1633189251Ssam passwd = NULL; 1634189251Ssam 1635189251Ssam SSL_CTX_set_default_passwd_cb(ssl_ctx, tls_passwd_cb); 1636189251Ssam SSL_CTX_set_default_passwd_cb_userdata(ssl_ctx, passwd); 1637189251Ssam 1638189251Ssam ok = 0; 1639189251Ssam while (private_key_blob) { 1640189251Ssam if (SSL_use_PrivateKey_ASN1(EVP_PKEY_RSA, conn->ssl, 1641189251Ssam (u8 *) private_key_blob, 1642189251Ssam private_key_blob_len) == 1) { 1643189251Ssam wpa_printf(MSG_DEBUG, "OpenSSL: SSL_use_PrivateKey_" 1644189251Ssam "ASN1(EVP_PKEY_RSA) --> OK"); 1645189251Ssam ok = 1; 1646189251Ssam break; 1647189251Ssam } else { 1648189251Ssam tls_show_errors(MSG_DEBUG, __func__, 1649189251Ssam "SSL_use_PrivateKey_ASN1(EVP_PKEY_RSA)" 1650189251Ssam " failed"); 1651189251Ssam } 1652189251Ssam 1653189251Ssam if (SSL_use_PrivateKey_ASN1(EVP_PKEY_DSA, conn->ssl, 1654189251Ssam (u8 *) private_key_blob, 1655189251Ssam private_key_blob_len) == 1) { 1656189251Ssam wpa_printf(MSG_DEBUG, "OpenSSL: SSL_use_PrivateKey_" 1657189251Ssam "ASN1(EVP_PKEY_DSA) --> OK"); 1658189251Ssam ok = 1; 1659189251Ssam break; 1660189251Ssam } else { 1661189251Ssam tls_show_errors(MSG_DEBUG, __func__, 1662189251Ssam "SSL_use_PrivateKey_ASN1(EVP_PKEY_DSA)" 1663189251Ssam " failed"); 1664189251Ssam } 1665189251Ssam 1666189251Ssam if (SSL_use_RSAPrivateKey_ASN1(conn->ssl, 1667189251Ssam (u8 *) private_key_blob, 1668189251Ssam private_key_blob_len) == 1) { 1669189251Ssam wpa_printf(MSG_DEBUG, "OpenSSL: " 1670189251Ssam "SSL_use_RSAPrivateKey_ASN1 --> OK"); 1671189251Ssam ok = 1; 1672189251Ssam break; 1673189251Ssam } else { 1674189251Ssam tls_show_errors(MSG_DEBUG, __func__, 1675189251Ssam "SSL_use_RSAPrivateKey_ASN1 failed"); 1676189251Ssam } 1677189251Ssam 1678189251Ssam if (tls_read_pkcs12_blob(ssl_ctx, conn->ssl, private_key_blob, 1679189251Ssam private_key_blob_len, passwd) == 0) { 1680189251Ssam wpa_printf(MSG_DEBUG, "OpenSSL: PKCS#12 as blob --> " 1681189251Ssam "OK"); 1682189251Ssam ok = 1; 1683189251Ssam break; 1684189251Ssam } 1685189251Ssam 1686189251Ssam break; 1687189251Ssam } 1688189251Ssam 1689189251Ssam while (!ok && private_key) { 1690189251Ssam#ifndef OPENSSL_NO_STDIO 1691189251Ssam if (SSL_use_PrivateKey_file(conn->ssl, private_key, 1692189251Ssam SSL_FILETYPE_ASN1) == 1) { 1693189251Ssam wpa_printf(MSG_DEBUG, "OpenSSL: " 1694189251Ssam "SSL_use_PrivateKey_File (DER) --> OK"); 1695189251Ssam ok = 1; 1696189251Ssam break; 1697189251Ssam } else { 1698189251Ssam tls_show_errors(MSG_DEBUG, __func__, 1699189251Ssam "SSL_use_PrivateKey_File (DER) " 1700189251Ssam "failed"); 1701189251Ssam } 1702189251Ssam 1703189251Ssam if (SSL_use_PrivateKey_file(conn->ssl, private_key, 1704189251Ssam SSL_FILETYPE_PEM) == 1) { 1705189251Ssam wpa_printf(MSG_DEBUG, "OpenSSL: " 1706189251Ssam "SSL_use_PrivateKey_File (PEM) --> OK"); 1707189251Ssam ok = 1; 1708189251Ssam break; 1709189251Ssam } else { 1710189251Ssam tls_show_errors(MSG_DEBUG, __func__, 1711189251Ssam "SSL_use_PrivateKey_File (PEM) " 1712189251Ssam "failed"); 1713189251Ssam } 1714189251Ssam#else /* OPENSSL_NO_STDIO */ 1715189251Ssam wpa_printf(MSG_DEBUG, "OpenSSL: %s - OPENSSL_NO_STDIO", 1716189251Ssam __func__); 1717189251Ssam#endif /* OPENSSL_NO_STDIO */ 1718189251Ssam 1719189251Ssam if (tls_read_pkcs12(ssl_ctx, conn->ssl, private_key, passwd) 1720189251Ssam == 0) { 1721189251Ssam wpa_printf(MSG_DEBUG, "OpenSSL: Reading PKCS#12 file " 1722189251Ssam "--> OK"); 1723189251Ssam ok = 1; 1724189251Ssam break; 1725189251Ssam } 1726189251Ssam 1727189251Ssam if (tls_cryptoapi_cert(conn->ssl, private_key) == 0) { 1728189251Ssam wpa_printf(MSG_DEBUG, "OpenSSL: Using CryptoAPI to " 1729189251Ssam "access certificate store --> OK"); 1730189251Ssam ok = 1; 1731189251Ssam break; 1732189251Ssam } 1733189251Ssam 1734189251Ssam break; 1735189251Ssam } 1736189251Ssam 1737189251Ssam if (!ok) { 1738189251Ssam wpa_printf(MSG_INFO, "OpenSSL: Failed to load private key"); 1739189251Ssam os_free(passwd); 1740189251Ssam ERR_clear_error(); 1741189251Ssam return -1; 1742189251Ssam } 1743189251Ssam ERR_clear_error(); 1744189251Ssam SSL_CTX_set_default_passwd_cb(ssl_ctx, NULL); 1745189251Ssam os_free(passwd); 1746189251Ssam 1747189251Ssam if (!SSL_check_private_key(conn->ssl)) { 1748189251Ssam tls_show_errors(MSG_INFO, __func__, "Private key failed " 1749189251Ssam "verification"); 1750189251Ssam return -1; 1751189251Ssam } 1752189251Ssam 1753189251Ssam wpa_printf(MSG_DEBUG, "SSL: Private key loaded successfully"); 1754189251Ssam return 0; 1755189251Ssam} 1756189251Ssam 1757189251Ssam 1758189251Ssamstatic int tls_global_private_key(SSL_CTX *ssl_ctx, const char *private_key, 1759189251Ssam const char *private_key_passwd) 1760189251Ssam{ 1761189251Ssam char *passwd; 1762189251Ssam 1763189251Ssam if (private_key == NULL) 1764189251Ssam return 0; 1765189251Ssam 1766189251Ssam if (private_key_passwd) { 1767189251Ssam passwd = os_strdup(private_key_passwd); 1768189251Ssam if (passwd == NULL) 1769189251Ssam return -1; 1770189251Ssam } else 1771189251Ssam passwd = NULL; 1772189251Ssam 1773189251Ssam SSL_CTX_set_default_passwd_cb(ssl_ctx, tls_passwd_cb); 1774189251Ssam SSL_CTX_set_default_passwd_cb_userdata(ssl_ctx, passwd); 1775189251Ssam if ( 1776189251Ssam#ifndef OPENSSL_NO_STDIO 1777189251Ssam SSL_CTX_use_PrivateKey_file(ssl_ctx, private_key, 1778189251Ssam SSL_FILETYPE_ASN1) != 1 && 1779189251Ssam SSL_CTX_use_PrivateKey_file(ssl_ctx, private_key, 1780189251Ssam SSL_FILETYPE_PEM) != 1 && 1781189251Ssam#endif /* OPENSSL_NO_STDIO */ 1782189251Ssam tls_read_pkcs12(ssl_ctx, NULL, private_key, passwd)) { 1783189251Ssam tls_show_errors(MSG_INFO, __func__, 1784189251Ssam "Failed to load private key"); 1785189251Ssam os_free(passwd); 1786189251Ssam ERR_clear_error(); 1787189251Ssam return -1; 1788189251Ssam } 1789189251Ssam os_free(passwd); 1790189251Ssam ERR_clear_error(); 1791189251Ssam SSL_CTX_set_default_passwd_cb(ssl_ctx, NULL); 1792189251Ssam 1793189251Ssam if (!SSL_CTX_check_private_key(ssl_ctx)) { 1794189251Ssam tls_show_errors(MSG_INFO, __func__, 1795189251Ssam "Private key failed verification"); 1796189251Ssam return -1; 1797189251Ssam } 1798189251Ssam 1799189251Ssam return 0; 1800189251Ssam} 1801189251Ssam 1802189251Ssam 1803189251Ssamstatic int tls_connection_dh(struct tls_connection *conn, const char *dh_file) 1804189251Ssam{ 1805189251Ssam#ifdef OPENSSL_NO_DH 1806189251Ssam if (dh_file == NULL) 1807189251Ssam return 0; 1808189251Ssam wpa_printf(MSG_ERROR, "TLS: openssl does not include DH support, but " 1809189251Ssam "dh_file specified"); 1810189251Ssam return -1; 1811189251Ssam#else /* OPENSSL_NO_DH */ 1812189251Ssam DH *dh; 1813189251Ssam BIO *bio; 1814189251Ssam 1815189251Ssam /* TODO: add support for dh_blob */ 1816189251Ssam if (dh_file == NULL) 1817189251Ssam return 0; 1818189251Ssam if (conn == NULL) 1819189251Ssam return -1; 1820189251Ssam 1821189251Ssam bio = BIO_new_file(dh_file, "r"); 1822189251Ssam if (bio == NULL) { 1823189251Ssam wpa_printf(MSG_INFO, "TLS: Failed to open DH file '%s': %s", 1824189251Ssam dh_file, ERR_error_string(ERR_get_error(), NULL)); 1825189251Ssam return -1; 1826189251Ssam } 1827189251Ssam dh = PEM_read_bio_DHparams(bio, NULL, NULL, NULL); 1828189251Ssam BIO_free(bio); 1829189251Ssam#ifndef OPENSSL_NO_DSA 1830189251Ssam while (dh == NULL) { 1831189251Ssam DSA *dsa; 1832189251Ssam wpa_printf(MSG_DEBUG, "TLS: Failed to parse DH file '%s': %s -" 1833189251Ssam " trying to parse as DSA params", dh_file, 1834189251Ssam ERR_error_string(ERR_get_error(), NULL)); 1835189251Ssam bio = BIO_new_file(dh_file, "r"); 1836189251Ssam if (bio == NULL) 1837189251Ssam break; 1838189251Ssam dsa = PEM_read_bio_DSAparams(bio, NULL, NULL, NULL); 1839189251Ssam BIO_free(bio); 1840189251Ssam if (!dsa) { 1841189251Ssam wpa_printf(MSG_DEBUG, "TLS: Failed to parse DSA file " 1842189251Ssam "'%s': %s", dh_file, 1843189251Ssam ERR_error_string(ERR_get_error(), NULL)); 1844189251Ssam break; 1845189251Ssam } 1846189251Ssam 1847189251Ssam wpa_printf(MSG_DEBUG, "TLS: DH file in DSA param format"); 1848189251Ssam dh = DSA_dup_DH(dsa); 1849189251Ssam DSA_free(dsa); 1850189251Ssam if (dh == NULL) { 1851189251Ssam wpa_printf(MSG_INFO, "TLS: Failed to convert DSA " 1852189251Ssam "params into DH params"); 1853189251Ssam break; 1854189251Ssam } 1855189251Ssam break; 1856189251Ssam } 1857189251Ssam#endif /* !OPENSSL_NO_DSA */ 1858189251Ssam if (dh == NULL) { 1859189251Ssam wpa_printf(MSG_INFO, "TLS: Failed to read/parse DH/DSA file " 1860189251Ssam "'%s'", dh_file); 1861189251Ssam return -1; 1862189251Ssam } 1863189251Ssam 1864189251Ssam if (SSL_set_tmp_dh(conn->ssl, dh) != 1) { 1865189251Ssam wpa_printf(MSG_INFO, "TLS: Failed to set DH params from '%s': " 1866189251Ssam "%s", dh_file, 1867189251Ssam ERR_error_string(ERR_get_error(), NULL)); 1868189251Ssam DH_free(dh); 1869189251Ssam return -1; 1870189251Ssam } 1871189251Ssam DH_free(dh); 1872189251Ssam return 0; 1873189251Ssam#endif /* OPENSSL_NO_DH */ 1874189251Ssam} 1875189251Ssam 1876189251Ssam 1877189251Ssamstatic int tls_global_dh(SSL_CTX *ssl_ctx, const char *dh_file) 1878189251Ssam{ 1879189251Ssam#ifdef OPENSSL_NO_DH 1880189251Ssam if (dh_file == NULL) 1881189251Ssam return 0; 1882189251Ssam wpa_printf(MSG_ERROR, "TLS: openssl does not include DH support, but " 1883189251Ssam "dh_file specified"); 1884189251Ssam return -1; 1885189251Ssam#else /* OPENSSL_NO_DH */ 1886189251Ssam DH *dh; 1887189251Ssam BIO *bio; 1888189251Ssam 1889189251Ssam /* TODO: add support for dh_blob */ 1890189251Ssam if (dh_file == NULL) 1891189251Ssam return 0; 1892189251Ssam if (ssl_ctx == NULL) 1893189251Ssam return -1; 1894189251Ssam 1895189251Ssam bio = BIO_new_file(dh_file, "r"); 1896189251Ssam if (bio == NULL) { 1897189251Ssam wpa_printf(MSG_INFO, "TLS: Failed to open DH file '%s': %s", 1898189251Ssam dh_file, ERR_error_string(ERR_get_error(), NULL)); 1899189251Ssam return -1; 1900189251Ssam } 1901189251Ssam dh = PEM_read_bio_DHparams(bio, NULL, NULL, NULL); 1902189251Ssam BIO_free(bio); 1903189251Ssam#ifndef OPENSSL_NO_DSA 1904189251Ssam while (dh == NULL) { 1905189251Ssam DSA *dsa; 1906189251Ssam wpa_printf(MSG_DEBUG, "TLS: Failed to parse DH file '%s': %s -" 1907189251Ssam " trying to parse as DSA params", dh_file, 1908189251Ssam ERR_error_string(ERR_get_error(), NULL)); 1909189251Ssam bio = BIO_new_file(dh_file, "r"); 1910189251Ssam if (bio == NULL) 1911189251Ssam break; 1912189251Ssam dsa = PEM_read_bio_DSAparams(bio, NULL, NULL, NULL); 1913189251Ssam BIO_free(bio); 1914189251Ssam if (!dsa) { 1915189251Ssam wpa_printf(MSG_DEBUG, "TLS: Failed to parse DSA file " 1916189251Ssam "'%s': %s", dh_file, 1917189251Ssam ERR_error_string(ERR_get_error(), NULL)); 1918189251Ssam break; 1919189251Ssam } 1920189251Ssam 1921189251Ssam wpa_printf(MSG_DEBUG, "TLS: DH file in DSA param format"); 1922189251Ssam dh = DSA_dup_DH(dsa); 1923189251Ssam DSA_free(dsa); 1924189251Ssam if (dh == NULL) { 1925189251Ssam wpa_printf(MSG_INFO, "TLS: Failed to convert DSA " 1926189251Ssam "params into DH params"); 1927189251Ssam break; 1928189251Ssam } 1929189251Ssam break; 1930189251Ssam } 1931189251Ssam#endif /* !OPENSSL_NO_DSA */ 1932189251Ssam if (dh == NULL) { 1933189251Ssam wpa_printf(MSG_INFO, "TLS: Failed to read/parse DH/DSA file " 1934189251Ssam "'%s'", dh_file); 1935189251Ssam return -1; 1936189251Ssam } 1937189251Ssam 1938189251Ssam if (SSL_CTX_set_tmp_dh(ssl_ctx, dh) != 1) { 1939189251Ssam wpa_printf(MSG_INFO, "TLS: Failed to set DH params from '%s': " 1940189251Ssam "%s", dh_file, 1941189251Ssam ERR_error_string(ERR_get_error(), NULL)); 1942189251Ssam DH_free(dh); 1943189251Ssam return -1; 1944189251Ssam } 1945189251Ssam DH_free(dh); 1946189251Ssam return 0; 1947189251Ssam#endif /* OPENSSL_NO_DH */ 1948189251Ssam} 1949189251Ssam 1950189251Ssam 1951189251Ssamint tls_connection_get_keys(void *ssl_ctx, struct tls_connection *conn, 1952189251Ssam struct tls_keys *keys) 1953189251Ssam{ 1954189251Ssam SSL *ssl; 1955189251Ssam 1956189251Ssam if (conn == NULL || keys == NULL) 1957189251Ssam return -1; 1958189251Ssam ssl = conn->ssl; 1959189251Ssam if (ssl == NULL || ssl->s3 == NULL || ssl->session == NULL) 1960189251Ssam return -1; 1961189251Ssam 1962189251Ssam os_memset(keys, 0, sizeof(*keys)); 1963189251Ssam keys->master_key = ssl->session->master_key; 1964189251Ssam keys->master_key_len = ssl->session->master_key_length; 1965189251Ssam keys->client_random = ssl->s3->client_random; 1966189251Ssam keys->client_random_len = SSL3_RANDOM_SIZE; 1967189251Ssam keys->server_random = ssl->s3->server_random; 1968189251Ssam keys->server_random_len = SSL3_RANDOM_SIZE; 1969189251Ssam 1970189251Ssam return 0; 1971189251Ssam} 1972189251Ssam 1973189251Ssam 1974189251Ssamint tls_connection_prf(void *tls_ctx, struct tls_connection *conn, 1975189251Ssam const char *label, int server_random_first, 1976189251Ssam u8 *out, size_t out_len) 1977189251Ssam{ 1978189251Ssam return -1; 1979189251Ssam} 1980189251Ssam 1981189251Ssam 1982189251Ssamu8 * tls_connection_handshake(void *ssl_ctx, struct tls_connection *conn, 1983189251Ssam const u8 *in_data, size_t in_len, 1984189251Ssam size_t *out_len, u8 **appl_data, 1985189251Ssam size_t *appl_data_len) 1986189251Ssam{ 1987189251Ssam int res; 1988189251Ssam u8 *out_data; 1989189251Ssam 1990189251Ssam if (appl_data) 1991189251Ssam *appl_data = NULL; 1992189251Ssam 1993189251Ssam /* 1994189251Ssam * Give TLS handshake data from the server (if available) to OpenSSL 1995189251Ssam * for processing. 1996189251Ssam */ 1997189251Ssam if (in_data && 1998189251Ssam BIO_write(conn->ssl_in, in_data, in_len) < 0) { 1999189251Ssam tls_show_errors(MSG_INFO, __func__, 2000189251Ssam "Handshake failed - BIO_write"); 2001189251Ssam return NULL; 2002189251Ssam } 2003189251Ssam 2004189251Ssam /* Initiate TLS handshake or continue the existing handshake */ 2005189251Ssam res = SSL_connect(conn->ssl); 2006189251Ssam if (res != 1) { 2007189251Ssam int err = SSL_get_error(conn->ssl, res); 2008189251Ssam if (err == SSL_ERROR_WANT_READ) 2009189251Ssam wpa_printf(MSG_DEBUG, "SSL: SSL_connect - want " 2010189251Ssam "more data"); 2011189251Ssam else if (err == SSL_ERROR_WANT_WRITE) 2012189251Ssam wpa_printf(MSG_DEBUG, "SSL: SSL_connect - want to " 2013189251Ssam "write"); 2014189251Ssam else { 2015189251Ssam tls_show_errors(MSG_INFO, __func__, "SSL_connect"); 2016189251Ssam conn->failed++; 2017189251Ssam } 2018189251Ssam } 2019189251Ssam 2020189251Ssam /* Get the TLS handshake data to be sent to the server */ 2021189251Ssam res = BIO_ctrl_pending(conn->ssl_out); 2022189251Ssam wpa_printf(MSG_DEBUG, "SSL: %d bytes pending from ssl_out", res); 2023189251Ssam out_data = os_malloc(res == 0 ? 1 : res); 2024189251Ssam if (out_data == NULL) { 2025189251Ssam wpa_printf(MSG_DEBUG, "SSL: Failed to allocate memory for " 2026189251Ssam "handshake output (%d bytes)", res); 2027189251Ssam if (BIO_reset(conn->ssl_out) < 0) { 2028189251Ssam tls_show_errors(MSG_INFO, __func__, 2029189251Ssam "BIO_reset failed"); 2030189251Ssam } 2031189251Ssam *out_len = 0; 2032189251Ssam return NULL; 2033189251Ssam } 2034189251Ssam res = res == 0 ? 0 : BIO_read(conn->ssl_out, out_data, res); 2035189251Ssam if (res < 0) { 2036189251Ssam tls_show_errors(MSG_INFO, __func__, 2037189251Ssam "Handshake failed - BIO_read"); 2038189251Ssam if (BIO_reset(conn->ssl_out) < 0) { 2039189251Ssam tls_show_errors(MSG_INFO, __func__, 2040189251Ssam "BIO_reset failed"); 2041189251Ssam } 2042189251Ssam *out_len = 0; 2043189251Ssam return NULL; 2044189251Ssam } 2045189251Ssam *out_len = res; 2046189251Ssam 2047189251Ssam if (SSL_is_init_finished(conn->ssl) && appl_data) { 2048189251Ssam *appl_data = os_malloc(in_len); 2049189251Ssam if (*appl_data) { 2050189251Ssam res = SSL_read(conn->ssl, *appl_data, in_len); 2051189251Ssam if (res < 0) { 2052209158Srpaulo int err = SSL_get_error(conn->ssl, res); 2053209158Srpaulo if (err == SSL_ERROR_WANT_READ || 2054209158Srpaulo err == SSL_ERROR_WANT_WRITE) { 2055209158Srpaulo wpa_printf(MSG_DEBUG, 2056209158Srpaulo "SSL: No Application Data " 2057209158Srpaulo "included"); 2058209158Srpaulo } else { 2059209158Srpaulo tls_show_errors(MSG_INFO, __func__, 2060209158Srpaulo "Failed to read " 2061209158Srpaulo "possible " 2062209158Srpaulo "Application Data"); 2063209158Srpaulo } 2064189251Ssam os_free(*appl_data); 2065189251Ssam *appl_data = NULL; 2066189251Ssam } else { 2067189251Ssam *appl_data_len = res; 2068189251Ssam wpa_hexdump_key(MSG_MSGDUMP, "SSL: Application" 2069189251Ssam " Data in Finish message", 2070189251Ssam *appl_data, *appl_data_len); 2071189251Ssam } 2072189251Ssam } 2073189251Ssam } 2074189251Ssam 2075189251Ssam return out_data; 2076189251Ssam} 2077189251Ssam 2078189251Ssam 2079189251Ssamu8 * tls_connection_server_handshake(void *ssl_ctx, 2080189251Ssam struct tls_connection *conn, 2081189251Ssam const u8 *in_data, size_t in_len, 2082189251Ssam size_t *out_len) 2083189251Ssam{ 2084189251Ssam int res; 2085189251Ssam u8 *out_data; 2086189251Ssam 2087189251Ssam /* 2088189251Ssam * Give TLS handshake data from the client (if available) to OpenSSL 2089189251Ssam * for processing. 2090189251Ssam */ 2091189251Ssam if (in_data && 2092189251Ssam BIO_write(conn->ssl_in, in_data, in_len) < 0) { 2093189251Ssam tls_show_errors(MSG_INFO, __func__, 2094189251Ssam "Handshake failed - BIO_write"); 2095189251Ssam return NULL; 2096189251Ssam } 2097189251Ssam 2098189251Ssam /* Initiate TLS handshake or continue the existing handshake */ 2099189251Ssam res = SSL_accept(conn->ssl); 2100189251Ssam if (res != 1) { 2101189251Ssam int err = SSL_get_error(conn->ssl, res); 2102189251Ssam if (err == SSL_ERROR_WANT_READ) 2103189251Ssam wpa_printf(MSG_DEBUG, "SSL: SSL_accept - want " 2104189251Ssam "more data"); 2105189251Ssam else if (err == SSL_ERROR_WANT_WRITE) 2106189251Ssam wpa_printf(MSG_DEBUG, "SSL: SSL_accept - want to " 2107189251Ssam "write"); 2108189251Ssam else { 2109189251Ssam tls_show_errors(MSG_INFO, __func__, "SSL_accept"); 2110189251Ssam return NULL; 2111189251Ssam } 2112189251Ssam } 2113189251Ssam 2114189251Ssam /* Get the TLS handshake data to be sent to the client */ 2115189251Ssam res = BIO_ctrl_pending(conn->ssl_out); 2116189251Ssam wpa_printf(MSG_DEBUG, "SSL: %d bytes pending from ssl_out", res); 2117189251Ssam out_data = os_malloc(res == 0 ? 1 : res); 2118189251Ssam if (out_data == NULL) { 2119189251Ssam wpa_printf(MSG_DEBUG, "SSL: Failed to allocate memory for " 2120189251Ssam "handshake output (%d bytes)", res); 2121189251Ssam if (BIO_reset(conn->ssl_out) < 0) { 2122189251Ssam tls_show_errors(MSG_INFO, __func__, 2123189251Ssam "BIO_reset failed"); 2124189251Ssam } 2125189251Ssam *out_len = 0; 2126189251Ssam return NULL; 2127189251Ssam } 2128189251Ssam res = res == 0 ? 0 : BIO_read(conn->ssl_out, out_data, res); 2129189251Ssam if (res < 0) { 2130189251Ssam tls_show_errors(MSG_INFO, __func__, 2131189251Ssam "Handshake failed - BIO_read"); 2132189251Ssam if (BIO_reset(conn->ssl_out) < 0) { 2133189251Ssam tls_show_errors(MSG_INFO, __func__, 2134189251Ssam "BIO_reset failed"); 2135189251Ssam } 2136189251Ssam *out_len = 0; 2137189251Ssam return NULL; 2138189251Ssam } 2139189251Ssam *out_len = res; 2140189251Ssam return out_data; 2141189251Ssam} 2142189251Ssam 2143189251Ssam 2144189251Ssamint tls_connection_encrypt(void *ssl_ctx, struct tls_connection *conn, 2145189251Ssam const u8 *in_data, size_t in_len, 2146189251Ssam u8 *out_data, size_t out_len) 2147189251Ssam{ 2148189251Ssam int res; 2149189251Ssam 2150189251Ssam if (conn == NULL) 2151189251Ssam return -1; 2152189251Ssam 2153189251Ssam /* Give plaintext data for OpenSSL to encrypt into the TLS tunnel. */ 2154189251Ssam if ((res = BIO_reset(conn->ssl_in)) < 0 || 2155189251Ssam (res = BIO_reset(conn->ssl_out)) < 0) { 2156189251Ssam tls_show_errors(MSG_INFO, __func__, "BIO_reset failed"); 2157189251Ssam return res; 2158189251Ssam } 2159189251Ssam res = SSL_write(conn->ssl, in_data, in_len); 2160189251Ssam if (res < 0) { 2161189251Ssam tls_show_errors(MSG_INFO, __func__, 2162189251Ssam "Encryption failed - SSL_write"); 2163189251Ssam return res; 2164189251Ssam } 2165189251Ssam 2166189251Ssam /* Read encrypted data to be sent to the server */ 2167189251Ssam res = BIO_read(conn->ssl_out, out_data, out_len); 2168189251Ssam if (res < 0) { 2169189251Ssam tls_show_errors(MSG_INFO, __func__, 2170189251Ssam "Encryption failed - BIO_read"); 2171189251Ssam return res; 2172189251Ssam } 2173189251Ssam 2174189251Ssam return res; 2175189251Ssam} 2176189251Ssam 2177189251Ssam 2178189251Ssamint tls_connection_decrypt(void *ssl_ctx, struct tls_connection *conn, 2179189251Ssam const u8 *in_data, size_t in_len, 2180189251Ssam u8 *out_data, size_t out_len) 2181189251Ssam{ 2182189251Ssam int res; 2183189251Ssam 2184189251Ssam /* Give encrypted data from TLS tunnel for OpenSSL to decrypt. */ 2185189251Ssam res = BIO_write(conn->ssl_in, in_data, in_len); 2186189251Ssam if (res < 0) { 2187189251Ssam tls_show_errors(MSG_INFO, __func__, 2188189251Ssam "Decryption failed - BIO_write"); 2189189251Ssam return res; 2190189251Ssam } 2191189251Ssam if (BIO_reset(conn->ssl_out) < 0) { 2192189251Ssam tls_show_errors(MSG_INFO, __func__, "BIO_reset failed"); 2193189251Ssam return res; 2194189251Ssam } 2195189251Ssam 2196189251Ssam /* Read decrypted data for further processing */ 2197189251Ssam res = SSL_read(conn->ssl, out_data, out_len); 2198189251Ssam if (res < 0) { 2199189251Ssam tls_show_errors(MSG_INFO, __func__, 2200189251Ssam "Decryption failed - SSL_read"); 2201189251Ssam return res; 2202189251Ssam } 2203189251Ssam 2204189251Ssam return res; 2205189251Ssam} 2206189251Ssam 2207189251Ssam 2208189251Ssamint tls_connection_resumed(void *ssl_ctx, struct tls_connection *conn) 2209189251Ssam{ 2210189251Ssam return conn ? conn->ssl->hit : 0; 2211189251Ssam} 2212189251Ssam 2213189251Ssam 2214189251Ssamint tls_connection_set_cipher_list(void *tls_ctx, struct tls_connection *conn, 2215189251Ssam u8 *ciphers) 2216189251Ssam{ 2217189251Ssam char buf[100], *pos, *end; 2218189251Ssam u8 *c; 2219189251Ssam int ret; 2220189251Ssam 2221189251Ssam if (conn == NULL || conn->ssl == NULL || ciphers == NULL) 2222189251Ssam return -1; 2223189251Ssam 2224189251Ssam buf[0] = '\0'; 2225189251Ssam pos = buf; 2226189251Ssam end = pos + sizeof(buf); 2227189251Ssam 2228189251Ssam c = ciphers; 2229189251Ssam while (*c != TLS_CIPHER_NONE) { 2230189251Ssam const char *suite; 2231189251Ssam 2232189251Ssam switch (*c) { 2233189251Ssam case TLS_CIPHER_RC4_SHA: 2234189251Ssam suite = "RC4-SHA"; 2235189251Ssam break; 2236189251Ssam case TLS_CIPHER_AES128_SHA: 2237189251Ssam suite = "AES128-SHA"; 2238189251Ssam break; 2239189251Ssam case TLS_CIPHER_RSA_DHE_AES128_SHA: 2240189251Ssam suite = "DHE-RSA-AES128-SHA"; 2241189251Ssam break; 2242189251Ssam case TLS_CIPHER_ANON_DH_AES128_SHA: 2243189251Ssam suite = "ADH-AES128-SHA"; 2244189251Ssam break; 2245189251Ssam default: 2246189251Ssam wpa_printf(MSG_DEBUG, "TLS: Unsupported " 2247189251Ssam "cipher selection: %d", *c); 2248189251Ssam return -1; 2249189251Ssam } 2250189251Ssam ret = os_snprintf(pos, end - pos, ":%s", suite); 2251189251Ssam if (ret < 0 || ret >= end - pos) 2252189251Ssam break; 2253189251Ssam pos += ret; 2254189251Ssam 2255189251Ssam c++; 2256189251Ssam } 2257189251Ssam 2258189251Ssam wpa_printf(MSG_DEBUG, "OpenSSL: cipher suites: %s", buf + 1); 2259189251Ssam 2260189251Ssam if (SSL_set_cipher_list(conn->ssl, buf + 1) != 1) { 2261189251Ssam tls_show_errors(MSG_INFO, __func__, 2262189251Ssam "Cipher suite configuration failed"); 2263189251Ssam return -1; 2264189251Ssam } 2265189251Ssam 2266189251Ssam return 0; 2267189251Ssam} 2268189251Ssam 2269189251Ssam 2270189251Ssamint tls_get_cipher(void *ssl_ctx, struct tls_connection *conn, 2271189251Ssam char *buf, size_t buflen) 2272189251Ssam{ 2273189251Ssam const char *name; 2274189251Ssam if (conn == NULL || conn->ssl == NULL) 2275189251Ssam return -1; 2276189251Ssam 2277189251Ssam name = SSL_get_cipher(conn->ssl); 2278189251Ssam if (name == NULL) 2279189251Ssam return -1; 2280189251Ssam 2281189251Ssam os_strlcpy(buf, name, buflen); 2282189251Ssam return 0; 2283189251Ssam} 2284189251Ssam 2285189251Ssam 2286189251Ssamint tls_connection_enable_workaround(void *ssl_ctx, 2287189251Ssam struct tls_connection *conn) 2288189251Ssam{ 2289189251Ssam SSL_set_options(conn->ssl, SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS); 2290189251Ssam 2291189251Ssam return 0; 2292189251Ssam} 2293189251Ssam 2294189251Ssam 2295189251Ssam#if defined(EAP_FAST) || defined(EAP_FAST_DYNAMIC) 2296189251Ssam/* ClientHello TLS extensions require a patch to openssl, so this function is 2297189251Ssam * commented out unless explicitly needed for EAP-FAST in order to be able to 2298189251Ssam * build this file with unmodified openssl. */ 2299189251Ssamint tls_connection_client_hello_ext(void *ssl_ctx, struct tls_connection *conn, 2300189251Ssam int ext_type, const u8 *data, 2301189251Ssam size_t data_len) 2302189251Ssam{ 2303189251Ssam if (conn == NULL || conn->ssl == NULL || ext_type != 35) 2304189251Ssam return -1; 2305189251Ssam 2306189251Ssam#ifdef CONFIG_OPENSSL_TICKET_OVERRIDE 2307189251Ssam if (SSL_set_session_ticket_ext(conn->ssl, (void *) data, 2308189251Ssam data_len) != 1) 2309189251Ssam return -1; 2310189251Ssam#else /* CONFIG_OPENSSL_TICKET_OVERRIDE */ 2311189251Ssam if (SSL_set_hello_extension(conn->ssl, ext_type, (void *) data, 2312189251Ssam data_len) != 1) 2313189251Ssam return -1; 2314189251Ssam#endif /* CONFIG_OPENSSL_TICKET_OVERRIDE */ 2315189251Ssam 2316189251Ssam return 0; 2317189251Ssam} 2318189251Ssam#endif /* EAP_FAST || EAP_FAST_DYNAMIC */ 2319189251Ssam 2320189251Ssam 2321189251Ssamint tls_connection_get_failed(void *ssl_ctx, struct tls_connection *conn) 2322189251Ssam{ 2323189251Ssam if (conn == NULL) 2324189251Ssam return -1; 2325189251Ssam return conn->failed; 2326189251Ssam} 2327189251Ssam 2328189251Ssam 2329189251Ssamint tls_connection_get_read_alerts(void *ssl_ctx, struct tls_connection *conn) 2330189251Ssam{ 2331189251Ssam if (conn == NULL) 2332189251Ssam return -1; 2333189251Ssam return conn->read_alerts; 2334189251Ssam} 2335189251Ssam 2336189251Ssam 2337189251Ssamint tls_connection_get_write_alerts(void *ssl_ctx, struct tls_connection *conn) 2338189251Ssam{ 2339189251Ssam if (conn == NULL) 2340189251Ssam return -1; 2341189251Ssam return conn->write_alerts; 2342189251Ssam} 2343189251Ssam 2344189251Ssam 2345189251Ssamint tls_connection_set_params(void *tls_ctx, struct tls_connection *conn, 2346189251Ssam const struct tls_connection_params *params) 2347189251Ssam{ 2348189251Ssam int ret; 2349189251Ssam unsigned long err; 2350189251Ssam 2351189251Ssam if (conn == NULL) 2352189251Ssam return -1; 2353189251Ssam 2354189251Ssam while ((err = ERR_get_error())) { 2355189251Ssam wpa_printf(MSG_INFO, "%s: Clearing pending SSL error: %s", 2356189251Ssam __func__, ERR_error_string(err, NULL)); 2357189251Ssam } 2358189251Ssam 2359189251Ssam if (params->engine) { 2360189251Ssam wpa_printf(MSG_DEBUG, "SSL: Initializing TLS engine"); 2361189251Ssam ret = tls_engine_init(conn, params->engine_id, params->pin, 2362189251Ssam params->key_id, params->cert_id, 2363189251Ssam params->ca_cert_id); 2364189251Ssam if (ret) 2365189251Ssam return ret; 2366189251Ssam } 2367189251Ssam if (tls_connection_set_subject_match(conn, 2368189251Ssam params->subject_match, 2369189251Ssam params->altsubject_match)) 2370189251Ssam return -1; 2371189251Ssam 2372189251Ssam if (params->engine && params->ca_cert_id) { 2373189251Ssam if (tls_connection_engine_ca_cert(tls_ctx, conn, 2374189251Ssam params->ca_cert_id)) 2375189251Ssam return TLS_SET_PARAMS_ENGINE_PRV_VERIFY_FAILED; 2376189251Ssam } else if (tls_connection_ca_cert(tls_ctx, conn, params->ca_cert, 2377189251Ssam params->ca_cert_blob, 2378189251Ssam params->ca_cert_blob_len, 2379189251Ssam params->ca_path)) 2380189251Ssam return -1; 2381189251Ssam 2382189251Ssam if (params->engine && params->cert_id) { 2383189251Ssam if (tls_connection_engine_client_cert(conn, params->cert_id)) 2384189251Ssam return TLS_SET_PARAMS_ENGINE_PRV_VERIFY_FAILED; 2385189251Ssam } else if (tls_connection_client_cert(conn, params->client_cert, 2386189251Ssam params->client_cert_blob, 2387189251Ssam params->client_cert_blob_len)) 2388189251Ssam return -1; 2389189251Ssam 2390189251Ssam if (params->engine && params->key_id) { 2391189251Ssam wpa_printf(MSG_DEBUG, "TLS: Using private key from engine"); 2392189251Ssam if (tls_connection_engine_private_key(conn)) 2393189251Ssam return TLS_SET_PARAMS_ENGINE_PRV_VERIFY_FAILED; 2394189251Ssam } else if (tls_connection_private_key(tls_ctx, conn, 2395189251Ssam params->private_key, 2396189251Ssam params->private_key_passwd, 2397189251Ssam params->private_key_blob, 2398189251Ssam params->private_key_blob_len)) { 2399189251Ssam wpa_printf(MSG_INFO, "TLS: Failed to load private key '%s'", 2400189251Ssam params->private_key); 2401189251Ssam return -1; 2402189251Ssam } 2403189251Ssam 2404189251Ssam if (tls_connection_dh(conn, params->dh_file)) { 2405189251Ssam wpa_printf(MSG_INFO, "TLS: Failed to load DH file '%s'", 2406189251Ssam params->dh_file); 2407189251Ssam return -1; 2408189251Ssam } 2409189251Ssam 2410189251Ssam tls_get_errors(tls_ctx); 2411189251Ssam 2412189251Ssam return 0; 2413189251Ssam} 2414189251Ssam 2415189251Ssam 2416189251Ssamint tls_global_set_params(void *tls_ctx, 2417189251Ssam const struct tls_connection_params *params) 2418189251Ssam{ 2419189251Ssam SSL_CTX *ssl_ctx = tls_ctx; 2420189251Ssam unsigned long err; 2421189251Ssam 2422189251Ssam while ((err = ERR_get_error())) { 2423189251Ssam wpa_printf(MSG_INFO, "%s: Clearing pending SSL error: %s", 2424189251Ssam __func__, ERR_error_string(err, NULL)); 2425189251Ssam } 2426189251Ssam 2427189251Ssam if (tls_global_ca_cert(ssl_ctx, params->ca_cert)) 2428189251Ssam return -1; 2429189251Ssam 2430189251Ssam if (tls_global_client_cert(ssl_ctx, params->client_cert)) 2431189251Ssam return -1; 2432189251Ssam 2433189251Ssam if (tls_global_private_key(ssl_ctx, params->private_key, 2434189251Ssam params->private_key_passwd)) 2435189251Ssam return -1; 2436189251Ssam 2437189251Ssam if (tls_global_dh(ssl_ctx, params->dh_file)) { 2438189251Ssam wpa_printf(MSG_INFO, "TLS: Failed to load DH file '%s'", 2439189251Ssam params->dh_file); 2440189251Ssam return -1; 2441189251Ssam } 2442189251Ssam 2443189251Ssam return 0; 2444189251Ssam} 2445189251Ssam 2446189251Ssam 2447189251Ssamint tls_connection_get_keyblock_size(void *tls_ctx, 2448189251Ssam struct tls_connection *conn) 2449189251Ssam{ 2450189251Ssam const EVP_CIPHER *c; 2451189251Ssam const EVP_MD *h; 2452189251Ssam 2453189251Ssam if (conn == NULL || conn->ssl == NULL || 2454189251Ssam conn->ssl->enc_read_ctx == NULL || 2455189251Ssam conn->ssl->enc_read_ctx->cipher == NULL || 2456189251Ssam conn->ssl->read_hash == NULL) 2457189251Ssam return -1; 2458189251Ssam 2459189251Ssam c = conn->ssl->enc_read_ctx->cipher; 2460189251Ssam#if OPENSSL_VERSION_NUMBER >= 0x00909000L 2461189251Ssam h = EVP_MD_CTX_md(conn->ssl->read_hash); 2462189251Ssam#else 2463189251Ssam h = conn->ssl->read_hash; 2464189251Ssam#endif 2465189251Ssam 2466189251Ssam return 2 * (EVP_CIPHER_key_length(c) + 2467189251Ssam EVP_MD_size(h) + 2468189251Ssam EVP_CIPHER_iv_length(c)); 2469189251Ssam} 2470189251Ssam 2471189251Ssam 2472189251Ssamunsigned int tls_capabilities(void *tls_ctx) 2473189251Ssam{ 2474189251Ssam return 0; 2475189251Ssam} 2476189251Ssam 2477189251Ssam 2478189251Ssamint tls_connection_set_ia(void *tls_ctx, struct tls_connection *conn, 2479189251Ssam int tls_ia) 2480189251Ssam{ 2481189251Ssam return -1; 2482189251Ssam} 2483189251Ssam 2484189251Ssam 2485189251Ssamint tls_connection_ia_send_phase_finished(void *tls_ctx, 2486189251Ssam struct tls_connection *conn, 2487189251Ssam int final, 2488189251Ssam u8 *out_data, size_t out_len) 2489189251Ssam{ 2490189251Ssam return -1; 2491189251Ssam} 2492189251Ssam 2493189251Ssam 2494189251Ssamint tls_connection_ia_final_phase_finished(void *tls_ctx, 2495189251Ssam struct tls_connection *conn) 2496189251Ssam{ 2497189251Ssam return -1; 2498189251Ssam} 2499189251Ssam 2500189251Ssam 2501189251Ssamint tls_connection_ia_permute_inner_secret(void *tls_ctx, 2502189251Ssam struct tls_connection *conn, 2503189251Ssam const u8 *key, size_t key_len) 2504189251Ssam{ 2505189251Ssam return -1; 2506189251Ssam} 2507189251Ssam 2508189251Ssam 2509189251Ssam#if defined(EAP_FAST) || defined(EAP_FAST_DYNAMIC) 2510189251Ssam/* Pre-shared secred requires a patch to openssl, so this function is 2511189251Ssam * commented out unless explicitly needed for EAP-FAST in order to be able to 2512189251Ssam * build this file with unmodified openssl. */ 2513189251Ssam 2514189251Ssamstatic int tls_sess_sec_cb(SSL *s, void *secret, int *secret_len, 2515189251Ssam STACK_OF(SSL_CIPHER) *peer_ciphers, 2516189251Ssam SSL_CIPHER **cipher, void *arg) 2517189251Ssam{ 2518189251Ssam struct tls_connection *conn = arg; 2519189251Ssam int ret; 2520189251Ssam 2521189251Ssam if (conn == NULL || conn->session_ticket_cb == NULL) 2522189251Ssam return 0; 2523189251Ssam 2524189251Ssam ret = conn->session_ticket_cb(conn->session_ticket_cb_ctx, 2525189251Ssam conn->session_ticket, 2526189251Ssam conn->session_ticket_len, 2527189251Ssam s->s3->client_random, 2528189251Ssam s->s3->server_random, secret); 2529189251Ssam os_free(conn->session_ticket); 2530189251Ssam conn->session_ticket = NULL; 2531189251Ssam 2532189251Ssam if (ret <= 0) 2533189251Ssam return 0; 2534189251Ssam 2535189251Ssam *secret_len = SSL_MAX_MASTER_KEY_LENGTH; 2536189251Ssam return 1; 2537189251Ssam} 2538189251Ssam 2539189251Ssam 2540189251Ssam#ifdef CONFIG_OPENSSL_TICKET_OVERRIDE 2541189251Ssamstatic int tls_session_ticket_ext_cb(SSL *s, const unsigned char *data, 2542189251Ssam int len, void *arg) 2543189251Ssam{ 2544189251Ssam struct tls_connection *conn = arg; 2545189251Ssam 2546189251Ssam if (conn == NULL || conn->session_ticket_cb == NULL) 2547189251Ssam return 0; 2548189251Ssam 2549189251Ssam wpa_printf(MSG_DEBUG, "OpenSSL: %s: length=%d", __func__, len); 2550189251Ssam 2551189251Ssam os_free(conn->session_ticket); 2552189251Ssam conn->session_ticket = NULL; 2553189251Ssam 2554189251Ssam wpa_hexdump(MSG_DEBUG, "OpenSSL: ClientHello SessionTicket " 2555189251Ssam "extension", data, len); 2556189251Ssam 2557189251Ssam conn->session_ticket = os_malloc(len); 2558189251Ssam if (conn->session_ticket == NULL) 2559189251Ssam return 0; 2560189251Ssam 2561189251Ssam os_memcpy(conn->session_ticket, data, len); 2562189251Ssam conn->session_ticket_len = len; 2563189251Ssam 2564189251Ssam return 1; 2565189251Ssam} 2566189251Ssam#else /* CONFIG_OPENSSL_TICKET_OVERRIDE */ 2567189251Ssam#ifdef SSL_OP_NO_TICKET 2568189251Ssamstatic void tls_hello_ext_cb(SSL *s, int client_server, int type, 2569189251Ssam unsigned char *data, int len, void *arg) 2570189251Ssam{ 2571189251Ssam struct tls_connection *conn = arg; 2572189251Ssam 2573189251Ssam if (conn == NULL || conn->session_ticket_cb == NULL) 2574189251Ssam return; 2575189251Ssam 2576189251Ssam wpa_printf(MSG_DEBUG, "OpenSSL: %s: type=%d length=%d", __func__, 2577189251Ssam type, len); 2578189251Ssam 2579189251Ssam if (type == TLSEXT_TYPE_session_ticket && !client_server) { 2580189251Ssam os_free(conn->session_ticket); 2581189251Ssam conn->session_ticket = NULL; 2582189251Ssam 2583189251Ssam wpa_hexdump(MSG_DEBUG, "OpenSSL: ClientHello SessionTicket " 2584189251Ssam "extension", data, len); 2585189251Ssam conn->session_ticket = os_malloc(len); 2586189251Ssam if (conn->session_ticket == NULL) 2587189251Ssam return; 2588189251Ssam 2589189251Ssam os_memcpy(conn->session_ticket, data, len); 2590189251Ssam conn->session_ticket_len = len; 2591189251Ssam } 2592189251Ssam} 2593189251Ssam#else /* SSL_OP_NO_TICKET */ 2594189251Ssamstatic int tls_hello_ext_cb(SSL *s, TLS_EXTENSION *ext, void *arg) 2595189251Ssam{ 2596189251Ssam struct tls_connection *conn = arg; 2597189251Ssam 2598189251Ssam if (conn == NULL || conn->session_ticket_cb == NULL) 2599189251Ssam return 0; 2600189251Ssam 2601189251Ssam wpa_printf(MSG_DEBUG, "OpenSSL: %s: type=%d length=%d", __func__, 2602189251Ssam ext->type, ext->length); 2603189251Ssam 2604189251Ssam os_free(conn->session_ticket); 2605189251Ssam conn->session_ticket = NULL; 2606189251Ssam 2607189251Ssam if (ext->type == 35) { 2608189251Ssam wpa_hexdump(MSG_DEBUG, "OpenSSL: ClientHello SessionTicket " 2609189251Ssam "extension", ext->data, ext->length); 2610189251Ssam conn->session_ticket = os_malloc(ext->length); 2611189251Ssam if (conn->session_ticket == NULL) 2612189251Ssam return SSL_AD_INTERNAL_ERROR; 2613189251Ssam 2614189251Ssam os_memcpy(conn->session_ticket, ext->data, ext->length); 2615189251Ssam conn->session_ticket_len = ext->length; 2616189251Ssam } 2617189251Ssam 2618189251Ssam return 0; 2619189251Ssam} 2620189251Ssam#endif /* SSL_OP_NO_TICKET */ 2621189251Ssam#endif /* CONFIG_OPENSSL_TICKET_OVERRIDE */ 2622189251Ssam#endif /* EAP_FAST || EAP_FAST_DYNAMIC */ 2623189251Ssam 2624189251Ssam 2625189251Ssamint tls_connection_set_session_ticket_cb(void *tls_ctx, 2626189251Ssam struct tls_connection *conn, 2627189251Ssam tls_session_ticket_cb cb, 2628189251Ssam void *ctx) 2629189251Ssam{ 2630189251Ssam#if defined(EAP_FAST) || defined(EAP_FAST_DYNAMIC) 2631189251Ssam conn->session_ticket_cb = cb; 2632189251Ssam conn->session_ticket_cb_ctx = ctx; 2633189251Ssam 2634189251Ssam if (cb) { 2635189251Ssam if (SSL_set_session_secret_cb(conn->ssl, tls_sess_sec_cb, 2636189251Ssam conn) != 1) 2637189251Ssam return -1; 2638189251Ssam#ifdef CONFIG_OPENSSL_TICKET_OVERRIDE 2639189251Ssam SSL_set_session_ticket_ext_cb(conn->ssl, 2640189251Ssam tls_session_ticket_ext_cb, conn); 2641189251Ssam#else /* CONFIG_OPENSSL_TICKET_OVERRIDE */ 2642189251Ssam#ifdef SSL_OP_NO_TICKET 2643189251Ssam SSL_set_tlsext_debug_callback(conn->ssl, tls_hello_ext_cb); 2644189251Ssam SSL_set_tlsext_debug_arg(conn->ssl, conn); 2645189251Ssam#else /* SSL_OP_NO_TICKET */ 2646189251Ssam if (SSL_set_hello_extension_cb(conn->ssl, tls_hello_ext_cb, 2647189251Ssam conn) != 1) 2648189251Ssam return -1; 2649189251Ssam#endif /* SSL_OP_NO_TICKET */ 2650189251Ssam#endif /* CONFIG_OPENSSL_TICKET_OVERRIDE */ 2651189251Ssam } else { 2652189251Ssam if (SSL_set_session_secret_cb(conn->ssl, NULL, NULL) != 1) 2653189251Ssam return -1; 2654189251Ssam#ifdef CONFIG_OPENSSL_TICKET_OVERRIDE 2655189251Ssam SSL_set_session_ticket_ext_cb(conn->ssl, NULL, NULL); 2656189251Ssam#else /* CONFIG_OPENSSL_TICKET_OVERRIDE */ 2657189251Ssam#ifdef SSL_OP_NO_TICKET 2658189251Ssam SSL_set_tlsext_debug_callback(conn->ssl, NULL); 2659189251Ssam SSL_set_tlsext_debug_arg(conn->ssl, conn); 2660189251Ssam#else /* SSL_OP_NO_TICKET */ 2661189251Ssam if (SSL_set_hello_extension_cb(conn->ssl, NULL, NULL) != 1) 2662189251Ssam return -1; 2663189251Ssam#endif /* SSL_OP_NO_TICKET */ 2664189251Ssam#endif /* CONFIG_OPENSSL_TICKET_OVERRIDE */ 2665189251Ssam } 2666189251Ssam 2667189251Ssam return 0; 2668189251Ssam#else /* EAP_FAST || EAP_FAST_DYNAMIC */ 2669189251Ssam return -1; 2670189251Ssam#endif /* EAP_FAST || EAP_FAST_DYNAMIC */ 2671189251Ssam} 2672