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