1 2 /* 3 * Copyright (C) Igor Sysoev 4 * Copyright (C) NGINX, Inc. 5 */ 6 7 #include <nxt_main.h> 8 #include <gnutls/gnutls.h> 9 10 11 typedef struct { 12 gnutls_session_t session; 13 14 uint8_t times; /* 2 bits */ 15 uint8_t no_shutdown; /* 1 bit */ 16 17 nxt_buf_mem_t buffer; 18 } nxt_gnutls_conn_t; 19 20 21 typedef struct { 22 gnutls_priority_t ciphers; 23 gnutls_certificate_credentials_t certificate; 24 } nxt_gnutls_ctx_t; 25 26 27 28 #if (NXT_HAVE_GNUTLS_SET_TIME) 29 time_t nxt_gnutls_time(time_t *tp); 30 #endif 31 static nxt_int_t nxt_gnutls_server_init(nxt_ssltls_conf_t *conf); 32 static nxt_int_t nxt_gnutls_set_ciphers(nxt_ssltls_conf_t *conf); 33 34 static void nxt_gnutls_conn_init(nxt_thread_t *thr, nxt_ssltls_conf_t *conf, 35 nxt_event_conn_t *c); 36 static void nxt_gnutls_session_cleanup(void *data); 37 static ssize_t nxt_gnutls_pull(gnutls_transport_ptr_t data, void *buf, 38 size_t size); 39 static ssize_t nxt_gnutls_push(gnutls_transport_ptr_t data, const void *buf, 40 size_t size); 41 #if (NXT_HAVE_GNUTLS_VEC_PUSH) 42 static ssize_t nxt_gnutls_vec_push(gnutls_transport_ptr_t data, 43 const giovec_t *iov, int iovcnt); 44 #endif 45 static void nxt_gnutls_conn_handshake(nxt_thread_t *thr, void *obj, void *data); 46 static void nxt_gnutls_conn_io_read(nxt_thread_t *thr, void *obj, void *data); 47 static ssize_t nxt_gnutls_conn_io_write_chunk(nxt_thread_t *thr, 48 nxt_event_conn_t *c, nxt_buf_t *b, size_t limit); 49 static ssize_t nxt_gnutls_conn_io_send(nxt_event_conn_t *c, void *buf, 50 size_t size); 51 static void nxt_gnutls_conn_io_shutdown(nxt_thread_t *thr, void *obj, 52 void *data); 53 static nxt_int_t nxt_gnutls_conn_test_error(nxt_thread_t *thr, 54 nxt_event_conn_t *c, ssize_t err, nxt_work_handler_t handler); 55 static void nxt_cdecl nxt_gnutls_conn_log_error(nxt_event_conn_t *c, 56 ssize_t err, const char *fmt, ...); 57 static nxt_uint_t nxt_gnutls_log_error_level(nxt_event_conn_t *c, ssize_t err); 58 static void nxt_cdecl nxt_gnutls_log_error(nxt_uint_t level, nxt_log_t *log, 59 int err, const char *fmt, ...); 60 61 62 const nxt_ssltls_lib_t nxt_gnutls_lib = { 63 nxt_gnutls_server_init, 64 NULL, 65 }; 66 67 68 static nxt_event_conn_io_t nxt_gnutls_event_conn_io = { 69 NULL, 70 NULL, 71 72 nxt_gnutls_conn_io_read, 73 NULL, 74 NULL, 75 76 nxt_event_conn_io_write, 77 nxt_gnutls_conn_io_write_chunk, 78 NULL, 79 NULL, 80 nxt_gnutls_conn_io_send, 81 82 nxt_gnutls_conn_io_shutdown, 83 }; 84 85 86 static nxt_int_t 87 nxt_gnutls_start(void) 88 { 89 int ret; 90 static nxt_bool_t started; 91 92 if (nxt_fast_path(started)) { 93 return NXT_OK; 94 } 95 96 started = 1; 97 98 /* TODO: gnutls_global_deinit */ 99 100 ret = gnutls_global_init(); 101 if (ret != GNUTLS_E_SUCCESS) { 102 nxt_gnutls_log_error(NXT_LOG_ALERT, nxt_thread_log(), ret, 103 "gnutls_global_init() failed"); 104 return NXT_ERROR; 105 } 106 107 nxt_thread_log_error(NXT_LOG_INFO, "GnuTLS version: %s", 108 gnutls_check_version(NULL)); 109 110 #if (NXT_HAVE_GNUTLS_SET_TIME) 111 gnutls_global_set_time_function(nxt_gnutls_time); 112 #endif 113 114 return NXT_OK; 115 } 116 117 118 #if (NXT_HAVE_GNUTLS_SET_TIME) 119 120 /* GnuTLS 2.12.0 */ 121 122 time_t 123 nxt_gnutls_time(time_t *tp) 124 { 125 time_t t; 126 nxt_thread_t *thr; 127 128 thr = nxt_thread(); 129 nxt_log_debug(thr->log, "gnutls time"); 130 131 t = (time_t) nxt_thread_time(thr); 132 133 if (tp != NULL) { 134 *tp = t; 135 } 136 137 return t; 138 } 139 140 #endif 141 142 143 static nxt_int_t 144 nxt_gnutls_server_init(nxt_ssltls_conf_t *conf) 145 { 146 int ret; 147 char *certificate, *key, *ca_certificate; 148 nxt_thread_t *thr; 149 nxt_gnutls_ctx_t *ctx; 150 151 if (nxt_slow_path(nxt_gnutls_start() != NXT_OK)) { 152 return NXT_ERROR; 153 } 154 155 /* TODO: mem_pool, cleanup: gnutls_certificate_free_credentials, 156 gnutls_priority_deinit */ 157 158 ctx = nxt_zalloc(sizeof(nxt_gnutls_ctx_t)); 159 if (ctx == NULL) { 160 return NXT_ERROR; 161 } 162 163 conf->ctx = ctx; 164 conf->conn_init = nxt_gnutls_conn_init; 165 166 thr = nxt_thread(); 167 168 ret = gnutls_certificate_allocate_credentials(&ctx->certificate); 169 if (ret != GNUTLS_E_SUCCESS) { 170 nxt_gnutls_log_error(NXT_LOG_ALERT, thr->log, ret, 171 "gnutls_certificate_allocate_credentials() failed"); 172 return NXT_ERROR; 173 } 174 175 certificate = conf->certificate; 176 key = conf->certificate_key; 177 178 ret = gnutls_certificate_set_x509_key_file(ctx->certificate, certificate, 179 key, GNUTLS_X509_FMT_PEM); 180 if (ret != GNUTLS_E_SUCCESS) { 181 nxt_gnutls_log_error(NXT_LOG_ALERT, thr->log, ret, 182 "gnutls_certificate_set_x509_key_file(\"%s\", \"%s\") failed", 183 certificate, key); 184 goto certificate_fail; 185 } 186 187 if (nxt_gnutls_set_ciphers(conf) != NXT_OK) { 188 goto ciphers_fail; 189 } 190 191 if (conf->ca_certificate != NULL) { 192 ca_certificate = conf->ca_certificate; 193 194 ret = gnutls_certificate_set_x509_trust_file(ctx->certificate, 195 ca_certificate, 196 GNUTLS_X509_FMT_PEM); 197 if (ret < 0) { 198 nxt_gnutls_log_error(NXT_LOG_ALERT, thr->log, ret, 199 "gnutls_certificate_set_x509_trust_file(\"%s\") failed", 200 ca_certificate); 201 goto ca_certificate_fail; 202 } 203 } 204 205 return NXT_OK; 206 207 ca_certificate_fail: 208 209 gnutls_priority_deinit(ctx->ciphers); 210 211 ciphers_fail: 212 213 certificate_fail: 214 215 gnutls_certificate_free_credentials(ctx->certificate); 216 217 return NXT_ERROR; 218 } 219 220 221 static nxt_int_t 222 nxt_gnutls_set_ciphers(nxt_ssltls_conf_t *conf) 223 { 224 int ret; 225 const char *ciphers; 226 const char *err; 227 nxt_gnutls_ctx_t *ctx; 228 229 ciphers = (conf->ciphers != NULL) ? conf->ciphers : "NORMAL:!COMP-DEFLATE"; 230 ctx = conf->ctx; 231 232 ret = gnutls_priority_init(&ctx->ciphers, ciphers, &err); 233 234 switch (ret) { 235 236 case GNUTLS_E_SUCCESS: 237 return NXT_OK; 238 239 case GNUTLS_E_INVALID_REQUEST: 240 nxt_gnutls_log_error(NXT_LOG_ALERT, nxt_thread_log(), ret, 241 "gnutls_priority_init(\"%s\") failed at \"%s\"", 242 ciphers, err); 243 return NXT_ERROR; 244 245 default: 246 nxt_gnutls_log_error(NXT_LOG_ALERT, nxt_thread_log(), ret, 247 "gnutls_priority_init() failed"); 248 return NXT_ERROR; 249 } 250 } 251 252 253 static void 254 nxt_gnutls_conn_init(nxt_thread_t *thr, nxt_ssltls_conf_t *conf, 255 nxt_event_conn_t *c) 256 { 257 int ret; 258 gnutls_session_t sess; 259 nxt_gnutls_ctx_t *ctx; 260 nxt_gnutls_conn_t *ssltls; 261 nxt_mem_pool_cleanup_t *mpcl; 262 263 nxt_log_debug(c->socket.log, "gnutls conn init"); 264 265 ssltls = nxt_mp_zget(c->mem_pool, sizeof(nxt_gnutls_conn_t)); 266 if (ssltls == NULL) { 267 goto fail; 268 } 269 270 c->u.ssltls = ssltls; 271 nxt_buf_mem_set_size(&ssltls->buffer, conf->buffer_size); 272 273 mpcl = nxt_mem_pool_cleanup(c->mem_pool, 0); 274 if (mpcl == NULL) { 275 goto fail; 276 } 277 278 ret = gnutls_init(&ssltls->session, GNUTLS_SERVER); 279 if (ret != GNUTLS_E_SUCCESS) { 280 nxt_gnutls_log_error(NXT_LOG_ALERT, c->socket.log, ret, 281 "gnutls_init() failed"); 282 goto fail; 283 } 284 285 sess = ssltls->session; 286 mpcl->handler = nxt_gnutls_session_cleanup; 287 mpcl->data = ssltls; 288 289 ctx = conf->ctx; 290 291 ret = gnutls_priority_set(sess, ctx->ciphers); 292 if (ret != GNUTLS_E_SUCCESS) { 293 nxt_gnutls_log_error(NXT_LOG_ALERT, c->socket.log, ret, 294 "gnutls_priority_set() failed"); 295 goto fail; 296 } 297 298 /* 299 * Disable TLS random padding of records in CBC ciphers, 300 * which may be up to 255 bytes. 301 */ 302 gnutls_record_disable_padding(sess); 303 304 ret = gnutls_credentials_set(sess, GNUTLS_CRD_CERTIFICATE, 305 ctx->certificate); 306 if (ret != GNUTLS_E_SUCCESS) { 307 nxt_gnutls_log_error(NXT_LOG_ALERT, c->socket.log, ret, 308 "gnutls_credentials_set() failed"); 309 goto fail; 310 } 311 312 if (conf->ca_certificate != NULL) { 313 gnutls_certificate_server_set_request(sess, GNUTLS_CERT_REQUEST); 314 } 315 316 gnutls_transport_set_ptr(sess, (gnutls_transport_ptr_t) c); 317 gnutls_transport_set_pull_function(sess, nxt_gnutls_pull); 318 gnutls_transport_set_push_function(sess, nxt_gnutls_push); 319 #if (NXT_HAVE_GNUTLS_VEC_PUSH) 320 gnutls_transport_set_vec_push_function(sess, nxt_gnutls_vec_push); 321 #endif 322 323 c->io = &nxt_gnutls_event_conn_io; 324 c->sendfile = NXT_CONN_SENDFILE_OFF; 325 326 nxt_gnutls_conn_handshake(thr, c, c->socket.data); 327 return; 328 329 fail: 330 331 nxt_event_conn_io_handle(thr, c->read_work_queue, 332 c->read_state->error_handler, c, c->socket.data); 333 } 334 335 336 static void 337 nxt_gnutls_session_cleanup(void *data) 338 { 339 nxt_gnutls_conn_t *ssltls; 340 341 ssltls = data; 342 343 nxt_thread_log_debug("gnutls session cleanup"); 344 345 nxt_free(ssltls->buffer.start); 346 347 gnutls_deinit(ssltls->session); 348 } 349 350 351 static ssize_t 352 nxt_gnutls_pull(gnutls_transport_ptr_t data, void *buf, size_t size) 353 { 354 ssize_t n; 355 nxt_thread_t *thr; 356 nxt_event_conn_t *c; 357 358 c = data; 359 thr = nxt_thread(); 360 361 n = thr->engine->event->io->recv(c, buf, size, 0); 362 363 if (n == NXT_AGAIN) { 364 nxt_set_errno(NXT_EAGAIN); 365 return -1; 366 } 367 368 return n; 369 } 370 371 372 static ssize_t 373 nxt_gnutls_push(gnutls_transport_ptr_t data, const void *buf, size_t size) 374 { 375 ssize_t n; 376 nxt_thread_t *thr; 377 nxt_event_conn_t *c; 378 379 c = data; 380 thr = nxt_thread(); 381 382 n = thr->engine->event->io->send(c, (u_char *) buf, size); 383 384 if (n == NXT_AGAIN) { 385 nxt_set_errno(NXT_EAGAIN); 386 return -1; 387 } 388 389 return n; 390 } 391 392 393 #if (NXT_HAVE_GNUTLS_VEC_PUSH) 394 395 /* GnuTLS 2.12.0 */ 396 397 static ssize_t 398 nxt_gnutls_vec_push(gnutls_transport_ptr_t data, const giovec_t *iov, 399 int iovcnt) 400 { 401 ssize_t n; 402 nxt_thread_t *thr; 403 nxt_event_conn_t *c; 404 405 c = data; 406 thr = nxt_thread(); 407 408 /* 409 * This code assumes that giovec_t is the same as "struct iovec" 410 * and nxt_iobuf_t. It is not true for Windows. 411 */ 412 n = thr->engine->event->io->writev(c, (nxt_iobuf_t *) iov, iovcnt); 413 414 if (n == NXT_AGAIN) { 415 nxt_set_errno(NXT_EAGAIN); 416 return -1; 417 } 418 419 return n; 420 } 421 422 #endif 423 424 425 static void 426 nxt_gnutls_conn_handshake(nxt_thread_t *thr, void *obj, void *data) 427 { 428 int err; 429 nxt_int_t ret; 430 nxt_event_conn_t *c; 431 nxt_gnutls_conn_t *ssltls; 432 433 c = obj; 434 ssltls = c->u.ssltls; 435 436 nxt_log_debug(thr->log, "gnutls conn handshake: %d", ssltls->times); 437 438 /* "ssltls->times == 1" is suitable to run gnutls_handshake() in job. */ 439 440 err = gnutls_handshake(ssltls->session); 441 442 nxt_thread_time_debug_update(thr); 443 444 nxt_log_debug(thr->log, "gnutls_handshake(): %d", err); 445 446 if (err == GNUTLS_E_SUCCESS) { 447 nxt_gnutls_conn_io_read(thr, c, data); 448 return; 449 } 450 451 ret = nxt_gnutls_conn_test_error(thr, c, err, nxt_gnutls_conn_handshake); 452 453 if (ret == NXT_ERROR) { 454 nxt_gnutls_conn_log_error(c, err, "gnutls_handshake() failed"); 455 456 nxt_event_conn_io_handle(thr, c->read_work_queue, 457 c->read_state->error_handler, c, data); 458 459 } else if (err == GNUTLS_E_AGAIN 460 && ssltls->times < 2 461 && gnutls_record_get_direction(ssltls->session) == 0) 462 { 463 ssltls->times++; 464 } 465 } 466 467 468 static void 469 nxt_gnutls_conn_io_read(nxt_thread_t *thr, void *obj, void *data) 470 { 471 ssize_t n; 472 nxt_buf_t *b; 473 nxt_int_t ret; 474 nxt_event_conn_t *c; 475 nxt_gnutls_conn_t *ssltls; 476 nxt_work_handler_t handler; 477 478 c = obj; 479 480 nxt_log_debug(thr->log, "gnutls conn read"); 481 482 handler = c->read_state->ready_handler; 483 b = c->read; 484 485 /* b == NULL is used to test descriptor readiness. */ 486 487 if (b != NULL) { 488 ssltls = c->u.ssltls; 489 490 n = gnutls_record_recv(ssltls->session, b->mem.free, 491 b->mem.end - b->mem.free); 492 493 nxt_log_debug(thr->log, "gnutls_record_recv(%d, %p, %uz): %z", 494 c->socket.fd, b->mem.free, b->mem.end - b->mem.free, n); 495 496 if (n > 0) { 497 /* c->socket.read_ready is kept. */ 498 b->mem.free += n; 499 handler = c->read_state->ready_handler; 500 501 } else if (n == 0) { 502 handler = c->read_state->close_handler; 503 504 } else { 505 ret = nxt_gnutls_conn_test_error(thr, c, n, 506 nxt_gnutls_conn_io_read); 507 508 if (nxt_fast_path(ret != NXT_ERROR)) { 509 return; 510 } 511 512 nxt_gnutls_conn_log_error(c, n, 513 "gnutls_record_recv(%d, %p, %uz): failed", 514 c->socket.fd, b->mem.free, 515 b->mem.end - b->mem.free); 516 517 handler = c->read_state->error_handler; 518 } 519 } 520 521 nxt_event_conn_io_handle(thr, c->read_work_queue, handler, c, data); 522 } 523 524 525 static ssize_t 526 nxt_gnutls_conn_io_write_chunk(nxt_thread_t *thr, nxt_event_conn_t *c, 527 nxt_buf_t *b, size_t limit) 528 { 529 nxt_gnutls_conn_t *ssltls; 530 531 nxt_log_debug(thr->log, "gnutls conn write chunk"); 532 533 ssltls = c->u.ssltls; 534 535 return nxt_sendbuf_copy_coalesce(c, &ssltls->buffer, b, limit); 536 } 537 538 539 static ssize_t 540 nxt_gnutls_conn_io_send(nxt_event_conn_t *c, void *buf, size_t size) 541 { 542 ssize_t n; 543 nxt_int_t ret; 544 nxt_gnutls_conn_t *ssltls; 545 546 ssltls = c->u.ssltls; 547 548 n = gnutls_record_send(ssltls->session, buf, size); 549 550 nxt_log_debug(c->socket.log, "gnutls_record_send(%d, %p, %uz): %z", 551 c->socket.fd, buf, size, n); 552 553 if (n > 0) { 554 return n; 555 } 556 557 ret = nxt_gnutls_conn_test_error(nxt_thread(), c, n, 558 nxt_event_conn_io_write); 559 560 if (nxt_slow_path(ret == NXT_ERROR)) { 561 nxt_gnutls_conn_log_error(c, n, 562 "gnutls_record_send(%d, %p, %uz): failed", 563 c->socket.fd, buf, size); 564 } 565 566 return ret; 567 } 568 569 570 static void 571 nxt_gnutls_conn_io_shutdown(nxt_thread_t *thr, void *obj, void *data) 572 { 573 int err; 574 nxt_int_t ret; 575 nxt_event_conn_t *c; 576 nxt_gnutls_conn_t *ssltls; 577 nxt_work_handler_t handler; 578 gnutls_close_request_t how; 579 580 c = obj; 581 ssltls = c->u.ssltls; 582 583 if (ssltls->session == NULL || ssltls->no_shutdown) { 584 handler = c->write_state->close_handler; 585 goto done; 586 } 587 588 nxt_log_debug(c->socket.log, "gnutls conn shutdown"); 589 590 if (c->socket.timedout || c->socket.error != 0) { 591 how = GNUTLS_SHUT_WR; 592 593 } else if (c->socket.closed) { 594 how = GNUTLS_SHUT_RDWR; 595 596 } else { 597 how = GNUTLS_SHUT_RDWR; 598 } 599 600 err = gnutls_bye(ssltls->session, how); 601 602 nxt_log_debug(c->socket.log, "gnutls_bye(%d, %d): %d", 603 c->socket.fd, how, err); 604 605 if (err == GNUTLS_E_SUCCESS) { 606 handler = c->write_state->close_handler; 607 608 } else { 609 ret = nxt_gnutls_conn_test_error(thr, c, err, 610 nxt_gnutls_conn_io_shutdown); 611 612 if (ret != NXT_ERROR) { /* ret == NXT_AGAIN */ 613 c->socket.error_handler = c->read_state->error_handler; 614 nxt_event_timer_add(thr->engine, &c->read_timer, 5000); 615 return; 616 } 617 618 nxt_gnutls_conn_log_error(c, err, "gnutls_bye(%d) failed", 619 c->socket.fd); 620 621 handler = c->write_state->error_handler; 622 } 623 624 done: 625 626 nxt_event_conn_io_handle(thr, c->write_work_queue, handler, c, data); 627 } 628 629 630 static nxt_int_t 631 nxt_gnutls_conn_test_error(nxt_thread_t *thr, nxt_event_conn_t *c, ssize_t err, 632 nxt_work_handler_t handler) 633 { 634 int ret; 635 nxt_gnutls_conn_t *ssltls; 636 637 switch (err) { 638 639 case GNUTLS_E_REHANDSHAKE: 640 case GNUTLS_E_AGAIN: 641 ssltls = c->u.ssltls; 642 ret = gnutls_record_get_direction(ssltls->session); 643 644 nxt_log_debug(thr->log, "gnutls_record_get_direction(): %d", ret); 645 646 if (ret == 0) { 647 /* A read direction. */ 648 649 nxt_event_fd_block_write(thr->engine, &c->socket); 650 651 c->socket.read_ready = 0; 652 c->socket.read_handler = handler; 653 654 if (nxt_event_fd_is_disabled(c->socket.read)) { 655 nxt_event_fd_enable_read(thr->engine, &c->socket); 656 } 657 658 } else { 659 /* A write direction. */ 660 661 nxt_event_fd_block_read(thr->engine, &c->socket); 662 663 c->socket.write_ready = 0; 664 c->socket.write_handler = handler; 665 666 if (nxt_event_fd_is_disabled(c->socket.write)) { 667 nxt_event_fd_enable_write(thr->engine, &c->socket); 668 } 669 } 670 671 return NXT_AGAIN; 672 673 default: 674 c->socket.error = 1000; /* Nonexistent errno code. */ 675 return NXT_ERROR; 676 } 677 } 678 679 680 static void 681 nxt_gnutls_conn_log_error(nxt_event_conn_t *c, ssize_t err, 682 const char *fmt, ...) 683 { 684 va_list args; 685 nxt_uint_t level; 686 u_char *p, msg[NXT_MAX_ERROR_STR]; 687 688 level = nxt_gnutls_log_error_level(c, err); 689 690 if (nxt_log_level_enough(c->socket.log, level)) { 691 692 va_start(args, fmt); 693 p = nxt_vsprintf(msg, msg + sizeof(msg), fmt, args); 694 va_end(args); 695 696 nxt_log_error(level, c->socket.log, "%*s (%d: %s)", 697 p - msg, msg, err, gnutls_strerror(err)); 698 } 699 } 700 701 702 static nxt_uint_t 703 nxt_gnutls_log_error_level(nxt_event_conn_t *c, ssize_t err) 704 { 705 nxt_gnutls_conn_t *ssltls; 706 707 switch (err) { 708 709 case GNUTLS_E_UNKNOWN_CIPHER_SUITE: /* -21 */ 710 711 /* Disable gnutls_bye(), because it returns GNUTLS_E_INTERNAL_ERROR. */ 712 ssltls = c->u.ssltls; 713 ssltls->no_shutdown = 1; 714 715 /* Fall through. */ 716 717 case GNUTLS_E_UNEXPECTED_PACKET_LENGTH: /* -9 */ 718 c->socket.error = 1000; /* Nonexistent errno code. */ 719 break; 720 721 default: 722 return NXT_LOG_ALERT; 723 } 724 725 return NXT_LOG_INFO; 726 } 727 728 729 static void 730 nxt_gnutls_log_error(nxt_uint_t level, nxt_log_t *log, int err, 731 const char *fmt, ...) 732 { 733 va_list args; 734 u_char *p, msg[NXT_MAX_ERROR_STR]; 735 736 va_start(args, fmt); 737 p = nxt_vsprintf(msg, msg + sizeof(msg), fmt, args); 738 va_end(args); 739 740 nxt_log_error(level, log, "%*s (%d: %s)", 741 p - msg, msg, err, gnutls_strerror(err)); 742 } 743