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 }