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 = con->plugin_ctx[plugin_data_singleton->id]; */ 139 static plugin_data *plugin_data_singleton; 140 #define LOCAL_SEND_BUFSIZE 16384 /* DEFAULT_MAX_RECORD_SIZE */ 141 static char *local_send_buffer; 142 143 typedef struct { 144 gnutls_session_t ssl; /* gnutls request/connection context */ 145 request_st *r; 146 connection *con; 147 int8_t close_notify; 148 uint8_t alpn; 149 int8_t ssl_session_ticket; 150 int handshake; 151 size_t pending_write; 152 plugin_config conf; 153 unsigned int verify_status; 154 buffer *tmp_buf; 155 log_error_st *errh; 156 gnutls_certificate_credentials_t acme_tls_1_cred; 157 } handler_ctx; 158 159 160 static handler_ctx * 161 handler_ctx_init (void) 162 { 163 handler_ctx *hctx = calloc(1, sizeof(*hctx)); 164 force_assert(hctx); 165 return hctx; 166 } 167 168 169 static void 170 handler_ctx_free (handler_ctx *hctx) 171 { 172 gnutls_deinit(hctx->ssl); 173 if (hctx->acme_tls_1_cred) 174 gnutls_certificate_free_credentials(hctx->acme_tls_1_cred); 175 free(hctx); 176 } 177 178 179 __attribute_cold__ 180 static void elog(log_error_st * const errh, 181 const char * const file, const int line, 182 const int rc, const char * const msg) 183 { 184 /* error logging convenience function that decodes gnutls result codes */ 185 log_error(errh, file, line, "GnuTLS: %s: (%s) %s", 186 msg, gnutls_strerror_name(rc), gnutls_strerror(rc)); 187 } 188 189 190 __attribute_cold__ 191 __attribute_format__((__printf__, 5, 6)) 192 static void elogf(log_error_st * const errh, 193 const char * const file, const int line, 194 const int rc, const char * const fmt, ...) 195 { 196 char msg[1024]; 197 va_list ap; 198 va_start(ap, fmt); 199 vsnprintf(msg, sizeof(msg), fmt, ap); 200 va_end(ap); 201 elog(errh, file, line, rc, msg); 202 } 203 204 205 /* gnutls func gnutls_load_file() loads file contents into a gnutls_datum_t. 206 * The data loaded could be sensitive, e.g. a private key included in a pemfile. 207 * However, gnutls_load_file() is not careful about zeroizing memory on error, 208 * might use realloc() (which does not guarantee to zeroize memory released), 209 * and silently continues on short read, so provide our own. Updates to 210 * gnutls 3.6.14 may be more careful with private key files, but do not 211 * extend the same care to pemfiles which might contain private keys. 212 * Related, see also mod_gnutls_datum_wipe() below. 213 * https://gitlab.com/gnutls/gnutls/-/issues/1001 214 * https://gitlab.com/gnutls/gnutls/-/issues/1002 215 * https://gitlab.com/gnutls/gnutls/-/merge_requests/1270 216 */ 217 static int 218 mod_gnutls_load_file (const char * const fn, gnutls_datum_t * const d, log_error_st *errh) 219 { 220 #if 0 221 int rc = gnutls_load_file(fn, d); 222 if (rc < 0) 223 elogf(errh, __FILE__, __LINE__, rc, "%s() %s", __func__, fn); 224 return rc; 225 #else 226 off_t dlen = 512*1024*1024;/*(arbitrary limit: 512 MB file; expect < 1 MB)*/ 227 char *data = fdevent_load_file(fn, &dlen, errh, gnutls_malloc, gnutls_free); 228 if (NULL == data) return GNUTLS_E_FILE_ERROR; 229 d->data = (unsigned char *)data; 230 d->size = (unsigned int)dlen; 231 return 0; 232 #endif 233 } 234 235 236 /* GnuTLS does not expose _gnutls_free_key_datum() so provide our own */ 237 static void 238 mod_gnutls_datum_wipe (gnutls_datum_t * const d) 239 { 240 if (NULL == d) return; 241 if (d->data) { 242 if (d->size) gnutls_memset(d->data, 0, d->size); 243 gnutls_free(d->data); 244 d->data = NULL; 245 } 246 d->size = 0; 247 } 248 249 250 /* session tickets 251 * 252 * gnutls expects 64 bytes of random data in gnutls_datum_t passed to 253 * gnutls_session_ticket_enable_server() 254 * 255 * (private) session ticket definitions from lib/gnutls_int.h 256 * #define TICKET_MASTER_KEY_SIZE (TICKET_KEY_NAME_SIZE+TICKET_CIPHER_KEY_SIZE+TICKET_MAC_SECRET_SIZE) 257 * #define TICKET_KEY_NAME_SIZE 16 258 * #define TICKET_CIPHER_KEY_SIZE 32 259 * #define TICKET_MAC_SECRET_SIZE 16 260 */ 261 #define TICKET_MASTER_KEY_SIZE 64 262 263 #define TLSEXT_KEYNAME_LENGTH 16 264 #define TLSEXT_TICK_KEY_LENGTH 32 265 266 /* construct our own session ticket encryption key structure 267 * to store keys that are not yet active 268 * (mirror from mod_openssl, even though not all bits are used here) */ 269 typedef struct tlsext_ticket_key_st { 270 time_t active_ts; /* tickets not issued w/ key until activation timestamp */ 271 time_t expire_ts; /* key not valid after expiration timestamp */ 272 unsigned char tick_key_name[TLSEXT_KEYNAME_LENGTH]; 273 unsigned char tick_hmac_key[TLSEXT_TICK_KEY_LENGTH]; 274 unsigned char tick_aes_key[TLSEXT_TICK_KEY_LENGTH]; 275 } tlsext_ticket_key_t; 276 277 static tlsext_ticket_key_t session_ticket_keys[1]; /* temp store until active */ 278 static time_t stek_rotate_ts; 279 280 static gnutls_datum_t session_ticket_key; 281 282 283 static void 284 mod_gnutls_session_ticket_key_free (void) 285 { 286 mod_gnutls_datum_wipe(&session_ticket_key); 287 } 288 static void 289 mod_gnutls_session_ticket_key_init (server *srv) 290 { 291 int rc = gnutls_session_ticket_key_generate(&session_ticket_key); 292 if (rc < 0) { 293 /*(should not happen, but if it does, disable session ticket)*/ 294 session_ticket_key.size = 0; 295 elog(srv->errh, __FILE__, __LINE__, rc, 296 "gnutls_session_ticket_key_generate()"); 297 } 298 } 299 static void 300 mod_gnutls_session_ticket_key_rotate (server *srv) 301 { 302 mod_gnutls_session_ticket_key_free(); 303 mod_gnutls_session_ticket_key_init(srv); 304 } 305 306 307 static int 308 mod_gnutls_session_ticket_key_file (const char *fn) 309 { 310 /* session ticket encryption key (STEK) 311 * 312 * STEK file should be stored in non-persistent storage, 313 * e.g. /dev/shm/lighttpd/stek-file (in memory) 314 * with appropriate permissions set to keep stek-file from being 315 * read by other users. Where possible, systems should also be 316 * configured without swap. 317 * 318 * admin should schedule an independent job to periodically 319 * generate new STEK up to 3 times during key lifetime 320 * (lighttpd stores up to 3 keys) 321 * 322 * format of binary file is: 323 * 4-byte - format version (always 0; for use if format changes) 324 * 4-byte - activation timestamp 325 * 4-byte - expiration timestamp 326 * 16-byte - session ticket key name 327 * 32-byte - session ticket HMAC encrpytion key 328 * 32-byte - session ticket AES encrpytion key 329 * 330 * STEK file can be created with a command such as: 331 * dd if=/dev/random bs=1 count=80 status=none | \ 332 * perl -e 'print pack("iii",0,time()+300,time()+86400),<>' \ 333 * > STEK-file.$$ && mv STEK-file.$$ STEK-file 334 * 335 * The above delays activation time by 5 mins (+300 sec) to allow file to 336 * be propagated to other machines. (admin must handle this independently) 337 * If STEK generation is performed immediately prior to starting lighttpd, 338 * admin should activate keys immediately (without +300). 339 */ 340 int buf[23]; /* 92 bytes */ 341 int 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 (chunkqueue * const cq, off_t max_bytes, 2205 const char ** const data, size_t * const data_len, 2206 log_error_st * const errh) 2207 { 2208 chunk *c = cq->first; 2209 2210 /* local_send_buffer is a static buffer of size (LOCAL_SEND_BUFSIZE) 2211 * 2212 * buffer is allocated once, is NOT realloced (note: not thread-safe) 2213 * */ 2214 2215 force_assert(NULL != c); 2216 2217 switch (c->type) { 2218 case MEM_CHUNK: 2219 *data = NULL; 2220 *data_len = 0; 2221 do { 2222 size_t have; 2223 2224 force_assert(c->offset >= 0 2225 && c->offset <= (off_t)buffer_string_length(c->mem)); 2226 2227 have = buffer_string_length(c->mem) - c->offset; 2228 2229 /* copy small mem chunks into single large buffer 2230 * before gnutls_record_send() to reduce number times 2231 * write() called underneath gnutls_record_send() and 2232 * potentially reduce number of packets generated if TCP_NODELAY 2233 * Alternatively, GnuTLS provides gnutls_record_cork() and 2234 * gnutls_record_uncork(), not currently used by mod_gnutls */ 2235 if (*data_len) { 2236 size_t space = LOCAL_SEND_BUFSIZE - *data_len; 2237 if (have > space) 2238 have = space; 2239 if (have > (size_t)max_bytes - *data_len) 2240 have = (size_t)max_bytes - *data_len; 2241 if (*data != local_send_buffer) { 2242 memcpy(local_send_buffer, *data, *data_len); 2243 *data = local_send_buffer; 2244 } 2245 memcpy(local_send_buffer+*data_len,c->mem->ptr+c->offset,have); 2246 *data_len += have; 2247 continue; 2248 } 2249 2250 if ((off_t) have > max_bytes) have = max_bytes; 2251 2252 *data = c->mem->ptr + c->offset; 2253 *data_len = have; 2254 } while ((c = c->next) && c->type == MEM_CHUNK 2255 && *data_len < LOCAL_SEND_BUFSIZE 2256 && (off_t) *data_len < max_bytes); 2257 return 0; 2258 2259 case FILE_CHUNK: 2260 if (0 != chunkqueue_open_file_chunk(cq, errh)) return -1; 2261 2262 { 2263 off_t offset, toSend; 2264 2265 force_assert(c->offset >= 0 && c->offset <= c->file.length); 2266 offset = c->file.start + c->offset; 2267 toSend = c->file.length - c->offset; 2268 2269 if (toSend > LOCAL_SEND_BUFSIZE) toSend = LOCAL_SEND_BUFSIZE; 2270 if (toSend > max_bytes) toSend = max_bytes; 2271 2272 if (-1 == lseek(c->file.fd, offset, SEEK_SET)) { 2273 log_perror(errh, __FILE__, __LINE__, "lseek"); 2274 return -1; 2275 } 2276 if (-1 == (toSend = read(c->file.fd, local_send_buffer, toSend))) { 2277 log_perror(errh, __FILE__, __LINE__, "read"); 2278 return -1; 2279 } 2280 2281 *data = local_send_buffer; 2282 *data_len = toSend; 2283 } 2284 return 0; 2285 } 2286 2287 return -1; 2288 } 2289 2290 2291 __attribute_cold__ 2292 static int 2293 mod_gnutls_write_err(connection *con, handler_ctx *hctx, int wr, size_t wr_len) 2294 { 2295 switch (wr) { 2296 case GNUTLS_E_AGAIN: 2297 case GNUTLS_E_INTERRUPTED: 2298 if (gnutls_record_get_direction(hctx->ssl)) 2299 con->is_writable = -1; 2300 else 2301 con->is_readable = -1; 2302 break; /* try again later */ 2303 default: 2304 #if 0 2305 /* ??? how to check for EPIPE or ECONNRESET and skip logging ??? */ 2306 if (hctx->conf.ssl_log_noise) 2307 elog(hctx->r->conf.errh, __FILE__, __LINE__, wr, __func__); 2308 #endif 2309 elog(hctx->r->conf.errh, __FILE__, __LINE__, wr, __func__); 2310 return -1; 2311 } 2312 2313 /* partial write; save attempted wr_len */ 2314 hctx->pending_write = wr_len; 2315 2316 return 0; /* try again later */ 2317 } 2318 2319 2320 __attribute_cold__ 2321 static int 2322 mod_gnutls_read_err(connection *con, handler_ctx *hctx, int rc) 2323 { 2324 switch (rc) { 2325 case GNUTLS_E_AGAIN: 2326 case GNUTLS_E_INTERRUPTED: 2327 if (gnutls_record_get_direction(hctx->ssl)) 2328 con->is_writable = -1; 2329 con->is_readable = 0; 2330 return 0; 2331 #if 0 2332 case GNUTLS_E_SESSION_EOF: /*(not exposed by library)*/ 2333 /* XXX: future: save state to avoid future read after response? */ 2334 con->is_readable = 0; 2335 r->keep_alive = 0; 2336 return (hctx->handshake ? -2 : -1); /*(-1 error if during handshake)*/ 2337 #endif 2338 case GNUTLS_E_REHANDSHAKE: 2339 if (!hctx->handshake) return -1; /*(not expected during handshake)*/ 2340 if (hctx->conf.ssl_disable_client_renegotiation)/*(mod_gnutls default)*/ 2341 return -1; 2342 #if 0 2343 if (gnutls_safe_renegotiation_status(hctx->ssl)) { 2344 hctx->handshake = 0; 2345 return con->network_read(con, cq, max_bytes); 2346 } 2347 #else 2348 return 0; /*(ignore client renegotiation request; generally unsafe)*/ 2349 #endif 2350 case GNUTLS_E_WARNING_ALERT_RECEIVED: 2351 case GNUTLS_E_FATAL_ALERT_RECEIVED: 2352 { 2353 const char *str; 2354 gnutls_alert_description_t alert = gnutls_alert_get(hctx->ssl); 2355 switch (alert) { 2356 case GNUTLS_A_NO_RENEGOTIATION: 2357 return 0; /*(ignore non-fatal alert from client)*/ 2358 case GNUTLS_A_HANDSHAKE_FAILURE: 2359 case GNUTLS_A_CLOSE_NOTIFY: /*(not exposed by library)*/ 2360 case GNUTLS_A_UNKNOWN_CA: 2361 case GNUTLS_A_CERTIFICATE_UNKNOWN: 2362 case GNUTLS_A_BAD_CERTIFICATE: 2363 if (!hctx->conf.ssl_log_noise) return -1; 2364 __attribute_fallthrough__ 2365 default: 2366 str = gnutls_alert_get_name(alert); 2367 elogf(hctx->r->conf.errh, __FILE__, __LINE__, rc, 2368 "%s(): alert %s", __func__, str ? str : "(unknown)"); 2369 return -1; 2370 } 2371 } 2372 case GNUTLS_E_UNEXPECTED_HANDSHAKE_PACKET: 2373 case GNUTLS_E_UNKNOWN_CIPHER_SUITE: /* GNUTLS_A_HANDSHAKE_FAILURE */ 2374 case GNUTLS_E_PREMATURE_TERMINATION: 2375 if (!hctx->conf.ssl_log_noise) return -1; 2376 __attribute_fallthrough__ 2377 case GNUTLS_E_GOT_APPLICATION_DATA: /*(not expected with current use)*/ 2378 /*if (hctx->handshake) return -1;*//*(accept only during handshake)*/ 2379 default: 2380 elog(hctx->r->conf.errh, __FILE__, __LINE__, rc, __func__); 2381 return -1; 2382 } 2383 } 2384 2385 2386 static int 2387 mod_gnutls_close_notify(handler_ctx *hctx); 2388 2389 2390 static int 2391 connection_write_cq_ssl (connection *con, chunkqueue *cq, off_t max_bytes) 2392 { 2393 handler_ctx *hctx = con->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 log_error_st * const errh = hctx->errh; 2421 while (max_bytes > 0 && NULL != cq->first) { 2422 const char *data; 2423 size_t data_len; 2424 int wr; 2425 2426 if (0 != load_next_chunk(cq,max_bytes,&data,&data_len,errh)) return -1; 2427 2428 /* gnutls_record_send() copies the data, up to max record size, but if 2429 * (temporarily) unable to write the entire record, it is documented 2430 * that the caller must call gnutls_record_send() again, later, with the 2431 * same arguments, or with NULL ptr and 0 data_len. The func may return 2432 * GNUTLS_E_AGAIN or GNUTLS_E_INTERRUPTED to indicate that caller should 2433 * wait for fd to be readable/writable before calling the func again, 2434 * which is why those (temporary) errors are returned instead of telling 2435 * the caller that the data was successfully copied. 2436 * Additionally, to be accurate, the size must fit into a record which 2437 * is why we restrict ourselves to sending max out record payload each 2438 * iteration. 2439 * XXX: above comments modified from mod_mbedtls; should be verified 2440 */ 2441 2442 int wr_total = 0; 2443 do { 2444 size_t wr_len = (data_len > lim) ? lim : data_len; 2445 wr = gnutls_record_send(ssl, data, wr_len); 2446 if (wr <= 0) { 2447 if (wr_total) chunkqueue_mark_written(cq, wr_total); 2448 return mod_gnutls_write_err(con, hctx, wr, wr_len); 2449 } 2450 wr_total += wr; 2451 data += wr; 2452 } while ((data_len -= wr)); 2453 chunkqueue_mark_written(cq, wr_total); 2454 max_bytes -= wr_total; 2455 } 2456 2457 return 0; 2458 } 2459 2460 2461 static int 2462 mod_gnutls_ssl_handshake (handler_ctx *hctx) 2463 { 2464 int rc = gnutls_handshake(hctx->ssl); 2465 if (rc < 0) 2466 return mod_gnutls_read_err(hctx->con, hctx, rc); 2467 2468 /*(rc == GNUTLS_E_SUCCESS)*/ 2469 2470 hctx->handshake = 1; 2471 #if GNUTLS_VERSION_NUMBER >= 0x030200 2472 if (hctx->alpn == MOD_GNUTLS_ALPN_ACME_TLS_1) { 2473 /* Once TLS handshake is complete, return -1 to result in 2474 * CON_STATE_ERROR so that socket connection is quickly closed */ 2475 return -1; 2476 } 2477 hctx->alpn = 0; 2478 #endif 2479 return 1; /* continue reading */ 2480 } 2481 2482 2483 static int 2484 connection_read_cq_ssl (connection *con, chunkqueue *cq, off_t max_bytes) 2485 { 2486 handler_ctx *hctx = con->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 hctx->errh = r->conf.errh; 2550 con->plugin_ctx[p->id] = hctx; 2551 2552 plugin_ssl_ctx * const s = p->ssl_ctxs + srv_sock->sidx; 2553 hctx->ssl_session_ticket = s->ssl_session_ticket; 2554 int flags = GNUTLS_SERVER | GNUTLS_NO_SIGNAL | GNUTLS_NONBLOCK; 2555 /* ??? add feature: GNUTLS_ENABLE_EARLY_START ??? */ 2556 int rc = gnutls_init(&hctx->ssl, flags); 2557 if (rc < 0) { 2558 elog(r->conf.errh, __FILE__, __LINE__, rc, "gnutls_init()"); 2559 return HANDLER_ERROR; 2560 } 2561 2562 rc = gnutls_priority_set(hctx->ssl, s->priority_cache); 2563 if (rc < 0) { 2564 elog(r->conf.errh, __FILE__, __LINE__, rc, "gnutls_priority_set()"); 2565 return HANDLER_ERROR; 2566 } 2567 2568 /* generic func replaces gnutls_handshake_set_post_client_hello_function()*/ 2569 gnutls_handshake_set_hook_function(hctx->ssl, GNUTLS_HANDSHAKE_CLIENT_HELLO, 2570 GNUTLS_HOOK_BOTH, 2571 mod_gnutls_client_hello_hook); 2572 2573 gnutls_session_set_ptr(hctx->ssl, hctx); 2574 gnutls_transport_set_int(hctx->ssl, con->fd); 2575 2576 con->network_read = connection_read_cq_ssl; 2577 con->network_write = connection_write_cq_ssl; 2578 con->proto_default_port = 443; /* "https" */ 2579 mod_gnutls_patch_config(r, &hctx->conf); 2580 2581 #if GNUTLS_VERSION_NUMBER < 0x030600 2582 hctx->conf.dh_params = s->dh_params; 2583 #endif 2584 2585 /* debug logging is global. Once enabled, debug hook will remain so, though 2586 * different connection might overwrite level, if configured differently. 2587 * If GNUTLS_DEBUG_LEVEL is set in environment (and ssl_log_noise not set), 2588 * then debugging will go to stderr */ 2589 if (hctx->conf.ssl_log_noise) {/* volume level for debug message callback */ 2590 gnutls_global_set_log_function(mod_gnutls_debug_cb); 2591 gnutls_global_set_log_level(hctx->conf.ssl_log_noise); 2592 } 2593 2594 /* GnuTLS limitation: must set session ticket encryption key before GnuTLS 2595 * client hello hook runs if TLSv1.3 (? key already set by then ?) */ 2596 if (hctx->ssl_session_ticket && session_ticket_key.size) { 2597 rc = gnutls_session_ticket_enable_server(hctx->ssl,&session_ticket_key); 2598 if (rc < 0) { 2599 elog(r->conf.errh, __FILE__, __LINE__, rc, 2600 "gnutls_session_ticket_enable_server()"); 2601 return HANDLER_ERROR; 2602 } 2603 } 2604 2605 return HANDLER_GO_ON; 2606 } 2607 2608 2609 static void 2610 mod_gnutls_detach(handler_ctx *hctx) 2611 { 2612 /* step aside from further SSL processing 2613 * (used after handle_connection_shut_wr hook) */ 2614 /* future: might restore prior network_read and network_write fn ptrs */ 2615 hctx->con->is_ssl_sock = 0; 2616 /* if called after handle_connection_shut_wr hook, shutdown SHUT_WR */ 2617 if (-1 == hctx->close_notify) shutdown(hctx->con->fd, SHUT_WR); 2618 hctx->close_notify = 1; 2619 } 2620 2621 2622 CONNECTION_FUNC(mod_gnutls_handle_con_shut_wr) 2623 { 2624 plugin_data *p = p_d; 2625 handler_ctx *hctx = con->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 plugin_data *p = p_d; 2665 handler_ctx *hctx = con->plugin_ctx[p->id]; 2666 if (NULL != hctx) { 2667 con->plugin_ctx[p->id] = NULL; 2668 if (1 != hctx->close_notify) 2669 mod_gnutls_close_notify(hctx); /*(one final try)*/ 2670 handler_ctx_free(hctx); 2671 } 2672 2673 return HANDLER_GO_ON; 2674 } 2675 2676 2677 __attribute_noinline__ 2678 static void 2679 https_add_ssl_client_cert (request_st * const r, const gnutls_x509_crt_t peer) 2680 { 2681 gnutls_datum_t d; 2682 if (gnutls_x509_crt_export2(peer, GNUTLS_X509_FMT_PEM, &d) >= 0) 2683 http_header_env_set(r, 2684 CONST_STR_LEN("SSL_CLIENT_CERT"), 2685 (char *)d.data, d.size); 2686 if (d.data) gnutls_free(d.data); 2687 } 2688 2689 2690 /* modified from gnutls tests/dn.c:print_dn() */ 2691 static void 2692 https_add_ssl_client_subject (request_st * const r, gnutls_x509_dn_t dn) 2693 { 2694 buffer * const tb = r->tmp_buf; 2695 int irdn = 0, i, rc; 2696 gnutls_x509_ava_st ava; 2697 char buf[512]; /*(expecting element value len <= 256)*/ 2698 2699 /* add components of client Subject DN */ 2700 buffer_copy_string_len(tb, CONST_STR_LEN("SSL_CLIENT_S_DN_")); 2701 2702 /* man gnutls_x509_dn_get_rdn_ava() 2703 * The X.509 distinguished name is a sequence of sequences of strings and 2704 * this is what the irdn and iava indexes model. 2705 * This is a low-level function that requires the caller to do the value 2706 * conversions when necessary (e.g. from UCS-2). 2707 * XXX: value conversions not done below; unprintable chars replaced w/ '?' 2708 */ 2709 2710 do { 2711 for (i=0; (rc = gnutls_x509_dn_get_rdn_ava(dn,irdn,i,&ava)) == 0; ++i) { 2712 const char *name = 2713 gnutls_x509_dn_oid_name((char *)ava.oid.data, 2714 GNUTLS_X509_DN_OID_RETURN_OID); 2715 buffer_string_set_length(tb, sizeof("SSL_CLIENT_S_DN_")-1); 2716 buffer_append_string_len(tb, name, strlen(name)); 2717 2718 unsigned int v, n = 0; 2719 for (v = 0; v < ava.value.size && n < sizeof(buf)-1; ++n) { 2720 unsigned char c = ava.value.data[v]; 2721 buf[n] = (c < 32 || c == 127 || (c > 128 && c < 160)) ? '?' : c; 2722 } 2723 2724 http_header_env_set(r, CONST_BUF_LEN(tb), buf, n); 2725 } 2726 ++irdn; 2727 } while (rc == GNUTLS_E_ASN1_ELEMENT_NOT_FOUND && i > 0); 2728 2729 if (rc != GNUTLS_E_ASN1_ELEMENT_NOT_FOUND) 2730 elog(r->conf.errh, __FILE__, __LINE__, rc, 2731 "gnutls_x509_dn_get_rdn_ava()"); 2732 } 2733 2734 static void 2735 https_add_ssl_client_entries (request_st * const r, handler_ctx * const hctx) 2736 { 2737 gnutls_session_t ssl = hctx->ssl; 2738 unsigned int crt_size = 0; 2739 const gnutls_datum_t *crts; 2740 gnutls_x509_crt_t crt; 2741 buffer * const tb = r->tmp_buf; 2742 char buf[513]; /*(512+1 for li_tohex_uc())*/ 2743 size_t sz; 2744 2745 if (hctx->verify_status != ~0u) 2746 crts = gnutls_certificate_get_peers(ssl, &crt_size); 2747 if (0 == crt_size) { /* || hctx->verify_status == ~0u) */ 2748 /*(e.g. no cert, or verify result not available)*/ 2749 http_header_env_set(r, 2750 CONST_STR_LEN("SSL_CLIENT_VERIFY"), 2751 CONST_STR_LEN("NONE")); 2752 return; 2753 } 2754 else if (0 != hctx->verify_status) { 2755 buffer_copy_string_len(tb, CONST_STR_LEN("FAILED:")); 2756 #if GNUTLS_VERSION_NUMBER >= 0x030104 2757 /* get failure string and translate newline to ':', removing last one */ 2758 /* (preserving behavior from mod_openssl) */ 2759 gnutls_datum_t msg = { NULL, 0 }; 2760 if (gnutls_certificate_verification_status_print(hctx->verify_status, 2761 GNUTLS_CRT_X509, 2762 &msg, 0) >= 0) { 2763 sz = msg.size-1; /* '\0'-terminated string */ 2764 for (char *nl=(char *)msg.data; NULL != (nl=strchr(nl, '\n')); ++nl) 2765 nl[0] = ('\0' == nl[1] ? (--sz, '\0') : ':'); 2766 buffer_append_string_len(tb, (char *)msg.data, sz); 2767 } 2768 if (msg.data) gnutls_free(msg.data); 2769 #endif 2770 http_header_env_set(r, 2771 CONST_STR_LEN("SSL_CLIENT_VERIFY"), 2772 CONST_BUF_LEN(tb)); 2773 return; 2774 } 2775 else { 2776 http_header_env_set(r, 2777 CONST_STR_LEN("SSL_CLIENT_VERIFY"), 2778 CONST_STR_LEN("SUCCESS")); 2779 } 2780 2781 if (gnutls_x509_crt_init(&crt) < 0) 2782 return; 2783 if (gnutls_x509_crt_import(crt, &crts[0], GNUTLS_X509_FMT_DER) < 0) { 2784 gnutls_x509_crt_deinit(crt); 2785 return; 2786 } 2787 2788 int rc; 2789 gnutls_datum_t d = { NULL, 0 }; 2790 /*rc = gnutls_x509_crt_print(cert, GNUTLS_CRT_PRINT_ONELINE, &d);*//* ??? */ 2791 #if GNUTLS_VERSION_NUMBER < 0x030507 2792 d.data = buf; 2793 d.size = sizeof(buf); 2794 rc = gnutls_x509_crt_get_dn(crt, buf, &d.size); 2795 #else 2796 rc = gnutls_x509_crt_get_dn3(crt, &d, 0); 2797 #endif 2798 if (rc >= 0) 2799 http_header_env_set(r, 2800 CONST_STR_LEN("SSL_CLIENT_S_DN"), 2801 (char *)d.data, d.size); 2802 if (d.data && d.data != (void *)buf) gnutls_free(d.data); 2803 2804 gnutls_x509_dn_t dn; 2805 rc = gnutls_x509_crt_get_subject(crt, &dn); 2806 if (rc >= 0) 2807 https_add_ssl_client_subject(r, dn); 2808 2809 sz = sizeof(buf)/2; 2810 if (gnutls_x509_crt_get_serial(crt, buf+sz, &sz) >= 0) { 2811 li_tohex_uc(buf, sizeof(buf), buf+(sizeof(buf)/2), sz); 2812 http_header_env_set(r, 2813 CONST_STR_LEN("SSL_CLIENT_M_SERIAL"), 2814 buf, sz*2); 2815 } 2816 2817 if (!buffer_string_is_empty(hctx->conf.ssl_verifyclient_username)) { 2818 /* pick one of the exported values as "REMOTE_USER", for example 2819 * ssl.verifyclient.username = "SSL_CLIENT_S_DN_UID" 2820 * or 2821 * ssl.verifyclient.username = "SSL_CLIENT_S_DN_emailAddress" 2822 */ 2823 const buffer *varname = hctx->conf.ssl_verifyclient_username; 2824 const buffer *vb = http_header_env_get(r, CONST_BUF_LEN(varname)); 2825 if (vb) { /* same as http_auth.c:http_auth_setenv() */ 2826 http_header_env_set(r, 2827 CONST_STR_LEN("REMOTE_USER"), 2828 CONST_BUF_LEN(vb)); 2829 http_header_env_set(r, 2830 CONST_STR_LEN("AUTH_TYPE"), 2831 CONST_STR_LEN("SSL_CLIENT_VERIFY")); 2832 } 2833 } 2834 2835 /* if (NULL != crt) (e.g. not PSK-based ciphersuite) */ 2836 if (hctx->conf.ssl_verifyclient_export_cert && NULL != crt) 2837 https_add_ssl_client_cert(r, crt); 2838 2839 gnutls_x509_crt_deinit(crt); 2840 } 2841 2842 2843 static void 2844 http_cgi_ssl_env (request_st * const r, handler_ctx * const hctx) 2845 { 2846 gnutls_session_t ssl = hctx->ssl; 2847 gnutls_protocol_t version = gnutls_protocol_get_version(ssl); 2848 gnutls_cipher_algorithm_t cipher = gnutls_cipher_get(ssl); 2849 gnutls_kx_algorithm_t kx = gnutls_kx_get(ssl); 2850 gnutls_mac_algorithm_t mac = gnutls_mac_get(ssl); 2851 const char *s; 2852 2853 s = gnutls_protocol_get_name(version); 2854 if (s) http_header_env_set(r, CONST_STR_LEN("SSL_PROTOCOL"), s, strlen(s)); 2855 2856 s = gnutls_cipher_suite_get_name(kx, cipher, mac); 2857 if (s) http_header_env_set(r, CONST_STR_LEN("SSL_CIPHER"), s, strlen(s)); 2858 2859 /* SSL_CIPHER_ALGKEYSIZE - Number of cipher bits (possible) */ 2860 /* SSL_CIPHER_USEKEYSIZE - Number of cipher bits (actually used) */ 2861 /* (always the same in extra/gnutls_openssl.c:SSL_CIPHER_get_bits()) 2862 * (The values are the same except for very old, weak ciphers, i.e. if you 2863 * care about this, then you instead ought to be using stronger ciphers)*/ 2864 /* ??? gnutls_x509_crt_get_pk_algorithm(crt, &usekeysize); ??? */ 2865 size_t algkeysize = 8 * gnutls_cipher_get_key_size(cipher); 2866 size_t usekeysize = algkeysize; 2867 char buf[LI_ITOSTRING_LENGTH]; 2868 http_header_env_set(r, CONST_STR_LEN("SSL_CIPHER_USEKEYSIZE"), 2869 buf, li_utostrn(buf, sizeof(buf), usekeysize)); 2870 http_header_env_set(r, CONST_STR_LEN("SSL_CIPHER_ALGKEYSIZE"), 2871 buf, li_utostrn(buf, sizeof(buf), algkeysize)); 2872 } 2873 2874 2875 REQUEST_FUNC(mod_gnutls_handle_request_env) 2876 { 2877 plugin_data *p = p_d; 2878 /* simple flag for request_env_patched */ 2879 if (r->plugin_ctx[p->id]) return HANDLER_GO_ON; 2880 handler_ctx *hctx = r->con->plugin_ctx[p->id]; 2881 if (NULL == hctx) return HANDLER_GO_ON; 2882 r->plugin_ctx[p->id] = (void *)(uintptr_t)1u; 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->con->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 r->plugin_ctx[p->id] = NULL; /* simple flag for request_env_patched */ 2919 return HANDLER_GO_ON; 2920 } 2921 2922 2923 TRIGGER_FUNC(mod_gnutls_handle_trigger) { 2924 const plugin_data * const p = p_d; 2925 const time_t cur_ts = log_epoch_secs; 2926 if (cur_ts & 0x3f) return HANDLER_GO_ON; /*(continue once each 64 sec)*/ 2927 2928 mod_gnutls_session_ticket_key_check(srv, p, cur_ts); 2929 mod_gnutls_refresh_stapling_files(srv, p, cur_ts); 2930 2931 return HANDLER_GO_ON; 2932 } 2933 2934 2935 int mod_gnutls_plugin_init (plugin *p); 2936 int mod_gnutls_plugin_init (plugin *p) 2937 { 2938 p->version = LIGHTTPD_VERSION_ID; 2939 p->name = "gnutls"; 2940 p->init = mod_gnutls_init; 2941 p->cleanup = mod_gnutls_free; 2942 p->priv_defaults= mod_gnutls_set_defaults; 2943 2944 p->handle_connection_accept = mod_gnutls_handle_con_accept; 2945 p->handle_connection_shut_wr = mod_gnutls_handle_con_shut_wr; 2946 p->handle_connection_close = mod_gnutls_handle_con_close; 2947 p->handle_uri_raw = mod_gnutls_handle_uri_raw; 2948 p->handle_request_env = mod_gnutls_handle_request_env; 2949 p->handle_request_reset = mod_gnutls_handle_request_reset; 2950 p->handle_trigger = mod_gnutls_handle_trigger; 2951 2952 return 0; 2953 } 2954 2955 2956 /* cipher suites 2957 * 2958 * (extremely coarse (and very possibly incorrect) mapping to openssl labels) 2959 */ 2960 2961 /* TLSv1.3 cipher list (supported in gnutls) */ 2962 static const char suite_TLSv13[] = 2963 "+CHACHA20-POLY1305:" 2964 "+AES-256-GCM:" 2965 "+AES-256-CCM:" 2966 "+AES-256-CCM-8:" 2967 "+AES-128-GCM:" 2968 "+AES-128-CCM:" 2969 "+AES-128-CCM-8:" 2970 ; 2971 2972 /* TLSv1.2 cipher list (supported in gnutls) */ 2973 static const char suite_TLSv12[] = 2974 "+CHACHA20-POLY1305:" 2975 "+AES-256-GCM:" 2976 "+AES-256-CCM:" 2977 "+AES-256-CBC:" 2978 "+AES-256-CCM-8:" 2979 "+CAMELLIA-256-GCM:" 2980 "+CAMELLIA-256-CBC:" 2981 "+AES-128-GCM:" 2982 "+AES-128-CCM:" 2983 "+AES-128-CBC:" 2984 "+AES-128-CCM-8:" 2985 "+CAMELLIA-128-GCM:" 2986 "+CAMELLIA-128-CBC:" 2987 ; 2988 2989 /* TLSv1.0 cipher list (supported in gnutls) */ 2990 /* XXX: intentionally not including overlapping eNULL ciphers */ 2991 static const char suite_TLSv10[] = 2992 "+AES-256-CBC:" 2993 "+AES-128-CBC:" 2994 "+CAMELLIA-256-CBC:" 2995 "+CAMELLIA-128-CBC:" 2996 ; 2997 2998 /* SSLv3 cipher list (supported in gnutls) */ 2999 /* XXX: intentionally not including overlapping eNULL ciphers */ 3000 static const char suite_SSLv3[] = 3001 "+AES-256-CBC:" 3002 "+AES-128-CBC:" 3003 "+CAMELLIA-256-CBC:" 3004 "+CAMELLIA-128-CBC:" 3005 "+3DES-CBC:" 3006 "+DES-CBC:" 3007 ; 3008 3009 /* HIGH cipher list (mapped from openssl list to gnutls) */ 3010 static const char suite_HIGH[] = 3011 "+CHACHA20-POLY1305:" 3012 "+AES-256-GCM:" 3013 "+AES-256-CCM:" 3014 "+AES-256-CBC:" 3015 "+AES-256-CCM-8:" 3016 "+CAMELLIA-256-CBC:" 3017 "+AES-128-GCM:" 3018 "+AES-128-CCM:" 3019 "+AES-128-CBC:" 3020 "+AES-128-CCM-8:" 3021 "+CAMELLIA-128-CBC:" 3022 ; 3023 3024 3025 static int 3026 mod_gnutls_ssl_conf_ciphersuites (server *srv, plugin_config_socket *s, buffer *ciphersuites, const buffer *cipherstring) 3027 { 3028 /* reference: https://www.openssl.org/docs/man1.1.1/man1/ciphers.html 3029 * Attempt to parse *some* keywords from Ciphersuites and CipherString 3030 * !!! openssl uses a *different* naming scheme than does GnuTLS !!! 3031 * Ciphersuites in openssl takes only TLSv1.3 suites. 3032 * Note that CipherString does allow cipher suites to be listed, 3033 * and this code does not currently attempt to provide mapping */ 3034 3035 buffer * const plist = &s->priority_str; 3036 char n[128]; /*(most ciphersuite names are about 40 chars)*/ 3037 3038 if (ciphersuites) { 3039 buffer *b = ciphersuites; 3040 buffer_to_upper(b); /*(ciphersuites are all uppercase (currently))*/ 3041 for (const char *p, *e = b->ptr-1; e && (e = strchr((p = e+1),':')); ) { 3042 size_t len = e ? (size_t)(e - p) : strlen(p); 3043 3044 if (buffer_eq_icase_ss(p, len, 3045 CONST_STR_LEN("TLS_CHACHA20_POLY1305_SHA256"))) 3046 buffer_append_string_len(plist, 3047 CONST_STR_LEN("+CHACHA20-POLY1305:")); 3048 else if (buffer_eq_icase_ss(p, len, 3049 CONST_STR_LEN("TLS_AES_256_GCM_SHA384"))) 3050 buffer_append_string_len(plist, 3051 CONST_STR_LEN("+AES-256-GCM:")); 3052 else if (buffer_eq_icase_ss(p, len, 3053 CONST_STR_LEN("TLS_AES_128_GCM_SHA256"))) 3054 buffer_append_string_len(plist, 3055 CONST_STR_LEN("+AES-128-GCM:")); 3056 else if (buffer_eq_icase_ss(p, len, 3057 CONST_STR_LEN("TLS_AES_128_CCM_SHA256"))) 3058 buffer_append_string_len(plist, 3059 CONST_STR_LEN("+AES-128-CCM:")); 3060 else if (buffer_eq_icase_ss(p, len, 3061 CONST_STR_LEN("TLS_AES_128_CCM_8_SHA256"))) 3062 buffer_append_string_len(plist, 3063 CONST_STR_LEN("+AES-128-CCM-8:")); 3064 else 3065 log_error(srv->errh, __FILE__, __LINE__, 3066 "GnuTLS: skipped ciphersuite; not recognized: %.*s", 3067 (int)len, p); 3068 } 3069 } 3070 3071 /* XXX: openssl config for CipherString=... is excessively complex. 3072 * If there is a need to enable specific ciphersuites, then that 3073 * can be accomplished with mod_gnutls by specifying the list in 3074 * Ciphersuites=... in the ssl.openssl.ssl-conf-cmd directive. 3075 * 3076 * The tokens parsed here are a quick attempt to handle a few cases 3077 * 3078 * XXX: not done: could make a list of ciphers with bitflag of attributes 3079 * to make future combining easier */ 3080 if (cipherstring) { 3081 const buffer *b = cipherstring; 3082 const char *e = b->ptr; 3083 3084 /* XXX: not done: no checking for duplication of ciphersuites 3085 * even if tokens overlap or are repeated */ 3086 3087 /* XXX: not done: might walk string and build up exclude list of !xxxxx 3088 * ciphersuites and walk string again, excluding as result list built */ 3089 3090 /* manually handle first token, since one-offs apply */ 3091 /* (openssl syntax NOT fully supported) */ 3092 if (0 == strncmp(e, "!ALL", 4) || 0 == strncmp(e, "-ALL", 4)) { 3093 /* "!ALL" excluding all ciphers is empty list */ 3094 e += sizeof("!ALL")-1; /* same as sizeof("-ALL")-1 */ 3095 buffer_append_string_len(plist, CONST_STR_LEN("-CIPHER-ALL:")); 3096 } 3097 else if (0 == strncmp(e, CONST_STR_LEN("!DEFAULT")) 3098 || 0 == strncmp(e, CONST_STR_LEN("-DEFAULT"))) { 3099 /* "!DEFAULT" excluding default ciphers is empty list */ 3100 e += sizeof("!DEFAULT")-1; /* same as sizeof("-DEFAULT")-1 */ 3101 buffer_append_string_len(plist, CONST_STR_LEN("-CIPHER-ALL:")); 3102 } 3103 else if (0 == strncmp(e, CONST_STR_LEN("DEFAULT"))) { 3104 e += sizeof("DEFAULT")-1; 3105 s->priority_base = "NORMAL"; 3106 } 3107 else if (0 == /* effectively the same as "DEFAULT" */ 3108 strncmp(e, CONST_STR_LEN("ALL:!COMPLEMENTOFDEFAULT:!eNULL"))) { 3109 e += sizeof("ALL:!COMPLEMENTOFDEFAULT:!eNULL")-1; 3110 s->priority_base = "NORMAL"; 3111 } 3112 else if (0 == strncmp(e, CONST_STR_LEN("SUITEB128")) 3113 || 0 == strncmp(e, CONST_STR_LEN("SUITEB128ONLY")) 3114 || 0 == strncmp(e, CONST_STR_LEN("SUITEB192"))) { 3115 s->priority_base = (0 == strncmp(e, CONST_STR_LEN("SUITEB192"))) 3116 ? "SUITEB192" 3117 : "SUITEB128"; 3118 e += (0 == strncmp(e, CONST_STR_LEN("SUITEB128ONLY"))) 3119 ? sizeof("SUITEB128ONLY")-1 3120 : sizeof("SUITEB128")-1; 3121 if (*e) 3122 log_error(srv->errh, __FILE__, __LINE__, 3123 "GnuTLS: ignoring cipher string after SUITEB: %s", e); 3124 return 1; 3125 } 3126 3127 if (e != b->ptr && *e != ':' && *e != '\0') { 3128 log_error(srv->errh, __FILE__, __LINE__, 3129 "GnuTLS: error: missing support for cipher list: %s", b->ptr); 3130 return 0; 3131 } 3132 3133 /* not handled: "ALL" is "DEFAULT" and "RC4" */ 3134 /* not handled: "COMPLEMENTOFALL" is "eNULL" */ 3135 3136 int rc = 1; 3137 if (e == b->ptr || *e == '\0') --e; /*initial condition for loop below*/ 3138 for (const char *p; e && (e = strchr((p = e+1),':')); ) { 3139 size_t len = e ? (size_t)(e - p) : strlen(p); 3140 if (len >= sizeof(n)) { 3141 log_error(srv->errh, __FILE__, __LINE__, 3142 "GnuTLS: skipped ciphersuite; too long: %.*s", 3143 (int)len, p); 3144 continue; 3145 } 3146 char c = (*p == '!' || *p == '-' || *p == '+') ? *p : 0; 3147 size_t nlen = c ? len-1 : len; 3148 memcpy(n, c ? p+1 : p, nlen); 3149 n[nlen] = '\0'; 3150 3151 /* not handled: !xxxxx -xxxxx and most +xxxxx */ 3152 if (c) { 3153 log_error(srv->errh, __FILE__, __LINE__, 3154 "GnuTLS: error: missing support for cipher list: %s", b->ptr); 3155 } 3156 3157 /* ignore @STRENGTH sorting and ignore @SECLEVEL=n */ 3158 char *a = strchr(n, '@'); 3159 if (a) { 3160 log_error(srv->errh, __FILE__, __LINE__, 3161 "GnuTLS: ignored %s in %.*s", a, (int)len, p); 3162 *a = '\0'; 3163 nlen = (size_t)(a - n); 3164 } 3165 3166 if (buffer_eq_icase_ss(n, nlen, CONST_STR_LEN("TLSv1.3"))) { 3167 buffer_append_string_len(plist, 3168 CONST_STR_LEN(suite_TLSv13)); 3169 continue; 3170 } 3171 3172 if (buffer_eq_icase_ss(n, nlen, CONST_STR_LEN("TLSv1.2"))) { 3173 buffer_append_string_len(plist, 3174 CONST_STR_LEN(suite_TLSv12)); 3175 continue; 3176 } 3177 3178 if (buffer_eq_icase_ss(n, nlen, CONST_STR_LEN("TLSv1.0"))) { 3179 buffer_append_string_len(plist, 3180 CONST_STR_LEN(suite_TLSv10)); 3181 continue; 3182 } 3183 3184 if (buffer_eq_icase_ss(n, nlen, CONST_STR_LEN("SSLv3"))) { 3185 buffer_append_string_len(plist, 3186 CONST_STR_LEN(suite_SSLv3)); 3187 continue; 3188 } 3189 3190 /* handle a popular recommendations 3191 * ssl.cipher-list = "EECDH+AESGCM:EDH+AESGCM" 3192 * ssl.cipher-list = "AES256+EECDH:AES256+EDH" 3193 * which uses AES hardware acceleration built into popular CPUs */ 3194 if (buffer_eq_icase_ss(n, nlen, CONST_STR_LEN("ECDHE+AESGCM")) 3195 || buffer_eq_icase_ss(n, nlen, CONST_STR_LEN("EECDH+AESGCM"))) { 3196 buffer_append_string_len(plist, 3197 CONST_STR_LEN("+AES-256-GCM:+AES-128-GCM:")); 3198 continue; 3199 } 3200 if (buffer_eq_icase_ss(n, nlen, CONST_STR_LEN("DHE+AESGCM")) 3201 || buffer_eq_icase_ss(n, nlen, CONST_STR_LEN("EDH+AESGCM"))) { 3202 buffer_append_string_len(plist, 3203 CONST_STR_LEN("+AES-256-GCM:+AES-128-GCM:")); 3204 continue; 3205 } 3206 if (buffer_eq_icase_ss(n, nlen, CONST_STR_LEN("AES256+EECDH"))) { 3207 buffer_append_string_len(plist, 3208 CONST_STR_LEN("+AES-256-GCM:+AES-256-CCM:+AES-256-CBC:+AES-256-CCM-8:")); 3209 continue; 3210 } 3211 if (buffer_eq_icase_ss(n, nlen, CONST_STR_LEN("AES256+EDH"))) { 3212 buffer_append_string_len(plist, 3213 CONST_STR_LEN("+AES-256-GCM:+AES-256-CCM:+AES-256-CBC:+AES-256-CCM-8:")); 3214 continue; 3215 } 3216 3217 if (buffer_eq_icase_ss(n, nlen, CONST_STR_LEN("HIGH"))) { 3218 buffer_append_string_len(plist, 3219 CONST_STR_LEN(suite_HIGH)); 3220 continue; 3221 } 3222 3223 if (buffer_eq_icase_ss(n, nlen, CONST_STR_LEN("AES256")) 3224 || buffer_eq_icase_ss(n, nlen, CONST_STR_LEN("AES"))) { 3225 buffer_append_string_len(plist, 3226 CONST_STR_LEN("+AES-256-GCM:+AES-256-CCM:+AES-256-CBC:+AES-256-CCM-8:")); 3227 if (nlen == sizeof("AES256")-1) continue; 3228 } 3229 3230 if (buffer_eq_icase_ss(n, nlen, CONST_STR_LEN("AES128")) 3231 || buffer_eq_icase_ss(n, nlen, CONST_STR_LEN("AES"))) { 3232 buffer_append_string_len(plist, 3233 CONST_STR_LEN("+AES-128-GCM:+AES-128-CCM:+AES-128-CBC:+AES-128-CCM-8:")); 3234 continue; 3235 } 3236 3237 if (buffer_eq_icase_ss(n, nlen, CONST_STR_LEN("CAMELLIA256")) 3238 || buffer_eq_icase_ss(n, nlen, CONST_STR_LEN("CAMELLIA"))) { 3239 buffer_append_string_len(plist, 3240 CONST_STR_LEN("+CAMELLIA-256-GCM:+CAMELLIA-256-CBC:")); 3241 if (nlen == sizeof("CAMELLIA256")-1) continue; 3242 } 3243 3244 if (buffer_eq_icase_ss(n, nlen, CONST_STR_LEN("CAMELLIA128")) 3245 || buffer_eq_icase_ss(n, nlen, CONST_STR_LEN("CAMELLIA"))) { 3246 buffer_append_string_len(plist, 3247 CONST_STR_LEN("+CAMELLIA-128-GCM:+CAMELLIA-128-CBC:")); 3248 continue; 3249 } 3250 3251 if (buffer_eq_icase_ss(n, nlen, CONST_STR_LEN("CHACHA20"))) { 3252 buffer_append_string_len(plist, 3253 CONST_STR_LEN("+CHACHA20-POLY1305:")); 3254 continue; 3255 } 3256 3257 if (buffer_eq_icase_ss(n, nlen, CONST_STR_LEN("3DES"))) { 3258 buffer_append_string_len(plist, 3259 CONST_STR_LEN("+3DES-CBC:")); 3260 continue; 3261 } 3262 3263 /* not recommended, but permitted if explicitly requested */ 3264 if (buffer_eq_icase_ss(n, nlen, CONST_STR_LEN("NULL")) 3265 || buffer_eq_icase_ss(n, nlen, CONST_STR_LEN("eNULL"))) { 3266 buffer_append_string_len(plist, 3267 CONST_STR_LEN("+NULL:")); 3268 continue; 3269 } 3270 3271 if (*e != ':' && *e != '\0') { 3272 log_error(srv->errh, __FILE__, __LINE__, 3273 "GnuTLS: error: missing support for cipher list: %.*s", 3274 (int)len, p); 3275 rc = 0; 3276 continue; 3277 } 3278 } 3279 if (0 == rc) return 0; 3280 } 3281 3282 return 1; 3283 } 3284 3285 3286 static int 3287 mod_gnutls_ssl_conf_curves(server *srv, plugin_config_socket *s, const buffer *curvelist) 3288 { 3289 /* map NIST name (e.g. P-256) or OpenSSL OID name (e.g. prime256v1) 3290 * to GnuTLS name of supported curves/groups */ 3291 static const char *names[] = { 3292 "P-192", "CURVE-SECP192R1", 3293 "P-224", "CURVE-SECP224R1", 3294 "P-256", "GROUP-SECP256R1", /* CURVE-SECP256R1 */ 3295 "P-384", "GROUP-SECP384R1", /* CURVE-SECP384R1 */ 3296 "P-521", "GROUP-SECP521R1", /* CURVE-SECP521R1 */ 3297 "X25519", "GROUP-X25519", /* CURVE-X25519 */ 3298 "X448", "GROUP-X448", /* CURVE-X448 */ 3299 "prime192v1", "CURVE-SECP192R1", 3300 "secp224r1", "CURVE-SECP224R1", 3301 "prime256v1", "GROUP-SECP256R1", /* CURVE-SECP256R1 */ 3302 "secp384r1", "GROUP-SECP384R1", /* CURVE-SECP384R1 */ 3303 "secp521r1", "GROUP-SECP521R1", /* CURVE-SECP521R1 */ 3304 "ffdhe2048", "GROUP-FFDHE2048", 3305 "ffdhe3072", "GROUP-FFDHE3072", 3306 "ffdhe4096", "GROUP-FFDHE4096", 3307 "ffdhe6144", "GROUP-FFDHE6144", 3308 "ffdhe8192", "GROUP-FFDHE8192", 3309 }; 3310 3311 buffer * const plist = &s->priority_str; 3312 const buffer * const b = curvelist; 3313 for (const char *n, *e = b->ptr-1; e && (e = strchr((n = e+1),':')); ) { 3314 size_t len = e ? (size_t)(e - n) : strlen(n); 3315 uint32_t i; 3316 for (i = 0; i < sizeof(names)/sizeof(*names)/2; i += 2) { 3317 if (0 == strncmp(names[i], n, len) && names[i][len] == '\0') 3318 break; 3319 } 3320 if (i == sizeof(names)/sizeof(*names)/2) { 3321 log_error(srv->errh, __FILE__, __LINE__, 3322 "GnuTLS: unrecognized curve: %.*s; ignored", (int)len, n); 3323 continue; 3324 } 3325 3326 buffer_append_string_len(plist, CONST_STR_LEN("+")); 3327 buffer_append_string_len(plist, names[i+1], strlen(names[i+1])); 3328 buffer_append_string_len(plist, CONST_STR_LEN(":")); 3329 } 3330 3331 return 1; 3332 } 3333 3334 3335 static int 3336 mod_gnutls_ssl_conf_proto_val (server *srv, plugin_config_socket *s, const buffer *b, int max) 3337 { 3338 if (NULL == b) /* default: min TLSv1.2, max TLSv1.3 */ 3339 return max ? GNUTLS_TLS1_3 : GNUTLS_TLS1_2; 3340 else if (buffer_eq_icase_slen(b, CONST_STR_LEN("None"))) /*"disable" limit*/ 3341 return max 3342 ? GNUTLS_TLS1_3 3343 : (s->ssl_use_sslv3 ? GNUTLS_SSL3 : GNUTLS_TLS1_0); 3344 else if (buffer_eq_icase_slen(b, CONST_STR_LEN("SSLv3"))) 3345 return GNUTLS_SSL3; 3346 else if (buffer_eq_icase_slen(b, CONST_STR_LEN("TLSv1.0"))) 3347 return GNUTLS_TLS1_0; 3348 else if (buffer_eq_icase_slen(b, CONST_STR_LEN("TLSv1.1"))) 3349 return GNUTLS_TLS1_1; 3350 else if (buffer_eq_icase_slen(b, CONST_STR_LEN("TLSv1.2"))) 3351 return GNUTLS_TLS1_2; 3352 else if (buffer_eq_icase_slen(b, CONST_STR_LEN("TLSv1.3"))) 3353 return GNUTLS_TLS1_3; 3354 else { 3355 if (buffer_eq_icase_slen(b, CONST_STR_LEN("DTLSv1")) 3356 || buffer_eq_icase_slen(b, CONST_STR_LEN("DTLSv1.2"))) 3357 log_error(srv->errh, __FILE__, __LINE__, 3358 "GnuTLS: ssl.openssl.ssl-conf-cmd %s %s ignored", 3359 max ? "MaxProtocol" : "MinProtocol", b->ptr); 3360 else 3361 log_error(srv->errh, __FILE__, __LINE__, 3362 "GnuTLS: ssl.openssl.ssl-conf-cmd %s %s invalid; ignored", 3363 max ? "MaxProtocol" : "MinProtocol", b->ptr); 3364 } 3365 return max ? GNUTLS_TLS1_3 : GNUTLS_TLS1_2; 3366 } 3367 3368 3369 static void 3370 mod_gnutls_ssl_conf_proto (server *srv, plugin_config_socket *s, const buffer *minb, const buffer *maxb) 3371 { 3372 /* use of SSL v3 should be avoided, and SSL v2 is not supported */ 3373 int n = mod_gnutls_ssl_conf_proto_val(srv, s, minb, 0); 3374 int x = mod_gnutls_ssl_conf_proto_val(srv, s, maxb, 1); 3375 if (n < 0) return; 3376 if (x < 0) return; 3377 buffer * const b = &s->priority_str; 3378 buffer_append_string_len(b, CONST_STR_LEN("-VERS-ALL:")); 3379 switch (n) { 3380 case GNUTLS_SSL3: 3381 buffer_append_string_len(b, CONST_STR_LEN("+VERS-SSL3.0:")); 3382 __attribute_fallthrough__ 3383 case GNUTLS_TLS1_0: 3384 if (x < GNUTLS_TLS1_0) break; 3385 buffer_append_string_len(b, CONST_STR_LEN("+VERS-TLS1.0:")); 3386 __attribute_fallthrough__ 3387 case GNUTLS_TLS1_1: 3388 if (x < GNUTLS_TLS1_1) break; 3389 buffer_append_string_len(b, CONST_STR_LEN("+VERS-TLS1.1:")); 3390 __attribute_fallthrough__ 3391 case GNUTLS_TLS1_2: 3392 if (x < GNUTLS_TLS1_2) break; 3393 buffer_append_string_len(b, CONST_STR_LEN("+VERS-TLS1.2:")); 3394 __attribute_fallthrough__ 3395 case GNUTLS_TLS1_3: 3396 if (x < GNUTLS_TLS1_3) break; 3397 buffer_append_string_len(b, CONST_STR_LEN("+VERS-TLS1.3:")); 3398 break; 3399 } 3400 } 3401