Fix work keepalive and rewrite to named location
[nginx-catap.git] / src / event / ngx_event_openssl.c
blob04baa81f8821e35bf09879b2adeec0d7cc9b067f
2 /*
3 * Copyright (C) Igor Sysoev
4 */
7 #include <ngx_config.h>
8 #include <ngx_core.h>
9 #include <ngx_event.h>
12 typedef struct {
13 ngx_uint_t engine; /* unsigned engine:1; */
14 } ngx_openssl_conf_t;
17 static int ngx_http_ssl_verify_callback(int ok, X509_STORE_CTX *x509_store);
18 static void ngx_ssl_info_callback(const ngx_ssl_conn_t *ssl_conn, int where,
19 int ret);
20 static void ngx_ssl_handshake_handler(ngx_event_t *ev);
21 static ngx_int_t ngx_ssl_handle_recv(ngx_connection_t *c, int n);
22 static void ngx_ssl_write_handler(ngx_event_t *wev);
23 static void ngx_ssl_read_handler(ngx_event_t *rev);
24 static void ngx_ssl_shutdown_handler(ngx_event_t *ev);
25 static void ngx_ssl_connection_error(ngx_connection_t *c, int sslerr,
26 ngx_err_t err, char *text);
27 static void ngx_ssl_clear_error(ngx_log_t *log);
29 static ngx_int_t ngx_ssl_session_cache_init(ngx_shm_zone_t *shm_zone,
30 void *data);
31 static int ngx_ssl_new_session(ngx_ssl_conn_t *ssl_conn,
32 ngx_ssl_session_t *sess);
33 static ngx_ssl_session_t *ngx_ssl_get_cached_session(ngx_ssl_conn_t *ssl_conn,
34 u_char *id, int len, int *copy);
35 static void ngx_ssl_remove_session(SSL_CTX *ssl, ngx_ssl_session_t *sess);
36 static void ngx_ssl_expire_sessions(ngx_ssl_session_cache_t *cache,
37 ngx_slab_pool_t *shpool, ngx_uint_t n);
38 static void ngx_ssl_session_rbtree_insert_value(ngx_rbtree_node_t *temp,
39 ngx_rbtree_node_t *node, ngx_rbtree_node_t *sentinel);
41 static void *ngx_openssl_create_conf(ngx_cycle_t *cycle);
42 static char *ngx_openssl_engine(ngx_conf_t *cf, ngx_command_t *cmd, void *conf);
43 static void ngx_openssl_exit(ngx_cycle_t *cycle);
46 static ngx_command_t ngx_openssl_commands[] = {
48 { ngx_string("ssl_engine"),
49 NGX_MAIN_CONF|NGX_DIRECT_CONF|NGX_CONF_TAKE1,
50 ngx_openssl_engine,
53 NULL },
55 ngx_null_command
59 static ngx_core_module_t ngx_openssl_module_ctx = {
60 ngx_string("openssl"),
61 ngx_openssl_create_conf,
62 NULL
66 ngx_module_t ngx_openssl_module = {
67 NGX_MODULE_V1,
68 &ngx_openssl_module_ctx, /* module context */
69 ngx_openssl_commands, /* module directives */
70 NGX_CORE_MODULE, /* module type */
71 NULL, /* init master */
72 NULL, /* init module */
73 NULL, /* init process */
74 NULL, /* init thread */
75 NULL, /* exit thread */
76 NULL, /* exit process */
77 ngx_openssl_exit, /* exit master */
78 NGX_MODULE_V1_PADDING
82 static long ngx_ssl_protocols[] = {
83 SSL_OP_NO_SSLv2|SSL_OP_NO_SSLv3|SSL_OP_NO_TLSv1,
84 SSL_OP_NO_SSLv3|SSL_OP_NO_TLSv1,
85 SSL_OP_NO_SSLv2|SSL_OP_NO_TLSv1,
86 SSL_OP_NO_TLSv1,
87 SSL_OP_NO_SSLv2|SSL_OP_NO_SSLv3,
88 SSL_OP_NO_SSLv3,
89 SSL_OP_NO_SSLv2,
94 int ngx_ssl_connection_index;
95 int ngx_ssl_server_conf_index;
96 int ngx_ssl_session_cache_index;
99 ngx_int_t
100 ngx_ssl_init(ngx_log_t *log)
102 OPENSSL_config(NULL);
104 SSL_library_init();
105 SSL_load_error_strings();
107 ENGINE_load_builtin_engines();
109 OpenSSL_add_all_algorithms();
111 ngx_ssl_connection_index = SSL_get_ex_new_index(0, NULL, NULL, NULL, NULL);
113 if (ngx_ssl_connection_index == -1) {
114 ngx_ssl_error(NGX_LOG_ALERT, log, 0, "SSL_get_ex_new_index() failed");
115 return NGX_ERROR;
118 ngx_ssl_server_conf_index = SSL_CTX_get_ex_new_index(0, NULL, NULL, NULL,
119 NULL);
120 if (ngx_ssl_server_conf_index == -1) {
121 ngx_ssl_error(NGX_LOG_ALERT, log, 0,
122 "SSL_CTX_get_ex_new_index() failed");
123 return NGX_ERROR;
126 ngx_ssl_session_cache_index = SSL_CTX_get_ex_new_index(0, NULL, NULL, NULL,
127 NULL);
128 if (ngx_ssl_session_cache_index == -1) {
129 ngx_ssl_error(NGX_LOG_ALERT, log, 0,
130 "SSL_CTX_get_ex_new_index() failed");
131 return NGX_ERROR;
134 return NGX_OK;
138 ngx_int_t
139 ngx_ssl_create(ngx_ssl_t *ssl, ngx_uint_t protocols, void *data)
141 ssl->ctx = SSL_CTX_new(SSLv23_method());
143 if (ssl->ctx == NULL) {
144 ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0, "SSL_CTX_new() failed");
145 return NGX_ERROR;
148 if (SSL_CTX_set_ex_data(ssl->ctx, ngx_ssl_server_conf_index, data) == 0) {
149 ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0,
150 "SSL_CTX_set_ex_data() failed");
151 return NGX_ERROR;
154 /* client side options */
156 SSL_CTX_set_options(ssl->ctx, SSL_OP_MICROSOFT_SESS_ID_BUG);
157 SSL_CTX_set_options(ssl->ctx, SSL_OP_NETSCAPE_CHALLENGE_BUG);
158 SSL_CTX_set_options(ssl->ctx, SSL_OP_NETSCAPE_REUSE_CIPHER_CHANGE_BUG);
160 /* server side options */
162 SSL_CTX_set_options(ssl->ctx, SSL_OP_SSLREF2_REUSE_CERT_TYPE_BUG);
163 SSL_CTX_set_options(ssl->ctx, SSL_OP_MICROSOFT_BIG_SSLV3_BUFFER);
165 /* this option allow a potential SSL 2.0 rollback (CAN-2005-2969) */
166 SSL_CTX_set_options(ssl->ctx, SSL_OP_MSIE_SSLV2_RSA_PADDING);
168 SSL_CTX_set_options(ssl->ctx, SSL_OP_SSLEAY_080_CLIENT_DH_BUG);
169 SSL_CTX_set_options(ssl->ctx, SSL_OP_TLS_D5_BUG);
170 SSL_CTX_set_options(ssl->ctx, SSL_OP_TLS_BLOCK_PADDING_BUG);
172 SSL_CTX_set_options(ssl->ctx, SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS);
174 SSL_CTX_set_options(ssl->ctx, SSL_OP_SINGLE_DH_USE);
176 if (ngx_ssl_protocols[protocols >> 1] != 0) {
177 SSL_CTX_set_options(ssl->ctx, ngx_ssl_protocols[protocols >> 1]);
180 SSL_CTX_set_read_ahead(ssl->ctx, 1);
182 SSL_CTX_set_info_callback(ssl->ctx, ngx_ssl_info_callback);
184 return NGX_OK;
188 ngx_int_t
189 ngx_ssl_certificate(ngx_conf_t *cf, ngx_ssl_t *ssl, ngx_str_t *cert,
190 ngx_str_t *key)
192 if (ngx_conf_full_name(cf->cycle, cert, 1) != NGX_OK) {
193 return NGX_ERROR;
196 if (SSL_CTX_use_certificate_chain_file(ssl->ctx, (char *) cert->data)
197 == 0)
199 ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0,
200 "SSL_CTX_use_certificate_chain_file(\"%s\") failed",
201 cert->data);
202 return NGX_ERROR;
205 if (ngx_conf_full_name(cf->cycle, key, 1) != NGX_OK) {
206 return NGX_ERROR;
209 if (SSL_CTX_use_PrivateKey_file(ssl->ctx, (char *) key->data,
210 SSL_FILETYPE_PEM)
211 == 0)
213 ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0,
214 "SSL_CTX_use_PrivateKey_file(\"%s\") failed", key->data);
215 return NGX_ERROR;
218 return NGX_OK;
222 ngx_int_t
223 ngx_ssl_client_certificate(ngx_conf_t *cf, ngx_ssl_t *ssl, ngx_str_t *cert,
224 ngx_int_t depth)
226 STACK_OF(X509_NAME) *list;
228 SSL_CTX_set_verify(ssl->ctx, SSL_VERIFY_PEER, ngx_http_ssl_verify_callback);
230 SSL_CTX_set_verify_depth(ssl->ctx, depth);
232 if (cert->len == 0) {
233 return NGX_OK;
236 if (ngx_conf_full_name(cf->cycle, cert, 1) != NGX_OK) {
237 return NGX_ERROR;
240 if (SSL_CTX_load_verify_locations(ssl->ctx, (char *) cert->data, NULL)
241 == 0)
243 ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0,
244 "SSL_CTX_load_verify_locations(\"%s\") failed",
245 cert->data);
246 return NGX_ERROR;
249 list = SSL_load_client_CA_file((char *) cert->data);
251 if (list == NULL) {
252 ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0,
253 "SSL_load_client_CA_file(\"%s\") failed", cert->data);
254 return NGX_ERROR;
258 * before 0.9.7h and 0.9.8 SSL_load_client_CA_file()
259 * always leaved an error in the error queue
262 ERR_clear_error();
264 SSL_CTX_set_client_CA_list(ssl->ctx, list);
266 return NGX_OK;
270 ngx_int_t
271 ngx_ssl_crl(ngx_conf_t *cf, ngx_ssl_t *ssl, ngx_str_t *crl)
273 X509_STORE *store;
274 X509_LOOKUP *lookup;
276 if (crl->len == 0) {
277 return NGX_OK;
280 if (ngx_conf_full_name(cf->cycle, crl, 1) != NGX_OK) {
281 return NGX_ERROR;
284 store = SSL_CTX_get_cert_store(ssl->ctx);
286 if (store == NULL) {
287 ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0,
288 "SSL_CTX_get_cert_store() failed");
289 return NGX_ERROR;
292 lookup = X509_STORE_add_lookup(store, X509_LOOKUP_file());
294 if (lookup == NULL) {
295 ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0,
296 "X509_STORE_add_lookup() failed");
297 return NGX_ERROR;
300 if (X509_LOOKUP_load_file(lookup, (char *) crl->data, X509_FILETYPE_PEM)
301 == 0)
303 ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0,
304 "X509_LOOKUP_load_file(\"%s\") failed", crl->data);
305 return NGX_ERROR;
308 X509_STORE_set_flags(store,
309 X509_V_FLAG_CRL_CHECK|X509_V_FLAG_CRL_CHECK_ALL);
311 return NGX_OK;
315 static int
316 ngx_http_ssl_verify_callback(int ok, X509_STORE_CTX *x509_store)
318 #if (NGX_DEBUG)
319 char *subject, *issuer;
320 int err, depth;
321 X509 *cert;
322 X509_NAME *sname, *iname;
323 ngx_connection_t *c;
324 ngx_ssl_conn_t *ssl_conn;
326 ssl_conn = X509_STORE_CTX_get_ex_data(x509_store,
327 SSL_get_ex_data_X509_STORE_CTX_idx());
329 c = ngx_ssl_get_connection(ssl_conn);
331 cert = X509_STORE_CTX_get_current_cert(x509_store);
332 err = X509_STORE_CTX_get_error(x509_store);
333 depth = X509_STORE_CTX_get_error_depth(x509_store);
335 sname = X509_get_subject_name(cert);
336 subject = sname ? X509_NAME_oneline(sname, NULL, 0) : "(none)";
338 iname = X509_get_issuer_name(cert);
339 issuer = iname ? X509_NAME_oneline(iname, NULL, 0) : "(none)";
341 ngx_log_debug5(NGX_LOG_DEBUG_EVENT, c->log, 0,
342 "verify:%d, error:%d, depth:%d, "
343 "subject:\"%s\",issuer: \"%s\"",
344 ok, err, depth, subject, issuer);
346 if (sname) {
347 OPENSSL_free(subject);
350 if (iname) {
351 OPENSSL_free(issuer);
353 #endif
355 return 1;
359 static void
360 ngx_ssl_info_callback(const ngx_ssl_conn_t *ssl_conn, int where, int ret)
362 ngx_connection_t *c;
364 if (where & SSL_CB_HANDSHAKE_START) {
365 c = ngx_ssl_get_connection((ngx_ssl_conn_t *) ssl_conn);
367 if (c->ssl->handshaked) {
368 c->ssl->renegotiation = 1;
369 ngx_log_debug0(NGX_LOG_DEBUG_EVENT, c->log, 0, "SSL renegotiation");
375 ngx_int_t
376 ngx_ssl_generate_rsa512_key(ngx_ssl_t *ssl)
378 RSA *key;
380 if (SSL_CTX_need_tmp_RSA(ssl->ctx) == 0) {
381 return NGX_OK;
384 key = RSA_generate_key(512, RSA_F4, NULL, NULL);
386 if (key) {
387 SSL_CTX_set_tmp_rsa(ssl->ctx, key);
389 RSA_free(key);
391 return NGX_OK;
394 ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0, "RSA_generate_key(512) failed");
396 return NGX_ERROR;
400 ngx_int_t
401 ngx_ssl_dhparam(ngx_conf_t *cf, ngx_ssl_t *ssl, ngx_str_t *file)
403 DH *dh;
404 BIO *bio;
407 * -----BEGIN DH PARAMETERS-----
408 * MIGHAoGBALu8LcrYRnSQfEP89YDpz9vZWKP1aLQtSwju1OsPs1BMbAMCducQgAxc
409 * y7qokiYUxb7spWWl/fHSh6K8BJvmd4Bg6RqSp1fjBI9osHb302zI8pul34HcLKcl
410 * 7OZicMyaUDXYzs7vnqAnSmOrHlj6/UmI0PZdFGdX2gcd8EXP4WubAgEC
411 * -----END DH PARAMETERS-----
414 static unsigned char dh1024_p[] = {
415 0xBB, 0xBC, 0x2D, 0xCA, 0xD8, 0x46, 0x74, 0x90, 0x7C, 0x43, 0xFC, 0xF5,
416 0x80, 0xE9, 0xCF, 0xDB, 0xD9, 0x58, 0xA3, 0xF5, 0x68, 0xB4, 0x2D, 0x4B,
417 0x08, 0xEE, 0xD4, 0xEB, 0x0F, 0xB3, 0x50, 0x4C, 0x6C, 0x03, 0x02, 0x76,
418 0xE7, 0x10, 0x80, 0x0C, 0x5C, 0xCB, 0xBA, 0xA8, 0x92, 0x26, 0x14, 0xC5,
419 0xBE, 0xEC, 0xA5, 0x65, 0xA5, 0xFD, 0xF1, 0xD2, 0x87, 0xA2, 0xBC, 0x04,
420 0x9B, 0xE6, 0x77, 0x80, 0x60, 0xE9, 0x1A, 0x92, 0xA7, 0x57, 0xE3, 0x04,
421 0x8F, 0x68, 0xB0, 0x76, 0xF7, 0xD3, 0x6C, 0xC8, 0xF2, 0x9B, 0xA5, 0xDF,
422 0x81, 0xDC, 0x2C, 0xA7, 0x25, 0xEC, 0xE6, 0x62, 0x70, 0xCC, 0x9A, 0x50,
423 0x35, 0xD8, 0xCE, 0xCE, 0xEF, 0x9E, 0xA0, 0x27, 0x4A, 0x63, 0xAB, 0x1E,
424 0x58, 0xFA, 0xFD, 0x49, 0x88, 0xD0, 0xF6, 0x5D, 0x14, 0x67, 0x57, 0xDA,
425 0x07, 0x1D, 0xF0, 0x45, 0xCF, 0xE1, 0x6B, 0x9B
428 static unsigned char dh1024_g[] = { 0x02 };
431 if (file->len == 0) {
433 dh = DH_new();
434 if (dh == NULL) {
435 ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0, "DH_new() failed");
436 return NGX_ERROR;
439 dh->p = BN_bin2bn(dh1024_p, sizeof(dh1024_p), NULL);
440 dh->g = BN_bin2bn(dh1024_g, sizeof(dh1024_g), NULL);
442 if (dh->p == NULL || dh->g == NULL) {
443 ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0, "BN_bin2bn() failed");
444 DH_free(dh);
445 return NGX_ERROR;
448 SSL_CTX_set_tmp_dh(ssl->ctx, dh);
450 DH_free(dh);
452 return NGX_OK;
455 if (ngx_conf_full_name(cf->cycle, file, 1) != NGX_OK) {
456 return NGX_ERROR;
459 bio = BIO_new_file((char *) file->data, "r");
460 if (bio == NULL) {
461 ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0,
462 "BIO_new_file(\"%s\") failed", file->data);
463 return NGX_ERROR;
466 dh = PEM_read_bio_DHparams(bio, NULL, NULL, NULL);
467 if (dh == NULL) {
468 ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0,
469 "PEM_read_bio_DHparams(\"%s\") failed", file->data);
470 BIO_free(bio);
471 return NGX_ERROR;
474 SSL_CTX_set_tmp_dh(ssl->ctx, dh);
476 DH_free(dh);
477 BIO_free(bio);
479 return NGX_OK;
483 ngx_int_t
484 ngx_ssl_create_connection(ngx_ssl_t *ssl, ngx_connection_t *c, ngx_uint_t flags)
486 ngx_ssl_connection_t *sc;
488 sc = ngx_pcalloc(c->pool, sizeof(ngx_ssl_connection_t));
489 if (sc == NULL) {
490 return NGX_ERROR;
493 sc->buffer = ((flags & NGX_SSL_BUFFER) != 0);
495 sc->connection = SSL_new(ssl->ctx);
497 if (sc->connection == NULL) {
498 ngx_ssl_error(NGX_LOG_ALERT, c->log, 0, "SSL_new() failed");
499 return NGX_ERROR;
502 if (SSL_set_fd(sc->connection, c->fd) == 0) {
503 ngx_ssl_error(NGX_LOG_ALERT, c->log, 0, "SSL_set_fd() failed");
504 return NGX_ERROR;
507 if (flags & NGX_SSL_CLIENT) {
508 SSL_set_connect_state(sc->connection);
510 } else {
511 SSL_set_accept_state(sc->connection);
514 if (SSL_set_ex_data(sc->connection, ngx_ssl_connection_index, c) == 0) {
515 ngx_ssl_error(NGX_LOG_ALERT, c->log, 0, "SSL_set_ex_data() failed");
516 return NGX_ERROR;
519 c->ssl = sc;
521 return NGX_OK;
525 ngx_int_t
526 ngx_ssl_set_session(ngx_connection_t *c, ngx_ssl_session_t *session)
528 if (session) {
529 if (SSL_set_session(c->ssl->connection, session) == 0) {
530 ngx_ssl_error(NGX_LOG_ALERT, c->log, 0, "SSL_set_session() failed");
531 return NGX_ERROR;
535 return NGX_OK;
539 ngx_int_t
540 ngx_ssl_handshake(ngx_connection_t *c)
542 int n, sslerr;
543 ngx_err_t err;
545 ngx_ssl_clear_error(c->log);
547 n = SSL_do_handshake(c->ssl->connection);
549 ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0, "SSL_do_handshake: %d", n);
551 if (n == 1) {
553 if (ngx_handle_read_event(c->read, 0) != NGX_OK) {
554 return NGX_ERROR;
557 if (ngx_handle_write_event(c->write, 0) != NGX_OK) {
558 return NGX_ERROR;
561 #if (NGX_DEBUG)
563 char buf[129], *s, *d;
564 #if OPENSSL_VERSION_NUMBER >= 0x1000000fL
565 const
566 #endif
567 SSL_CIPHER *cipher;
569 cipher = SSL_get_current_cipher(c->ssl->connection);
571 if (cipher) {
572 SSL_CIPHER_description(cipher, &buf[1], 128);
574 for (s = &buf[1], d = buf; *s; s++) {
575 if (*s == ' ' && *d == ' ') {
576 continue;
579 if (*s == LF || *s == CR) {
580 continue;
583 *++d = *s;
586 if (*d != ' ') {
587 d++;
590 *d = '\0';
592 ngx_log_debug2(NGX_LOG_DEBUG_EVENT, c->log, 0,
593 "SSL: %s, cipher: \"%s\"",
594 SSL_get_version(c->ssl->connection), &buf[1]);
596 if (SSL_session_reused(c->ssl->connection)) {
597 ngx_log_debug0(NGX_LOG_DEBUG_EVENT, c->log, 0,
598 "SSL reused session");
601 } else {
602 ngx_log_debug0(NGX_LOG_DEBUG_EVENT, c->log, 0,
603 "SSL no shared ciphers");
606 #endif
608 c->ssl->handshaked = 1;
610 c->recv = ngx_ssl_recv;
611 c->send = ngx_ssl_write;
612 c->recv_chain = ngx_ssl_recv_chain;
613 c->send_chain = ngx_ssl_send_chain;
615 /* initial handshake done, disable renegotiation (CVE-2009-3555) */
616 if (c->ssl->connection->s3) {
617 c->ssl->connection->s3->flags |= SSL3_FLAGS_NO_RENEGOTIATE_CIPHERS;
620 return NGX_OK;
623 sslerr = SSL_get_error(c->ssl->connection, n);
625 ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0, "SSL_get_error: %d", sslerr);
627 if (sslerr == SSL_ERROR_WANT_READ) {
628 c->read->ready = 0;
629 c->read->handler = ngx_ssl_handshake_handler;
630 c->write->handler = ngx_ssl_handshake_handler;
632 if (ngx_handle_read_event(c->read, 0) != NGX_OK) {
633 return NGX_ERROR;
636 return NGX_AGAIN;
639 if (sslerr == SSL_ERROR_WANT_WRITE) {
640 c->write->ready = 0;
641 c->read->handler = ngx_ssl_handshake_handler;
642 c->write->handler = ngx_ssl_handshake_handler;
644 if (ngx_handle_write_event(c->write, 0) != NGX_OK) {
645 return NGX_ERROR;
648 return NGX_AGAIN;
651 err = (sslerr == SSL_ERROR_SYSCALL) ? ngx_errno : 0;
653 c->ssl->no_wait_shutdown = 1;
654 c->ssl->no_send_shutdown = 1;
655 c->read->eof = 1;
657 if (sslerr == SSL_ERROR_ZERO_RETURN || ERR_peek_error() == 0) {
658 ngx_log_error(NGX_LOG_INFO, c->log, err,
659 "peer closed connection in SSL handshake");
661 return NGX_ERROR;
664 c->read->error = 1;
666 ngx_ssl_connection_error(c, sslerr, err, "SSL_do_handshake() failed");
668 return NGX_ERROR;
672 static void
673 ngx_ssl_handshake_handler(ngx_event_t *ev)
675 ngx_connection_t *c;
677 c = ev->data;
679 ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0,
680 "SSL handshake handler: %d", ev->write);
682 if (ev->timedout) {
683 c->ssl->handler(c);
684 return;
687 if (ngx_ssl_handshake(c) == NGX_AGAIN) {
688 return;
691 c->ssl->handler(c);
695 ssize_t
696 ngx_ssl_recv_chain(ngx_connection_t *c, ngx_chain_t *cl)
698 u_char *last;
699 ssize_t n, bytes;
700 ngx_buf_t *b;
702 bytes = 0;
704 b = cl->buf;
705 last = b->last;
707 for ( ;; ) {
709 n = ngx_ssl_recv(c, last, b->end - last);
711 if (n > 0) {
712 last += n;
713 bytes += n;
715 if (last == b->end) {
716 cl = cl->next;
718 if (cl == NULL) {
719 return bytes;
722 b = cl->buf;
723 last = b->last;
726 continue;
729 if (bytes) {
731 if (n == 0 || n == NGX_ERROR) {
732 c->read->ready = 1;
735 return bytes;
738 return n;
743 ssize_t
744 ngx_ssl_recv(ngx_connection_t *c, u_char *buf, size_t size)
746 int n, bytes;
748 if (c->ssl->last == NGX_ERROR) {
749 c->read->error = 1;
750 return NGX_ERROR;
753 if (c->ssl->last == NGX_DONE) {
754 c->read->ready = 0;
755 c->read->eof = 1;
756 return 0;
759 bytes = 0;
761 ngx_ssl_clear_error(c->log);
764 * SSL_read() may return data in parts, so try to read
765 * until SSL_read() would return no data
768 for ( ;; ) {
770 n = SSL_read(c->ssl->connection, buf, size);
772 ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0, "SSL_read: %d", n);
774 if (n > 0) {
775 bytes += n;
778 c->ssl->last = ngx_ssl_handle_recv(c, n);
780 if (c->ssl->last == NGX_OK) {
782 size -= n;
784 if (size == 0) {
785 return bytes;
788 buf += n;
790 continue;
793 if (bytes) {
794 return bytes;
797 switch (c->ssl->last) {
799 case NGX_DONE:
800 c->read->ready = 0;
801 c->read->eof = 1;
802 return 0;
804 case NGX_ERROR:
805 c->read->error = 1;
807 /* fall thruogh */
809 case NGX_AGAIN:
810 return c->ssl->last;
816 static ngx_int_t
817 ngx_ssl_handle_recv(ngx_connection_t *c, int n)
819 int sslerr;
820 ngx_err_t err;
822 if (c->ssl->renegotiation) {
824 * disable renegotiation (CVE-2009-3555):
825 * OpenSSL (at least up to 0.9.8l) does not handle disabled
826 * renegotiation gracefully, so drop connection here
829 ngx_log_error(NGX_LOG_NOTICE, c->log, 0, "SSL renegotiation disabled");
831 c->ssl->no_wait_shutdown = 1;
832 c->ssl->no_send_shutdown = 1;
834 return NGX_ERROR;
837 if (n > 0) {
839 if (c->ssl->saved_write_handler) {
841 c->write->handler = c->ssl->saved_write_handler;
842 c->ssl->saved_write_handler = NULL;
843 c->write->ready = 1;
845 if (ngx_handle_write_event(c->write, 0) != NGX_OK) {
846 return NGX_ERROR;
849 ngx_post_event(c->write, &ngx_posted_events);
852 return NGX_OK;
855 sslerr = SSL_get_error(c->ssl->connection, n);
857 err = (sslerr == SSL_ERROR_SYSCALL) ? ngx_errno : 0;
859 ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0, "SSL_get_error: %d", sslerr);
861 if (sslerr == SSL_ERROR_WANT_READ) {
862 c->read->ready = 0;
863 return NGX_AGAIN;
866 if (sslerr == SSL_ERROR_WANT_WRITE) {
868 ngx_log_error(NGX_LOG_INFO, c->log, 0,
869 "peer started SSL renegotiation");
871 c->write->ready = 0;
873 if (ngx_handle_write_event(c->write, 0) != NGX_OK) {
874 return NGX_ERROR;
878 * we do not set the timer because there is already the read event timer
881 if (c->ssl->saved_write_handler == NULL) {
882 c->ssl->saved_write_handler = c->write->handler;
883 c->write->handler = ngx_ssl_write_handler;
886 return NGX_AGAIN;
889 c->ssl->no_wait_shutdown = 1;
890 c->ssl->no_send_shutdown = 1;
892 if (sslerr == SSL_ERROR_ZERO_RETURN || ERR_peek_error() == 0) {
893 ngx_log_debug0(NGX_LOG_DEBUG_EVENT, c->log, 0,
894 "peer shutdown SSL cleanly");
895 return NGX_DONE;
898 ngx_ssl_connection_error(c, sslerr, err, "SSL_read() failed");
900 return NGX_ERROR;
904 static void
905 ngx_ssl_write_handler(ngx_event_t *wev)
907 ngx_connection_t *c;
909 c = wev->data;
911 c->read->handler(c->read);
916 * OpenSSL has no SSL_writev() so we copy several bufs into our 16K buffer
917 * before the SSL_write() call to decrease a SSL overhead.
919 * Besides for protocols such as HTTP it is possible to always buffer
920 * the output to decrease a SSL overhead some more.
923 ngx_chain_t *
924 ngx_ssl_send_chain(ngx_connection_t *c, ngx_chain_t *in, off_t limit)
926 int n;
927 ngx_uint_t flush;
928 ssize_t send, size;
929 ngx_buf_t *buf;
931 if (!c->ssl->buffer) {
933 while (in) {
934 if (ngx_buf_special(in->buf)) {
935 in = in->next;
936 continue;
939 n = ngx_ssl_write(c, in->buf->pos, in->buf->last - in->buf->pos);
941 if (n == NGX_ERROR) {
942 return NGX_CHAIN_ERROR;
945 if (n == NGX_AGAIN) {
946 c->buffered |= NGX_SSL_BUFFERED;
947 return in;
950 in->buf->pos += n;
952 if (in->buf->pos == in->buf->last) {
953 in = in->next;
957 return in;
961 /* the maximum limit size is the maximum uint32_t value - the page size */
963 if (limit == 0 || limit > (off_t) (NGX_MAX_UINT32_VALUE - ngx_pagesize)) {
964 limit = NGX_MAX_UINT32_VALUE - ngx_pagesize;
967 buf = c->ssl->buf;
969 if (buf == NULL) {
970 buf = ngx_create_temp_buf(c->pool, NGX_SSL_BUFSIZE);
971 if (buf == NULL) {
972 return NGX_CHAIN_ERROR;
975 c->ssl->buf = buf;
978 if (buf->start == NULL) {
979 buf->start = ngx_palloc(c->pool, NGX_SSL_BUFSIZE);
980 if (buf->start == NULL) {
981 return NGX_CHAIN_ERROR;
984 buf->pos = buf->start;
985 buf->last = buf->start;
986 buf->end = buf->start + NGX_SSL_BUFSIZE;
989 send = 0;
990 flush = (in == NULL) ? 1 : 0;
992 for ( ;; ) {
994 while (in && buf->last < buf->end && send < limit) {
995 if (in->buf->last_buf || in->buf->flush) {
996 flush = 1;
999 if (ngx_buf_special(in->buf)) {
1000 in = in->next;
1001 continue;
1004 size = in->buf->last - in->buf->pos;
1006 if (size > buf->end - buf->last) {
1007 size = buf->end - buf->last;
1010 if (send + size > limit) {
1011 size = (ssize_t) (limit - send);
1012 flush = 1;
1015 ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0,
1016 "SSL buf copy: %d", size);
1018 ngx_memcpy(buf->last, in->buf->pos, size);
1020 buf->last += size;
1021 in->buf->pos += size;
1022 send += size;
1024 if (in->buf->pos == in->buf->last) {
1025 in = in->next;
1029 size = buf->last - buf->pos;
1031 if (!flush && buf->last < buf->end && c->ssl->buffer) {
1032 break;
1035 n = ngx_ssl_write(c, buf->pos, size);
1037 if (n == NGX_ERROR) {
1038 return NGX_CHAIN_ERROR;
1041 if (n == NGX_AGAIN) {
1042 c->buffered |= NGX_SSL_BUFFERED;
1043 return in;
1046 buf->pos += n;
1047 c->sent += n;
1049 if (n < size) {
1050 break;
1053 if (buf->pos == buf->last) {
1054 buf->pos = buf->start;
1055 buf->last = buf->start;
1058 if (in == NULL || send == limit) {
1059 break;
1063 if (buf->pos < buf->last) {
1064 c->buffered |= NGX_SSL_BUFFERED;
1066 } else {
1067 c->buffered &= ~NGX_SSL_BUFFERED;
1070 return in;
1074 ssize_t
1075 ngx_ssl_write(ngx_connection_t *c, u_char *data, size_t size)
1077 int n, sslerr;
1078 ngx_err_t err;
1080 ngx_ssl_clear_error(c->log);
1082 ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0, "SSL to write: %d", size);
1084 n = SSL_write(c->ssl->connection, data, size);
1086 ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0, "SSL_write: %d", n);
1088 if (n > 0) {
1090 if (c->ssl->saved_read_handler) {
1092 c->read->handler = c->ssl->saved_read_handler;
1093 c->ssl->saved_read_handler = NULL;
1094 c->read->ready = 1;
1096 if (ngx_handle_read_event(c->read, 0) != NGX_OK) {
1097 return NGX_ERROR;
1100 ngx_post_event(c->read, &ngx_posted_events);
1103 return n;
1106 sslerr = SSL_get_error(c->ssl->connection, n);
1108 err = (sslerr == SSL_ERROR_SYSCALL) ? ngx_errno : 0;
1110 ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0, "SSL_get_error: %d", sslerr);
1112 if (sslerr == SSL_ERROR_WANT_WRITE) {
1113 c->write->ready = 0;
1114 return NGX_AGAIN;
1117 if (sslerr == SSL_ERROR_WANT_READ) {
1119 ngx_log_error(NGX_LOG_INFO, c->log, 0,
1120 "peer started SSL renegotiation");
1122 c->read->ready = 0;
1124 if (ngx_handle_read_event(c->read, 0) != NGX_OK) {
1125 return NGX_ERROR;
1129 * we do not set the timer because there is already
1130 * the write event timer
1133 if (c->ssl->saved_read_handler == NULL) {
1134 c->ssl->saved_read_handler = c->read->handler;
1135 c->read->handler = ngx_ssl_read_handler;
1138 return NGX_AGAIN;
1141 c->ssl->no_wait_shutdown = 1;
1142 c->ssl->no_send_shutdown = 1;
1143 c->write->error = 1;
1145 ngx_ssl_connection_error(c, sslerr, err, "SSL_write() failed");
1147 return NGX_ERROR;
1151 static void
1152 ngx_ssl_read_handler(ngx_event_t *rev)
1154 ngx_connection_t *c;
1156 c = rev->data;
1158 c->write->handler(c->write);
1162 void
1163 ngx_ssl_free_buffer(ngx_connection_t *c)
1165 if (c->ssl->buf && c->ssl->buf->start) {
1166 if (ngx_pfree(c->pool, c->ssl->buf->start) == NGX_OK) {
1167 c->ssl->buf->start = NULL;
1173 ngx_int_t
1174 ngx_ssl_shutdown(ngx_connection_t *c)
1176 int n, sslerr, mode;
1177 ngx_err_t err;
1179 if (c->timedout) {
1180 mode = SSL_RECEIVED_SHUTDOWN|SSL_SENT_SHUTDOWN;
1182 } else {
1183 mode = SSL_get_shutdown(c->ssl->connection);
1185 if (c->ssl->no_wait_shutdown) {
1186 mode |= SSL_RECEIVED_SHUTDOWN;
1189 if (c->ssl->no_send_shutdown) {
1190 mode |= SSL_SENT_SHUTDOWN;
1194 SSL_set_shutdown(c->ssl->connection, mode);
1196 ngx_ssl_clear_error(c->log);
1198 n = SSL_shutdown(c->ssl->connection);
1200 ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0, "SSL_shutdown: %d", n);
1202 sslerr = 0;
1204 /* SSL_shutdown() never returns -1, on error it returns 0 */
1206 if (n != 1 && ERR_peek_error()) {
1207 sslerr = SSL_get_error(c->ssl->connection, n);
1209 ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0,
1210 "SSL_get_error: %d", sslerr);
1213 if (n == 1 || sslerr == 0 || sslerr == SSL_ERROR_ZERO_RETURN) {
1214 SSL_free(c->ssl->connection);
1215 c->ssl = NULL;
1217 return NGX_OK;
1220 if (sslerr == SSL_ERROR_WANT_READ || sslerr == SSL_ERROR_WANT_WRITE) {
1221 c->read->handler = ngx_ssl_shutdown_handler;
1222 c->write->handler = ngx_ssl_shutdown_handler;
1224 if (ngx_handle_read_event(c->read, 0) != NGX_OK) {
1225 return NGX_ERROR;
1228 if (ngx_handle_write_event(c->write, 0) != NGX_OK) {
1229 return NGX_ERROR;
1232 if (sslerr == SSL_ERROR_WANT_READ) {
1233 ngx_add_timer(c->read, 30000);
1236 return NGX_AGAIN;
1239 err = (sslerr == SSL_ERROR_SYSCALL) ? ngx_errno : 0;
1241 ngx_ssl_connection_error(c, sslerr, err, "SSL_shutdown() failed");
1243 SSL_free(c->ssl->connection);
1244 c->ssl = NULL;
1246 return NGX_ERROR;
1250 static void
1251 ngx_ssl_shutdown_handler(ngx_event_t *ev)
1253 ngx_connection_t *c;
1254 ngx_connection_handler_pt handler;
1256 c = ev->data;
1257 handler = c->ssl->handler;
1259 if (ev->timedout) {
1260 c->timedout = 1;
1263 ngx_log_debug0(NGX_LOG_DEBUG_EVENT, ev->log, 0, "SSL shutdown handler");
1265 if (ngx_ssl_shutdown(c) == NGX_AGAIN) {
1266 return;
1269 handler(c);
1273 static void
1274 ngx_ssl_connection_error(ngx_connection_t *c, int sslerr, ngx_err_t err,
1275 char *text)
1277 int n;
1278 ngx_uint_t level;
1280 level = NGX_LOG_CRIT;
1282 if (sslerr == SSL_ERROR_SYSCALL) {
1284 if (err == NGX_ECONNRESET
1285 || err == NGX_EPIPE
1286 || err == NGX_ENOTCONN
1287 || err == NGX_ETIMEDOUT
1288 || err == NGX_ECONNREFUSED
1289 || err == NGX_ENETDOWN
1290 || err == NGX_ENETUNREACH
1291 || err == NGX_EHOSTDOWN
1292 || err == NGX_EHOSTUNREACH)
1294 switch (c->log_error) {
1296 case NGX_ERROR_IGNORE_ECONNRESET:
1297 case NGX_ERROR_INFO:
1298 level = NGX_LOG_INFO;
1299 break;
1301 case NGX_ERROR_ERR:
1302 level = NGX_LOG_ERR;
1303 break;
1305 default:
1306 break;
1310 } else if (sslerr == SSL_ERROR_SSL) {
1312 n = ERR_GET_REASON(ERR_peek_error());
1314 /* handshake failures */
1315 if (n == SSL_R_DIGEST_CHECK_FAILED /* 149 */
1316 || n == SSL_R_LENGTH_MISMATCH /* 159 */
1317 || n == SSL_R_NO_CIPHERS_PASSED /* 182 */
1318 || n == SSL_R_NO_CIPHERS_SPECIFIED /* 183 */
1319 || n == SSL_R_NO_SHARED_CIPHER /* 193 */
1320 || n == SSL_R_RECORD_LENGTH_MISMATCH /* 213 */
1321 || n == SSL_R_UNEXPECTED_MESSAGE /* 244 */
1322 || n == SSL_R_UNEXPECTED_RECORD /* 245 */
1323 || n == SSL_R_UNKNOWN_ALERT_TYPE /* 246 */
1324 || n == SSL_R_UNKNOWN_PROTOCOL /* 252 */
1325 || n == SSL_R_WRONG_VERSION_NUMBER /* 267 */
1326 || n == SSL_R_DECRYPTION_FAILED_OR_BAD_RECORD_MAC /* 281 */
1327 || n == 1000 /* SSL_R_SSLV3_ALERT_CLOSE_NOTIFY */
1328 || n == SSL_R_SSLV3_ALERT_UNEXPECTED_MESSAGE /* 1010 */
1329 || n == SSL_R_SSLV3_ALERT_BAD_RECORD_MAC /* 1020 */
1330 || n == SSL_R_TLSV1_ALERT_DECRYPTION_FAILED /* 1021 */
1331 || n == SSL_R_TLSV1_ALERT_RECORD_OVERFLOW /* 1022 */
1332 || n == SSL_R_SSLV3_ALERT_DECOMPRESSION_FAILURE /* 1030 */
1333 || n == SSL_R_SSLV3_ALERT_HANDSHAKE_FAILURE /* 1040 */
1334 || n == SSL_R_SSLV3_ALERT_NO_CERTIFICATE /* 1041 */
1335 || n == SSL_R_SSLV3_ALERT_BAD_CERTIFICATE /* 1042 */
1336 || n == SSL_R_SSLV3_ALERT_UNSUPPORTED_CERTIFICATE /* 1043 */
1337 || n == SSL_R_SSLV3_ALERT_CERTIFICATE_REVOKED /* 1044 */
1338 || n == SSL_R_SSLV3_ALERT_CERTIFICATE_EXPIRED /* 1045 */
1339 || n == SSL_R_SSLV3_ALERT_CERTIFICATE_UNKNOWN /* 1046 */
1340 || n == SSL_R_SSLV3_ALERT_ILLEGAL_PARAMETER /* 1047 */
1341 || n == SSL_R_TLSV1_ALERT_UNKNOWN_CA /* 1048 */
1342 || n == SSL_R_TLSV1_ALERT_ACCESS_DENIED /* 1049 */
1343 || n == SSL_R_TLSV1_ALERT_DECODE_ERROR /* 1050 */
1344 || n == SSL_R_TLSV1_ALERT_DECRYPT_ERROR /* 1051 */
1345 || n == SSL_R_TLSV1_ALERT_EXPORT_RESTRICTION /* 1060 */
1346 || n == SSL_R_TLSV1_ALERT_PROTOCOL_VERSION /* 1070 */
1347 || n == SSL_R_TLSV1_ALERT_INSUFFICIENT_SECURITY /* 1071 */
1348 || n == SSL_R_TLSV1_ALERT_INTERNAL_ERROR /* 1080 */
1349 || n == SSL_R_TLSV1_ALERT_USER_CANCELLED /* 1090 */
1350 || n == SSL_R_TLSV1_ALERT_NO_RENEGOTIATION) /* 1100 */
1352 switch (c->log_error) {
1354 case NGX_ERROR_IGNORE_ECONNRESET:
1355 case NGX_ERROR_INFO:
1356 level = NGX_LOG_INFO;
1357 break;
1359 case NGX_ERROR_ERR:
1360 level = NGX_LOG_ERR;
1361 break;
1363 default:
1364 break;
1369 ngx_ssl_error(level, c->log, err, text);
1373 static void
1374 ngx_ssl_clear_error(ngx_log_t *log)
1376 while (ERR_peek_error()) {
1377 ngx_ssl_error(NGX_LOG_ALERT, log, 0, "ignoring stale global SSL error");
1380 ERR_clear_error();
1384 void ngx_cdecl
1385 ngx_ssl_error(ngx_uint_t level, ngx_log_t *log, ngx_err_t err, char *fmt, ...)
1387 u_long n;
1388 va_list args;
1389 u_char *p, *last;
1390 u_char errstr[NGX_MAX_CONF_ERRSTR];
1392 last = errstr + NGX_MAX_CONF_ERRSTR;
1394 va_start(args, fmt);
1395 p = ngx_vslprintf(errstr, last - 1, fmt, args);
1396 va_end(args);
1398 p = ngx_cpystrn(p, (u_char *) " (SSL:", last - p);
1400 for ( ;; ) {
1402 n = ERR_get_error();
1404 if (n == 0) {
1405 break;
1408 if (p >= last) {
1409 continue;
1412 *p++ = ' ';
1414 ERR_error_string_n(n, (char *) p, last - p);
1416 while (p < last && *p) {
1417 p++;
1421 ngx_log_error(level, log, err, "%s)", errstr);
1425 ngx_int_t
1426 ngx_ssl_session_cache(ngx_ssl_t *ssl, ngx_str_t *sess_ctx,
1427 ssize_t builtin_session_cache, ngx_shm_zone_t *shm_zone, time_t timeout)
1429 long cache_mode;
1431 if (builtin_session_cache == NGX_SSL_NO_SCACHE) {
1432 SSL_CTX_set_session_cache_mode(ssl->ctx, SSL_SESS_CACHE_OFF);
1433 return NGX_OK;
1436 SSL_CTX_set_session_id_context(ssl->ctx, sess_ctx->data, sess_ctx->len);
1438 if (builtin_session_cache == NGX_SSL_NONE_SCACHE) {
1441 * If the server explicitly says that it does not support
1442 * session reuse (see SSL_SESS_CACHE_OFF above), then
1443 * Outlook Express fails to upload a sent email to
1444 * the Sent Items folder on the IMAP server via a separate IMAP
1445 * connection in the background. Therefore we have a special
1446 * mode (SSL_SESS_CACHE_SERVER|SSL_SESS_CACHE_NO_INTERNAL_STORE)
1447 * where the server pretends that it supports session reuse,
1448 * but it does not actually store any session.
1451 SSL_CTX_set_session_cache_mode(ssl->ctx,
1452 SSL_SESS_CACHE_SERVER
1453 |SSL_SESS_CACHE_NO_AUTO_CLEAR
1454 |SSL_SESS_CACHE_NO_INTERNAL_STORE);
1456 SSL_CTX_sess_set_cache_size(ssl->ctx, 1);
1458 return NGX_OK;
1461 cache_mode = SSL_SESS_CACHE_SERVER;
1463 if (shm_zone && builtin_session_cache == NGX_SSL_NO_BUILTIN_SCACHE) {
1464 cache_mode |= SSL_SESS_CACHE_NO_INTERNAL;
1467 SSL_CTX_set_session_cache_mode(ssl->ctx, cache_mode);
1469 if (builtin_session_cache != NGX_SSL_NO_BUILTIN_SCACHE) {
1471 if (builtin_session_cache != NGX_SSL_DFLT_BUILTIN_SCACHE) {
1472 SSL_CTX_sess_set_cache_size(ssl->ctx, builtin_session_cache);
1476 SSL_CTX_set_timeout(ssl->ctx, (long) timeout);
1478 if (shm_zone) {
1479 shm_zone->init = ngx_ssl_session_cache_init;
1481 SSL_CTX_sess_set_new_cb(ssl->ctx, ngx_ssl_new_session);
1482 SSL_CTX_sess_set_get_cb(ssl->ctx, ngx_ssl_get_cached_session);
1483 SSL_CTX_sess_set_remove_cb(ssl->ctx, ngx_ssl_remove_session);
1485 if (SSL_CTX_set_ex_data(ssl->ctx, ngx_ssl_session_cache_index, shm_zone)
1486 == 0)
1488 ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0,
1489 "SSL_CTX_set_ex_data() failed");
1490 return NGX_ERROR;
1494 return NGX_OK;
1498 static ngx_int_t
1499 ngx_ssl_session_cache_init(ngx_shm_zone_t *shm_zone, void *data)
1501 size_t len;
1502 ngx_slab_pool_t *shpool;
1503 ngx_ssl_session_cache_t *cache;
1505 if (data) {
1506 shm_zone->data = data;
1507 return NGX_OK;
1510 if (shm_zone->shm.exists) {
1511 shm_zone->data = data;
1512 return NGX_OK;
1515 shpool = (ngx_slab_pool_t *) shm_zone->shm.addr;
1517 cache = ngx_slab_alloc(shpool, sizeof(ngx_ssl_session_cache_t));
1518 if (cache == NULL) {
1519 return NGX_ERROR;
1522 shpool->data = cache;
1523 shm_zone->data = cache;
1525 ngx_rbtree_init(&cache->session_rbtree, &cache->sentinel,
1526 ngx_ssl_session_rbtree_insert_value);
1528 ngx_queue_init(&cache->expire_queue);
1530 len = sizeof(" in SSL session shared cache \"\"") + shm_zone->shm.name.len;
1532 shpool->log_ctx = ngx_slab_alloc(shpool, len);
1533 if (shpool->log_ctx == NULL) {
1534 return NGX_ERROR;
1537 ngx_sprintf(shpool->log_ctx, " in SSL session shared cache \"%V\"%Z",
1538 &shm_zone->shm.name);
1540 return NGX_OK;
1545 * The length of the session id is 16 bytes for SSLv2 sessions and
1546 * between 1 and 32 bytes for SSLv3/TLSv1, typically 32 bytes.
1547 * It seems that the typical length of the external ASN1 representation
1548 * of a session is 118 or 119 bytes for SSLv3/TSLv1.
1550 * Thus on 32-bit platforms we allocate separately an rbtree node,
1551 * a session id, and an ASN1 representation, they take accordingly
1552 * 64, 32, and 128 bytes.
1554 * On 64-bit platforms we allocate separately an rbtree node + session_id,
1555 * and an ASN1 representation, they take accordingly 128 and 128 bytes.
1557 * OpenSSL's i2d_SSL_SESSION() and d2i_SSL_SESSION are slow,
1558 * so they are outside the code locked by shared pool mutex
1561 static int
1562 ngx_ssl_new_session(ngx_ssl_conn_t *ssl_conn, ngx_ssl_session_t *sess)
1564 int len;
1565 u_char *p, *id, *cached_sess;
1566 uint32_t hash;
1567 SSL_CTX *ssl_ctx;
1568 ngx_shm_zone_t *shm_zone;
1569 ngx_connection_t *c;
1570 ngx_slab_pool_t *shpool;
1571 ngx_ssl_sess_id_t *sess_id;
1572 ngx_ssl_session_cache_t *cache;
1573 u_char buf[NGX_SSL_MAX_SESSION_SIZE];
1575 len = i2d_SSL_SESSION(sess, NULL);
1577 /* do not cache too big session */
1579 if (len > (int) NGX_SSL_MAX_SESSION_SIZE) {
1580 return 0;
1583 p = buf;
1584 i2d_SSL_SESSION(sess, &p);
1586 c = ngx_ssl_get_connection(ssl_conn);
1588 ssl_ctx = SSL_get_SSL_CTX(ssl_conn);
1589 shm_zone = SSL_CTX_get_ex_data(ssl_ctx, ngx_ssl_session_cache_index);
1591 cache = shm_zone->data;
1592 shpool = (ngx_slab_pool_t *) shm_zone->shm.addr;
1594 ngx_shmtx_lock(&shpool->mutex);
1596 /* drop one or two expired sessions */
1597 ngx_ssl_expire_sessions(cache, shpool, 1);
1599 cached_sess = ngx_slab_alloc_locked(shpool, len);
1601 if (cached_sess == NULL) {
1603 /* drop the oldest non-expired session and try once more */
1605 ngx_ssl_expire_sessions(cache, shpool, 0);
1607 cached_sess = ngx_slab_alloc_locked(shpool, len);
1609 if (cached_sess == NULL) {
1610 sess_id = NULL;
1611 goto failed;
1615 sess_id = ngx_slab_alloc_locked(shpool, sizeof(ngx_ssl_sess_id_t));
1616 if (sess_id == NULL) {
1617 goto failed;
1620 #if (NGX_PTR_SIZE == 8)
1622 id = sess_id->sess_id;
1624 #else
1626 id = ngx_slab_alloc_locked(shpool, sess->session_id_length);
1627 if (id == NULL) {
1628 goto failed;
1631 #endif
1633 ngx_memcpy(cached_sess, buf, len);
1635 ngx_memcpy(id, sess->session_id, sess->session_id_length);
1637 hash = ngx_crc32_short(sess->session_id, sess->session_id_length);
1639 ngx_log_debug3(NGX_LOG_DEBUG_EVENT, c->log, 0,
1640 "ssl new session: %08XD:%d:%d",
1641 hash, sess->session_id_length, len);
1643 sess_id->node.key = hash;
1644 sess_id->node.data = (u_char) sess->session_id_length;
1645 sess_id->id = id;
1646 sess_id->len = len;
1647 sess_id->session = cached_sess;
1649 sess_id->expire = ngx_time() + SSL_CTX_get_timeout(ssl_ctx);
1651 ngx_queue_insert_head(&cache->expire_queue, &sess_id->queue);
1653 ngx_rbtree_insert(&cache->session_rbtree, &sess_id->node);
1655 ngx_shmtx_unlock(&shpool->mutex);
1657 return 0;
1659 failed:
1661 if (cached_sess) {
1662 ngx_slab_free_locked(shpool, cached_sess);
1665 if (sess_id) {
1666 ngx_slab_free_locked(shpool, sess_id);
1669 ngx_shmtx_unlock(&shpool->mutex);
1671 ngx_log_error(NGX_LOG_ALERT, c->log, 0,
1672 "could not add new SSL session to the session cache");
1674 return 0;
1678 static ngx_ssl_session_t *
1679 ngx_ssl_get_cached_session(ngx_ssl_conn_t *ssl_conn, u_char *id, int len,
1680 int *copy)
1682 #if OPENSSL_VERSION_NUMBER >= 0x0090707fL
1683 const
1684 #endif
1685 u_char *p;
1686 uint32_t hash;
1687 ngx_int_t rc;
1688 ngx_shm_zone_t *shm_zone;
1689 ngx_slab_pool_t *shpool;
1690 ngx_connection_t *c;
1691 ngx_rbtree_node_t *node, *sentinel;
1692 ngx_ssl_session_t *sess;
1693 ngx_ssl_sess_id_t *sess_id;
1694 ngx_ssl_session_cache_t *cache;
1695 u_char buf[NGX_SSL_MAX_SESSION_SIZE];
1697 c = ngx_ssl_get_connection(ssl_conn);
1699 hash = ngx_crc32_short(id, (size_t) len);
1700 *copy = 0;
1702 ngx_log_debug2(NGX_LOG_DEBUG_EVENT, c->log, 0,
1703 "ssl get session: %08XD:%d", hash, len);
1705 shm_zone = SSL_CTX_get_ex_data(SSL_get_SSL_CTX(ssl_conn),
1706 ngx_ssl_session_cache_index);
1708 cache = shm_zone->data;
1710 sess = NULL;
1712 shpool = (ngx_slab_pool_t *) shm_zone->shm.addr;
1714 ngx_shmtx_lock(&shpool->mutex);
1716 node = cache->session_rbtree.root;
1717 sentinel = cache->session_rbtree.sentinel;
1719 while (node != sentinel) {
1721 if (hash < node->key) {
1722 node = node->left;
1723 continue;
1726 if (hash > node->key) {
1727 node = node->right;
1728 continue;
1731 /* hash == node->key */
1733 do {
1734 sess_id = (ngx_ssl_sess_id_t *) node;
1736 rc = ngx_memn2cmp(id, sess_id->id,
1737 (size_t) len, (size_t) node->data);
1738 if (rc == 0) {
1740 if (sess_id->expire > ngx_time()) {
1741 ngx_memcpy(buf, sess_id->session, sess_id->len);
1743 ngx_shmtx_unlock(&shpool->mutex);
1745 p = buf;
1746 sess = d2i_SSL_SESSION(NULL, &p, sess_id->len);
1748 return sess;
1751 ngx_queue_remove(&sess_id->queue);
1753 ngx_rbtree_delete(&cache->session_rbtree, node);
1755 ngx_slab_free_locked(shpool, sess_id->session);
1756 #if (NGX_PTR_SIZE == 4)
1757 ngx_slab_free_locked(shpool, sess_id->id);
1758 #endif
1759 ngx_slab_free_locked(shpool, sess_id);
1761 sess = NULL;
1763 goto done;
1766 node = (rc < 0) ? node->left : node->right;
1768 } while (node != sentinel && hash == node->key);
1770 break;
1773 done:
1775 ngx_shmtx_unlock(&shpool->mutex);
1777 return sess;
1781 void
1782 ngx_ssl_remove_cached_session(SSL_CTX *ssl, ngx_ssl_session_t *sess)
1784 SSL_CTX_remove_session(ssl, sess);
1786 ngx_ssl_remove_session(ssl, sess);
1790 static void
1791 ngx_ssl_remove_session(SSL_CTX *ssl, ngx_ssl_session_t *sess)
1793 size_t len;
1794 u_char *id;
1795 uint32_t hash;
1796 ngx_int_t rc;
1797 ngx_shm_zone_t *shm_zone;
1798 ngx_slab_pool_t *shpool;
1799 ngx_rbtree_node_t *node, *sentinel;
1800 ngx_ssl_sess_id_t *sess_id;
1801 ngx_ssl_session_cache_t *cache;
1803 shm_zone = SSL_CTX_get_ex_data(ssl, ngx_ssl_session_cache_index);
1805 if (shm_zone == NULL) {
1806 return;
1809 cache = shm_zone->data;
1811 id = sess->session_id;
1812 len = (size_t) sess->session_id_length;
1814 hash = ngx_crc32_short(id, len);
1816 ngx_log_debug2(NGX_LOG_DEBUG_EVENT, ngx_cycle->log, 0,
1817 "ssl remove session: %08XD:%uz", hash, len);
1819 shpool = (ngx_slab_pool_t *) shm_zone->shm.addr;
1821 ngx_shmtx_lock(&shpool->mutex);
1823 node = cache->session_rbtree.root;
1824 sentinel = cache->session_rbtree.sentinel;
1826 while (node != sentinel) {
1828 if (hash < node->key) {
1829 node = node->left;
1830 continue;
1833 if (hash > node->key) {
1834 node = node->right;
1835 continue;
1838 /* hash == node->key */
1840 do {
1841 sess_id = (ngx_ssl_sess_id_t *) node;
1843 rc = ngx_memn2cmp(id, sess_id->id, len, (size_t) node->data);
1845 if (rc == 0) {
1847 ngx_queue_remove(&sess_id->queue);
1849 ngx_rbtree_delete(&cache->session_rbtree, node);
1851 ngx_slab_free_locked(shpool, sess_id->session);
1852 #if (NGX_PTR_SIZE == 4)
1853 ngx_slab_free_locked(shpool, sess_id->id);
1854 #endif
1855 ngx_slab_free_locked(shpool, sess_id);
1857 goto done;
1860 node = (rc < 0) ? node->left : node->right;
1862 } while (node != sentinel && hash == node->key);
1864 break;
1867 done:
1869 ngx_shmtx_unlock(&shpool->mutex);
1873 static void
1874 ngx_ssl_expire_sessions(ngx_ssl_session_cache_t *cache,
1875 ngx_slab_pool_t *shpool, ngx_uint_t n)
1877 time_t now;
1878 ngx_queue_t *q;
1879 ngx_ssl_sess_id_t *sess_id;
1881 now = ngx_time();
1883 while (n < 3) {
1885 if (ngx_queue_empty(&cache->expire_queue)) {
1886 return;
1889 q = ngx_queue_last(&cache->expire_queue);
1891 sess_id = ngx_queue_data(q, ngx_ssl_sess_id_t, queue);
1893 if (n++ != 0 && sess_id->expire > now) {
1894 return;
1897 ngx_queue_remove(q);
1899 ngx_log_debug1(NGX_LOG_DEBUG_EVENT, ngx_cycle->log, 0,
1900 "expire session: %08Xi", sess_id->node.key);
1902 ngx_rbtree_delete(&cache->session_rbtree, &sess_id->node);
1904 ngx_slab_free_locked(shpool, sess_id->session);
1905 #if (NGX_PTR_SIZE == 4)
1906 ngx_slab_free_locked(shpool, sess_id->id);
1907 #endif
1908 ngx_slab_free_locked(shpool, sess_id);
1913 static void
1914 ngx_ssl_session_rbtree_insert_value(ngx_rbtree_node_t *temp,
1915 ngx_rbtree_node_t *node, ngx_rbtree_node_t *sentinel)
1917 ngx_rbtree_node_t **p;
1918 ngx_ssl_sess_id_t *sess_id, *sess_id_temp;
1920 for ( ;; ) {
1922 if (node->key < temp->key) {
1924 p = &temp->left;
1926 } else if (node->key > temp->key) {
1928 p = &temp->right;
1930 } else { /* node->key == temp->key */
1932 sess_id = (ngx_ssl_sess_id_t *) node;
1933 sess_id_temp = (ngx_ssl_sess_id_t *) temp;
1935 p = (ngx_memn2cmp(sess_id->id, sess_id_temp->id,
1936 (size_t) node->data, (size_t) temp->data)
1937 < 0) ? &temp->left : &temp->right;
1940 if (*p == sentinel) {
1941 break;
1944 temp = *p;
1947 *p = node;
1948 node->parent = temp;
1949 node->left = sentinel;
1950 node->right = sentinel;
1951 ngx_rbt_red(node);
1955 void
1956 ngx_ssl_cleanup_ctx(void *data)
1958 ngx_ssl_t *ssl = data;
1960 SSL_CTX_free(ssl->ctx);
1964 ngx_int_t
1965 ngx_ssl_get_protocol(ngx_connection_t *c, ngx_pool_t *pool, ngx_str_t *s)
1967 s->data = (u_char *) SSL_get_version(c->ssl->connection);
1968 return NGX_OK;
1972 ngx_int_t
1973 ngx_ssl_get_cipher_name(ngx_connection_t *c, ngx_pool_t *pool, ngx_str_t *s)
1975 s->data = (u_char *) SSL_get_cipher_name(c->ssl->connection);
1976 return NGX_OK;
1980 ngx_int_t
1981 ngx_ssl_get_session_id(ngx_connection_t *c, ngx_pool_t *pool, ngx_str_t *s)
1983 int len;
1984 u_char *p, *buf;
1985 SSL_SESSION *sess;
1987 sess = SSL_get0_session(c->ssl->connection);
1989 len = i2d_SSL_SESSION(sess, NULL);
1991 buf = ngx_alloc(len, c->log);
1992 if (buf == NULL) {
1993 return NGX_ERROR;
1996 s->len = 2 * len;
1997 s->data = ngx_pnalloc(pool, 2 * len);
1998 if (s->data == NULL) {
1999 ngx_free(buf);
2000 return NGX_ERROR;
2003 p = buf;
2004 i2d_SSL_SESSION(sess, &p);
2006 ngx_hex_dump(s->data, buf, len);
2008 ngx_free(buf);
2010 return NGX_OK;
2014 ngx_int_t
2015 ngx_ssl_get_raw_certificate(ngx_connection_t *c, ngx_pool_t *pool, ngx_str_t *s)
2017 size_t len;
2018 BIO *bio;
2019 X509 *cert;
2021 s->len = 0;
2023 cert = SSL_get_peer_certificate(c->ssl->connection);
2024 if (cert == NULL) {
2025 return NGX_OK;
2028 bio = BIO_new(BIO_s_mem());
2029 if (bio == NULL) {
2030 ngx_ssl_error(NGX_LOG_ALERT, c->log, 0, "BIO_new() failed");
2031 X509_free(cert);
2032 return NGX_ERROR;
2035 if (PEM_write_bio_X509(bio, cert) == 0) {
2036 ngx_ssl_error(NGX_LOG_ALERT, c->log, 0, "PEM_write_bio_X509() failed");
2037 goto failed;
2040 len = BIO_pending(bio);
2041 s->len = len;
2043 s->data = ngx_pnalloc(pool, len);
2044 if (s->data == NULL) {
2045 goto failed;
2048 BIO_read(bio, s->data, len);
2050 BIO_free(bio);
2051 X509_free(cert);
2053 return NGX_OK;
2055 failed:
2057 BIO_free(bio);
2058 X509_free(cert);
2060 return NGX_ERROR;
2064 ngx_int_t
2065 ngx_ssl_get_certificate(ngx_connection_t *c, ngx_pool_t *pool, ngx_str_t *s)
2067 u_char *p;
2068 size_t len;
2069 ngx_uint_t i;
2070 ngx_str_t cert;
2072 if (ngx_ssl_get_raw_certificate(c, pool, &cert) != NGX_OK) {
2073 return NGX_ERROR;
2076 if (cert.len == 0) {
2077 s->len = 0;
2078 return NGX_OK;
2081 len = cert.len - 1;
2083 for (i = 0; i < cert.len - 1; i++) {
2084 if (cert.data[i] == LF) {
2085 len++;
2089 s->len = len;
2090 s->data = ngx_pnalloc(pool, len);
2091 if (s->data == NULL) {
2092 return NGX_ERROR;
2095 p = s->data;
2097 for (i = 0; i < cert.len - 1; i++) {
2098 *p++ = cert.data[i];
2099 if (cert.data[i] == LF) {
2100 *p++ = '\t';
2104 return NGX_OK;
2108 ngx_int_t
2109 ngx_ssl_get_subject_dn(ngx_connection_t *c, ngx_pool_t *pool, ngx_str_t *s)
2111 char *p;
2112 size_t len;
2113 X509 *cert;
2114 X509_NAME *name;
2116 s->len = 0;
2118 cert = SSL_get_peer_certificate(c->ssl->connection);
2119 if (cert == NULL) {
2120 return NGX_OK;
2123 name = X509_get_subject_name(cert);
2124 if (name == NULL) {
2125 X509_free(cert);
2126 return NGX_ERROR;
2129 p = X509_NAME_oneline(name, NULL, 0);
2131 for (len = 0; p[len]; len++) { /* void */ }
2133 s->len = len;
2134 s->data = ngx_pnalloc(pool, len);
2135 if (s->data == NULL) {
2136 OPENSSL_free(p);
2137 X509_free(cert);
2138 return NGX_ERROR;
2141 ngx_memcpy(s->data, p, len);
2143 OPENSSL_free(p);
2144 X509_free(cert);
2146 return NGX_OK;
2150 ngx_int_t
2151 ngx_ssl_get_issuer_dn(ngx_connection_t *c, ngx_pool_t *pool, ngx_str_t *s)
2153 char *p;
2154 size_t len;
2155 X509 *cert;
2156 X509_NAME *name;
2158 s->len = 0;
2160 cert = SSL_get_peer_certificate(c->ssl->connection);
2161 if (cert == NULL) {
2162 return NGX_OK;
2165 name = X509_get_issuer_name(cert);
2166 if (name == NULL) {
2167 X509_free(cert);
2168 return NGX_ERROR;
2171 p = X509_NAME_oneline(name, NULL, 0);
2173 for (len = 0; p[len]; len++) { /* void */ }
2175 s->len = len;
2176 s->data = ngx_pnalloc(pool, len);
2177 if (s->data == NULL) {
2178 OPENSSL_free(p);
2179 X509_free(cert);
2180 return NGX_ERROR;
2183 ngx_memcpy(s->data, p, len);
2185 OPENSSL_free(p);
2186 X509_free(cert);
2188 return NGX_OK;
2192 ngx_int_t
2193 ngx_ssl_get_serial_number(ngx_connection_t *c, ngx_pool_t *pool, ngx_str_t *s)
2195 size_t len;
2196 X509 *cert;
2197 BIO *bio;
2199 s->len = 0;
2201 cert = SSL_get_peer_certificate(c->ssl->connection);
2202 if (cert == NULL) {
2203 return NGX_OK;
2206 bio = BIO_new(BIO_s_mem());
2207 if (bio == NULL) {
2208 X509_free(cert);
2209 return NGX_ERROR;
2212 i2a_ASN1_INTEGER(bio, X509_get_serialNumber(cert));
2213 len = BIO_pending(bio);
2215 s->len = len;
2216 s->data = ngx_pnalloc(pool, len);
2217 if (s->data == NULL) {
2218 BIO_free(bio);
2219 X509_free(cert);
2220 return NGX_ERROR;
2223 BIO_read(bio, s->data, len);
2224 BIO_free(bio);
2225 X509_free(cert);
2227 return NGX_OK;
2231 ngx_int_t
2232 ngx_ssl_get_client_verify(ngx_connection_t *c, ngx_pool_t *pool, ngx_str_t *s)
2234 X509 *cert;
2236 if (SSL_get_verify_result(c->ssl->connection) != X509_V_OK) {
2237 ngx_str_set(s, "FAILED");
2238 return NGX_OK;
2241 cert = SSL_get_peer_certificate(c->ssl->connection);
2243 if (cert) {
2244 ngx_str_set(s, "SUCCESS");
2246 } else {
2247 ngx_str_set(s, "NONE");
2250 X509_free(cert);
2252 return NGX_OK;
2256 static void *
2257 ngx_openssl_create_conf(ngx_cycle_t *cycle)
2259 ngx_openssl_conf_t *oscf;
2261 oscf = ngx_pcalloc(cycle->pool, sizeof(ngx_openssl_conf_t));
2262 if (oscf == NULL) {
2263 return NULL;
2267 * set by ngx_pcalloc():
2269 * oscf->engine = 0;
2272 return oscf;
2276 static char *
2277 ngx_openssl_engine(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
2279 ngx_openssl_conf_t *oscf = conf;
2281 ENGINE *engine;
2282 ngx_str_t *value;
2284 if (oscf->engine) {
2285 return "is duplicate";
2288 oscf->engine = 1;
2290 value = cf->args->elts;
2292 engine = ENGINE_by_id((const char *) value[1].data);
2294 if (engine == NULL) {
2295 ngx_ssl_error(NGX_LOG_WARN, cf->log, 0,
2296 "ENGINE_by_id(\"%V\") failed", &value[1]);
2297 return NGX_CONF_ERROR;
2300 if (ENGINE_set_default(engine, ENGINE_METHOD_ALL) == 0) {
2301 ngx_ssl_error(NGX_LOG_WARN, cf->log, 0,
2302 "ENGINE_set_default(\"%V\", ENGINE_METHOD_ALL) failed",
2303 &value[1]);
2305 ENGINE_free(engine);
2307 return NGX_CONF_ERROR;
2310 ENGINE_free(engine);
2312 return NGX_CONF_OK;
2316 static void
2317 ngx_openssl_exit(ngx_cycle_t *cycle)
2319 EVP_cleanup();
2320 ENGINE_cleanup();