1 /* 2 * mod_gnutls - GnuTLS support for lighttpd 3 * 4 * Copyright(c) 2020 Glenn Strauss gstrauss()gluelogic.com All rights reserved 5 * License: BSD 3-clause (same as lighttpd) 6 */ 7 /* 8 * GnuTLS manual: https://www.gnutls.org/documentation.html 9 * 10 * Note: If session tickets are -not- disabled with 11 * ssl.openssl.ssl-conf-cmd = ("Options" => "-SessionTicket") 12 * mod_gnutls rotates server ticket encryption key (STEK) every 18 hours. 13 * (https://gnutls.org/manual/html_node/Session-resumption.html) 14 * This is fine for use with a single lighttpd instance, but with multiple 15 * lighttpd workers, no coordinated STEK (server ticket encryption key) 16 * rotation occurs unless ssl.stek-file is defined and maintained (preferred), 17 * or if some external job restarts lighttpd. Restarting lighttpd generates a 18 * new key that is shared by lighttpd workers for the lifetime of the new key. 19 * If the rotation period expires and lighttpd has not been restarted, and if 20 * ssl.stek-file is not in use, then lighttpd workers will generate new 21 * independent keys, making session tickets less effective for session 22 * resumption, since clients have a lower chance for future connections to 23 * reach the same lighttpd worker. However, things will still work, and a new 24 * session will be created if session resumption fails. Admins should plan to 25 * restart lighttpd at least every 18 hours if session tickets are enabled and 26 * multiple lighttpd workers are configured. Since that is likely disruptive, 27 * if multiple lighttpd workers are configured, ssl.stek-file should be 28 * defined and the file maintained externally. 29 * 30 * future possible enhancements to lighttpd mod_gnutls: 31 * - session cache (though session tickets are implemented) 32 * See gnutls_db_set_store_function() and gnutls_db_set_retrieve_function() 33 * (and do not enable unless server.feature-flags ssl.session-cache enabled) 34 */ 35 #include "first.h" 36 37 #include <sys/types.h> 38 #include <sys/stat.h> 39 #include <errno.h> 40 #include <fcntl.h> 41 #include <stdarg.h> 42 #include <stdlib.h> 43 #include <stdio.h> /* vsnprintf() */ 44 #include <string.h> 45 46 #include <gnutls/gnutls.h> 47 #include <gnutls/ocsp.h> 48 #include <gnutls/x509.h> 49 #include <gnutls/x509-ext.h> 50 #include <gnutls/abstract.h> 51 #include <gnutls/socket.h> 52 53 #ifdef GNUTLS_SKIP_GLOBAL_INIT 54 GNUTLS_SKIP_GLOBAL_INIT 55 #endif 56 57 #include "base.h" 58 #include "fdevent.h" 59 #include "http_header.h" 60 #include "http_kv.h" 61 #include "log.h" 62 #include "plugin.h" 63 64 typedef struct { 65 /* SNI per host: with COMP_SERVER_SOCKET, COMP_HTTP_SCHEME, COMP_HTTP_HOST */ 66 gnutls_certificate_credentials_t ssl_cred; 67 char trust_inited; 68 char must_staple; 69 gnutls_datum_t *ssl_pemfile_x509; 70 gnutls_privkey_t ssl_pemfile_pkey; 71 const buffer *ssl_stapling_file; 72 unix_time64_t ssl_stapling_loadts; 73 unix_time64_t ssl_stapling_nextts; 74 } plugin_cert; 75 76 typedef struct { 77 int8_t ssl_session_ticket; 78 /*(preserved here for deinit at server shutdown)*/ 79 gnutls_priority_t priority_cache; 80 #if GNUTLS_VERSION_NUMBER < 0x030600 81 gnutls_dh_params_t dh_params; 82 #endif 83 } plugin_ssl_ctx; 84 85 typedef struct { 86 plugin_cert *pc; 87 88 /*(used only during startup; not patched)*/ 89 unsigned char ssl_enabled; /* only interesting for setting up listening sockets. don't use at runtime */ 90 unsigned char ssl_honor_cipher_order; /* determine SSL cipher in server-preferred order, not client-order */ 91 const buffer *ssl_cipher_list; 92 array *ssl_conf_cmd; 93 94 /*(copied from plugin_data for socket ssl_ctx config)*/ 95 gnutls_priority_t priority_cache; 96 unsigned char ssl_session_ticket; 97 unsigned char ssl_verifyclient; 98 unsigned char ssl_verifyclient_enforce; 99 unsigned char ssl_verifyclient_depth; 100 101 const char *priority_base; 102 buffer *priority_override; 103 buffer priority_str; 104 #if GNUTLS_VERSION_NUMBER < 0x030600 105 gnutls_dh_params_t dh_params; 106 #endif 107 } plugin_config_socket; /*(used at startup during configuration)*/ 108 109 typedef struct { 110 /* SNI per host: w/ COMP_SERVER_SOCKET, COMP_HTTP_SCHEME, COMP_HTTP_HOST */ 111 plugin_cert *pc; 112 gnutls_datum_t *ssl_ca_file; /* .data is (gnutls_x509_crt_t) */ 113 gnutls_datum_t *ssl_ca_dn_file; /* .data is (gnutls_x509_crt_t) */ 114 gnutls_datum_t *ssl_ca_crl_file;/* .data is (gnutls_x509_crl_t) */ 115 116 unsigned char ssl_verifyclient; 117 unsigned char ssl_verifyclient_enforce; 118 unsigned char ssl_verifyclient_depth; 119 unsigned char ssl_verifyclient_export_cert; 120 unsigned char ssl_read_ahead; 121 unsigned char ssl_log_noise; 122 const buffer *ssl_verifyclient_username; 123 const buffer *ssl_acme_tls_1; 124 #if GNUTLS_VERSION_NUMBER < 0x030600 125 gnutls_dh_params_t dh_params; 126 #endif 127 } plugin_config; 128 129 typedef struct { 130 PLUGIN_DATA; 131 plugin_ssl_ctx *ssl_ctxs; 132 plugin_config defaults; 133 server *srv; 134 const char *ssl_stek_file; 135 } plugin_data; 136 137 static int ssl_is_init; 138 /* need assigned p->id for deep access of module handler_ctx for connection 139 * i.e. handler_ctx *hctx = con->plugin_ctx[plugin_data_singleton->id]; */ 140 static plugin_data *plugin_data_singleton; 141 #define LOCAL_SEND_BUFSIZE 16384 /* DEFAULT_MAX_RECORD_SIZE */ 142 static char *local_send_buffer; 143 144 typedef struct { 145 gnutls_session_t ssl; /* gnutls request/connection context */ 146 request_st *r; 147 connection *con; 148 int8_t close_notify; 149 uint8_t alpn; 150 int8_t ssl_session_ticket; 151 int handshake; 152 size_t pending_write; 153 plugin_config conf; 154 unsigned int verify_status; 155 buffer *tmp_buf; 156 log_error_st *errh; 157 gnutls_certificate_credentials_t acme_tls_1_cred; 158 } handler_ctx; 159 160 161 static handler_ctx * 162 handler_ctx_init (void) 163 { 164 return ck_calloc(1, sizeof(handler_ctx)); 165 } 166 167 168 static void 169 handler_ctx_free (handler_ctx *hctx) 170 { 171 gnutls_deinit(hctx->ssl); 172 if (hctx->acme_tls_1_cred) 173 gnutls_certificate_free_credentials(hctx->acme_tls_1_cred); 174 free(hctx); 175 } 176 177 178 __attribute_cold__ 179 static void elog(log_error_st * const errh, 180 const char * const file, const int line, 181 const int rc, const char * const msg) 182 { 183 /* error logging convenience function that decodes gnutls result codes */ 184 log_error(errh, file, line, "GnuTLS: %s: (%s) %s", 185 msg, gnutls_strerror_name(rc), gnutls_strerror(rc)); 186 } 187 188 189 __attribute_cold__ 190 __attribute_format__((__printf__, 5, 6)) 191 static void elogf(log_error_st * const errh, 192 const char * const file, const int line, 193 const int rc, const char * const fmt, ...) 194 { 195 char msg[1024]; 196 va_list ap; 197 va_start(ap, fmt); 198 vsnprintf(msg, sizeof(msg), fmt, ap); 199 va_end(ap); 200 elog(errh, file, line, rc, msg); 201 } 202 203 204 /* gnutls func gnutls_load_file() loads file contents into a gnutls_datum_t. 205 * The data loaded could be sensitive, e.g. a private key included in a pemfile. 206 * However, gnutls_load_file() is not careful about zeroizing memory on error, 207 * might use realloc() (which does not guarantee to zeroize memory released), 208 * and silently continues on short read, so provide our own. Updates to 209 * gnutls 3.6.14 may be more careful with private key files, but do not 210 * extend the same care to pemfiles which might contain private keys. 211 * Related, see also mod_gnutls_datum_wipe() below. 212 * https://gitlab.com/gnutls/gnutls/-/issues/1001 213 * https://gitlab.com/gnutls/gnutls/-/issues/1002 214 * https://gitlab.com/gnutls/gnutls/-/merge_requests/1270 215 */ 216 static int 217 mod_gnutls_load_file (const char * const fn, gnutls_datum_t * const d, log_error_st *errh) 218 { 219 #if 0 220 int rc = gnutls_load_file(fn, d); 221 if (rc < 0) 222 elogf(errh, __FILE__, __LINE__, rc, "%s() %s", __func__, fn); 223 return rc; 224 #else 225 off_t dlen = 512*1024*1024;/*(arbitrary limit: 512 MB file; expect < 1 MB)*/ 226 char *data = fdevent_load_file(fn, &dlen, errh, gnutls_malloc, gnutls_free); 227 if (NULL == data) return GNUTLS_E_FILE_ERROR; 228 d->data = (unsigned char *)data; 229 d->size = (unsigned int)dlen; 230 return 0; 231 #endif 232 } 233 234 235 /* GnuTLS does not expose _gnutls_free_key_datum() so provide our own */ 236 static void 237 mod_gnutls_datum_wipe (gnutls_datum_t * const d) 238 { 239 if (NULL == d) return; 240 if (d->data) { 241 if (d->size) gnutls_memset(d->data, 0, d->size); 242 gnutls_free(d->data); 243 d->data = NULL; 244 } 245 d->size = 0; 246 } 247 248 249 /* session tickets 250 * 251 * gnutls expects 64 bytes of random data in gnutls_datum_t passed to 252 * gnutls_session_ticket_enable_server() 253 * 254 * (private) session ticket definitions from lib/gnutls_int.h 255 * #define TICKET_MASTER_KEY_SIZE (TICKET_KEY_NAME_SIZE+TICKET_CIPHER_KEY_SIZE+TICKET_MAC_SECRET_SIZE) 256 * #define TICKET_KEY_NAME_SIZE 16 257 * #define TICKET_CIPHER_KEY_SIZE 32 258 * #define TICKET_MAC_SECRET_SIZE 16 259 */ 260 #define TICKET_MASTER_KEY_SIZE 64 261 262 #define TLSEXT_KEYNAME_LENGTH 16 263 #define TLSEXT_TICK_KEY_LENGTH 32 264 265 /* construct our own session ticket encryption key structure 266 * to store keys that are not yet active 267 * (mirror from mod_openssl, even though not all bits are used here) */ 268 typedef struct tlsext_ticket_key_st { 269 unix_time64_t active_ts; /* tickets not issued w/ key until activation ts*/ 270 unix_time64_t expire_ts; /* key not valid after expiration timestamp */ 271 unsigned char tick_key_name[TLSEXT_KEYNAME_LENGTH]; 272 unsigned char tick_hmac_key[TLSEXT_TICK_KEY_LENGTH]; 273 unsigned char tick_aes_key[TLSEXT_TICK_KEY_LENGTH]; 274 } tlsext_ticket_key_t; 275 276 static tlsext_ticket_key_t session_ticket_keys[1]; /* temp store until active */ 277 static unix_time64_t stek_rotate_ts; 278 279 static gnutls_datum_t session_ticket_key; 280 281 282 static void 283 mod_gnutls_session_ticket_key_free (void) 284 { 285 mod_gnutls_datum_wipe(&session_ticket_key); 286 } 287 static void 288 mod_gnutls_session_ticket_key_init (server *srv) 289 { 290 int rc = gnutls_session_ticket_key_generate(&session_ticket_key); 291 if (rc < 0) { 292 /*(should not happen, but if it does, disable session ticket)*/ 293 session_ticket_key.size = 0; 294 elog(srv->errh, __FILE__, __LINE__, rc, 295 "gnutls_session_ticket_key_generate()"); 296 } 297 } 298 static void 299 mod_gnutls_session_ticket_key_rotate (server *srv) 300 { 301 mod_gnutls_session_ticket_key_free(); 302 mod_gnutls_session_ticket_key_init(srv); 303 } 304 305 306 static int 307 mod_gnutls_session_ticket_key_file (const char *fn) 308 { 309 /* session ticket encryption key (STEK) 310 * 311 * STEK file should be stored in non-persistent storage, 312 * e.g. /dev/shm/lighttpd/stek-file (in memory) 313 * with appropriate permissions set to keep stek-file from being 314 * read by other users. Where possible, systems should also be 315 * configured without swap. 316 * 317 * admin should schedule an independent job to periodically 318 * generate new STEK up to 3 times during key lifetime 319 * (lighttpd stores up to 3 keys) 320 * 321 * format of binary file is: 322 * 4-byte - format version (always 0; for use if format changes) 323 * 4-byte - activation timestamp 324 * 4-byte - expiration timestamp 325 * 16-byte - session ticket key name 326 * 32-byte - session ticket HMAC encrpytion key 327 * 32-byte - session ticket AES encrpytion key 328 * 329 * STEK file can be created with a command such as: 330 * dd if=/dev/random bs=1 count=80 status=none | \ 331 * perl -e 'print pack("iii",0,time()+300,time()+86400),<>' \ 332 * > STEK-file.$$ && mv STEK-file.$$ STEK-file 333 * 334 * The above delays activation time by 5 mins (+300 sec) to allow file to 335 * be propagated to other machines. (admin must handle this independently) 336 * If STEK generation is performed immediately prior to starting lighttpd, 337 * admin should activate keys immediately (without +300). 338 */ 339 int buf[23]; /* 92 bytes */ 340 int rc = 0; /*(will retry on next check interval upon any error)*/ 341 if (0 != fdevent_load_file_bytes((char *)buf,(off_t)sizeof(buf),0,fn,NULL)) 342 return rc; 343 if (buf[0] == 0) { /*(format version 0)*/ 344 session_ticket_keys[0].active_ts = TIME64_CAST(buf[1]); 345 session_ticket_keys[0].expire_ts = TIME64_CAST(buf[2]); 346 #ifndef __COVERITY__ 347 memcpy(&session_ticket_keys[0].tick_key_name, buf+3, 80); 348 #else 349 memcpy(&session_ticket_keys[0].tick_key_name, 350 buf+3, TLSEXT_KEYNAME_LENGTH); 351 memcpy(&session_ticket_keys[0].tick_hmac_key, 352 buf+7, TLSEXT_TICK_KEY_LENGTH); 353 memcpy(&session_ticket_keys[0].tick_aes_key, 354 buf+15, TLSEXT_TICK_KEY_LENGTH); 355 #endif 356 rc = 1; 357 } 358 359 gnutls_memset(buf, 0, sizeof(buf)); 360 return rc; 361 } 362 363 364 static void 365 mod_gnutls_session_ticket_key_check (server *srv, const plugin_data *p, const unix_time64_t cur_ts) 366 { 367 static unix_time64_t detect_retrograde_ts; 368 if (detect_retrograde_ts > cur_ts && detect_retrograde_ts - cur_ts > 28800) 369 stek_rotate_ts = 0; 370 detect_retrograde_ts = cur_ts; 371 372 if (p->ssl_stek_file) { 373 struct stat st; 374 if (0 == stat(p->ssl_stek_file, &st) 375 && TIME64_CAST(st.st_mtime) > stek_rotate_ts 376 && mod_gnutls_session_ticket_key_file(p->ssl_stek_file)) { 377 stek_rotate_ts = cur_ts; 378 } 379 380 tlsext_ticket_key_t *stek = session_ticket_keys; 381 if (stek->active_ts != 0 && stek->active_ts - 63 <= cur_ts) { 382 if (NULL == session_ticket_key.data) { 383 session_ticket_key.data = gnutls_malloc(TICKET_MASTER_KEY_SIZE); 384 if (NULL == session_ticket_key.data) return; 385 session_ticket_key.size = TICKET_MASTER_KEY_SIZE; 386 } 387 #ifndef __COVERITY__ 388 memcpy(session_ticket_key.data, 389 stek->tick_key_name, TICKET_MASTER_KEY_SIZE); 390 gnutls_memset(stek->tick_key_name, 0, TICKET_MASTER_KEY_SIZE); 391 #else 392 char * const data = (char *)session_ticket_key.data; 393 memcpy(data, 394 stek->tick_key_name, TLSEXT_KEYNAME_LENGTH); 395 memcpy(data+TLSEXT_KEYNAME_LENGTH, 396 stek->tick_hmac_key, TLSEXT_TICK_KEY_LENGTH); 397 memcpy(data+TLSEXT_KEYNAME_LENGTH+TLSEXT_TICK_KEY_LENGTH, 398 stek->tick_aes_key, 399 TICKET_MASTER_KEY_SIZE 400 - (TLSEXT_KEYNAME_LENGTH + TLSEXT_TICK_KEY_LENGTH)); 401 gnutls_memset(stek->tick_key_name, 0, TLSEXT_KEYNAME_LENGTH); 402 gnutls_memset(stek->tick_hmac_key, 0, TLSEXT_TICK_KEY_LENGTH); 403 gnutls_memset(stek->tick_aes_key, 0, TLSEXT_TICK_KEY_LENGTH); 404 #endif 405 } 406 if (stek->expire_ts < cur_ts) 407 mod_gnutls_session_ticket_key_free(); 408 } 409 else if (cur_ts - 86400 >= stek_rotate_ts /*(24 hours)*/ 410 || 0 == stek_rotate_ts) { 411 mod_gnutls_session_ticket_key_rotate(srv); 412 stek_rotate_ts = cur_ts; 413 } 414 } 415 416 417 INIT_FUNC(mod_gnutls_init) 418 { 419 plugin_data_singleton = (plugin_data *)ck_calloc(1, sizeof(plugin_data)); 420 return plugin_data_singleton; 421 } 422 423 424 static int mod_gnutls_init_once_gnutls (void) 425 { 426 if (ssl_is_init) return 1; 427 ssl_is_init = 1; 428 429 /* Note: on systems with support for weak symbols, GNUTLS_SKIP_GLOBAL_INIT 430 * is set near top of this file to inhibit GnuTLS implicit initialization 431 * in a library constructor. On systems without support for weak symbols, 432 * set GNUTLS_NO_EXPLICIT_INIT=1 in the environment before starting lighttpd 433 * (GnuTLS 3.3.0 or later) */ 434 435 if (gnutls_global_init() != GNUTLS_E_SUCCESS) 436 return 0; 437 438 local_send_buffer = ck_malloc(LOCAL_SEND_BUFSIZE); 439 return 1; 440 } 441 442 443 static void mod_gnutls_free_gnutls (void) 444 { 445 if (!ssl_is_init) return; 446 447 gnutls_memset(session_ticket_keys, 0, sizeof(session_ticket_keys)); 448 mod_gnutls_session_ticket_key_free(); 449 stek_rotate_ts = 0; 450 451 gnutls_global_deinit(); 452 453 free(local_send_buffer); 454 ssl_is_init = 0; 455 } 456 457 458 __attribute_noinline__ 459 static void 460 mod_gnutls_free_config_crts_data (gnutls_datum_t *d) 461 { 462 if (NULL == d) return; 463 gnutls_x509_crt_t *crts = (gnutls_x509_crt_t *)(void *)d->data; 464 unsigned int u = d->size; 465 for (unsigned int i = 0; i < u; ++i) 466 gnutls_x509_crt_deinit(crts[i]); 467 gnutls_free(crts); 468 } 469 470 471 static void 472 mod_gnutls_free_config_crts (gnutls_datum_t *d) 473 { 474 mod_gnutls_free_config_crts_data(d); 475 gnutls_free(d); 476 } 477 478 479 static void 480 mod_gnutls_free_config_crls (gnutls_datum_t *d) 481 { 482 if (NULL == d) return; 483 gnutls_x509_crl_t *crls = (gnutls_x509_crl_t *)(void *)d->data; 484 unsigned int u = d->size; 485 for (unsigned int i = 0; i < u; ++i) 486 gnutls_x509_crl_deinit(crls[i]); 487 gnutls_free(crls); 488 gnutls_free(d); 489 } 490 491 492 static int 493 mod_gnutls_cert_is_active (gnutls_x509_crt_t crt) 494 { 495 const time_t before = gnutls_x509_crt_get_activation_time(crt); 496 const time_t after = gnutls_x509_crt_get_expiration_time(crt); 497 const unix_time64_t now = log_epoch_secs; 498 return (before <= now && now <= after); 499 } 500 501 502 static gnutls_datum_t * 503 mod_gnutls_load_config_crts (const char *fn, log_error_st *errh) 504 { 505 /*(very similar to other mod_gnutls_load_config_*())*/ 506 if (!mod_gnutls_init_once_gnutls()) return NULL; 507 508 gnutls_datum_t f = { NULL, 0 }; 509 int rc = mod_gnutls_load_file(fn, &f, errh); 510 if (rc < 0) return NULL; 511 gnutls_datum_t *d = gnutls_malloc(sizeof(gnutls_datum_t)); 512 if (d == NULL) { 513 mod_gnutls_datum_wipe(&f); 514 return NULL; 515 } 516 d->data = NULL; 517 d->size = 0; 518 rc = gnutls_x509_crt_list_import2((gnutls_x509_crt_t **)&d->data, &d->size, 519 &f, GNUTLS_X509_FMT_PEM, 520 GNUTLS_X509_CRT_LIST_SORT); 521 if (rc < 0) { 522 mod_gnutls_free_config_crts_data(d); 523 d->data = NULL; 524 d->size = 0; 525 if (0 == gnutls_x509_crt_list_import2((gnutls_x509_crt_t **)&d->data, 526 &d->size, &f, GNUTLS_X509_FMT_DER, 527 GNUTLS_X509_CRT_LIST_SORT)) 528 rc = 0; 529 } 530 mod_gnutls_datum_wipe(&f); 531 if (rc < 0) { 532 elogf(errh, __FILE__, __LINE__, rc, 533 "gnutls_x509_crt_list_import2() %s", fn); 534 mod_gnutls_free_config_crts(d); 535 return NULL; 536 } 537 else if ( 538 !mod_gnutls_cert_is_active(((gnutls_x509_crt_t *)(void *)d->data)[0])) { 539 log_error(errh, __FILE__, __LINE__, 540 "GnuTLS: inactive/expired X509 certificate '%s'", fn); 541 } 542 543 return d; 544 } 545 546 547 static gnutls_datum_t * 548 mod_gnutls_load_config_crls (const char *fn, log_error_st *errh) 549 { 550 /*(very similar to other mod_gnutls_load_config_*())*/ 551 if (!mod_gnutls_init_once_gnutls()) return NULL; 552 553 gnutls_datum_t f = { NULL, 0 }; 554 int rc = mod_gnutls_load_file(fn, &f, errh); 555 if (rc < 0) return NULL; 556 gnutls_datum_t *d = gnutls_malloc(sizeof(gnutls_datum_t)); 557 if (d == NULL) { 558 mod_gnutls_datum_wipe(&f); 559 return NULL; 560 } 561 d->data = NULL; 562 d->size = 0; 563 rc = gnutls_x509_crl_list_import2((gnutls_x509_crl_t **)&d->data, &d->size, 564 &f, GNUTLS_X509_FMT_PEM, 0); 565 mod_gnutls_datum_wipe(&f); 566 if (rc < 0) { 567 elogf(errh, __FILE__, __LINE__, rc, 568 "gnutls_x509_crl_list_import2() %s", fn); 569 mod_gnutls_free_config_crls(d); 570 return NULL; 571 } 572 573 return d; 574 } 575 576 577 static gnutls_privkey_t 578 mod_gnutls_load_config_pkey (const char *fn, log_error_st *errh) 579 { 580 /*(very similar to other mod_gnutls_load_config_*())*/ 581 if (!mod_gnutls_init_once_gnutls()) return NULL; 582 583 gnutls_datum_t f = { NULL, 0 }; 584 int rc = mod_gnutls_load_file(fn, &f, errh); 585 if (rc < 0) return NULL; 586 gnutls_privkey_t pkey; 587 rc = gnutls_privkey_init(&pkey); 588 if (rc < 0) { 589 mod_gnutls_datum_wipe(&f); 590 return NULL; 591 } 592 rc = gnutls_privkey_import_x509_raw(pkey, &f, GNUTLS_X509_FMT_PEM, NULL, 0); 593 if (rc < 0) { 594 gnutls_privkey_deinit(pkey); 595 if (0 == gnutls_privkey_init(&pkey) 596 && 0 == gnutls_privkey_import_x509_raw(pkey, &f, 597 GNUTLS_X509_FMT_DER,NULL,0)) 598 rc = 0; 599 } 600 mod_gnutls_datum_wipe(&f); 601 if (rc < 0) { 602 elogf(errh, __FILE__, __LINE__, rc, 603 "gnutls_privkey_import_x509_raw() %s", fn); 604 gnutls_privkey_deinit(pkey); 605 return NULL; 606 } 607 608 return pkey; 609 } 610 611 612 static void 613 mod_gnutls_free_config (server *srv, plugin_data * const p) 614 { 615 if (NULL != p->ssl_ctxs) { 616 gnutls_priority_t pcache_global_scope = p->ssl_ctxs->priority_cache; 617 /* free from $SERVER["socket"] (if not copy of global scope) */ 618 for (uint32_t i = 1; i < srv->config_context->used; ++i) { 619 plugin_ssl_ctx * const s = p->ssl_ctxs + i; 620 if (s->priority_cache && s->priority_cache != pcache_global_scope) { 621 if (s->priority_cache) 622 gnutls_priority_deinit(s->priority_cache); 623 #if GNUTLS_VERSION_NUMBER < 0x030600 624 if (s->dh_params) 625 gnutls_dh_params_deinit(s->dh_params); 626 #endif 627 } 628 } 629 /* free from global scope */ 630 if (pcache_global_scope) { 631 if (p->ssl_ctxs[0].priority_cache) 632 gnutls_priority_deinit(p->ssl_ctxs[0].priority_cache); 633 #if GNUTLS_VERSION_NUMBER < 0x030600 634 if (p->ssl_ctxs[0].dh_params) 635 gnutls_dh_params_deinit(p->ssl_ctxs[0].dh_params); 636 #endif 637 } 638 free(p->ssl_ctxs); 639 } 640 641 if (NULL == p->cvlist) return; 642 /* (init i to 0 if global context; to 1 to skip empty global context) */ 643 for (int i = !p->cvlist[0].v.u2[1], used = p->nconfig; i < used; ++i) { 644 config_plugin_value_t *cpv = p->cvlist + p->cvlist[i].v.u2[0]; 645 for (; -1 != cpv->k_id; ++cpv) { 646 switch (cpv->k_id) { 647 case 0: /* ssl.pemfile */ 648 if (cpv->vtype == T_CONFIG_LOCAL) { 649 plugin_cert *pc = cpv->v.v; 650 gnutls_certificate_free_credentials(pc->ssl_cred); 651 mod_gnutls_free_config_crts(pc->ssl_pemfile_x509); 652 gnutls_privkey_deinit(pc->ssl_pemfile_pkey); 653 free(pc); 654 } 655 break; 656 case 2: /* ssl.ca-file */ 657 case 3: /* ssl.ca-dn-file */ 658 if (cpv->vtype == T_CONFIG_LOCAL) 659 mod_gnutls_free_config_crts(cpv->v.v); 660 break; 661 case 4: /* ssl.ca-crl-file */ 662 if (cpv->vtype == T_CONFIG_LOCAL) 663 mod_gnutls_free_config_crls(cpv->v.v); 664 break; 665 default: 666 break; 667 } 668 } 669 } 670 } 671 672 673 FREE_FUNC(mod_gnutls_free) 674 { 675 plugin_data *p = p_d; 676 if (NULL == p->srv) return; 677 mod_gnutls_free_config(p->srv, p); 678 mod_gnutls_free_gnutls(); 679 } 680 681 682 static void 683 mod_gnutls_merge_config_cpv (plugin_config * const pconf, const config_plugin_value_t * const cpv) 684 { 685 switch (cpv->k_id) { /* index into static config_plugin_keys_t cpk[] */ 686 case 0: /* ssl.pemfile */ 687 if (cpv->vtype == T_CONFIG_LOCAL) 688 pconf->pc = cpv->v.v; 689 break; 690 case 1: /* ssl.privkey */ 691 break; 692 case 2: /* ssl.ca-file */ 693 if (cpv->vtype == T_CONFIG_LOCAL) 694 pconf->ssl_ca_file = cpv->v.v; 695 break; 696 case 3: /* ssl.ca-dn-file */ 697 if (cpv->vtype == T_CONFIG_LOCAL) 698 pconf->ssl_ca_dn_file = cpv->v.v; 699 break; 700 case 4: /* ssl.ca-crl-file */ 701 if (cpv->vtype == T_CONFIG_LOCAL) 702 pconf->ssl_ca_crl_file = cpv->v.v; 703 break; 704 case 5: /* ssl.read-ahead */ 705 pconf->ssl_read_ahead = (0 != cpv->v.u); 706 break; 707 case 6: /* ssl.disable-client-renegotiation */ 708 /*(ignored; unsafe renegotiation disabled by default)*/ 709 break; 710 case 7: /* ssl.verifyclient.activate */ 711 pconf->ssl_verifyclient = (0 != cpv->v.u); 712 break; 713 case 8: /* ssl.verifyclient.enforce */ 714 pconf->ssl_verifyclient_enforce = (0 != cpv->v.u); 715 break; 716 case 9: /* ssl.verifyclient.depth */ 717 pconf->ssl_verifyclient_depth = (unsigned char)cpv->v.shrt; 718 break; 719 case 10:/* ssl.verifyclient.username */ 720 pconf->ssl_verifyclient_username = cpv->v.b; 721 break; 722 case 11:/* ssl.verifyclient.exportcert */ 723 pconf->ssl_verifyclient_export_cert = (0 != cpv->v.u); 724 break; 725 case 12:/* ssl.acme-tls-1 */ 726 pconf->ssl_acme_tls_1 = cpv->v.b; 727 break; 728 case 13:/* ssl.stapling-file */ 729 break; 730 case 14:/* debug.log-ssl-noise */ 731 pconf->ssl_log_noise = (unsigned char)cpv->v.shrt; 732 break; 733 #if 0 /*(cpk->k_id remapped in mod_gnutls_set_defaults())*/ 734 case 15:/* ssl.verifyclient.ca-file */ 735 case 16:/* ssl.verifyclient.ca-dn-file */ 736 case 17:/* ssl.verifyclient.ca-crl-file */ 737 break; 738 #endif 739 default:/* should not happen */ 740 return; 741 } 742 } 743 744 745 static void 746 mod_gnutls_merge_config(plugin_config * const pconf, const config_plugin_value_t *cpv) 747 { 748 do { 749 mod_gnutls_merge_config_cpv(pconf, cpv); 750 } while ((++cpv)->k_id != -1); 751 } 752 753 754 static void 755 mod_gnutls_patch_config (request_st * const r, plugin_config * const pconf) 756 { 757 plugin_data * const p = plugin_data_singleton; 758 memcpy(pconf, &p->defaults, sizeof(plugin_config)); 759 for (int i = 1, used = p->nconfig; i < used; ++i) { 760 if (config_check_cond(r, (uint32_t)p->cvlist[i].k_id)) 761 mod_gnutls_merge_config(pconf, p->cvlist + p->cvlist[i].v.u2[0]); 762 } 763 } 764 765 766 static int 767 mod_gnutls_verify_set_tlist (handler_ctx *hctx, int req) 768 { 769 /* XXX GnuTLS interfaces appear to be better for client-side use than for 770 * server-side use. If gnutls_x509_trust_list_t were available to attach 771 * to a gnutls_session_t (without copying), then there would not be race 772 * conditions swapping trust lists on the credential *shared* between 773 * connections when ssl.ca-dn-file and ssl.ca-file are both set. If both 774 * are set, current code attempts to set ssl.ca-dn-file right before sending 775 * client cert request, and sets ssl.ca-file right before client cert verify 776 * 777 * Architecture would be cleaner if the trust list for verifying client cert 778 * (gnutls_x509_trust_list_t) were available to attach to a gnutls_session_t 779 * instead of attaching to a gnutls_certificate_credentials_t. 780 */ 781 if (hctx->conf.pc->trust_inited) return GNUTLS_E_SUCCESS; 782 783 gnutls_datum_t *d; 784 int rc; 785 786 /* set trust list using ssl_ca_dn_file, if set, for client cert request 787 * (when req is true) (for CAs sent by server to client in cert request) 788 * (trust is later replaced by ssl_ca_file for client cert verification) */ 789 d = req && hctx->conf.ssl_ca_dn_file 790 ? hctx->conf.ssl_ca_dn_file 791 : hctx->conf.ssl_ca_file; 792 if (NULL == d) { 793 log_error(hctx->r->conf.errh, __FILE__, __LINE__, 794 "GnuTLS: can't verify client without ssl.verifyclient.ca-file " 795 "for TLS server name %s", 796 hctx->r->uri.authority.ptr); /*(might not be set yet if no SNI)*/ 797 return GNUTLS_E_INTERNAL_ERROR; 798 } 799 800 gnutls_x509_trust_list_t tlist = NULL; 801 rc = gnutls_x509_trust_list_init(&tlist, 0); 802 if (rc < 0) { 803 elog(hctx->r->conf.errh, __FILE__, __LINE__, rc, 804 "gnutls_x509_trust_list_init()"); 805 return rc; 806 } 807 808 gnutls_x509_crt_t *clist = (gnutls_x509_crt_t *)(void *)d->data; 809 rc = gnutls_x509_trust_list_add_cas(tlist, clist, d->size, 0); 810 if (rc < 0) { 811 elog(hctx->r->conf.errh, __FILE__, __LINE__, rc, 812 "gnutls_x509_trust_list_add_cas()"); 813 gnutls_x509_trust_list_deinit(tlist, 0); 814 return rc; 815 } 816 817 d = hctx->conf.ssl_ca_crl_file; 818 if (NULL != d && req && hctx->conf.ssl_ca_dn_file) { 819 /*(check req and ssl_ca_dn_file to see if tlist will be replaced later, 820 * and, if so, defer setting crls until later)*/ 821 gnutls_x509_crl_t *crl_list = (gnutls_x509_crl_t *)(void *)d->data; 822 rc = gnutls_x509_trust_list_add_crls(tlist, crl_list, d->size, 0, 0); 823 if (rc < 0) { 824 elog(hctx->r->conf.errh, __FILE__, __LINE__, rc, 825 "gnutls_x509_trust_list_add_crls()"); 826 gnutls_x509_trust_list_deinit(tlist, 0); 827 return rc; 828 } 829 } 830 831 /* gnutls limitation; wasteful to have to copy into each cred */ 832 /* (would be better to share list with session, instead of with cred) */ 833 gnutls_certificate_credentials_t ssl_cred = hctx->conf.pc->ssl_cred; 834 gnutls_certificate_set_trust_list(ssl_cred, tlist, 0); /* transfer tlist */ 835 836 /* (must flip trust lists back and forth b/w DN names and verify CAs) */ 837 if (NULL == hctx->conf.ssl_ca_dn_file) 838 hctx->conf.pc->trust_inited = 1; 839 840 return GNUTLS_E_SUCCESS; 841 } 842 843 844 static int 845 mod_gnutls_verify_cb (gnutls_session_t ssl) 846 { 847 handler_ctx * const hctx = gnutls_session_get_ptr(ssl); 848 if (!hctx->conf.ssl_verifyclient) return 0; 849 850 if (gnutls_auth_client_get_type(ssl) != GNUTLS_CRD_CERTIFICATE) 851 return GNUTLS_E_SUCCESS; 852 853 int rc; 854 855 /* gnutls limitation; wasteful to have to copy into each cred */ 856 /* (would be better to share list with session, instead of with cred) */ 857 if (hctx->conf.ssl_ca_dn_file) { 858 rc = mod_gnutls_verify_set_tlist(hctx, 0); /* for client cert verify */ 859 if (rc < 0) return rc; 860 } 861 862 /* gnutls_certificate_verify_peers2() includes processing OCSP staping, 863 * as well as certificate depth verification before getting internal 864 * flags and calling gnutls_x509_trust_list_verify_crt2() 865 * advanced reference: 866 * gnutls lib/cert-sessions.c:_gnutls_x509_cert_verify_peers() 867 * XXX: if GnuTLS provided a more advanced interface which permitted 868 * providing trust list, verify depth, and flags, we could avoid copying 869 * ca chain and crls into each credential, using 870 * gnutls_x509_trust_list_add_cas() 871 * gnutls_x509_trust_list_add_crls() 872 * gnutls_x509_trust_list_verify_crt2() 873 * See also GnuTLS manual Section 7.3.4 Advanced certificate verification 874 */ 875 876 rc = gnutls_certificate_verify_peers2(ssl, &hctx->verify_status); 877 if (rc < 0) return rc; 878 879 if (hctx->verify_status == 0 && hctx->conf.ssl_ca_dn_file) { 880 /* verify that client cert is issued by CA in ssl.ca-dn-file 881 * if both ssl.ca-dn-file and ssl.ca-file were configured */ 882 gnutls_x509_crt_t *CA_list = 883 (gnutls_x509_crt_t *)(void *)hctx->conf.ssl_ca_dn_file->data; 884 unsigned int len = hctx->conf.ssl_ca_dn_file->size; 885 unsigned int i; 886 gnutls_x509_dn_t issuer, subject; 887 unsigned int crt_size = 0; 888 const gnutls_datum_t *crts; 889 gnutls_x509_crt_t crt = NULL; 890 crts = gnutls_certificate_get_peers(ssl, &crt_size); 891 if (0 == crt_size 892 || gnutls_x509_crt_init(&crt) < 0 893 || gnutls_x509_crt_import(crt, &crts[0], GNUTLS_X509_FMT_DER) < 0 894 || gnutls_x509_crt_get_subject(crt, &issuer) < 0) 895 len = 0; /*(trigger failure path below)*/ 896 for (i = 0; i < len; ++i) { 897 if (gnutls_x509_crt_get_subject(CA_list[i], &subject) >= 0 898 && 0 == memcmp(&subject, &issuer, sizeof(issuer))) 899 break; 900 } 901 if (i == len) 902 hctx->verify_status |= GNUTLS_CERT_SIGNER_NOT_CA; 903 if (crt) gnutls_x509_crt_deinit(crt); 904 } 905 906 if (hctx->verify_status != 0 && hctx->conf.ssl_verifyclient_enforce) { 907 /* (not looping on GNUTLS_E_INTERRUPTED or GNUTLS_E_AGAIN 908 * since we do not want to block here (and not expecting to have to))*/ 909 (void)gnutls_alert_send(ssl, GNUTLS_AL_FATAL, GNUTLS_A_ACCESS_DENIED); 910 return GNUTLS_E_CERTIFICATE_VERIFICATION_ERROR; 911 } 912 913 return GNUTLS_E_SUCCESS; 914 } 915 916 917 #if GNUTLS_VERSION_NUMBER < 0x030603 918 static time_t 919 mod_gnutls_ocsp_next_update (plugin_cert *pc, log_error_st *errh) 920 { 921 gnutls_datum_t f = { NULL, 0 }; 922 int rc = mod_gnutls_load_file(pc->ssl_stapling_file->ptr, &f, errh); 923 if (rc < 0) return (time_t)-1; 924 925 gnutls_ocsp_resp_t resp = NULL; 926 time_t nextupd; 927 if ( gnutls_ocsp_resp_init(&resp) < 0 928 || gnutls_ocsp_resp_import(resp, &f) < 0 929 || gnutls_ocsp_resp_get_single(resp, 0, NULL, NULL, NULL, NULL, NULL, 930 NULL, &nextupd, NULL, NULL) < 0) 931 nextupd = (time_t)-1; 932 gnutls_ocsp_resp_deinit(resp); 933 mod_gnutls_datum_wipe(&f); 934 return nextupd; 935 } 936 #endif 937 938 939 __attribute_cold__ 940 static void 941 mod_gnutls_expire_stapling_file (server *srv, plugin_cert *pc) 942 { 943 #if 0 944 /* discard expired OCSP stapling response */ 945 /* Does GnuTLS detect expired OCSP response? */ 946 /* or must we rebuild gnutls_certificate_credentials_t ? */ 947 #endif 948 if (pc->must_staple) 949 log_error(srv->errh, __FILE__, __LINE__, 950 "certificate marked OCSP Must-Staple, " 951 "but OCSP response expired from ssl.stapling-file %s", 952 pc->ssl_stapling_file->ptr); 953 } 954 955 956 static int 957 mod_gnutls_reload_stapling_file (server *srv, plugin_cert *pc, const unix_time64_t cur_ts) 958 { 959 #if GNUTLS_VERSION_NUMBER < 0x030603 960 /* load file into gnutls_ocsp_resp_t before loading into 961 * gnutls_certificate_credentials_t for safety. Still ToC-ToU since file 962 * is loaded twice, but unlikely condition. (GnuTLS limitation does not 963 * expose access to OCSP response from gnutls_certificate_credentials_t 964 * before GnuTLS 3.6.3) */ 965 time_t nextupd = mod_gnutls_ocsp_next_update(pc, srv->errh); 966 #else 967 UNUSED(srv); 968 #endif 969 970 /* GnuTLS 3.5.6 added the ability to include multiple OCSP responses for 971 * certificate chain as allowed in TLSv1.3, but that is not utilized here. 972 * If implemented, it will probably operate on a new directive, 973 * e.g. ssl.stapling-pemfile 974 * GnuTLS 3.6.3 added gnutls_certificate_set_ocsp_status_request_file2() 975 * GnuTLS 3.6.3 added gnutls_certificate_set_ocsp_status_request_mem() 976 * GnuTLS 3.6.3 added gnutls_certificate_get_ocsp_expiration() */ 977 978 /* gnutls_certificate_get_ocsp_expiration() code comments: 979 * Note that the credentials structure should be read-only when in 980 * use, thus when reloading, either the credentials structure must not 981 * be in use by any sessions, or a new credentials structure should be 982 * allocated for new sessions. 983 * XXX: lighttpd is not threaded, so this is probably not an issue (?) 984 */ 985 986 #if 0 987 gnutls_certificate_set_flags(pc->ssl_cred, 988 GNUTLS_CERTIFICATE_SKIP_OCSP_RESPONSE_CHECK); 989 #endif 990 991 const char *fn = pc->ssl_stapling_file->ptr; 992 int rc = gnutls_certificate_set_ocsp_status_request_file(pc->ssl_cred,fn,0); 993 if (rc < 0) 994 return rc; 995 996 #if GNUTLS_VERSION_NUMBER >= 0x030603 997 time_t nextupd = 998 gnutls_certificate_get_ocsp_expiration(pc->ssl_cred, 0, 0, 0); 999 if (nextupd == (time_t)-2) nextupd = (time_t)-1; 1000 #endif 1001 1002 pc->ssl_stapling_loadts = cur_ts; 1003 pc->ssl_stapling_nextts = nextupd; 1004 if (pc->ssl_stapling_nextts == -1) { 1005 /* "Next Update" might not be provided by OCSP responder 1006 * Use 3600 sec (1 hour) in that case. */ 1007 /* retry in 1 hour if unable to determine Next Update */ 1008 pc->ssl_stapling_nextts = cur_ts + 3600; 1009 pc->ssl_stapling_loadts = 0; 1010 } 1011 else if (pc->ssl_stapling_nextts < cur_ts) 1012 mod_gnutls_expire_stapling_file(srv, pc); 1013 1014 return 0; 1015 } 1016 1017 1018 static int 1019 mod_gnutls_refresh_stapling_file (server *srv, plugin_cert *pc, const unix_time64_t cur_ts) 1020 { 1021 if (pc->ssl_stapling_nextts > cur_ts + 256) 1022 return 0; /* skip check for refresh unless close to expire */ 1023 struct stat st; 1024 if (0 != stat(pc->ssl_stapling_file->ptr, &st) 1025 || TIME64_CAST(st.st_mtime) <= pc->ssl_stapling_loadts) { 1026 if (pc->ssl_stapling_nextts < cur_ts) 1027 mod_gnutls_expire_stapling_file(srv, pc); 1028 return 0; 1029 } 1030 return mod_gnutls_reload_stapling_file(srv, pc, cur_ts); 1031 } 1032 1033 1034 static void 1035 mod_gnutls_refresh_stapling_files (server *srv, const plugin_data *p, const unix_time64_t cur_ts) 1036 { 1037 /* future: might construct array of (plugin_cert *) at startup 1038 * to avoid the need to search for them here */ 1039 /* (init i to 0 if global context; to 1 to skip empty global context) */ 1040 if (NULL == p->cvlist) return; 1041 for (int i = !p->cvlist[0].v.u2[1], used = p->nconfig; i < used; ++i) { 1042 const config_plugin_value_t *cpv = p->cvlist + p->cvlist[i].v.u2[0]; 1043 for (; cpv->k_id != -1; ++cpv) { 1044 if (cpv->k_id != 0) continue; /* k_id == 0 for ssl.pemfile */ 1045 if (cpv->vtype != T_CONFIG_LOCAL) continue; 1046 plugin_cert *pc = cpv->v.v; 1047 if (pc->ssl_stapling_file) 1048 mod_gnutls_refresh_stapling_file(srv, pc, cur_ts); 1049 } 1050 } 1051 } 1052 1053 1054 static int 1055 mod_gnutls_crt_must_staple (gnutls_x509_crt_t crt) 1056 { 1057 /* Look for TLS features X.509 extension with value 5 1058 * RFC 7633 https://tools.ietf.org/html/rfc7633#appendix-A 1059 * 5 = OCSP Must-Staple (security mechanism) */ 1060 1061 int rc; 1062 1063 #if GNUTLS_VERSION_NUMBER < 0x030501 1064 1065 unsigned int i; 1066 char oid[128]; 1067 size_t oidsz; 1068 for (i = 0; ; ++i) { 1069 oidsz = sizeof(oid); 1070 rc = gnutls_x509_crt_get_extension_info(crt, i, oid, &oidsz, NULL); 1071 if (rc < 0 || 0 == strcmp(oid, GNUTLS_X509EXT_OID_TLSFEATURES)) break; 1072 } 1073 /* ext not found if (rc == GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE) */ 1074 if (rc < 0) return rc; 1075 1076 gnutls_datum_t der = { NULL, 0 }; 1077 rc = gnutls_x509_crt_get_extension_data2(crt, i, &der); 1078 if (rc < 0) return rc; 1079 1080 /* DER encoding (Tag, Length, Value (TLV)) expecting: 30:03:02:01:05 1081 * [TL[TLV]] (30=Sequence, Len=03, (02=Integer, Len=01, Value=05)) 1082 * XXX: This is not future-proof if TLS feature list values are extended */ 1083 /*const char must_staple[] = { 0x30, 0x03, 0x02, 0x01, 0x05 };*/ 1084 /*rc = (der.size == 5 && 0 == memcmp(der.data, must_staple, 5))*/ 1085 rc = (der.size >= 5 && der.data[0] == 0x30 && der.data[1] >= 0x03 1086 && der.data[2] == 0x2 && der.data[3] == 0x1 && der.data[4] == 0x5) 1087 ? 1 1088 : 0; 1089 1090 gnutls_free(der.data); 1091 1092 #else 1093 1094 gnutls_x509_tlsfeatures_t f; 1095 rc = gnutls_x509_tlsfeatures_init(&f); 1096 if (rc < 0) return rc; 1097 rc = gnutls_x509_tlsfeatures_add(f, 5); /* 5 = OCSP Must-Staple */ 1098 if (rc < 0) return rc; 1099 rc = (0 != gnutls_x509_tlsfeatures_check_crt(f, crt)); 1100 gnutls_x509_tlsfeatures_deinit(f); 1101 1102 #endif 1103 1104 return rc; /* 1 if OCSP Must-Staple found; 0 if not */ 1105 } 1106 1107 1108 static int 1109 mod_gnutls_construct_crt_chain (plugin_cert *pc, gnutls_datum_t *d, log_error_st *errh) 1110 { 1111 /* Historically, openssl will use the cert chain in (SSL_CTX *) if a cert 1112 * does not have a chain configured in (SSL *). Attempt to provide 1113 * compatible behavior here. This may be called after startup since 1114 * ssl.pemfile might be defined in a config scope without ssl.ca-file, 1115 * and at runtime is when ssl.ca-file (e.g. from matching $SERVER["socket"]) 1116 * would be known along with ssl.pemfile (e.g. from $HTTP["host"]) */ 1117 1118 gnutls_certificate_credentials_t ssl_cred; 1119 int rc = gnutls_certificate_allocate_credentials(&ssl_cred); 1120 if (rc < 0) return rc; 1121 unsigned int ncrt = (d ? d->size : 0); 1122 unsigned int off = (d == pc->ssl_pemfile_x509) ? 0 : 1; 1123 gnutls_pcert_st * const pcert_list = 1124 gnutls_malloc(sizeof(gnutls_pcert_st) * (off+ncrt)); 1125 if (NULL == pcert_list) { 1126 gnutls_certificate_free_credentials(ssl_cred); 1127 return GNUTLS_E_MEMORY_ERROR; 1128 } 1129 memset(pcert_list, 0, sizeof(gnutls_pcert_st) * (off+ncrt)); 1130 rc = 0; 1131 1132 if (off) { /*(add crt to chain if different from d)*/ 1133 /*assert(pc->ssl_pemfile_x509->size == 1)*/ 1134 gnutls_x509_crt_t *crts = 1135 (gnutls_x509_crt_t *)(void *)pc->ssl_pemfile_x509->data; 1136 rc = gnutls_pcert_import_x509(pcert_list, crts[0], 0); 1137 } 1138 1139 if (0 == rc && ncrt) { 1140 gnutls_x509_crt_t *crts = (gnutls_x509_crt_t *)(void *)d->data; 1141 #if GNUTLS_VERSION_NUMBER < 0x030400 1142 /*(GNUTLS_X509_CRT_LIST_SORT not needed; crts sorted when file read)*/ 1143 rc = gnutls_pcert_import_x509_list(pcert_list+off, crts, &ncrt, 0); 1144 #else /* manually import list, but note that sorting is not implemented */ 1145 rc = 0; 1146 for (unsigned int i = 0; i < ncrt; ++i) { 1147 rc = gnutls_pcert_import_x509(pcert_list+off+i, crts[i], 0); 1148 if (rc < 0) break; 1149 } 1150 #endif 1151 } 1152 ncrt += off; 1153 if (0 == rc) 1154 rc = gnutls_certificate_set_key(ssl_cred, NULL, 0, pcert_list, ncrt, 1155 pc->ssl_pemfile_pkey); 1156 if (rc < 0) { 1157 for (unsigned int i = 0; i < ncrt; ++i) 1158 gnutls_pcert_deinit(pcert_list+i); 1159 gnutls_free(pcert_list); 1160 gnutls_certificate_free_credentials(ssl_cred); 1161 elog(errh, __FILE__, __LINE__, rc, "gnutls_certificate_set_key()"); 1162 return rc; 1163 } 1164 /* XXX: gnutls_certificate_set_key() has an inconsistent implementation. 1165 * On success, key ownership is transferred, and so should not be freed, 1166 * but pcert_list is a shallow memcpy(), so gnutls_pcert_deinit() should 1167 * not be run on gnutls_pcert_st in list, though top-level list storage 1168 * should be freed. On failure, ownership is not transferred for either. */ 1169 gnutls_free(pcert_list); 1170 pc->ssl_pemfile_pkey = NULL; 1171 pc->ssl_cred = ssl_cred; 1172 1173 /* release lists used to configure pc->ssl_cred */ 1174 mod_gnutls_free_config_crts(pc->ssl_pemfile_x509); 1175 pc->ssl_pemfile_x509 = NULL; 1176 1177 return 0; 1178 } 1179 1180 1181 static void * 1182 network_gnutls_load_pemfile (server *srv, const buffer *pemfile, const buffer *privkey, const buffer *ssl_stapling_file) 1183 { 1184 #if 0 /* see comments in mod_gnutls_construct_crt_chain() above */ 1185 1186 gnutls_certificate_credentials_t ssl_cred = NULL; 1187 int rc; 1188 1189 rc = gnutls_certificate_allocate_credentials(&ssl_cred); 1190 if (rc < 0) return NULL; 1191 1192 rc = gnutls_certificate_set_x509_key_file2(ssl_cred, 1193 pemfile->ptr, privkey->ptr, 1194 GNUTLS_X509_FMT_PEM, NULL, 0); 1195 if (rc < 0) { 1196 elogf(srv->errh, __FILE__, __LINE__, rc, 1197 "gnutls_certificate_set_x509_key_file2(%s, %s)", 1198 pemfile->ptr, privkey->ptr); 1199 gnutls_certificate_free_credentials(ssl_cred); 1200 return NULL; 1201 } 1202 1203 plugin_cert *pc = ck_malloc(sizeof(plugin_cert)); 1204 pc->ssl_cred = ssl_cred; 1205 pc->trust_inited = 0; 1206 1207 return pc; 1208 1209 #else 1210 1211 gnutls_datum_t *d = mod_gnutls_load_config_crts(pemfile->ptr, srv->errh); 1212 if (NULL == d) return NULL; 1213 if (0 == d->size) { 1214 mod_gnutls_free_config_crts(d); 1215 return NULL; 1216 } 1217 1218 gnutls_privkey_t pkey = mod_gnutls_load_config_pkey(privkey->ptr,srv->errh); 1219 if (NULL == pkey) { 1220 mod_gnutls_free_config_crts(d); 1221 return NULL; 1222 } 1223 1224 plugin_cert *pc = ck_malloc(sizeof(plugin_cert)); 1225 pc->ssl_cred = NULL; 1226 pc->trust_inited = 0; 1227 pc->ssl_pemfile_x509 = d; 1228 pc->ssl_pemfile_pkey = pkey; 1229 pc->ssl_stapling_file= ssl_stapling_file; 1230 pc->ssl_stapling_loadts = 0; 1231 pc->ssl_stapling_nextts = 0; 1232 pc->must_staple = 1233 mod_gnutls_crt_must_staple(((gnutls_x509_crt_t *)(void *)d->data)[0]); 1234 1235 if (d->size > 1) { /*(certificate chain provided)*/ 1236 int rc = mod_gnutls_construct_crt_chain(pc, d, srv->errh); 1237 if (rc < 0) { 1238 mod_gnutls_free_config_crts(d); 1239 gnutls_privkey_deinit(pkey); 1240 free(pc); 1241 return NULL; 1242 } 1243 } 1244 1245 if (pc->ssl_stapling_file) { 1246 if (mod_gnutls_reload_stapling_file(srv, pc, log_epoch_secs) < 0) { 1247 /* continue without OCSP response if there is an error */ 1248 } 1249 } 1250 else if (pc->must_staple) { 1251 log_error(srv->errh, __FILE__, __LINE__, 1252 "certificate %s marked OCSP Must-Staple, " 1253 "but ssl.stapling-file not provided", pemfile->ptr); 1254 } 1255 1256 #if 0 1257 pc->notAfter = TIME64_CAST(gnutls_x509_crt_get_expiration_time( 1258 ((gnutls_x509_crt_t *)(void *)d->data)[0])); 1259 #endif 1260 1261 return pc; 1262 1263 #endif 1264 } 1265 1266 1267 #if GNUTLS_VERSION_NUMBER >= 0x030200 1268 1269 static int 1270 mod_gnutls_acme_tls_1 (handler_ctx *hctx) 1271 { 1272 buffer * const b = hctx->tmp_buf; 1273 const buffer * const name = &hctx->r->uri.authority; 1274 log_error_st * const errh = hctx->r->conf.errh; 1275 int rc = GNUTLS_E_INVALID_REQUEST; 1276 1277 /* check if acme-tls/1 protocol is enabled (path to dir of cert(s) is set)*/ 1278 if (!hctx->conf.ssl_acme_tls_1) 1279 return 0; 1280 1281 /* check if SNI set server name (required for acme-tls/1 protocol) 1282 * and perform simple path checks for no '/' 1283 * and no leading '.' (e.g. ignore "." or ".." or anything beginning '.') */ 1284 if (buffer_is_blank(name)) return rc; 1285 if (NULL != strchr(name->ptr, '/')) return rc; 1286 if (name->ptr[0] == '.') return rc; 1287 #if 0 1288 if (0 != http_request_host_policy(name, hctx->r->conf.http_parseopts, 443)) 1289 return rc; 1290 #endif 1291 buffer_copy_path_len2(b, BUF_PTR_LEN(hctx->conf.ssl_acme_tls_1), 1292 BUF_PTR_LEN(name)); 1293 1294 #if 0 1295 1296 buffer * const privkey = buffer_init(); 1297 buffer_append_str2(b, BUF_PTR_LEN(b), CONST_STR_LEN(".crt.pem")); 1298 buffer_append_string_len(privkey, CONST_STR_LEN(".key.pem")); 1299 1300 /*(similar to network_gnutls_load_pemfile() but propagates rc)*/ 1301 gnutls_certificate_credentials_t ssl_cred = NULL; 1302 rc = gnutls_certificate_allocate_credentials(&ssl_cred); 1303 if (rc < 0) { buffer_free(privkey); return rc; } 1304 rc = gnutls_certificate_set_x509_key_file2(ssl_cred, 1305 b->ptr, privkey->ptr, 1306 GNUTLS_X509_FMT_PEM, NULL, 0); 1307 if (rc < 0) { 1308 elogf(errh, __FILE__, __LINE__, rc, 1309 "failed to load acme-tls/1 cert (%s, %s)", 1310 b->ptr, privkey->ptr); 1311 buffer_free(privkey); 1312 gnutls_certificate_free_credentials(ssl_cred); 1313 return rc; 1314 } 1315 buffer_free(privkey); 1316 1317 #else 1318 1319 /* gnutls_certificate_set_x509_key_file2() does not securely wipe 1320 * sensitive data from memory, so take a few extra steps */ 1321 1322 /* similar to network_gnutls_load_pemfile() */ 1323 1324 uint32_t len = buffer_clen(b); 1325 buffer_append_string_len(b, CONST_STR_LEN(".crt.pem")); 1326 1327 gnutls_datum_t *d = mod_gnutls_load_config_crts(b->ptr, errh); 1328 if (NULL == d) return GNUTLS_E_FILE_ERROR; 1329 if (0 == d->size) { 1330 mod_gnutls_free_config_crts(d); 1331 return GNUTLS_E_FILE_ERROR; 1332 } 1333 1334 buffer_truncate(b, len); 1335 buffer_append_string_len(b, CONST_STR_LEN(".key.pem")); 1336 1337 gnutls_privkey_t pkey = mod_gnutls_load_config_pkey(b->ptr, errh); 1338 if (NULL == pkey) { 1339 mod_gnutls_free_config_crts(d); 1340 return GNUTLS_E_FILE_ERROR; 1341 } 1342 1343 plugin_cert pc; 1344 pc.ssl_cred = NULL; 1345 pc.trust_inited = 0; 1346 pc.ssl_pemfile_x509 = d; 1347 pc.ssl_pemfile_pkey = pkey; 1348 1349 rc = mod_gnutls_construct_crt_chain(&pc, d, errh); 1350 if (rc < 0) { 1351 mod_gnutls_free_config_crts(d); 1352 gnutls_privkey_deinit(pkey); 1353 return rc; 1354 } 1355 1356 gnutls_certificate_credentials_t ssl_cred = pc.ssl_cred; 1357 1358 #endif 1359 1360 hctx->acme_tls_1_cred = ssl_cred; /*(save ptr and free later)*/ 1361 1362 gnutls_credentials_clear(hctx->ssl); 1363 rc = gnutls_credentials_set(hctx->ssl, GNUTLS_CRD_CERTIFICATE, ssl_cred); 1364 if (rc < 0) { 1365 elogf(hctx->r->conf.errh, __FILE__, __LINE__, rc, 1366 "failed to set acme-tls/1 certificate for TLS server name %s", 1367 hctx->r->uri.authority.ptr); 1368 return rc; 1369 } 1370 1371 /*(acme-tls/1 is separate from certificate auth access to website)*/ 1372 gnutls_certificate_server_set_request(hctx->ssl, GNUTLS_CERT_IGNORE); 1373 1374 return GNUTLS_E_SUCCESS; /* 0 */ 1375 } 1376 1377 1378 static int 1379 mod_gnutls_alpn_h2_policy (handler_ctx * const hctx) 1380 { 1381 /*(currently called after handshake has completed)*/ 1382 #if 0 /* SNI omitted by client when connecting to IP instead of to name */ 1383 if (buffer_is_blank(&hctx->r->uri.authority)) { 1384 log_error(hctx->errh, __FILE__, __LINE__, 1385 "SSL: error ALPN h2 without SNI"); 1386 return -1; 1387 } 1388 #endif 1389 if (gnutls_protocol_get_version(hctx->ssl) < GNUTLS_TLS1_2) { 1390 /*(future: if DTLS supported by lighttpd, add DTLS condition)*/ 1391 log_error(hctx->errh, __FILE__, __LINE__, 1392 "SSL: error ALPN h2 requires TLSv1.2 or later"); 1393 return -1; 1394 } 1395 1396 return 0; 1397 } 1398 1399 1400 enum { 1401 MOD_GNUTLS_ALPN_HTTP11 = 1 1402 ,MOD_GNUTLS_ALPN_HTTP10 = 2 1403 ,MOD_GNUTLS_ALPN_H2 = 3 1404 ,MOD_GNUTLS_ALPN_ACME_TLS_1 = 4 1405 }; 1406 1407 1408 /* https://www.iana.org/assignments/tls-extensiontype-values/tls-extensiontype-values.xhtml#alpn-protocol-ids */ 1409 static int 1410 mod_gnutls_ALPN (handler_ctx * const hctx, const unsigned char * const in, const unsigned int inlen) 1411 { 1412 /*(skip first two bytes which should match inlen-2)*/ 1413 for (unsigned int i = 2, n; i < inlen; i += n) { 1414 n = in[i++]; 1415 if (i+n > inlen || 0 == n) break; 1416 1417 switch (n) { 1418 case 2: /* "h2" */ 1419 if (in[i] == 'h' && in[i+1] == '2') { 1420 if (!hctx->r->conf.h2proto) continue; 1421 hctx->alpn = MOD_GNUTLS_ALPN_H2; 1422 if (hctx->r->handler_module == NULL)/*(e.g. not mod_sockproxy)*/ 1423 hctx->r->http_version = HTTP_VERSION_2; 1424 return GNUTLS_E_SUCCESS; 1425 } 1426 continue; 1427 case 8: /* "http/1.1" "http/1.0" */ 1428 if (0 == memcmp(in+i, "http/1.", 7)) { 1429 if (in[i+7] == '1') { 1430 hctx->alpn = MOD_GNUTLS_ALPN_HTTP11; 1431 return GNUTLS_E_SUCCESS; 1432 } 1433 if (in[i+7] == '0') { 1434 hctx->alpn = MOD_GNUTLS_ALPN_HTTP10; 1435 return GNUTLS_E_SUCCESS; 1436 } 1437 } 1438 continue; 1439 case 10: /* "acme-tls/1" */ 1440 if (0 == memcmp(in+i, "acme-tls/1", 10)) { 1441 int rc = mod_gnutls_acme_tls_1(hctx); 1442 if (0 == rc) { 1443 hctx->alpn = MOD_GNUTLS_ALPN_ACME_TLS_1; 1444 return GNUTLS_E_SUCCESS; 1445 } 1446 return rc; 1447 } 1448 continue; 1449 default: 1450 continue; 1451 } 1452 } 1453 1454 return GNUTLS_E_SUCCESS; 1455 } 1456 1457 #endif /* GNUTLS_VERSION_NUMBER >= 0x030200 */ 1458 1459 1460 static int 1461 mod_gnutls_SNI(handler_ctx * const hctx, 1462 const unsigned char *servername, unsigned int len) 1463 { 1464 /* https://www.gnutls.org/manual/gnutls.html#Virtual-hosts-and-credentials 1465 * figure the advertized name - the following hack relies on the fact that 1466 * this extension only supports DNS names, and due to a protocol bug cannot 1467 * be extended to support anything else. */ 1468 if (len < 5) return 0; 1469 len -= 5; 1470 servername += 5; 1471 request_st * const r = hctx->r; 1472 buffer_copy_string_len(&r->uri.scheme, CONST_STR_LEN("https")); 1473 1474 if (len >= 1024) { /*(expecting < 256; TLSEXT_MAXLEN_host_name is 255)*/ 1475 log_error(r->conf.errh, __FILE__, __LINE__, 1476 "GnuTLS: SNI name too long %.*s", (int)len, servername); 1477 return GNUTLS_E_INVALID_REQUEST; 1478 } 1479 1480 /* use SNI to patch mod_gnutls config and then reset COMP_HTTP_HOST */ 1481 buffer_copy_string_len_lc(&r->uri.authority, (const char *)servername, len); 1482 #if 0 1483 /*(r->uri.authority used below for configuration before request read; 1484 * revisit for h2)*/ 1485 if (0 != http_request_host_policy(&r->uri.authority, 1486 r->conf.http_parseopts, 443)) 1487 return GNUTLS_E_INVALID_REQUEST; 1488 #endif 1489 1490 r->conditional_is_valid |= (1 << COMP_HTTP_SCHEME) 1491 | (1 << COMP_HTTP_HOST); 1492 1493 mod_gnutls_patch_config(r, &hctx->conf); 1494 /* reset COMP_HTTP_HOST so that conditions re-run after request hdrs read */ 1495 /*(done in configfile-glue.c:config_cond_cache_reset() after request hdrs read)*/ 1496 /*config_cond_cache_reset_item(r, COMP_HTTP_HOST);*/ 1497 /*buffer_clear(&r->uri.authority);*/ 1498 1499 return 0; 1500 } 1501 1502 1503 static int 1504 mod_gnutls_client_hello_ext_cb(void *ctx, unsigned int tls_id, 1505 const unsigned char *data, unsigned int dlen) 1506 { 1507 switch (tls_id) { 1508 case 0: /* Server Name */ 1509 return mod_gnutls_SNI((handler_ctx *)ctx, data, dlen); 1510 #if GNUTLS_VERSION_NUMBER >= 0x030200 1511 case 16: /* ALPN */ 1512 return mod_gnutls_ALPN((handler_ctx *)ctx, data, dlen); 1513 #endif 1514 /*case 35:*/ /* Session Ticket */ 1515 default: 1516 break; 1517 } 1518 1519 return GNUTLS_E_SUCCESS; /* 0 */ 1520 } 1521 1522 1523 static int 1524 mod_gnutls_client_hello_hook(gnutls_session_t ssl, unsigned int htype, 1525 unsigned when, unsigned int incoming, 1526 const gnutls_datum_t *msg) 1527 { 1528 /*assert(htype == GNUTLS_HANDSHAKE_CLIENT_HELLO);*/ 1529 /*assert(when == GNUTLS_HOOK_PRE);*/ 1530 UNUSED(htype); 1531 UNUSED(when); 1532 UNUSED(incoming); 1533 1534 handler_ctx * const hctx = gnutls_session_get_ptr(ssl); 1535 #if GNUTLS_VERSION_NUMBER >= 0x030200 1536 /*(do not repeat if acme-tls/1 creds have been set 1537 * and still in handshake (hctx->alpn not unset yet))*/ 1538 if (hctx->alpn == MOD_GNUTLS_ALPN_ACME_TLS_1) 1539 return GNUTLS_E_SUCCESS; /* 0 */ 1540 #endif 1541 /* ??? why might this be called more than once ??? renegotiation? */ 1542 void *existing_cred = NULL; 1543 if (0 == gnutls_credentials_get(ssl, GNUTLS_CRD_CERTIFICATE, &existing_cred) 1544 && existing_cred) 1545 return GNUTLS_E_SUCCESS; /* 0 */ 1546 1547 int rc = gnutls_ext_raw_parse(hctx, mod_gnutls_client_hello_ext_cb, msg, 1548 GNUTLS_EXT_RAW_FLAG_TLS_CLIENT_HELLO); 1549 if (rc < 0) { 1550 log_error_st *errh = hctx->r->conf.errh; 1551 elog(errh, __FILE__, __LINE__, rc, "gnutls_ext_raw_parse()"); 1552 return rc; 1553 } 1554 1555 #if GNUTLS_VERSION_NUMBER >= 0x030200 1556 /* https://www.iana.org/assignments/tls-extensiontype-values/tls-extensiontype-values.xhtml#alpn-protocol-ids */ 1557 static const gnutls_datum_t alpn_protos_http_acme[] = { 1558 { (unsigned char *)CONST_STR_LEN("h2") } 1559 ,{ (unsigned char *)CONST_STR_LEN("http/1.1") } 1560 ,{ (unsigned char *)CONST_STR_LEN("http/1.0") } 1561 ,{ (unsigned char *)CONST_STR_LEN("acme-tls/1") } 1562 }; 1563 unsigned int n = hctx->conf.ssl_acme_tls_1 ? 4 : 3; 1564 const gnutls_datum_t *alpn_protos = alpn_protos_http_acme; 1565 if (!hctx->r->conf.h2proto) { 1566 ++alpn_protos; 1567 --n; 1568 } 1569 /*unsigned int flags = GNUTLS_ALPN_SERVER_PRECEDENCE;*/ 1570 rc = gnutls_alpn_set_protocols(hctx->ssl, alpn_protos, n, 0); 1571 if (rc < 0) { 1572 log_error_st *errh = hctx->r->conf.errh; 1573 elog(errh, __FILE__, __LINE__, rc, "gnutls_alpn_set_protocols()"); 1574 return rc; 1575 } 1576 /*(skip below if creds already set for acme-tls/1 1577 * via mod_gnutls_client_hello_ext_cb())*/ 1578 if (hctx->alpn == MOD_GNUTLS_ALPN_ACME_TLS_1) 1579 return GNUTLS_E_SUCCESS; /* 0 */ 1580 #endif 1581 1582 #if 0 /* must enable before GnuTLS client hello hook */ 1583 /* GnuTLS returns an error here if TLSv1.3 (? key already set ?) */ 1584 /* see mod_gnutls_handle_con_accept() */ 1585 /* future: ? handle in mod_gnutls_client_hello_ext_cb() */ 1586 if (hctx->ssl_session_ticket && session_ticket_key.size) { 1587 /* XXX: NOT done: parse client hello for session ticket extension 1588 * and choose from among multiple keys */ 1589 rc = gnutls_session_ticket_enable_server(ssl, &session_ticket_key); 1590 if (rc < 0) { 1591 elog(hctx->r->conf.errh, __FILE__, __LINE__, rc, 1592 "gnutls_session_ticket_enable_server()"); 1593 return rc; 1594 } 1595 } 1596 #endif 1597 1598 if (NULL == hctx->conf.pc->ssl_cred) { 1599 rc = mod_gnutls_construct_crt_chain(hctx->conf.pc, 1600 hctx->conf.ssl_ca_file, 1601 hctx->r->conf.errh); 1602 if (rc < 0) return rc; 1603 } 1604 1605 gnutls_certificate_credentials_t ssl_cred = hctx->conf.pc->ssl_cred; 1606 1607 hctx->verify_status = ~0u; 1608 gnutls_certificate_request_t req = GNUTLS_CERT_IGNORE; 1609 if (hctx->conf.ssl_verifyclient) { 1610 /*(cred shared; settings should be consistent across site using cred)*/ 1611 /*(i.e. settings for client certs must not differ under this cred)*/ 1612 req = hctx->conf.ssl_verifyclient_enforce 1613 ? GNUTLS_CERT_REQUIRE 1614 : GNUTLS_CERT_REQUEST; 1615 gnutls_certificate_set_verify_function(ssl_cred, mod_gnutls_verify_cb); 1616 gnutls_certificate_set_verify_limits(ssl_cred, 8200 /*(default)*/, 1617 hctx->conf.ssl_verifyclient_depth); 1618 rc = mod_gnutls_verify_set_tlist(hctx, 1); /* for client cert request */ 1619 if (rc < 0) return rc; 1620 } 1621 gnutls_certificate_server_set_request(ssl, req); 1622 1623 #if GNUTLS_VERSION_NUMBER < 0x030600 1624 if (hctx->conf.dh_params) 1625 gnutls_certificate_set_dh_params(ssl_cred, hctx->conf.dh_params); 1626 #if GNUTLS_VERSION_NUMBER >= 0x030506 1627 else 1628 gnutls_certificate_set_known_dh_params(ssl_cred, GNUTLS_SEC_PARAM_HIGH); 1629 #endif 1630 #endif 1631 1632 rc = gnutls_credentials_set(ssl, GNUTLS_CRD_CERTIFICATE, ssl_cred); 1633 if (rc < 0) { 1634 elogf(hctx->r->conf.errh, __FILE__, __LINE__, rc, 1635 "failed to set SNI certificate for TLS server name %s", 1636 hctx->r->uri.authority.ptr); 1637 return rc; 1638 } 1639 1640 return GNUTLS_E_SUCCESS; /* 0 */ 1641 } 1642 1643 1644 static int 1645 mod_gnutls_ssl_conf_ciphersuites (server *srv, plugin_config_socket *s, buffer *ciphersuites, const buffer *cipherstring); 1646 1647 1648 #if GNUTLS_VERSION_NUMBER < 0x030600 1649 static int 1650 mod_gnutls_ssl_conf_dhparameters(server *srv, plugin_config_socket *s, const buffer *dhparameters); 1651 #endif 1652 1653 1654 static int 1655 mod_gnutls_ssl_conf_curves(server *srv, plugin_config_socket *s, const buffer *curvelist); 1656 1657 1658 static void 1659 mod_gnutls_ssl_conf_proto (server *srv, plugin_config_socket *s, const buffer *minb, const buffer *maxb); 1660 1661 1662 static int 1663 mod_gnutls_ssl_conf_cmd (server *srv, plugin_config_socket *s) 1664 { 1665 /* reference: 1666 * https://www.openssl.org/docs/man1.1.1/man3/SSL_CONF_cmd.html */ 1667 int rc = 0; 1668 buffer *cipherstring = NULL; 1669 buffer *ciphersuites = NULL; 1670 buffer *minb = NULL; 1671 buffer *maxb = NULL; 1672 buffer *curves = NULL; 1673 1674 for (size_t i = 0; i < s->ssl_conf_cmd->used; ++i) { 1675 data_string *ds = (data_string *)s->ssl_conf_cmd->data[i]; 1676 if (buffer_eq_icase_slen(&ds->key, CONST_STR_LEN("CipherString"))) 1677 cipherstring = &ds->value; 1678 else if (buffer_eq_icase_slen(&ds->key, CONST_STR_LEN("Ciphersuites"))) 1679 ciphersuites = &ds->value; 1680 else if (buffer_eq_icase_slen(&ds->key, CONST_STR_LEN("Curves")) 1681 || buffer_eq_icase_slen(&ds->key, CONST_STR_LEN("Groups"))) 1682 curves = &ds->value; 1683 #if GNUTLS_VERSION_NUMBER < 0x030600 1684 else if (buffer_eq_icase_slen(&ds->key, CONST_STR_LEN("DHParameters"))){ 1685 if (!buffer_is_blank(&ds->value)) { 1686 if (!mod_gnutls_ssl_conf_dhparameters(srv, s, &ds->value)) 1687 rc = -1; 1688 } 1689 } 1690 #endif 1691 else if (buffer_eq_icase_slen(&ds->key, CONST_STR_LEN("MaxProtocol"))) 1692 maxb = &ds->value; 1693 else if (buffer_eq_icase_slen(&ds->key, CONST_STR_LEN("MinProtocol"))) 1694 minb = &ds->value; 1695 else if (buffer_eq_icase_slen(&ds->key, CONST_STR_LEN("Protocol"))) { 1696 /* openssl config for Protocol=... is complex and deprecated */ 1697 log_error(srv->errh, __FILE__, __LINE__, 1698 "GnuTLS: ssl.openssl.ssl-conf-cmd %s ignored; " 1699 "use MinProtocol=... and MaxProtocol=... instead", 1700 ds->key.ptr); 1701 } 1702 else if (buffer_eq_icase_slen(&ds->key, CONST_STR_LEN("Options"))) { 1703 for (char *v = ds->value.ptr, *e; *v; v = e) { 1704 while (*v == ' ' || *v == '\t' || *v == ',') ++v; 1705 int flag = 1; 1706 if (*v == '-') { 1707 flag = 0; 1708 ++v; 1709 } 1710 else if (*v == '+') 1711 ++v; 1712 for (e = v; light_isalpha(*e); ++e) ; 1713 switch ((int)(e-v)) { 1714 case 11: 1715 if (buffer_eq_icase_ssn(v, "Compression", 11)) { 1716 /* GnuTLS 3.6.0+ no longer implements 1717 * any support for compression */ 1718 if (!flag) continue; 1719 } 1720 break; 1721 case 13: 1722 if (buffer_eq_icase_ssn(v, "SessionTicket", 13)) { 1723 /*(translates to "%NO_TICKETS" priority str if !flag)*/ 1724 s->ssl_session_ticket = flag; 1725 continue; 1726 } 1727 break; 1728 case 16: 1729 if (buffer_eq_icase_ssn(v, "ServerPreference", 16)) { 1730 /*(translates to "%SERVER_PRECEDENCE" priority string)*/ 1731 s->ssl_honor_cipher_order = flag; 1732 continue; 1733 } 1734 break; 1735 default: 1736 break; 1737 } 1738 /* warn if not explicitly handled or ignored above */ 1739 if (!flag) --v; 1740 log_error(srv->errh, __FILE__, __LINE__, 1741 "GnuTLS: ssl.openssl.ssl-conf-cmd Options %.*s " 1742 "ignored", (int)(e-v), v); 1743 } 1744 } 1745 else if (buffer_eq_icase_slen(&ds->key, 1746 CONST_STR_LEN("gnutls-override"))) { 1747 s->priority_override = &ds->value; 1748 } 1749 #if 0 1750 else if (buffer_eq_icase_slen(&ds->key, CONST_STR_LEN("..."))) { 1751 } 1752 #endif 1753 else { 1754 /* warn if not explicitly handled or ignored above */ 1755 log_error(srv->errh, __FILE__, __LINE__, 1756 "GnuTLS: ssl.openssl.ssl-conf-cmd %s ignored", 1757 ds->key.ptr); 1758 } 1759 } 1760 1761 if (minb || maxb) /*(if at least one was set)*/ 1762 mod_gnutls_ssl_conf_proto(srv, s, minb, maxb); 1763 1764 if (!mod_gnutls_ssl_conf_ciphersuites(srv, s, ciphersuites, cipherstring)) 1765 rc = -1; 1766 1767 if (curves) { 1768 buffer_append_string_len(&s->priority_str, 1769 CONST_STR_LEN("-CURVE-ALL:")); 1770 if (!mod_gnutls_ssl_conf_curves(srv, s, curves)) 1771 rc = -1; 1772 } 1773 1774 return rc; 1775 } 1776 1777 1778 static int 1779 network_init_ssl (server *srv, plugin_config_socket *s, plugin_data *p) 1780 { 1781 int rc; 1782 UNUSED(p); 1783 1784 /* construct GnuTLS "priority" string 1785 * 1786 * default: NORMAL (since GnuTLS 3.3.0, could also use NULL for defaults) 1787 * SUITEB128 and SUITEB192 are stricter than NORMAL 1788 * (and are attempted to be supported in mod_gnutls_ssl_conf_ciphersuites()) 1789 */ 1790 1791 #if GNUTLS_VERSION_NUMBER < 0x030600 1792 /* GnuTLS 3.6.0+ no longer implements any support for compression, 1793 * but we still explicitly disable for earlier versions */ 1794 buffer_append_string_len(&s->priority_str, 1795 CONST_STR_LEN("-COMP_ALL:+COMP-NULL:")); 1796 #endif 1797 1798 if (s->ssl_cipher_list) { 1799 if (!mod_gnutls_ssl_conf_ciphersuites(srv,s,NULL,s->ssl_cipher_list)) 1800 return -1; 1801 } 1802 1803 #if GNUTLS_VERSION_NUMBER < 0x030600 1804 { 1805 if (!mod_gnutls_ssl_conf_dhparameters(srv, s, NULL)) 1806 return -1; 1807 } 1808 #endif 1809 1810 if (s->ssl_conf_cmd && s->ssl_conf_cmd->used) { 1811 if (0 != mod_gnutls_ssl_conf_cmd(srv, s)) return -1; 1812 } 1813 1814 if (s->ssl_honor_cipher_order) 1815 buffer_append_string_len(&s->priority_str, 1816 CONST_STR_LEN("%SERVER_PRECEDENCE:")); 1817 1818 if (!s->ssl_session_ticket) 1819 buffer_append_string_len(&s->priority_str, 1820 CONST_STR_LEN("%NO_TICKETS:")); 1821 1822 if (NULL == strstr(s->priority_str.ptr, "-VERS-ALL:")) 1823 mod_gnutls_ssl_conf_proto(srv, s, NULL, NULL); 1824 1825 /* explicitly disable SSLv3 unless enabled in config 1826 * (gnutls library would also need to be compiled with legacy support) */ 1827 buffer_append_string_len(&s->priority_str, 1828 CONST_STR_LEN("-VERS-SSL3.0:")); 1829 1830 /* gnutls_priority_init2() is available since GnuTLS 3.6.3 and could be 1831 * called once with s->priority_base, and a second time with s->priority_str 1832 * and GNUTLS_PRIORITY_INIT_DEF_APPEND, but preserve compat with earlier 1833 * GnuTLS by concatenating into a single priority string */ 1834 1835 buffer *b = srv->tmp_buf; 1836 if (NULL == s->priority_base) s->priority_base = "NORMAL"; 1837 buffer_copy_string_len(b, s->priority_base, strlen(s->priority_base)); 1838 if (!buffer_is_blank(&s->priority_str)) { 1839 buffer_append_char(b, ':'); 1840 uint32_t len = buffer_clen(&s->priority_str); 1841 if (s->priority_str.ptr[len-1] == ':') 1842 --len; /* remove trailing ':' */ 1843 buffer_append_string_len(b, s->priority_str.ptr, len); 1844 } 1845 1846 if (s->priority_override && !buffer_is_blank(s->priority_override)) { 1847 b = s->priority_override; 1848 s->ssl_session_ticket = (NULL == strstr(b->ptr, "%NO_TICKET")); 1849 } 1850 1851 if (p->defaults.ssl_log_noise) 1852 log_error(srv->errh, __FILE__, __LINE__, 1853 "debug: GnuTLS priority string: %s", b->ptr); 1854 1855 const char *err_pos; 1856 rc = gnutls_priority_init(&s->priority_cache, b->ptr, &err_pos); 1857 if (rc < 0) { 1858 elogf(srv->errh, __FILE__, __LINE__, rc, 1859 "gnutls_priority_init() error near %s", err_pos); 1860 return -1; 1861 } 1862 1863 return 0; 1864 } 1865 1866 1867 #define LIGHTTPD_DEFAULT_CIPHER_LIST \ 1868 "EECDH+AESGCM:AES256+EECDH:CHACHA20:!SHA1:!SHA256:!SHA384" 1869 1870 1871 static int 1872 mod_gnutls_set_defaults_sockets(server *srv, plugin_data *p) 1873 { 1874 static const config_plugin_keys_t cpk[] = { 1875 { CONST_STR_LEN("ssl.engine"), 1876 T_CONFIG_BOOL, 1877 T_CONFIG_SCOPE_SOCKET } 1878 ,{ CONST_STR_LEN("ssl.cipher-list"), 1879 T_CONFIG_STRING, 1880 T_CONFIG_SCOPE_SOCKET } 1881 ,{ CONST_STR_LEN("ssl.openssl.ssl-conf-cmd"), 1882 T_CONFIG_ARRAY_KVSTRING, 1883 T_CONFIG_SCOPE_SOCKET } 1884 ,{ CONST_STR_LEN("ssl.pemfile"), /* included to process global scope */ 1885 T_CONFIG_STRING, 1886 T_CONFIG_SCOPE_CONNECTION } 1887 ,{ CONST_STR_LEN("ssl.stek-file"), 1888 T_CONFIG_STRING, 1889 T_CONFIG_SCOPE_SERVER } 1890 ,{ NULL, 0, 1891 T_CONFIG_UNSET, 1892 T_CONFIG_SCOPE_UNSET } 1893 }; 1894 static const buffer default_ssl_cipher_list = 1895 { CONST_STR_LEN(LIGHTTPD_DEFAULT_CIPHER_LIST), 0 }; 1896 1897 p->ssl_ctxs = ck_calloc(srv->config_context->used, sizeof(plugin_ssl_ctx)); 1898 1899 int rc = HANDLER_GO_ON; 1900 plugin_data_base srvplug; 1901 memset(&srvplug, 0, sizeof(srvplug)); 1902 plugin_data_base * const ps = &srvplug; 1903 if (!config_plugin_values_init(srv, ps, cpk, "mod_gnutls")) 1904 return HANDLER_ERROR; 1905 1906 plugin_config_socket defaults; 1907 memset(&defaults, 0, sizeof(defaults)); 1908 defaults.ssl_session_ticket = 1; /* enabled by default */ 1909 defaults.ssl_cipher_list = &default_ssl_cipher_list; 1910 1911 /* process and validate config directives for global and $SERVER["socket"] 1912 * (init i to 0 if global context; to 1 to skip empty global context) */ 1913 for (int i = !ps->cvlist[0].v.u2[1]; i < ps->nconfig; ++i) { 1914 config_cond_info cfginfo; 1915 config_get_config_cond_info(&cfginfo, (uint32_t)ps->cvlist[i].k_id); 1916 int is_socket_scope = (0 == i || cfginfo.comp == COMP_SERVER_SOCKET); 1917 int count_not_engine = 0; 1918 1919 plugin_config_socket conf; 1920 memcpy(&conf, &defaults, sizeof(conf)); 1921 config_plugin_value_t *cpv = ps->cvlist + ps->cvlist[i].v.u2[0]; 1922 for (; -1 != cpv->k_id; ++cpv) { 1923 /* ignore ssl.pemfile (k_id=6); included to process global scope */ 1924 if (!is_socket_scope && cpv->k_id != 6) { 1925 log_error(srv->errh, __FILE__, __LINE__, 1926 "GnuTLS: %s is valid only in global scope or " 1927 "$SERVER[\"socket\"] condition", cpk[cpv->k_id].k); 1928 continue; 1929 } 1930 ++count_not_engine; 1931 switch (cpv->k_id) { 1932 case 0: /* ssl.engine */ 1933 conf.ssl_enabled = (0 != cpv->v.u); 1934 --count_not_engine; 1935 break; 1936 case 1: /* ssl.cipher-list */ 1937 if (!buffer_is_blank(cpv->v.b)) { 1938 conf.ssl_cipher_list = cpv->v.b; 1939 /*(historical use might list non-PFS ciphers)*/ 1940 conf.ssl_honor_cipher_order = 1; 1941 log_error(srv->errh, __FILE__, __LINE__, 1942 "%s is deprecated. " 1943 "Please prefer lighttpd secure TLS defaults, or use " 1944 "ssl.openssl.ssl-conf-cmd \"CipherString\" to set custom " 1945 "cipher list.", cpk[cpv->k_id].k); 1946 } 1947 break; 1948 case 2: /* ssl.openssl.ssl-conf-cmd */ 1949 *(const array **)&conf.ssl_conf_cmd = cpv->v.a; 1950 break; 1951 case 3: /* ssl.pemfile */ 1952 /* ignore here; included to process global scope when 1953 * ssl.pemfile is set, but ssl.engine is not "enable" */ 1954 break; 1955 case 4: /* ssl.stek-file */ 1956 if (!buffer_is_blank(cpv->v.b)) 1957 p->ssl_stek_file = cpv->v.b->ptr; 1958 break; 1959 default:/* should not happen */ 1960 break; 1961 } 1962 } 1963 if (HANDLER_GO_ON != rc) break; 1964 if (0 == i) memcpy(&defaults, &conf, sizeof(conf)); 1965 1966 if (0 != i && !conf.ssl_enabled) continue; 1967 1968 /* fill plugin_config_socket with global context then $SERVER["socket"] 1969 * only for directives directly in current $SERVER["socket"] condition*/ 1970 1971 /*conf.pc = p->defaults.pc;*/ 1972 conf.ssl_verifyclient = p->defaults.ssl_verifyclient; 1973 conf.ssl_verifyclient_enforce = p->defaults.ssl_verifyclient_enforce; 1974 conf.ssl_verifyclient_depth = p->defaults.ssl_verifyclient_depth; 1975 1976 int sidx = ps->cvlist[i].k_id; 1977 for (int j = !p->cvlist[0].v.u2[1]; j < p->nconfig; ++j) { 1978 if (p->cvlist[j].k_id != sidx) continue; 1979 /*if (0 == sidx) break;*//*(repeat to get ssl_pemfile,ssl_privkey)*/ 1980 cpv = p->cvlist + p->cvlist[j].v.u2[0]; 1981 for (; -1 != cpv->k_id; ++cpv) { 1982 ++count_not_engine; 1983 switch (cpv->k_id) { 1984 case 0: /* ssl.pemfile */ 1985 if (cpv->vtype == T_CONFIG_LOCAL) 1986 conf.pc = cpv->v.v; 1987 break; 1988 case 7: /* ssl.verifyclient.activate */ 1989 conf.ssl_verifyclient = (0 != cpv->v.u); 1990 break; 1991 case 8: /* ssl.verifyclient.enforce */ 1992 conf.ssl_verifyclient_enforce = (0 != cpv->v.u); 1993 break; 1994 case 9: /* ssl.verifyclient.depth */ 1995 conf.ssl_verifyclient_depth = (unsigned char)cpv->v.shrt; 1996 break; 1997 default: 1998 break; 1999 } 2000 } 2001 break; 2002 } 2003 2004 if (NULL == conf.pc) { 2005 if (0 == i && !conf.ssl_enabled) continue; 2006 if (0 != i) { 2007 /* inherit ssl settings from global scope 2008 * (if only ssl.engine = "enable" and no other ssl.* settings) 2009 * (This is for convenience when defining both IPv4 and IPv6 2010 * and desiring to inherit the ssl config from global context 2011 * without having to duplicate the directives)*/ 2012 if (count_not_engine 2013 || (conf.ssl_enabled 2014 && NULL == p->ssl_ctxs[0].priority_cache)) { 2015 log_error(srv->errh, __FILE__, __LINE__, 2016 "GnuTLS: ssl.pemfile has to be set in same " 2017 "$SERVER[\"socket\"] scope as other ssl.* directives, " 2018 "unless only ssl.engine is set, inheriting ssl.* from " 2019 "global scope"); 2020 rc = HANDLER_ERROR; 2021 continue; 2022 } 2023 plugin_ssl_ctx * const s = p->ssl_ctxs + sidx; 2024 *s = *p->ssl_ctxs;/*(copy struct of ssl_ctx from global scope)*/ 2025 continue; 2026 } 2027 /* PEM file is required */ 2028 log_error(srv->errh, __FILE__, __LINE__, 2029 "GnuTLS: ssl.pemfile has to be set when ssl.engine = \"enable\""); 2030 rc = HANDLER_ERROR; 2031 continue; 2032 } 2033 2034 /* (initialize once if module enabled) */ 2035 if (!mod_gnutls_init_once_gnutls()) { 2036 rc = HANDLER_ERROR; 2037 break; 2038 } 2039 2040 /* configure ssl_ctx for socket */ 2041 2042 /*conf.ssl_ctx = NULL;*//*(filled by network_init_ssl() even on error)*/ 2043 if (0 == network_init_ssl(srv, &conf, p)) { 2044 plugin_ssl_ctx * const s = p->ssl_ctxs + sidx; 2045 s->ssl_session_ticket = conf.ssl_session_ticket; 2046 s->priority_cache = conf.priority_cache; 2047 #if GNUTLS_VERSION_NUMBER < 0x030600 2048 s->dh_params = conf.dh_params; 2049 #endif 2050 } 2051 else { 2052 gnutls_priority_deinit(conf.priority_cache); 2053 #if GNUTLS_VERSION_NUMBER < 0x030600 2054 gnutls_dh_params_deinit(conf.dh_params); 2055 #endif 2056 rc = HANDLER_ERROR; 2057 } 2058 free(conf.priority_str.ptr); 2059 } 2060 2061 if (rc == HANDLER_GO_ON && ssl_is_init) 2062 mod_gnutls_session_ticket_key_check(srv, p, log_epoch_secs); 2063 2064 free(srvplug.cvlist); 2065 return rc; 2066 } 2067 2068 2069 SETDEFAULTS_FUNC(mod_gnutls_set_defaults) 2070 { 2071 static const config_plugin_keys_t cpk[] = { 2072 { CONST_STR_LEN("ssl.pemfile"), 2073 T_CONFIG_STRING, 2074 T_CONFIG_SCOPE_CONNECTION } 2075 ,{ CONST_STR_LEN("ssl.privkey"), 2076 T_CONFIG_STRING, 2077 T_CONFIG_SCOPE_CONNECTION } 2078 ,{ CONST_STR_LEN("ssl.ca-file"), 2079 T_CONFIG_STRING, 2080 T_CONFIG_SCOPE_CONNECTION } 2081 ,{ CONST_STR_LEN("ssl.ca-dn-file"), 2082 T_CONFIG_STRING, 2083 T_CONFIG_SCOPE_CONNECTION } 2084 ,{ CONST_STR_LEN("ssl.ca-crl-file"), 2085 T_CONFIG_STRING, 2086 T_CONFIG_SCOPE_CONNECTION } 2087 ,{ CONST_STR_LEN("ssl.read-ahead"), 2088 T_CONFIG_BOOL, 2089 T_CONFIG_SCOPE_CONNECTION } 2090 ,{ CONST_STR_LEN("ssl.disable-client-renegotiation"), 2091 T_CONFIG_BOOL, /*(directive ignored)*/ 2092 T_CONFIG_SCOPE_CONNECTION } 2093 ,{ CONST_STR_LEN("ssl.verifyclient.activate"), 2094 T_CONFIG_BOOL, 2095 T_CONFIG_SCOPE_CONNECTION } 2096 ,{ CONST_STR_LEN("ssl.verifyclient.enforce"), 2097 T_CONFIG_BOOL, 2098 T_CONFIG_SCOPE_CONNECTION } 2099 ,{ CONST_STR_LEN("ssl.verifyclient.depth"), 2100 T_CONFIG_SHORT, 2101 T_CONFIG_SCOPE_CONNECTION } 2102 ,{ CONST_STR_LEN("ssl.verifyclient.username"), 2103 T_CONFIG_STRING, 2104 T_CONFIG_SCOPE_CONNECTION } 2105 ,{ CONST_STR_LEN("ssl.verifyclient.exportcert"), 2106 T_CONFIG_BOOL, 2107 T_CONFIG_SCOPE_CONNECTION } 2108 ,{ CONST_STR_LEN("ssl.acme-tls-1"), 2109 T_CONFIG_STRING, 2110 T_CONFIG_SCOPE_CONNECTION } 2111 ,{ CONST_STR_LEN("ssl.stapling-file"), 2112 T_CONFIG_STRING, 2113 T_CONFIG_SCOPE_CONNECTION } 2114 ,{ CONST_STR_LEN("debug.log-ssl-noise"), 2115 T_CONFIG_BOOL, 2116 T_CONFIG_SCOPE_CONNECTION } 2117 ,{ CONST_STR_LEN("ssl.verifyclient.ca-file"), 2118 T_CONFIG_STRING, 2119 T_CONFIG_SCOPE_CONNECTION } 2120 ,{ CONST_STR_LEN("ssl.verifyclient.ca-dn-file"), 2121 T_CONFIG_STRING, 2122 T_CONFIG_SCOPE_CONNECTION } 2123 ,{ CONST_STR_LEN("ssl.verifyclient.ca-crl-file"), 2124 T_CONFIG_STRING, 2125 T_CONFIG_SCOPE_CONNECTION } 2126 ,{ NULL, 0, 2127 T_CONFIG_UNSET, 2128 T_CONFIG_SCOPE_UNSET } 2129 }; 2130 2131 plugin_data * const p = p_d; 2132 p->srv = srv; 2133 if (!config_plugin_values_init(srv, p, cpk, "mod_gnutls")) 2134 return HANDLER_ERROR; 2135 2136 /* process and validate config directives 2137 * (init i to 0 if global context; to 1 to skip empty global context) */ 2138 for (int i = !p->cvlist[0].v.u2[1]; i < p->nconfig; ++i) { 2139 config_plugin_value_t *cpv = p->cvlist + p->cvlist[i].v.u2[0]; 2140 config_plugin_value_t *pemfile = NULL; 2141 config_plugin_value_t *privkey = NULL; 2142 const buffer *ssl_stapling_file = NULL; 2143 for (; -1 != cpv->k_id; ++cpv) { 2144 switch (cpv->k_id) { 2145 case 0: /* ssl.pemfile */ 2146 if (!buffer_is_blank(cpv->v.b)) pemfile = cpv; 2147 break; 2148 case 1: /* ssl.privkey */ 2149 if (!buffer_is_blank(cpv->v.b)) privkey = cpv; 2150 break; 2151 case 15:/* ssl.verifyclient.ca-file */ 2152 if (cpv->k_id == 15) cpv->k_id = 2; 2153 __attribute_fallthrough__ 2154 case 16:/* ssl.verifyclient.ca-dn-file */ 2155 if (cpv->k_id == 16) cpv->k_id = 3; 2156 __attribute_fallthrough__ 2157 case 2: /* ssl.ca-file */ 2158 case 3: /* ssl.ca-dn-file */ 2159 if (!buffer_is_blank(cpv->v.b)) { 2160 gnutls_datum_t *d = 2161 mod_gnutls_load_config_crts(cpv->v.b->ptr, srv->errh); 2162 if (d != NULL) { 2163 cpv->vtype = T_CONFIG_LOCAL; 2164 cpv->v.v = d; 2165 } 2166 else { 2167 log_error(srv->errh, __FILE__, __LINE__, 2168 "%s = %s", cpk[cpv->k_id].k, cpv->v.b->ptr); 2169 return HANDLER_ERROR; 2170 } 2171 } 2172 break; 2173 case 17:/* ssl.verifyclient.ca-crl-file */ 2174 cpv->k_id = 4; 2175 __attribute_fallthrough__ 2176 case 4: /* ssl.ca-crl-file */ 2177 if (!buffer_is_blank(cpv->v.b)) { 2178 gnutls_datum_t *d = 2179 mod_gnutls_load_config_crls(cpv->v.b->ptr, srv->errh); 2180 if (d != NULL) { 2181 cpv->vtype = T_CONFIG_LOCAL; 2182 cpv->v.v = d; 2183 } 2184 else { 2185 log_error(srv->errh, __FILE__, __LINE__, 2186 "%s = %s", cpk[cpv->k_id].k, cpv->v.b->ptr); 2187 return HANDLER_ERROR; 2188 } 2189 } 2190 break; 2191 case 5: /* ssl.read-ahead */ 2192 case 6: /* ssl.disable-client-renegotiation */ 2193 /*(ignored; unsafe renegotiation disabled by default)*/ 2194 case 7: /* ssl.verifyclient.activate */ 2195 case 8: /* ssl.verifyclient.enforce */ 2196 break; 2197 case 9: /* ssl.verifyclient.depth */ 2198 if (cpv->v.shrt > 255) { 2199 log_error(srv->errh, __FILE__, __LINE__, 2200 "GnuTLS: %s is absurdly large (%hu); limiting to 255", 2201 cpk[cpv->k_id].k, cpv->v.shrt); 2202 cpv->v.shrt = 255; 2203 } 2204 break; 2205 case 10:/* ssl.verifyclient.username */ 2206 if (buffer_is_blank(cpv->v.b)) 2207 cpv->v.b = NULL; 2208 break; 2209 case 11:/* ssl.verifyclient.exportcert */ 2210 break; 2211 case 12:/* ssl.acme-tls-1 */ 2212 if (buffer_is_blank(cpv->v.b)) 2213 cpv->v.b = NULL; 2214 break; 2215 case 13:/* ssl.stapling-file */ 2216 if (!buffer_is_blank(cpv->v.b)) 2217 ssl_stapling_file = cpv->v.b; 2218 break; 2219 case 14:/* debug.log-ssl-noise */ 2220 #if 0 /*(handled further above)*/ 2221 case 15:/* ssl.verifyclient.ca-file */ 2222 case 16:/* ssl.verifyclient.ca-dn-file */ 2223 case 17:/* ssl.verifyclient.ca-crl-file */ 2224 #endif 2225 break; 2226 default:/* should not happen */ 2227 break; 2228 } 2229 } 2230 2231 if (pemfile) { 2232 if (NULL == privkey) privkey = pemfile; 2233 pemfile->v.v = 2234 network_gnutls_load_pemfile(srv, pemfile->v.b, privkey->v.b, 2235 ssl_stapling_file); 2236 if (pemfile->v.v) 2237 pemfile->vtype = T_CONFIG_LOCAL; 2238 else 2239 return HANDLER_ERROR; 2240 } 2241 } 2242 2243 p->defaults.ssl_verifyclient = 0; 2244 p->defaults.ssl_verifyclient_enforce = 1; 2245 p->defaults.ssl_verifyclient_depth = 9; 2246 p->defaults.ssl_verifyclient_export_cert = 0; 2247 p->defaults.ssl_read_ahead = 0; 2248 2249 /* initialize p->defaults from global config context */ 2250 if (p->nconfig > 0 && p->cvlist->v.u2[1]) { 2251 const config_plugin_value_t *cpv = p->cvlist + p->cvlist->v.u2[0]; 2252 if (-1 != cpv->k_id) 2253 mod_gnutls_merge_config(&p->defaults, cpv); 2254 } 2255 2256 return mod_gnutls_set_defaults_sockets(srv, p); 2257 } 2258 2259 2260 /* local_send_buffer is a static buffer of size (LOCAL_SEND_BUFSIZE) 2261 * 2262 * buffer is allocated once, is NOT realloced (note: not thread-safe) 2263 * */ 2264 2265 /* copy small mem chunks into single large buffer 2266 * before gnutls_record_send() to reduce number times 2267 * write() called underneath gnutls_record_send() and 2268 * potentially reduce number of packets generated if TCP_NODELAY 2269 * Alternatively, GnuTLS provides gnutls_record_cork() and 2270 * gnutls_record_uncork(), not currently used by mod_gnutls */ 2271 2272 2273 __attribute_cold__ 2274 static int 2275 mod_gnutls_write_err(connection *con, handler_ctx *hctx, int wr, size_t wr_len) 2276 { 2277 switch (wr) { 2278 case GNUTLS_E_AGAIN: 2279 case GNUTLS_E_INTERRUPTED: 2280 if (gnutls_record_get_direction(hctx->ssl)) 2281 con->is_writable = -1; 2282 else 2283 con->is_readable = -1; 2284 break; /* try again later */ 2285 default: 2286 #if 0 2287 /* ??? how to check for EPIPE or ECONNRESET and skip logging ??? */ 2288 if (hctx->conf.ssl_log_noise) 2289 elog(hctx->r->conf.errh, __FILE__, __LINE__, wr, __func__); 2290 #endif 2291 elog(hctx->r->conf.errh, __FILE__, __LINE__, wr, __func__); 2292 return -1; 2293 } 2294 2295 /* partial write; save attempted wr_len */ 2296 hctx->pending_write = wr_len; 2297 2298 return 0; /* try again later */ 2299 } 2300 2301 2302 __attribute_cold__ 2303 static int 2304 mod_gnutls_read_err(connection *con, handler_ctx *hctx, int rc) 2305 { 2306 switch (rc) { 2307 case GNUTLS_E_AGAIN: 2308 case GNUTLS_E_INTERRUPTED: 2309 if (gnutls_record_get_direction(hctx->ssl)) 2310 con->is_writable = -1; 2311 con->is_readable = 0; 2312 return 0; 2313 #if 0 2314 case GNUTLS_E_SESSION_EOF: /*(not exposed by library)*/ 2315 /* XXX: future: save state to avoid future read after response? */ 2316 con->is_readable = 0; 2317 r->keep_alive = 0; 2318 return (hctx->handshake ? -2 : -1); /*(-1 error if during handshake)*/ 2319 #endif 2320 case GNUTLS_E_REHANDSHAKE: 2321 if (!hctx->handshake) return -1; /*(not expected during handshake)*/ 2322 #if 0 2323 if (gnutls_safe_renegotiation_status(hctx->ssl)) { 2324 hctx->handshake = 0; 2325 return con->network_read(con, cq, max_bytes); 2326 } 2327 #else 2328 return -1; 2329 #endif 2330 case GNUTLS_E_WARNING_ALERT_RECEIVED: 2331 case GNUTLS_E_FATAL_ALERT_RECEIVED: 2332 { 2333 const char *str; 2334 gnutls_alert_description_t alert = gnutls_alert_get(hctx->ssl); 2335 switch (alert) { 2336 case GNUTLS_A_NO_RENEGOTIATION: 2337 return 0; /*(ignore non-fatal alert from client)*/ 2338 case GNUTLS_A_HANDSHAKE_FAILURE: 2339 case GNUTLS_A_CLOSE_NOTIFY: /*(not exposed by library)*/ 2340 case GNUTLS_A_UNKNOWN_CA: 2341 case GNUTLS_A_CERTIFICATE_UNKNOWN: 2342 case GNUTLS_A_BAD_CERTIFICATE: 2343 if (!hctx->conf.ssl_log_noise) return -1; 2344 __attribute_fallthrough__ 2345 default: 2346 str = gnutls_alert_get_name(alert); 2347 elogf(hctx->r->conf.errh, __FILE__, __LINE__, rc, 2348 "%s(): alert %s", __func__, str ? str : "(unknown)"); 2349 return -1; 2350 } 2351 } 2352 case GNUTLS_E_UNEXPECTED_HANDSHAKE_PACKET: 2353 case GNUTLS_E_UNKNOWN_CIPHER_SUITE: /* GNUTLS_A_HANDSHAKE_FAILURE */ 2354 case GNUTLS_E_PREMATURE_TERMINATION: 2355 if (!hctx->conf.ssl_log_noise) return -1; 2356 __attribute_fallthrough__ 2357 case GNUTLS_E_GOT_APPLICATION_DATA: /*(not expected with current use)*/ 2358 /*if (hctx->handshake) return -1;*//*(accept only during handshake)*/ 2359 default: 2360 elog(hctx->r->conf.errh, __FILE__, __LINE__, rc, __func__); 2361 return -1; 2362 } 2363 } 2364 2365 2366 static int 2367 mod_gnutls_close_notify(handler_ctx *hctx); 2368 2369 2370 static int 2371 connection_write_cq_ssl (connection * const con, chunkqueue * const cq, off_t max_bytes) 2372 { 2373 handler_ctx * const hctx = con->plugin_ctx[plugin_data_singleton->id]; 2374 gnutls_session_t const ssl = hctx->ssl; 2375 if (!hctx->handshake) return 0; 2376 2377 if (hctx->pending_write) { 2378 int wr = gnutls_record_send(ssl, NULL, 0); 2379 if (wr <= 0) 2380 return mod_gnutls_write_err(con, hctx, wr, hctx->pending_write); 2381 max_bytes -= wr; 2382 hctx->pending_write = 0; 2383 chunkqueue_mark_written(cq, wr); 2384 } 2385 2386 if (__builtin_expect( (0 != hctx->close_notify), 0)) 2387 return mod_gnutls_close_notify(hctx); 2388 2389 const size_t lim = gnutls_record_get_max_size(ssl); 2390 2391 /* future: for efficiency/performance might consider using GnuTLS corking 2392 * gnutls_record_cork() 2393 * gnutls_record_uncork() 2394 * gnutls_record_check_corked() 2395 * though chunkqueue_peek_data() already will read a mix of MEM_CHUNK and 2396 * FILE_CHUNK into the buffer before sending, e.g. to send header response 2397 * headers and beginning of files, but does so for LOCAL_SEND_BUFSIZE (16k) 2398 * More might be possible to send before uncorking. 2399 */ 2400 2401 log_error_st * const errh = hctx->errh; 2402 while (max_bytes > 0 && !chunkqueue_is_empty(cq)) { 2403 char *data = local_send_buffer; 2404 uint32_t data_len = LOCAL_SEND_BUFSIZE < max_bytes 2405 ? LOCAL_SEND_BUFSIZE 2406 : (uint32_t)max_bytes; 2407 int wr; 2408 2409 if (0 != chunkqueue_peek_data(cq, &data, &data_len, errh)) return -1; 2410 if (__builtin_expect( (0 == data_len), 0)) { 2411 chunkqueue_remove_finished_chunks(cq); 2412 continue; 2413 } 2414 2415 /* gnutls_record_send() copies the data, up to max record size, but if 2416 * (temporarily) unable to write the entire record, it is documented 2417 * that the caller must call gnutls_record_send() again, later, with the 2418 * same arguments, or with NULL ptr and 0 data_len. The func may return 2419 * GNUTLS_E_AGAIN or GNUTLS_E_INTERRUPTED to indicate that caller should 2420 * wait for fd to be readable/writable before calling the func again, 2421 * which is why those (temporary) errors are returned instead of telling 2422 * the caller that the data was successfully copied. 2423 * Additionally, to be accurate, the size must fit into a record which 2424 * is why we restrict ourselves to sending max out record payload each 2425 * iteration. 2426 * XXX: above comments modified from mod_mbedtls; should be verified 2427 */ 2428 2429 int wr_total = 0; 2430 do { 2431 size_t wr_len = (data_len > lim) ? lim : data_len; 2432 wr = gnutls_record_send(ssl, data, wr_len); 2433 if (wr <= 0) { 2434 if (wr_total) chunkqueue_mark_written(cq, wr_total); 2435 return mod_gnutls_write_err(con, hctx, wr, wr_len); 2436 } 2437 wr_total += wr; 2438 data += wr; 2439 } while ((data_len -= wr)); 2440 chunkqueue_mark_written(cq, wr_total); 2441 max_bytes -= wr_total; 2442 } 2443 2444 return 0; 2445 } 2446 2447 2448 #if GNUTLS_VERSION_NUMBER >= 0x030704 2449 static int 2450 connection_write_cq_ssl_ktls (connection * const con, chunkqueue * const cq, off_t max_bytes) 2451 { 2452 /* gnutls_record_send_file() interface has non-intuitive behavior if 2453 * gnutls_transport_is_ktls_enabled() *is not* enabled for GNUTLS_KTLS_SEND 2454 * (If not enabled, offset is *relative* to current underlying file pointer, 2455 * which is different from sendfile()) 2456 * Therefore, callers should ensure GNUTLS_KTLS_SEND is enabled before 2457 * configuring: con->network_write = connection_write_cq_ssl_ktls */ 2458 2459 handler_ctx * const hctx = con->plugin_ctx[plugin_data_singleton->id]; 2460 if (!hctx->handshake) return 0; 2461 2462 if (hctx->pending_write) { 2463 int wr = gnutls_record_send(hctx->ssl, NULL, 0); 2464 if (wr <= 0) 2465 return mod_gnutls_write_err(con, hctx, wr, hctx->pending_write); 2466 max_bytes -= wr; 2467 hctx->pending_write = 0; 2468 chunkqueue_mark_written(cq, wr); 2469 } 2470 2471 if (__builtin_expect( (0 != hctx->close_notify), 0)) 2472 return mod_gnutls_close_notify(hctx); 2473 2474 /* not done: scan cq for FILE_CHUNK within first max_bytes rather than 2475 * only using gnutls_record_send_file() if the first chunk is FILE_CHUNK. 2476 * Checking first chunk for FILE_CHUNK means that initial response headers 2477 * and beginning of file will be read into memory before subsequent writes 2478 * use gnutls_record_send_file(). TBD: possible to be further optimized? */ 2479 2480 for (chunk *c; (c = cq->first) && c->type == FILE_CHUNK; ) { 2481 off_t len = c->file.length - c->offset; 2482 if (len > max_bytes) len = max_bytes; 2483 if (0 == len) break; /*(FILE_CHUNK or max_bytes should not be 0)*/ 2484 if (-1 == c->file.fd && 0 != chunkqueue_open_file_chunk(cq, hctx->errh)) 2485 return -1; 2486 2487 ssize_t wr = 2488 gnutls_record_send_file(hctx->ssl, c->file.fd, &c->offset, (size_t)len); 2489 if (wr < 0) 2490 return mod_gnutls_write_err(con, hctx, (int)wr, 0); 2491 /* undo gnutls_record_send_file before chunkqueue_mark_written redo */ 2492 c->offset -= wr; 2493 2494 chunkqueue_mark_written(cq, wr); 2495 max_bytes -= wr; 2496 2497 if (wr < len) return 0; /* try again later */ 2498 } 2499 2500 return connection_write_cq_ssl(con, cq, max_bytes); 2501 } 2502 #endif 2503 2504 2505 static int 2506 mod_gnutls_ssl_handshake (handler_ctx *hctx) 2507 { 2508 int rc = gnutls_handshake(hctx->ssl); 2509 if (rc < 0) 2510 return mod_gnutls_read_err(hctx->con, hctx, rc); 2511 2512 /*(rc == GNUTLS_E_SUCCESS)*/ 2513 2514 hctx->handshake = 1; 2515 #if GNUTLS_VERSION_NUMBER >= 0x030704 2516 gnutls_transport_ktls_enable_flags_t kflags = 2517 gnutls_transport_is_ktls_enabled(hctx->ssl); 2518 if (kflags == GNUTLS_KTLS_SEND || kflags == GNUTLS_KTLS_DUPLEX) 2519 hctx->con->network_write = connection_write_cq_ssl_ktls; 2520 #endif 2521 #if GNUTLS_VERSION_NUMBER >= 0x030200 2522 if (hctx->alpn == MOD_GNUTLS_ALPN_H2) { 2523 if (0 != mod_gnutls_alpn_h2_policy(hctx)) 2524 return -1; 2525 #if GNUTLS_VERSION_NUMBER >= 0x030704 2526 /*(not expecting FILE_CHUNKs in write_queue with h2, 2527 * so skip ktls and gnutls_record_send_file; reset to default)*/ 2528 hctx->con->network_write = connection_write_cq_ssl; 2529 #endif 2530 } 2531 else if (hctx->alpn == MOD_GNUTLS_ALPN_ACME_TLS_1) { 2532 /* Once TLS handshake is complete, return -1 to result in 2533 * CON_STATE_ERROR so that socket connection is quickly closed */ 2534 return -1; 2535 } 2536 hctx->alpn = 0; 2537 #endif 2538 return 1; /* continue reading */ 2539 } 2540 2541 2542 static int 2543 connection_read_cq_ssl (connection * const con, chunkqueue * const cq, off_t max_bytes) 2544 { 2545 handler_ctx * const hctx = con->plugin_ctx[plugin_data_singleton->id]; 2546 2547 UNUSED(max_bytes); 2548 2549 if (__builtin_expect( (0 != hctx->close_notify), 0)) 2550 return mod_gnutls_close_notify(hctx); 2551 2552 if (!hctx->handshake) { 2553 int rc = mod_gnutls_ssl_handshake(hctx); 2554 if (1 != rc) return rc; /* !hctx->handshake; not done, or error */ 2555 } 2556 2557 gnutls_session_t ssl = hctx->ssl; 2558 ssize_t len; 2559 char *mem = NULL; 2560 size_t mem_len = 0; 2561 size_t pend = gnutls_record_check_pending(ssl); 2562 do { 2563 mem_len = pend < 2048 ? 2048 : pend; 2564 chunk * const ckpt = cq->last; 2565 mem = chunkqueue_get_memory(cq, &mem_len); 2566 2567 len = gnutls_record_recv(ssl, mem, mem_len); 2568 chunkqueue_use_memory(cq, ckpt, len > 0 ? len : 0); 2569 } while (len > 0 && (pend = gnutls_record_check_pending(ssl))); 2570 2571 if (len < 0) { 2572 return mod_gnutls_read_err(con, hctx, (int)len); 2573 } else if (len == 0) { 2574 con->is_readable = 0; 2575 /* the other end closed the connection -> KEEP-ALIVE */ 2576 2577 return -2; 2578 } else { 2579 return 0; 2580 } 2581 } 2582 2583 2584 static void 2585 mod_gnutls_debug_cb(int level, const char *str) 2586 { 2587 UNUSED(level); 2588 log_error_st *errh = plugin_data_singleton->srv->errh; 2589 log_error(errh, __FILE__, __LINE__, "GnuTLS: %s", str); 2590 } 2591 2592 2593 CONNECTION_FUNC(mod_gnutls_handle_con_accept) 2594 { 2595 const server_socket *srv_sock = con->srv_socket; 2596 if (!srv_sock->is_ssl) return HANDLER_GO_ON; 2597 2598 plugin_data *p = p_d; 2599 handler_ctx * const hctx = handler_ctx_init(); 2600 request_st * const r = &con->request; 2601 hctx->r = r; 2602 hctx->con = con; 2603 hctx->tmp_buf = con->srv->tmp_buf; 2604 hctx->errh = r->conf.errh; 2605 con->plugin_ctx[p->id] = hctx; 2606 buffer_blank(&r->uri.authority); 2607 2608 plugin_ssl_ctx * const s = p->ssl_ctxs + srv_sock->sidx; 2609 hctx->ssl_session_ticket = s->ssl_session_ticket; 2610 int flags = GNUTLS_SERVER | GNUTLS_NO_SIGNAL | GNUTLS_NONBLOCK; 2611 /* ??? add feature: GNUTLS_ENABLE_EARLY_START ??? */ 2612 int rc = gnutls_init(&hctx->ssl, flags); 2613 if (rc < 0) { 2614 elog(r->conf.errh, __FILE__, __LINE__, rc, "gnutls_init()"); 2615 return HANDLER_ERROR; 2616 } 2617 2618 rc = gnutls_priority_set(hctx->ssl, s->priority_cache); 2619 if (rc < 0) { 2620 elog(r->conf.errh, __FILE__, __LINE__, rc, "gnutls_priority_set()"); 2621 return HANDLER_ERROR; 2622 } 2623 2624 /* generic func replaces gnutls_handshake_set_post_client_hello_function()*/ 2625 gnutls_handshake_set_hook_function(hctx->ssl, GNUTLS_HANDSHAKE_CLIENT_HELLO, 2626 GNUTLS_HOOK_PRE, 2627 mod_gnutls_client_hello_hook); 2628 2629 gnutls_session_set_ptr(hctx->ssl, hctx); 2630 gnutls_transport_set_int(hctx->ssl, con->fd); 2631 2632 con->network_read = connection_read_cq_ssl; 2633 con->network_write = connection_write_cq_ssl; 2634 con->proto_default_port = 443; /* "https" */ 2635 mod_gnutls_patch_config(r, &hctx->conf); 2636 2637 #if GNUTLS_VERSION_NUMBER < 0x030600 2638 hctx->conf.dh_params = s->dh_params; 2639 #endif 2640 2641 /* debug logging is global. Once enabled, debug hook will remain so, though 2642 * different connection might overwrite level, if configured differently. 2643 * If GNUTLS_DEBUG_LEVEL is set in environment (and ssl_log_noise not set), 2644 * then debugging will go to stderr */ 2645 if (hctx->conf.ssl_log_noise) {/* volume level for debug message callback */ 2646 gnutls_global_set_log_function(mod_gnutls_debug_cb); 2647 gnutls_global_set_log_level(hctx->conf.ssl_log_noise); 2648 } 2649 2650 /* GnuTLS limitation: must set session ticket encryption key before GnuTLS 2651 * client hello hook runs if TLSv1.3 (? key already set by then ?) */ 2652 if (hctx->ssl_session_ticket && session_ticket_key.size) { 2653 rc = gnutls_session_ticket_enable_server(hctx->ssl,&session_ticket_key); 2654 if (rc < 0) { 2655 elog(r->conf.errh, __FILE__, __LINE__, rc, 2656 "gnutls_session_ticket_enable_server()"); 2657 return HANDLER_ERROR; 2658 } 2659 } 2660 2661 return HANDLER_GO_ON; 2662 } 2663 2664 2665 static void 2666 mod_gnutls_detach(handler_ctx *hctx) 2667 { 2668 /* step aside from further SSL processing 2669 * (used after handle_connection_shut_wr hook) */ 2670 /* future: might restore prior network_read and network_write fn ptrs */ 2671 hctx->con->is_ssl_sock = 0; 2672 /* if called after handle_connection_shut_wr hook, shutdown SHUT_WR */ 2673 if (-1 == hctx->close_notify) shutdown(hctx->con->fd, SHUT_WR); 2674 hctx->close_notify = 1; 2675 } 2676 2677 2678 CONNECTION_FUNC(mod_gnutls_handle_con_shut_wr) 2679 { 2680 plugin_data *p = p_d; 2681 handler_ctx *hctx = con->plugin_ctx[p->id]; 2682 if (NULL == hctx) return HANDLER_GO_ON; 2683 2684 hctx->close_notify = -2; 2685 if (hctx->handshake) { 2686 mod_gnutls_close_notify(hctx); 2687 } 2688 else { 2689 mod_gnutls_detach(hctx); 2690 } 2691 2692 return HANDLER_GO_ON; 2693 } 2694 2695 2696 static int 2697 mod_gnutls_close_notify (handler_ctx *hctx) 2698 { 2699 if (1 == hctx->close_notify) return -2; 2700 2701 int rc = gnutls_bye(hctx->ssl, GNUTLS_SHUT_WR); 2702 switch (rc) { 2703 case GNUTLS_E_SUCCESS: 2704 mod_gnutls_detach(hctx); 2705 return -2; 2706 case GNUTLS_E_AGAIN: 2707 case GNUTLS_E_INTERRUPTED: 2708 return 0; 2709 default: 2710 elog(hctx->r->conf.errh, __FILE__, __LINE__, rc, 2711 "mod_gnutls_close_notify()"); 2712 __attribute_fallthrough__ 2713 case GNUTLS_E_PUSH_ERROR: /*(noisy; probably connection reset)*/ 2714 mod_gnutls_detach(hctx); 2715 return -1; 2716 } 2717 } 2718 2719 2720 CONNECTION_FUNC(mod_gnutls_handle_con_close) 2721 { 2722 plugin_data *p = p_d; 2723 handler_ctx *hctx = con->plugin_ctx[p->id]; 2724 if (NULL != hctx) { 2725 con->plugin_ctx[p->id] = NULL; 2726 if (1 != hctx->close_notify) 2727 mod_gnutls_close_notify(hctx); /*(one final try)*/ 2728 handler_ctx_free(hctx); 2729 } 2730 2731 return HANDLER_GO_ON; 2732 } 2733 2734 2735 __attribute_noinline__ 2736 static void 2737 https_add_ssl_client_cert (request_st * const r, const gnutls_x509_crt_t peer) 2738 { 2739 gnutls_datum_t d; 2740 if (gnutls_x509_crt_export2(peer, GNUTLS_X509_FMT_PEM, &d) >= 0) 2741 http_header_env_set(r, 2742 CONST_STR_LEN("SSL_CLIENT_CERT"), 2743 (char *)d.data, d.size); 2744 if (d.data) gnutls_free(d.data); 2745 } 2746 2747 2748 /* modified from gnutls tests/dn.c:print_dn() */ 2749 static void 2750 https_add_ssl_client_subject (request_st * const r, gnutls_x509_dn_t dn) 2751 { 2752 int irdn = 0, i, rc; 2753 gnutls_x509_ava_st ava; 2754 const size_t prelen = sizeof("SSL_CLIENT_S_DN_")-1; 2755 char key[64] = "SSL_CLIENT_S_DN_"; 2756 char buf[512]; /*(expecting element value len <= 256)*/ 2757 2758 /* add components of client Subject DN */ 2759 2760 /* man gnutls_x509_dn_get_rdn_ava() 2761 * The X.509 distinguished name is a sequence of sequences of strings and 2762 * this is what the irdn and iava indexes model. 2763 * This is a low-level function that requires the caller to do the value 2764 * conversions when necessary (e.g. from UCS-2). 2765 * XXX: value conversions not done below; unprintable chars replaced w/ '?' 2766 */ 2767 2768 do { 2769 for (i=0; (rc = gnutls_x509_dn_get_rdn_ava(dn,irdn,i,&ava)) == 0; ++i) { 2770 const char *name = 2771 gnutls_x509_dn_oid_name((char *)ava.oid.data, 2772 GNUTLS_X509_DN_OID_RETURN_OID); 2773 const size_t len = strlen(name); 2774 if (prelen+len >= sizeof(key)) continue; 2775 memcpy(key+prelen, name, len); /*(not '\0'-terminated)*/ 2776 2777 unsigned int n, vlen = ava.value.size; 2778 if (vlen > sizeof(buf)-1) 2779 vlen = sizeof(buf)-1; 2780 for (n = 0; n < vlen; ++n) { 2781 unsigned char c = ava.value.data[n]; 2782 buf[n] = (c >= 32 && c != 127) ? c : '?'; 2783 } 2784 2785 http_header_env_set(r, key, prelen+len, buf, n); 2786 } 2787 ++irdn; 2788 } while (rc == GNUTLS_E_ASN1_ELEMENT_NOT_FOUND && i > 0); 2789 2790 if (rc != GNUTLS_E_ASN1_ELEMENT_NOT_FOUND) 2791 elog(r->conf.errh, __FILE__, __LINE__, rc, 2792 "gnutls_x509_dn_get_rdn_ava()"); 2793 } 2794 2795 2796 __attribute_cold__ 2797 static void 2798 https_add_ssl_client_verify_err (buffer * const b, unsigned int status) 2799 { 2800 #if GNUTLS_VERSION_NUMBER >= 0x030104 2801 /* get failure string and translate newline to ':', removing last one */ 2802 /* (preserving behavior from mod_openssl) */ 2803 gnutls_datum_t msg = { NULL, 0 }; 2804 if (gnutls_certificate_verification_status_print(status, GNUTLS_CRT_X509, 2805 &msg, 0) >= 0) { 2806 size_t sz = msg.size-1; /* '\0'-terminated string */ 2807 for (char *nl=(char *)msg.data; NULL != (nl=strchr(nl, '\n')); ++nl) 2808 nl[0] = ('\0' == nl[1] ? (--sz, '\0') : ':'); 2809 buffer_append_string_len(b, (char *)msg.data, sz); 2810 } 2811 if (msg.data) gnutls_free(msg.data); 2812 #else 2813 UNUSED(b); 2814 UNUSED(status); 2815 #endif 2816 } 2817 2818 2819 __attribute_noinline__ 2820 static void 2821 https_add_ssl_client_entries (request_st * const r, handler_ctx * const hctx) 2822 { 2823 gnutls_session_t ssl = hctx->ssl; 2824 unsigned int crt_size = 0; 2825 const gnutls_datum_t *crts = NULL; 2826 buffer *vb = http_header_env_set_ptr(r, CONST_STR_LEN("SSL_CLIENT_VERIFY")); 2827 2828 if (hctx->verify_status != ~0u) 2829 crts = gnutls_certificate_get_peers(ssl, &crt_size); 2830 if (0 == crt_size) { /* || hctx->verify_status == ~0u) */ 2831 /*(e.g. no cert, or verify result not available)*/ 2832 buffer_copy_string_len(vb, CONST_STR_LEN("NONE")); 2833 return; 2834 } 2835 else if (0 != hctx->verify_status) { 2836 buffer_copy_string_len(vb, CONST_STR_LEN("FAILED:")); 2837 https_add_ssl_client_verify_err(vb, hctx->verify_status); 2838 return; 2839 } 2840 else { 2841 buffer_copy_string_len(vb, CONST_STR_LEN("SUCCESS")); 2842 } 2843 2844 gnutls_x509_crt_t crt; 2845 if (gnutls_x509_crt_init(&crt) < 0) 2846 return; 2847 if (crts && gnutls_x509_crt_import(crt, &crts[0], GNUTLS_X509_FMT_DER) < 0){ 2848 gnutls_x509_crt_deinit(crt); 2849 return; 2850 } 2851 2852 int rc; 2853 gnutls_datum_t d = { NULL, 0 }; 2854 char buf[512]; 2855 /*rc = gnutls_x509_crt_print(cert, GNUTLS_CRT_PRINT_ONELINE, &d);*//* ??? */ 2856 #if GNUTLS_VERSION_NUMBER < 0x030507 2857 d.data = buf; 2858 d.size = sizeof(buf); 2859 rc = gnutls_x509_crt_get_dn(crt, buf, &d.size); 2860 #else 2861 rc = gnutls_x509_crt_get_dn3(crt, &d, 0); 2862 #endif 2863 if (rc >= 0) 2864 http_header_env_set(r, 2865 CONST_STR_LEN("SSL_CLIENT_S_DN"), 2866 (char *)d.data, d.size); 2867 if (d.data && d.data != (void *)buf) gnutls_free(d.data); 2868 2869 gnutls_x509_dn_t dn; 2870 rc = gnutls_x509_crt_get_subject(crt, &dn); 2871 if (rc >= 0) 2872 https_add_ssl_client_subject(r, dn); 2873 2874 size_t sz = sizeof(buf); 2875 if (gnutls_x509_crt_get_serial(crt, buf, &sz) >= 0) 2876 buffer_append_string_encoded_hex_uc( 2877 http_header_env_set_ptr(r, CONST_STR_LEN("SSL_CLIENT_M_SERIAL")), 2878 buf, sz); 2879 2880 if (hctx->conf.ssl_verifyclient_username) { 2881 /* pick one of the exported values as "REMOTE_USER", for example 2882 * ssl.verifyclient.username = "SSL_CLIENT_S_DN_UID" 2883 * or 2884 * ssl.verifyclient.username = "SSL_CLIENT_S_DN_emailAddress" 2885 */ 2886 const buffer *varname = hctx->conf.ssl_verifyclient_username; 2887 vb = http_header_env_get(r, BUF_PTR_LEN(varname)); 2888 if (vb) { /* same as mod_auth_api.c:http_auth_setenv() */ 2889 http_header_env_set(r, 2890 CONST_STR_LEN("REMOTE_USER"), 2891 BUF_PTR_LEN(vb)); 2892 http_header_env_set(r, 2893 CONST_STR_LEN("AUTH_TYPE"), 2894 CONST_STR_LEN("SSL_CLIENT_VERIFY")); 2895 } 2896 } 2897 2898 /* if (NULL != crt) (e.g. not PSK-based ciphersuite) */ 2899 if (hctx->conf.ssl_verifyclient_export_cert && NULL != crt) 2900 https_add_ssl_client_cert(r, crt); 2901 2902 gnutls_x509_crt_deinit(crt); 2903 } 2904 2905 2906 static void 2907 http_cgi_ssl_env (request_st * const r, handler_ctx * const hctx) 2908 { 2909 gnutls_session_t ssl = hctx->ssl; 2910 gnutls_protocol_t version = gnutls_protocol_get_version(ssl); 2911 gnutls_cipher_algorithm_t cipher = gnutls_cipher_get(ssl); 2912 gnutls_kx_algorithm_t kx = gnutls_kx_get(ssl); 2913 gnutls_mac_algorithm_t mac = gnutls_mac_get(ssl); 2914 const char *s; 2915 2916 s = gnutls_protocol_get_name(version); 2917 if (s) http_header_env_set(r, CONST_STR_LEN("SSL_PROTOCOL"), s, strlen(s)); 2918 2919 s = gnutls_cipher_suite_get_name(kx, cipher, mac); 2920 if (s) http_header_env_set(r, CONST_STR_LEN("SSL_CIPHER"), s, strlen(s)); 2921 2922 /* SSL_CIPHER_ALGKEYSIZE - Number of cipher bits (possible) */ 2923 /* SSL_CIPHER_USEKEYSIZE - Number of cipher bits (actually used) */ 2924 /* (always the same in extra/gnutls_openssl.c:SSL_CIPHER_get_bits()) 2925 * (The values are the same except for very old, weak ciphers, i.e. if you 2926 * care about this, then you instead ought to be using stronger ciphers)*/ 2927 /* ??? gnutls_x509_crt_get_pk_algorithm(crt, &usekeysize); ??? */ 2928 size_t algkeysize = 8 * gnutls_cipher_get_key_size(cipher); 2929 size_t usekeysize = algkeysize; 2930 char buf[LI_ITOSTRING_LENGTH]; 2931 http_header_env_set(r, CONST_STR_LEN("SSL_CIPHER_USEKEYSIZE"), 2932 buf, li_utostrn(buf, sizeof(buf), usekeysize)); 2933 http_header_env_set(r, CONST_STR_LEN("SSL_CIPHER_ALGKEYSIZE"), 2934 buf, li_utostrn(buf, sizeof(buf), algkeysize)); 2935 } 2936 2937 2938 REQUEST_FUNC(mod_gnutls_handle_request_env) 2939 { 2940 plugin_data *p = p_d; 2941 /* simple flag for request_env_patched */ 2942 if (r->plugin_ctx[p->id]) return HANDLER_GO_ON; 2943 handler_ctx *hctx = r->con->plugin_ctx[p->id]; 2944 if (NULL == hctx) return HANDLER_GO_ON; 2945 r->plugin_ctx[p->id] = (void *)(uintptr_t)1u; 2946 2947 http_cgi_ssl_env(r, hctx); 2948 if (hctx->conf.ssl_verifyclient) { 2949 https_add_ssl_client_entries(r, hctx); 2950 } 2951 2952 return HANDLER_GO_ON; 2953 } 2954 2955 2956 REQUEST_FUNC(mod_gnutls_handle_uri_raw) 2957 { 2958 /* mod_gnutls must be loaded prior to mod_auth 2959 * if mod_gnutls is configured to set REMOTE_USER based on client cert */ 2960 /* mod_gnutls must be loaded after mod_extforward 2961 * if mod_gnutls config is based on lighttpd.conf remote IP conditional 2962 * using remote IP address set by mod_extforward, *unless* PROXY protocol 2963 * is enabled with extforward.hap-PROXY = "enable", in which case the 2964 * reverse is true: mod_extforward must be loaded after mod_gnutls */ 2965 plugin_data *p = p_d; 2966 handler_ctx *hctx = r->con->plugin_ctx[p->id]; 2967 if (NULL == hctx) return HANDLER_GO_ON; 2968 2969 mod_gnutls_patch_config(r, &hctx->conf); 2970 if (hctx->conf.ssl_verifyclient) { 2971 mod_gnutls_handle_request_env(r, p); 2972 } 2973 2974 return HANDLER_GO_ON; 2975 } 2976 2977 2978 REQUEST_FUNC(mod_gnutls_handle_request_reset) 2979 { 2980 plugin_data *p = p_d; 2981 r->plugin_ctx[p->id] = NULL; /* simple flag for request_env_patched */ 2982 return HANDLER_GO_ON; 2983 } 2984 2985 2986 TRIGGER_FUNC(mod_gnutls_handle_trigger) { 2987 const plugin_data * const p = p_d; 2988 const unix_time64_t cur_ts = log_epoch_secs; 2989 if (cur_ts & 0x3f) return HANDLER_GO_ON; /*(continue once each 64 sec)*/ 2990 2991 mod_gnutls_session_ticket_key_check(srv, p, cur_ts); 2992 mod_gnutls_refresh_stapling_files(srv, p, cur_ts); 2993 2994 return HANDLER_GO_ON; 2995 } 2996 2997 2998 __attribute_cold__ 2999 int mod_gnutls_plugin_init (plugin *p); 3000 int mod_gnutls_plugin_init (plugin *p) 3001 { 3002 p->version = LIGHTTPD_VERSION_ID; 3003 p->name = "gnutls"; 3004 p->init = mod_gnutls_init; 3005 p->cleanup = mod_gnutls_free; 3006 p->priv_defaults= mod_gnutls_set_defaults; 3007 3008 p->handle_connection_accept = mod_gnutls_handle_con_accept; 3009 p->handle_connection_shut_wr = mod_gnutls_handle_con_shut_wr; 3010 p->handle_connection_close = mod_gnutls_handle_con_close; 3011 p->handle_uri_raw = mod_gnutls_handle_uri_raw; 3012 p->handle_request_env = mod_gnutls_handle_request_env; 3013 p->handle_request_reset = mod_gnutls_handle_request_reset; 3014 p->handle_trigger = mod_gnutls_handle_trigger; 3015 3016 return 0; 3017 } 3018 3019 3020 /* cipher suites 3021 * 3022 * (extremely coarse (and very possibly incorrect) mapping to openssl labels) 3023 */ 3024 3025 /* TLSv1.3 cipher list (supported in gnutls) */ 3026 static const char suite_TLSv13[] = 3027 "+CHACHA20-POLY1305:" 3028 "+AES-256-GCM:" 3029 "+AES-256-CCM:" 3030 "+AES-256-CCM-8:" 3031 "+AES-128-GCM:" 3032 "+AES-128-CCM:" 3033 "+AES-128-CCM-8:" 3034 ; 3035 3036 /* TLSv1.2 cipher list (supported in gnutls) */ 3037 static const char suite_TLSv12[] = 3038 "+CHACHA20-POLY1305:" 3039 "+AES-256-GCM:" 3040 "+AES-256-CCM:" 3041 "+AES-256-CBC:" 3042 "+AES-256-CCM-8:" 3043 "+CAMELLIA-256-GCM:" 3044 "+CAMELLIA-256-CBC:" 3045 "+AES-128-GCM:" 3046 "+AES-128-CCM:" 3047 "+AES-128-CBC:" 3048 "+AES-128-CCM-8:" 3049 "+CAMELLIA-128-GCM:" 3050 "+CAMELLIA-128-CBC:" 3051 ; 3052 3053 /* TLSv1.0 cipher list (supported in gnutls) */ 3054 /* XXX: intentionally not including overlapping eNULL ciphers */ 3055 static const char suite_TLSv10[] = 3056 "+AES-256-CBC:" 3057 "+AES-128-CBC:" 3058 "+CAMELLIA-256-CBC:" 3059 "+CAMELLIA-128-CBC:" 3060 ; 3061 3062 /* HIGH cipher list (mapped from openssl list to gnutls) */ 3063 static const char suite_HIGH[] = 3064 "+CHACHA20-POLY1305:" 3065 "+AES-256-GCM:" 3066 "+AES-256-CCM:" 3067 "+AES-256-CBC:" 3068 "+AES-256-CCM-8:" 3069 "+CAMELLIA-256-CBC:" 3070 "+AES-128-GCM:" 3071 "+AES-128-CCM:" 3072 "+AES-128-CBC:" 3073 "+AES-128-CCM-8:" 3074 "+CAMELLIA-128-CBC:" 3075 ; 3076 3077 3078 static int 3079 mod_gnutls_ssl_conf_ciphersuites (server *srv, plugin_config_socket *s, buffer *ciphersuites, const buffer *cipherstring) 3080 { 3081 /* reference: https://www.openssl.org/docs/man1.1.1/man1/ciphers.html 3082 * Attempt to parse *some* keywords from Ciphersuites and CipherString 3083 * !!! openssl uses a *different* naming scheme than does GnuTLS !!! 3084 * Ciphersuites in openssl takes only TLSv1.3 suites. 3085 * Note that CipherString does allow cipher suites to be listed, 3086 * and this code does not currently attempt to provide mapping */ 3087 3088 buffer * const plist = &s->priority_str; 3089 char n[128]; /*(most ciphersuite names are about 40 chars)*/ 3090 3091 if (ciphersuites) { 3092 buffer *b = ciphersuites; 3093 buffer_to_upper(b); /*(ciphersuites are all uppercase (currently))*/ 3094 for (const char *e = b->ptr-1; e; ) { 3095 const char * const p = e+1; 3096 e = strchr(p, ':'); 3097 size_t len = e ? (size_t)(e - p) : strlen(p); 3098 3099 if (buffer_eq_icase_ss(p, len, 3100 CONST_STR_LEN("TLS_CHACHA20_POLY1305_SHA256"))) 3101 buffer_append_string_len(plist, 3102 CONST_STR_LEN("+CHACHA20-POLY1305:")); 3103 else if (buffer_eq_icase_ss(p, len, 3104 CONST_STR_LEN("TLS_AES_256_GCM_SHA384"))) 3105 buffer_append_string_len(plist, 3106 CONST_STR_LEN("+AES-256-GCM:")); 3107 else if (buffer_eq_icase_ss(p, len, 3108 CONST_STR_LEN("TLS_AES_128_GCM_SHA256"))) 3109 buffer_append_string_len(plist, 3110 CONST_STR_LEN("+AES-128-GCM:")); 3111 else if (buffer_eq_icase_ss(p, len, 3112 CONST_STR_LEN("TLS_AES_128_CCM_SHA256"))) 3113 buffer_append_string_len(plist, 3114 CONST_STR_LEN("+AES-128-CCM:")); 3115 else if (buffer_eq_icase_ss(p, len, 3116 CONST_STR_LEN("TLS_AES_128_CCM_8_SHA256"))) 3117 buffer_append_string_len(plist, 3118 CONST_STR_LEN("+AES-128-CCM-8:")); 3119 else 3120 log_error(srv->errh, __FILE__, __LINE__, 3121 "GnuTLS: skipped ciphersuite; not recognized: %.*s", 3122 (int)len, p); 3123 } 3124 } 3125 3126 /* XXX: openssl config for CipherString=... is excessively complex. 3127 * If there is a need to enable specific ciphersuites, then that 3128 * can be accomplished with mod_gnutls by specifying the list in 3129 * Ciphersuites=... in the ssl.openssl.ssl-conf-cmd directive. 3130 * 3131 * The tokens parsed here are a quick attempt to handle a few cases 3132 * 3133 * XXX: not done: could make a list of ciphers with bitflag of attributes 3134 * to make future combining easier */ 3135 if (cipherstring && !buffer_is_blank(cipherstring)) { 3136 const buffer *b = cipherstring; 3137 const char *e = b->ptr; 3138 3139 /* XXX: not done: no checking for duplication of ciphersuites 3140 * even if tokens overlap or are repeated */ 3141 3142 /* XXX: not done: might walk string and build up exclude list of !xxxxx 3143 * ciphersuites and walk string again, excluding as result list built */ 3144 3145 /* manually handle first token, since one-offs apply */ 3146 /* (openssl syntax NOT fully supported) */ 3147 #define strncmp_const(s,cs) strncmp((s),(cs),sizeof(cs)-1) 3148 if (0 == strncmp_const(e, "!ALL") || 0 == strncmp_const(e, "-ALL")) { 3149 /* "!ALL" excluding all ciphers is empty list */ 3150 e += sizeof("!ALL")-1; /* same as sizeof("-ALL")-1 */ 3151 buffer_append_string_len(plist, CONST_STR_LEN("-CIPHER-ALL:")); 3152 } 3153 else if (0 == strncmp_const(e, "!DEFAULT") 3154 || 0 == strncmp_const(e, "-DEFAULT")) { 3155 /* "!DEFAULT" excluding default ciphers is empty list */ 3156 e += sizeof("!DEFAULT")-1; /* same as sizeof("-DEFAULT")-1 */ 3157 buffer_append_string_len(plist, CONST_STR_LEN("-CIPHER-ALL:")); 3158 } 3159 else if (0 == strncmp_const(e, "DEFAULT")) { 3160 e += sizeof("DEFAULT")-1; 3161 s->priority_base = "NORMAL"; 3162 } 3163 else if (0 == /* effectively the same as "DEFAULT" */ 3164 strncmp_const(e, "ALL:!COMPLEMENTOFDEFAULT:!eNULL")) { 3165 e += sizeof("ALL:!COMPLEMENTOFDEFAULT:!eNULL")-1; 3166 s->priority_base = "NORMAL"; 3167 } 3168 else if (0 == strncmp_const(e, "SUITEB128") 3169 || 0 == strncmp_const(e, "SUITEB128ONLY") 3170 || 0 == strncmp_const(e, "SUITEB192")) { 3171 s->priority_base = (0 == strncmp_const(e, "SUITEB192")) 3172 ? "SUITEB192" 3173 : "SUITEB128"; 3174 e += (0 == strncmp_const(e, "SUITEB128ONLY")) 3175 ? sizeof("SUITEB128ONLY")-1 3176 : sizeof("SUITEB128")-1; 3177 if (*e) 3178 log_error(srv->errh, __FILE__, __LINE__, 3179 "GnuTLS: ignoring cipher string after SUITEB: %s", e); 3180 return 1; 3181 } 3182 else if (0 == strncmp_const(e, 3183 "ECDHE+AESGCM:ECDHE+AES256:CHACHA20:!SHA1:!SHA256:!SHA384") 3184 || 0 == strncmp_const(e, 3185 "EECDH+AESGCM:AES256+EECDH:CHACHA20:!SHA1:!SHA256:!SHA384")) { 3186 e += sizeof( 3187 "EECDH+AESGCM:AES256+EECDH:CHACHA20:!SHA1:!SHA256:!SHA384")-1; 3188 buffer_append_string_len(plist, 3189 CONST_STR_LEN("+AES-256-GCM:+AES-128-GCM:+AES-256-CCM:+AES-256-CCM-8:+CHACHA20-POLY1305:")); 3190 } 3191 3192 if (e != b->ptr && *e != ':' && *e != '\0') { 3193 log_error(srv->errh, __FILE__, __LINE__, 3194 "GnuTLS: error: missing support for cipher list: %s", b->ptr); 3195 return 0; 3196 } 3197 3198 /* not handled: "ALL" is "DEFAULT" and "RC4" */ 3199 /* not handled: "COMPLEMENTOFALL" is "eNULL" */ 3200 3201 int rc = 1; 3202 if (e == b->ptr || *e == '\0') --e; /*initial condition for loop below*/ 3203 do { 3204 const char * const p = e+1; 3205 e = strchr(p, ':'); 3206 size_t len = e ? (size_t)(e - p) : strlen(p); 3207 if (0 == len) continue; 3208 if (len >= sizeof(n)) { 3209 log_error(srv->errh, __FILE__, __LINE__, 3210 "GnuTLS: skipped ciphersuite; too long: %.*s", 3211 (int)len, p); 3212 continue; 3213 } 3214 char c = (*p == '!' || *p == '-' || *p == '+') ? *p : 0; 3215 size_t nlen = c ? len-1 : len; 3216 memcpy(n, c ? p+1 : p, nlen); 3217 n[nlen] = '\0'; 3218 3219 /* not handled: !xxxxx -xxxxx and most +xxxxx */ 3220 if (c) { 3221 log_error(srv->errh, __FILE__, __LINE__, 3222 "GnuTLS: error: missing support for cipher list: %s", b->ptr); 3223 } 3224 3225 /* ignore @STRENGTH sorting and ignore @SECLEVEL=n */ 3226 char *a = strchr(n, '@'); 3227 if (a) { 3228 log_error(srv->errh, __FILE__, __LINE__, 3229 "GnuTLS: ignored %s in %.*s", a, (int)len, p); 3230 *a = '\0'; 3231 nlen = (size_t)(a - n); 3232 } 3233 3234 if (buffer_eq_icase_ss(n, nlen, CONST_STR_LEN("TLSv1.3"))) { 3235 buffer_append_string_len(plist, 3236 CONST_STR_LEN(suite_TLSv13)); 3237 continue; 3238 } 3239 3240 if (buffer_eq_icase_ss(n, nlen, CONST_STR_LEN("TLSv1.2"))) { 3241 buffer_append_string_len(plist, 3242 CONST_STR_LEN(suite_TLSv12)); 3243 continue; 3244 } 3245 3246 if (buffer_eq_icase_ss(n, nlen, CONST_STR_LEN("TLSv1.0"))) { 3247 buffer_append_string_len(plist, 3248 CONST_STR_LEN(suite_TLSv10)); 3249 continue; 3250 } 3251 3252 /* handle a popular recommendations 3253 * ssl.cipher-list = "EECDH+AESGCM:EDH+AESGCM" 3254 * ssl.cipher-list = "AES256+EECDH:AES256+EDH" 3255 * which uses AES hardware acceleration built into popular CPUs */ 3256 if (buffer_eq_icase_ss(n, nlen, CONST_STR_LEN("ECDHE+AESGCM")) 3257 || buffer_eq_icase_ss(n, nlen, CONST_STR_LEN("EECDH+AESGCM"))) { 3258 buffer_append_string_len(plist, 3259 CONST_STR_LEN("+AES-256-GCM:+AES-128-GCM:")); 3260 continue; 3261 } 3262 if (buffer_eq_icase_ss(n, nlen, CONST_STR_LEN("DHE+AESGCM")) 3263 || buffer_eq_icase_ss(n, nlen, CONST_STR_LEN("EDH+AESGCM"))) { 3264 buffer_append_string_len(plist, 3265 CONST_STR_LEN("+AES-256-GCM:+AES-128-GCM:")); 3266 continue; 3267 } 3268 if (buffer_eq_icase_ss(n, nlen, CONST_STR_LEN("AES256+EECDH"))) { 3269 buffer_append_string_len(plist, 3270 CONST_STR_LEN("+AES-256-GCM:+AES-256-CCM:+AES-256-CBC:+AES-256-CCM-8:")); 3271 continue; 3272 } 3273 if (buffer_eq_icase_ss(n, nlen, CONST_STR_LEN("AES256+EDH"))) { 3274 buffer_append_string_len(plist, 3275 CONST_STR_LEN("+AES-256-GCM:+AES-256-CCM:+AES-256-CBC:+AES-256-CCM-8:")); 3276 continue; 3277 } 3278 3279 if (buffer_eq_icase_ss(n, nlen, CONST_STR_LEN("HIGH"))) { 3280 buffer_append_string_len(plist, 3281 CONST_STR_LEN(suite_HIGH)); 3282 continue; 3283 } 3284 3285 if (buffer_eq_icase_ss(n, nlen, CONST_STR_LEN("AES256")) 3286 || buffer_eq_icase_ss(n, nlen, CONST_STR_LEN("AES"))) { 3287 buffer_append_string_len(plist, 3288 CONST_STR_LEN("+AES-256-GCM:+AES-256-CCM:+AES-256-CBC:+AES-256-CCM-8:")); 3289 if (nlen == sizeof("AES256")-1) continue; 3290 } 3291 3292 if (buffer_eq_icase_ss(n, nlen, CONST_STR_LEN("AES128")) 3293 || buffer_eq_icase_ss(n, nlen, CONST_STR_LEN("AES"))) { 3294 buffer_append_string_len(plist, 3295 CONST_STR_LEN("+AES-128-GCM:+AES-128-CCM:+AES-128-CBC:+AES-128-CCM-8:")); 3296 continue; 3297 } 3298 3299 if (buffer_eq_icase_ss(n, nlen, CONST_STR_LEN("CAMELLIA256")) 3300 || buffer_eq_icase_ss(n, nlen, CONST_STR_LEN("CAMELLIA"))) { 3301 buffer_append_string_len(plist, 3302 CONST_STR_LEN("+CAMELLIA-256-GCM:+CAMELLIA-256-CBC:")); 3303 if (nlen == sizeof("CAMELLIA256")-1) continue; 3304 } 3305 3306 if (buffer_eq_icase_ss(n, nlen, CONST_STR_LEN("CAMELLIA128")) 3307 || buffer_eq_icase_ss(n, nlen, CONST_STR_LEN("CAMELLIA"))) { 3308 buffer_append_string_len(plist, 3309 CONST_STR_LEN("+CAMELLIA-128-GCM:+CAMELLIA-128-CBC:")); 3310 continue; 3311 } 3312 3313 if (buffer_eq_icase_ss(n, nlen, CONST_STR_LEN("CHACHA20"))) { 3314 buffer_append_string_len(plist, 3315 CONST_STR_LEN("+CHACHA20-POLY1305:")); 3316 continue; 3317 } 3318 3319 if (buffer_eq_icase_ss(n, nlen, CONST_STR_LEN("3DES"))) { 3320 buffer_append_string_len(plist, 3321 CONST_STR_LEN("+3DES-CBC:")); 3322 continue; 3323 } 3324 3325 /* not recommended, but permitted if explicitly requested */ 3326 if (buffer_eq_icase_ss(n, nlen, CONST_STR_LEN("NULL")) 3327 || buffer_eq_icase_ss(n, nlen, CONST_STR_LEN("eNULL"))) { 3328 buffer_append_string_len(plist, 3329 CONST_STR_LEN("+NULL:")); 3330 continue; 3331 } 3332 3333 { 3334 log_error(srv->errh, __FILE__, __LINE__, 3335 "GnuTLS: error: missing support for cipher list: %.*s", 3336 (int)len, p); 3337 rc = 0; 3338 continue; 3339 } 3340 } while (e); 3341 if (0 == rc) return 0; 3342 } 3343 3344 return 1; 3345 } 3346 3347 3348 #if GNUTLS_VERSION_NUMBER < 0x030600 3349 static int 3350 mod_gnutls_ssl_conf_dhparameters(server *srv, plugin_config_socket *s, const buffer *dhparameters) 3351 { 3352 if (dhparameters) { 3353 /* "Prior to GnuTLS 3.6.0 for the ephemeral or anonymous Diffie-Hellman 3354 * (DH) TLS ciphersuites the application was required to generate or 3355 * provide DH parameters. That is no longer necessary as GnuTLS utilizes 3356 * DH parameters and negotiation from [RFC7919]." 3357 */ 3358 /* In other words, the following should not be used in 3.6.0 or later: 3359 * gnutls_certificate_set_dh_params() 3360 * gnutls_certificate_set_known_dh_params() 3361 * However, if support is implemented in mod_gnutls, must also free in 3362 * mod_gnutls_free_config() as gnutls_certificate_free_credentials() 3363 * does not free RSA or DH params manually associated with credential */ 3364 gnutls_datum_t f = { NULL, 0 }; 3365 rc = gnutls_dh_params_init(&s->dh_params); 3366 if (rc < 0) return 0; 3367 rc = mod_gnutls_load_file(dhparameters->ptr, &f, srv->errh); 3368 if (rc < 0) return 0; 3369 rc = gnutls_dh_params_import_pkcs3(s->dh_params,&f,GNUTLS_X509_FMT_PEM); 3370 mod_gnutls_datum_wipe(&f); 3371 if (rc < 0) { 3372 elogf(srv->errh, __FILE__, __LINE__, rc, 3373 "gnutls_dh_params_import_pkcs3() %s", dhparameters->ptr); 3374 return 0; 3375 } 3376 } 3377 else { 3378 #if GNUTLS_VERSION_NUMBER < 0x030506 3379 /* (this might take a while; you should upgrade to newer gnutls) */ 3380 rc = gnutls_dh_params_init(&s->dh_params); 3381 if (rc < 0) return 0; 3382 unsigned int bits = 3383 gnutls_sec_param_to_pk_bits(GNUTLS_PK_DH, GNUTLS_SEC_PARAM_HIGH); 3384 rc = gnutls_dh_params_generate2(s->dh_params, bits); 3385 if (rc < 0) { 3386 elogf(srv->errh, __FILE__, __LINE__, rc, 3387 "gnutls_dh_params_generate2()"); 3388 return 0; 3389 } 3390 #endif 3391 } 3392 3393 return 1; 3394 } 3395 #endif /* GNUTLS_VERSION_NUMBER < 0x030600 */ 3396 3397 3398 static int 3399 mod_gnutls_ssl_conf_curves(server *srv, plugin_config_socket *s, const buffer *curvelist) 3400 { 3401 /* map NIST name (e.g. P-256) or OpenSSL OID name (e.g. prime256v1) 3402 * to GnuTLS name of supported curves/groups */ 3403 static const char *names[] = { 3404 "P-192", "CURVE-SECP192R1", 3405 "P-224", "CURVE-SECP224R1", 3406 "P-256", "GROUP-SECP256R1", /* CURVE-SECP256R1 */ 3407 "P-384", "GROUP-SECP384R1", /* CURVE-SECP384R1 */ 3408 "P-521", "GROUP-SECP521R1", /* CURVE-SECP521R1 */ 3409 "X25519", "GROUP-X25519", /* CURVE-X25519 */ 3410 "X448", "GROUP-X448", /* CURVE-X448 */ 3411 "prime192v1", "CURVE-SECP192R1", 3412 "secp224r1", "CURVE-SECP224R1", 3413 "prime256v1", "GROUP-SECP256R1", /* CURVE-SECP256R1 */ 3414 "secp384r1", "GROUP-SECP384R1", /* CURVE-SECP384R1 */ 3415 "secp521r1", "GROUP-SECP521R1", /* CURVE-SECP521R1 */ 3416 "ffdhe2048", "GROUP-FFDHE2048", 3417 "ffdhe3072", "GROUP-FFDHE3072", 3418 "ffdhe4096", "GROUP-FFDHE4096", 3419 "ffdhe6144", "GROUP-FFDHE6144", 3420 "ffdhe8192", "GROUP-FFDHE8192", 3421 }; 3422 3423 buffer * const plist = &s->priority_str; 3424 const buffer * const b = curvelist; 3425 for (const char *e = b->ptr-1; e; ) { 3426 const char * const n = e+1; 3427 e = strchr(n, ':'); 3428 size_t len = e ? (size_t)(e - n) : strlen(n); 3429 uint32_t i; 3430 for (i = 0; i < sizeof(names)/sizeof(*names)/2; i += 2) { 3431 if (0 == strncmp(names[i], n, len) && names[i][len] == '\0') 3432 break; 3433 } 3434 if (i == sizeof(names)/sizeof(*names)/2) { 3435 log_error(srv->errh, __FILE__, __LINE__, 3436 "GnuTLS: unrecognized curve: %.*s; ignored", (int)len, n); 3437 continue; 3438 } 3439 3440 buffer_append_char(plist, '+'); 3441 buffer_append_string_len(plist, names[i+1], strlen(names[i+1])); 3442 buffer_append_char(plist, ':'); 3443 } 3444 3445 return 1; 3446 } 3447 3448 3449 static int 3450 mod_gnutls_ssl_conf_proto_val (server *srv, const buffer *b, int max) 3451 { 3452 if (NULL == b) /* default: min TLSv1.2, max TLSv1.3 */ 3453 return max ? GNUTLS_TLS1_3 : GNUTLS_TLS1_2; 3454 else if (buffer_eq_icase_slen(b, CONST_STR_LEN("None"))) /*"disable" limit*/ 3455 return max ? GNUTLS_TLS1_3 : GNUTLS_TLS1_0; 3456 else if (buffer_eq_icase_slen(b, CONST_STR_LEN("TLSv1.0"))) 3457 return GNUTLS_TLS1_0; 3458 else if (buffer_eq_icase_slen(b, CONST_STR_LEN("TLSv1.1"))) 3459 return GNUTLS_TLS1_1; 3460 else if (buffer_eq_icase_slen(b, CONST_STR_LEN("TLSv1.2"))) 3461 return GNUTLS_TLS1_2; 3462 else if (buffer_eq_icase_slen(b, CONST_STR_LEN("TLSv1.3"))) 3463 return GNUTLS_TLS1_3; 3464 else { 3465 if (buffer_eq_icase_slen(b, CONST_STR_LEN("DTLSv1")) 3466 || buffer_eq_icase_slen(b, CONST_STR_LEN("DTLSv1.2"))) 3467 log_error(srv->errh, __FILE__, __LINE__, 3468 "GnuTLS: ssl.openssl.ssl-conf-cmd %s %s ignored", 3469 max ? "MaxProtocol" : "MinProtocol", b->ptr); 3470 else 3471 log_error(srv->errh, __FILE__, __LINE__, 3472 "GnuTLS: ssl.openssl.ssl-conf-cmd %s %s invalid; ignored", 3473 max ? "MaxProtocol" : "MinProtocol", b->ptr); 3474 } 3475 return max ? GNUTLS_TLS1_3 : GNUTLS_TLS1_2; 3476 } 3477 3478 3479 static void 3480 mod_gnutls_ssl_conf_proto (server *srv, plugin_config_socket *s, const buffer *minb, const buffer *maxb) 3481 { 3482 /* use of SSL v3 should be avoided, and SSL v2 is not supported */ 3483 int n = mod_gnutls_ssl_conf_proto_val(srv, minb, 0); 3484 int x = mod_gnutls_ssl_conf_proto_val(srv, maxb, 1); 3485 if (n < 0) return; 3486 if (x < 0) return; 3487 buffer * const b = &s->priority_str; 3488 buffer_append_string_len(b, CONST_STR_LEN("-VERS-ALL:")); 3489 switch (n) { 3490 case GNUTLS_SSL3: 3491 buffer_append_string_len(b, CONST_STR_LEN("+VERS-SSL3.0:")); 3492 __attribute_fallthrough__ 3493 case GNUTLS_TLS1_0: 3494 if (x < GNUTLS_TLS1_0) break; 3495 buffer_append_string_len(b, CONST_STR_LEN("+VERS-TLS1.0:")); 3496 __attribute_fallthrough__ 3497 case GNUTLS_TLS1_1: 3498 if (x < GNUTLS_TLS1_1) break; 3499 buffer_append_string_len(b, CONST_STR_LEN("+VERS-TLS1.1:")); 3500 __attribute_fallthrough__ 3501 case GNUTLS_TLS1_2: 3502 if (x < GNUTLS_TLS1_2) break; 3503 buffer_append_string_len(b, CONST_STR_LEN("+VERS-TLS1.2:")); 3504 __attribute_fallthrough__ 3505 case GNUTLS_TLS1_3: 3506 if (x < GNUTLS_TLS1_3) break; 3507 buffer_append_string_len(b, CONST_STR_LEN("+VERS-TLS1.3:")); 3508 break; 3509 } 3510 } 3511