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