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