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