unrealircd

- supernets unrealircd source & configuration
git clone git://git.acid.vegas/unrealircd.git
Log | Files | Refs | Archive | README | LICENSE

tls.c (41273B)

      1 /************************************************************************
      2  *   Unreal Internet Relay Chat Daemon, src/tls.c
      3  *      (C) 2000 hq.alert.sk (base)
      4  *      (C) 2000 Carsten V. Munk <stskeeps@tspre.org> 
      5  *
      6  *   This program is free software; you can redistribute it and/or modify
      7  *   it under the terms of the GNU General Public License as published by
      8  *   the Free Software Foundation; either version 1, or (at your option)
      9  *   any later version.
     10  *
     11  *   This program is distributed in the hope that it will be useful,
     12  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
     13  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     14  *   GNU General Public License for more details.
     15  *
     16  *   You should have received a copy of the GNU General Public License
     17  *   along with this program; if not, write to the Free Software
     18  *   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
     19  */
     20 
     21 /** @file
     22  * @brief TLS functions
     23  */
     24 
     25 #include "unrealircd.h"
     26 #include "openssl_hostname_validation.h"
     27 
     28 #ifdef _WIN32
     29 #define IDC_PASS                        1166
     30 extern HINSTANCE hInst;
     31 extern HWND hwIRCDWnd;
     32 #endif
     33 
     34 #define FUNC_TLS_READ 1
     35 #define FUNC_TLS_WRITE 2
     36 #define FUNC_TLS_ACCEPT 3
     37 #define FUNC_TLS_CONNECT 4
     38 
     39 /* Forward declarations */
     40 static int fatal_tls_error(int ssl_error, int where, int my_errno, Client *client);
     41 int cipher_check(SSL_CTX *ctx, char **errstr);
     42 int certificate_quality_check(SSL_CTX *ctx, char **errstr);
     43 
     44 /* The TLS structures */
     45 SSL_CTX *ctx_server;
     46 SSL_CTX *ctx_client;
     47 
     48 char *TLSKeyPasswd;
     49 
     50 typedef struct {
     51 	int *size;
     52 	char **buffer;
     53 } StreamIO;
     54 
     55 MODVAR int tls_client_index = 0;
     56 
     57 #ifdef _WIN32
     58 /** Ask private key password (Windows GUI mode only) */
     59 LRESULT TLS_key_passwd_dialog(HWND hDlg, UINT Message, WPARAM wParam, LPARAM lParam)
     60 {
     61 	static StreamIO *stream;
     62 	switch (Message) {
     63 		case WM_INITDIALOG:
     64 			stream = (StreamIO*)lParam;
     65 			return TRUE;
     66 		case WM_COMMAND:
     67 			if (LOWORD(wParam) == IDCANCEL) {
     68 				*stream->buffer = NULL;
     69 				EndDialog(hDlg, IDCANCEL);
     70 			}
     71 			else if (LOWORD(wParam) == IDOK) {
     72 				GetDlgItemText(hDlg, IDC_PASS, *stream->buffer, *stream->size);
     73 				EndDialog(hDlg, IDOK);
     74 			}
     75 			return FALSE;
     76 		case WM_CLOSE:
     77 			*stream->buffer = NULL;
     78 			EndDialog(hDlg, IDCANCEL);
     79 		default:
     80 			return FALSE;
     81 	}
     82 }
     83 #endif				
     84 
     85 /** Return error string for OpenSSL error.
     86  * @param err		OpenSSL error number to lookup
     87  * @param my_errno	The value of errno to use in case we want to call strerror().
     88  * @returns Error string, only valid until next call to this function.
     89  */
     90 const char *ssl_error_str(int err, int my_errno)
     91 {
     92 	static char ssl_errbuf[256];
     93 	char *ssl_errstr = NULL;
     94 
     95 	switch(err)
     96 	{
     97 		case SSL_ERROR_NONE:
     98 			ssl_errstr = "OpenSSL: No error";
     99 			break;
    100 		case SSL_ERROR_SSL:
    101 			ssl_errstr = "Internal OpenSSL error or protocol error";
    102 			break;
    103 		case SSL_ERROR_WANT_READ:
    104 			ssl_errstr = "OpenSSL functions requested a read()";
    105 			break;
    106 		case SSL_ERROR_WANT_WRITE:
    107 			ssl_errstr = "OpenSSL functions requested a write()";
    108 			break;
    109 		case SSL_ERROR_WANT_X509_LOOKUP:
    110 			ssl_errstr = "OpenSSL requested a X509 lookup which didn't arrive";
    111 			break;
    112 		case SSL_ERROR_SYSCALL:
    113 			snprintf(ssl_errbuf, sizeof(ssl_errbuf), "%s", STRERROR(my_errno));
    114 			ssl_errstr = ssl_errbuf;
    115 			break;
    116 		case SSL_ERROR_ZERO_RETURN:
    117 			ssl_errstr = "Underlying socket operation returned zero";
    118 			break;
    119 		case SSL_ERROR_WANT_CONNECT:
    120 			ssl_errstr = "OpenSSL functions wanted a connect()";
    121 			break;
    122 		default:
    123 			ssl_errstr = "Unknown OpenSSL error (huh?)";
    124 	}
    125 	return ssl_errstr;
    126 }
    127 
    128 /** Ask certificate private key password (rare) */
    129 int TLS_key_passwd_cb(char *buf, int size, int rwflag, void *password)
    130 {
    131 	char *pass;
    132 	static int before = 0;
    133 	static char beforebuf[1024];
    134 #ifdef _WIN32
    135 	StreamIO stream;
    136 	char passbuf[512];	
    137 	int passsize = 512;
    138 #endif
    139 	if (before)
    140 	{
    141 		strlcpy(buf, beforebuf, size);
    142 		return strlen(buf);
    143 	}
    144 #ifndef _WIN32
    145 	pass = getpass("Password for TLS private key: ");
    146 #else
    147 	pass = passbuf;
    148 	stream.buffer = &pass;
    149 	stream.size = &passsize;
    150 	DialogBoxParam(hInst, "TLSKey", hwIRCDWnd, (DLGPROC)TLS_key_passwd_dialog, (LPARAM)&stream); 
    151 #endif
    152 	if (pass)
    153 	{
    154 		strlcpy(buf, pass, size);
    155 		strlcpy(beforebuf, pass, sizeof(beforebuf));
    156 		before = 1;
    157 		TLSKeyPasswd = beforebuf;
    158 		return (strlen(buf));
    159 	}
    160 	return 0;
    161 }
    162 
    163 /** Verify certificate callback. */
    164 static int ssl_verify_callback(int preverify_ok, X509_STORE_CTX *ctx)
    165 {
    166 	/* We accept the connection. Certificate verifiction takes
    167 	 * place elsewhere, such as in _verify_link().
    168 	 */
    169 	return 1;
    170 }
    171 
    172 /** Get Client pointer by SSL pointer */
    173 Client *get_client_by_ssl(SSL *ssl)
    174 {
    175 	return SSL_get_ex_data(ssl, tls_client_index);
    176 }
    177 
    178 /** Set requested server name as indicated by SNI */
    179 static void set_client_sni_name(SSL *ssl, char *name)
    180 {
    181 	Client *client = get_client_by_ssl(ssl);
    182 	if (client)
    183 		safe_strdup(client->local->sni_servername, name);
    184 }
    185 
    186 /** Hostname callback, used for SNI */
    187 static int ssl_hostname_callback(SSL *ssl, int *unk, void *arg)
    188 {
    189 	char *name = (char *)SSL_get_servername(ssl, TLSEXT_NAMETYPE_host_name);
    190 	ConfigItem_sni *sni;
    191 
    192 	if (name && (sni = find_sni(name)))
    193 	{
    194 		SSL_set_SSL_CTX(ssl, sni->ssl_ctx);
    195 		set_client_sni_name(ssl, name);
    196 	}
    197 
    198 	return SSL_TLSEXT_ERR_OK;
    199 }
    200 
    201 /** Disable TLS protocols as set by config */
    202 void disable_ssl_protocols(SSL_CTX *ctx, TLSOptions *tlsoptions)
    203 {
    204 	/* OpenSSL has three mechanisms for protocol version control... */
    205 
    206 #ifdef HAS_SSL_CTX_SET_SECURITY_LEVEL
    207 	/* The first one is setting a "security level" as introduced
    208 	 * by OpenSSL 1.1.0. Some Linux distro's like Ubuntu 20.04
    209 	 * seemingly compile with -DOPENSSL_TLS_SECURITY_LEVEL=2.
    210 	 * This means the application (UnrealIRCd) is unable to allow
    211 	 * TLSv1.0/1.1 even if the application is configured to do so.
    212 	 * So here we set the level to 1, but -again- ONLY if we are
    213 	 * configured to allow TLSv1.0 or v1.1, of course.
    214 	 */
    215 	if ((tlsoptions->protocols & TLS_PROTOCOL_TLSV1) ||
    216 	    (tlsoptions->protocols & TLS_PROTOCOL_TLSV1_1))
    217 	{
    218 		SSL_CTX_set_security_level(ctx, 0);
    219 	}
    220 #endif
    221 
    222 	/* The remaining two mechanisms are:
    223 	 * The old way, which is most flexible, is to use:
    224 	 * SSL_CTX_set_options(... SSL_OP_NO_<version>) which allows
    225 	 * you to disable each and every specific TLS version.
    226 	 *
    227 	 * And the new way, which only allows setting a
    228 	 * minimum and maximum protocol version, using:
    229 	 * SSL_CTX_set_min_proto_version(... <version>)
    230 	 * SSL_CTX_set_max_proto_version(....<version>)
    231 	 *
    232 	 * We prefer the old way, but because OpenSSL 1.0.1 and
    233 	 * OS's like Debian use system-wide options we are also
    234 	 * forced to use the new way... or at least to set a
    235 	 * minimum protocol version to begin with.
    236 	 */
    237 #ifdef HAS_SSL_CTX_SET_MIN_PROTO_VERSION
    238 	if (!(tlsoptions->protocols & TLS_PROTOCOL_TLSV1) &&
    239 	    !(tlsoptions->protocols & TLS_PROTOCOL_TLSV1_1))
    240 	{
    241 		SSL_CTX_set_min_proto_version(ctx, TLS1_2_VERSION);
    242 	} else
    243 	if (!(tlsoptions->protocols & TLS_PROTOCOL_TLSV1))
    244 	{
    245 		SSL_CTX_set_min_proto_version(ctx, TLS1_1_VERSION);
    246 	} else
    247 	{
    248 		SSL_CTX_set_min_proto_version(ctx, TLS1_VERSION);
    249 	}
    250 #endif
    251 	SSL_CTX_set_options(ctx, SSL_OP_NO_SSLv2); /* always disable SSLv2 */
    252 	SSL_CTX_set_options(ctx, SSL_OP_NO_SSLv3); /* always disable SSLv3 */
    253 
    254 #ifdef SSL_OP_NO_TLSv1
    255 	if (!(tlsoptions->protocols & TLS_PROTOCOL_TLSV1))
    256 		SSL_CTX_set_options(ctx, SSL_OP_NO_TLSv1);
    257 #endif
    258 
    259 #ifdef SSL_OP_NO_TLSv1_1
    260 	if (!(tlsoptions->protocols & TLS_PROTOCOL_TLSV1_1))
    261 		SSL_CTX_set_options(ctx, SSL_OP_NO_TLSv1_1);
    262 #endif
    263 
    264 #ifdef SSL_OP_NO_TLSv1_2
    265 	if (!(tlsoptions->protocols & TLS_PROTOCOL_TLSV1_2))
    266 		SSL_CTX_set_options(ctx, SSL_OP_NO_TLSv1_2);
    267 #endif
    268 
    269 #ifdef SSL_OP_NO_TLSv1_3
    270 	if (!(tlsoptions->protocols & TLS_PROTOCOL_TLSV1_3))
    271 		SSL_CTX_set_options(ctx, SSL_OP_NO_TLSv1_3);
    272 #endif
    273 }
    274 
    275 /** Initialize TLS context
    276  * @param tlsoptions	The ::tls-options configuration
    277  * @param server	Set to 1 if we are initializing a server, 0 for client.
    278  * @returns The TLS context (SSL_CTX) or NULL in case of error.
    279  */
    280 SSL_CTX *init_ctx(TLSOptions *tlsoptions, int server)
    281 {
    282 	SSL_CTX *ctx;
    283 	char *errstr = NULL;
    284 
    285 	if (server)
    286 		ctx = SSL_CTX_new(SSLv23_server_method());
    287 	else
    288 		ctx = SSL_CTX_new(SSLv23_client_method());
    289 
    290 	if (!ctx)
    291 	{
    292 		unreal_log(ULOG_ERROR, "config", "TLS_LOAD_FAILED", NULL,
    293 		           "Failed to do SSL_CTX_new() !?\n$tls_error.all",
    294 		           log_data_tls_error());
    295 		return NULL;
    296 	}
    297 	disable_ssl_protocols(ctx, tlsoptions);
    298 	SSL_CTX_set_default_passwd_cb(ctx, TLS_key_passwd_cb);
    299 
    300 	if (server && !(tlsoptions->options & TLSFLAG_DISABLECLIENTCERT))
    301 	{
    302 		/* We tell OpenSSL/LibreSSL to verify the certificate and set our callback.
    303 		 * Our callback will always accept the certificate since actual checking
    304 		 * will take place elsewhere. Why? Because certificate is (often) delayed
    305 		 * until after the TLS handshake. Such as in the case of link blocks where
    306 		 * _verify_link() will take care of it only after we learned what server
    307 		 * we are dealing with (and if we should verify certificates for that server).
    308 		 */
    309 		SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER|SSL_VERIFY_CLIENT_ONCE | (tlsoptions->options & TLSFLAG_FAILIFNOCERT ? SSL_VERIFY_FAIL_IF_NO_PEER_CERT : 0), ssl_verify_callback);
    310 	}
    311 	SSL_CTX_set_session_cache_mode(ctx, SSL_SESS_CACHE_OFF);
    312 #ifndef SSL_OP_NO_TICKET
    313  #error "Your system has an outdated OpenSSL version. Please upgrade OpenSSL."
    314 #endif
    315 	SSL_CTX_set_options(ctx, SSL_OP_NO_TICKET);
    316 
    317 	if (SSL_CTX_use_certificate_chain_file(ctx, tlsoptions->certificate_file) <= 0)
    318 	{
    319 		unreal_log(ULOG_ERROR, "config", "TLS_LOAD_FAILED", NULL,
    320 		           "Failed to load TLS certificate $filename\n$tls_error.all",
    321 		           log_data_string("filename", tlsoptions->certificate_file),
    322 		           log_data_tls_error());
    323 		goto fail;
    324 	}
    325 
    326 	if (SSL_CTX_use_PrivateKey_file(ctx, tlsoptions->key_file, SSL_FILETYPE_PEM) <= 0)
    327 	{
    328 		unreal_log(ULOG_ERROR, "config", "TLS_LOAD_FAILED", NULL,
    329 		           "Failed to load TLS private key $filename\n$tls_error.all",
    330 		           log_data_string("filename", tlsoptions->key_file),
    331 		           log_data_tls_error());
    332 		goto fail;
    333 	}
    334 
    335 	if (!SSL_CTX_check_private_key(ctx))
    336 	{
    337 		unreal_log(ULOG_ERROR, "config", "TLS_LOAD_FAILED", NULL,
    338 		           "Check for TLS private key failed $filename\n$tls_error.all",
    339 		           log_data_string("filename", tlsoptions->key_file),
    340 		           log_data_tls_error());
    341 		goto fail;
    342 	}
    343 
    344 	if (SSL_CTX_set_cipher_list(ctx, tlsoptions->ciphers) == 0)
    345 	{
    346 		unreal_log(ULOG_ERROR, "config", "TLS_INVALID_CIPHERS_LIST", NULL,
    347 		           "Failed to set TLS cipher list '$tls_ciphers_list'\n$tls_error.all",
    348 		           log_data_string("tls_ciphers_list", tlsoptions->ciphers),
    349 		           log_data_tls_error());
    350 		goto fail;
    351 	}
    352 
    353 #ifdef SSL_OP_NO_TLSv1_3
    354 	if (SSL_CTX_set_ciphersuites(ctx, tlsoptions->ciphersuites) == 0)
    355 	{
    356 		unreal_log(ULOG_ERROR, "config", "TLS_INVALID_CIPHERSUITES_LIST", NULL,
    357 		           "Failed to set TLS ciphersuites list '$tls_ciphersuites_list'\n$tls_error.all",
    358 		           log_data_string("tls_ciphersuites_list", tlsoptions->ciphersuites),
    359 		           log_data_tls_error());
    360 		goto fail;
    361 	}
    362 #endif
    363 
    364 	if (!cipher_check(ctx, &errstr))
    365 	{
    366 		unreal_log(ULOG_ERROR, "config", "TLS_CIPHER_CHECK_FAILED", NULL,
    367 		           "There is a problem with your TLS 'ciphers' configuration setting: $quality_check_error\n"
    368 		           "Remove the ciphers setting from your configuration file to use safer defaults, or change the cipher setting.",
    369 		           log_data_string("quality_check_error", errstr));
    370 		goto fail;
    371 	}
    372 
    373 	if (!certificate_quality_check(ctx, &errstr))
    374 	{
    375 		unreal_log(ULOG_ERROR, "config", "TLS_CERTIFICATE_CHECK_FAILED", NULL,
    376 		           "There is a problem with your TLS certificate '$filename': $quality_check_error\n"
    377 		           "If you use the standard UnrealIRCd certificates then you can simply run 'make pem' and 'make install' "
    378 		           "from your UnrealIRCd source directory (eg: ~/unrealircd-6.X.Y/) to create and install new certificates",
    379 		           log_data_string("filename", tlsoptions->certificate_file),
    380 		           log_data_string("quality_check_error", errstr));
    381 		goto fail;
    382 	}
    383 
    384 	if (server)
    385 		SSL_CTX_set_options(ctx, SSL_OP_CIPHER_SERVER_PREFERENCE);
    386 
    387 	if (tlsoptions->trusted_ca_file)
    388 	{
    389 		if (!SSL_CTX_load_verify_locations(ctx, tlsoptions->trusted_ca_file, NULL))
    390 		{
    391 			unreal_log(ULOG_ERROR, "config", "TLS_LOAD_FAILED", NULL,
    392 				   "Failed to load trusted-ca-file $filename\n$tls_error.all",
    393 				   log_data_string("filename", tlsoptions->trusted_ca_file),
    394 				   log_data_tls_error());
    395 			goto fail;
    396 		}
    397 	}
    398 
    399 	if (server)
    400 	{
    401 #if defined(SSL_CTX_set_ecdh_auto)
    402 		/* OpenSSL 1.0.x requires us to explicitly turn this on */
    403 		SSL_CTX_set_ecdh_auto(ctx, 1);
    404 #elif OPENSSL_VERSION_NUMBER < 0x10100000L
    405 		/* Even older versions require require setting a fixed curve.
    406 		 * NOTE: Don't be confused by the <1.1.x check.
    407 		 * Yes, it must be there. Do not remove it!
    408 		 */
    409 		SSL_CTX_set_tmp_ecdh(ctx, EC_KEY_new_by_curve_name(NID_X9_62_prime256v1));
    410 #else
    411 		/* If we end up here we don't have SSL_CTX_set_ecdh_auto
    412 		 * and we are on OpenSSL 1.1.0 or later. We don't need to
    413 		 * do anything then, since auto ecdh is the default.
    414 		 */
    415 #endif
    416 		/* Let's see if we need to (and can) set specific curves */
    417 		if (tlsoptions->ecdh_curves)
    418 		{
    419 #ifdef HAS_SSL_CTX_SET1_CURVES_LIST
    420 			if (!SSL_CTX_set1_curves_list(ctx, tlsoptions->ecdh_curves))
    421 			{
    422 				unreal_log(ULOG_ERROR, "config", "TLS_INVALID_ECDH_CURVES_LIST", NULL,
    423 					   "Failed to set ecdh-curves '$ecdh_curves_list'\n$tls_error.all\n"
    424 					   "HINT: o get a list of supported curves with the appropriate names, "
    425 					   "run 'openssl ecparam -list_curves' on the server. "
    426 					   "Separate multiple curves by colon, for example: "
    427 					   "ecdh-curves \"secp521r1:secp384r1\".",
    428 					   log_data_string("ecdh_curves_list", tlsoptions->ecdh_curves),
    429 					   log_data_tls_error());
    430 				goto fail;
    431 			}
    432 #else
    433 			/* We try to avoid this in the config code, but better have
    434 			 * it here too than be sorry if someone screws up:
    435 			 */
    436 			unreal_log(ULOG_ERROR, "config", "BUG_ECDH_CURVES", NULL,
    437 			           "ecdh-curves specified but not supported by library -- BAD!");
    438 			goto fail;
    439 #endif
    440 		}
    441 		/* We really want the ECDHE/ECDHE to be generated per-session.
    442 		 * Added in 2015 for safety. Seems OpenSSL was smart enough
    443 		 * to make this the default in 2016 after a security advisory.
    444 		 */
    445 		SSL_CTX_set_options(ctx, SSL_OP_SINGLE_ECDH_USE|SSL_OP_SINGLE_DH_USE);
    446 	}
    447 
    448 	if (server)
    449 	{
    450 		SSL_CTX_set_tlsext_servername_callback(ctx, ssl_hostname_callback);
    451 	}
    452 
    453 	return ctx;
    454 fail:
    455 	SSL_CTX_free(ctx);
    456 	return NULL;
    457 }
    458 
    459 #if OPENSSL_VERSION_NUMBER >= 0x30000000L
    460 MODVAR EVP_MD *sha256_function; /**< SHA256 function for EVP_DigestInit_ex() call */
    461 MODVAR EVP_MD *sha1_function; /**< SHA1 function for EVP_DigestInit_ex() call */
    462 MODVAR EVP_MD *md5_function; /**< MD5 function for EVP_DigestInit_ex() call */
    463 #endif
    464 
    465 /** Early initalization of TLS subsystem - called on startup */
    466 int early_init_tls(void)
    467 {
    468 	SSL_load_error_strings();
    469 	SSLeay_add_ssl_algorithms();
    470 
    471 	/* This is used to track (SSL *) <--> (Client *) relationships: */
    472 	tls_client_index = SSL_get_ex_new_index(0, "tls_client", NULL, NULL, NULL);
    473 
    474 #if OPENSSL_VERSION_NUMBER >= 0x30000000L
    475 	sha256_function = EVP_MD_fetch(NULL, "SHA2-256", NULL);
    476 	if (!sha256_function)
    477 	{
    478 		fprintf(stderr, "Could not find SHA256 algorithm in TLS library\n");
    479 		exit(6);
    480 	}
    481 
    482 	sha1_function = EVP_MD_fetch(NULL, "SHA1", NULL);
    483 	if (!sha1_function)
    484 	{
    485 		fprintf(stderr, "Could not find SHA1 algorithm in TLS library\n");
    486 		exit(6);
    487 	}
    488 
    489 	md5_function = EVP_MD_fetch(NULL, "MD5", NULL);
    490 	if (!md5_function)
    491 	{
    492 		fprintf(stderr, "Could not find MD5 algorithm in TLS library\n");
    493 		exit(6);
    494 	}
    495 #endif
    496 	return 1;
    497 }
    498 
    499 /** Initialize the server and client contexts.
    500  * This is only possible after reading the configuration file.
    501  */
    502 int init_tls(void)
    503 {
    504 	ctx_server = init_ctx(iConf.tls_options, 1);
    505 	if (!ctx_server)
    506 		return 0;
    507 	ctx_client = init_ctx(iConf.tls_options, 0);
    508 	if (!ctx_client)
    509 		return 0;
    510 	return 1;
    511 }
    512 
    513 /** Reinitialize TLS server and client contexts - after REHASH -tls
    514  */
    515 int reinit_tls(void)
    516 {
    517 	SSL_CTX *tmp;
    518 	ConfigItem_listen *listen;
    519 	ConfigItem_sni *sni;
    520 	ConfigItem_link *link;
    521 
    522 	tmp = init_ctx(iConf.tls_options, 1);
    523 	if (!tmp)
    524 	{
    525 		unreal_log(ULOG_ERROR, "config", "TLS_RELOAD_FAILED", NULL,
    526 		           "TLS Reload failed. See previous errors.");
    527 		return 0;
    528 	}
    529 	if (ctx_server)
    530 		SSL_CTX_free(ctx_server);
    531 	ctx_server = tmp; /* activate */
    532 	
    533 	tmp = init_ctx(iConf.tls_options, 0);
    534 	if (!tmp)
    535 	{
    536 		unreal_log(ULOG_ERROR, "config", "TLS_RELOAD_FAILED", NULL,
    537 		           "TLS Reload failed at client context. See previous errors.");
    538 		return 0;
    539 	}
    540 	if (ctx_client)
    541 		SSL_CTX_free(ctx_client);
    542 	ctx_client = tmp; /* activate */
    543 
    544 	/* listen::tls-options.... */
    545 	for (listen = conf_listen; listen; listen = listen->next)
    546 	{
    547 		if (listen->tls_options)
    548 		{
    549 			tmp = init_ctx(listen->tls_options, 1);
    550 			if (!tmp)
    551 			{
    552 				unreal_log(ULOG_ERROR, "config", "TLS_RELOAD_FAILED", NULL,
    553 					   "TLS Reload failed at listen::tls-options. See previous errors.");
    554 				return 0;
    555 			}
    556 			if (listen->ssl_ctx)
    557 				SSL_CTX_free(listen->ssl_ctx);
    558 			listen->ssl_ctx = tmp; /* activate */
    559 		}
    560 	}
    561 
    562 	/* sni::tls-options.... */
    563 	for (sni = conf_sni; sni; sni = sni->next)
    564 	{
    565 		if (sni->tls_options)
    566 		{
    567 			tmp = init_ctx(sni->tls_options, 1);
    568 			if (!tmp)
    569 			{
    570 				unreal_log(ULOG_ERROR, "config", "TLS_RELOAD_FAILED", NULL,
    571 					   "TLS Reload failed at sni::tls-options. See previous errors.");
    572 				return 0;
    573 			}
    574 			if (sni->ssl_ctx)
    575 				SSL_CTX_free(sni->ssl_ctx);
    576 			sni->ssl_ctx = tmp; /* activate */
    577 		}
    578 	}
    579 
    580 	/* link::outgoing::tls-options.... */
    581 	for (link = conf_link; link; link = link->next)
    582 	{
    583 		if (link->tls_options)
    584 		{
    585 			tmp = init_ctx(link->tls_options, 0);
    586 			if (!tmp)
    587 			{
    588 				unreal_log(ULOG_ERROR, "config", "TLS_RELOAD_FAILED", NULL,
    589 					   "TLS Reload failed at link $servername due to outgoing::tls-options. See previous errors.",
    590 					   log_data_string("servername", link->servername));
    591 				return 0;
    592 			}
    593 			if (link->ssl_ctx)
    594 				SSL_CTX_free(link->ssl_ctx);
    595 			link->ssl_ctx = tmp; /* activate */
    596 		}
    597 	}
    598 
    599 	return 1;
    600 }
    601 
    602 /** Set SSL connection as nonblocking */
    603 void SSL_set_nonblocking(SSL *s)
    604 {
    605 	BIO_set_nbio(SSL_get_rbio(s),1);
    606 	BIO_set_nbio(SSL_get_wbio(s),1);
    607 }
    608 
    609 /** Get TLS ciphersuite */
    610 const char *tls_get_cipher(Client *client)
    611 {
    612 	static char buf[256];
    613 	const char *cached;
    614 
    615 	cached = moddata_client_get(client, "tls_cipher");
    616 	if (cached)
    617 		return cached;
    618 
    619 	if (!MyConnect(client) || !client->local->ssl)
    620 		return NULL;
    621 
    622 	buf[0] = '\0';
    623 	strlcpy(buf, SSL_get_version(client->local->ssl), sizeof(buf));
    624 	strlcat(buf, "-", sizeof(buf));
    625 	strlcat(buf, SSL_get_cipher(client->local->ssl), sizeof(buf));
    626 
    627 	return buf;
    628 }
    629 
    630 /** Get the applicable ::tls-options block for this local client,
    631  * which may be defined in the link block, listen block, or set block.
    632  */
    633 TLSOptions *get_tls_options_for_client(Client *client)
    634 {
    635 	if (!client->local)
    636 		return NULL;
    637 	if (client->server && client->server->conf && client->server->conf->tls_options)
    638 		return client->server->conf->tls_options;
    639 	if (client->local && client->local->listener && client->local->listener->tls_options)
    640 		return client->local->listener->tls_options;
    641 	return iConf.tls_options;
    642 }
    643 
    644 /** Outgoing TLS connect (read: handshake) to another server. */
    645 void unreal_tls_client_handshake(int fd, int revents, void *data)
    646 {
    647 	Client *client = data;
    648 	SSL_CTX *ctx = (client->server && client->server->conf && client->server->conf->ssl_ctx) ? client->server->conf->ssl_ctx : ctx_client;
    649 	TLSOptions *tlsoptions = get_tls_options_for_client(client);
    650 
    651 	if (!ctx)
    652 	{
    653 		unreal_log(ULOG_ERROR, "config", "TLS_CREATE_SESSION_FAILED", NULL,
    654 		           "Could not start TLS client handshake (no ctx?): TLS was possibly not loaded correctly on this server!?\n$tls_error.all",
    655 		           log_data_tls_error());
    656 		return;
    657 	}
    658 
    659 	client->local->ssl = SSL_new(ctx);
    660 	if (!client->local->ssl)
    661 	{
    662 		unreal_log(ULOG_ERROR, "config", "TLS_CREATE_SESSION_FAILED", NULL,
    663 		           "Could not start TLS client handshake: TLS was possibly not loaded correctly on this server!?\n$tls_error.all",
    664 		           log_data_tls_error());
    665 		return;
    666 	}
    667 
    668 	SSL_set_fd(client->local->ssl, client->local->fd);
    669 	SSL_set_connect_state(client->local->ssl);
    670 	SSL_set_nonblocking(client->local->ssl);
    671 
    672 	if (tlsoptions->renegotiate_bytes > 0)
    673 	{
    674 		BIO_set_ssl_renegotiate_bytes(SSL_get_rbio(client->local->ssl), tlsoptions->renegotiate_bytes);
    675 		BIO_set_ssl_renegotiate_bytes(SSL_get_wbio(client->local->ssl), tlsoptions->renegotiate_bytes);
    676 	}
    677 
    678 	if (tlsoptions->renegotiate_timeout > 0)
    679 	{
    680 		BIO_set_ssl_renegotiate_timeout(SSL_get_rbio(client->local->ssl), tlsoptions->renegotiate_timeout);
    681 		BIO_set_ssl_renegotiate_timeout(SSL_get_wbio(client->local->ssl), tlsoptions->renegotiate_timeout);
    682 	}
    683 
    684 	if (client->server && client->server->conf)
    685 	{
    686 		/* Client: set hostname for SNI */
    687 		SSL_set_tlsext_host_name(client->local->ssl, client->server->conf->servername);
    688 	}
    689 
    690 	SetTLS(client);
    691 
    692 	switch (unreal_tls_connect(client, fd))
    693 	{
    694 		case -1:
    695 			SSL_set_shutdown(client->local->ssl, SSL_RECEIVED_SHUTDOWN);
    696 			SSL_smart_shutdown(client->local->ssl);
    697 			SSL_free(client->local->ssl);
    698 			client->local->ssl = NULL;
    699 			ClearTLS(client);
    700 			SetDeadSocket(client);
    701 			fd_close(fd);
    702 			fd_unnotify(fd);
    703 			client->local->fd = -1;
    704 			--OpenFiles;
    705 			return;
    706 		case 0: 
    707 			SetTLSConnectHandshake(client);
    708 			return;
    709 		case 1:
    710 			return;
    711 		default:
    712 			return;
    713 	}
    714 
    715 }
    716 
    717 /** Called by I/O engine to (re)try accepting an TLS connection */
    718 static void unreal_tls_accept_retry(int fd, int revents, void *data)
    719 {
    720 	Client *client = data;
    721 	unreal_tls_accept(client, fd);
    722 }
    723 
    724 /** Accept an TLS connection - that is: do the TLS handshake */
    725 int unreal_tls_accept(Client *client, int fd)
    726 {
    727 	int ssl_err;
    728 
    729 #ifdef MSG_PEEK
    730 	if (!IsNextCall(client))
    731 	{
    732 		char buf[1024];
    733 		int n;
    734 		
    735 		n = recv(fd, buf, sizeof(buf), MSG_PEEK);
    736 		if ((n >= 8) && !strncmp(buf, "STARTTLS", 8))
    737 		{
    738 			char buf[512];
    739 			snprintf(buf, sizeof(buf),
    740 				"ERROR :STARTTLS received but this is a TLS-only port. Check your connect settings. "
    741 				"If this is a server linking in then add 'tls' in your link::outgoing::options block.\r\n");
    742 			(void)send(fd, buf, strlen(buf), 0);
    743 			return fatal_tls_error(SSL_ERROR_SSL, FUNC_TLS_ACCEPT, ERRNO, client);
    744 		}
    745 		if ((n >= 4) && (!strncmp(buf, "USER", 4) || !strncmp(buf, "NICK", 4) || !strncmp(buf, "PASS", 4) || !strncmp(buf, "CAP ", 4)))
    746 		{
    747 			char buf[512];
    748 			snprintf(buf, sizeof(buf),
    749 				"ERROR :NON-TLS command received on TLS-only port. Check your connection settings.\r\n");
    750 			(void)send(fd, buf, strlen(buf), 0);
    751 			return fatal_tls_error(SSL_ERROR_SSL, FUNC_TLS_ACCEPT, ERRNO, client);
    752 		}
    753 		if ((n >= 8) && (!strncmp(buf, "PROTOCTL", 8) || !strncmp(buf, "SERVER", 6)))
    754 		{
    755 			char buf[512];
    756 			snprintf(buf, sizeof(buf),
    757 				"ERROR :NON-TLS command received on TLS-only port. Check your connection settings.\r\n");
    758 			(void)send(fd, buf, strlen(buf), 0);
    759 			return fatal_tls_error(SSL_ERROR_SSL, FUNC_TLS_ACCEPT, ERRNO, client);
    760 		}
    761 		if (n > 0)
    762 			SetNextCall(client);
    763 	}
    764 #endif
    765 	if ((ssl_err = SSL_accept(client->local->ssl)) <= 0)
    766 	{
    767 		switch (ssl_err = SSL_get_error(client->local->ssl, ssl_err))
    768 		{
    769 			case SSL_ERROR_SYSCALL:
    770 				if (ERRNO == P_EINTR || ERRNO == P_EWOULDBLOCK || ERRNO == P_EAGAIN)
    771 				{
    772 					return 1;
    773 				}
    774 				return fatal_tls_error(ssl_err, FUNC_TLS_ACCEPT, ERRNO, client);
    775 			case SSL_ERROR_WANT_READ:
    776 				fd_setselect(fd, FD_SELECT_READ, unreal_tls_accept_retry, client);
    777 				fd_setselect(fd, FD_SELECT_WRITE, NULL, client);
    778 				return 1;
    779 			case SSL_ERROR_WANT_WRITE:
    780 				fd_setselect(fd, FD_SELECT_READ, NULL, client);
    781 				fd_setselect(fd, FD_SELECT_WRITE, unreal_tls_accept_retry, client);
    782 				return 1;
    783 			default:
    784 				return fatal_tls_error(ssl_err, FUNC_TLS_ACCEPT, ERRNO, client);
    785 		}
    786 		/* NOTREACHED */
    787 		return -1;
    788 	}
    789 
    790 	client->local->listener->start_handshake(client);
    791 
    792 	return 1;
    793 }
    794 
    795 /** Called by the I/O engine to (re)try to connect to a remote host */
    796 static void unreal_tls_connect_retry(int fd, int revents, void *data)
    797 {
    798 	Client *client = data;
    799 	unreal_tls_connect(client, fd);
    800 }
    801 
    802 /** Connect to a remote host - that is: connect and do the TLS handshake */
    803 int unreal_tls_connect(Client *client, int fd)
    804 {
    805 	int ssl_err;
    806 
    807 	if ((ssl_err = SSL_connect(client->local->ssl)) <= 0)
    808 	{
    809 		ssl_err = SSL_get_error(client->local->ssl, ssl_err);
    810 		switch(ssl_err)
    811 		{
    812 			case SSL_ERROR_SYSCALL:
    813 				if (ERRNO == P_EINTR || ERRNO == P_EWOULDBLOCK || ERRNO == P_EAGAIN)
    814 				{
    815 					/* Hmmm. This implementation is different than in unreal_tls_accept().
    816 					 * One of them must be wrong -- better check! (TODO)
    817 					 */
    818 					fd_setselect(fd, FD_SELECT_READ|FD_SELECT_WRITE, unreal_tls_connect_retry, client);
    819 					return 0;
    820 				}
    821 				return fatal_tls_error(ssl_err, FUNC_TLS_CONNECT, ERRNO, client);
    822 			case SSL_ERROR_WANT_READ:
    823 				fd_setselect(fd, FD_SELECT_READ, unreal_tls_connect_retry, client);
    824 				fd_setselect(fd, FD_SELECT_WRITE, NULL, client);
    825 				return 0;
    826 			case SSL_ERROR_WANT_WRITE:
    827 				fd_setselect(fd, FD_SELECT_READ, NULL, client);
    828 				fd_setselect(fd, FD_SELECT_WRITE, unreal_tls_connect_retry, client);
    829 				return 0;
    830 			default:
    831 				return fatal_tls_error(ssl_err, FUNC_TLS_CONNECT, ERRNO, client);
    832 		}
    833 		/* NOTREACHED */
    834 		return -1;
    835 	}
    836 
    837 	fd_setselect(fd, FD_SELECT_READ | FD_SELECT_WRITE, NULL, client);
    838 	completed_connection(fd, FD_SELECT_READ | FD_SELECT_WRITE, client);
    839 
    840 	return 1;
    841 }
    842 
    843 /** Shutdown a TLS connection (gracefully) */
    844 int SSL_smart_shutdown(SSL *ssl)
    845 {
    846 	char i;
    847 	int rc = 0;
    848 
    849 	for(i = 0; i < 4; i++)
    850 	{
    851 		if ((rc = SSL_shutdown(ssl)))
    852 			break;
    853 	}
    854 	return rc;
    855 }
    856 
    857 /**
    858  * Report a fatal TLS error and disconnect the associated client.
    859  *
    860  * @param ssl_error The error as from OpenSSL.
    861  * @param where The location, one of the SAFE_SSL_* defines.
    862  * @param my_errno A preserved value of errno to pass to ssl_error_str().
    863  * @param client The client the error is associated with.
    864  */
    865 static int fatal_tls_error(int ssl_error, int where, int my_errno, Client *client)
    866 {
    867 	/* don`t alter ERRNO */
    868 	int errtmp = ERRNO;
    869 	const char *ssl_errstr, *ssl_func;
    870 	unsigned long additional_errno = ERR_get_error();
    871 	char additional_info[256];
    872 	char buf[512];
    873 	const char *one, *two;
    874 
    875 	if (IsDeadSocket(client))
    876 		return -1;
    877 
    878 	switch(where)
    879 	{
    880 		case FUNC_TLS_READ:
    881 			ssl_func = "SSL_read()";
    882 			break;
    883 		case FUNC_TLS_WRITE:
    884 			ssl_func = "SSL_write()";
    885 			break;
    886 		case FUNC_TLS_ACCEPT:
    887 			ssl_func = "SSL_accept()";
    888 			break;
    889 		case FUNC_TLS_CONNECT:
    890 			ssl_func = "SSL_connect()";
    891 			break;
    892 		default:
    893 			ssl_func = "undefined SSL func";
    894 	}
    895 
    896 #if OPENSSL_VERSION_NUMBER >= 0x30000000L
    897 	/* Fetch additional error information from OpenSSL 3.0.0+ */
    898 	two = ERR_reason_error_string(additional_errno);
    899 	if (two && *two)
    900 	{
    901 		snprintf(additional_info, sizeof(additional_info), ": %s", two);
    902 	} else {
    903 		*additional_info = '\0';
    904 	}
    905 #else
    906 	/* Fetch additional error information from OpenSSL. This is new as of Nov 2017 (4.0.16+) */
    907 	one = ERR_func_error_string(additional_errno);
    908 	two = ERR_reason_error_string(additional_errno);
    909 	if (one && *one && two && *two)
    910 	{
    911 		snprintf(additional_info, sizeof(additional_info), ": %s: %s", one, two);
    912 	} else {
    913 		*additional_info = '\0';
    914 	}
    915 #endif
    916 
    917 	ssl_errstr = ssl_error_str(ssl_error, my_errno);
    918 
    919 	SetDeadSocket(client);
    920 	unreal_log(ULOG_DEBUG, "tls", "DEBUG_TLS_FATAL_ERROR", client,
    921 		   "Exiting TLS client $client.details: $tls_function: $tls_error_string: $tls_additional_info",
    922 		   log_data_string("tls_function", ssl_func),
    923 		   log_data_string("tls_error_string", ssl_errstr),
    924 		   log_data_string("tls_additional_info", additional_info));
    925 
    926 	if (where == FUNC_TLS_CONNECT)
    927 	{
    928 		char extra[256];
    929 		*extra = '\0';
    930 		if (ssl_error == SSL_ERROR_SSL)
    931 		{
    932 			snprintf(extra, sizeof(extra),
    933 			         ". Please verify that listen::options::ssl is enabled on port %d in %s's configuration file.",
    934 			         (client->server && client->server->conf) ? client->server->conf->outgoing.port : -1,
    935 			         client->name);
    936 		}
    937 		snprintf(buf, sizeof(buf), "%s: %s%s%s", ssl_func, ssl_errstr, additional_info, extra);
    938 		lost_server_link(client, buf);
    939 	} else
    940 	if (IsServer(client) || (client->server && client->server->conf))
    941 	{
    942 		/* Either a trusted fully established server (incoming) or an outgoing server link (established or not) */
    943 		snprintf(buf, sizeof(buf), "%s: %s%s", ssl_func, ssl_errstr, additional_info);
    944 		lost_server_link(client, buf);
    945 	}
    946 
    947 	if (errtmp)
    948 	{
    949 		SET_ERRNO(errtmp);
    950 		safe_strdup(client->local->error_str, strerror(errtmp));
    951 	} else {
    952 		SET_ERRNO(P_EIO);
    953 		safe_strdup(client->local->error_str, ssl_errstr);
    954 	}
    955 
    956 	/* deregister I/O notification since we don't care anymore. the actual closing of socket will happen later. */
    957 	if (client->local->fd >= 0)
    958 		fd_unnotify(client->local->fd);
    959 
    960 	return -1;
    961 }
    962 
    963 /** Do a TLS handshake after a STARTTLS, as a client */
    964 int client_starttls(Client *client)
    965 {
    966 	if ((client->local->ssl = SSL_new(ctx_client)) == NULL)
    967 		goto fail_starttls;
    968 
    969 	SetTLS(client);
    970 
    971 	SSL_set_fd(client->local->ssl, client->local->fd);
    972 	SSL_set_nonblocking(client->local->ssl);
    973 
    974 	if (client->server && client->server->conf)
    975 	{
    976 		/* Client: set hostname for SNI */
    977 		SSL_set_tlsext_host_name(client->local->ssl, client->server->conf->servername);
    978 	}
    979 
    980 	if (unreal_tls_connect(client, client->local->fd) < 0)
    981 	{
    982 		SSL_set_shutdown(client->local->ssl, SSL_RECEIVED_SHUTDOWN);
    983 		SSL_smart_shutdown(client->local->ssl);
    984 		SSL_free(client->local->ssl);
    985 		goto fail_starttls;
    986 	}
    987 
    988 	/* HANDSHAKE IN PROGRESS */
    989 	return 0;
    990 fail_starttls:
    991 	/* Failure */
    992 	sendnumeric(client, ERR_STARTTLS, "STARTTLS failed");
    993 	client->local->ssl = NULL;
    994 	ClearTLS(client);
    995 	SetUnknown(client);
    996 	return 0; /* hm. we allow to continue anyway. not sure if we want that. */
    997 }
    998 
    999 /** Find the appropriate TLSOptions structure for a client.
   1000  * NOTE: The default global TLS options will be returned if not found,
   1001  *       or NULL if no such options are available (unlikely, but possible?).
   1002  */
   1003 TLSOptions *FindTLSOptionsForUser(Client *client)
   1004 {
   1005 	ConfigItem_sni *sni;
   1006 	TLSOptions *sslopt = iConf.tls_options; /* default */
   1007 	
   1008 	if (!MyConnect(client) || !IsSecure(client))
   1009 		return NULL;
   1010 
   1011 	/* Different sts-policy depending on SNI: */
   1012 	if (client->local->sni_servername)
   1013 	{
   1014 		sni = find_sni(client->local->sni_servername);
   1015 		if (sni)
   1016 		{
   1017 			sslopt = sni->tls_options;
   1018 		}
   1019 		/* It is perfectly possible that 'name' is not found and 'sni' is NULL,
   1020 		 * if a client used a hostname which we do not know about (eg: 'dummy').
   1021 		 */
   1022 	}
   1023 
   1024 	return sslopt;
   1025 }
   1026 
   1027 /** Verify certificate and make sure the certificate is valid for 'hostname'.
   1028  * @param ssl: The SSL structure of the client or server
   1029  * @param hostname: The hostname we should expect the certificate to be valid for
   1030  * @param errstr: Error will be stored in here (optional)
   1031  * @returns Returns 1 on success and 0 on error.
   1032  */
   1033 int verify_certificate(SSL *ssl, const char *hostname, char **errstr)
   1034 {
   1035 	static char buf[512];
   1036 	X509 *cert;
   1037 	int n;
   1038 
   1039 	*buf = '\0';
   1040 
   1041 	if (errstr)
   1042 		*errstr = NULL; /* default */
   1043 
   1044 	if (!ssl)
   1045 	{
   1046 		strlcpy(buf, "Not using TLS", sizeof(buf));
   1047 		if (errstr)
   1048 			*errstr = buf;
   1049 		return 0; /* Cannot verify a non-TLS connection */
   1050 	}
   1051 
   1052 	if (SSL_get_verify_result(ssl) != X509_V_OK)
   1053 	{
   1054 		// FIXME: there are actually about 25+ different possible errors,
   1055 		// this is only the most common one:
   1056 		strlcpy(buf, "Certificate is not issued by a trusted Certificate Authority", sizeof(buf));
   1057 		if (errstr)
   1058 			*errstr = buf;
   1059 		return 0; /* Certificate verify failed */
   1060 	}
   1061 
   1062 	/* Now verify if the name of the certificate matches hostname */
   1063 	cert = SSL_get_peer_certificate(ssl);
   1064 
   1065 	if (!cert)
   1066 	{
   1067 		strlcpy(buf, "No certificate provided", sizeof(buf));
   1068 		if (errstr)
   1069 			*errstr = buf;
   1070 		return 0;
   1071 	}
   1072 
   1073 #ifdef HAS_X509_check_host
   1074 	n = X509_check_host(cert, hostname, strlen(hostname), 0, NULL);
   1075 	X509_free(cert);
   1076 	if (n == 1)
   1077 		return 1; /* Hostname matched. All tests passed. */
   1078 #else
   1079 	/* Fallback code for OpenSSL <1.0.2.
   1080 	 * Wait... 1.0.1 is out of support since January 2017,
   1081 	 * so why do we even support that in 2023 ?
   1082 	 * An well, TODO: ditch this old TLS support in next major UnrealIRCd
   1083 	 * along with all the other old OpenSSL checks in this tls.c :D
   1084 	 * XXX: Actually our HAS_X509_check_host includes openssl/x509v3.h
   1085 	 * which does not exist in 1.0.2 yet either (it is openssl/x509.h there).
   1086 	 * And 1.0.2 is out of support since January 1st, 2020... just saying.
   1087 	 */
   1088 	n = validate_hostname(hostname, cert);
   1089 	X509_free(cert);
   1090 	if (n == MatchFound)
   1091 		return 1; /* Hostname matched. All tests passed. */
   1092 #endif
   1093 
   1094 	/* Certificate is verified but is issued for a different hostname */
   1095 	snprintf(buf, sizeof(buf), "Certificate '%s' is not valid for hostname '%s'",
   1096 		certificate_name(ssl), hostname);
   1097 	if (errstr)
   1098 		*errstr = buf;
   1099 	return 0;
   1100 }
   1101 
   1102 /** Grab the certificate name */
   1103 const char *certificate_name(SSL *ssl)
   1104 {
   1105 	static char buf[384];
   1106 	X509 *cert;
   1107 	X509_NAME *n;
   1108 
   1109 	if (!ssl)
   1110 		return NULL;
   1111 
   1112 	cert = SSL_get_peer_certificate(ssl);
   1113 	if (!cert)
   1114 		return NULL;
   1115 
   1116 	n = X509_get_subject_name(cert);
   1117 	if (n)
   1118 	{
   1119 		buf[0] = '\0';
   1120 		X509_NAME_oneline(n, buf, sizeof(buf));
   1121 		X509_free(cert);
   1122 		return buf;
   1123 	} else {
   1124 		X509_free(cert);
   1125 		return NULL;
   1126 	}
   1127 }
   1128 
   1129 /** Check if any weak ciphers are in use */
   1130 int cipher_check(SSL_CTX *ctx, char **errstr)
   1131 {
   1132 	SSL *ssl;
   1133 	static char errbuf[256];
   1134 	int i;
   1135 	const char *cipher;
   1136 
   1137 	*errbuf = '\0'; // safety
   1138 
   1139 	if (errstr)
   1140 		*errstr = errbuf;
   1141 
   1142 	/* there isn't an SSL_CTX_get_cipher_list() unfortunately. */
   1143 	ssl = SSL_new(ctx);
   1144 	if (!ssl)
   1145 	{
   1146 		snprintf(errbuf, sizeof(errbuf), "Could not create TLS structure");
   1147 		return 0;
   1148 	}
   1149 
   1150 	/* Very weak */
   1151 	i = 0;
   1152 	while ((cipher = SSL_get_cipher_list(ssl, i++)))
   1153 	{
   1154 		if (strstr(cipher, "DES-"))
   1155 		{
   1156 			snprintf(errbuf, sizeof(errbuf), "DES is enabled but is a weak cipher");
   1157 			SSL_free(ssl);
   1158 			return 0;
   1159 		}
   1160 		else if (strstr(cipher, "3DES-"))
   1161 		{
   1162 			snprintf(errbuf, sizeof(errbuf), "3DES is enabled but is a weak cipher");
   1163 			SSL_free(ssl);
   1164 			return 0;
   1165 		}
   1166 		else if (strstr(cipher, "RC4-"))
   1167 		{
   1168 			snprintf(errbuf, sizeof(errbuf), "RC4 is enabled but is a weak cipher");
   1169 			SSL_free(ssl);
   1170 			return 0;
   1171 		}
   1172 		else if (strstr(cipher, "NULL-"))
   1173 		{
   1174 			snprintf(errbuf, sizeof(errbuf), "NULL cipher provides no encryption");
   1175 			SSL_free(ssl);
   1176 			return 0;
   1177 		}
   1178 	}
   1179 
   1180 	SSL_free(ssl);
   1181 	return 1;
   1182 }
   1183 
   1184 /** Check if a certificate (or actually: key) is weak */
   1185 int certificate_quality_check(SSL_CTX *ctx, char **errstr)
   1186 {
   1187 #if OPENSSL_VERSION_NUMBER < 0x30000000L
   1188 	// FIXME: this only works on OpenSSL <3.0.0
   1189 	SSL *ssl;
   1190 	X509 *cert;
   1191 	EVP_PKEY *public_key;
   1192 	RSA *rsa_key;
   1193 	int key_length;
   1194 	static char errbuf[256];
   1195 
   1196 	*errbuf = '\0'; // safety
   1197 
   1198 	if (errstr)
   1199 		*errstr = errbuf;
   1200 
   1201 	/* there isn't an SSL_CTX_get_cipher_list() unfortunately. */
   1202 	ssl = SSL_new(ctx);
   1203 	if (!ssl)
   1204 	{
   1205 		snprintf(errbuf, sizeof(errbuf), "Could not create TLS structure");
   1206 		return 0;
   1207 	}
   1208 
   1209 	cert = SSL_get_certificate(ssl);
   1210 	if (!cert)
   1211 	{
   1212 		snprintf(errbuf, sizeof(errbuf), "Could not retrieve TLS certificate");
   1213 		SSL_free(ssl);
   1214 		return 0;
   1215 	}
   1216 
   1217 	public_key = X509_get_pubkey(cert);
   1218 	if (!public_key)
   1219 	{
   1220 		/* Now this is unexpected.. */
   1221 		config_warn("certificate_quality_check(): could not check public key !? BUG?");
   1222 		SSL_free(ssl);
   1223 		return 1;
   1224 	}
   1225 	rsa_key = EVP_PKEY_get1_RSA(public_key);
   1226 	if (!rsa_key)
   1227 	{
   1228 		/* Not an RSA key, then we are done. */
   1229 		EVP_PKEY_free(public_key);
   1230 		SSL_free(ssl);
   1231 		return 1;
   1232 	}
   1233 	key_length = RSA_size(rsa_key) * 8;
   1234 
   1235 	EVP_PKEY_free(public_key);
   1236 	RSA_free(rsa_key);
   1237 	SSL_free(ssl);
   1238 
   1239 	if (key_length < 2048)
   1240 	{
   1241 		snprintf(errbuf, sizeof(errbuf), "Your TLS certificate key is only %d bits, which is insecure", key_length);
   1242 		return 0;
   1243 	}
   1244 
   1245 #endif
   1246 	return 1;
   1247 }
   1248 
   1249 const char *spki_fingerprint_ex(X509 *x509_cert);
   1250 
   1251 /** Return the SPKI Fingerprint for a client.
   1252  *
   1253  * This is basically the same output as
   1254  * openssl x509 -noout -in certificate.pem -pubkey | openssl asn1parse -noout -inform pem -out public.key
   1255  * openssl dgst -sha256 -binary public.key | openssl enc -base64
   1256  * ( from https://tools.ietf.org/html/draft-ietf-websec-key-pinning-21#appendix-A )
   1257  */
   1258 const char *spki_fingerprint(Client *cptr)
   1259 {
   1260 	X509 *x509_cert = NULL;
   1261 	const char *ret;
   1262 
   1263 	if (!MyConnect(cptr) || !cptr->local->ssl)
   1264 		return NULL;
   1265 
   1266 	x509_cert = SSL_get_peer_certificate(cptr->local->ssl);
   1267 	if (!x509_cert)
   1268 		return NULL;
   1269 	ret = spki_fingerprint_ex(x509_cert);
   1270 	X509_free(x509_cert);
   1271 	return ret;
   1272 }
   1273 
   1274 const char *spki_fingerprint_ex(X509 *x509_cert)
   1275 {
   1276 	unsigned char *der_cert = NULL, *p;
   1277 	int der_cert_len, n;
   1278 	static char retbuf[256];
   1279 	unsigned char checksum[SHA256_DIGEST_LENGTH];
   1280 
   1281 	memset(retbuf, 0, sizeof(retbuf));
   1282 
   1283 	der_cert_len = i2d_X509_PUBKEY(X509_get_X509_PUBKEY(x509_cert), NULL);
   1284 	if ((der_cert_len > 0) && (der_cert_len < 16384))
   1285 	{
   1286 		der_cert = p = safe_alloc(der_cert_len);
   1287 		n = i2d_X509_PUBKEY(X509_get_X509_PUBKEY(x509_cert), &p);
   1288 
   1289 		if ((n > 0) && ((p - der_cert) == der_cert_len))
   1290 		{
   1291 			/* The DER encoded SPKI is stored in 'der_cert' with length 'der_cert_len'.
   1292 			 * Now we need to create an SHA256 hash out of it.
   1293 			 */
   1294 			sha256hash_binary(checksum, der_cert, der_cert_len);
   1295 
   1296 			/* And convert the binary to a base64 string... */
   1297 			n = b64_encode(checksum, SHA256_DIGEST_LENGTH, retbuf, sizeof(retbuf));
   1298 			safe_free(der_cert);
   1299 			return retbuf; /* SUCCESS */
   1300 		}
   1301 		safe_free(der_cert);
   1302 	}
   1303 	return NULL;
   1304 }
   1305 
   1306 /** Returns 1 if the client is using an outdated protocol or cipher, 0 otherwise */
   1307 int outdated_tls_client(Client *client)
   1308 {
   1309 	TLSOptions *tlsoptions = get_tls_options_for_client(client);
   1310 	char buf[1024], *name, *p;
   1311 	const char *client_protocol = SSL_get_version(client->local->ssl);
   1312 	const char *client_ciphersuite = SSL_get_cipher(client->local->ssl);
   1313 
   1314 	if (!tlsoptions)
   1315 		return 0; /* odd.. */
   1316 
   1317 	strlcpy(buf, tlsoptions->outdated_protocols, sizeof(buf));
   1318 	for (name = strtoken(&p, buf, ","); name; name = strtoken(&p, NULL, ","))
   1319 	{
   1320 		if (match_simple(name, client_protocol))
   1321 			 return 1; /* outdated protocol */
   1322 	}
   1323 
   1324 	strlcpy(buf, tlsoptions->outdated_ciphers, sizeof(buf));
   1325 	for (name = strtoken(&p, buf, ","); name; name = strtoken(&p, NULL, ","))
   1326 	{
   1327 		if (match_simple(name, client_ciphersuite))
   1328 			return 1; /* outdated cipher */
   1329 	}
   1330 
   1331 	return 0; /* OK, not outdated */
   1332 }
   1333 
   1334 /** Returns the expanded string used for set::outdated-tls-policy::user-message etc. */
   1335 const char *outdated_tls_client_build_string(const char *pattern, Client *client)
   1336 {
   1337 	static char buf[512];
   1338 	const char *name[3], *value[3];
   1339 	const char *str;
   1340 
   1341 	str = SSL_get_version(client->local->ssl);
   1342 	name[0] = "protocol";
   1343 	value[0] = str ? str : "???";
   1344 
   1345 	str = SSL_get_cipher(client->local->ssl);
   1346 	name[1] = "cipher";
   1347 	value[1] = str ? str : "???";
   1348 
   1349 	name[2] = value[2] = NULL;
   1350 
   1351 	buildvarstring(pattern, buf, sizeof(buf), name, value);
   1352 	return buf;
   1353 }
   1354 
   1355 int check_certificate_expiry_ctx(SSL_CTX *ctx, char **errstr)
   1356 {
   1357 #if !defined(HAS_ASN1_TIME_diff) || !defined(HAS_X509_get0_notAfter)
   1358 	return 0;
   1359 #else
   1360 	static char errbuf[512];
   1361 	SSL *ssl;
   1362 	X509 *cert;
   1363 	const ASN1_TIME *cert_expiry_time;
   1364 	int days_expiry = 0, seconds_expiry = 0;
   1365 	long duration;
   1366 
   1367 	*errstr = NULL;
   1368 
   1369 	ssl = SSL_new(ctx);
   1370 	if (!ssl)
   1371 		return 0;
   1372 
   1373 	cert = SSL_get_certificate(ssl);
   1374 	if (!cert)
   1375 	{
   1376 		SSL_free(ssl);
   1377 		return 0;
   1378 	}
   1379 
   1380 	/* get certificate time */
   1381 	cert_expiry_time = X509_get0_notAfter(cert);
   1382 
   1383 	/* calculate difference */
   1384 	ASN1_TIME_diff(&days_expiry, &seconds_expiry, cert_expiry_time, NULL);
   1385 	duration = (days_expiry * 86400) + seconds_expiry;
   1386 
   1387 	/* certificate expiry? */
   1388 	if ((days_expiry > 0) || (seconds_expiry > 0))
   1389 	{
   1390 		snprintf(errbuf, sizeof(errbuf), "certificate expired %s ago", pretty_time_val(duration));
   1391 		SSL_free(ssl);
   1392 		*errstr = errbuf;
   1393 		return 1;
   1394 	} else
   1395 	/* or near-expiry? */
   1396 	if (((days_expiry < 0) || (seconds_expiry < 0)) && (days_expiry > -7))
   1397 	{
   1398 		snprintf(errbuf, sizeof(errbuf), "certificate will expire in %s", pretty_time_val(0 - duration));
   1399 		SSL_free(ssl);
   1400 		*errstr = errbuf;
   1401 		return 1;
   1402 	}
   1403 
   1404 	/* All good */
   1405 	SSL_free(ssl);
   1406 	return 0;
   1407 #endif
   1408 }
   1409 
   1410 void check_certificate_expiry_tlsoptions_and_warn(TLSOptions *tlsoptions)
   1411 {
   1412 	SSL_CTX *ctx;
   1413 	int ret;
   1414 	char *errstr = NULL;
   1415 
   1416 	ctx = init_ctx(tlsoptions, 1);
   1417 	if (!ctx)
   1418 		return;
   1419 
   1420 	if (check_certificate_expiry_ctx(ctx, &errstr))
   1421 	{
   1422 		unreal_log(ULOG_ERROR, "tls", "TLS_CERT_EXPIRING", NULL,
   1423 		           "Warning: TLS certificate '$filename': $error_string",
   1424 		           log_data_string("filename", tlsoptions->certificate_file),
   1425 		           log_data_string("error_string", errstr));
   1426 	}
   1427 	SSL_CTX_free(ctx);
   1428 }
   1429 
   1430 EVENT(tls_check_expiry)
   1431 {
   1432 	ConfigItem_listen *listen;
   1433 	ConfigItem_sni *sni;
   1434 	ConfigItem_link *link;
   1435 
   1436 	/* set block */
   1437 	check_certificate_expiry_tlsoptions_and_warn(iConf.tls_options);
   1438 
   1439 	for (listen = conf_listen; listen; listen = listen->next)
   1440 		if (listen->tls_options)
   1441 			check_certificate_expiry_tlsoptions_and_warn(listen->tls_options);
   1442 
   1443 	/* sni::tls-options.... */
   1444 	for (sni = conf_sni; sni; sni = sni->next)
   1445 		if (sni->tls_options)
   1446 			check_certificate_expiry_tlsoptions_and_warn(sni->tls_options);
   1447 
   1448 	/* link::outgoing::tls-options.... */
   1449 	for (link = conf_link; link; link = link->next)
   1450 		if (link->tls_options)
   1451 			check_certificate_expiry_tlsoptions_and_warn(link->tls_options);
   1452 }