Mercurial > hg > nginx
comparison src/event/ngx_event_openssl_stapling.c @ 7650:abb6cc8f1dd8
OCSP stapling: moved response verification to a separate function.
author | Roman Arutyunyan <arut@nginx.com> |
---|---|
date | Wed, 06 May 2020 21:44:14 +0300 |
parents | b99cbafd51da |
children | 6ca8e15caf1f |
comparison
equal
deleted
inserted
replaced
7649:3c8082c3f98a | 7650:abb6cc8f1dd8 |
---|---|
42 | 42 |
43 | 43 |
44 typedef struct ngx_ssl_ocsp_ctx_s ngx_ssl_ocsp_ctx_t; | 44 typedef struct ngx_ssl_ocsp_ctx_s ngx_ssl_ocsp_ctx_t; |
45 | 45 |
46 struct ngx_ssl_ocsp_ctx_s { | 46 struct ngx_ssl_ocsp_ctx_s { |
47 SSL_CTX *ssl_ctx; | |
48 | |
47 X509 *cert; | 49 X509 *cert; |
48 X509 *issuer; | 50 X509 *issuer; |
51 | |
52 int status; | |
53 time_t valid; | |
49 | 54 |
50 u_char *name; | 55 u_char *name; |
51 | 56 |
52 ngx_uint_t naddrs; | 57 ngx_uint_t naddrs; |
53 | 58 |
72 | 77 |
73 ngx_uint_t state; | 78 ngx_uint_t state; |
74 | 79 |
75 ngx_uint_t code; | 80 ngx_uint_t code; |
76 ngx_uint_t count; | 81 ngx_uint_t count; |
77 | 82 ngx_uint_t flags; |
78 ngx_uint_t done; | 83 ngx_uint_t done; |
79 | 84 |
80 u_char *header_name_start; | 85 u_char *header_name_start; |
81 u_char *header_name_end; | 86 u_char *header_name_end; |
82 u_char *header_start; | 87 u_char *header_start; |
118 static ngx_int_t ngx_ssl_ocsp_process_status_line(ngx_ssl_ocsp_ctx_t *ctx); | 123 static ngx_int_t ngx_ssl_ocsp_process_status_line(ngx_ssl_ocsp_ctx_t *ctx); |
119 static ngx_int_t ngx_ssl_ocsp_parse_status_line(ngx_ssl_ocsp_ctx_t *ctx); | 124 static ngx_int_t ngx_ssl_ocsp_parse_status_line(ngx_ssl_ocsp_ctx_t *ctx); |
120 static ngx_int_t ngx_ssl_ocsp_process_headers(ngx_ssl_ocsp_ctx_t *ctx); | 125 static ngx_int_t ngx_ssl_ocsp_process_headers(ngx_ssl_ocsp_ctx_t *ctx); |
121 static ngx_int_t ngx_ssl_ocsp_parse_header_line(ngx_ssl_ocsp_ctx_t *ctx); | 126 static ngx_int_t ngx_ssl_ocsp_parse_header_line(ngx_ssl_ocsp_ctx_t *ctx); |
122 static ngx_int_t ngx_ssl_ocsp_process_body(ngx_ssl_ocsp_ctx_t *ctx); | 127 static ngx_int_t ngx_ssl_ocsp_process_body(ngx_ssl_ocsp_ctx_t *ctx); |
128 static ngx_int_t ngx_ssl_ocsp_verify(ngx_ssl_ocsp_ctx_t *ctx); | |
123 | 129 |
124 static u_char *ngx_ssl_ocsp_log_error(ngx_log_t *log, u_char *buf, size_t len); | 130 static u_char *ngx_ssl_ocsp_log_error(ngx_log_t *log, u_char *buf, size_t len); |
125 | 131 |
126 | 132 |
127 ngx_int_t | 133 ngx_int_t |
562 ctx = ngx_ssl_ocsp_start(); | 568 ctx = ngx_ssl_ocsp_start(); |
563 if (ctx == NULL) { | 569 if (ctx == NULL) { |
564 return; | 570 return; |
565 } | 571 } |
566 | 572 |
573 ctx->ssl_ctx = staple->ssl_ctx; | |
567 ctx->cert = staple->cert; | 574 ctx->cert = staple->cert; |
568 ctx->issuer = staple->issuer; | 575 ctx->issuer = staple->issuer; |
569 ctx->name = staple->name; | 576 ctx->name = staple->name; |
577 ctx->flags = (staple->verify ? OCSP_TRUSTOTHER : OCSP_NOVERIFY); | |
570 | 578 |
571 ctx->addrs = staple->addrs; | 579 ctx->addrs = staple->addrs; |
572 ctx->host = staple->host; | 580 ctx->host = staple->host; |
573 ctx->uri = staple->uri; | 581 ctx->uri = staple->uri; |
574 ctx->port = staple->port; | 582 ctx->port = staple->port; |
587 | 595 |
588 | 596 |
589 static void | 597 static void |
590 ngx_ssl_stapling_ocsp_handler(ngx_ssl_ocsp_ctx_t *ctx) | 598 ngx_ssl_stapling_ocsp_handler(ngx_ssl_ocsp_ctx_t *ctx) |
591 { | 599 { |
592 int n; | 600 time_t now; |
593 size_t len; | 601 ngx_str_t response; |
594 time_t now, valid; | 602 ngx_ssl_stapling_t *staple; |
595 ngx_str_t response; | |
596 X509_STORE *store; | |
597 const u_char *p; | |
598 STACK_OF(X509) *chain; | |
599 OCSP_CERTID *id; | |
600 OCSP_RESPONSE *ocsp; | |
601 OCSP_BASICRESP *basic; | |
602 ngx_ssl_stapling_t *staple; | |
603 ASN1_GENERALIZEDTIME *thisupdate, *nextupdate; | |
604 | 603 |
605 staple = ctx->data; | 604 staple = ctx->data; |
606 now = ngx_time(); | 605 now = ngx_time(); |
607 ocsp = NULL; | 606 |
608 basic = NULL; | 607 if (ngx_ssl_ocsp_verify(ctx) != NGX_OK) { |
609 id = NULL; | |
610 | |
611 if (ctx->code != 200) { | |
612 goto error; | 608 goto error; |
613 } | 609 } |
614 | 610 |
615 /* check the response */ | 611 if (ctx->status != V_OCSP_CERTSTATUS_GOOD) { |
616 | |
617 len = ctx->response->last - ctx->response->pos; | |
618 p = ctx->response->pos; | |
619 | |
620 ocsp = d2i_OCSP_RESPONSE(NULL, &p, len); | |
621 if (ocsp == NULL) { | |
622 ngx_ssl_error(NGX_LOG_ERR, ctx->log, 0, | |
623 "d2i_OCSP_RESPONSE() failed"); | |
624 goto error; | |
625 } | |
626 | |
627 n = OCSP_response_status(ocsp); | |
628 | |
629 if (n != OCSP_RESPONSE_STATUS_SUCCESSFUL) { | |
630 ngx_log_error(NGX_LOG_ERR, ctx->log, 0, | |
631 "OCSP response not successful (%d: %s)", | |
632 n, OCSP_response_status_str(n)); | |
633 goto error; | |
634 } | |
635 | |
636 basic = OCSP_response_get1_basic(ocsp); | |
637 if (basic == NULL) { | |
638 ngx_ssl_error(NGX_LOG_ERR, ctx->log, 0, | |
639 "OCSP_response_get1_basic() failed"); | |
640 goto error; | |
641 } | |
642 | |
643 store = SSL_CTX_get_cert_store(staple->ssl_ctx); | |
644 if (store == NULL) { | |
645 ngx_ssl_error(NGX_LOG_CRIT, ctx->log, 0, | |
646 "SSL_CTX_get_cert_store() failed"); | |
647 goto error; | |
648 } | |
649 | |
650 #ifdef SSL_CTRL_SELECT_CURRENT_CERT | |
651 /* OpenSSL 1.0.2+ */ | |
652 SSL_CTX_select_current_cert(staple->ssl_ctx, ctx->cert); | |
653 #endif | |
654 | |
655 #ifdef SSL_CTRL_GET_EXTRA_CHAIN_CERTS | |
656 /* OpenSSL 1.0.1+ */ | |
657 SSL_CTX_get_extra_chain_certs(staple->ssl_ctx, &chain); | |
658 #else | |
659 chain = staple->ssl_ctx->extra_certs; | |
660 #endif | |
661 | |
662 if (OCSP_basic_verify(basic, chain, store, | |
663 staple->verify ? OCSP_TRUSTOTHER : OCSP_NOVERIFY) | |
664 != 1) | |
665 { | |
666 ngx_ssl_error(NGX_LOG_ERR, ctx->log, 0, | |
667 "OCSP_basic_verify() failed"); | |
668 goto error; | |
669 } | |
670 | |
671 id = OCSP_cert_to_id(NULL, ctx->cert, ctx->issuer); | |
672 if (id == NULL) { | |
673 ngx_ssl_error(NGX_LOG_CRIT, ctx->log, 0, | |
674 "OCSP_cert_to_id() failed"); | |
675 goto error; | |
676 } | |
677 | |
678 if (OCSP_resp_find_status(basic, id, &n, NULL, NULL, | |
679 &thisupdate, &nextupdate) | |
680 != 1) | |
681 { | |
682 ngx_log_error(NGX_LOG_ERR, ctx->log, 0, | |
683 "certificate status not found in the OCSP response"); | |
684 goto error; | |
685 } | |
686 | |
687 if (n != V_OCSP_CERTSTATUS_GOOD) { | |
688 ngx_log_error(NGX_LOG_ERR, ctx->log, 0, | 612 ngx_log_error(NGX_LOG_ERR, ctx->log, 0, |
689 "certificate status \"%s\" in the OCSP response", | 613 "certificate status \"%s\" in the OCSP response", |
690 OCSP_cert_status_str(n)); | 614 OCSP_cert_status_str(ctx->status)); |
691 goto error; | 615 goto error; |
692 } | 616 } |
693 | 617 |
694 if (OCSP_check_validity(thisupdate, nextupdate, 300, -1) != 1) { | |
695 ngx_ssl_error(NGX_LOG_ERR, ctx->log, 0, | |
696 "OCSP_check_validity() failed"); | |
697 goto error; | |
698 } | |
699 | |
700 if (nextupdate) { | |
701 valid = ngx_ssl_stapling_time(nextupdate); | |
702 if (valid == (time_t) NGX_ERROR) { | |
703 ngx_log_error(NGX_LOG_ERR, ctx->log, 0, | |
704 "invalid nextUpdate time in certificate status"); | |
705 goto error; | |
706 } | |
707 | |
708 } else { | |
709 valid = NGX_MAX_TIME_T_VALUE; | |
710 } | |
711 | |
712 OCSP_CERTID_free(id); | |
713 OCSP_BASICRESP_free(basic); | |
714 OCSP_RESPONSE_free(ocsp); | |
715 | |
716 id = NULL; | |
717 basic = NULL; | |
718 ocsp = NULL; | |
719 | |
720 /* copy the response to memory not in ctx->pool */ | 618 /* copy the response to memory not in ctx->pool */ |
721 | 619 |
722 response.len = len; | 620 response.len = ctx->response->last - ctx->response->pos; |
723 response.data = ngx_alloc(response.len, ctx->log); | 621 response.data = ngx_alloc(response.len, ctx->log); |
724 | 622 |
725 if (response.data == NULL) { | 623 if (response.data == NULL) { |
726 goto error; | 624 goto error; |
727 } | 625 } |
728 | 626 |
729 ngx_memcpy(response.data, ctx->response->pos, response.len); | 627 ngx_memcpy(response.data, ctx->response->pos, response.len); |
730 | 628 |
731 ngx_log_debug2(NGX_LOG_DEBUG_EVENT, ctx->log, 0, | |
732 "ssl ocsp response, %s, %uz", | |
733 OCSP_cert_status_str(n), response.len); | |
734 | |
735 if (staple->staple.data) { | 629 if (staple->staple.data) { |
736 ngx_free(staple->staple.data); | 630 ngx_free(staple->staple.data); |
737 } | 631 } |
738 | 632 |
739 staple->staple = response; | 633 staple->staple = response; |
740 staple->valid = valid; | 634 staple->valid = ctx->valid; |
741 | 635 |
742 /* | 636 /* |
743 * refresh before the response expires, | 637 * refresh before the response expires, |
744 * but not earlier than in 5 minutes, and at least in an hour | 638 * but not earlier than in 5 minutes, and at least in an hour |
745 */ | 639 */ |
746 | 640 |
747 staple->loading = 0; | 641 staple->loading = 0; |
748 staple->refresh = ngx_max(ngx_min(valid - 300, now + 3600), now + 300); | 642 staple->refresh = ngx_max(ngx_min(ctx->valid - 300, now + 3600), now + 300); |
749 | 643 |
750 ngx_ssl_ocsp_done(ctx); | 644 ngx_ssl_ocsp_done(ctx); |
751 return; | 645 return; |
752 | 646 |
753 error: | 647 error: |
754 | 648 |
755 staple->loading = 0; | 649 staple->loading = 0; |
756 staple->refresh = now + 300; | 650 staple->refresh = now + 300; |
757 | |
758 if (id) { | |
759 OCSP_CERTID_free(id); | |
760 } | |
761 | |
762 if (basic) { | |
763 OCSP_BASICRESP_free(basic); | |
764 } | |
765 | |
766 if (ocsp) { | |
767 OCSP_RESPONSE_free(ocsp); | |
768 } | |
769 | 651 |
770 ngx_ssl_ocsp_done(ctx); | 652 ngx_ssl_ocsp_done(ctx); |
771 } | 653 } |
772 | 654 |
773 | 655 |
1829 | 1711 |
1830 return NGX_AGAIN; | 1712 return NGX_AGAIN; |
1831 } | 1713 } |
1832 | 1714 |
1833 | 1715 |
1716 static ngx_int_t | |
1717 ngx_ssl_ocsp_verify(ngx_ssl_ocsp_ctx_t *ctx) | |
1718 { | |
1719 int n; | |
1720 size_t len; | |
1721 X509_STORE *store; | |
1722 const u_char *p; | |
1723 STACK_OF(X509) *chain; | |
1724 OCSP_CERTID *id; | |
1725 OCSP_RESPONSE *ocsp; | |
1726 OCSP_BASICRESP *basic; | |
1727 ASN1_GENERALIZEDTIME *thisupdate, *nextupdate; | |
1728 | |
1729 ocsp = NULL; | |
1730 basic = NULL; | |
1731 id = NULL; | |
1732 | |
1733 if (ctx->code != 200) { | |
1734 goto error; | |
1735 } | |
1736 | |
1737 /* check the response */ | |
1738 | |
1739 len = ctx->response->last - ctx->response->pos; | |
1740 p = ctx->response->pos; | |
1741 | |
1742 ocsp = d2i_OCSP_RESPONSE(NULL, &p, len); | |
1743 if (ocsp == NULL) { | |
1744 ngx_ssl_error(NGX_LOG_ERR, ctx->log, 0, | |
1745 "d2i_OCSP_RESPONSE() failed"); | |
1746 goto error; | |
1747 } | |
1748 | |
1749 n = OCSP_response_status(ocsp); | |
1750 | |
1751 if (n != OCSP_RESPONSE_STATUS_SUCCESSFUL) { | |
1752 ngx_log_error(NGX_LOG_ERR, ctx->log, 0, | |
1753 "OCSP response not successful (%d: %s)", | |
1754 n, OCSP_response_status_str(n)); | |
1755 goto error; | |
1756 } | |
1757 | |
1758 basic = OCSP_response_get1_basic(ocsp); | |
1759 if (basic == NULL) { | |
1760 ngx_ssl_error(NGX_LOG_ERR, ctx->log, 0, | |
1761 "OCSP_response_get1_basic() failed"); | |
1762 goto error; | |
1763 } | |
1764 | |
1765 store = SSL_CTX_get_cert_store(ctx->ssl_ctx); | |
1766 if (store == NULL) { | |
1767 ngx_ssl_error(NGX_LOG_CRIT, ctx->log, 0, | |
1768 "SSL_CTX_get_cert_store() failed"); | |
1769 goto error; | |
1770 } | |
1771 | |
1772 #ifdef SSL_CTRL_SELECT_CURRENT_CERT | |
1773 /* OpenSSL 1.0.2+ */ | |
1774 SSL_CTX_select_current_cert(ctx->ssl_ctx, ctx->cert); | |
1775 #endif | |
1776 | |
1777 #ifdef SSL_CTRL_GET_EXTRA_CHAIN_CERTS | |
1778 /* OpenSSL 1.0.1+ */ | |
1779 SSL_CTX_get_extra_chain_certs(ctx->ssl_ctx, &chain); | |
1780 #else | |
1781 chain = ctx->ssl_ctx->extra_certs; | |
1782 #endif | |
1783 | |
1784 if (OCSP_basic_verify(basic, chain, store, ctx->flags) != 1) { | |
1785 ngx_ssl_error(NGX_LOG_ERR, ctx->log, 0, | |
1786 "OCSP_basic_verify() failed"); | |
1787 goto error; | |
1788 } | |
1789 | |
1790 id = OCSP_cert_to_id(NULL, ctx->cert, ctx->issuer); | |
1791 if (id == NULL) { | |
1792 ngx_ssl_error(NGX_LOG_CRIT, ctx->log, 0, | |
1793 "OCSP_cert_to_id() failed"); | |
1794 goto error; | |
1795 } | |
1796 | |
1797 if (OCSP_resp_find_status(basic, id, &ctx->status, NULL, NULL, | |
1798 &thisupdate, &nextupdate) | |
1799 != 1) | |
1800 { | |
1801 ngx_log_error(NGX_LOG_ERR, ctx->log, 0, | |
1802 "certificate status not found in the OCSP response"); | |
1803 goto error; | |
1804 } | |
1805 | |
1806 if (OCSP_check_validity(thisupdate, nextupdate, 300, -1) != 1) { | |
1807 ngx_ssl_error(NGX_LOG_ERR, ctx->log, 0, | |
1808 "OCSP_check_validity() failed"); | |
1809 goto error; | |
1810 } | |
1811 | |
1812 if (nextupdate) { | |
1813 ctx->valid = ngx_ssl_stapling_time(nextupdate); | |
1814 if (ctx->valid == (time_t) NGX_ERROR) { | |
1815 ngx_log_error(NGX_LOG_ERR, ctx->log, 0, | |
1816 "invalid nextUpdate time in certificate status"); | |
1817 goto error; | |
1818 } | |
1819 | |
1820 } else { | |
1821 ctx->valid = NGX_MAX_TIME_T_VALUE; | |
1822 } | |
1823 | |
1824 OCSP_CERTID_free(id); | |
1825 OCSP_BASICRESP_free(basic); | |
1826 OCSP_RESPONSE_free(ocsp); | |
1827 | |
1828 ngx_log_debug2(NGX_LOG_DEBUG_EVENT, ctx->log, 0, | |
1829 "ssl ocsp response, %s, %uz", | |
1830 OCSP_cert_status_str(ctx->status), len); | |
1831 | |
1832 return NGX_OK; | |
1833 | |
1834 error: | |
1835 | |
1836 if (id) { | |
1837 OCSP_CERTID_free(id); | |
1838 } | |
1839 | |
1840 if (basic) { | |
1841 OCSP_BASICRESP_free(basic); | |
1842 } | |
1843 | |
1844 if (ocsp) { | |
1845 OCSP_RESPONSE_free(ocsp); | |
1846 } | |
1847 | |
1848 return NGX_ERROR; | |
1849 } | |
1850 | |
1851 | |
1834 static u_char * | 1852 static u_char * |
1835 ngx_ssl_ocsp_log_error(ngx_log_t *log, u_char *buf, size_t len) | 1853 ngx_ssl_ocsp_log_error(ngx_log_t *log, u_char *buf, size_t len) |
1836 { | 1854 { |
1837 u_char *p; | 1855 u_char *p; |
1838 ngx_ssl_ocsp_ctx_t *ctx; | 1856 ngx_ssl_ocsp_ctx_t *ctx; |