3 * Copyright (C) Igor Sysoev
7 #include <ngx_config.h>
11 #include <openssl/engine.h>
14 static ngx_int_t
ngx_ssl_handle_recv(ngx_connection_t
*c
, int n
);
15 static void ngx_ssl_write_handler(ngx_event_t
*wev
);
16 static ssize_t
ngx_ssl_write(ngx_connection_t
*c
, u_char
*data
, size_t size
);
17 static void ngx_ssl_read_handler(ngx_event_t
*rev
);
21 ngx_ssl_init(ngx_log_t
*log
)
26 SSL_load_error_strings();
27 ENGINE_load_builtin_engines();
34 ngx_ssl_create_session(ngx_ssl_ctx_t
*ssl_ctx
, ngx_connection_t
*c
,
39 if (!(ssl
= ngx_pcalloc(c
->pool
, sizeof(ngx_ssl_t
)))) {
43 if (!(ssl
->buf
= ngx_create_temp_buf(c
->pool
, NGX_SSL_BUFSIZE
))) {
47 if (flags
& NGX_SSL_BUFFER
) {
51 ssl
->ssl
= SSL_new(ssl_ctx
);
53 if (ssl
->ssl
== NULL
) {
54 ngx_ssl_error(NGX_LOG_ALERT
, c
->log
, 0, "SSL_new() failed");
58 if (SSL_set_fd(ssl
->ssl
, c
->fd
) == 0) {
59 ngx_ssl_error(NGX_LOG_ALERT
, c
->log
, 0, "SSL_set_fd() failed");
63 SSL_set_accept_state(ssl
->ssl
);
72 ngx_ssl_recv(ngx_connection_t
*c
, u_char
*buf
, size_t size
)
76 if (c
->ssl
->last
== NGX_ERROR
) {
83 * SSL_read() may return data in parts, so try to read
84 * until SSL_read() would return no data
89 n
= SSL_read(c
->ssl
->ssl
, buf
, size
);
91 ngx_log_debug1(NGX_LOG_DEBUG_EVENT
, c
->log
, 0, "SSL_read: %d", n
);
99 if (!c
->ssl
->handshaked
&& SSL_is_init_finished(c
->ssl
->ssl
)) {
100 char buf
[129], *s
, *d
;
103 c
->ssl
->handshaked
= 1;
105 cipher
= SSL_get_current_cipher(c
->ssl
->ssl
);
108 SSL_CIPHER_description(cipher
, &buf
[1], 128);
110 for (s
= &buf
[1], d
= buf
; *s
; s
++) {
111 if (*s
== ' ' && *d
== ' ') {
115 if (*s
== '\n' || *s
== '\r') {
128 ngx_log_debug1(NGX_LOG_DEBUG_EVENT
, c
->log
, 0,
129 "SSL cipher: \"%s\"", &buf
[1]);
131 ngx_log_debug0(NGX_LOG_DEBUG_EVENT
, c
->log
, 0,
132 "SSL no shared ciphers");
139 c
->ssl
->last
= ngx_ssl_handle_recv(c
, n
);
141 if (c
->ssl
->last
!= NGX_OK
) {
163 ngx_ssl_handle_recv(ngx_connection_t
*c
, int n
)
171 if (c
->ssl
->saved_write_handler
) {
173 c
->write
->event_handler
= c
->ssl
->saved_write_handler
;
174 c
->ssl
->saved_write_handler
= NULL
;
177 if (ngx_handle_write_event(c
->write
, 0) == NGX_ERROR
) {
181 if (ngx_mutex_lock(ngx_posted_events_mutex
) == NGX_ERROR
) {
185 ngx_post_event(c
->write
);
187 ngx_mutex_unlock(ngx_posted_events_mutex
);
193 if (!SSL_is_init_finished(c
->ssl
->ssl
)) {
194 handshake
= " in SSL handshake";
200 sslerr
= SSL_get_error(c
->ssl
->ssl
, n
);
202 err
= (sslerr
== SSL_ERROR_SYSCALL
) ? ngx_errno
: 0;
204 ngx_log_debug1(NGX_LOG_DEBUG_EVENT
, c
->log
, 0, "SSL_get_error: %d", sslerr
);
206 if (sslerr
== SSL_ERROR_WANT_READ
) {
211 if (sslerr
== SSL_ERROR_WANT_WRITE
) {
212 ngx_log_error(NGX_LOG_ALERT
, c
->log
, err
,
213 "SSL wants to write%s", handshake
);
217 if (ngx_handle_write_event(c
->write
, 0) == NGX_ERROR
) {
222 * we do not set the timer because there is already the read event timer
225 if (c
->ssl
->saved_write_handler
== NULL
) {
226 c
->ssl
->saved_write_handler
= c
->write
->event_handler
;
227 c
->write
->event_handler
= ngx_ssl_write_handler
;
233 c
->ssl
->no_rcv_shut
= 1;
234 c
->ssl
->no_send_shut
= 1;
236 if (sslerr
== SSL_ERROR_ZERO_RETURN
|| ERR_peek_error() == 0) {
237 ngx_log_error(NGX_LOG_INFO
, c
->log
, err
,
238 "client closed connection%s", handshake
);
243 ngx_ssl_error(NGX_LOG_ALERT
, c
->log
, err
,
244 "SSL_read() failed%s", handshake
);
251 ngx_ssl_write_handler(ngx_event_t
*wev
)
256 c
->read
->event_handler(c
->read
);
261 * OpenSSL has no SSL_writev() so we copy several bufs into our 16K buffer
262 * before the SSL_write() call to decrease a SSL overhead.
264 * Besides for protocols such as HTTP it is possible to always buffer
265 * the output to decrease a SSL overhead some more.
269 ngx_ssl_send_chain(ngx_connection_t
*c
, ngx_chain_t
*in
, off_t limit
)
278 if (in
&& in
->next
== NULL
&& !c
->buffered
&& !c
->ssl
->buffer
) {
281 * we avoid a buffer copy if the incoming buf is a single,
282 * our buffer is empty, and we do not need to buffer the output
285 n
= ngx_ssl_write(c
, in
->buf
->pos
, in
->buf
->last
- in
->buf
->pos
);
287 if (n
== NGX_ERROR
) {
288 return NGX_CHAIN_ERROR
;
301 /* the maximum limit size is the maximum uint32_t value - the page size */
303 if (limit
== 0 || limit
> NGX_MAX_UINT32_VALUE
- ngx_pagesize
) {
304 limit
= NGX_MAX_UINT32_VALUE
- ngx_pagesize
;
309 flush
= (in
== NULL
) ? 1 : 0;
313 while (in
&& buf
->last
< buf
->end
) {
314 if (in
->buf
->last_buf
) {
318 if (ngx_buf_special(in
->buf
)) {
323 size
= in
->buf
->last
- in
->buf
->pos
;
325 if (size
> buf
->end
- buf
->last
) {
326 size
= buf
->end
- buf
->last
;
330 * TODO: the taking in->buf->flush into account can be
331 * implemented using the limit on the higher level
334 if (send
+ size
> limit
) {
339 ngx_log_debug1(NGX_LOG_DEBUG_EVENT
, c
->log
, 0,
340 "SSL buf copy: %d", size
);
342 ngx_memcpy(buf
->last
, in
->buf
->pos
, size
);
346 in
->buf
->pos
+= size
;
347 if (in
->buf
->pos
== in
->buf
->last
) {
352 size
= buf
->last
- buf
->pos
;
354 if (!flush
&& buf
->last
< buf
->end
&& c
->ssl
->buffer
) {
358 n
= ngx_ssl_write(c
, buf
->pos
, size
);
360 if (n
== NGX_ERROR
) {
361 return NGX_CHAIN_ERROR
;
376 if (buf
->pos
== buf
->last
) {
377 buf
->pos
= buf
->start
;
378 buf
->last
= buf
->start
;
381 if (in
== NULL
|| send
== limit
) {
386 c
->buffered
= (buf
->pos
< buf
->last
) ? 1 : 0;
393 ngx_ssl_write(ngx_connection_t
*c
, u_char
*data
, size_t size
)
399 ngx_log_debug1(NGX_LOG_DEBUG_EVENT
, c
->log
, 0, "SSL to write: %d", size
);
401 n
= SSL_write(c
->ssl
->ssl
, data
, size
);
403 ngx_log_debug1(NGX_LOG_DEBUG_EVENT
, c
->log
, 0, "SSL_write: %d", n
);
406 if (c
->ssl
->saved_read_handler
) {
408 c
->read
->event_handler
= c
->ssl
->saved_read_handler
;
409 c
->ssl
->saved_read_handler
= NULL
;
412 if (ngx_handle_read_event(c
->read
, 0) == NGX_ERROR
) {
416 if (ngx_mutex_lock(ngx_posted_events_mutex
) == NGX_ERROR
) {
420 ngx_post_event(c
->read
);
422 ngx_mutex_unlock(ngx_posted_events_mutex
);
428 sslerr
= SSL_get_error(c
->ssl
->ssl
, n
);
430 err
= (sslerr
== SSL_ERROR_SYSCALL
) ? ngx_errno
: 0;
432 ngx_log_debug1(NGX_LOG_DEBUG_EVENT
, c
->log
, 0, "SSL_get_error: %d", sslerr
);
434 if (sslerr
== SSL_ERROR_WANT_WRITE
) {
439 if (sslerr
== SSL_ERROR_WANT_READ
) {
441 if (!SSL_is_init_finished(c
->ssl
->ssl
)) {
442 handshake
= " in SSL handshake";
448 ngx_log_error(NGX_LOG_ALERT
, c
->log
, err
,
449 "SSL wants to read%s", handshake
);
453 if (ngx_handle_read_event(c
->read
, 0) == NGX_ERROR
) {
458 * we do not set the timer because there is already
459 * the write event timer
462 if (c
->ssl
->saved_read_handler
== NULL
) {
463 c
->ssl
->saved_read_handler
= c
->read
->event_handler
;
464 c
->read
->event_handler
= ngx_ssl_read_handler
;
470 c
->ssl
->no_rcv_shut
= 1;
471 c
->ssl
->no_send_shut
= 1;
473 ngx_ssl_error(NGX_LOG_ALERT
, c
->log
, err
, "SSL_write() failed");
480 ngx_ssl_read_handler(ngx_event_t
*rev
)
485 c
->write
->event_handler(c
->write
);
490 ngx_ssl_shutdown(ngx_connection_t
*c
)
495 if (!c
->ssl
->shutdown_set
) {
497 /* it seems that SSL_set_shutdown() could be called once only */
499 if (c
->read
->timedout
) {
500 mode
= SSL_RECEIVED_SHUTDOWN
|SSL_SENT_SHUTDOWN
;
505 if (c
->ssl
->no_rcv_shut
) {
506 mode
= SSL_RECEIVED_SHUTDOWN
;
509 if (c
->ssl
->no_send_shut
) {
510 mode
|= SSL_SENT_SHUTDOWN
;
515 SSL_set_shutdown(c
->ssl
->ssl
, mode
);
516 c
->ssl
->shutdown_set
= 1;
521 #if (NGX_SUPPRESS_WARN)
526 n
= SSL_shutdown(c
->ssl
->ssl
);
528 ngx_log_debug1(NGX_LOG_DEBUG_EVENT
, c
->log
, 0, "SSL_shutdown: %d", n
);
530 if (n
== 1 || (n
== 0 && c
->read
->timedout
)) {
531 SSL_free(c
->ssl
->ssl
);
545 sslerr
= SSL_get_error(c
->ssl
->ssl
, n
);
547 ngx_log_debug1(NGX_LOG_DEBUG_EVENT
, c
->log
, 0,
548 "SSL_get_error: %d", sslerr
);
551 if (again
|| sslerr
== SSL_ERROR_WANT_READ
) {
553 ngx_add_timer(c
->read
, 30000);
555 if (ngx_handle_read_event(c
->read
, 0) == NGX_ERROR
) {
562 if (sslerr
== SSL_ERROR_WANT_WRITE
) {
564 if (ngx_handle_write_event(c
->write
, 0) == NGX_ERROR
) {
571 ngx_ssl_error(NGX_LOG_ALERT
, c
->log
, 0, "SSL_shutdown() failed");
578 ngx_ssl_error(ngx_uint_t level
, ngx_log_t
*log
, ngx_err_t err
, char *fmt
, ...)
580 u_char errstr
[NGX_MAX_CONF_ERRSTR
], *p
, *last
;
583 last
= errstr
+ NGX_MAX_CONF_ERRSTR
;
586 p
= ngx_vsnprintf(errstr
, sizeof(errstr
) - 1, fmt
, args
);
589 p
= ngx_cpystrn(p
, " (SSL: ", last
- p
);
591 ERR_error_string_n(ERR_get_error(), (char *) p
, last
- p
);
593 ngx_log_error(level
, log
, err
, "%s)", errstr
);