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