xref: /unit/src/nxt_openssl.c (revision 0)
1*0Sigor@sysoev.ru 
2*0Sigor@sysoev.ru /*
3*0Sigor@sysoev.ru  * Copyright (C) Igor Sysoev
4*0Sigor@sysoev.ru  * Copyright (C) NGINX, Inc.
5*0Sigor@sysoev.ru  */
6*0Sigor@sysoev.ru 
7*0Sigor@sysoev.ru #include <nxt_main.h>
8*0Sigor@sysoev.ru #include <openssl/ssl.h>
9*0Sigor@sysoev.ru #include <openssl/conf.h>
10*0Sigor@sysoev.ru #include <openssl/err.h>
11*0Sigor@sysoev.ru 
12*0Sigor@sysoev.ru 
13*0Sigor@sysoev.ru typedef struct {
14*0Sigor@sysoev.ru     SSL            *session;
15*0Sigor@sysoev.ru 
16*0Sigor@sysoev.ru     int            ssl_error;
17*0Sigor@sysoev.ru     uint8_t        times;      /* 2 bits */
18*0Sigor@sysoev.ru 
19*0Sigor@sysoev.ru     nxt_buf_mem_t  buffer;
20*0Sigor@sysoev.ru } nxt_openssl_conn_t;
21*0Sigor@sysoev.ru 
22*0Sigor@sysoev.ru 
23*0Sigor@sysoev.ru static nxt_int_t nxt_openssl_server_init(nxt_ssltls_conf_t *conf);
24*0Sigor@sysoev.ru 
25*0Sigor@sysoev.ru static void nxt_openssl_conn_init(nxt_thread_t *thr, nxt_ssltls_conf_t *conf,
26*0Sigor@sysoev.ru     nxt_event_conn_t *c);
27*0Sigor@sysoev.ru static void nxt_openssl_session_cleanup(void *data);
28*0Sigor@sysoev.ru static void nxt_openssl_conn_handshake(nxt_thread_t *thr, void *obj,
29*0Sigor@sysoev.ru     void *data);
30*0Sigor@sysoev.ru static void nxt_openssl_conn_io_read(nxt_thread_t *thr, void *obj, void *data);
31*0Sigor@sysoev.ru static void nxt_openssl_conn_io_shutdown(nxt_thread_t *thr, void *obj,
32*0Sigor@sysoev.ru     void *data);
33*0Sigor@sysoev.ru static ssize_t nxt_openssl_conn_io_write_chunk(nxt_thread_t *thr,
34*0Sigor@sysoev.ru     nxt_event_conn_t *c, nxt_buf_t *b, size_t limit);
35*0Sigor@sysoev.ru static ssize_t nxt_openssl_conn_io_send(nxt_event_conn_t *c, void *buf,
36*0Sigor@sysoev.ru     size_t size);
37*0Sigor@sysoev.ru static nxt_int_t nxt_openssl_conn_test_error(nxt_thread_t *thr,
38*0Sigor@sysoev.ru     nxt_event_conn_t *c, int ret, nxt_err_t sys_err,
39*0Sigor@sysoev.ru     nxt_work_handler_t handler);
40*0Sigor@sysoev.ru static void nxt_cdecl nxt_openssl_conn_error(nxt_event_conn_t *c, nxt_err_t err,
41*0Sigor@sysoev.ru     const char *fmt, ...);
42*0Sigor@sysoev.ru static nxt_uint_t nxt_openssl_log_error_level(nxt_event_conn_t *c,
43*0Sigor@sysoev.ru     nxt_err_t err);
44*0Sigor@sysoev.ru static void nxt_cdecl nxt_openssl_log_error(nxt_uint_t level, nxt_log_t *log,
45*0Sigor@sysoev.ru     const char *fmt, ...);
46*0Sigor@sysoev.ru static u_char *nxt_openssl_copy_error(u_char *p, u_char *end);
47*0Sigor@sysoev.ru 
48*0Sigor@sysoev.ru 
49*0Sigor@sysoev.ru const nxt_ssltls_lib_t  nxt_openssl_lib = {
50*0Sigor@sysoev.ru     nxt_openssl_server_init,
51*0Sigor@sysoev.ru     NULL,
52*0Sigor@sysoev.ru };
53*0Sigor@sysoev.ru 
54*0Sigor@sysoev.ru 
55*0Sigor@sysoev.ru static nxt_event_conn_io_t  nxt_openssl_event_conn_io = {
56*0Sigor@sysoev.ru     NULL,
57*0Sigor@sysoev.ru     NULL,
58*0Sigor@sysoev.ru 
59*0Sigor@sysoev.ru     nxt_openssl_conn_io_read,
60*0Sigor@sysoev.ru     NULL,
61*0Sigor@sysoev.ru     NULL,
62*0Sigor@sysoev.ru 
63*0Sigor@sysoev.ru     nxt_event_conn_io_write,
64*0Sigor@sysoev.ru     nxt_openssl_conn_io_write_chunk,
65*0Sigor@sysoev.ru     NULL,
66*0Sigor@sysoev.ru     NULL,
67*0Sigor@sysoev.ru     nxt_openssl_conn_io_send,
68*0Sigor@sysoev.ru 
69*0Sigor@sysoev.ru     nxt_openssl_conn_io_shutdown,
70*0Sigor@sysoev.ru };
71*0Sigor@sysoev.ru 
72*0Sigor@sysoev.ru 
73*0Sigor@sysoev.ru static long  nxt_openssl_version;
74*0Sigor@sysoev.ru static int   nxt_openssl_connection_index;
75*0Sigor@sysoev.ru 
76*0Sigor@sysoev.ru 
77*0Sigor@sysoev.ru static nxt_int_t
78*0Sigor@sysoev.ru nxt_openssl_start(nxt_thread_t *thr)
79*0Sigor@sysoev.ru {
80*0Sigor@sysoev.ru     int  index;
81*0Sigor@sysoev.ru 
82*0Sigor@sysoev.ru     if (nxt_fast_path(nxt_openssl_version != 0)) {
83*0Sigor@sysoev.ru         return NXT_OK;
84*0Sigor@sysoev.ru     }
85*0Sigor@sysoev.ru 
86*0Sigor@sysoev.ru     SSL_load_error_strings();
87*0Sigor@sysoev.ru 
88*0Sigor@sysoev.ru     OPENSSL_config(NULL);
89*0Sigor@sysoev.ru 
90*0Sigor@sysoev.ru     /*
91*0Sigor@sysoev.ru      * SSL_library_init(3):
92*0Sigor@sysoev.ru      *
93*0Sigor@sysoev.ru      *   SSL_library_init() always returns "1",
94*0Sigor@sysoev.ru      *   so it is safe to discard the return value.
95*0Sigor@sysoev.ru      */
96*0Sigor@sysoev.ru     (void) SSL_library_init();
97*0Sigor@sysoev.ru 
98*0Sigor@sysoev.ru     nxt_openssl_version = SSLeay();
99*0Sigor@sysoev.ru 
100*0Sigor@sysoev.ru     nxt_log_error(NXT_LOG_INFO, thr->log, "%s, %xl",
101*0Sigor@sysoev.ru                   SSLeay_version(SSLEAY_VERSION), nxt_openssl_version);
102*0Sigor@sysoev.ru 
103*0Sigor@sysoev.ru #ifndef SSL_OP_NO_COMPRESSION
104*0Sigor@sysoev.ru     {
105*0Sigor@sysoev.ru         /*
106*0Sigor@sysoev.ru          * Disable gzip compression in OpenSSL prior to 1.0.0
107*0Sigor@sysoev.ru          * version, this saves about 522K per connection.
108*0Sigor@sysoev.ru          */
109*0Sigor@sysoev.ru         int                 n;
110*0Sigor@sysoev.ru         STACK_OF(SSL_COMP)  *ssl_comp_methods;
111*0Sigor@sysoev.ru 
112*0Sigor@sysoev.ru         ssl_comp_methods = SSL_COMP_get_compression_methods();
113*0Sigor@sysoev.ru 
114*0Sigor@sysoev.ru         for (n = sk_SSL_COMP_num(ssl_comp_methods); n != 0; n--) {
115*0Sigor@sysoev.ru             (void) sk_SSL_COMP_pop(ssl_comp_methods);
116*0Sigor@sysoev.ru         }
117*0Sigor@sysoev.ru     }
118*0Sigor@sysoev.ru #endif
119*0Sigor@sysoev.ru 
120*0Sigor@sysoev.ru     index = SSL_get_ex_new_index(0, NULL, NULL, NULL, NULL);
121*0Sigor@sysoev.ru 
122*0Sigor@sysoev.ru     if (index == -1) {
123*0Sigor@sysoev.ru         nxt_openssl_log_error(NXT_LOG_CRIT, thr->log,
124*0Sigor@sysoev.ru                               "SSL_get_ex_new_index() failed");
125*0Sigor@sysoev.ru         return NXT_ERROR;
126*0Sigor@sysoev.ru     }
127*0Sigor@sysoev.ru 
128*0Sigor@sysoev.ru     nxt_openssl_connection_index = index;
129*0Sigor@sysoev.ru 
130*0Sigor@sysoev.ru     return NXT_OK;
131*0Sigor@sysoev.ru }
132*0Sigor@sysoev.ru 
133*0Sigor@sysoev.ru 
134*0Sigor@sysoev.ru static nxt_int_t
135*0Sigor@sysoev.ru nxt_openssl_server_init(nxt_ssltls_conf_t *conf)
136*0Sigor@sysoev.ru {
137*0Sigor@sysoev.ru     SSL_CTX              *ctx;
138*0Sigor@sysoev.ru     const char           *certificate, *key, *ciphers, *ca_certificate;
139*0Sigor@sysoev.ru     nxt_thread_t         *thr;
140*0Sigor@sysoev.ru     STACK_OF(X509_NAME)  *list;
141*0Sigor@sysoev.ru 
142*0Sigor@sysoev.ru     thr = nxt_thread();
143*0Sigor@sysoev.ru 
144*0Sigor@sysoev.ru     if (nxt_openssl_start(thr) != NXT_OK) {
145*0Sigor@sysoev.ru         return NXT_ERROR;
146*0Sigor@sysoev.ru     }
147*0Sigor@sysoev.ru 
148*0Sigor@sysoev.ru     ctx = SSL_CTX_new(SSLv23_server_method());
149*0Sigor@sysoev.ru     if (ctx == NULL) {
150*0Sigor@sysoev.ru         nxt_openssl_log_error(NXT_LOG_CRIT, thr->log, "SSL_CTX_new() failed");
151*0Sigor@sysoev.ru         return NXT_ERROR;
152*0Sigor@sysoev.ru     }
153*0Sigor@sysoev.ru 
154*0Sigor@sysoev.ru     conf->ctx = ctx;
155*0Sigor@sysoev.ru     conf->conn_init = nxt_openssl_conn_init;
156*0Sigor@sysoev.ru 
157*0Sigor@sysoev.ru #ifdef SSL_OP_NO_COMPRESSION
158*0Sigor@sysoev.ru     /*
159*0Sigor@sysoev.ru      * Disable gzip compression in OpenSSL 1.0.0,
160*0Sigor@sysoev.ru      * this saves about 522K per connection.
161*0Sigor@sysoev.ru      */
162*0Sigor@sysoev.ru     SSL_CTX_set_options(ctx, SSL_OP_NO_COMPRESSION);
163*0Sigor@sysoev.ru #endif
164*0Sigor@sysoev.ru 
165*0Sigor@sysoev.ru #ifdef SSL_MODE_RELEASE_BUFFERS
166*0Sigor@sysoev.ru 
167*0Sigor@sysoev.ru     if (nxt_openssl_version >= 10001078) {
168*0Sigor@sysoev.ru         /*
169*0Sigor@sysoev.ru          * Allow to release read and write buffers in OpenSSL 1.0.0,
170*0Sigor@sysoev.ru          * this saves about 34K per idle connection.  It is not safe
171*0Sigor@sysoev.ru          * before OpenSSL 1.0.1h (CVE-2010-5298).
172*0Sigor@sysoev.ru          */
173*0Sigor@sysoev.ru         SSL_CTX_set_mode(ctx, SSL_MODE_RELEASE_BUFFERS);
174*0Sigor@sysoev.ru     }
175*0Sigor@sysoev.ru 
176*0Sigor@sysoev.ru #endif
177*0Sigor@sysoev.ru 
178*0Sigor@sysoev.ru     certificate = conf->certificate;
179*0Sigor@sysoev.ru 
180*0Sigor@sysoev.ru     if (SSL_CTX_use_certificate_chain_file(ctx, certificate) == 0) {
181*0Sigor@sysoev.ru         nxt_openssl_log_error(NXT_LOG_CRIT, thr->log,
182*0Sigor@sysoev.ru                               "SSL_CTX_use_certificate_file(\"%s\") failed",
183*0Sigor@sysoev.ru                               certificate);
184*0Sigor@sysoev.ru         goto fail;
185*0Sigor@sysoev.ru     }
186*0Sigor@sysoev.ru 
187*0Sigor@sysoev.ru     key = conf->certificate_key;
188*0Sigor@sysoev.ru 
189*0Sigor@sysoev.ru     if (SSL_CTX_use_PrivateKey_file(ctx, key, SSL_FILETYPE_PEM) == 0) {
190*0Sigor@sysoev.ru         nxt_openssl_log_error(NXT_LOG_CRIT, thr->log,
191*0Sigor@sysoev.ru                               "SSL_CTX_use_PrivateKey_file(\"%s\") failed",
192*0Sigor@sysoev.ru                               key);
193*0Sigor@sysoev.ru         goto fail;
194*0Sigor@sysoev.ru     }
195*0Sigor@sysoev.ru 
196*0Sigor@sysoev.ru     ciphers = (conf->ciphers != NULL) ? conf->ciphers : "HIGH:!aNULL:!MD5";
197*0Sigor@sysoev.ru 
198*0Sigor@sysoev.ru     if (SSL_CTX_set_cipher_list(ctx, ciphers) == 0) {
199*0Sigor@sysoev.ru         nxt_openssl_log_error(NXT_LOG_CRIT, thr->log,
200*0Sigor@sysoev.ru                               "SSL_CTX_set_cipher_list(\"%s\") failed",
201*0Sigor@sysoev.ru                               ciphers);
202*0Sigor@sysoev.ru         goto fail;
203*0Sigor@sysoev.ru     }
204*0Sigor@sysoev.ru 
205*0Sigor@sysoev.ru     SSL_CTX_set_options(ctx, SSL_OP_CIPHER_SERVER_PREFERENCE);
206*0Sigor@sysoev.ru 
207*0Sigor@sysoev.ru     if (conf->ca_certificate != NULL) {
208*0Sigor@sysoev.ru 
209*0Sigor@sysoev.ru         /* TODO: verify callback */
210*0Sigor@sysoev.ru         SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER, NULL);
211*0Sigor@sysoev.ru 
212*0Sigor@sysoev.ru         /* TODO: verify depth */
213*0Sigor@sysoev.ru         SSL_CTX_set_verify_depth(ctx, 1);
214*0Sigor@sysoev.ru 
215*0Sigor@sysoev.ru         ca_certificate = conf->ca_certificate;
216*0Sigor@sysoev.ru 
217*0Sigor@sysoev.ru         if (SSL_CTX_load_verify_locations(ctx, ca_certificate, NULL) == 0) {
218*0Sigor@sysoev.ru             nxt_openssl_log_error(NXT_LOG_CRIT, thr->log,
219*0Sigor@sysoev.ru                               "SSL_CTX_load_verify_locations(\"%s\") failed",
220*0Sigor@sysoev.ru                               ca_certificate);
221*0Sigor@sysoev.ru             goto fail;
222*0Sigor@sysoev.ru         }
223*0Sigor@sysoev.ru 
224*0Sigor@sysoev.ru         list = SSL_load_client_CA_file(ca_certificate);
225*0Sigor@sysoev.ru 
226*0Sigor@sysoev.ru         if (list == NULL) {
227*0Sigor@sysoev.ru             nxt_openssl_log_error(NXT_LOG_CRIT, thr->log,
228*0Sigor@sysoev.ru                               "SSL_load_client_CA_file(\"%s\") failed",
229*0Sigor@sysoev.ru                               ca_certificate);
230*0Sigor@sysoev.ru             goto fail;
231*0Sigor@sysoev.ru         }
232*0Sigor@sysoev.ru 
233*0Sigor@sysoev.ru         /*
234*0Sigor@sysoev.ru          * SSL_load_client_CA_file() in OpenSSL prior to 0.9.7h and
235*0Sigor@sysoev.ru          * 0.9.8 versions always leaves an error in the error queue.
236*0Sigor@sysoev.ru          */
237*0Sigor@sysoev.ru         ERR_clear_error();
238*0Sigor@sysoev.ru 
239*0Sigor@sysoev.ru         SSL_CTX_set_client_CA_list(ctx, list);
240*0Sigor@sysoev.ru     }
241*0Sigor@sysoev.ru 
242*0Sigor@sysoev.ru     return NXT_OK;
243*0Sigor@sysoev.ru 
244*0Sigor@sysoev.ru fail:
245*0Sigor@sysoev.ru 
246*0Sigor@sysoev.ru     SSL_CTX_free(ctx);
247*0Sigor@sysoev.ru 
248*0Sigor@sysoev.ru     return NXT_ERROR;
249*0Sigor@sysoev.ru }
250*0Sigor@sysoev.ru 
251*0Sigor@sysoev.ru 
252*0Sigor@sysoev.ru static void
253*0Sigor@sysoev.ru nxt_openssl_conn_init(nxt_thread_t *thr, nxt_ssltls_conf_t *conf,
254*0Sigor@sysoev.ru     nxt_event_conn_t *c)
255*0Sigor@sysoev.ru {
256*0Sigor@sysoev.ru     int                     ret;
257*0Sigor@sysoev.ru     SSL                     *s;
258*0Sigor@sysoev.ru     SSL_CTX                 *ctx;
259*0Sigor@sysoev.ru     nxt_openssl_conn_t      *ssltls;
260*0Sigor@sysoev.ru     nxt_mem_pool_cleanup_t  *mpcl;
261*0Sigor@sysoev.ru 
262*0Sigor@sysoev.ru     nxt_log_debug(c->socket.log, "openssl conn init");
263*0Sigor@sysoev.ru 
264*0Sigor@sysoev.ru     ssltls = nxt_mem_zalloc(c->mem_pool, sizeof(nxt_openssl_conn_t));
265*0Sigor@sysoev.ru     if (ssltls == NULL) {
266*0Sigor@sysoev.ru         goto fail;
267*0Sigor@sysoev.ru     }
268*0Sigor@sysoev.ru 
269*0Sigor@sysoev.ru     c->u.ssltls = ssltls;
270*0Sigor@sysoev.ru     nxt_buf_mem_set_size(&ssltls->buffer, conf->buffer_size);
271*0Sigor@sysoev.ru 
272*0Sigor@sysoev.ru     mpcl = nxt_mem_pool_cleanup(c->mem_pool, 0);
273*0Sigor@sysoev.ru     if (mpcl == NULL) {
274*0Sigor@sysoev.ru         goto fail;
275*0Sigor@sysoev.ru     }
276*0Sigor@sysoev.ru 
277*0Sigor@sysoev.ru     ctx = conf->ctx;
278*0Sigor@sysoev.ru 
279*0Sigor@sysoev.ru     s = SSL_new(ctx);
280*0Sigor@sysoev.ru     if (s == NULL) {
281*0Sigor@sysoev.ru         nxt_openssl_log_error(NXT_LOG_CRIT, c->socket.log, "SSL_new() failed");
282*0Sigor@sysoev.ru         goto fail;
283*0Sigor@sysoev.ru     }
284*0Sigor@sysoev.ru 
285*0Sigor@sysoev.ru     ssltls->session = s;
286*0Sigor@sysoev.ru     mpcl->handler = nxt_openssl_session_cleanup;
287*0Sigor@sysoev.ru     mpcl->data = ssltls;
288*0Sigor@sysoev.ru 
289*0Sigor@sysoev.ru     ret = SSL_set_fd(s, c->socket.fd);
290*0Sigor@sysoev.ru 
291*0Sigor@sysoev.ru     if (ret == 0) {
292*0Sigor@sysoev.ru         nxt_openssl_log_error(NXT_LOG_CRIT, c->socket.log,
293*0Sigor@sysoev.ru                               "SSL_set_fd(%d) failed", c->socket.fd);
294*0Sigor@sysoev.ru         goto fail;
295*0Sigor@sysoev.ru     }
296*0Sigor@sysoev.ru 
297*0Sigor@sysoev.ru     SSL_set_accept_state(s);
298*0Sigor@sysoev.ru 
299*0Sigor@sysoev.ru     if (SSL_set_ex_data(s, nxt_openssl_connection_index, c) == 0) {
300*0Sigor@sysoev.ru         nxt_openssl_log_error(NXT_LOG_CRIT, c->socket.log,
301*0Sigor@sysoev.ru                               "SSL_set_ex_data() failed");
302*0Sigor@sysoev.ru         goto fail;
303*0Sigor@sysoev.ru     }
304*0Sigor@sysoev.ru 
305*0Sigor@sysoev.ru     c->io = &nxt_openssl_event_conn_io;
306*0Sigor@sysoev.ru     c->sendfile = NXT_CONN_SENDFILE_OFF;
307*0Sigor@sysoev.ru 
308*0Sigor@sysoev.ru     nxt_openssl_conn_handshake(thr, c, c->socket.data);
309*0Sigor@sysoev.ru     return;
310*0Sigor@sysoev.ru 
311*0Sigor@sysoev.ru fail:
312*0Sigor@sysoev.ru 
313*0Sigor@sysoev.ru     nxt_event_conn_io_handle(thr, c->read_work_queue,
314*0Sigor@sysoev.ru                              c->read_state->error_handler, c, c->socket.data);
315*0Sigor@sysoev.ru }
316*0Sigor@sysoev.ru 
317*0Sigor@sysoev.ru 
318*0Sigor@sysoev.ru static void
319*0Sigor@sysoev.ru nxt_openssl_session_cleanup(void *data)
320*0Sigor@sysoev.ru {
321*0Sigor@sysoev.ru     nxt_openssl_conn_t  *ssltls;
322*0Sigor@sysoev.ru 
323*0Sigor@sysoev.ru     ssltls = data;
324*0Sigor@sysoev.ru 
325*0Sigor@sysoev.ru     nxt_thread_log_debug("openssl session cleanup");
326*0Sigor@sysoev.ru 
327*0Sigor@sysoev.ru     nxt_free(ssltls->buffer.start);
328*0Sigor@sysoev.ru 
329*0Sigor@sysoev.ru     SSL_free(ssltls->session);
330*0Sigor@sysoev.ru }
331*0Sigor@sysoev.ru 
332*0Sigor@sysoev.ru 
333*0Sigor@sysoev.ru static void
334*0Sigor@sysoev.ru nxt_openssl_conn_handshake(nxt_thread_t *thr, void *obj, void *data)
335*0Sigor@sysoev.ru {
336*0Sigor@sysoev.ru     int                 ret;
337*0Sigor@sysoev.ru     nxt_int_t           n;
338*0Sigor@sysoev.ru     nxt_err_t           err;
339*0Sigor@sysoev.ru     nxt_event_conn_t    *c;
340*0Sigor@sysoev.ru     nxt_openssl_conn_t  *ssltls;
341*0Sigor@sysoev.ru 
342*0Sigor@sysoev.ru     c = obj;
343*0Sigor@sysoev.ru     ssltls = c->u.ssltls;
344*0Sigor@sysoev.ru 
345*0Sigor@sysoev.ru     nxt_log_debug(thr->log, "openssl conn handshake: %d", ssltls->times);
346*0Sigor@sysoev.ru 
347*0Sigor@sysoev.ru     /* "ssltls->times == 1" is suitable to run SSL_do_handshake() in job. */
348*0Sigor@sysoev.ru 
349*0Sigor@sysoev.ru     ret = SSL_do_handshake(ssltls->session);
350*0Sigor@sysoev.ru 
351*0Sigor@sysoev.ru     err = (ret <= 0) ? nxt_socket_errno : 0;
352*0Sigor@sysoev.ru 
353*0Sigor@sysoev.ru     nxt_thread_time_debug_update(thr);
354*0Sigor@sysoev.ru 
355*0Sigor@sysoev.ru     nxt_log_debug(thr->log, "SSL_do_handshake(%d): %d err:%d",
356*0Sigor@sysoev.ru                   c->socket.fd, ret, err);
357*0Sigor@sysoev.ru 
358*0Sigor@sysoev.ru     if (ret > 0) {
359*0Sigor@sysoev.ru         /* ret == 1, the handshake was successfully completed. */
360*0Sigor@sysoev.ru         nxt_openssl_conn_io_read(thr, c, data);
361*0Sigor@sysoev.ru         return;
362*0Sigor@sysoev.ru     }
363*0Sigor@sysoev.ru 
364*0Sigor@sysoev.ru     n = nxt_openssl_conn_test_error(thr, c, ret, err,
365*0Sigor@sysoev.ru                                     nxt_openssl_conn_handshake);
366*0Sigor@sysoev.ru 
367*0Sigor@sysoev.ru     if (n == NXT_ERROR) {
368*0Sigor@sysoev.ru         nxt_openssl_conn_error(c, err, "SSL_do_handshake(%d) failed",
369*0Sigor@sysoev.ru                                c->socket.fd);
370*0Sigor@sysoev.ru 
371*0Sigor@sysoev.ru         nxt_event_conn_io_handle(thr, c->read_work_queue,
372*0Sigor@sysoev.ru                                  c->read_state->error_handler, c, data);
373*0Sigor@sysoev.ru 
374*0Sigor@sysoev.ru     } else if (ssltls->ssl_error == SSL_ERROR_WANT_READ && ssltls->times < 2) {
375*0Sigor@sysoev.ru         ssltls->times++;
376*0Sigor@sysoev.ru     }
377*0Sigor@sysoev.ru }
378*0Sigor@sysoev.ru 
379*0Sigor@sysoev.ru 
380*0Sigor@sysoev.ru static void
381*0Sigor@sysoev.ru nxt_openssl_conn_io_read(nxt_thread_t *thr, void *obj, void *data)
382*0Sigor@sysoev.ru {
383*0Sigor@sysoev.ru     int                 ret;
384*0Sigor@sysoev.ru     nxt_buf_t           *b;
385*0Sigor@sysoev.ru     nxt_int_t           n;
386*0Sigor@sysoev.ru     nxt_err_t           err;
387*0Sigor@sysoev.ru     nxt_event_conn_t    *c;
388*0Sigor@sysoev.ru     nxt_work_handler_t  handler;
389*0Sigor@sysoev.ru     nxt_openssl_conn_t  *ssltls;
390*0Sigor@sysoev.ru 
391*0Sigor@sysoev.ru     c = obj;
392*0Sigor@sysoev.ru 
393*0Sigor@sysoev.ru     nxt_log_debug(thr->log, "openssl conn read");
394*0Sigor@sysoev.ru 
395*0Sigor@sysoev.ru     handler = c->read_state->ready_handler;
396*0Sigor@sysoev.ru     b = c->read;
397*0Sigor@sysoev.ru 
398*0Sigor@sysoev.ru     /* b == NULL is used to test descriptor readiness. */
399*0Sigor@sysoev.ru 
400*0Sigor@sysoev.ru     if (b != NULL) {
401*0Sigor@sysoev.ru         ssltls = c->u.ssltls;
402*0Sigor@sysoev.ru 
403*0Sigor@sysoev.ru         ret = SSL_read(ssltls->session, b->mem.free, b->mem.end - b->mem.free);
404*0Sigor@sysoev.ru 
405*0Sigor@sysoev.ru         err = (ret <= 0) ? nxt_socket_errno : 0;
406*0Sigor@sysoev.ru 
407*0Sigor@sysoev.ru         nxt_log_debug(thr->log, "SSL_read(%d, %p, %uz): %d err:%d",
408*0Sigor@sysoev.ru                       c->socket.fd, b->mem.free, b->mem.end - b->mem.free,
409*0Sigor@sysoev.ru                       ret, err);
410*0Sigor@sysoev.ru 
411*0Sigor@sysoev.ru         if (ret > 0) {
412*0Sigor@sysoev.ru             /* c->socket.read_ready is kept. */
413*0Sigor@sysoev.ru             b->mem.free += ret;
414*0Sigor@sysoev.ru             handler = c->read_state->ready_handler;
415*0Sigor@sysoev.ru 
416*0Sigor@sysoev.ru         } else {
417*0Sigor@sysoev.ru             n = nxt_openssl_conn_test_error(thr, c, ret, err,
418*0Sigor@sysoev.ru                                             nxt_openssl_conn_io_read);
419*0Sigor@sysoev.ru 
420*0Sigor@sysoev.ru             if (nxt_fast_path(n != NXT_ERROR)) {
421*0Sigor@sysoev.ru                 return;
422*0Sigor@sysoev.ru             }
423*0Sigor@sysoev.ru 
424*0Sigor@sysoev.ru             nxt_openssl_conn_error(c, err, "SSL_read(%d, %p, %uz) failed",
425*0Sigor@sysoev.ru                                    c->socket.fd, b->mem.free,
426*0Sigor@sysoev.ru                                    b->mem.end - b->mem.free);
427*0Sigor@sysoev.ru 
428*0Sigor@sysoev.ru             handler = c->read_state->error_handler;
429*0Sigor@sysoev.ru         }
430*0Sigor@sysoev.ru     }
431*0Sigor@sysoev.ru 
432*0Sigor@sysoev.ru     nxt_event_conn_io_handle(thr, c->read_work_queue, handler, c, data);
433*0Sigor@sysoev.ru }
434*0Sigor@sysoev.ru 
435*0Sigor@sysoev.ru 
436*0Sigor@sysoev.ru static ssize_t
437*0Sigor@sysoev.ru nxt_openssl_conn_io_write_chunk(nxt_thread_t *thr, nxt_event_conn_t *c,
438*0Sigor@sysoev.ru     nxt_buf_t *b, size_t limit)
439*0Sigor@sysoev.ru {
440*0Sigor@sysoev.ru     nxt_openssl_conn_t  *ssltls;
441*0Sigor@sysoev.ru 
442*0Sigor@sysoev.ru     nxt_log_debug(thr->log, "openssl conn write chunk");
443*0Sigor@sysoev.ru 
444*0Sigor@sysoev.ru     ssltls = c->u.ssltls;
445*0Sigor@sysoev.ru 
446*0Sigor@sysoev.ru     return nxt_sendbuf_copy_coalesce(c, &ssltls->buffer, b, limit);
447*0Sigor@sysoev.ru }
448*0Sigor@sysoev.ru 
449*0Sigor@sysoev.ru 
450*0Sigor@sysoev.ru static ssize_t
451*0Sigor@sysoev.ru nxt_openssl_conn_io_send(nxt_event_conn_t *c, void *buf, size_t size)
452*0Sigor@sysoev.ru {
453*0Sigor@sysoev.ru     int                 ret;
454*0Sigor@sysoev.ru     nxt_err_t           err;
455*0Sigor@sysoev.ru     nxt_int_t           n;
456*0Sigor@sysoev.ru     nxt_openssl_conn_t  *ssltls;
457*0Sigor@sysoev.ru 
458*0Sigor@sysoev.ru     ssltls = c->u.ssltls;
459*0Sigor@sysoev.ru 
460*0Sigor@sysoev.ru     ret = SSL_write(ssltls->session, buf, size);
461*0Sigor@sysoev.ru 
462*0Sigor@sysoev.ru     if (ret <= 0) {
463*0Sigor@sysoev.ru         err = nxt_socket_errno;
464*0Sigor@sysoev.ru         c->socket.error = err;
465*0Sigor@sysoev.ru 
466*0Sigor@sysoev.ru     } else {
467*0Sigor@sysoev.ru         err = 0;
468*0Sigor@sysoev.ru     }
469*0Sigor@sysoev.ru 
470*0Sigor@sysoev.ru     nxt_log_debug(c->socket.log, "SSL_write(%d, %p, %uz): %d err:%d",
471*0Sigor@sysoev.ru                   c->socket.fd, buf, size, ret, err);
472*0Sigor@sysoev.ru 
473*0Sigor@sysoev.ru     if (ret > 0) {
474*0Sigor@sysoev.ru         return ret;
475*0Sigor@sysoev.ru     }
476*0Sigor@sysoev.ru 
477*0Sigor@sysoev.ru     n = nxt_openssl_conn_test_error(nxt_thread(), c, ret, err,
478*0Sigor@sysoev.ru                                     nxt_event_conn_io_write);
479*0Sigor@sysoev.ru 
480*0Sigor@sysoev.ru     if (n == NXT_ERROR) {
481*0Sigor@sysoev.ru         nxt_openssl_conn_error(c, err, "SSL_write(%d, %p, %uz) failed",
482*0Sigor@sysoev.ru                                c->socket.fd, buf, size);
483*0Sigor@sysoev.ru     }
484*0Sigor@sysoev.ru 
485*0Sigor@sysoev.ru     return n;
486*0Sigor@sysoev.ru }
487*0Sigor@sysoev.ru 
488*0Sigor@sysoev.ru 
489*0Sigor@sysoev.ru static void
490*0Sigor@sysoev.ru nxt_openssl_conn_io_shutdown(nxt_thread_t *thr, void *obj, void *data)
491*0Sigor@sysoev.ru {
492*0Sigor@sysoev.ru     int                 ret, mode;
493*0Sigor@sysoev.ru     SSL                 *s;
494*0Sigor@sysoev.ru     nxt_err_t           err;
495*0Sigor@sysoev.ru     nxt_int_t           n;
496*0Sigor@sysoev.ru     nxt_bool_t          quiet, once;
497*0Sigor@sysoev.ru     nxt_event_conn_t    *c;
498*0Sigor@sysoev.ru     nxt_work_handler_t  handler;
499*0Sigor@sysoev.ru     nxt_openssl_conn_t  *ssltls;
500*0Sigor@sysoev.ru 
501*0Sigor@sysoev.ru     c = obj;
502*0Sigor@sysoev.ru 
503*0Sigor@sysoev.ru     nxt_log_debug(thr->log, "openssl conn shutdown");
504*0Sigor@sysoev.ru 
505*0Sigor@sysoev.ru     ssltls = c->u.ssltls;
506*0Sigor@sysoev.ru     s = ssltls->session;
507*0Sigor@sysoev.ru 
508*0Sigor@sysoev.ru     if (s == NULL) {
509*0Sigor@sysoev.ru         handler = c->write_state->close_handler;
510*0Sigor@sysoev.ru         goto done;
511*0Sigor@sysoev.ru     }
512*0Sigor@sysoev.ru 
513*0Sigor@sysoev.ru     mode = SSL_get_shutdown(s);
514*0Sigor@sysoev.ru 
515*0Sigor@sysoev.ru     if (c->socket.timedout || c->socket.error != 0) {
516*0Sigor@sysoev.ru         quiet = 1;
517*0Sigor@sysoev.ru 
518*0Sigor@sysoev.ru     } else if (c->socket.closed && !(mode & SSL_RECEIVED_SHUTDOWN)) {
519*0Sigor@sysoev.ru         quiet = 1;
520*0Sigor@sysoev.ru 
521*0Sigor@sysoev.ru     } else {
522*0Sigor@sysoev.ru         quiet = 0;
523*0Sigor@sysoev.ru     }
524*0Sigor@sysoev.ru 
525*0Sigor@sysoev.ru     SSL_set_quiet_shutdown(s, quiet);
526*0Sigor@sysoev.ru 
527*0Sigor@sysoev.ru     once = 1;
528*0Sigor@sysoev.ru 
529*0Sigor@sysoev.ru     for ( ;; ) {
530*0Sigor@sysoev.ru         SSL_set_shutdown(s, mode);
531*0Sigor@sysoev.ru 
532*0Sigor@sysoev.ru         ret = SSL_shutdown(s);
533*0Sigor@sysoev.ru 
534*0Sigor@sysoev.ru         err = (ret <= 0) ? nxt_socket_errno : 0;
535*0Sigor@sysoev.ru 
536*0Sigor@sysoev.ru         nxt_log_debug(thr->log, "SSL_shutdown(%d, %d, %b): %d err:%d",
537*0Sigor@sysoev.ru                       c->socket.fd, mode, quiet, ret, err);
538*0Sigor@sysoev.ru 
539*0Sigor@sysoev.ru         if (ret > 0) {
540*0Sigor@sysoev.ru             /* ret == 1, the shutdown was successfully completed. */
541*0Sigor@sysoev.ru             handler = c->write_state->close_handler;
542*0Sigor@sysoev.ru             goto done;
543*0Sigor@sysoev.ru         }
544*0Sigor@sysoev.ru 
545*0Sigor@sysoev.ru         if (ret == 0) {
546*0Sigor@sysoev.ru             /*
547*0Sigor@sysoev.ru              * If SSL_shutdown() returns 0 then it should be called
548*0Sigor@sysoev.ru              * again.  The second SSL_shutdown() call should returns
549*0Sigor@sysoev.ru              * -1/SSL_ERROR_WANT_READ or -1/SSL_ERROR_WANT_WRITE.
550*0Sigor@sysoev.ru              * OpenSSL prior to 0.9.8m version however never returns
551*0Sigor@sysoev.ru              * -1 at all.  Fortunately, OpenSSL internals preserve
552*0Sigor@sysoev.ru              * correct status available via SSL_get_error(-1).
553*0Sigor@sysoev.ru              */
554*0Sigor@sysoev.ru             if (once) {
555*0Sigor@sysoev.ru                 mode = SSL_get_shutdown(s);
556*0Sigor@sysoev.ru                 once = 0;
557*0Sigor@sysoev.ru                 continue;
558*0Sigor@sysoev.ru             }
559*0Sigor@sysoev.ru 
560*0Sigor@sysoev.ru             ret = -1;
561*0Sigor@sysoev.ru         }
562*0Sigor@sysoev.ru 
563*0Sigor@sysoev.ru         /* ret == -1 */
564*0Sigor@sysoev.ru 
565*0Sigor@sysoev.ru         break;
566*0Sigor@sysoev.ru     }
567*0Sigor@sysoev.ru 
568*0Sigor@sysoev.ru     n = nxt_openssl_conn_test_error(thr, c, ret, err,
569*0Sigor@sysoev.ru                                     nxt_openssl_conn_io_shutdown);
570*0Sigor@sysoev.ru 
571*0Sigor@sysoev.ru     if (nxt_fast_path(n == 0)) {
572*0Sigor@sysoev.ru         return;
573*0Sigor@sysoev.ru     }
574*0Sigor@sysoev.ru 
575*0Sigor@sysoev.ru     if (n != NXT_ERROR) {  /* n == NXT_AGAIN */
576*0Sigor@sysoev.ru         c->socket.error_handler = c->read_state->error_handler;
577*0Sigor@sysoev.ru         nxt_event_timer_add(thr->engine, &c->read_timer, 5000);
578*0Sigor@sysoev.ru         return;
579*0Sigor@sysoev.ru     }
580*0Sigor@sysoev.ru 
581*0Sigor@sysoev.ru     nxt_openssl_conn_error(c, err, "SSL_shutdown(%d) failed", c->socket.fd);
582*0Sigor@sysoev.ru 
583*0Sigor@sysoev.ru     handler = c->write_state->error_handler;
584*0Sigor@sysoev.ru 
585*0Sigor@sysoev.ru done:
586*0Sigor@sysoev.ru 
587*0Sigor@sysoev.ru     nxt_event_conn_io_handle(thr, c->write_work_queue, handler, c, data);
588*0Sigor@sysoev.ru }
589*0Sigor@sysoev.ru 
590*0Sigor@sysoev.ru 
591*0Sigor@sysoev.ru static nxt_int_t
592*0Sigor@sysoev.ru nxt_openssl_conn_test_error(nxt_thread_t *thr, nxt_event_conn_t *c, int ret,
593*0Sigor@sysoev.ru     nxt_err_t sys_err, nxt_work_handler_t handler)
594*0Sigor@sysoev.ru {
595*0Sigor@sysoev.ru     u_long              lib_err;
596*0Sigor@sysoev.ru     nxt_work_queue_t    *wq;
597*0Sigor@sysoev.ru     nxt_openssl_conn_t  *ssltls;
598*0Sigor@sysoev.ru 
599*0Sigor@sysoev.ru     ssltls = c->u.ssltls;
600*0Sigor@sysoev.ru 
601*0Sigor@sysoev.ru     ssltls->ssl_error = SSL_get_error(ssltls->session, ret);
602*0Sigor@sysoev.ru 
603*0Sigor@sysoev.ru     nxt_log_debug(c->socket.log, "SSL_get_error(): %d", ssltls->ssl_error);
604*0Sigor@sysoev.ru 
605*0Sigor@sysoev.ru     switch (ssltls->ssl_error) {
606*0Sigor@sysoev.ru 
607*0Sigor@sysoev.ru     case SSL_ERROR_WANT_READ:
608*0Sigor@sysoev.ru         nxt_event_fd_block_write(thr->engine, &c->socket);
609*0Sigor@sysoev.ru 
610*0Sigor@sysoev.ru         c->socket.read_ready = 0;
611*0Sigor@sysoev.ru         c->socket.read_handler = handler;
612*0Sigor@sysoev.ru 
613*0Sigor@sysoev.ru         if (nxt_event_fd_is_disabled(c->socket.read)) {
614*0Sigor@sysoev.ru             nxt_event_fd_enable_read(thr->engine, &c->socket);
615*0Sigor@sysoev.ru         }
616*0Sigor@sysoev.ru 
617*0Sigor@sysoev.ru         return NXT_AGAIN;
618*0Sigor@sysoev.ru 
619*0Sigor@sysoev.ru     case SSL_ERROR_WANT_WRITE:
620*0Sigor@sysoev.ru         nxt_event_fd_block_read(thr->engine, &c->socket);
621*0Sigor@sysoev.ru 
622*0Sigor@sysoev.ru         c->socket.write_ready = 0;
623*0Sigor@sysoev.ru         c->socket.write_handler = handler;
624*0Sigor@sysoev.ru 
625*0Sigor@sysoev.ru         if (nxt_event_fd_is_disabled(c->socket.write)) {
626*0Sigor@sysoev.ru             nxt_event_fd_enable_write(thr->engine, &c->socket);
627*0Sigor@sysoev.ru         }
628*0Sigor@sysoev.ru 
629*0Sigor@sysoev.ru         return NXT_AGAIN;
630*0Sigor@sysoev.ru 
631*0Sigor@sysoev.ru     case SSL_ERROR_SYSCALL:
632*0Sigor@sysoev.ru 
633*0Sigor@sysoev.ru         lib_err = ERR_peek_error();
634*0Sigor@sysoev.ru 
635*0Sigor@sysoev.ru         nxt_log_debug(c->socket.log, "ERR_peek_error(): %l", lib_err);
636*0Sigor@sysoev.ru 
637*0Sigor@sysoev.ru         if (sys_err != 0 || lib_err != 0) {
638*0Sigor@sysoev.ru             return NXT_ERROR;
639*0Sigor@sysoev.ru         }
640*0Sigor@sysoev.ru 
641*0Sigor@sysoev.ru         /* A connection was just closed. */
642*0Sigor@sysoev.ru         c->socket.closed = 1;
643*0Sigor@sysoev.ru 
644*0Sigor@sysoev.ru         /* Fall through. */
645*0Sigor@sysoev.ru 
646*0Sigor@sysoev.ru     case SSL_ERROR_ZERO_RETURN:
647*0Sigor@sysoev.ru         /* A "close notify" alert. */
648*0Sigor@sysoev.ru 
649*0Sigor@sysoev.ru         if (c->read_state != NULL) {
650*0Sigor@sysoev.ru             wq = c->read_work_queue;
651*0Sigor@sysoev.ru             handler = c->read_state->close_handler;
652*0Sigor@sysoev.ru 
653*0Sigor@sysoev.ru         } else {
654*0Sigor@sysoev.ru             wq = c->write_work_queue;
655*0Sigor@sysoev.ru             handler = c->write_state->close_handler;
656*0Sigor@sysoev.ru         }
657*0Sigor@sysoev.ru 
658*0Sigor@sysoev.ru         nxt_event_conn_io_handle(thr, wq, handler, c, c->socket.data);
659*0Sigor@sysoev.ru 
660*0Sigor@sysoev.ru         return 0;
661*0Sigor@sysoev.ru 
662*0Sigor@sysoev.ru     default: /* SSL_ERROR_SSL, etc. */
663*0Sigor@sysoev.ru         c->socket.error = 1000;  /* Nonexistent errno code. */
664*0Sigor@sysoev.ru         return NXT_ERROR;
665*0Sigor@sysoev.ru     }
666*0Sigor@sysoev.ru }
667*0Sigor@sysoev.ru 
668*0Sigor@sysoev.ru 
669*0Sigor@sysoev.ru static void nxt_cdecl
670*0Sigor@sysoev.ru nxt_openssl_conn_error(nxt_event_conn_t *c, nxt_err_t err, const char *fmt, ...)
671*0Sigor@sysoev.ru {
672*0Sigor@sysoev.ru     u_char      *p, *end;
673*0Sigor@sysoev.ru     va_list     args;
674*0Sigor@sysoev.ru     nxt_uint_t  level;
675*0Sigor@sysoev.ru     u_char      msg[NXT_MAX_ERROR_STR];
676*0Sigor@sysoev.ru 
677*0Sigor@sysoev.ru     c->socket.error = err;
678*0Sigor@sysoev.ru     level = nxt_openssl_log_error_level(c, err);
679*0Sigor@sysoev.ru 
680*0Sigor@sysoev.ru     if (nxt_log_level_enough(c->socket.log, level)) {
681*0Sigor@sysoev.ru 
682*0Sigor@sysoev.ru         end = msg + sizeof(msg);
683*0Sigor@sysoev.ru 
684*0Sigor@sysoev.ru         va_start(args, fmt);
685*0Sigor@sysoev.ru         p = nxt_vsprintf(msg, end, fmt, args);
686*0Sigor@sysoev.ru         va_end(args);
687*0Sigor@sysoev.ru 
688*0Sigor@sysoev.ru         if (err != 0) {
689*0Sigor@sysoev.ru             p = nxt_sprintf(p, end, " %E", err);
690*0Sigor@sysoev.ru         }
691*0Sigor@sysoev.ru 
692*0Sigor@sysoev.ru         p = nxt_openssl_copy_error(p, end);
693*0Sigor@sysoev.ru 
694*0Sigor@sysoev.ru         nxt_log_error(level, c->socket.log, "%*s", p - msg, msg);
695*0Sigor@sysoev.ru 
696*0Sigor@sysoev.ru     } else {
697*0Sigor@sysoev.ru         ERR_clear_error();
698*0Sigor@sysoev.ru     }
699*0Sigor@sysoev.ru }
700*0Sigor@sysoev.ru 
701*0Sigor@sysoev.ru 
702*0Sigor@sysoev.ru static nxt_uint_t
703*0Sigor@sysoev.ru nxt_openssl_log_error_level(nxt_event_conn_t *c, nxt_err_t err)
704*0Sigor@sysoev.ru {
705*0Sigor@sysoev.ru     switch (ERR_GET_REASON(ERR_peek_error())) {
706*0Sigor@sysoev.ru 
707*0Sigor@sysoev.ru     case 0:
708*0Sigor@sysoev.ru         return nxt_socket_error_level(err, c->socket.log_error);
709*0Sigor@sysoev.ru 
710*0Sigor@sysoev.ru     case SSL_R_BAD_CHANGE_CIPHER_SPEC:                    /*  103 */
711*0Sigor@sysoev.ru     case SSL_R_BLOCK_CIPHER_PAD_IS_WRONG:                 /*  129 */
712*0Sigor@sysoev.ru     case SSL_R_DIGEST_CHECK_FAILED:                       /*  149 */
713*0Sigor@sysoev.ru     case SSL_R_ERROR_IN_RECEIVED_CIPHER_LIST:             /*  151 */
714*0Sigor@sysoev.ru     case SSL_R_EXCESSIVE_MESSAGE_SIZE:                    /*  152 */
715*0Sigor@sysoev.ru     case SSL_R_LENGTH_MISMATCH:                           /*  159 */
716*0Sigor@sysoev.ru     case SSL_R_NO_CIPHERS_PASSED:                         /*  182 */
717*0Sigor@sysoev.ru     case SSL_R_NO_CIPHERS_SPECIFIED:                      /*  183 */
718*0Sigor@sysoev.ru     case SSL_R_NO_COMPRESSION_SPECIFIED:                  /*  187 */
719*0Sigor@sysoev.ru     case SSL_R_NO_SHARED_CIPHER:                          /*  193 */
720*0Sigor@sysoev.ru     case SSL_R_RECORD_LENGTH_MISMATCH:                    /*  213 */
721*0Sigor@sysoev.ru #ifdef SSL_R_PARSE_TLSEXT
722*0Sigor@sysoev.ru     case SSL_R_PARSE_TLSEXT:                              /*  227 */
723*0Sigor@sysoev.ru #endif
724*0Sigor@sysoev.ru     case SSL_R_UNEXPECTED_MESSAGE:                        /*  244 */
725*0Sigor@sysoev.ru     case SSL_R_UNEXPECTED_RECORD:                         /*  245 */
726*0Sigor@sysoev.ru     case SSL_R_UNKNOWN_ALERT_TYPE:                        /*  246 */
727*0Sigor@sysoev.ru     case SSL_R_UNKNOWN_PROTOCOL:                          /*  252 */
728*0Sigor@sysoev.ru     case SSL_R_WRONG_VERSION_NUMBER:                      /*  267 */
729*0Sigor@sysoev.ru     case SSL_R_DECRYPTION_FAILED_OR_BAD_RECORD_MAC:       /*  281 */
730*0Sigor@sysoev.ru #ifdef SSL_R_RENEGOTIATE_EXT_TOO_LONG
731*0Sigor@sysoev.ru     case SSL_R_RENEGOTIATE_EXT_TOO_LONG:                  /*  335 */
732*0Sigor@sysoev.ru     case SSL_R_RENEGOTIATION_ENCODING_ERR:                /*  336 */
733*0Sigor@sysoev.ru     case SSL_R_RENEGOTIATION_MISMATCH:                    /*  337 */
734*0Sigor@sysoev.ru #endif
735*0Sigor@sysoev.ru #ifdef SSL_R_UNSAFE_LEGACY_RENEGOTIATION_DISABLED
736*0Sigor@sysoev.ru     case SSL_R_UNSAFE_LEGACY_RENEGOTIATION_DISABLED:      /*  338 */
737*0Sigor@sysoev.ru #endif
738*0Sigor@sysoev.ru #ifdef SSL_R_SCSV_RECEIVED_WHEN_RENEGOTIATING
739*0Sigor@sysoev.ru     case SSL_R_SCSV_RECEIVED_WHEN_RENEGOTIATING:          /*  345 */
740*0Sigor@sysoev.ru #endif
741*0Sigor@sysoev.ru     case 1000:/* SSL_R_SSLV3_ALERT_CLOSE_NOTIFY */
742*0Sigor@sysoev.ru     case SSL_R_SSLV3_ALERT_UNEXPECTED_MESSAGE:            /* 1010 */
743*0Sigor@sysoev.ru     case SSL_R_SSLV3_ALERT_BAD_RECORD_MAC:                /* 1020 */
744*0Sigor@sysoev.ru     case SSL_R_TLSV1_ALERT_DECRYPTION_FAILED:             /* 1021 */
745*0Sigor@sysoev.ru     case SSL_R_TLSV1_ALERT_RECORD_OVERFLOW:               /* 1022 */
746*0Sigor@sysoev.ru     case SSL_R_SSLV3_ALERT_DECOMPRESSION_FAILURE:         /* 1030 */
747*0Sigor@sysoev.ru     case SSL_R_SSLV3_ALERT_HANDSHAKE_FAILURE:             /* 1040 */
748*0Sigor@sysoev.ru     case SSL_R_SSLV3_ALERT_ILLEGAL_PARAMETER:             /* 1047 */
749*0Sigor@sysoev.ru         break;
750*0Sigor@sysoev.ru 
751*0Sigor@sysoev.ru     case SSL_R_SSLV3_ALERT_NO_CERTIFICATE:                /* 1041 */
752*0Sigor@sysoev.ru     case SSL_R_SSLV3_ALERT_BAD_CERTIFICATE:               /* 1042 */
753*0Sigor@sysoev.ru     case SSL_R_SSLV3_ALERT_UNSUPPORTED_CERTIFICATE:       /* 1043 */
754*0Sigor@sysoev.ru     case SSL_R_SSLV3_ALERT_CERTIFICATE_REVOKED:           /* 1044 */
755*0Sigor@sysoev.ru     case SSL_R_SSLV3_ALERT_CERTIFICATE_EXPIRED:           /* 1045 */
756*0Sigor@sysoev.ru     case SSL_R_SSLV3_ALERT_CERTIFICATE_UNKNOWN:           /* 1046 */
757*0Sigor@sysoev.ru     case SSL_R_TLSV1_ALERT_UNKNOWN_CA:                    /* 1048 */
758*0Sigor@sysoev.ru     case SSL_R_TLSV1_ALERT_ACCESS_DENIED:                 /* 1049 */
759*0Sigor@sysoev.ru     case SSL_R_TLSV1_ALERT_DECODE_ERROR:                  /* 1050 */
760*0Sigor@sysoev.ru     case SSL_R_TLSV1_ALERT_DECRYPT_ERROR:                 /* 1051 */
761*0Sigor@sysoev.ru     case SSL_R_TLSV1_ALERT_EXPORT_RESTRICTION:            /* 1060 */
762*0Sigor@sysoev.ru     case SSL_R_TLSV1_ALERT_PROTOCOL_VERSION:              /* 1070 */
763*0Sigor@sysoev.ru     case SSL_R_TLSV1_ALERT_INSUFFICIENT_SECURITY:         /* 1071 */
764*0Sigor@sysoev.ru     case SSL_R_TLSV1_ALERT_INTERNAL_ERROR:                /* 1080 */
765*0Sigor@sysoev.ru     case SSL_R_TLSV1_ALERT_USER_CANCELLED:                /* 1090 */
766*0Sigor@sysoev.ru     case SSL_R_TLSV1_ALERT_NO_RENEGOTIATION:              /* 1100 */
767*0Sigor@sysoev.ru         return NXT_LOG_ERR;
768*0Sigor@sysoev.ru 
769*0Sigor@sysoev.ru     default:
770*0Sigor@sysoev.ru         return NXT_LOG_CRIT;
771*0Sigor@sysoev.ru     }
772*0Sigor@sysoev.ru 
773*0Sigor@sysoev.ru     return NXT_LOG_INFO;
774*0Sigor@sysoev.ru }
775*0Sigor@sysoev.ru 
776*0Sigor@sysoev.ru 
777*0Sigor@sysoev.ru static void nxt_cdecl
778*0Sigor@sysoev.ru nxt_openssl_log_error(nxt_uint_t level, nxt_log_t *log, const char *fmt, ...)
779*0Sigor@sysoev.ru {
780*0Sigor@sysoev.ru     u_char   *p, *end;
781*0Sigor@sysoev.ru     va_list  args;
782*0Sigor@sysoev.ru     u_char   msg[NXT_MAX_ERROR_STR];
783*0Sigor@sysoev.ru 
784*0Sigor@sysoev.ru     end = msg + sizeof(msg);
785*0Sigor@sysoev.ru 
786*0Sigor@sysoev.ru     va_start(args, fmt);
787*0Sigor@sysoev.ru     p = nxt_vsprintf(msg, end, fmt, args);
788*0Sigor@sysoev.ru     va_end(args);
789*0Sigor@sysoev.ru 
790*0Sigor@sysoev.ru     p = nxt_openssl_copy_error(p, end);
791*0Sigor@sysoev.ru 
792*0Sigor@sysoev.ru     nxt_log_error(level, log, "%*s", p - msg, msg);
793*0Sigor@sysoev.ru }
794*0Sigor@sysoev.ru 
795*0Sigor@sysoev.ru 
796*0Sigor@sysoev.ru static u_char *
797*0Sigor@sysoev.ru nxt_openssl_copy_error(u_char *p, u_char *end)
798*0Sigor@sysoev.ru {
799*0Sigor@sysoev.ru     int         flags;
800*0Sigor@sysoev.ru     u_long      err;
801*0Sigor@sysoev.ru     nxt_bool_t  clear;
802*0Sigor@sysoev.ru     const char  *data, *delimiter;
803*0Sigor@sysoev.ru 
804*0Sigor@sysoev.ru     err = ERR_peek_error();
805*0Sigor@sysoev.ru     if (err == 0) {
806*0Sigor@sysoev.ru         return p;
807*0Sigor@sysoev.ru     }
808*0Sigor@sysoev.ru 
809*0Sigor@sysoev.ru     /* Log the most relevant error message ... */
810*0Sigor@sysoev.ru     data = ERR_reason_error_string(err);
811*0Sigor@sysoev.ru 
812*0Sigor@sysoev.ru     p = nxt_sprintf(p, end, " (%d: %s) (OpenSSL: ", ERR_GET_REASON(err), data);
813*0Sigor@sysoev.ru 
814*0Sigor@sysoev.ru     /*
815*0Sigor@sysoev.ru      * ... followed by all queued cumbersome OpenSSL
816*0Sigor@sysoev.ru      * error messages and drain the error queue.
817*0Sigor@sysoev.ru      */
818*0Sigor@sysoev.ru     delimiter = "";
819*0Sigor@sysoev.ru     clear = 0;
820*0Sigor@sysoev.ru 
821*0Sigor@sysoev.ru     for ( ;; ) {
822*0Sigor@sysoev.ru         err = ERR_get_error_line_data(NULL, NULL, &data, &flags);
823*0Sigor@sysoev.ru         if (err == 0) {
824*0Sigor@sysoev.ru             break;
825*0Sigor@sysoev.ru         }
826*0Sigor@sysoev.ru 
827*0Sigor@sysoev.ru         p = nxt_sprintf(p, end, "%s", delimiter);
828*0Sigor@sysoev.ru 
829*0Sigor@sysoev.ru         ERR_error_string_n(err, (char *) p, end - p);
830*0Sigor@sysoev.ru 
831*0Sigor@sysoev.ru         while (p < end && *p != '\0') {
832*0Sigor@sysoev.ru             p++;
833*0Sigor@sysoev.ru         }
834*0Sigor@sysoev.ru 
835*0Sigor@sysoev.ru         if ((flags & ERR_TXT_STRING) != 0) {
836*0Sigor@sysoev.ru             p = nxt_sprintf(p, end, ":%s", data);
837*0Sigor@sysoev.ru         }
838*0Sigor@sysoev.ru 
839*0Sigor@sysoev.ru         clear |= ((flags & ERR_TXT_MALLOCED) != 0);
840*0Sigor@sysoev.ru 
841*0Sigor@sysoev.ru         delimiter = "; ";
842*0Sigor@sysoev.ru     }
843*0Sigor@sysoev.ru 
844*0Sigor@sysoev.ru     /* Deallocate additional data. */
845*0Sigor@sysoev.ru 
846*0Sigor@sysoev.ru     if (clear) {
847*0Sigor@sysoev.ru         ERR_clear_error();
848*0Sigor@sysoev.ru     }
849*0Sigor@sysoev.ru 
850*0Sigor@sysoev.ru     if (p < end) {
851*0Sigor@sysoev.ru         *p++ = ')';
852*0Sigor@sysoev.ru     }
853*0Sigor@sysoev.ru 
854*0Sigor@sysoev.ru     return p;
855*0Sigor@sysoev.ru }
856