comparison src/event/ngx_event_openssl.c @ 9035: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
9034:79cd6993a3e3 9035: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