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