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