Mercurial > hg > nginx-quic
comparison src/event/ngx_event_openssl.c @ 8957:3be953161026 quic
Merged with the default branch.
author | Sergey Kandaurov <pluknet@nginx.com> |
---|---|
date | Thu, 20 Oct 2022 16:41:36 +0400 |
parents | b30bec3d71d6 81b4326daac7 |
children | 91ad1abfb285 |
comparison
equal
deleted
inserted
replaced
8956:79cd6993a3e3 | 8957:3be953161026 |
---|---|
69 ngx_slab_pool_t *shpool, ngx_uint_t n); | 69 ngx_slab_pool_t *shpool, ngx_uint_t n); |
70 static void ngx_ssl_session_rbtree_insert_value(ngx_rbtree_node_t *temp, | 70 static void ngx_ssl_session_rbtree_insert_value(ngx_rbtree_node_t *temp, |
71 ngx_rbtree_node_t *node, ngx_rbtree_node_t *sentinel); | 71 ngx_rbtree_node_t *node, ngx_rbtree_node_t *sentinel); |
72 | 72 |
73 #ifdef SSL_CTRL_SET_TLSEXT_TICKET_KEY_CB | 73 #ifdef SSL_CTRL_SET_TLSEXT_TICKET_KEY_CB |
74 static int ngx_ssl_session_ticket_key_callback(ngx_ssl_conn_t *ssl_conn, | 74 static int ngx_ssl_ticket_key_callback(ngx_ssl_conn_t *ssl_conn, |
75 unsigned char *name, unsigned char *iv, EVP_CIPHER_CTX *ectx, | 75 unsigned char *name, unsigned char *iv, EVP_CIPHER_CTX *ectx, |
76 HMAC_CTX *hctx, int enc); | 76 HMAC_CTX *hctx, int enc); |
77 static void ngx_ssl_session_ticket_keys_cleanup(void *data); | 77 static ngx_int_t ngx_ssl_rotate_ticket_keys(SSL_CTX *ssl_ctx, ngx_log_t *log); |
78 static void ngx_ssl_ticket_keys_cleanup(void *data); | |
78 #endif | 79 #endif |
79 | 80 |
80 #ifndef X509_CHECK_FLAG_ALWAYS_CHECK_SUBJECT | 81 #ifndef X509_CHECK_FLAG_ALWAYS_CHECK_SUBJECT |
81 static ngx_int_t ngx_ssl_check_name(ngx_str_t *name, ASN1_STRING *str); | 82 static ngx_int_t ngx_ssl_check_name(ngx_str_t *name, ASN1_STRING *str); |
82 #endif | 83 #endif |
129 | 130 |
130 | 131 |
131 int ngx_ssl_connection_index; | 132 int ngx_ssl_connection_index; |
132 int ngx_ssl_server_conf_index; | 133 int ngx_ssl_server_conf_index; |
133 int ngx_ssl_session_cache_index; | 134 int ngx_ssl_session_cache_index; |
134 int ngx_ssl_session_ticket_keys_index; | 135 int ngx_ssl_ticket_keys_index; |
135 int ngx_ssl_ocsp_index; | 136 int ngx_ssl_ocsp_index; |
136 int ngx_ssl_certificate_index; | 137 int ngx_ssl_certificate_index; |
137 int ngx_ssl_next_certificate_index; | 138 int ngx_ssl_next_certificate_index; |
138 int ngx_ssl_certificate_name_index; | 139 int ngx_ssl_certificate_name_index; |
139 int ngx_ssl_stapling_index; | 140 int ngx_ssl_stapling_index; |
206 ngx_ssl_error(NGX_LOG_ALERT, log, 0, | 207 ngx_ssl_error(NGX_LOG_ALERT, log, 0, |
207 "SSL_CTX_get_ex_new_index() failed"); | 208 "SSL_CTX_get_ex_new_index() failed"); |
208 return NGX_ERROR; | 209 return NGX_ERROR; |
209 } | 210 } |
210 | 211 |
211 ngx_ssl_session_ticket_keys_index = SSL_CTX_get_ex_new_index(0, NULL, NULL, | 212 ngx_ssl_ticket_keys_index = SSL_CTX_get_ex_new_index(0, NULL, NULL, NULL, |
212 NULL, NULL); | 213 NULL); |
213 if (ngx_ssl_session_ticket_keys_index == -1) { | 214 if (ngx_ssl_ticket_keys_index == -1) { |
214 ngx_ssl_error(NGX_LOG_ALERT, log, 0, | 215 ngx_ssl_error(NGX_LOG_ALERT, log, 0, |
215 "SSL_CTX_get_ex_new_index() failed"); | 216 "SSL_CTX_get_ex_new_index() failed"); |
216 return NGX_ERROR; | 217 return NGX_ERROR; |
217 } | 218 } |
218 | 219 |
1078 c = ngx_ssl_get_connection((ngx_ssl_conn_t *) ssl_conn); | 1079 c = ngx_ssl_get_connection((ngx_ssl_conn_t *) ssl_conn); |
1079 | 1080 |
1080 if (c->ssl->handshaked) { | 1081 if (c->ssl->handshaked) { |
1081 c->ssl->renegotiation = 1; | 1082 c->ssl->renegotiation = 1; |
1082 ngx_log_debug0(NGX_LOG_DEBUG_EVENT, c->log, 0, "SSL renegotiation"); | 1083 ngx_log_debug0(NGX_LOG_DEBUG_EVENT, c->log, 0, "SSL renegotiation"); |
1084 } | |
1085 } | |
1086 | |
1087 #endif | |
1088 | |
1089 #ifdef TLS1_3_VERSION | |
1090 | |
1091 if ((where & SSL_CB_ACCEPT_LOOP) == SSL_CB_ACCEPT_LOOP | |
1092 && SSL_version(ssl_conn) == TLS1_3_VERSION) | |
1093 { | |
1094 time_t now, time, timeout, conf_timeout; | |
1095 SSL_SESSION *sess; | |
1096 | |
1097 /* | |
1098 * OpenSSL with TLSv1.3 updates the session creation time on | |
1099 * session resumption and keeps the session timeout unmodified, | |
1100 * making it possible to maintain the session forever, bypassing | |
1101 * client certificate expiration and revocation. To make sure | |
1102 * session timeouts are actually used, we now update the session | |
1103 * creation time and reduce the session timeout accordingly. | |
1104 * | |
1105 * BoringSSL with TLSv1.3 ignores configured session timeouts | |
1106 * and uses a hardcoded timeout instead, 7 days. So we update | |
1107 * session timeout to the configured value as soon as a session | |
1108 * is created. | |
1109 */ | |
1110 | |
1111 c = ngx_ssl_get_connection((ngx_ssl_conn_t *) ssl_conn); | |
1112 sess = SSL_get0_session(ssl_conn); | |
1113 | |
1114 if (!c->ssl->session_timeout_set && sess) { | |
1115 c->ssl->session_timeout_set = 1; | |
1116 | |
1117 now = ngx_time(); | |
1118 time = SSL_SESSION_get_time(sess); | |
1119 timeout = SSL_SESSION_get_timeout(sess); | |
1120 conf_timeout = SSL_CTX_get_timeout(c->ssl->session_ctx); | |
1121 | |
1122 timeout = ngx_min(timeout, conf_timeout); | |
1123 | |
1124 if (now - time >= timeout) { | |
1125 SSL_SESSION_set1_id_context(sess, (unsigned char *) "", 0); | |
1126 | |
1127 } else { | |
1128 SSL_SESSION_set_time(sess, now); | |
1129 SSL_SESSION_set_timeout(sess, timeout - (now - time)); | |
1130 } | |
1083 } | 1131 } |
1084 } | 1132 } |
1085 | 1133 |
1086 #endif | 1134 #endif |
1087 | 1135 |
1424 * does for ciphers. | 1472 * does for ciphers. |
1425 */ | 1473 */ |
1426 | 1474 |
1427 SSL_CTX_set_options(ssl->ctx, SSL_OP_SINGLE_ECDH_USE); | 1475 SSL_CTX_set_options(ssl->ctx, SSL_OP_SINGLE_ECDH_USE); |
1428 | 1476 |
1429 #if SSL_CTRL_SET_ECDH_AUTO | 1477 #ifdef SSL_CTRL_SET_ECDH_AUTO |
1430 /* not needed in OpenSSL 1.1.0+ */ | 1478 /* not needed in OpenSSL 1.1.0+ */ |
1431 SSL_CTX_set_ecdh_auto(ssl->ctx, 1); | 1479 (void) SSL_CTX_set_ecdh_auto(ssl->ctx, 1); |
1432 #endif | 1480 #endif |
1433 | 1481 |
1434 if (ngx_strcmp(name->data, "auto") == 0) { | 1482 if (ngx_strcmp(name->data, "auto") == 0) { |
1435 return NGX_OK; | 1483 return NGX_OK; |
1436 } | 1484 } |
1767 | 1815 |
1768 #endif | 1816 #endif |
1769 #endif | 1817 #endif |
1770 #endif | 1818 #endif |
1771 | 1819 |
1772 #ifdef BIO_get_ktls_send | 1820 #if (defined BIO_get_ktls_send && !NGX_WIN32) |
1773 | 1821 |
1774 if (BIO_get_ktls_send(SSL_get_wbio(c->ssl->connection)) == 1) { | 1822 if (BIO_get_ktls_send(SSL_get_wbio(c->ssl->connection)) == 1) { |
1775 ngx_log_debug0(NGX_LOG_DEBUG_EVENT, c->log, 0, | 1823 ngx_log_debug0(NGX_LOG_DEBUG_EVENT, c->log, 0, |
1776 "BIO_get_ktls_send(): 1"); | 1824 "BIO_get_ktls_send(): 1"); |
1777 c->ssl->sendfile = 1; | 1825 c->ssl->sendfile = 1; |
1912 c->send_chain = ngx_ssl_send_chain; | 1960 c->send_chain = ngx_ssl_send_chain; |
1913 | 1961 |
1914 c->read->ready = 1; | 1962 c->read->ready = 1; |
1915 c->write->ready = 1; | 1963 c->write->ready = 1; |
1916 | 1964 |
1917 #ifdef BIO_get_ktls_send | 1965 #if (defined BIO_get_ktls_send && !NGX_WIN32) |
1918 | 1966 |
1919 if (BIO_get_ktls_send(SSL_get_wbio(c->ssl->connection)) == 1) { | 1967 if (BIO_get_ktls_send(SSL_get_wbio(c->ssl->connection)) == 1) { |
1920 ngx_log_debug0(NGX_LOG_DEBUG_EVENT, c->log, 0, | 1968 ngx_log_debug0(NGX_LOG_DEBUG_EVENT, c->log, 0, |
1921 "BIO_get_ktls_send(): 1"); | 1969 "BIO_get_ktls_send(): 1"); |
1922 c->ssl->sendfile = 1; | 1970 c->ssl->sendfile = 1; |
2941 | 2989 |
2942 | 2990 |
2943 static ssize_t | 2991 static ssize_t |
2944 ngx_ssl_sendfile(ngx_connection_t *c, ngx_buf_t *file, size_t size) | 2992 ngx_ssl_sendfile(ngx_connection_t *c, ngx_buf_t *file, size_t size) |
2945 { | 2993 { |
2946 #ifdef BIO_get_ktls_send | 2994 #if (defined BIO_get_ktls_send && !NGX_WIN32) |
2947 | 2995 |
2948 int sslerr, flags; | 2996 int sslerr, flags; |
2949 ssize_t n; | 2997 ssize_t n; |
2950 ngx_err_t err; | 2998 ngx_err_t err; |
2951 | 2999 |
3427 #ifdef SSL_R_CERT_CB_ERROR | 3475 #ifdef SSL_R_CERT_CB_ERROR |
3428 || n == SSL_R_CERT_CB_ERROR /* 377 */ | 3476 || n == SSL_R_CERT_CB_ERROR /* 377 */ |
3429 #endif | 3477 #endif |
3430 #ifdef SSL_R_VERSION_TOO_LOW | 3478 #ifdef SSL_R_VERSION_TOO_LOW |
3431 || n == SSL_R_VERSION_TOO_LOW /* 396 */ | 3479 || n == SSL_R_VERSION_TOO_LOW /* 396 */ |
3480 #endif | |
3481 #ifdef SSL_R_BAD_RECORD_TYPE | |
3482 || n == SSL_R_BAD_RECORD_TYPE /* 443 */ | |
3432 #endif | 3483 #endif |
3433 || n == 1000 /* SSL_R_SSLV3_ALERT_CLOSE_NOTIFY */ | 3484 || n == 1000 /* SSL_R_SSLV3_ALERT_CLOSE_NOTIFY */ |
3434 #ifdef SSL_R_SSLV3_ALERT_UNEXPECTED_MESSAGE | 3485 #ifdef SSL_R_SSLV3_ALERT_UNEXPECTED_MESSAGE |
3435 || n == SSL_R_SSLV3_ALERT_UNEXPECTED_MESSAGE /* 1010 */ | 3486 || n == SSL_R_SSLV3_ALERT_UNEXPECTED_MESSAGE /* 1010 */ |
3436 || n == SSL_R_SSLV3_ALERT_BAD_RECORD_MAC /* 1020 */ | 3487 || n == SSL_R_SSLV3_ALERT_BAD_RECORD_MAC /* 1020 */ |
3772 ngx_rbtree_init(&cache->session_rbtree, &cache->sentinel, | 3823 ngx_rbtree_init(&cache->session_rbtree, &cache->sentinel, |
3773 ngx_ssl_session_rbtree_insert_value); | 3824 ngx_ssl_session_rbtree_insert_value); |
3774 | 3825 |
3775 ngx_queue_init(&cache->expire_queue); | 3826 ngx_queue_init(&cache->expire_queue); |
3776 | 3827 |
3828 cache->ticket_keys[0].expire = 0; | |
3829 cache->ticket_keys[1].expire = 0; | |
3830 cache->ticket_keys[2].expire = 0; | |
3831 | |
3832 cache->fail_time = 0; | |
3833 | |
3777 len = sizeof(" in SSL session shared cache \"\"") + shm_zone->shm.name.len; | 3834 len = sizeof(" in SSL session shared cache \"\"") + shm_zone->shm.name.len; |
3778 | 3835 |
3779 shpool->log_ctx = ngx_slab_alloc(shpool, len); | 3836 shpool->log_ctx = ngx_slab_alloc(shpool, len); |
3780 if (shpool->log_ctx == NULL) { | 3837 if (shpool->log_ctx == NULL) { |
3781 return NGX_ERROR; | 3838 return NGX_ERROR; |
3790 } | 3847 } |
3791 | 3848 |
3792 | 3849 |
3793 /* | 3850 /* |
3794 * The length of the session id is 16 bytes for SSLv2 sessions and | 3851 * The length of the session id is 16 bytes for SSLv2 sessions and |
3795 * between 1 and 32 bytes for SSLv3/TLSv1, typically 32 bytes. | 3852 * between 1 and 32 bytes for SSLv3 and TLS, typically 32 bytes. |
3796 * It seems that the typical length of the external ASN1 representation | 3853 * Typical length of the external ASN1 representation of a session |
3797 * of a session is 118 or 119 bytes for SSLv3/TSLv1. | 3854 * is about 150 bytes plus SNI server name. |
3798 * | 3855 * |
3799 * Thus on 32-bit platforms we allocate separately an rbtree node, | 3856 * On 32-bit platforms we allocate an rbtree node, a session id, and |
3800 * a session id, and an ASN1 representation, they take accordingly | 3857 * an ASN1 representation in a single allocation, it typically takes |
3801 * 64, 32, and 128 bytes. | 3858 * 256 bytes. |
3802 * | 3859 * |
3803 * On 64-bit platforms we allocate separately an rbtree node + session_id, | 3860 * On 64-bit platforms we allocate separately an rbtree node + session_id, |
3804 * and an ASN1 representation, they take accordingly 128 and 128 bytes. | 3861 * and an ASN1 representation, they take accordingly 128 and 256 bytes. |
3805 * | 3862 * |
3806 * OpenSSL's i2d_SSL_SESSION() and d2i_SSL_SESSION are slow, | 3863 * OpenSSL's i2d_SSL_SESSION() and d2i_SSL_SESSION are slow, |
3807 * so they are outside the code locked by shared pool mutex | 3864 * so they are outside the code locked by shared pool mutex |
3808 */ | 3865 */ |
3809 | 3866 |
3810 static int | 3867 static int |
3811 ngx_ssl_new_session(ngx_ssl_conn_t *ssl_conn, ngx_ssl_session_t *sess) | 3868 ngx_ssl_new_session(ngx_ssl_conn_t *ssl_conn, ngx_ssl_session_t *sess) |
3812 { | 3869 { |
3813 int len; | 3870 int len; |
3814 u_char *p, *id, *cached_sess, *session_id; | 3871 u_char *p, *session_id; |
3872 size_t n; | |
3815 uint32_t hash; | 3873 uint32_t hash; |
3816 SSL_CTX *ssl_ctx; | 3874 SSL_CTX *ssl_ctx; |
3817 unsigned int session_id_length; | 3875 unsigned int session_id_length; |
3818 ngx_shm_zone_t *shm_zone; | 3876 ngx_shm_zone_t *shm_zone; |
3819 ngx_connection_t *c; | 3877 ngx_connection_t *c; |
3820 ngx_slab_pool_t *shpool; | 3878 ngx_slab_pool_t *shpool; |
3821 ngx_ssl_sess_id_t *sess_id; | 3879 ngx_ssl_sess_id_t *sess_id; |
3822 ngx_ssl_session_cache_t *cache; | 3880 ngx_ssl_session_cache_t *cache; |
3823 u_char buf[NGX_SSL_MAX_SESSION_SIZE]; | 3881 u_char buf[NGX_SSL_MAX_SESSION_SIZE]; |
3824 | 3882 |
3883 #ifdef TLS1_3_VERSION | |
3884 | |
3885 /* | |
3886 * OpenSSL tries to save TLSv1.3 sessions into session cache | |
3887 * even when using tickets for stateless session resumption, | |
3888 * "because some applications just want to know about the creation | |
3889 * of a session"; do not cache such sessions | |
3890 */ | |
3891 | |
3892 if (SSL_version(ssl_conn) == TLS1_3_VERSION | |
3893 && (SSL_get_options(ssl_conn) & SSL_OP_NO_TICKET) == 0) | |
3894 { | |
3895 return 0; | |
3896 } | |
3897 | |
3898 #endif | |
3899 | |
3825 len = i2d_SSL_SESSION(sess, NULL); | 3900 len = i2d_SSL_SESSION(sess, NULL); |
3826 | 3901 |
3827 /* do not cache too big session */ | 3902 /* do not cache too big session */ |
3828 | 3903 |
3829 if (len > (int) NGX_SSL_MAX_SESSION_SIZE) { | 3904 if (len > NGX_SSL_MAX_SESSION_SIZE) { |
3830 return 0; | 3905 return 0; |
3831 } | 3906 } |
3832 | 3907 |
3833 p = buf; | 3908 p = buf; |
3834 i2d_SSL_SESSION(sess, &p); | 3909 i2d_SSL_SESSION(sess, &p); |
3835 | 3910 |
3911 session_id = (u_char *) SSL_SESSION_get_id(sess, &session_id_length); | |
3912 | |
3913 /* do not cache sessions with too long session id */ | |
3914 | |
3915 if (session_id_length > 32) { | |
3916 return 0; | |
3917 } | |
3918 | |
3836 c = ngx_ssl_get_connection(ssl_conn); | 3919 c = ngx_ssl_get_connection(ssl_conn); |
3837 | 3920 |
3838 ssl_ctx = c->ssl->session_ctx; | 3921 ssl_ctx = c->ssl->session_ctx; |
3839 shm_zone = SSL_CTX_get_ex_data(ssl_ctx, ngx_ssl_session_cache_index); | 3922 shm_zone = SSL_CTX_get_ex_data(ssl_ctx, ngx_ssl_session_cache_index); |
3840 | 3923 |
3844 ngx_shmtx_lock(&shpool->mutex); | 3927 ngx_shmtx_lock(&shpool->mutex); |
3845 | 3928 |
3846 /* drop one or two expired sessions */ | 3929 /* drop one or two expired sessions */ |
3847 ngx_ssl_expire_sessions(cache, shpool, 1); | 3930 ngx_ssl_expire_sessions(cache, shpool, 1); |
3848 | 3931 |
3849 cached_sess = ngx_slab_alloc_locked(shpool, len); | 3932 #if (NGX_PTR_SIZE == 8) |
3850 | 3933 n = sizeof(ngx_ssl_sess_id_t); |
3851 if (cached_sess == NULL) { | 3934 #else |
3935 n = offsetof(ngx_ssl_sess_id_t, session) + len; | |
3936 #endif | |
3937 | |
3938 sess_id = ngx_slab_alloc_locked(shpool, n); | |
3939 | |
3940 if (sess_id == NULL) { | |
3852 | 3941 |
3853 /* drop the oldest non-expired session and try once more */ | 3942 /* drop the oldest non-expired session and try once more */ |
3854 | 3943 |
3855 ngx_ssl_expire_sessions(cache, shpool, 0); | 3944 ngx_ssl_expire_sessions(cache, shpool, 0); |
3856 | 3945 |
3857 cached_sess = ngx_slab_alloc_locked(shpool, len); | 3946 sess_id = ngx_slab_alloc_locked(shpool, n); |
3858 | |
3859 if (cached_sess == NULL) { | |
3860 sess_id = NULL; | |
3861 goto failed; | |
3862 } | |
3863 } | |
3864 | |
3865 sess_id = ngx_slab_alloc_locked(shpool, sizeof(ngx_ssl_sess_id_t)); | |
3866 | |
3867 if (sess_id == NULL) { | |
3868 | |
3869 /* drop the oldest non-expired session and try once more */ | |
3870 | |
3871 ngx_ssl_expire_sessions(cache, shpool, 0); | |
3872 | |
3873 sess_id = ngx_slab_alloc_locked(shpool, sizeof(ngx_ssl_sess_id_t)); | |
3874 | 3947 |
3875 if (sess_id == NULL) { | 3948 if (sess_id == NULL) { |
3876 goto failed; | 3949 goto failed; |
3877 } | 3950 } |
3878 } | 3951 } |
3879 | 3952 |
3880 session_id = (u_char *) SSL_SESSION_get_id(sess, &session_id_length); | |
3881 | |
3882 #if (NGX_PTR_SIZE == 8) | 3953 #if (NGX_PTR_SIZE == 8) |
3883 | 3954 |
3884 id = sess_id->sess_id; | 3955 sess_id->session = ngx_slab_alloc_locked(shpool, len); |
3885 | 3956 |
3886 #else | 3957 if (sess_id->session == NULL) { |
3887 | |
3888 id = ngx_slab_alloc_locked(shpool, session_id_length); | |
3889 | |
3890 if (id == NULL) { | |
3891 | 3958 |
3892 /* drop the oldest non-expired session and try once more */ | 3959 /* drop the oldest non-expired session and try once more */ |
3893 | 3960 |
3894 ngx_ssl_expire_sessions(cache, shpool, 0); | 3961 ngx_ssl_expire_sessions(cache, shpool, 0); |
3895 | 3962 |
3896 id = ngx_slab_alloc_locked(shpool, session_id_length); | 3963 sess_id->session = ngx_slab_alloc_locked(shpool, len); |
3897 | 3964 |
3898 if (id == NULL) { | 3965 if (sess_id->session == NULL) { |
3899 goto failed; | 3966 goto failed; |
3900 } | 3967 } |
3901 } | 3968 } |
3902 | 3969 |
3903 #endif | 3970 #endif |
3904 | 3971 |
3905 ngx_memcpy(cached_sess, buf, len); | 3972 ngx_memcpy(sess_id->session, buf, len); |
3906 | 3973 ngx_memcpy(sess_id->id, session_id, session_id_length); |
3907 ngx_memcpy(id, session_id, session_id_length); | |
3908 | 3974 |
3909 hash = ngx_crc32_short(session_id, session_id_length); | 3975 hash = ngx_crc32_short(session_id, session_id_length); |
3910 | 3976 |
3911 ngx_log_debug3(NGX_LOG_DEBUG_EVENT, c->log, 0, | 3977 ngx_log_debug3(NGX_LOG_DEBUG_EVENT, c->log, 0, |
3912 "ssl new session: %08XD:%ud:%d", | 3978 "ssl new session: %08XD:%ud:%d", |
3913 hash, session_id_length, len); | 3979 hash, session_id_length, len); |
3914 | 3980 |
3915 sess_id->node.key = hash; | 3981 sess_id->node.key = hash; |
3916 sess_id->node.data = (u_char) session_id_length; | 3982 sess_id->node.data = (u_char) session_id_length; |
3917 sess_id->id = id; | |
3918 sess_id->len = len; | 3983 sess_id->len = len; |
3919 sess_id->session = cached_sess; | |
3920 | 3984 |
3921 sess_id->expire = ngx_time() + SSL_CTX_get_timeout(ssl_ctx); | 3985 sess_id->expire = ngx_time() + SSL_CTX_get_timeout(ssl_ctx); |
3922 | 3986 |
3923 ngx_queue_insert_head(&cache->expire_queue, &sess_id->queue); | 3987 ngx_queue_insert_head(&cache->expire_queue, &sess_id->queue); |
3924 | 3988 |
3927 ngx_shmtx_unlock(&shpool->mutex); | 3991 ngx_shmtx_unlock(&shpool->mutex); |
3928 | 3992 |
3929 return 0; | 3993 return 0; |
3930 | 3994 |
3931 failed: | 3995 failed: |
3932 | |
3933 if (cached_sess) { | |
3934 ngx_slab_free_locked(shpool, cached_sess); | |
3935 } | |
3936 | 3996 |
3937 if (sess_id) { | 3997 if (sess_id) { |
3938 ngx_slab_free_locked(shpool, sess_id); | 3998 ngx_slab_free_locked(shpool, sess_id); |
3939 } | 3999 } |
3940 | 4000 |
3941 ngx_shmtx_unlock(&shpool->mutex); | 4001 ngx_shmtx_unlock(&shpool->mutex); |
3942 | 4002 |
3943 ngx_log_error(NGX_LOG_ALERT, c->log, 0, | 4003 if (cache->fail_time != ngx_time()) { |
3944 "could not allocate new session%s", shpool->log_ctx); | 4004 cache->fail_time = ngx_time(); |
4005 ngx_log_error(NGX_LOG_WARN, c->log, 0, | |
4006 "could not allocate new session%s", shpool->log_ctx); | |
4007 } | |
3945 | 4008 |
3946 return 0; | 4009 return 0; |
3947 } | 4010 } |
3948 | 4011 |
3949 | 4012 |
4025 | 4088 |
4026 ngx_queue_remove(&sess_id->queue); | 4089 ngx_queue_remove(&sess_id->queue); |
4027 | 4090 |
4028 ngx_rbtree_delete(&cache->session_rbtree, node); | 4091 ngx_rbtree_delete(&cache->session_rbtree, node); |
4029 | 4092 |
4093 ngx_explicit_memzero(sess_id->session, sess_id->len); | |
4094 | |
4095 #if (NGX_PTR_SIZE == 8) | |
4030 ngx_slab_free_locked(shpool, sess_id->session); | 4096 ngx_slab_free_locked(shpool, sess_id->session); |
4031 #if (NGX_PTR_SIZE == 4) | |
4032 ngx_slab_free_locked(shpool, sess_id->id); | |
4033 #endif | 4097 #endif |
4034 ngx_slab_free_locked(shpool, sess_id); | 4098 ngx_slab_free_locked(shpool, sess_id); |
4035 | 4099 |
4036 sess = NULL; | 4100 sess = NULL; |
4037 | 4101 |
4115 | 4179 |
4116 ngx_queue_remove(&sess_id->queue); | 4180 ngx_queue_remove(&sess_id->queue); |
4117 | 4181 |
4118 ngx_rbtree_delete(&cache->session_rbtree, node); | 4182 ngx_rbtree_delete(&cache->session_rbtree, node); |
4119 | 4183 |
4184 ngx_explicit_memzero(sess_id->session, sess_id->len); | |
4185 | |
4186 #if (NGX_PTR_SIZE == 8) | |
4120 ngx_slab_free_locked(shpool, sess_id->session); | 4187 ngx_slab_free_locked(shpool, sess_id->session); |
4121 #if (NGX_PTR_SIZE == 4) | |
4122 ngx_slab_free_locked(shpool, sess_id->id); | |
4123 #endif | 4188 #endif |
4124 ngx_slab_free_locked(shpool, sess_id); | 4189 ngx_slab_free_locked(shpool, sess_id); |
4125 | 4190 |
4126 goto done; | 4191 goto done; |
4127 } | 4192 } |
4164 ngx_log_debug1(NGX_LOG_DEBUG_EVENT, ngx_cycle->log, 0, | 4229 ngx_log_debug1(NGX_LOG_DEBUG_EVENT, ngx_cycle->log, 0, |
4165 "expire session: %08Xi", sess_id->node.key); | 4230 "expire session: %08Xi", sess_id->node.key); |
4166 | 4231 |
4167 ngx_rbtree_delete(&cache->session_rbtree, &sess_id->node); | 4232 ngx_rbtree_delete(&cache->session_rbtree, &sess_id->node); |
4168 | 4233 |
4234 ngx_explicit_memzero(sess_id->session, sess_id->len); | |
4235 | |
4236 #if (NGX_PTR_SIZE == 8) | |
4169 ngx_slab_free_locked(shpool, sess_id->session); | 4237 ngx_slab_free_locked(shpool, sess_id->session); |
4170 #if (NGX_PTR_SIZE == 4) | |
4171 ngx_slab_free_locked(shpool, sess_id->id); | |
4172 #endif | 4238 #endif |
4173 ngx_slab_free_locked(shpool, sess_id); | 4239 ngx_slab_free_locked(shpool, sess_id); |
4174 } | 4240 } |
4175 } | 4241 } |
4176 | 4242 |
4220 #ifdef SSL_CTRL_SET_TLSEXT_TICKET_KEY_CB | 4286 #ifdef SSL_CTRL_SET_TLSEXT_TICKET_KEY_CB |
4221 | 4287 |
4222 ngx_int_t | 4288 ngx_int_t |
4223 ngx_ssl_session_ticket_keys(ngx_conf_t *cf, ngx_ssl_t *ssl, ngx_array_t *paths) | 4289 ngx_ssl_session_ticket_keys(ngx_conf_t *cf, ngx_ssl_t *ssl, ngx_array_t *paths) |
4224 { | 4290 { |
4225 u_char buf[80]; | 4291 u_char buf[80]; |
4226 size_t size; | 4292 size_t size; |
4227 ssize_t n; | 4293 ssize_t n; |
4228 ngx_str_t *path; | 4294 ngx_str_t *path; |
4229 ngx_file_t file; | 4295 ngx_file_t file; |
4230 ngx_uint_t i; | 4296 ngx_uint_t i; |
4231 ngx_array_t *keys; | 4297 ngx_array_t *keys; |
4232 ngx_file_info_t fi; | 4298 ngx_file_info_t fi; |
4233 ngx_pool_cleanup_t *cln; | 4299 ngx_pool_cleanup_t *cln; |
4234 ngx_ssl_session_ticket_key_t *key; | 4300 ngx_ssl_ticket_key_t *key; |
4235 | 4301 |
4236 if (paths == NULL) { | 4302 if (paths == NULL |
4303 && SSL_CTX_get_ex_data(ssl->ctx, ngx_ssl_session_cache_index) == NULL) | |
4304 { | |
4237 return NGX_OK; | 4305 return NGX_OK; |
4238 } | 4306 } |
4239 | 4307 |
4240 keys = ngx_array_create(cf->pool, paths->nelts, | 4308 keys = ngx_array_create(cf->pool, paths ? paths->nelts : 3, |
4241 sizeof(ngx_ssl_session_ticket_key_t)); | 4309 sizeof(ngx_ssl_ticket_key_t)); |
4242 if (keys == NULL) { | 4310 if (keys == NULL) { |
4243 return NGX_ERROR; | 4311 return NGX_ERROR; |
4244 } | 4312 } |
4245 | 4313 |
4246 cln = ngx_pool_cleanup_add(cf->pool, 0); | 4314 cln = ngx_pool_cleanup_add(cf->pool, 0); |
4247 if (cln == NULL) { | 4315 if (cln == NULL) { |
4248 return NGX_ERROR; | 4316 return NGX_ERROR; |
4249 } | 4317 } |
4250 | 4318 |
4251 cln->handler = ngx_ssl_session_ticket_keys_cleanup; | 4319 cln->handler = ngx_ssl_ticket_keys_cleanup; |
4252 cln->data = keys; | 4320 cln->data = keys; |
4253 | 4321 |
4254 path = paths->elts; | 4322 if (SSL_CTX_set_ex_data(ssl->ctx, ngx_ssl_ticket_keys_index, keys) == 0) { |
4255 for (i = 0; i < paths->nelts; i++) { | |
4256 | |
4257 if (ngx_conf_full_name(cf->cycle, &path[i], 1) != NGX_OK) { | |
4258 return NGX_ERROR; | |
4259 } | |
4260 | |
4261 ngx_memzero(&file, sizeof(ngx_file_t)); | |
4262 file.name = path[i]; | |
4263 file.log = cf->log; | |
4264 | |
4265 file.fd = ngx_open_file(file.name.data, NGX_FILE_RDONLY, | |
4266 NGX_FILE_OPEN, 0); | |
4267 | |
4268 if (file.fd == NGX_INVALID_FILE) { | |
4269 ngx_conf_log_error(NGX_LOG_EMERG, cf, ngx_errno, | |
4270 ngx_open_file_n " \"%V\" failed", &file.name); | |
4271 return NGX_ERROR; | |
4272 } | |
4273 | |
4274 if (ngx_fd_info(file.fd, &fi) == NGX_FILE_ERROR) { | |
4275 ngx_conf_log_error(NGX_LOG_CRIT, cf, ngx_errno, | |
4276 ngx_fd_info_n " \"%V\" failed", &file.name); | |
4277 goto failed; | |
4278 } | |
4279 | |
4280 size = ngx_file_size(&fi); | |
4281 | |
4282 if (size != 48 && size != 80) { | |
4283 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, | |
4284 "\"%V\" must be 48 or 80 bytes", &file.name); | |
4285 goto failed; | |
4286 } | |
4287 | |
4288 n = ngx_read_file(&file, buf, size, 0); | |
4289 | |
4290 if (n == NGX_ERROR) { | |
4291 ngx_conf_log_error(NGX_LOG_CRIT, cf, ngx_errno, | |
4292 ngx_read_file_n " \"%V\" failed", &file.name); | |
4293 goto failed; | |
4294 } | |
4295 | |
4296 if ((size_t) n != size) { | |
4297 ngx_conf_log_error(NGX_LOG_CRIT, cf, 0, | |
4298 ngx_read_file_n " \"%V\" returned only " | |
4299 "%z bytes instead of %uz", &file.name, n, size); | |
4300 goto failed; | |
4301 } | |
4302 | |
4303 key = ngx_array_push(keys); | |
4304 if (key == NULL) { | |
4305 goto failed; | |
4306 } | |
4307 | |
4308 if (size == 48) { | |
4309 key->size = 48; | |
4310 ngx_memcpy(key->name, buf, 16); | |
4311 ngx_memcpy(key->aes_key, buf + 16, 16); | |
4312 ngx_memcpy(key->hmac_key, buf + 32, 16); | |
4313 | |
4314 } else { | |
4315 key->size = 80; | |
4316 ngx_memcpy(key->name, buf, 16); | |
4317 ngx_memcpy(key->hmac_key, buf + 16, 32); | |
4318 ngx_memcpy(key->aes_key, buf + 48, 32); | |
4319 } | |
4320 | |
4321 if (ngx_close_file(file.fd) == NGX_FILE_ERROR) { | |
4322 ngx_log_error(NGX_LOG_ALERT, cf->log, ngx_errno, | |
4323 ngx_close_file_n " \"%V\" failed", &file.name); | |
4324 } | |
4325 | |
4326 ngx_explicit_memzero(&buf, 80); | |
4327 } | |
4328 | |
4329 if (SSL_CTX_set_ex_data(ssl->ctx, ngx_ssl_session_ticket_keys_index, keys) | |
4330 == 0) | |
4331 { | |
4332 ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0, | 4323 ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0, |
4333 "SSL_CTX_set_ex_data() failed"); | 4324 "SSL_CTX_set_ex_data() failed"); |
4334 return NGX_ERROR; | 4325 return NGX_ERROR; |
4335 } | 4326 } |
4336 | 4327 |
4337 if (SSL_CTX_set_tlsext_ticket_key_cb(ssl->ctx, | 4328 if (SSL_CTX_set_tlsext_ticket_key_cb(ssl->ctx, ngx_ssl_ticket_key_callback) |
4338 ngx_ssl_session_ticket_key_callback) | |
4339 == 0) | 4329 == 0) |
4340 { | 4330 { |
4341 ngx_log_error(NGX_LOG_WARN, cf->log, 0, | 4331 ngx_log_error(NGX_LOG_WARN, cf->log, 0, |
4342 "nginx was built with Session Tickets support, however, " | 4332 "nginx was built with Session Tickets support, however, " |
4343 "now it is linked dynamically to an OpenSSL library " | 4333 "now it is linked dynamically to an OpenSSL library " |
4344 "which has no tlsext support, therefore Session Tickets " | 4334 "which has no tlsext support, therefore Session Tickets " |
4345 "are not available"); | 4335 "are not available"); |
4336 return NGX_OK; | |
4337 } | |
4338 | |
4339 if (paths == NULL) { | |
4340 | |
4341 /* placeholder for keys in shared memory */ | |
4342 | |
4343 key = ngx_array_push_n(keys, 3); | |
4344 key[0].shared = 1; | |
4345 key[0].expire = 0; | |
4346 key[1].shared = 1; | |
4347 key[1].expire = 0; | |
4348 key[2].shared = 1; | |
4349 key[2].expire = 0; | |
4350 | |
4351 return NGX_OK; | |
4352 } | |
4353 | |
4354 path = paths->elts; | |
4355 for (i = 0; i < paths->nelts; i++) { | |
4356 | |
4357 if (ngx_conf_full_name(cf->cycle, &path[i], 1) != NGX_OK) { | |
4358 return NGX_ERROR; | |
4359 } | |
4360 | |
4361 ngx_memzero(&file, sizeof(ngx_file_t)); | |
4362 file.name = path[i]; | |
4363 file.log = cf->log; | |
4364 | |
4365 file.fd = ngx_open_file(file.name.data, NGX_FILE_RDONLY, | |
4366 NGX_FILE_OPEN, 0); | |
4367 | |
4368 if (file.fd == NGX_INVALID_FILE) { | |
4369 ngx_conf_log_error(NGX_LOG_EMERG, cf, ngx_errno, | |
4370 ngx_open_file_n " \"%V\" failed", &file.name); | |
4371 return NGX_ERROR; | |
4372 } | |
4373 | |
4374 if (ngx_fd_info(file.fd, &fi) == NGX_FILE_ERROR) { | |
4375 ngx_conf_log_error(NGX_LOG_CRIT, cf, ngx_errno, | |
4376 ngx_fd_info_n " \"%V\" failed", &file.name); | |
4377 goto failed; | |
4378 } | |
4379 | |
4380 size = ngx_file_size(&fi); | |
4381 | |
4382 if (size != 48 && size != 80) { | |
4383 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, | |
4384 "\"%V\" must be 48 or 80 bytes", &file.name); | |
4385 goto failed; | |
4386 } | |
4387 | |
4388 n = ngx_read_file(&file, buf, size, 0); | |
4389 | |
4390 if (n == NGX_ERROR) { | |
4391 ngx_conf_log_error(NGX_LOG_CRIT, cf, ngx_errno, | |
4392 ngx_read_file_n " \"%V\" failed", &file.name); | |
4393 goto failed; | |
4394 } | |
4395 | |
4396 if ((size_t) n != size) { | |
4397 ngx_conf_log_error(NGX_LOG_CRIT, cf, 0, | |
4398 ngx_read_file_n " \"%V\" returned only " | |
4399 "%z bytes instead of %uz", &file.name, n, size); | |
4400 goto failed; | |
4401 } | |
4402 | |
4403 key = ngx_array_push(keys); | |
4404 if (key == NULL) { | |
4405 goto failed; | |
4406 } | |
4407 | |
4408 key->shared = 0; | |
4409 key->expire = 1; | |
4410 | |
4411 if (size == 48) { | |
4412 key->size = 48; | |
4413 ngx_memcpy(key->name, buf, 16); | |
4414 ngx_memcpy(key->aes_key, buf + 16, 16); | |
4415 ngx_memcpy(key->hmac_key, buf + 32, 16); | |
4416 | |
4417 } else { | |
4418 key->size = 80; | |
4419 ngx_memcpy(key->name, buf, 16); | |
4420 ngx_memcpy(key->hmac_key, buf + 16, 32); | |
4421 ngx_memcpy(key->aes_key, buf + 48, 32); | |
4422 } | |
4423 | |
4424 if (ngx_close_file(file.fd) == NGX_FILE_ERROR) { | |
4425 ngx_log_error(NGX_LOG_ALERT, cf->log, ngx_errno, | |
4426 ngx_close_file_n " \"%V\" failed", &file.name); | |
4427 } | |
4428 | |
4429 ngx_explicit_memzero(&buf, 80); | |
4346 } | 4430 } |
4347 | 4431 |
4348 return NGX_OK; | 4432 return NGX_OK; |
4349 | 4433 |
4350 failed: | 4434 failed: |
4359 return NGX_ERROR; | 4443 return NGX_ERROR; |
4360 } | 4444 } |
4361 | 4445 |
4362 | 4446 |
4363 static int | 4447 static int |
4364 ngx_ssl_session_ticket_key_callback(ngx_ssl_conn_t *ssl_conn, | 4448 ngx_ssl_ticket_key_callback(ngx_ssl_conn_t *ssl_conn, |
4365 unsigned char *name, unsigned char *iv, EVP_CIPHER_CTX *ectx, | 4449 unsigned char *name, unsigned char *iv, EVP_CIPHER_CTX *ectx, |
4366 HMAC_CTX *hctx, int enc) | 4450 HMAC_CTX *hctx, int enc) |
4367 { | 4451 { |
4368 size_t size; | 4452 size_t size; |
4369 SSL_CTX *ssl_ctx; | 4453 SSL_CTX *ssl_ctx; |
4370 ngx_uint_t i; | 4454 ngx_uint_t i; |
4371 ngx_array_t *keys; | 4455 ngx_array_t *keys; |
4372 ngx_connection_t *c; | 4456 ngx_connection_t *c; |
4373 ngx_ssl_session_ticket_key_t *key; | 4457 ngx_ssl_ticket_key_t *key; |
4374 const EVP_MD *digest; | 4458 const EVP_MD *digest; |
4375 const EVP_CIPHER *cipher; | 4459 const EVP_CIPHER *cipher; |
4376 | 4460 |
4377 c = ngx_ssl_get_connection(ssl_conn); | 4461 c = ngx_ssl_get_connection(ssl_conn); |
4378 ssl_ctx = c->ssl->session_ctx; | 4462 ssl_ctx = c->ssl->session_ctx; |
4463 | |
4464 if (ngx_ssl_rotate_ticket_keys(ssl_ctx, c->log) != NGX_OK) { | |
4465 return -1; | |
4466 } | |
4379 | 4467 |
4380 #ifdef OPENSSL_NO_SHA256 | 4468 #ifdef OPENSSL_NO_SHA256 |
4381 digest = EVP_sha1(); | 4469 digest = EVP_sha1(); |
4382 #else | 4470 #else |
4383 digest = EVP_sha256(); | 4471 digest = EVP_sha256(); |
4384 #endif | 4472 #endif |
4385 | 4473 |
4386 keys = SSL_CTX_get_ex_data(ssl_ctx, ngx_ssl_session_ticket_keys_index); | 4474 keys = SSL_CTX_get_ex_data(ssl_ctx, ngx_ssl_ticket_keys_index); |
4387 if (keys == NULL) { | 4475 if (keys == NULL) { |
4388 return -1; | 4476 return -1; |
4389 } | 4477 } |
4390 | 4478 |
4391 key = keys->elts; | 4479 key = keys->elts; |
4392 | 4480 |
4393 if (enc == 1) { | 4481 if (enc == 1) { |
4394 /* encrypt session ticket */ | 4482 /* encrypt session ticket */ |
4395 | 4483 |
4396 ngx_log_debug3(NGX_LOG_DEBUG_EVENT, c->log, 0, | 4484 ngx_log_debug3(NGX_LOG_DEBUG_EVENT, c->log, 0, |
4397 "ssl session ticket encrypt, key: \"%*xs\" (%s session)", | 4485 "ssl ticket encrypt, key: \"%*xs\" (%s session)", |
4398 (size_t) 16, key[0].name, | 4486 (size_t) 16, key[0].name, |
4399 SSL_session_reused(ssl_conn) ? "reused" : "new"); | 4487 SSL_session_reused(ssl_conn) ? "reused" : "new"); |
4400 | 4488 |
4401 if (key[0].size == 48) { | 4489 if (key[0].size == 48) { |
4402 cipher = EVP_aes_128_cbc(); | 4490 cipher = EVP_aes_128_cbc(); |
4439 goto found; | 4527 goto found; |
4440 } | 4528 } |
4441 } | 4529 } |
4442 | 4530 |
4443 ngx_log_debug2(NGX_LOG_DEBUG_EVENT, c->log, 0, | 4531 ngx_log_debug2(NGX_LOG_DEBUG_EVENT, c->log, 0, |
4444 "ssl session ticket decrypt, key: \"%*xs\" not found", | 4532 "ssl ticket decrypt, key: \"%*xs\" not found", |
4445 (size_t) 16, name); | 4533 (size_t) 16, name); |
4446 | 4534 |
4447 return 0; | 4535 return 0; |
4448 | 4536 |
4449 found: | 4537 found: |
4450 | 4538 |
4451 ngx_log_debug3(NGX_LOG_DEBUG_EVENT, c->log, 0, | 4539 ngx_log_debug3(NGX_LOG_DEBUG_EVENT, c->log, 0, |
4452 "ssl session ticket decrypt, key: \"%*xs\"%s", | 4540 "ssl ticket decrypt, key: \"%*xs\"%s", |
4453 (size_t) 16, key[i].name, (i == 0) ? " (default)" : ""); | 4541 (size_t) 16, key[i].name, (i == 0) ? " (default)" : ""); |
4454 | 4542 |
4455 if (key[i].size == 48) { | 4543 if (key[i].size == 48) { |
4456 cipher = EVP_aes_128_cbc(); | 4544 cipher = EVP_aes_128_cbc(); |
4457 size = 16; | 4545 size = 16; |
4484 } | 4572 } |
4485 #endif | 4573 #endif |
4486 | 4574 |
4487 /* renew if non-default key */ | 4575 /* renew if non-default key */ |
4488 | 4576 |
4489 if (i != 0) { | 4577 if (i != 0 && key[i].expire) { |
4490 return 2; | 4578 return 2; |
4491 } | 4579 } |
4492 | 4580 |
4493 return 1; | 4581 return 1; |
4494 } | 4582 } |
4495 } | 4583 } |
4496 | 4584 |
4497 | 4585 |
4586 static ngx_int_t | |
4587 ngx_ssl_rotate_ticket_keys(SSL_CTX *ssl_ctx, ngx_log_t *log) | |
4588 { | |
4589 time_t now, expire; | |
4590 ngx_array_t *keys; | |
4591 ngx_shm_zone_t *shm_zone; | |
4592 ngx_slab_pool_t *shpool; | |
4593 ngx_ssl_ticket_key_t *key; | |
4594 ngx_ssl_session_cache_t *cache; | |
4595 u_char buf[80]; | |
4596 | |
4597 keys = SSL_CTX_get_ex_data(ssl_ctx, ngx_ssl_ticket_keys_index); | |
4598 if (keys == NULL) { | |
4599 return NGX_OK; | |
4600 } | |
4601 | |
4602 key = keys->elts; | |
4603 | |
4604 if (!key[0].shared) { | |
4605 return NGX_OK; | |
4606 } | |
4607 | |
4608 /* | |
4609 * if we don't need to update expiration of the current key | |
4610 * and the previous key is still needed, don't sync with shared | |
4611 * memory to save some work; in the worst case other worker process | |
4612 * will switch to the next key, but this process will still be able | |
4613 * to decrypt tickets encrypted with it | |
4614 */ | |
4615 | |
4616 now = ngx_time(); | |
4617 expire = now + SSL_CTX_get_timeout(ssl_ctx); | |
4618 | |
4619 if (key[0].expire >= expire && key[1].expire >= now) { | |
4620 return NGX_OK; | |
4621 } | |
4622 | |
4623 shm_zone = SSL_CTX_get_ex_data(ssl_ctx, ngx_ssl_session_cache_index); | |
4624 | |
4625 cache = shm_zone->data; | |
4626 shpool = (ngx_slab_pool_t *) shm_zone->shm.addr; | |
4627 | |
4628 ngx_shmtx_lock(&shpool->mutex); | |
4629 | |
4630 key = cache->ticket_keys; | |
4631 | |
4632 if (key[0].expire == 0) { | |
4633 | |
4634 /* initialize the current key */ | |
4635 | |
4636 if (RAND_bytes(buf, 80) != 1) { | |
4637 ngx_ssl_error(NGX_LOG_ALERT, log, 0, "RAND_bytes() failed"); | |
4638 ngx_shmtx_unlock(&shpool->mutex); | |
4639 return NGX_ERROR; | |
4640 } | |
4641 | |
4642 key[0].shared = 1; | |
4643 key[0].expire = expire; | |
4644 key[0].size = 80; | |
4645 ngx_memcpy(key[0].name, buf, 16); | |
4646 ngx_memcpy(key[0].hmac_key, buf + 16, 32); | |
4647 ngx_memcpy(key[0].aes_key, buf + 48, 32); | |
4648 | |
4649 ngx_explicit_memzero(&buf, 80); | |
4650 | |
4651 ngx_log_debug2(NGX_LOG_DEBUG_EVENT, log, 0, | |
4652 "ssl ticket key: \"%*xs\"", | |
4653 (size_t) 16, key[0].name); | |
4654 | |
4655 /* | |
4656 * copy the current key to the next key, as initialization of | |
4657 * the previous key will replace the current key with the next | |
4658 * key | |
4659 */ | |
4660 | |
4661 key[2] = key[0]; | |
4662 } | |
4663 | |
4664 if (key[1].expire < now) { | |
4665 | |
4666 /* | |
4667 * if the previous key is no longer needed (or not initialized), | |
4668 * replace it with the current key, replace the current key with | |
4669 * the next key, and generate new next key | |
4670 */ | |
4671 | |
4672 key[1] = key[0]; | |
4673 key[0] = key[2]; | |
4674 | |
4675 if (RAND_bytes(buf, 80) != 1) { | |
4676 ngx_ssl_error(NGX_LOG_ALERT, log, 0, "RAND_bytes() failed"); | |
4677 ngx_shmtx_unlock(&shpool->mutex); | |
4678 return NGX_ERROR; | |
4679 } | |
4680 | |
4681 key[2].shared = 1; | |
4682 key[2].expire = 0; | |
4683 key[2].size = 80; | |
4684 ngx_memcpy(key[2].name, buf, 16); | |
4685 ngx_memcpy(key[2].hmac_key, buf + 16, 32); | |
4686 ngx_memcpy(key[2].aes_key, buf + 48, 32); | |
4687 | |
4688 ngx_explicit_memzero(&buf, 80); | |
4689 | |
4690 ngx_log_debug2(NGX_LOG_DEBUG_EVENT, log, 0, | |
4691 "ssl ticket key: \"%*xs\"", | |
4692 (size_t) 16, key[2].name); | |
4693 } | |
4694 | |
4695 /* | |
4696 * update expiration of the current key: it is going to be needed | |
4697 * at least till the session being created expires | |
4698 */ | |
4699 | |
4700 if (expire > key[0].expire) { | |
4701 key[0].expire = expire; | |
4702 } | |
4703 | |
4704 /* sync keys to the worker process memory */ | |
4705 | |
4706 ngx_memcpy(keys->elts, cache->ticket_keys, | |
4707 2 * sizeof(ngx_ssl_ticket_key_t)); | |
4708 | |
4709 ngx_shmtx_unlock(&shpool->mutex); | |
4710 | |
4711 return NGX_OK; | |
4712 } | |
4713 | |
4714 | |
4498 static void | 4715 static void |
4499 ngx_ssl_session_ticket_keys_cleanup(void *data) | 4716 ngx_ssl_ticket_keys_cleanup(void *data) |
4500 { | 4717 { |
4501 ngx_array_t *keys = data; | 4718 ngx_array_t *keys = data; |
4502 | 4719 |
4503 ngx_explicit_memzero(keys->elts, | 4720 ngx_explicit_memzero(keys->elts, |
4504 keys->nelts * sizeof(ngx_ssl_session_ticket_key_t)); | 4721 keys->nelts * sizeof(ngx_ssl_ticket_key_t)); |
4505 } | 4722 } |
4506 | 4723 |
4507 #else | 4724 #else |
4508 | 4725 |
4509 ngx_int_t | 4726 ngx_int_t |