xref: /unit/src/nxt_openssl.c (revision 771)
10Sigor@sysoev.ru 
20Sigor@sysoev.ru /*
30Sigor@sysoev.ru  * Copyright (C) Igor Sysoev
40Sigor@sysoev.ru  * Copyright (C) NGINX, Inc.
50Sigor@sysoev.ru  */
60Sigor@sysoev.ru 
70Sigor@sysoev.ru #include <nxt_main.h>
80Sigor@sysoev.ru #include <openssl/ssl.h>
90Sigor@sysoev.ru #include <openssl/conf.h>
100Sigor@sysoev.ru #include <openssl/err.h>
110Sigor@sysoev.ru 
120Sigor@sysoev.ru 
130Sigor@sysoev.ru typedef struct {
140Sigor@sysoev.ru     SSL            *session;
15*771Sigor@sysoev.ru     nxt_conn_t     *conn;
160Sigor@sysoev.ru 
170Sigor@sysoev.ru     int            ssl_error;
180Sigor@sysoev.ru     uint8_t        times;      /* 2 bits */
19*771Sigor@sysoev.ru     uint8_t        handshake;  /* 1 bit  */
200Sigor@sysoev.ru 
210Sigor@sysoev.ru     nxt_buf_mem_t  buffer;
220Sigor@sysoev.ru } nxt_openssl_conn_t;
230Sigor@sysoev.ru 
240Sigor@sysoev.ru 
25*771Sigor@sysoev.ru typedef enum {
26*771Sigor@sysoev.ru     NXT_OPENSSL_HANDSHAKE = 0,
27*771Sigor@sysoev.ru     NXT_OPENSSL_READ,
28*771Sigor@sysoev.ru     NXT_OPENSSL_WRITE,
29*771Sigor@sysoev.ru     NXT_OPENSSL_SHUTDOWN,
30*771Sigor@sysoev.ru } nxt_openssl_io_t;
31*771Sigor@sysoev.ru 
320Sigor@sysoev.ru 
33*771Sigor@sysoev.ru static nxt_int_t nxt_openssl_library_init(nxt_task_t *task);
34*771Sigor@sysoev.ru static void nxt_openssl_library_free(nxt_task_t *task);
35*771Sigor@sysoev.ru #if OPENSSL_VERSION_NUMBER < 0x10100004L
36*771Sigor@sysoev.ru static nxt_int_t nxt_openssl_locks_init(void);
37*771Sigor@sysoev.ru static void nxt_openssl_lock(int mode, int type, const char *file, int line);
38*771Sigor@sysoev.ru static unsigned long nxt_openssl_thread_id(void);
39*771Sigor@sysoev.ru static void nxt_openssl_locks_free(void);
40*771Sigor@sysoev.ru #endif
41*771Sigor@sysoev.ru static nxt_int_t nxt_openssl_server_init(nxt_task_t *task,
42*771Sigor@sysoev.ru     nxt_tls_conf_t *conf);
43*771Sigor@sysoev.ru static void nxt_openssl_server_free(nxt_task_t *task, nxt_tls_conf_t *conf);
44*771Sigor@sysoev.ru static void nxt_openssl_conn_init(nxt_task_t *task, nxt_tls_conf_t *conf,
4562Sigor@sysoev.ru     nxt_conn_t *c);
461Sigor@sysoev.ru static void nxt_openssl_conn_handshake(nxt_task_t *task, void *obj, void *data);
47*771Sigor@sysoev.ru static ssize_t nxt_openssl_conn_io_recvbuf(nxt_conn_t *c, nxt_buf_t *b);
48*771Sigor@sysoev.ru static ssize_t nxt_openssl_conn_io_sendbuf(nxt_task_t *task, nxt_sendbuf_t *sb);
49*771Sigor@sysoev.ru static ssize_t nxt_openssl_conn_io_send(nxt_task_t *task, nxt_sendbuf_t *sb,
50*771Sigor@sysoev.ru     void *buf, size_t size);
511Sigor@sysoev.ru static void nxt_openssl_conn_io_shutdown(nxt_task_t *task, void *obj,
520Sigor@sysoev.ru     void *data);
53*771Sigor@sysoev.ru static nxt_int_t nxt_openssl_conn_test_error(nxt_task_t *task, nxt_conn_t *c,
54*771Sigor@sysoev.ru     int ret, nxt_err_t sys_err, nxt_openssl_io_t io);
55*771Sigor@sysoev.ru static void nxt_cdecl nxt_openssl_conn_error(nxt_task_t *task,
56*771Sigor@sysoev.ru     nxt_err_t err, const char *fmt, ...);
57*771Sigor@sysoev.ru static nxt_uint_t nxt_openssl_log_error_level(nxt_err_t err);
580Sigor@sysoev.ru 
590Sigor@sysoev.ru 
60*771Sigor@sysoev.ru const nxt_tls_lib_t  nxt_openssl_lib = {
61*771Sigor@sysoev.ru     .library_init = nxt_openssl_library_init,
62*771Sigor@sysoev.ru     .library_free = nxt_openssl_library_free,
63*771Sigor@sysoev.ru 
64*771Sigor@sysoev.ru     .server_init = nxt_openssl_server_init,
65*771Sigor@sysoev.ru     .server_free = nxt_openssl_server_free,
660Sigor@sysoev.ru };
670Sigor@sysoev.ru 
680Sigor@sysoev.ru 
6962Sigor@sysoev.ru static nxt_conn_io_t  nxt_openssl_conn_io = {
70*771Sigor@sysoev.ru     .read = nxt_conn_io_read,
71*771Sigor@sysoev.ru     .recvbuf = nxt_openssl_conn_io_recvbuf,
720Sigor@sysoev.ru 
73*771Sigor@sysoev.ru     .write = nxt_conn_io_write,
74*771Sigor@sysoev.ru     .sendbuf = nxt_openssl_conn_io_sendbuf,
750Sigor@sysoev.ru 
76*771Sigor@sysoev.ru     .shutdown = nxt_openssl_conn_io_shutdown,
770Sigor@sysoev.ru };
780Sigor@sysoev.ru 
790Sigor@sysoev.ru 
800Sigor@sysoev.ru static long  nxt_openssl_version;
810Sigor@sysoev.ru static int   nxt_openssl_connection_index;
820Sigor@sysoev.ru 
830Sigor@sysoev.ru 
840Sigor@sysoev.ru static nxt_int_t
85*771Sigor@sysoev.ru nxt_openssl_library_init(nxt_task_t *task)
860Sigor@sysoev.ru {
870Sigor@sysoev.ru     int  index;
880Sigor@sysoev.ru 
890Sigor@sysoev.ru     if (nxt_fast_path(nxt_openssl_version != 0)) {
900Sigor@sysoev.ru         return NXT_OK;
910Sigor@sysoev.ru     }
920Sigor@sysoev.ru 
93*771Sigor@sysoev.ru #if OPENSSL_VERSION_NUMBER >= 0x10100003L
94*771Sigor@sysoev.ru 
95*771Sigor@sysoev.ru     OPENSSL_init_ssl(OPENSSL_INIT_LOAD_CONFIG, NULL);
960Sigor@sysoev.ru 
97*771Sigor@sysoev.ru #else
98*771Sigor@sysoev.ru     {
99*771Sigor@sysoev.ru         nxt_int_t  ret;
100*771Sigor@sysoev.ru 
101*771Sigor@sysoev.ru         SSL_load_error_strings();
102*771Sigor@sysoev.ru 
103*771Sigor@sysoev.ru         OPENSSL_config(NULL);
1040Sigor@sysoev.ru 
105*771Sigor@sysoev.ru         /*
106*771Sigor@sysoev.ru          * SSL_library_init(3):
107*771Sigor@sysoev.ru          *
108*771Sigor@sysoev.ru          *   SSL_library_init() always returns "1",
109*771Sigor@sysoev.ru          *   so it is safe to discard the return value.
110*771Sigor@sysoev.ru          */
111*771Sigor@sysoev.ru         (void) SSL_library_init();
112*771Sigor@sysoev.ru 
113*771Sigor@sysoev.ru         ret = nxt_openssl_locks_init();
114*771Sigor@sysoev.ru         if (nxt_slow_path(ret != NXT_OK)) {
115*771Sigor@sysoev.ru             return ret;
116*771Sigor@sysoev.ru         }
117*771Sigor@sysoev.ru     }
118*771Sigor@sysoev.ru 
119*771Sigor@sysoev.ru #endif
1200Sigor@sysoev.ru 
1210Sigor@sysoev.ru     nxt_openssl_version = SSLeay();
1220Sigor@sysoev.ru 
123*771Sigor@sysoev.ru     nxt_log(task, NXT_LOG_INFO, "%s, %xl",
124*771Sigor@sysoev.ru             SSLeay_version(SSLEAY_VERSION), nxt_openssl_version);
1250Sigor@sysoev.ru 
1260Sigor@sysoev.ru #ifndef SSL_OP_NO_COMPRESSION
1270Sigor@sysoev.ru     {
1280Sigor@sysoev.ru         /*
1290Sigor@sysoev.ru          * Disable gzip compression in OpenSSL prior to 1.0.0
1300Sigor@sysoev.ru          * version, this saves about 522K per connection.
1310Sigor@sysoev.ru          */
1320Sigor@sysoev.ru         int                 n;
1330Sigor@sysoev.ru         STACK_OF(SSL_COMP)  *ssl_comp_methods;
1340Sigor@sysoev.ru 
1350Sigor@sysoev.ru         ssl_comp_methods = SSL_COMP_get_compression_methods();
1360Sigor@sysoev.ru 
1370Sigor@sysoev.ru         for (n = sk_SSL_COMP_num(ssl_comp_methods); n != 0; n--) {
1380Sigor@sysoev.ru             (void) sk_SSL_COMP_pop(ssl_comp_methods);
1390Sigor@sysoev.ru         }
1400Sigor@sysoev.ru     }
1410Sigor@sysoev.ru #endif
1420Sigor@sysoev.ru 
1430Sigor@sysoev.ru     index = SSL_get_ex_new_index(0, NULL, NULL, NULL, NULL);
1440Sigor@sysoev.ru 
1450Sigor@sysoev.ru     if (index == -1) {
146*771Sigor@sysoev.ru         nxt_openssl_log_error(task, NXT_LOG_ALERT,
1470Sigor@sysoev.ru                               "SSL_get_ex_new_index() failed");
1480Sigor@sysoev.ru         return NXT_ERROR;
1490Sigor@sysoev.ru     }
1500Sigor@sysoev.ru 
1510Sigor@sysoev.ru     nxt_openssl_connection_index = index;
1520Sigor@sysoev.ru 
1530Sigor@sysoev.ru     return NXT_OK;
1540Sigor@sysoev.ru }
1550Sigor@sysoev.ru 
1560Sigor@sysoev.ru 
157*771Sigor@sysoev.ru #if OPENSSL_VERSION_NUMBER >= 0x10100003L
158*771Sigor@sysoev.ru 
159*771Sigor@sysoev.ru static void
160*771Sigor@sysoev.ru nxt_openssl_library_free(nxt_task_t *task)
161*771Sigor@sysoev.ru {
162*771Sigor@sysoev.ru }
163*771Sigor@sysoev.ru 
164*771Sigor@sysoev.ru #else
165*771Sigor@sysoev.ru 
166*771Sigor@sysoev.ru static nxt_thread_mutex_t  *nxt_openssl_locks;
167*771Sigor@sysoev.ru 
1680Sigor@sysoev.ru static nxt_int_t
169*771Sigor@sysoev.ru nxt_openssl_locks_init(void)
170*771Sigor@sysoev.ru {
171*771Sigor@sysoev.ru     int        i, n;
172*771Sigor@sysoev.ru     nxt_int_t  ret;
173*771Sigor@sysoev.ru 
174*771Sigor@sysoev.ru     n = CRYPTO_num_locks();
175*771Sigor@sysoev.ru 
176*771Sigor@sysoev.ru     nxt_openssl_locks = OPENSSL_malloc(n * sizeof(nxt_thread_mutex_t));
177*771Sigor@sysoev.ru     if (nxt_slow_path(nxt_openssl_locks == NULL)) {
178*771Sigor@sysoev.ru         return NXT_ERROR;
179*771Sigor@sysoev.ru     }
180*771Sigor@sysoev.ru 
181*771Sigor@sysoev.ru     for (i = 0; i < n; i++) {
182*771Sigor@sysoev.ru         ret = nxt_thread_mutex_create(&nxt_openssl_locks[i]);
183*771Sigor@sysoev.ru         if (nxt_slow_path(ret != NXT_OK)) {
184*771Sigor@sysoev.ru             return ret;
185*771Sigor@sysoev.ru         }
186*771Sigor@sysoev.ru     }
187*771Sigor@sysoev.ru 
188*771Sigor@sysoev.ru     CRYPTO_set_locking_callback(nxt_openssl_lock);
189*771Sigor@sysoev.ru 
190*771Sigor@sysoev.ru     CRYPTO_set_id_callback(nxt_openssl_thread_id);
191*771Sigor@sysoev.ru 
192*771Sigor@sysoev.ru     return NXT_OK;
193*771Sigor@sysoev.ru }
194*771Sigor@sysoev.ru 
195*771Sigor@sysoev.ru 
196*771Sigor@sysoev.ru static void
197*771Sigor@sysoev.ru nxt_openssl_lock(int mode, int type, const char *file, int line)
198*771Sigor@sysoev.ru {
199*771Sigor@sysoev.ru     nxt_thread_mutex_t  *lock;
200*771Sigor@sysoev.ru 
201*771Sigor@sysoev.ru     lock = &nxt_openssl_locks[type];
202*771Sigor@sysoev.ru 
203*771Sigor@sysoev.ru     if ((mode & CRYPTO_LOCK) != 0) {
204*771Sigor@sysoev.ru         (void) nxt_thread_mutex_lock(lock);
205*771Sigor@sysoev.ru 
206*771Sigor@sysoev.ru     } else {
207*771Sigor@sysoev.ru         (void) nxt_thread_mutex_unlock(lock);
208*771Sigor@sysoev.ru     }
209*771Sigor@sysoev.ru }
210*771Sigor@sysoev.ru 
211*771Sigor@sysoev.ru 
212*771Sigor@sysoev.ru static u_long
213*771Sigor@sysoev.ru nxt_openssl_thread_id(void)
214*771Sigor@sysoev.ru {
215*771Sigor@sysoev.ru     return (u_long) nxt_thread_handle();
216*771Sigor@sysoev.ru }
217*771Sigor@sysoev.ru 
218*771Sigor@sysoev.ru 
219*771Sigor@sysoev.ru static void
220*771Sigor@sysoev.ru nxt_openssl_library_free(nxt_task_t *task)
221*771Sigor@sysoev.ru {
222*771Sigor@sysoev.ru     nxt_openssl_locks_free();
223*771Sigor@sysoev.ru }
224*771Sigor@sysoev.ru 
225*771Sigor@sysoev.ru 
226*771Sigor@sysoev.ru static void
227*771Sigor@sysoev.ru nxt_openssl_locks_free(void)
228*771Sigor@sysoev.ru {
229*771Sigor@sysoev.ru     int  i, n;
230*771Sigor@sysoev.ru 
231*771Sigor@sysoev.ru     n = CRYPTO_num_locks();
232*771Sigor@sysoev.ru 
233*771Sigor@sysoev.ru     CRYPTO_set_locking_callback(NULL);
234*771Sigor@sysoev.ru 
235*771Sigor@sysoev.ru     for (i = 0; i < n; i++) {
236*771Sigor@sysoev.ru         nxt_thread_mutex_destroy(&nxt_openssl_locks[i]);
237*771Sigor@sysoev.ru     }
238*771Sigor@sysoev.ru 
239*771Sigor@sysoev.ru     OPENSSL_free(nxt_openssl_locks);
240*771Sigor@sysoev.ru }
241*771Sigor@sysoev.ru 
242*771Sigor@sysoev.ru #endif
243*771Sigor@sysoev.ru 
244*771Sigor@sysoev.ru 
245*771Sigor@sysoev.ru static nxt_int_t
246*771Sigor@sysoev.ru nxt_openssl_server_init(nxt_task_t *task, nxt_tls_conf_t *conf)
2470Sigor@sysoev.ru {
2480Sigor@sysoev.ru     SSL_CTX              *ctx;
2490Sigor@sysoev.ru     const char           *certificate, *key, *ciphers, *ca_certificate;
2500Sigor@sysoev.ru     STACK_OF(X509_NAME)  *list;
2510Sigor@sysoev.ru 
2520Sigor@sysoev.ru     ctx = SSL_CTX_new(SSLv23_server_method());
2530Sigor@sysoev.ru     if (ctx == NULL) {
254*771Sigor@sysoev.ru         nxt_openssl_log_error(task, NXT_LOG_ALERT, "SSL_CTX_new() failed");
2550Sigor@sysoev.ru         return NXT_ERROR;
2560Sigor@sysoev.ru     }
2570Sigor@sysoev.ru 
2580Sigor@sysoev.ru     conf->ctx = ctx;
2590Sigor@sysoev.ru     conf->conn_init = nxt_openssl_conn_init;
2600Sigor@sysoev.ru 
261*771Sigor@sysoev.ru #ifdef SSL_OP_NO_RENEGOTIATION
262*771Sigor@sysoev.ru     /* Renegration is not currently supported. */
263*771Sigor@sysoev.ru     SSL_CTX_set_options(ctx, SSL_OP_NO_RENEGOTIATION);
264*771Sigor@sysoev.ru #endif
265*771Sigor@sysoev.ru 
2660Sigor@sysoev.ru #ifdef SSL_OP_NO_COMPRESSION
2670Sigor@sysoev.ru     /*
2680Sigor@sysoev.ru      * Disable gzip compression in OpenSSL 1.0.0,
2690Sigor@sysoev.ru      * this saves about 522K per connection.
2700Sigor@sysoev.ru      */
2710Sigor@sysoev.ru     SSL_CTX_set_options(ctx, SSL_OP_NO_COMPRESSION);
2720Sigor@sysoev.ru #endif
2730Sigor@sysoev.ru 
2740Sigor@sysoev.ru #ifdef SSL_MODE_RELEASE_BUFFERS
2750Sigor@sysoev.ru 
2760Sigor@sysoev.ru     if (nxt_openssl_version >= 10001078) {
2770Sigor@sysoev.ru         /*
2780Sigor@sysoev.ru          * Allow to release read and write buffers in OpenSSL 1.0.0,
2790Sigor@sysoev.ru          * this saves about 34K per idle connection.  It is not safe
2800Sigor@sysoev.ru          * before OpenSSL 1.0.1h (CVE-2010-5298).
2810Sigor@sysoev.ru          */
2820Sigor@sysoev.ru         SSL_CTX_set_mode(ctx, SSL_MODE_RELEASE_BUFFERS);
2830Sigor@sysoev.ru     }
2840Sigor@sysoev.ru 
2850Sigor@sysoev.ru #endif
2860Sigor@sysoev.ru 
2870Sigor@sysoev.ru     certificate = conf->certificate;
2880Sigor@sysoev.ru 
2890Sigor@sysoev.ru     if (SSL_CTX_use_certificate_chain_file(ctx, certificate) == 0) {
290*771Sigor@sysoev.ru         nxt_openssl_log_error(task, NXT_LOG_ALERT,
2910Sigor@sysoev.ru                               "SSL_CTX_use_certificate_file(\"%s\") failed",
2920Sigor@sysoev.ru                               certificate);
2930Sigor@sysoev.ru         goto fail;
2940Sigor@sysoev.ru     }
2950Sigor@sysoev.ru 
2960Sigor@sysoev.ru     key = conf->certificate_key;
2970Sigor@sysoev.ru 
2980Sigor@sysoev.ru     if (SSL_CTX_use_PrivateKey_file(ctx, key, SSL_FILETYPE_PEM) == 0) {
299*771Sigor@sysoev.ru         nxt_openssl_log_error(task, NXT_LOG_ALERT,
3000Sigor@sysoev.ru                               "SSL_CTX_use_PrivateKey_file(\"%s\") failed",
3010Sigor@sysoev.ru                               key);
3020Sigor@sysoev.ru         goto fail;
3030Sigor@sysoev.ru     }
3040Sigor@sysoev.ru 
3050Sigor@sysoev.ru     ciphers = (conf->ciphers != NULL) ? conf->ciphers : "HIGH:!aNULL:!MD5";
3060Sigor@sysoev.ru 
3070Sigor@sysoev.ru     if (SSL_CTX_set_cipher_list(ctx, ciphers) == 0) {
308*771Sigor@sysoev.ru         nxt_openssl_log_error(task, NXT_LOG_ALERT,
3090Sigor@sysoev.ru                               "SSL_CTX_set_cipher_list(\"%s\") failed",
3100Sigor@sysoev.ru                               ciphers);
3110Sigor@sysoev.ru         goto fail;
3120Sigor@sysoev.ru     }
3130Sigor@sysoev.ru 
3140Sigor@sysoev.ru     SSL_CTX_set_options(ctx, SSL_OP_CIPHER_SERVER_PREFERENCE);
3150Sigor@sysoev.ru 
3160Sigor@sysoev.ru     if (conf->ca_certificate != NULL) {
3170Sigor@sysoev.ru 
3180Sigor@sysoev.ru         /* TODO: verify callback */
3190Sigor@sysoev.ru         SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER, NULL);
3200Sigor@sysoev.ru 
3210Sigor@sysoev.ru         /* TODO: verify depth */
3220Sigor@sysoev.ru         SSL_CTX_set_verify_depth(ctx, 1);
3230Sigor@sysoev.ru 
3240Sigor@sysoev.ru         ca_certificate = conf->ca_certificate;
3250Sigor@sysoev.ru 
3260Sigor@sysoev.ru         if (SSL_CTX_load_verify_locations(ctx, ca_certificate, NULL) == 0) {
327*771Sigor@sysoev.ru             nxt_openssl_log_error(task, NXT_LOG_ALERT,
3280Sigor@sysoev.ru                               "SSL_CTX_load_verify_locations(\"%s\") failed",
3290Sigor@sysoev.ru                               ca_certificate);
3300Sigor@sysoev.ru             goto fail;
3310Sigor@sysoev.ru         }
3320Sigor@sysoev.ru 
3330Sigor@sysoev.ru         list = SSL_load_client_CA_file(ca_certificate);
3340Sigor@sysoev.ru 
3350Sigor@sysoev.ru         if (list == NULL) {
336*771Sigor@sysoev.ru             nxt_openssl_log_error(task, NXT_LOG_ALERT,
3370Sigor@sysoev.ru                               "SSL_load_client_CA_file(\"%s\") failed",
3380Sigor@sysoev.ru                               ca_certificate);
3390Sigor@sysoev.ru             goto fail;
3400Sigor@sysoev.ru         }
3410Sigor@sysoev.ru 
3420Sigor@sysoev.ru         /*
3430Sigor@sysoev.ru          * SSL_load_client_CA_file() in OpenSSL prior to 0.9.7h and
3440Sigor@sysoev.ru          * 0.9.8 versions always leaves an error in the error queue.
3450Sigor@sysoev.ru          */
3460Sigor@sysoev.ru         ERR_clear_error();
3470Sigor@sysoev.ru 
3480Sigor@sysoev.ru         SSL_CTX_set_client_CA_list(ctx, list);
3490Sigor@sysoev.ru     }
3500Sigor@sysoev.ru 
3510Sigor@sysoev.ru     return NXT_OK;
3520Sigor@sysoev.ru 
3530Sigor@sysoev.ru fail:
3540Sigor@sysoev.ru 
3550Sigor@sysoev.ru     SSL_CTX_free(ctx);
3560Sigor@sysoev.ru 
3570Sigor@sysoev.ru     return NXT_ERROR;
3580Sigor@sysoev.ru }
3590Sigor@sysoev.ru 
3600Sigor@sysoev.ru 
3610Sigor@sysoev.ru static void
362*771Sigor@sysoev.ru nxt_openssl_server_free(nxt_task_t *task, nxt_tls_conf_t *conf)
3630Sigor@sysoev.ru {
364*771Sigor@sysoev.ru     SSL_CTX_free(conf->ctx);
365*771Sigor@sysoev.ru }
366*771Sigor@sysoev.ru 
367*771Sigor@sysoev.ru 
368*771Sigor@sysoev.ru static void
369*771Sigor@sysoev.ru nxt_openssl_conn_init(nxt_task_t *task, nxt_tls_conf_t *conf, nxt_conn_t *c)
370*771Sigor@sysoev.ru {
371*771Sigor@sysoev.ru     int                 ret;
372*771Sigor@sysoev.ru     SSL                 *s;
373*771Sigor@sysoev.ru     SSL_CTX             *ctx;
374*771Sigor@sysoev.ru     nxt_openssl_conn_t  *tls;
3750Sigor@sysoev.ru 
3760Sigor@sysoev.ru     nxt_log_debug(c->socket.log, "openssl conn init");
3770Sigor@sysoev.ru 
378*771Sigor@sysoev.ru     tls = nxt_mp_zget(c->mem_pool, sizeof(nxt_openssl_conn_t));
379*771Sigor@sysoev.ru     if (tls == NULL) {
3800Sigor@sysoev.ru         goto fail;
3810Sigor@sysoev.ru     }
3820Sigor@sysoev.ru 
383*771Sigor@sysoev.ru     c->u.tls = tls;
384*771Sigor@sysoev.ru     nxt_buf_mem_set_size(&tls->buffer, conf->buffer_size);
3850Sigor@sysoev.ru 
3860Sigor@sysoev.ru     ctx = conf->ctx;
3870Sigor@sysoev.ru 
3880Sigor@sysoev.ru     s = SSL_new(ctx);
3890Sigor@sysoev.ru     if (s == NULL) {
390*771Sigor@sysoev.ru         nxt_openssl_log_error(task, NXT_LOG_ALERT, "SSL_new() failed");
3910Sigor@sysoev.ru         goto fail;
3920Sigor@sysoev.ru     }
3930Sigor@sysoev.ru 
394*771Sigor@sysoev.ru     tls->session = s;
395*771Sigor@sysoev.ru     tls->conn = c;
3960Sigor@sysoev.ru 
3970Sigor@sysoev.ru     ret = SSL_set_fd(s, c->socket.fd);
3980Sigor@sysoev.ru 
3990Sigor@sysoev.ru     if (ret == 0) {
400*771Sigor@sysoev.ru         nxt_openssl_log_error(task, NXT_LOG_ALERT, "SSL_set_fd(%d) failed",
401*771Sigor@sysoev.ru                               c->socket.fd);
4020Sigor@sysoev.ru         goto fail;
4030Sigor@sysoev.ru     }
4040Sigor@sysoev.ru 
4050Sigor@sysoev.ru     SSL_set_accept_state(s);
4060Sigor@sysoev.ru 
4070Sigor@sysoev.ru     if (SSL_set_ex_data(s, nxt_openssl_connection_index, c) == 0) {
408*771Sigor@sysoev.ru         nxt_openssl_log_error(task, NXT_LOG_ALERT, "SSL_set_ex_data() failed");
4090Sigor@sysoev.ru         goto fail;
4100Sigor@sysoev.ru     }
4110Sigor@sysoev.ru 
41262Sigor@sysoev.ru     c->io = &nxt_openssl_conn_io;
4130Sigor@sysoev.ru     c->sendfile = NXT_CONN_SENDFILE_OFF;
4140Sigor@sysoev.ru 
4151Sigor@sysoev.ru     nxt_openssl_conn_handshake(task, c, c->socket.data);
4160Sigor@sysoev.ru     return;
4170Sigor@sysoev.ru 
4180Sigor@sysoev.ru fail:
4190Sigor@sysoev.ru 
42013Sigor@sysoev.ru     nxt_work_queue_add(c->read_work_queue, c->read_state->error_handler,
42113Sigor@sysoev.ru                        task, c, c->socket.data);
4220Sigor@sysoev.ru }
4230Sigor@sysoev.ru 
4240Sigor@sysoev.ru 
425*771Sigor@sysoev.ru nxt_inline void
426*771Sigor@sysoev.ru nxt_openssl_conn_free(nxt_task_t *task, nxt_openssl_conn_t *tls)
4270Sigor@sysoev.ru {
428*771Sigor@sysoev.ru     nxt_debug(task, "openssl conn free");
4290Sigor@sysoev.ru 
430*771Sigor@sysoev.ru     nxt_free(tls->buffer.start);
4310Sigor@sysoev.ru 
432*771Sigor@sysoev.ru     SSL_free(tls->session);
4330Sigor@sysoev.ru }
4340Sigor@sysoev.ru 
4350Sigor@sysoev.ru 
4360Sigor@sysoev.ru static void
4371Sigor@sysoev.ru nxt_openssl_conn_handshake(nxt_task_t *task, void *obj, void *data)
4380Sigor@sysoev.ru {
439*771Sigor@sysoev.ru     int                     ret;
440*771Sigor@sysoev.ru     nxt_int_t               n;
441*771Sigor@sysoev.ru     nxt_err_t               err;
442*771Sigor@sysoev.ru     nxt_conn_t              *c;
443*771Sigor@sysoev.ru     nxt_work_queue_t        *wq;
444*771Sigor@sysoev.ru     nxt_work_handler_t      handler;
445*771Sigor@sysoev.ru     nxt_openssl_conn_t      *tls;
446*771Sigor@sysoev.ru     const nxt_conn_state_t  *state;
4470Sigor@sysoev.ru 
4480Sigor@sysoev.ru     c = obj;
449*771Sigor@sysoev.ru     tls = c->u.tls;
4500Sigor@sysoev.ru 
451*771Sigor@sysoev.ru     nxt_debug(task, "openssl conn handshake: %d", tls->times);
4520Sigor@sysoev.ru 
453*771Sigor@sysoev.ru     /* "tls->times == 1" is suitable to run SSL_do_handshake() in job. */
4540Sigor@sysoev.ru 
455*771Sigor@sysoev.ru     ret = SSL_do_handshake(tls->session);
4560Sigor@sysoev.ru 
4570Sigor@sysoev.ru     err = (ret <= 0) ? nxt_socket_errno : 0;
4580Sigor@sysoev.ru 
4591Sigor@sysoev.ru     nxt_thread_time_debug_update(task->thread);
4600Sigor@sysoev.ru 
4611Sigor@sysoev.ru     nxt_debug(task, "SSL_do_handshake(%d): %d err:%d", c->socket.fd, ret, err);
4620Sigor@sysoev.ru 
463*771Sigor@sysoev.ru     state = (c->read_state != NULL) ? c->read_state : c->write_state;
464*771Sigor@sysoev.ru 
4650Sigor@sysoev.ru     if (ret > 0) {
4660Sigor@sysoev.ru         /* ret == 1, the handshake was successfully completed. */
467*771Sigor@sysoev.ru         tls->handshake = 1;
4680Sigor@sysoev.ru 
469*771Sigor@sysoev.ru         if (c->read_state != NULL) {
470*771Sigor@sysoev.ru             if (state->io_read_handler != NULL || c->read != NULL) {
471*771Sigor@sysoev.ru                 nxt_conn_read(task->thread->engine, c);
4720Sigor@sysoev.ru                 return;
4730Sigor@sysoev.ru             }
4740Sigor@sysoev.ru 
475*771Sigor@sysoev.ru         } else {
476*771Sigor@sysoev.ru             if (c->write != NULL) {
477*771Sigor@sysoev.ru                 nxt_conn_write(task->thread->engine, c);
478*771Sigor@sysoev.ru                 return;
479*771Sigor@sysoev.ru             }
480*771Sigor@sysoev.ru         }
481*771Sigor@sysoev.ru 
482*771Sigor@sysoev.ru         handler = state->ready_handler;
483*771Sigor@sysoev.ru 
484*771Sigor@sysoev.ru     } else {
485*771Sigor@sysoev.ru         c->socket.read_handler = nxt_openssl_conn_handshake;
486*771Sigor@sysoev.ru         c->socket.write_handler = nxt_openssl_conn_handshake;
487*771Sigor@sysoev.ru 
488*771Sigor@sysoev.ru         n = nxt_openssl_conn_test_error(task, c, ret, err,
489*771Sigor@sysoev.ru                                         NXT_OPENSSL_HANDSHAKE);
490*771Sigor@sysoev.ru         switch (n) {
4910Sigor@sysoev.ru 
492*771Sigor@sysoev.ru         case NXT_AGAIN:
493*771Sigor@sysoev.ru             if (tls->ssl_error == SSL_ERROR_WANT_READ && tls->times < 2) {
494*771Sigor@sysoev.ru                 tls->times++;
495*771Sigor@sysoev.ru             }
496*771Sigor@sysoev.ru 
497*771Sigor@sysoev.ru             return;
498*771Sigor@sysoev.ru 
499*771Sigor@sysoev.ru         case 0:
500*771Sigor@sysoev.ru             handler = state->close_handler;
501*771Sigor@sysoev.ru             break;
502*771Sigor@sysoev.ru 
503*771Sigor@sysoev.ru         default:
504*771Sigor@sysoev.ru         case NXT_ERROR:
505*771Sigor@sysoev.ru             c->socket.error = err;
506*771Sigor@sysoev.ru             nxt_openssl_conn_error(task, err, "SSL_do_handshake(%d) failed",
507*771Sigor@sysoev.ru                                    c->socket.fd);
508*771Sigor@sysoev.ru 
509*771Sigor@sysoev.ru             handler = state->error_handler;
510*771Sigor@sysoev.ru             break;
5110Sigor@sysoev.ru         }
5120Sigor@sysoev.ru     }
5130Sigor@sysoev.ru 
514*771Sigor@sysoev.ru     wq = (c->read_state != NULL) ? c->read_work_queue : c->write_work_queue;
515*771Sigor@sysoev.ru 
516*771Sigor@sysoev.ru     nxt_work_queue_add(wq, handler, task, c, data);
5170Sigor@sysoev.ru }
5180Sigor@sysoev.ru 
5190Sigor@sysoev.ru 
5200Sigor@sysoev.ru static ssize_t
521*771Sigor@sysoev.ru nxt_openssl_conn_io_recvbuf(nxt_conn_t *c, nxt_buf_t *b)
5220Sigor@sysoev.ru {
523*771Sigor@sysoev.ru     int                 ret;
524*771Sigor@sysoev.ru     size_t              size;
525*771Sigor@sysoev.ru     nxt_int_t           n;
526*771Sigor@sysoev.ru     nxt_err_t           err;
527*771Sigor@sysoev.ru     nxt_openssl_conn_t  *tls;
528*771Sigor@sysoev.ru 
529*771Sigor@sysoev.ru     tls = c->u.tls;
530*771Sigor@sysoev.ru     size = b->mem.end - b->mem.free;
531*771Sigor@sysoev.ru 
532*771Sigor@sysoev.ru     ret = SSL_read(tls->session, b->mem.free, size);
533*771Sigor@sysoev.ru 
534*771Sigor@sysoev.ru     err = (ret <= 0) ? nxt_socket_errno : 0;
535*771Sigor@sysoev.ru 
536*771Sigor@sysoev.ru     nxt_debug(c->socket.task, "SSL_read(%d, %p, %uz): %d err:%d",
537*771Sigor@sysoev.ru               c->socket.fd, b->mem.free, size, ret, err);
5380Sigor@sysoev.ru 
539*771Sigor@sysoev.ru     if (ret > 0) {
540*771Sigor@sysoev.ru         if ((size_t) ret < size) {
541*771Sigor@sysoev.ru             c->socket.read_ready = 0;
542*771Sigor@sysoev.ru         }
543*771Sigor@sysoev.ru 
544*771Sigor@sysoev.ru         return ret;
545*771Sigor@sysoev.ru     }
5460Sigor@sysoev.ru 
547*771Sigor@sysoev.ru     n = nxt_openssl_conn_test_error(c->socket.task, c, ret, err,
548*771Sigor@sysoev.ru                                     NXT_OPENSSL_READ);
549*771Sigor@sysoev.ru     if (n == NXT_ERROR) {
550*771Sigor@sysoev.ru         c->socket.error = err;
551*771Sigor@sysoev.ru         nxt_openssl_conn_error(c->socket.task, err,
552*771Sigor@sysoev.ru                                "SSL_read(%d, %p, %uz) failed",
553*771Sigor@sysoev.ru                                c->socket.fd, b->mem.free, size);
554*771Sigor@sysoev.ru     }
5550Sigor@sysoev.ru 
556*771Sigor@sysoev.ru     return n;
5570Sigor@sysoev.ru }
5580Sigor@sysoev.ru 
5590Sigor@sysoev.ru 
5600Sigor@sysoev.ru static ssize_t
561*771Sigor@sysoev.ru nxt_openssl_conn_io_sendbuf(nxt_task_t *task, nxt_sendbuf_t *sb)
562*771Sigor@sysoev.ru {
563*771Sigor@sysoev.ru     nxt_uint_t    niov;
564*771Sigor@sysoev.ru     struct iovec  iov;
565*771Sigor@sysoev.ru 
566*771Sigor@sysoev.ru     niov = nxt_sendbuf_mem_coalesce0(task, sb, &iov, 1);
567*771Sigor@sysoev.ru 
568*771Sigor@sysoev.ru     if (niov == 0 && sb->sync) {
569*771Sigor@sysoev.ru         return 0;
570*771Sigor@sysoev.ru     }
571*771Sigor@sysoev.ru 
572*771Sigor@sysoev.ru     return nxt_openssl_conn_io_send(task, sb, iov.iov_base, iov.iov_len);
573*771Sigor@sysoev.ru }
574*771Sigor@sysoev.ru 
575*771Sigor@sysoev.ru 
576*771Sigor@sysoev.ru static ssize_t
577*771Sigor@sysoev.ru nxt_openssl_conn_io_send(nxt_task_t *task, nxt_sendbuf_t *sb, void *buf,
578*771Sigor@sysoev.ru     size_t size)
5790Sigor@sysoev.ru {
5800Sigor@sysoev.ru     int                 ret;
5810Sigor@sysoev.ru     nxt_err_t           err;
5820Sigor@sysoev.ru     nxt_int_t           n;
583*771Sigor@sysoev.ru     nxt_conn_t          *c;
584*771Sigor@sysoev.ru     nxt_openssl_conn_t  *tls;
5850Sigor@sysoev.ru 
586*771Sigor@sysoev.ru     tls = sb->tls;
5870Sigor@sysoev.ru 
588*771Sigor@sysoev.ru     ret = SSL_write(tls->session, buf, size);
5890Sigor@sysoev.ru 
5900Sigor@sysoev.ru     if (ret <= 0) {
5910Sigor@sysoev.ru         err = nxt_socket_errno;
592*771Sigor@sysoev.ru         sb->error = err;
5930Sigor@sysoev.ru 
5940Sigor@sysoev.ru     } else {
5950Sigor@sysoev.ru         err = 0;
5960Sigor@sysoev.ru     }
5970Sigor@sysoev.ru 
598*771Sigor@sysoev.ru     nxt_debug(task, "SSL_write(%d, %p, %uz): %d err:%d",
599*771Sigor@sysoev.ru               sb->socket, buf, size, ret, err);
6000Sigor@sysoev.ru 
6010Sigor@sysoev.ru     if (ret > 0) {
6020Sigor@sysoev.ru         return ret;
6030Sigor@sysoev.ru     }
6040Sigor@sysoev.ru 
605*771Sigor@sysoev.ru     c = tls->conn;
606*771Sigor@sysoev.ru     c->socket.write_ready = sb->ready;
607*771Sigor@sysoev.ru     c->socket.error = sb->error;
608*771Sigor@sysoev.ru 
609*771Sigor@sysoev.ru     n = nxt_openssl_conn_test_error(task, c, ret, err, NXT_OPENSSL_WRITE);
610*771Sigor@sysoev.ru 
611*771Sigor@sysoev.ru     sb->ready = c->socket.write_ready;
612*771Sigor@sysoev.ru     sb->error = c->socket.error;
6130Sigor@sysoev.ru 
6140Sigor@sysoev.ru     if (n == NXT_ERROR) {
615*771Sigor@sysoev.ru         sb->error = err;
616*771Sigor@sysoev.ru         nxt_openssl_conn_error(task, err, "SSL_write(%d, %p, %uz) failed",
617*771Sigor@sysoev.ru                                sb->socket, buf, size);
6180Sigor@sysoev.ru     }
6190Sigor@sysoev.ru 
6200Sigor@sysoev.ru     return n;
6210Sigor@sysoev.ru }
6220Sigor@sysoev.ru 
6230Sigor@sysoev.ru 
6240Sigor@sysoev.ru static void
6251Sigor@sysoev.ru nxt_openssl_conn_io_shutdown(nxt_task_t *task, void *obj, void *data)
6260Sigor@sysoev.ru {
6270Sigor@sysoev.ru     int                 ret, mode;
6280Sigor@sysoev.ru     SSL                 *s;
6290Sigor@sysoev.ru     nxt_err_t           err;
6300Sigor@sysoev.ru     nxt_int_t           n;
6310Sigor@sysoev.ru     nxt_bool_t          quiet, once;
63262Sigor@sysoev.ru     nxt_conn_t          *c;
633*771Sigor@sysoev.ru     nxt_openssl_conn_t  *tls;
6340Sigor@sysoev.ru     nxt_work_handler_t  handler;
6350Sigor@sysoev.ru 
6360Sigor@sysoev.ru     c = obj;
6370Sigor@sysoev.ru 
6381Sigor@sysoev.ru     nxt_debug(task, "openssl conn shutdown");
6390Sigor@sysoev.ru 
640*771Sigor@sysoev.ru     c->read_state = NULL;
641*771Sigor@sysoev.ru     tls = c->u.tls;
642*771Sigor@sysoev.ru     s = tls->session;
6430Sigor@sysoev.ru 
644*771Sigor@sysoev.ru     if (s == NULL || !tls->handshake) {
645*771Sigor@sysoev.ru         handler = c->write_state->ready_handler;
6460Sigor@sysoev.ru         goto done;
6470Sigor@sysoev.ru     }
6480Sigor@sysoev.ru 
6490Sigor@sysoev.ru     mode = SSL_get_shutdown(s);
6500Sigor@sysoev.ru 
6510Sigor@sysoev.ru     if (c->socket.timedout || c->socket.error != 0) {
6520Sigor@sysoev.ru         quiet = 1;
6530Sigor@sysoev.ru 
6540Sigor@sysoev.ru     } else if (c->socket.closed && !(mode & SSL_RECEIVED_SHUTDOWN)) {
6550Sigor@sysoev.ru         quiet = 1;
6560Sigor@sysoev.ru 
6570Sigor@sysoev.ru     } else {
6580Sigor@sysoev.ru         quiet = 0;
6590Sigor@sysoev.ru     }
6600Sigor@sysoev.ru 
6610Sigor@sysoev.ru     SSL_set_quiet_shutdown(s, quiet);
6620Sigor@sysoev.ru 
6630Sigor@sysoev.ru     once = 1;
6640Sigor@sysoev.ru 
6650Sigor@sysoev.ru     for ( ;; ) {
6660Sigor@sysoev.ru         SSL_set_shutdown(s, mode);
6670Sigor@sysoev.ru 
6680Sigor@sysoev.ru         ret = SSL_shutdown(s);
6690Sigor@sysoev.ru 
6700Sigor@sysoev.ru         err = (ret <= 0) ? nxt_socket_errno : 0;
6710Sigor@sysoev.ru 
6721Sigor@sysoev.ru         nxt_debug(task, "SSL_shutdown(%d, %d, %b): %d err:%d",
6731Sigor@sysoev.ru                   c->socket.fd, mode, quiet, ret, err);
6740Sigor@sysoev.ru 
6750Sigor@sysoev.ru         if (ret > 0) {
6760Sigor@sysoev.ru             /* ret == 1, the shutdown was successfully completed. */
677*771Sigor@sysoev.ru             handler = c->write_state->ready_handler;
6780Sigor@sysoev.ru             goto done;
6790Sigor@sysoev.ru         }
6800Sigor@sysoev.ru 
6810Sigor@sysoev.ru         if (ret == 0) {
6820Sigor@sysoev.ru             /*
6830Sigor@sysoev.ru              * If SSL_shutdown() returns 0 then it should be called
684*771Sigor@sysoev.ru              * again.  The second SSL_shutdown() call should return
6850Sigor@sysoev.ru              * -1/SSL_ERROR_WANT_READ or -1/SSL_ERROR_WANT_WRITE.
6860Sigor@sysoev.ru              * OpenSSL prior to 0.9.8m version however never returns
687*771Sigor@sysoev.ru              * -1 at all.  Fortunately, OpenSSL preserves internally
6880Sigor@sysoev.ru              * correct status available via SSL_get_error(-1).
6890Sigor@sysoev.ru              */
6900Sigor@sysoev.ru             if (once) {
691*771Sigor@sysoev.ru                 once = 0;
6920Sigor@sysoev.ru                 mode = SSL_get_shutdown(s);
6930Sigor@sysoev.ru                 continue;
6940Sigor@sysoev.ru             }
6950Sigor@sysoev.ru 
6960Sigor@sysoev.ru             ret = -1;
6970Sigor@sysoev.ru         }
6980Sigor@sysoev.ru 
6990Sigor@sysoev.ru         /* ret == -1 */
7000Sigor@sysoev.ru 
7010Sigor@sysoev.ru         break;
7020Sigor@sysoev.ru     }
7030Sigor@sysoev.ru 
704*771Sigor@sysoev.ru     c->socket.read_handler = nxt_openssl_conn_io_shutdown;
705*771Sigor@sysoev.ru     c->socket.write_handler = nxt_openssl_conn_io_shutdown;
706*771Sigor@sysoev.ru     c->socket.error_handler = c->write_state->error_handler;
707*771Sigor@sysoev.ru 
708*771Sigor@sysoev.ru     n = nxt_openssl_conn_test_error(task, c, ret, err, NXT_OPENSSL_SHUTDOWN);
709*771Sigor@sysoev.ru 
710*771Sigor@sysoev.ru     switch (n) {
7110Sigor@sysoev.ru 
712*771Sigor@sysoev.ru     case 0:
713*771Sigor@sysoev.ru         handler = c->write_state->close_handler;
714*771Sigor@sysoev.ru         break;
715*771Sigor@sysoev.ru 
716*771Sigor@sysoev.ru     case NXT_AGAIN:
717*771Sigor@sysoev.ru         nxt_timer_add(task->thread->engine, &c->read_timer, 5000);
7180Sigor@sysoev.ru         return;
719*771Sigor@sysoev.ru 
720*771Sigor@sysoev.ru     default:
721*771Sigor@sysoev.ru     case NXT_ERROR:
722*771Sigor@sysoev.ru         c->socket.error = err;
723*771Sigor@sysoev.ru         nxt_openssl_conn_error(task, err, "SSL_shutdown(%d) failed",
724*771Sigor@sysoev.ru                                c->socket.fd);
725*771Sigor@sysoev.ru         handler = c->write_state->error_handler;
7260Sigor@sysoev.ru     }
7270Sigor@sysoev.ru 
728*771Sigor@sysoev.ru done:
7290Sigor@sysoev.ru 
730*771Sigor@sysoev.ru     nxt_openssl_conn_free(task, tls);
7310Sigor@sysoev.ru 
73213Sigor@sysoev.ru     nxt_work_queue_add(c->write_work_queue, handler, task, c, data);
7330Sigor@sysoev.ru }
7340Sigor@sysoev.ru 
7350Sigor@sysoev.ru 
7360Sigor@sysoev.ru static nxt_int_t
73762Sigor@sysoev.ru nxt_openssl_conn_test_error(nxt_task_t *task, nxt_conn_t *c, int ret,
738*771Sigor@sysoev.ru     nxt_err_t sys_err, nxt_openssl_io_t io)
7390Sigor@sysoev.ru {
7400Sigor@sysoev.ru     u_long              lib_err;
741*771Sigor@sysoev.ru     nxt_openssl_conn_t  *tls;
7420Sigor@sysoev.ru 
743*771Sigor@sysoev.ru     tls = c->u.tls;
7440Sigor@sysoev.ru 
745*771Sigor@sysoev.ru     tls->ssl_error = SSL_get_error(tls->session, ret);
7460Sigor@sysoev.ru 
747*771Sigor@sysoev.ru     nxt_debug(task, "SSL_get_error(): %d", tls->ssl_error);
7480Sigor@sysoev.ru 
749*771Sigor@sysoev.ru     switch (tls->ssl_error) {
7500Sigor@sysoev.ru 
7510Sigor@sysoev.ru     case SSL_ERROR_WANT_READ:
752*771Sigor@sysoev.ru 
753*771Sigor@sysoev.ru         if (io != NXT_OPENSSL_READ) {
754*771Sigor@sysoev.ru             nxt_fd_event_block_write(task->thread->engine, &c->socket);
7550Sigor@sysoev.ru 
756*771Sigor@sysoev.ru             c->socket.read_ready = 0;
7570Sigor@sysoev.ru 
758*771Sigor@sysoev.ru             if (nxt_fd_event_is_disabled(c->socket.read)) {
759*771Sigor@sysoev.ru                 nxt_fd_event_enable_read(task->thread->engine, &c->socket);
760*771Sigor@sysoev.ru             }
7610Sigor@sysoev.ru         }
7620Sigor@sysoev.ru 
7630Sigor@sysoev.ru         return NXT_AGAIN;
7640Sigor@sysoev.ru 
7650Sigor@sysoev.ru     case SSL_ERROR_WANT_WRITE:
766*771Sigor@sysoev.ru 
767*771Sigor@sysoev.ru         if (io != NXT_OPENSSL_WRITE) {
768*771Sigor@sysoev.ru             nxt_fd_event_block_read(task->thread->engine, &c->socket);
7690Sigor@sysoev.ru 
770*771Sigor@sysoev.ru             c->socket.write_ready = 0;
7710Sigor@sysoev.ru 
772*771Sigor@sysoev.ru             if (nxt_fd_event_is_disabled(c->socket.write)) {
773*771Sigor@sysoev.ru                 nxt_fd_event_enable_write(task->thread->engine, &c->socket);
774*771Sigor@sysoev.ru             }
7750Sigor@sysoev.ru         }
7760Sigor@sysoev.ru 
7770Sigor@sysoev.ru         return NXT_AGAIN;
7780Sigor@sysoev.ru 
7790Sigor@sysoev.ru     case SSL_ERROR_SYSCALL:
7800Sigor@sysoev.ru         lib_err = ERR_peek_error();
7810Sigor@sysoev.ru 
7821Sigor@sysoev.ru         nxt_debug(task, "ERR_peek_error(): %l", lib_err);
7830Sigor@sysoev.ru 
7840Sigor@sysoev.ru         if (sys_err != 0 || lib_err != 0) {
7850Sigor@sysoev.ru             return NXT_ERROR;
7860Sigor@sysoev.ru         }
7870Sigor@sysoev.ru 
7880Sigor@sysoev.ru         /* A connection was just closed. */
7890Sigor@sysoev.ru         c->socket.closed = 1;
790*771Sigor@sysoev.ru         return 0;
7910Sigor@sysoev.ru 
7920Sigor@sysoev.ru     case SSL_ERROR_ZERO_RETURN:
7930Sigor@sysoev.ru         /* A "close notify" alert. */
7940Sigor@sysoev.ru         return 0;
7950Sigor@sysoev.ru 
7960Sigor@sysoev.ru     default: /* SSL_ERROR_SSL, etc. */
7970Sigor@sysoev.ru         c->socket.error = 1000;  /* Nonexistent errno code. */
7980Sigor@sysoev.ru         return NXT_ERROR;
7990Sigor@sysoev.ru     }
8000Sigor@sysoev.ru }
8010Sigor@sysoev.ru 
8020Sigor@sysoev.ru 
8030Sigor@sysoev.ru static void nxt_cdecl
804*771Sigor@sysoev.ru nxt_openssl_conn_error(nxt_task_t *task, nxt_err_t err, const char *fmt, ...)
8050Sigor@sysoev.ru {
8060Sigor@sysoev.ru     u_char      *p, *end;
8070Sigor@sysoev.ru     va_list     args;
8080Sigor@sysoev.ru     nxt_uint_t  level;
8090Sigor@sysoev.ru     u_char      msg[NXT_MAX_ERROR_STR];
8100Sigor@sysoev.ru 
811*771Sigor@sysoev.ru     level = nxt_openssl_log_error_level(err);
8120Sigor@sysoev.ru 
813*771Sigor@sysoev.ru     if (nxt_log_level_enough(task->log, level)) {
8140Sigor@sysoev.ru 
8150Sigor@sysoev.ru         end = msg + sizeof(msg);
8160Sigor@sysoev.ru 
8170Sigor@sysoev.ru         va_start(args, fmt);
8180Sigor@sysoev.ru         p = nxt_vsprintf(msg, end, fmt, args);
8190Sigor@sysoev.ru         va_end(args);
8200Sigor@sysoev.ru 
8210Sigor@sysoev.ru         if (err != 0) {
8220Sigor@sysoev.ru             p = nxt_sprintf(p, end, " %E", err);
8230Sigor@sysoev.ru         }
8240Sigor@sysoev.ru 
8250Sigor@sysoev.ru         p = nxt_openssl_copy_error(p, end);
8260Sigor@sysoev.ru 
827*771Sigor@sysoev.ru         nxt_log(task, level, "%*s", p - msg, msg);
8280Sigor@sysoev.ru 
8290Sigor@sysoev.ru     } else {
8300Sigor@sysoev.ru         ERR_clear_error();
8310Sigor@sysoev.ru     }
8320Sigor@sysoev.ru }
8330Sigor@sysoev.ru 
8340Sigor@sysoev.ru 
8350Sigor@sysoev.ru static nxt_uint_t
836*771Sigor@sysoev.ru nxt_openssl_log_error_level(nxt_err_t err)
8370Sigor@sysoev.ru {
8380Sigor@sysoev.ru     switch (ERR_GET_REASON(ERR_peek_error())) {
8390Sigor@sysoev.ru 
8400Sigor@sysoev.ru     case 0:
84113Sigor@sysoev.ru         return nxt_socket_error_level(err);
8420Sigor@sysoev.ru 
8430Sigor@sysoev.ru     case SSL_R_BAD_CHANGE_CIPHER_SPEC:                    /*  103 */
8440Sigor@sysoev.ru     case SSL_R_BLOCK_CIPHER_PAD_IS_WRONG:                 /*  129 */
8450Sigor@sysoev.ru     case SSL_R_DIGEST_CHECK_FAILED:                       /*  149 */
8460Sigor@sysoev.ru     case SSL_R_ERROR_IN_RECEIVED_CIPHER_LIST:             /*  151 */
8470Sigor@sysoev.ru     case SSL_R_EXCESSIVE_MESSAGE_SIZE:                    /*  152 */
8480Sigor@sysoev.ru     case SSL_R_LENGTH_MISMATCH:                           /*  159 */
849*771Sigor@sysoev.ru #ifdef SSL_R_NO_CIPHERS_PASSED
8500Sigor@sysoev.ru     case SSL_R_NO_CIPHERS_PASSED:                         /*  182 */
851*771Sigor@sysoev.ru #endif
8520Sigor@sysoev.ru     case SSL_R_NO_CIPHERS_SPECIFIED:                      /*  183 */
8530Sigor@sysoev.ru     case SSL_R_NO_COMPRESSION_SPECIFIED:                  /*  187 */
8540Sigor@sysoev.ru     case SSL_R_NO_SHARED_CIPHER:                          /*  193 */
8550Sigor@sysoev.ru     case SSL_R_RECORD_LENGTH_MISMATCH:                    /*  213 */
8560Sigor@sysoev.ru #ifdef SSL_R_PARSE_TLSEXT
8570Sigor@sysoev.ru     case SSL_R_PARSE_TLSEXT:                              /*  227 */
8580Sigor@sysoev.ru #endif
8590Sigor@sysoev.ru     case SSL_R_UNEXPECTED_MESSAGE:                        /*  244 */
8600Sigor@sysoev.ru     case SSL_R_UNEXPECTED_RECORD:                         /*  245 */
8610Sigor@sysoev.ru     case SSL_R_UNKNOWN_ALERT_TYPE:                        /*  246 */
8620Sigor@sysoev.ru     case SSL_R_UNKNOWN_PROTOCOL:                          /*  252 */
8630Sigor@sysoev.ru     case SSL_R_WRONG_VERSION_NUMBER:                      /*  267 */
8640Sigor@sysoev.ru     case SSL_R_DECRYPTION_FAILED_OR_BAD_RECORD_MAC:       /*  281 */
8650Sigor@sysoev.ru #ifdef SSL_R_RENEGOTIATE_EXT_TOO_LONG
8660Sigor@sysoev.ru     case SSL_R_RENEGOTIATE_EXT_TOO_LONG:                  /*  335 */
8670Sigor@sysoev.ru     case SSL_R_RENEGOTIATION_ENCODING_ERR:                /*  336 */
8680Sigor@sysoev.ru     case SSL_R_RENEGOTIATION_MISMATCH:                    /*  337 */
8690Sigor@sysoev.ru #endif
8700Sigor@sysoev.ru #ifdef SSL_R_UNSAFE_LEGACY_RENEGOTIATION_DISABLED
8710Sigor@sysoev.ru     case SSL_R_UNSAFE_LEGACY_RENEGOTIATION_DISABLED:      /*  338 */
8720Sigor@sysoev.ru #endif
8730Sigor@sysoev.ru #ifdef SSL_R_SCSV_RECEIVED_WHEN_RENEGOTIATING
8740Sigor@sysoev.ru     case SSL_R_SCSV_RECEIVED_WHEN_RENEGOTIATING:          /*  345 */
8750Sigor@sysoev.ru #endif
8760Sigor@sysoev.ru     case 1000:/* SSL_R_SSLV3_ALERT_CLOSE_NOTIFY */
8770Sigor@sysoev.ru     case SSL_R_SSLV3_ALERT_UNEXPECTED_MESSAGE:            /* 1010 */
8780Sigor@sysoev.ru     case SSL_R_SSLV3_ALERT_BAD_RECORD_MAC:                /* 1020 */
8790Sigor@sysoev.ru     case SSL_R_TLSV1_ALERT_DECRYPTION_FAILED:             /* 1021 */
8800Sigor@sysoev.ru     case SSL_R_TLSV1_ALERT_RECORD_OVERFLOW:               /* 1022 */
8810Sigor@sysoev.ru     case SSL_R_SSLV3_ALERT_DECOMPRESSION_FAILURE:         /* 1030 */
8820Sigor@sysoev.ru     case SSL_R_SSLV3_ALERT_HANDSHAKE_FAILURE:             /* 1040 */
8830Sigor@sysoev.ru     case SSL_R_SSLV3_ALERT_ILLEGAL_PARAMETER:             /* 1047 */
8840Sigor@sysoev.ru         break;
8850Sigor@sysoev.ru 
8860Sigor@sysoev.ru     case SSL_R_SSLV3_ALERT_NO_CERTIFICATE:                /* 1041 */
8870Sigor@sysoev.ru     case SSL_R_SSLV3_ALERT_BAD_CERTIFICATE:               /* 1042 */
8880Sigor@sysoev.ru     case SSL_R_SSLV3_ALERT_UNSUPPORTED_CERTIFICATE:       /* 1043 */
8890Sigor@sysoev.ru     case SSL_R_SSLV3_ALERT_CERTIFICATE_REVOKED:           /* 1044 */
8900Sigor@sysoev.ru     case SSL_R_SSLV3_ALERT_CERTIFICATE_EXPIRED:           /* 1045 */
8910Sigor@sysoev.ru     case SSL_R_SSLV3_ALERT_CERTIFICATE_UNKNOWN:           /* 1046 */
8920Sigor@sysoev.ru     case SSL_R_TLSV1_ALERT_UNKNOWN_CA:                    /* 1048 */
8930Sigor@sysoev.ru     case SSL_R_TLSV1_ALERT_ACCESS_DENIED:                 /* 1049 */
8940Sigor@sysoev.ru     case SSL_R_TLSV1_ALERT_DECODE_ERROR:                  /* 1050 */
8950Sigor@sysoev.ru     case SSL_R_TLSV1_ALERT_DECRYPT_ERROR:                 /* 1051 */
8960Sigor@sysoev.ru     case SSL_R_TLSV1_ALERT_EXPORT_RESTRICTION:            /* 1060 */
8970Sigor@sysoev.ru     case SSL_R_TLSV1_ALERT_PROTOCOL_VERSION:              /* 1070 */
8980Sigor@sysoev.ru     case SSL_R_TLSV1_ALERT_INSUFFICIENT_SECURITY:         /* 1071 */
8990Sigor@sysoev.ru     case SSL_R_TLSV1_ALERT_INTERNAL_ERROR:                /* 1080 */
9000Sigor@sysoev.ru     case SSL_R_TLSV1_ALERT_USER_CANCELLED:                /* 1090 */
9010Sigor@sysoev.ru     case SSL_R_TLSV1_ALERT_NO_RENEGOTIATION:              /* 1100 */
9020Sigor@sysoev.ru         return NXT_LOG_ERR;
9030Sigor@sysoev.ru 
9040Sigor@sysoev.ru     default:
905564Svbart@nginx.com         return NXT_LOG_ALERT;
9060Sigor@sysoev.ru     }
9070Sigor@sysoev.ru 
9080Sigor@sysoev.ru     return NXT_LOG_INFO;
9090Sigor@sysoev.ru }
9100Sigor@sysoev.ru 
9110Sigor@sysoev.ru 
912*771Sigor@sysoev.ru void nxt_cdecl
913*771Sigor@sysoev.ru nxt_openssl_log_error(nxt_task_t *task, nxt_uint_t level, const char *fmt, ...)
9140Sigor@sysoev.ru {
9150Sigor@sysoev.ru     u_char   *p, *end;
9160Sigor@sysoev.ru     va_list  args;
9170Sigor@sysoev.ru     u_char   msg[NXT_MAX_ERROR_STR];
9180Sigor@sysoev.ru 
9190Sigor@sysoev.ru     end = msg + sizeof(msg);
9200Sigor@sysoev.ru 
9210Sigor@sysoev.ru     va_start(args, fmt);
9220Sigor@sysoev.ru     p = nxt_vsprintf(msg, end, fmt, args);
9230Sigor@sysoev.ru     va_end(args);
9240Sigor@sysoev.ru 
9250Sigor@sysoev.ru     p = nxt_openssl_copy_error(p, end);
9260Sigor@sysoev.ru 
927*771Sigor@sysoev.ru     nxt_log(task, level, "%*s", p - msg, msg);
9280Sigor@sysoev.ru }
9290Sigor@sysoev.ru 
9300Sigor@sysoev.ru 
931*771Sigor@sysoev.ru u_char *
9320Sigor@sysoev.ru nxt_openssl_copy_error(u_char *p, u_char *end)
9330Sigor@sysoev.ru {
9340Sigor@sysoev.ru     int         flags;
9350Sigor@sysoev.ru     u_long      err;
9360Sigor@sysoev.ru     nxt_bool_t  clear;
9370Sigor@sysoev.ru     const char  *data, *delimiter;
9380Sigor@sysoev.ru 
9390Sigor@sysoev.ru     err = ERR_peek_error();
9400Sigor@sysoev.ru     if (err == 0) {
9410Sigor@sysoev.ru         return p;
9420Sigor@sysoev.ru     }
9430Sigor@sysoev.ru 
9440Sigor@sysoev.ru     /* Log the most relevant error message ... */
9450Sigor@sysoev.ru     data = ERR_reason_error_string(err);
9460Sigor@sysoev.ru 
9470Sigor@sysoev.ru     p = nxt_sprintf(p, end, " (%d: %s) (OpenSSL: ", ERR_GET_REASON(err), data);
9480Sigor@sysoev.ru 
9490Sigor@sysoev.ru     /*
950*771Sigor@sysoev.ru      * ... followed by all queued cumbersome OpenSSL error messages
951*771Sigor@sysoev.ru      * and drain the error queue.
9520Sigor@sysoev.ru      */
9530Sigor@sysoev.ru     delimiter = "";
9540Sigor@sysoev.ru     clear = 0;
9550Sigor@sysoev.ru 
9560Sigor@sysoev.ru     for ( ;; ) {
9570Sigor@sysoev.ru         err = ERR_get_error_line_data(NULL, NULL, &data, &flags);
9580Sigor@sysoev.ru         if (err == 0) {
9590Sigor@sysoev.ru             break;
9600Sigor@sysoev.ru         }
9610Sigor@sysoev.ru 
9620Sigor@sysoev.ru         p = nxt_sprintf(p, end, "%s", delimiter);
9630Sigor@sysoev.ru 
9640Sigor@sysoev.ru         ERR_error_string_n(err, (char *) p, end - p);
9650Sigor@sysoev.ru 
9660Sigor@sysoev.ru         while (p < end && *p != '\0') {
9670Sigor@sysoev.ru             p++;
9680Sigor@sysoev.ru         }
9690Sigor@sysoev.ru 
9700Sigor@sysoev.ru         if ((flags & ERR_TXT_STRING) != 0) {
9710Sigor@sysoev.ru             p = nxt_sprintf(p, end, ":%s", data);
9720Sigor@sysoev.ru         }
9730Sigor@sysoev.ru 
9740Sigor@sysoev.ru         clear |= ((flags & ERR_TXT_MALLOCED) != 0);
9750Sigor@sysoev.ru 
9760Sigor@sysoev.ru         delimiter = "; ";
9770Sigor@sysoev.ru     }
9780Sigor@sysoev.ru 
9790Sigor@sysoev.ru     /* Deallocate additional data. */
9800Sigor@sysoev.ru 
9810Sigor@sysoev.ru     if (clear) {
9820Sigor@sysoev.ru         ERR_clear_error();
9830Sigor@sysoev.ru     }
9840Sigor@sysoev.ru 
9850Sigor@sysoev.ru     if (p < end) {
9860Sigor@sysoev.ru         *p++ = ')';
9870Sigor@sysoev.ru     }
9880Sigor@sysoev.ru 
9890Sigor@sysoev.ru     return p;
9900Sigor@sysoev.ru }
991