Mercurial > hg > nginx
comparison src/event/ngx_event_openssl_stapling.c @ 6181:6893a1007a7c
OCSP stapling: avoid sending expired responses (ticket #425).
author | Maxim Dounin <mdounin@mdounin.ru> |
---|---|
date | Thu, 11 Jun 2015 20:42:39 +0300 |
parents | ff957cd36860 |
children | dcae651b2a0c |
comparison
equal
deleted
inserted
replaced
6180:8b6fa4842133 | 6181:6893a1007a7c |
---|---|
30 | 30 |
31 X509 *cert; | 31 X509 *cert; |
32 X509 *issuer; | 32 X509 *issuer; |
33 | 33 |
34 time_t valid; | 34 time_t valid; |
35 time_t refresh; | |
35 | 36 |
36 unsigned verify:1; | 37 unsigned verify:1; |
37 unsigned loading:1; | 38 unsigned loading:1; |
38 } ngx_ssl_stapling_t; | 39 } ngx_ssl_stapling_t; |
39 | 40 |
90 | 91 |
91 static int ngx_ssl_certificate_status_callback(ngx_ssl_conn_t *ssl_conn, | 92 static int ngx_ssl_certificate_status_callback(ngx_ssl_conn_t *ssl_conn, |
92 void *data); | 93 void *data); |
93 static void ngx_ssl_stapling_update(ngx_ssl_stapling_t *staple); | 94 static void ngx_ssl_stapling_update(ngx_ssl_stapling_t *staple); |
94 static void ngx_ssl_stapling_ocsp_handler(ngx_ssl_ocsp_ctx_t *ctx); | 95 static void ngx_ssl_stapling_ocsp_handler(ngx_ssl_ocsp_ctx_t *ctx); |
96 | |
97 static time_t ngx_ssl_stapling_time(ASN1_GENERALIZEDTIME *asn1time); | |
95 | 98 |
96 static void ngx_ssl_stapling_cleanup(void *data); | 99 static void ngx_ssl_stapling_cleanup(void *data); |
97 | 100 |
98 static ngx_ssl_ocsp_ctx_t *ngx_ssl_ocsp_start(void); | 101 static ngx_ssl_ocsp_ctx_t *ngx_ssl_ocsp_start(void); |
99 static void ngx_ssl_ocsp_done(ngx_ssl_ocsp_ctx_t *ctx); | 102 static void ngx_ssl_ocsp_done(ngx_ssl_ocsp_ctx_t *ctx); |
460 "SSL certificate status callback"); | 463 "SSL certificate status callback"); |
461 | 464 |
462 staple = data; | 465 staple = data; |
463 rc = SSL_TLSEXT_ERR_NOACK; | 466 rc = SSL_TLSEXT_ERR_NOACK; |
464 | 467 |
465 if (staple->staple.len) { | 468 if (staple->staple.len |
469 && staple->valid >= ngx_time()) | |
470 { | |
466 /* we have to copy ocsp response as OpenSSL will free it by itself */ | 471 /* we have to copy ocsp response as OpenSSL will free it by itself */ |
467 | 472 |
468 p = OPENSSL_malloc(staple->staple.len); | 473 p = OPENSSL_malloc(staple->staple.len); |
469 if (p == NULL) { | 474 if (p == NULL) { |
470 ngx_ssl_error(NGX_LOG_ALERT, c->log, 0, "OPENSSL_malloc() failed"); | 475 ngx_ssl_error(NGX_LOG_ALERT, c->log, 0, "OPENSSL_malloc() failed"); |
488 ngx_ssl_stapling_update(ngx_ssl_stapling_t *staple) | 493 ngx_ssl_stapling_update(ngx_ssl_stapling_t *staple) |
489 { | 494 { |
490 ngx_ssl_ocsp_ctx_t *ctx; | 495 ngx_ssl_ocsp_ctx_t *ctx; |
491 | 496 |
492 if (staple->host.len == 0 | 497 if (staple->host.len == 0 |
493 || staple->loading || staple->valid >= ngx_time()) | 498 || staple->loading || staple->refresh >= ngx_time()) |
494 { | 499 { |
495 return; | 500 return; |
496 } | 501 } |
497 | 502 |
498 staple->loading = 1; | 503 staple->loading = 1; |
530 const | 535 const |
531 #endif | 536 #endif |
532 u_char *p; | 537 u_char *p; |
533 int n; | 538 int n; |
534 size_t len; | 539 size_t len; |
540 time_t now, valid; | |
535 ngx_str_t response; | 541 ngx_str_t response; |
536 X509_STORE *store; | 542 X509_STORE *store; |
537 STACK_OF(X509) *chain; | 543 STACK_OF(X509) *chain; |
538 OCSP_CERTID *id; | 544 OCSP_CERTID *id; |
539 OCSP_RESPONSE *ocsp; | 545 OCSP_RESPONSE *ocsp; |
540 OCSP_BASICRESP *basic; | 546 OCSP_BASICRESP *basic; |
541 ngx_ssl_stapling_t *staple; | 547 ngx_ssl_stapling_t *staple; |
542 ASN1_GENERALIZEDTIME *thisupdate, *nextupdate; | 548 ASN1_GENERALIZEDTIME *thisupdate, *nextupdate; |
543 | 549 |
544 staple = ctx->data; | 550 staple = ctx->data; |
551 now = ngx_time(); | |
545 ocsp = NULL; | 552 ocsp = NULL; |
546 basic = NULL; | 553 basic = NULL; |
547 id = NULL; | 554 id = NULL; |
548 | 555 |
549 if (ctx->code != 200) { | 556 if (ctx->code != 200) { |
627 ngx_ssl_error(NGX_LOG_ERR, ctx->log, 0, | 634 ngx_ssl_error(NGX_LOG_ERR, ctx->log, 0, |
628 "OCSP_check_validity() failed"); | 635 "OCSP_check_validity() failed"); |
629 goto error; | 636 goto error; |
630 } | 637 } |
631 | 638 |
639 valid = ngx_ssl_stapling_time(nextupdate); | |
640 if (valid == (time_t) NGX_ERROR) { | |
641 ngx_log_error(NGX_LOG_ERR, ctx->log, 0, | |
642 "invalid nextUpdate time in certificate status"); | |
643 goto error; | |
644 } | |
645 | |
632 OCSP_CERTID_free(id); | 646 OCSP_CERTID_free(id); |
633 OCSP_BASICRESP_free(basic); | 647 OCSP_BASICRESP_free(basic); |
634 OCSP_RESPONSE_free(ocsp); | 648 OCSP_RESPONSE_free(ocsp); |
635 | 649 |
650 id = NULL; | |
651 basic = NULL; | |
652 ocsp = NULL; | |
653 | |
636 /* copy the response to memory not in ctx->pool */ | 654 /* copy the response to memory not in ctx->pool */ |
637 | 655 |
638 response.len = len; | 656 response.len = len; |
639 response.data = ngx_alloc(response.len, ctx->log); | 657 response.data = ngx_alloc(response.len, ctx->log); |
640 | 658 |
641 if (response.data == NULL) { | 659 if (response.data == NULL) { |
642 goto done; | 660 goto error; |
643 } | 661 } |
644 | 662 |
645 ngx_memcpy(response.data, ctx->response->pos, response.len); | 663 ngx_memcpy(response.data, ctx->response->pos, response.len); |
646 | 664 |
647 ngx_log_debug2(NGX_LOG_DEBUG_EVENT, ctx->log, 0, | 665 ngx_log_debug2(NGX_LOG_DEBUG_EVENT, ctx->log, 0, |
651 if (staple->staple.data) { | 669 if (staple->staple.data) { |
652 ngx_free(staple->staple.data); | 670 ngx_free(staple->staple.data); |
653 } | 671 } |
654 | 672 |
655 staple->staple = response; | 673 staple->staple = response; |
656 | 674 staple->valid = valid; |
657 done: | 675 |
676 /* | |
677 * refresh before the response expires, | |
678 * but not earlier than in 5 minutes, and at least in an hour | |
679 */ | |
658 | 680 |
659 staple->loading = 0; | 681 staple->loading = 0; |
660 staple->valid = ngx_time() + 3600; /* ssl_stapling_valid */ | 682 staple->refresh = ngx_max(ngx_min(valid - 300, now + 3600), now + 300); |
661 | 683 |
662 ngx_ssl_ocsp_done(ctx); | 684 ngx_ssl_ocsp_done(ctx); |
663 return; | 685 return; |
664 | 686 |
665 error: | 687 error: |
666 | 688 |
667 staple->loading = 0; | 689 staple->loading = 0; |
668 staple->valid = ngx_time() + 300; /* ssl_stapling_err_valid */ | 690 staple->refresh = now + 300; |
669 | 691 |
670 if (id) { | 692 if (id) { |
671 OCSP_CERTID_free(id); | 693 OCSP_CERTID_free(id); |
672 } | 694 } |
673 | 695 |
678 if (ocsp) { | 700 if (ocsp) { |
679 OCSP_RESPONSE_free(ocsp); | 701 OCSP_RESPONSE_free(ocsp); |
680 } | 702 } |
681 | 703 |
682 ngx_ssl_ocsp_done(ctx); | 704 ngx_ssl_ocsp_done(ctx); |
705 } | |
706 | |
707 | |
708 static time_t | |
709 ngx_ssl_stapling_time(ASN1_GENERALIZEDTIME *asn1time) | |
710 { | |
711 u_char *value; | |
712 size_t len; | |
713 time_t time; | |
714 BIO *bio; | |
715 | |
716 /* | |
717 * OpenSSL doesn't provide a way to convert ASN1_GENERALIZEDTIME | |
718 * into time_t. To do this, we use ASN1_GENERALIZEDTIME_print(), | |
719 * which uses the "MMM DD HH:MM:SS YYYY [GMT]" format (e.g., | |
720 * "Feb 3 00:55:52 2015 GMT"), and parse the result. | |
721 */ | |
722 | |
723 bio = BIO_new(BIO_s_mem()); | |
724 if (bio == NULL) { | |
725 return NGX_ERROR; | |
726 } | |
727 | |
728 /* fake weekday prepended to match C asctime() format */ | |
729 | |
730 BIO_write(bio, "Tue ", sizeof("Tue ") - 1); | |
731 ASN1_GENERALIZEDTIME_print(bio, asn1time); | |
732 len = BIO_get_mem_data(bio, &value); | |
733 | |
734 time = ngx_parse_http_time(value, len); | |
735 | |
736 BIO_free(bio); | |
737 | |
738 return time; | |
683 } | 739 } |
684 | 740 |
685 | 741 |
686 static void | 742 static void |
687 ngx_ssl_stapling_cleanup(void *data) | 743 ngx_ssl_stapling_cleanup(void *data) |