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)