10Sigor@sysoev.ru 20Sigor@sysoev.ru /* 30Sigor@sysoev.ru * Copyright (C) Igor Sysoev 40Sigor@sysoev.ru * Copyright (C) NGINX, Inc. 50Sigor@sysoev.ru */ 60Sigor@sysoev.ru 70Sigor@sysoev.ru #include <nxt_main.h> 80Sigor@sysoev.ru #include <openssl/ssl.h> 90Sigor@sysoev.ru #include <openssl/conf.h> 100Sigor@sysoev.ru #include <openssl/err.h> 110Sigor@sysoev.ru 120Sigor@sysoev.ru 130Sigor@sysoev.ru typedef struct { 140Sigor@sysoev.ru SSL *session; 150Sigor@sysoev.ru 160Sigor@sysoev.ru int ssl_error; 170Sigor@sysoev.ru uint8_t times; /* 2 bits */ 180Sigor@sysoev.ru 190Sigor@sysoev.ru nxt_buf_mem_t buffer; 200Sigor@sysoev.ru } nxt_openssl_conn_t; 210Sigor@sysoev.ru 220Sigor@sysoev.ru 230Sigor@sysoev.ru static nxt_int_t nxt_openssl_server_init(nxt_ssltls_conf_t *conf); 240Sigor@sysoev.ru 25*1Sigor@sysoev.ru static void nxt_openssl_conn_init(nxt_task_t *task, nxt_ssltls_conf_t *conf, 260Sigor@sysoev.ru nxt_event_conn_t *c); 270Sigor@sysoev.ru static void nxt_openssl_session_cleanup(void *data); 28*1Sigor@sysoev.ru static void nxt_openssl_conn_handshake(nxt_task_t *task, void *obj, void *data); 29*1Sigor@sysoev.ru static void nxt_openssl_conn_io_read(nxt_task_t *task, void *obj, void *data); 30*1Sigor@sysoev.ru static void nxt_openssl_conn_io_shutdown(nxt_task_t *task, void *obj, 310Sigor@sysoev.ru void *data); 32*1Sigor@sysoev.ru static ssize_t nxt_openssl_conn_io_write_chunk(nxt_event_conn_t *c, 33*1Sigor@sysoev.ru nxt_buf_t *b, size_t limit); 340Sigor@sysoev.ru static ssize_t nxt_openssl_conn_io_send(nxt_event_conn_t *c, void *buf, 350Sigor@sysoev.ru size_t size); 36*1Sigor@sysoev.ru static nxt_int_t nxt_openssl_conn_test_error(nxt_task_t *task, 370Sigor@sysoev.ru nxt_event_conn_t *c, int ret, nxt_err_t sys_err, 380Sigor@sysoev.ru nxt_work_handler_t handler); 390Sigor@sysoev.ru static void nxt_cdecl nxt_openssl_conn_error(nxt_event_conn_t *c, nxt_err_t err, 400Sigor@sysoev.ru const char *fmt, ...); 410Sigor@sysoev.ru static nxt_uint_t nxt_openssl_log_error_level(nxt_event_conn_t *c, 420Sigor@sysoev.ru nxt_err_t err); 430Sigor@sysoev.ru static void nxt_cdecl nxt_openssl_log_error(nxt_uint_t level, nxt_log_t *log, 440Sigor@sysoev.ru const char *fmt, ...); 450Sigor@sysoev.ru static u_char *nxt_openssl_copy_error(u_char *p, u_char *end); 460Sigor@sysoev.ru 470Sigor@sysoev.ru 480Sigor@sysoev.ru const nxt_ssltls_lib_t nxt_openssl_lib = { 490Sigor@sysoev.ru nxt_openssl_server_init, 500Sigor@sysoev.ru NULL, 510Sigor@sysoev.ru }; 520Sigor@sysoev.ru 530Sigor@sysoev.ru 540Sigor@sysoev.ru static nxt_event_conn_io_t nxt_openssl_event_conn_io = { 550Sigor@sysoev.ru NULL, 560Sigor@sysoev.ru NULL, 570Sigor@sysoev.ru 580Sigor@sysoev.ru nxt_openssl_conn_io_read, 590Sigor@sysoev.ru NULL, 600Sigor@sysoev.ru NULL, 610Sigor@sysoev.ru 620Sigor@sysoev.ru nxt_event_conn_io_write, 630Sigor@sysoev.ru nxt_openssl_conn_io_write_chunk, 640Sigor@sysoev.ru NULL, 650Sigor@sysoev.ru NULL, 660Sigor@sysoev.ru nxt_openssl_conn_io_send, 670Sigor@sysoev.ru 680Sigor@sysoev.ru nxt_openssl_conn_io_shutdown, 690Sigor@sysoev.ru }; 700Sigor@sysoev.ru 710Sigor@sysoev.ru 720Sigor@sysoev.ru static long nxt_openssl_version; 730Sigor@sysoev.ru static int nxt_openssl_connection_index; 740Sigor@sysoev.ru 750Sigor@sysoev.ru 760Sigor@sysoev.ru static nxt_int_t 770Sigor@sysoev.ru nxt_openssl_start(nxt_thread_t *thr) 780Sigor@sysoev.ru { 790Sigor@sysoev.ru int index; 800Sigor@sysoev.ru 810Sigor@sysoev.ru if (nxt_fast_path(nxt_openssl_version != 0)) { 820Sigor@sysoev.ru return NXT_OK; 830Sigor@sysoev.ru } 840Sigor@sysoev.ru 850Sigor@sysoev.ru SSL_load_error_strings(); 860Sigor@sysoev.ru 870Sigor@sysoev.ru OPENSSL_config(NULL); 880Sigor@sysoev.ru 890Sigor@sysoev.ru /* 900Sigor@sysoev.ru * SSL_library_init(3): 910Sigor@sysoev.ru * 920Sigor@sysoev.ru * SSL_library_init() always returns "1", 930Sigor@sysoev.ru * so it is safe to discard the return value. 940Sigor@sysoev.ru */ 950Sigor@sysoev.ru (void) SSL_library_init(); 960Sigor@sysoev.ru 970Sigor@sysoev.ru nxt_openssl_version = SSLeay(); 980Sigor@sysoev.ru 990Sigor@sysoev.ru nxt_log_error(NXT_LOG_INFO, thr->log, "%s, %xl", 1000Sigor@sysoev.ru SSLeay_version(SSLEAY_VERSION), nxt_openssl_version); 1010Sigor@sysoev.ru 1020Sigor@sysoev.ru #ifndef SSL_OP_NO_COMPRESSION 1030Sigor@sysoev.ru { 1040Sigor@sysoev.ru /* 1050Sigor@sysoev.ru * Disable gzip compression in OpenSSL prior to 1.0.0 1060Sigor@sysoev.ru * version, this saves about 522K per connection. 1070Sigor@sysoev.ru */ 1080Sigor@sysoev.ru int n; 1090Sigor@sysoev.ru STACK_OF(SSL_COMP) *ssl_comp_methods; 1100Sigor@sysoev.ru 1110Sigor@sysoev.ru ssl_comp_methods = SSL_COMP_get_compression_methods(); 1120Sigor@sysoev.ru 1130Sigor@sysoev.ru for (n = sk_SSL_COMP_num(ssl_comp_methods); n != 0; n--) { 1140Sigor@sysoev.ru (void) sk_SSL_COMP_pop(ssl_comp_methods); 1150Sigor@sysoev.ru } 1160Sigor@sysoev.ru } 1170Sigor@sysoev.ru #endif 1180Sigor@sysoev.ru 1190Sigor@sysoev.ru index = SSL_get_ex_new_index(0, NULL, NULL, NULL, NULL); 1200Sigor@sysoev.ru 1210Sigor@sysoev.ru if (index == -1) { 1220Sigor@sysoev.ru nxt_openssl_log_error(NXT_LOG_CRIT, thr->log, 1230Sigor@sysoev.ru "SSL_get_ex_new_index() failed"); 1240Sigor@sysoev.ru return NXT_ERROR; 1250Sigor@sysoev.ru } 1260Sigor@sysoev.ru 1270Sigor@sysoev.ru nxt_openssl_connection_index = index; 1280Sigor@sysoev.ru 1290Sigor@sysoev.ru return NXT_OK; 1300Sigor@sysoev.ru } 1310Sigor@sysoev.ru 1320Sigor@sysoev.ru 1330Sigor@sysoev.ru static nxt_int_t 1340Sigor@sysoev.ru nxt_openssl_server_init(nxt_ssltls_conf_t *conf) 1350Sigor@sysoev.ru { 1360Sigor@sysoev.ru SSL_CTX *ctx; 1370Sigor@sysoev.ru const char *certificate, *key, *ciphers, *ca_certificate; 1380Sigor@sysoev.ru nxt_thread_t *thr; 1390Sigor@sysoev.ru STACK_OF(X509_NAME) *list; 1400Sigor@sysoev.ru 1410Sigor@sysoev.ru thr = nxt_thread(); 1420Sigor@sysoev.ru 1430Sigor@sysoev.ru if (nxt_openssl_start(thr) != NXT_OK) { 1440Sigor@sysoev.ru return NXT_ERROR; 1450Sigor@sysoev.ru } 1460Sigor@sysoev.ru 1470Sigor@sysoev.ru ctx = SSL_CTX_new(SSLv23_server_method()); 1480Sigor@sysoev.ru if (ctx == NULL) { 1490Sigor@sysoev.ru nxt_openssl_log_error(NXT_LOG_CRIT, thr->log, "SSL_CTX_new() failed"); 1500Sigor@sysoev.ru return NXT_ERROR; 1510Sigor@sysoev.ru } 1520Sigor@sysoev.ru 1530Sigor@sysoev.ru conf->ctx = ctx; 1540Sigor@sysoev.ru conf->conn_init = nxt_openssl_conn_init; 1550Sigor@sysoev.ru 1560Sigor@sysoev.ru #ifdef SSL_OP_NO_COMPRESSION 1570Sigor@sysoev.ru /* 1580Sigor@sysoev.ru * Disable gzip compression in OpenSSL 1.0.0, 1590Sigor@sysoev.ru * this saves about 522K per connection. 1600Sigor@sysoev.ru */ 1610Sigor@sysoev.ru SSL_CTX_set_options(ctx, SSL_OP_NO_COMPRESSION); 1620Sigor@sysoev.ru #endif 1630Sigor@sysoev.ru 1640Sigor@sysoev.ru #ifdef SSL_MODE_RELEASE_BUFFERS 1650Sigor@sysoev.ru 1660Sigor@sysoev.ru if (nxt_openssl_version >= 10001078) { 1670Sigor@sysoev.ru /* 1680Sigor@sysoev.ru * Allow to release read and write buffers in OpenSSL 1.0.0, 1690Sigor@sysoev.ru * this saves about 34K per idle connection. It is not safe 1700Sigor@sysoev.ru * before OpenSSL 1.0.1h (CVE-2010-5298). 1710Sigor@sysoev.ru */ 1720Sigor@sysoev.ru SSL_CTX_set_mode(ctx, SSL_MODE_RELEASE_BUFFERS); 1730Sigor@sysoev.ru } 1740Sigor@sysoev.ru 1750Sigor@sysoev.ru #endif 1760Sigor@sysoev.ru 1770Sigor@sysoev.ru certificate = conf->certificate; 1780Sigor@sysoev.ru 1790Sigor@sysoev.ru if (SSL_CTX_use_certificate_chain_file(ctx, certificate) == 0) { 1800Sigor@sysoev.ru nxt_openssl_log_error(NXT_LOG_CRIT, thr->log, 1810Sigor@sysoev.ru "SSL_CTX_use_certificate_file(\"%s\") failed", 1820Sigor@sysoev.ru certificate); 1830Sigor@sysoev.ru goto fail; 1840Sigor@sysoev.ru } 1850Sigor@sysoev.ru 1860Sigor@sysoev.ru key = conf->certificate_key; 1870Sigor@sysoev.ru 1880Sigor@sysoev.ru if (SSL_CTX_use_PrivateKey_file(ctx, key, SSL_FILETYPE_PEM) == 0) { 1890Sigor@sysoev.ru nxt_openssl_log_error(NXT_LOG_CRIT, thr->log, 1900Sigor@sysoev.ru "SSL_CTX_use_PrivateKey_file(\"%s\") failed", 1910Sigor@sysoev.ru key); 1920Sigor@sysoev.ru goto fail; 1930Sigor@sysoev.ru } 1940Sigor@sysoev.ru 1950Sigor@sysoev.ru ciphers = (conf->ciphers != NULL) ? conf->ciphers : "HIGH:!aNULL:!MD5"; 1960Sigor@sysoev.ru 1970Sigor@sysoev.ru if (SSL_CTX_set_cipher_list(ctx, ciphers) == 0) { 1980Sigor@sysoev.ru nxt_openssl_log_error(NXT_LOG_CRIT, thr->log, 1990Sigor@sysoev.ru "SSL_CTX_set_cipher_list(\"%s\") failed", 2000Sigor@sysoev.ru ciphers); 2010Sigor@sysoev.ru goto fail; 2020Sigor@sysoev.ru } 2030Sigor@sysoev.ru 2040Sigor@sysoev.ru SSL_CTX_set_options(ctx, SSL_OP_CIPHER_SERVER_PREFERENCE); 2050Sigor@sysoev.ru 2060Sigor@sysoev.ru if (conf->ca_certificate != NULL) { 2070Sigor@sysoev.ru 2080Sigor@sysoev.ru /* TODO: verify callback */ 2090Sigor@sysoev.ru SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER, NULL); 2100Sigor@sysoev.ru 2110Sigor@sysoev.ru /* TODO: verify depth */ 2120Sigor@sysoev.ru SSL_CTX_set_verify_depth(ctx, 1); 2130Sigor@sysoev.ru 2140Sigor@sysoev.ru ca_certificate = conf->ca_certificate; 2150Sigor@sysoev.ru 2160Sigor@sysoev.ru if (SSL_CTX_load_verify_locations(ctx, ca_certificate, NULL) == 0) { 2170Sigor@sysoev.ru nxt_openssl_log_error(NXT_LOG_CRIT, thr->log, 2180Sigor@sysoev.ru "SSL_CTX_load_verify_locations(\"%s\") failed", 2190Sigor@sysoev.ru ca_certificate); 2200Sigor@sysoev.ru goto fail; 2210Sigor@sysoev.ru } 2220Sigor@sysoev.ru 2230Sigor@sysoev.ru list = SSL_load_client_CA_file(ca_certificate); 2240Sigor@sysoev.ru 2250Sigor@sysoev.ru if (list == NULL) { 2260Sigor@sysoev.ru nxt_openssl_log_error(NXT_LOG_CRIT, thr->log, 2270Sigor@sysoev.ru "SSL_load_client_CA_file(\"%s\") failed", 2280Sigor@sysoev.ru ca_certificate); 2290Sigor@sysoev.ru goto fail; 2300Sigor@sysoev.ru } 2310Sigor@sysoev.ru 2320Sigor@sysoev.ru /* 2330Sigor@sysoev.ru * SSL_load_client_CA_file() in OpenSSL prior to 0.9.7h and 2340Sigor@sysoev.ru * 0.9.8 versions always leaves an error in the error queue. 2350Sigor@sysoev.ru */ 2360Sigor@sysoev.ru ERR_clear_error(); 2370Sigor@sysoev.ru 2380Sigor@sysoev.ru SSL_CTX_set_client_CA_list(ctx, list); 2390Sigor@sysoev.ru } 2400Sigor@sysoev.ru 2410Sigor@sysoev.ru return NXT_OK; 2420Sigor@sysoev.ru 2430Sigor@sysoev.ru fail: 2440Sigor@sysoev.ru 2450Sigor@sysoev.ru SSL_CTX_free(ctx); 2460Sigor@sysoev.ru 2470Sigor@sysoev.ru return NXT_ERROR; 2480Sigor@sysoev.ru } 2490Sigor@sysoev.ru 2500Sigor@sysoev.ru 2510Sigor@sysoev.ru static void 252*1Sigor@sysoev.ru nxt_openssl_conn_init(nxt_task_t *task, nxt_ssltls_conf_t *conf, 2530Sigor@sysoev.ru nxt_event_conn_t *c) 2540Sigor@sysoev.ru { 2550Sigor@sysoev.ru int ret; 2560Sigor@sysoev.ru SSL *s; 2570Sigor@sysoev.ru SSL_CTX *ctx; 2580Sigor@sysoev.ru nxt_openssl_conn_t *ssltls; 2590Sigor@sysoev.ru nxt_mem_pool_cleanup_t *mpcl; 2600Sigor@sysoev.ru 2610Sigor@sysoev.ru nxt_log_debug(c->socket.log, "openssl conn init"); 2620Sigor@sysoev.ru 2630Sigor@sysoev.ru ssltls = nxt_mem_zalloc(c->mem_pool, sizeof(nxt_openssl_conn_t)); 2640Sigor@sysoev.ru if (ssltls == NULL) { 2650Sigor@sysoev.ru goto fail; 2660Sigor@sysoev.ru } 2670Sigor@sysoev.ru 2680Sigor@sysoev.ru c->u.ssltls = ssltls; 2690Sigor@sysoev.ru nxt_buf_mem_set_size(&ssltls->buffer, conf->buffer_size); 2700Sigor@sysoev.ru 2710Sigor@sysoev.ru mpcl = nxt_mem_pool_cleanup(c->mem_pool, 0); 2720Sigor@sysoev.ru if (mpcl == NULL) { 2730Sigor@sysoev.ru goto fail; 2740Sigor@sysoev.ru } 2750Sigor@sysoev.ru 2760Sigor@sysoev.ru ctx = conf->ctx; 2770Sigor@sysoev.ru 2780Sigor@sysoev.ru s = SSL_new(ctx); 2790Sigor@sysoev.ru if (s == NULL) { 2800Sigor@sysoev.ru nxt_openssl_log_error(NXT_LOG_CRIT, c->socket.log, "SSL_new() failed"); 2810Sigor@sysoev.ru goto fail; 2820Sigor@sysoev.ru } 2830Sigor@sysoev.ru 2840Sigor@sysoev.ru ssltls->session = s; 2850Sigor@sysoev.ru mpcl->handler = nxt_openssl_session_cleanup; 2860Sigor@sysoev.ru mpcl->data = ssltls; 2870Sigor@sysoev.ru 2880Sigor@sysoev.ru ret = SSL_set_fd(s, c->socket.fd); 2890Sigor@sysoev.ru 2900Sigor@sysoev.ru if (ret == 0) { 2910Sigor@sysoev.ru nxt_openssl_log_error(NXT_LOG_CRIT, c->socket.log, 2920Sigor@sysoev.ru "SSL_set_fd(%d) failed", c->socket.fd); 2930Sigor@sysoev.ru goto fail; 2940Sigor@sysoev.ru } 2950Sigor@sysoev.ru 2960Sigor@sysoev.ru SSL_set_accept_state(s); 2970Sigor@sysoev.ru 2980Sigor@sysoev.ru if (SSL_set_ex_data(s, nxt_openssl_connection_index, c) == 0) { 2990Sigor@sysoev.ru nxt_openssl_log_error(NXT_LOG_CRIT, c->socket.log, 3000Sigor@sysoev.ru "SSL_set_ex_data() failed"); 3010Sigor@sysoev.ru goto fail; 3020Sigor@sysoev.ru } 3030Sigor@sysoev.ru 3040Sigor@sysoev.ru c->io = &nxt_openssl_event_conn_io; 3050Sigor@sysoev.ru c->sendfile = NXT_CONN_SENDFILE_OFF; 3060Sigor@sysoev.ru 307*1Sigor@sysoev.ru nxt_openssl_conn_handshake(task, c, c->socket.data); 3080Sigor@sysoev.ru return; 3090Sigor@sysoev.ru 3100Sigor@sysoev.ru fail: 3110Sigor@sysoev.ru 312*1Sigor@sysoev.ru nxt_event_conn_io_handle(task->thread, c->read_work_queue, 313*1Sigor@sysoev.ru c->read_state->error_handler, 314*1Sigor@sysoev.ru task, c, c->socket.data); 3150Sigor@sysoev.ru } 3160Sigor@sysoev.ru 3170Sigor@sysoev.ru 3180Sigor@sysoev.ru static void 3190Sigor@sysoev.ru nxt_openssl_session_cleanup(void *data) 3200Sigor@sysoev.ru { 3210Sigor@sysoev.ru nxt_openssl_conn_t *ssltls; 3220Sigor@sysoev.ru 3230Sigor@sysoev.ru ssltls = data; 3240Sigor@sysoev.ru 3250Sigor@sysoev.ru nxt_thread_log_debug("openssl session cleanup"); 3260Sigor@sysoev.ru 3270Sigor@sysoev.ru nxt_free(ssltls->buffer.start); 3280Sigor@sysoev.ru 3290Sigor@sysoev.ru SSL_free(ssltls->session); 3300Sigor@sysoev.ru } 3310Sigor@sysoev.ru 3320Sigor@sysoev.ru 3330Sigor@sysoev.ru static void 334*1Sigor@sysoev.ru nxt_openssl_conn_handshake(nxt_task_t *task, void *obj, void *data) 3350Sigor@sysoev.ru { 3360Sigor@sysoev.ru int ret; 3370Sigor@sysoev.ru nxt_int_t n; 3380Sigor@sysoev.ru nxt_err_t err; 3390Sigor@sysoev.ru nxt_event_conn_t *c; 3400Sigor@sysoev.ru nxt_openssl_conn_t *ssltls; 3410Sigor@sysoev.ru 3420Sigor@sysoev.ru c = obj; 3430Sigor@sysoev.ru ssltls = c->u.ssltls; 3440Sigor@sysoev.ru 345*1Sigor@sysoev.ru nxt_debug(task, "openssl conn handshake: %d", ssltls->times); 3460Sigor@sysoev.ru 3470Sigor@sysoev.ru /* "ssltls->times == 1" is suitable to run SSL_do_handshake() in job. */ 3480Sigor@sysoev.ru 3490Sigor@sysoev.ru ret = SSL_do_handshake(ssltls->session); 3500Sigor@sysoev.ru 3510Sigor@sysoev.ru err = (ret <= 0) ? nxt_socket_errno : 0; 3520Sigor@sysoev.ru 353*1Sigor@sysoev.ru nxt_thread_time_debug_update(task->thread); 3540Sigor@sysoev.ru 355*1Sigor@sysoev.ru nxt_debug(task, "SSL_do_handshake(%d): %d err:%d", c->socket.fd, ret, err); 3560Sigor@sysoev.ru 3570Sigor@sysoev.ru if (ret > 0) { 3580Sigor@sysoev.ru /* ret == 1, the handshake was successfully completed. */ 359*1Sigor@sysoev.ru nxt_openssl_conn_io_read(task, c, data); 3600Sigor@sysoev.ru return; 3610Sigor@sysoev.ru } 3620Sigor@sysoev.ru 363*1Sigor@sysoev.ru n = nxt_openssl_conn_test_error(task, c, ret, err, 3640Sigor@sysoev.ru nxt_openssl_conn_handshake); 3650Sigor@sysoev.ru 3660Sigor@sysoev.ru if (n == NXT_ERROR) { 3670Sigor@sysoev.ru nxt_openssl_conn_error(c, err, "SSL_do_handshake(%d) failed", 3680Sigor@sysoev.ru c->socket.fd); 3690Sigor@sysoev.ru 370*1Sigor@sysoev.ru nxt_event_conn_io_handle(task->thread, c->read_work_queue, 371*1Sigor@sysoev.ru c->read_state->error_handler, 372*1Sigor@sysoev.ru task, c, data); 3730Sigor@sysoev.ru 3740Sigor@sysoev.ru } else if (ssltls->ssl_error == SSL_ERROR_WANT_READ && ssltls->times < 2) { 3750Sigor@sysoev.ru ssltls->times++; 3760Sigor@sysoev.ru } 3770Sigor@sysoev.ru } 3780Sigor@sysoev.ru 3790Sigor@sysoev.ru 3800Sigor@sysoev.ru static void 381*1Sigor@sysoev.ru nxt_openssl_conn_io_read(nxt_task_t *task, void *obj, void *data) 3820Sigor@sysoev.ru { 3830Sigor@sysoev.ru int ret; 3840Sigor@sysoev.ru nxt_buf_t *b; 3850Sigor@sysoev.ru nxt_int_t n; 3860Sigor@sysoev.ru nxt_err_t err; 3870Sigor@sysoev.ru nxt_event_conn_t *c; 3880Sigor@sysoev.ru nxt_work_handler_t handler; 3890Sigor@sysoev.ru nxt_openssl_conn_t *ssltls; 3900Sigor@sysoev.ru 3910Sigor@sysoev.ru c = obj; 3920Sigor@sysoev.ru 393*1Sigor@sysoev.ru nxt_debug(task, "openssl conn read"); 3940Sigor@sysoev.ru 3950Sigor@sysoev.ru handler = c->read_state->ready_handler; 3960Sigor@sysoev.ru b = c->read; 3970Sigor@sysoev.ru 3980Sigor@sysoev.ru /* b == NULL is used to test descriptor readiness. */ 3990Sigor@sysoev.ru 4000Sigor@sysoev.ru if (b != NULL) { 4010Sigor@sysoev.ru ssltls = c->u.ssltls; 4020Sigor@sysoev.ru 4030Sigor@sysoev.ru ret = SSL_read(ssltls->session, b->mem.free, b->mem.end - b->mem.free); 4040Sigor@sysoev.ru 4050Sigor@sysoev.ru err = (ret <= 0) ? nxt_socket_errno : 0; 4060Sigor@sysoev.ru 407*1Sigor@sysoev.ru nxt_debug(task, "SSL_read(%d, %p, %uz): %d err:%d", 408*1Sigor@sysoev.ru c->socket.fd, b->mem.free, b->mem.end - b->mem.free, 409*1Sigor@sysoev.ru ret, err); 4100Sigor@sysoev.ru 4110Sigor@sysoev.ru if (ret > 0) { 4120Sigor@sysoev.ru /* c->socket.read_ready is kept. */ 4130Sigor@sysoev.ru b->mem.free += ret; 4140Sigor@sysoev.ru handler = c->read_state->ready_handler; 4150Sigor@sysoev.ru 4160Sigor@sysoev.ru } else { 417*1Sigor@sysoev.ru n = nxt_openssl_conn_test_error(task, c, ret, err, 4180Sigor@sysoev.ru nxt_openssl_conn_io_read); 4190Sigor@sysoev.ru 4200Sigor@sysoev.ru if (nxt_fast_path(n != NXT_ERROR)) { 4210Sigor@sysoev.ru return; 4220Sigor@sysoev.ru } 4230Sigor@sysoev.ru 4240Sigor@sysoev.ru nxt_openssl_conn_error(c, err, "SSL_read(%d, %p, %uz) failed", 4250Sigor@sysoev.ru c->socket.fd, b->mem.free, 4260Sigor@sysoev.ru b->mem.end - b->mem.free); 4270Sigor@sysoev.ru 4280Sigor@sysoev.ru handler = c->read_state->error_handler; 4290Sigor@sysoev.ru } 4300Sigor@sysoev.ru } 4310Sigor@sysoev.ru 432*1Sigor@sysoev.ru nxt_event_conn_io_handle(task->thread, c->read_work_queue, handler, 433*1Sigor@sysoev.ru task, c, data); 4340Sigor@sysoev.ru } 4350Sigor@sysoev.ru 4360Sigor@sysoev.ru 4370Sigor@sysoev.ru static ssize_t 438*1Sigor@sysoev.ru nxt_openssl_conn_io_write_chunk(nxt_event_conn_t *c, nxt_buf_t *b, size_t limit) 4390Sigor@sysoev.ru { 4400Sigor@sysoev.ru nxt_openssl_conn_t *ssltls; 4410Sigor@sysoev.ru 442*1Sigor@sysoev.ru nxt_debug(c->socket.task, "openssl conn write chunk"); 4430Sigor@sysoev.ru 4440Sigor@sysoev.ru ssltls = c->u.ssltls; 4450Sigor@sysoev.ru 4460Sigor@sysoev.ru return nxt_sendbuf_copy_coalesce(c, &ssltls->buffer, b, limit); 4470Sigor@sysoev.ru } 4480Sigor@sysoev.ru 4490Sigor@sysoev.ru 4500Sigor@sysoev.ru static ssize_t 4510Sigor@sysoev.ru nxt_openssl_conn_io_send(nxt_event_conn_t *c, void *buf, size_t size) 4520Sigor@sysoev.ru { 4530Sigor@sysoev.ru int ret; 4540Sigor@sysoev.ru nxt_err_t err; 4550Sigor@sysoev.ru nxt_int_t n; 4560Sigor@sysoev.ru nxt_openssl_conn_t *ssltls; 4570Sigor@sysoev.ru 4580Sigor@sysoev.ru ssltls = c->u.ssltls; 4590Sigor@sysoev.ru 4600Sigor@sysoev.ru ret = SSL_write(ssltls->session, buf, size); 4610Sigor@sysoev.ru 4620Sigor@sysoev.ru if (ret <= 0) { 4630Sigor@sysoev.ru err = nxt_socket_errno; 4640Sigor@sysoev.ru c->socket.error = err; 4650Sigor@sysoev.ru 4660Sigor@sysoev.ru } else { 4670Sigor@sysoev.ru err = 0; 4680Sigor@sysoev.ru } 4690Sigor@sysoev.ru 4700Sigor@sysoev.ru nxt_log_debug(c->socket.log, "SSL_write(%d, %p, %uz): %d err:%d", 4710Sigor@sysoev.ru c->socket.fd, buf, size, ret, err); 4720Sigor@sysoev.ru 4730Sigor@sysoev.ru if (ret > 0) { 4740Sigor@sysoev.ru return ret; 4750Sigor@sysoev.ru } 4760Sigor@sysoev.ru 477*1Sigor@sysoev.ru n = nxt_openssl_conn_test_error(c->socket.task, c, ret, err, 4780Sigor@sysoev.ru nxt_event_conn_io_write); 4790Sigor@sysoev.ru 4800Sigor@sysoev.ru if (n == NXT_ERROR) { 4810Sigor@sysoev.ru nxt_openssl_conn_error(c, err, "SSL_write(%d, %p, %uz) failed", 4820Sigor@sysoev.ru c->socket.fd, buf, size); 4830Sigor@sysoev.ru } 4840Sigor@sysoev.ru 4850Sigor@sysoev.ru return n; 4860Sigor@sysoev.ru } 4870Sigor@sysoev.ru 4880Sigor@sysoev.ru 4890Sigor@sysoev.ru static void 490*1Sigor@sysoev.ru nxt_openssl_conn_io_shutdown(nxt_task_t *task, void *obj, void *data) 4910Sigor@sysoev.ru { 4920Sigor@sysoev.ru int ret, mode; 4930Sigor@sysoev.ru SSL *s; 4940Sigor@sysoev.ru nxt_err_t err; 4950Sigor@sysoev.ru nxt_int_t n; 4960Sigor@sysoev.ru nxt_bool_t quiet, once; 4970Sigor@sysoev.ru nxt_event_conn_t *c; 4980Sigor@sysoev.ru nxt_work_handler_t handler; 4990Sigor@sysoev.ru nxt_openssl_conn_t *ssltls; 5000Sigor@sysoev.ru 5010Sigor@sysoev.ru c = obj; 5020Sigor@sysoev.ru 503*1Sigor@sysoev.ru nxt_debug(task, "openssl conn shutdown"); 5040Sigor@sysoev.ru 5050Sigor@sysoev.ru ssltls = c->u.ssltls; 5060Sigor@sysoev.ru s = ssltls->session; 5070Sigor@sysoev.ru 5080Sigor@sysoev.ru if (s == NULL) { 5090Sigor@sysoev.ru handler = c->write_state->close_handler; 5100Sigor@sysoev.ru goto done; 5110Sigor@sysoev.ru } 5120Sigor@sysoev.ru 5130Sigor@sysoev.ru mode = SSL_get_shutdown(s); 5140Sigor@sysoev.ru 5150Sigor@sysoev.ru if (c->socket.timedout || c->socket.error != 0) { 5160Sigor@sysoev.ru quiet = 1; 5170Sigor@sysoev.ru 5180Sigor@sysoev.ru } else if (c->socket.closed && !(mode & SSL_RECEIVED_SHUTDOWN)) { 5190Sigor@sysoev.ru quiet = 1; 5200Sigor@sysoev.ru 5210Sigor@sysoev.ru } else { 5220Sigor@sysoev.ru quiet = 0; 5230Sigor@sysoev.ru } 5240Sigor@sysoev.ru 5250Sigor@sysoev.ru SSL_set_quiet_shutdown(s, quiet); 5260Sigor@sysoev.ru 5270Sigor@sysoev.ru once = 1; 5280Sigor@sysoev.ru 5290Sigor@sysoev.ru for ( ;; ) { 5300Sigor@sysoev.ru SSL_set_shutdown(s, mode); 5310Sigor@sysoev.ru 5320Sigor@sysoev.ru ret = SSL_shutdown(s); 5330Sigor@sysoev.ru 5340Sigor@sysoev.ru err = (ret <= 0) ? nxt_socket_errno : 0; 5350Sigor@sysoev.ru 536*1Sigor@sysoev.ru nxt_debug(task, "SSL_shutdown(%d, %d, %b): %d err:%d", 537*1Sigor@sysoev.ru c->socket.fd, mode, quiet, ret, err); 5380Sigor@sysoev.ru 5390Sigor@sysoev.ru if (ret > 0) { 5400Sigor@sysoev.ru /* ret == 1, the shutdown was successfully completed. */ 5410Sigor@sysoev.ru handler = c->write_state->close_handler; 5420Sigor@sysoev.ru goto done; 5430Sigor@sysoev.ru } 5440Sigor@sysoev.ru 5450Sigor@sysoev.ru if (ret == 0) { 5460Sigor@sysoev.ru /* 5470Sigor@sysoev.ru * If SSL_shutdown() returns 0 then it should be called 5480Sigor@sysoev.ru * again. The second SSL_shutdown() call should returns 5490Sigor@sysoev.ru * -1/SSL_ERROR_WANT_READ or -1/SSL_ERROR_WANT_WRITE. 5500Sigor@sysoev.ru * OpenSSL prior to 0.9.8m version however never returns 5510Sigor@sysoev.ru * -1 at all. Fortunately, OpenSSL internals preserve 5520Sigor@sysoev.ru * correct status available via SSL_get_error(-1). 5530Sigor@sysoev.ru */ 5540Sigor@sysoev.ru if (once) { 5550Sigor@sysoev.ru mode = SSL_get_shutdown(s); 5560Sigor@sysoev.ru once = 0; 5570Sigor@sysoev.ru continue; 5580Sigor@sysoev.ru } 5590Sigor@sysoev.ru 5600Sigor@sysoev.ru ret = -1; 5610Sigor@sysoev.ru } 5620Sigor@sysoev.ru 5630Sigor@sysoev.ru /* ret == -1 */ 5640Sigor@sysoev.ru 5650Sigor@sysoev.ru break; 5660Sigor@sysoev.ru } 5670Sigor@sysoev.ru 568*1Sigor@sysoev.ru n = nxt_openssl_conn_test_error(task, c, ret, err, 5690Sigor@sysoev.ru nxt_openssl_conn_io_shutdown); 5700Sigor@sysoev.ru 5710Sigor@sysoev.ru if (nxt_fast_path(n == 0)) { 5720Sigor@sysoev.ru return; 5730Sigor@sysoev.ru } 5740Sigor@sysoev.ru 5750Sigor@sysoev.ru if (n != NXT_ERROR) { /* n == NXT_AGAIN */ 5760Sigor@sysoev.ru c->socket.error_handler = c->read_state->error_handler; 577*1Sigor@sysoev.ru nxt_event_timer_add(task->thread->engine, &c->read_timer, 5000); 5780Sigor@sysoev.ru return; 5790Sigor@sysoev.ru } 5800Sigor@sysoev.ru 5810Sigor@sysoev.ru nxt_openssl_conn_error(c, err, "SSL_shutdown(%d) failed", c->socket.fd); 5820Sigor@sysoev.ru 5830Sigor@sysoev.ru handler = c->write_state->error_handler; 5840Sigor@sysoev.ru 5850Sigor@sysoev.ru done: 5860Sigor@sysoev.ru 587*1Sigor@sysoev.ru nxt_event_conn_io_handle(task->thread, c->write_work_queue, handler, 588*1Sigor@sysoev.ru task, c, data); 5890Sigor@sysoev.ru } 5900Sigor@sysoev.ru 5910Sigor@sysoev.ru 5920Sigor@sysoev.ru static nxt_int_t 593*1Sigor@sysoev.ru nxt_openssl_conn_test_error(nxt_task_t *task, nxt_event_conn_t *c, int ret, 5940Sigor@sysoev.ru nxt_err_t sys_err, nxt_work_handler_t handler) 5950Sigor@sysoev.ru { 5960Sigor@sysoev.ru u_long lib_err; 5970Sigor@sysoev.ru nxt_work_queue_t *wq; 5980Sigor@sysoev.ru nxt_openssl_conn_t *ssltls; 5990Sigor@sysoev.ru 6000Sigor@sysoev.ru ssltls = c->u.ssltls; 6010Sigor@sysoev.ru 6020Sigor@sysoev.ru ssltls->ssl_error = SSL_get_error(ssltls->session, ret); 6030Sigor@sysoev.ru 6040Sigor@sysoev.ru nxt_log_debug(c->socket.log, "SSL_get_error(): %d", ssltls->ssl_error); 6050Sigor@sysoev.ru 6060Sigor@sysoev.ru switch (ssltls->ssl_error) { 6070Sigor@sysoev.ru 6080Sigor@sysoev.ru case SSL_ERROR_WANT_READ: 609*1Sigor@sysoev.ru nxt_event_fd_block_write(task->thread->engine, &c->socket); 6100Sigor@sysoev.ru 6110Sigor@sysoev.ru c->socket.read_ready = 0; 6120Sigor@sysoev.ru c->socket.read_handler = handler; 6130Sigor@sysoev.ru 6140Sigor@sysoev.ru if (nxt_event_fd_is_disabled(c->socket.read)) { 615*1Sigor@sysoev.ru nxt_event_fd_enable_read(task->thread->engine, &c->socket); 6160Sigor@sysoev.ru } 6170Sigor@sysoev.ru 6180Sigor@sysoev.ru return NXT_AGAIN; 6190Sigor@sysoev.ru 6200Sigor@sysoev.ru case SSL_ERROR_WANT_WRITE: 621*1Sigor@sysoev.ru nxt_event_fd_block_read(task->thread->engine, &c->socket); 6220Sigor@sysoev.ru 6230Sigor@sysoev.ru c->socket.write_ready = 0; 6240Sigor@sysoev.ru c->socket.write_handler = handler; 6250Sigor@sysoev.ru 6260Sigor@sysoev.ru if (nxt_event_fd_is_disabled(c->socket.write)) { 627*1Sigor@sysoev.ru nxt_event_fd_enable_write(task->thread->engine, &c->socket); 6280Sigor@sysoev.ru } 6290Sigor@sysoev.ru 6300Sigor@sysoev.ru return NXT_AGAIN; 6310Sigor@sysoev.ru 6320Sigor@sysoev.ru case SSL_ERROR_SYSCALL: 6330Sigor@sysoev.ru 6340Sigor@sysoev.ru lib_err = ERR_peek_error(); 6350Sigor@sysoev.ru 636*1Sigor@sysoev.ru nxt_debug(task, "ERR_peek_error(): %l", lib_err); 6370Sigor@sysoev.ru 6380Sigor@sysoev.ru if (sys_err != 0 || lib_err != 0) { 6390Sigor@sysoev.ru return NXT_ERROR; 6400Sigor@sysoev.ru } 6410Sigor@sysoev.ru 6420Sigor@sysoev.ru /* A connection was just closed. */ 6430Sigor@sysoev.ru c->socket.closed = 1; 6440Sigor@sysoev.ru 6450Sigor@sysoev.ru /* Fall through. */ 6460Sigor@sysoev.ru 6470Sigor@sysoev.ru case SSL_ERROR_ZERO_RETURN: 6480Sigor@sysoev.ru /* A "close notify" alert. */ 6490Sigor@sysoev.ru 6500Sigor@sysoev.ru if (c->read_state != NULL) { 6510Sigor@sysoev.ru wq = c->read_work_queue; 6520Sigor@sysoev.ru handler = c->read_state->close_handler; 6530Sigor@sysoev.ru 6540Sigor@sysoev.ru } else { 6550Sigor@sysoev.ru wq = c->write_work_queue; 6560Sigor@sysoev.ru handler = c->write_state->close_handler; 6570Sigor@sysoev.ru } 6580Sigor@sysoev.ru 659*1Sigor@sysoev.ru nxt_event_conn_io_handle(task->thread, wq, handler, 660*1Sigor@sysoev.ru task, c, c->socket.data); 6610Sigor@sysoev.ru 6620Sigor@sysoev.ru return 0; 6630Sigor@sysoev.ru 6640Sigor@sysoev.ru default: /* SSL_ERROR_SSL, etc. */ 6650Sigor@sysoev.ru c->socket.error = 1000; /* Nonexistent errno code. */ 6660Sigor@sysoev.ru return NXT_ERROR; 6670Sigor@sysoev.ru } 6680Sigor@sysoev.ru } 6690Sigor@sysoev.ru 6700Sigor@sysoev.ru 6710Sigor@sysoev.ru static void nxt_cdecl 6720Sigor@sysoev.ru nxt_openssl_conn_error(nxt_event_conn_t *c, nxt_err_t err, const char *fmt, ...) 6730Sigor@sysoev.ru { 6740Sigor@sysoev.ru u_char *p, *end; 6750Sigor@sysoev.ru va_list args; 6760Sigor@sysoev.ru nxt_uint_t level; 6770Sigor@sysoev.ru u_char msg[NXT_MAX_ERROR_STR]; 6780Sigor@sysoev.ru 6790Sigor@sysoev.ru c->socket.error = err; 6800Sigor@sysoev.ru level = nxt_openssl_log_error_level(c, err); 6810Sigor@sysoev.ru 6820Sigor@sysoev.ru if (nxt_log_level_enough(c->socket.log, level)) { 6830Sigor@sysoev.ru 6840Sigor@sysoev.ru end = msg + sizeof(msg); 6850Sigor@sysoev.ru 6860Sigor@sysoev.ru va_start(args, fmt); 6870Sigor@sysoev.ru p = nxt_vsprintf(msg, end, fmt, args); 6880Sigor@sysoev.ru va_end(args); 6890Sigor@sysoev.ru 6900Sigor@sysoev.ru if (err != 0) { 6910Sigor@sysoev.ru p = nxt_sprintf(p, end, " %E", err); 6920Sigor@sysoev.ru } 6930Sigor@sysoev.ru 6940Sigor@sysoev.ru p = nxt_openssl_copy_error(p, end); 6950Sigor@sysoev.ru 6960Sigor@sysoev.ru nxt_log_error(level, c->socket.log, "%*s", p - msg, msg); 6970Sigor@sysoev.ru 6980Sigor@sysoev.ru } else { 6990Sigor@sysoev.ru ERR_clear_error(); 7000Sigor@sysoev.ru } 7010Sigor@sysoev.ru } 7020Sigor@sysoev.ru 7030Sigor@sysoev.ru 7040Sigor@sysoev.ru static nxt_uint_t 7050Sigor@sysoev.ru nxt_openssl_log_error_level(nxt_event_conn_t *c, nxt_err_t err) 7060Sigor@sysoev.ru { 7070Sigor@sysoev.ru switch (ERR_GET_REASON(ERR_peek_error())) { 7080Sigor@sysoev.ru 7090Sigor@sysoev.ru case 0: 7100Sigor@sysoev.ru return nxt_socket_error_level(err, c->socket.log_error); 7110Sigor@sysoev.ru 7120Sigor@sysoev.ru case SSL_R_BAD_CHANGE_CIPHER_SPEC: /* 103 */ 7130Sigor@sysoev.ru case SSL_R_BLOCK_CIPHER_PAD_IS_WRONG: /* 129 */ 7140Sigor@sysoev.ru case SSL_R_DIGEST_CHECK_FAILED: /* 149 */ 7150Sigor@sysoev.ru case SSL_R_ERROR_IN_RECEIVED_CIPHER_LIST: /* 151 */ 7160Sigor@sysoev.ru case SSL_R_EXCESSIVE_MESSAGE_SIZE: /* 152 */ 7170Sigor@sysoev.ru case SSL_R_LENGTH_MISMATCH: /* 159 */ 7180Sigor@sysoev.ru case SSL_R_NO_CIPHERS_PASSED: /* 182 */ 7190Sigor@sysoev.ru case SSL_R_NO_CIPHERS_SPECIFIED: /* 183 */ 7200Sigor@sysoev.ru case SSL_R_NO_COMPRESSION_SPECIFIED: /* 187 */ 7210Sigor@sysoev.ru case SSL_R_NO_SHARED_CIPHER: /* 193 */ 7220Sigor@sysoev.ru case SSL_R_RECORD_LENGTH_MISMATCH: /* 213 */ 7230Sigor@sysoev.ru #ifdef SSL_R_PARSE_TLSEXT 7240Sigor@sysoev.ru case SSL_R_PARSE_TLSEXT: /* 227 */ 7250Sigor@sysoev.ru #endif 7260Sigor@sysoev.ru case SSL_R_UNEXPECTED_MESSAGE: /* 244 */ 7270Sigor@sysoev.ru case SSL_R_UNEXPECTED_RECORD: /* 245 */ 7280Sigor@sysoev.ru case SSL_R_UNKNOWN_ALERT_TYPE: /* 246 */ 7290Sigor@sysoev.ru case SSL_R_UNKNOWN_PROTOCOL: /* 252 */ 7300Sigor@sysoev.ru case SSL_R_WRONG_VERSION_NUMBER: /* 267 */ 7310Sigor@sysoev.ru case SSL_R_DECRYPTION_FAILED_OR_BAD_RECORD_MAC: /* 281 */ 7320Sigor@sysoev.ru #ifdef SSL_R_RENEGOTIATE_EXT_TOO_LONG 7330Sigor@sysoev.ru case SSL_R_RENEGOTIATE_EXT_TOO_LONG: /* 335 */ 7340Sigor@sysoev.ru case SSL_R_RENEGOTIATION_ENCODING_ERR: /* 336 */ 7350Sigor@sysoev.ru case SSL_R_RENEGOTIATION_MISMATCH: /* 337 */ 7360Sigor@sysoev.ru #endif 7370Sigor@sysoev.ru #ifdef SSL_R_UNSAFE_LEGACY_RENEGOTIATION_DISABLED 7380Sigor@sysoev.ru case SSL_R_UNSAFE_LEGACY_RENEGOTIATION_DISABLED: /* 338 */ 7390Sigor@sysoev.ru #endif 7400Sigor@sysoev.ru #ifdef SSL_R_SCSV_RECEIVED_WHEN_RENEGOTIATING 7410Sigor@sysoev.ru case SSL_R_SCSV_RECEIVED_WHEN_RENEGOTIATING: /* 345 */ 7420Sigor@sysoev.ru #endif 7430Sigor@sysoev.ru case 1000:/* SSL_R_SSLV3_ALERT_CLOSE_NOTIFY */ 7440Sigor@sysoev.ru case SSL_R_SSLV3_ALERT_UNEXPECTED_MESSAGE: /* 1010 */ 7450Sigor@sysoev.ru case SSL_R_SSLV3_ALERT_BAD_RECORD_MAC: /* 1020 */ 7460Sigor@sysoev.ru case SSL_R_TLSV1_ALERT_DECRYPTION_FAILED: /* 1021 */ 7470Sigor@sysoev.ru case SSL_R_TLSV1_ALERT_RECORD_OVERFLOW: /* 1022 */ 7480Sigor@sysoev.ru case SSL_R_SSLV3_ALERT_DECOMPRESSION_FAILURE: /* 1030 */ 7490Sigor@sysoev.ru case SSL_R_SSLV3_ALERT_HANDSHAKE_FAILURE: /* 1040 */ 7500Sigor@sysoev.ru case SSL_R_SSLV3_ALERT_ILLEGAL_PARAMETER: /* 1047 */ 7510Sigor@sysoev.ru break; 7520Sigor@sysoev.ru 7530Sigor@sysoev.ru case SSL_R_SSLV3_ALERT_NO_CERTIFICATE: /* 1041 */ 7540Sigor@sysoev.ru case SSL_R_SSLV3_ALERT_BAD_CERTIFICATE: /* 1042 */ 7550Sigor@sysoev.ru case SSL_R_SSLV3_ALERT_UNSUPPORTED_CERTIFICATE: /* 1043 */ 7560Sigor@sysoev.ru case SSL_R_SSLV3_ALERT_CERTIFICATE_REVOKED: /* 1044 */ 7570Sigor@sysoev.ru case SSL_R_SSLV3_ALERT_CERTIFICATE_EXPIRED: /* 1045 */ 7580Sigor@sysoev.ru case SSL_R_SSLV3_ALERT_CERTIFICATE_UNKNOWN: /* 1046 */ 7590Sigor@sysoev.ru case SSL_R_TLSV1_ALERT_UNKNOWN_CA: /* 1048 */ 7600Sigor@sysoev.ru case SSL_R_TLSV1_ALERT_ACCESS_DENIED: /* 1049 */ 7610Sigor@sysoev.ru case SSL_R_TLSV1_ALERT_DECODE_ERROR: /* 1050 */ 7620Sigor@sysoev.ru case SSL_R_TLSV1_ALERT_DECRYPT_ERROR: /* 1051 */ 7630Sigor@sysoev.ru case SSL_R_TLSV1_ALERT_EXPORT_RESTRICTION: /* 1060 */ 7640Sigor@sysoev.ru case SSL_R_TLSV1_ALERT_PROTOCOL_VERSION: /* 1070 */ 7650Sigor@sysoev.ru case SSL_R_TLSV1_ALERT_INSUFFICIENT_SECURITY: /* 1071 */ 7660Sigor@sysoev.ru case SSL_R_TLSV1_ALERT_INTERNAL_ERROR: /* 1080 */ 7670Sigor@sysoev.ru case SSL_R_TLSV1_ALERT_USER_CANCELLED: /* 1090 */ 7680Sigor@sysoev.ru case SSL_R_TLSV1_ALERT_NO_RENEGOTIATION: /* 1100 */ 7690Sigor@sysoev.ru return NXT_LOG_ERR; 7700Sigor@sysoev.ru 7710Sigor@sysoev.ru default: 7720Sigor@sysoev.ru return NXT_LOG_CRIT; 7730Sigor@sysoev.ru } 7740Sigor@sysoev.ru 7750Sigor@sysoev.ru return NXT_LOG_INFO; 7760Sigor@sysoev.ru } 7770Sigor@sysoev.ru 7780Sigor@sysoev.ru 7790Sigor@sysoev.ru static void nxt_cdecl 7800Sigor@sysoev.ru nxt_openssl_log_error(nxt_uint_t level, nxt_log_t *log, const char *fmt, ...) 7810Sigor@sysoev.ru { 7820Sigor@sysoev.ru u_char *p, *end; 7830Sigor@sysoev.ru va_list args; 7840Sigor@sysoev.ru u_char msg[NXT_MAX_ERROR_STR]; 7850Sigor@sysoev.ru 7860Sigor@sysoev.ru end = msg + sizeof(msg); 7870Sigor@sysoev.ru 7880Sigor@sysoev.ru va_start(args, fmt); 7890Sigor@sysoev.ru p = nxt_vsprintf(msg, end, fmt, args); 7900Sigor@sysoev.ru va_end(args); 7910Sigor@sysoev.ru 7920Sigor@sysoev.ru p = nxt_openssl_copy_error(p, end); 7930Sigor@sysoev.ru 7940Sigor@sysoev.ru nxt_log_error(level, log, "%*s", p - msg, msg); 7950Sigor@sysoev.ru } 7960Sigor@sysoev.ru 7970Sigor@sysoev.ru 7980Sigor@sysoev.ru static u_char * 7990Sigor@sysoev.ru nxt_openssl_copy_error(u_char *p, u_char *end) 8000Sigor@sysoev.ru { 8010Sigor@sysoev.ru int flags; 8020Sigor@sysoev.ru u_long err; 8030Sigor@sysoev.ru nxt_bool_t clear; 8040Sigor@sysoev.ru const char *data, *delimiter; 8050Sigor@sysoev.ru 8060Sigor@sysoev.ru err = ERR_peek_error(); 8070Sigor@sysoev.ru if (err == 0) { 8080Sigor@sysoev.ru return p; 8090Sigor@sysoev.ru } 8100Sigor@sysoev.ru 8110Sigor@sysoev.ru /* Log the most relevant error message ... */ 8120Sigor@sysoev.ru data = ERR_reason_error_string(err); 8130Sigor@sysoev.ru 8140Sigor@sysoev.ru p = nxt_sprintf(p, end, " (%d: %s) (OpenSSL: ", ERR_GET_REASON(err), data); 8150Sigor@sysoev.ru 8160Sigor@sysoev.ru /* 8170Sigor@sysoev.ru * ... followed by all queued cumbersome OpenSSL 8180Sigor@sysoev.ru * error messages and drain the error queue. 8190Sigor@sysoev.ru */ 8200Sigor@sysoev.ru delimiter = ""; 8210Sigor@sysoev.ru clear = 0; 8220Sigor@sysoev.ru 8230Sigor@sysoev.ru for ( ;; ) { 8240Sigor@sysoev.ru err = ERR_get_error_line_data(NULL, NULL, &data, &flags); 8250Sigor@sysoev.ru if (err == 0) { 8260Sigor@sysoev.ru break; 8270Sigor@sysoev.ru } 8280Sigor@sysoev.ru 8290Sigor@sysoev.ru p = nxt_sprintf(p, end, "%s", delimiter); 8300Sigor@sysoev.ru 8310Sigor@sysoev.ru ERR_error_string_n(err, (char *) p, end - p); 8320Sigor@sysoev.ru 8330Sigor@sysoev.ru while (p < end && *p != '\0') { 8340Sigor@sysoev.ru p++; 8350Sigor@sysoev.ru } 8360Sigor@sysoev.ru 8370Sigor@sysoev.ru if ((flags & ERR_TXT_STRING) != 0) { 8380Sigor@sysoev.ru p = nxt_sprintf(p, end, ":%s", data); 8390Sigor@sysoev.ru } 8400Sigor@sysoev.ru 8410Sigor@sysoev.ru clear |= ((flags & ERR_TXT_MALLOCED) != 0); 8420Sigor@sysoev.ru 8430Sigor@sysoev.ru delimiter = "; "; 8440Sigor@sysoev.ru } 8450Sigor@sysoev.ru 8460Sigor@sysoev.ru /* Deallocate additional data. */ 8470Sigor@sysoev.ru 8480Sigor@sysoev.ru if (clear) { 8490Sigor@sysoev.ru ERR_clear_error(); 8500Sigor@sysoev.ru } 8510Sigor@sysoev.ru 8520Sigor@sysoev.ru if (p < end) { 8530Sigor@sysoev.ru *p++ = ')'; 8540Sigor@sysoev.ru } 8550Sigor@sysoev.ru 8560Sigor@sysoev.ru return p; 8570Sigor@sysoev.ru } 858