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