10Sigor@sysoev.ru 20Sigor@sysoev.ru /* 30Sigor@sysoev.ru * Copyright (C) NGINX, Inc. 40Sigor@sysoev.ru * Copyright (C) Igor Sysoev 50Sigor@sysoev.ru */ 60Sigor@sysoev.ru 70Sigor@sysoev.ru #include <nxt_main.h> 80Sigor@sysoev.ru #include <cyassl/ssl.h> 90Sigor@sysoev.ru #include <cyassl/error-ssl.h> 100Sigor@sysoev.ru 110Sigor@sysoev.ru 120Sigor@sysoev.ru typedef struct { 130Sigor@sysoev.ru CYASSL *session; 140Sigor@sysoev.ru 150Sigor@sysoev.ru int ssl_error; 160Sigor@sysoev.ru uint8_t times; /* 2 bits */ 170Sigor@sysoev.ru 180Sigor@sysoev.ru nxt_buf_mem_t buffer; 190Sigor@sysoev.ru } nxt_cyassl_conn_t; 200Sigor@sysoev.ru 210Sigor@sysoev.ru 220Sigor@sysoev.ru static nxt_int_t nxt_cyassl_server_init(nxt_ssltls_conf_t *conf); 230Sigor@sysoev.ru static void nxt_cyassl_conn_init(nxt_thread_t *thr, nxt_ssltls_conf_t *conf, 240Sigor@sysoev.ru nxt_event_conn_t *c); 250Sigor@sysoev.ru static void nxt_cyassl_session_cleanup(void *data); 260Sigor@sysoev.ru static int nxt_cyassl_io_recv(CYASSL *ssl, char *buf, int size, void *data); 270Sigor@sysoev.ru static int nxt_cyassl_io_send(CYASSL *ssl, char *buf, int size, void *data); 280Sigor@sysoev.ru static void nxt_cyassl_conn_handshake(nxt_thread_t *thr, void *obj, void *data); 290Sigor@sysoev.ru static void nxt_cyassl_conn_io_read(nxt_thread_t *thr, void *obj, void *data); 300Sigor@sysoev.ru static void nxt_cyassl_conn_io_shutdown(nxt_thread_t *thr, void *obj, 310Sigor@sysoev.ru void *data); 320Sigor@sysoev.ru static ssize_t nxt_cyassl_conn_io_write_chunk(nxt_thread_t *thr, 330Sigor@sysoev.ru nxt_event_conn_t *c, nxt_buf_t *b, size_t limit); 340Sigor@sysoev.ru static ssize_t nxt_cyassl_conn_io_send(nxt_event_conn_t *c, void *buf, 350Sigor@sysoev.ru size_t size); 360Sigor@sysoev.ru static nxt_int_t nxt_cyassl_conn_test_error(nxt_thread_t *thr, 370Sigor@sysoev.ru nxt_event_conn_t *c, int err, nxt_work_handler_t handler); 380Sigor@sysoev.ru static void nxt_cdecl nxt_cyassl_conn_error(nxt_event_conn_t *c, nxt_err_t err, 390Sigor@sysoev.ru const char *fmt, ...); 400Sigor@sysoev.ru static nxt_uint_t nxt_cyassl_log_error_level(nxt_event_conn_t *c, nxt_err_t err, 410Sigor@sysoev.ru int ssl_error); 420Sigor@sysoev.ru static void nxt_cdecl nxt_cyassl_log_error(nxt_uint_t level, nxt_log_t *log, 430Sigor@sysoev.ru int ret, const char *fmt, ...); 440Sigor@sysoev.ru static u_char *nxt_cyassl_copy_error(int err, u_char *p, u_char *end); 450Sigor@sysoev.ru 460Sigor@sysoev.ru 470Sigor@sysoev.ru const nxt_ssltls_lib_t nxt_cyassl_lib = { 480Sigor@sysoev.ru nxt_cyassl_server_init, 490Sigor@sysoev.ru NULL, 500Sigor@sysoev.ru }; 510Sigor@sysoev.ru 520Sigor@sysoev.ru 530Sigor@sysoev.ru static nxt_event_conn_io_t nxt_cyassl_event_conn_io = { 540Sigor@sysoev.ru NULL, 550Sigor@sysoev.ru NULL, 560Sigor@sysoev.ru 570Sigor@sysoev.ru nxt_cyassl_conn_io_read, 580Sigor@sysoev.ru NULL, 590Sigor@sysoev.ru NULL, 600Sigor@sysoev.ru 610Sigor@sysoev.ru nxt_event_conn_io_write, 620Sigor@sysoev.ru nxt_cyassl_conn_io_write_chunk, 630Sigor@sysoev.ru NULL, 640Sigor@sysoev.ru NULL, 650Sigor@sysoev.ru nxt_cyassl_conn_io_send, 660Sigor@sysoev.ru 670Sigor@sysoev.ru nxt_cyassl_conn_io_shutdown, 680Sigor@sysoev.ru }; 690Sigor@sysoev.ru 700Sigor@sysoev.ru 710Sigor@sysoev.ru static nxt_int_t 720Sigor@sysoev.ru nxt_cyassl_start(void) 730Sigor@sysoev.ru { 740Sigor@sysoev.ru int err; 750Sigor@sysoev.ru nxt_thread_t *thr; 760Sigor@sysoev.ru static nxt_bool_t started; 770Sigor@sysoev.ru 780Sigor@sysoev.ru if (nxt_fast_path(started)) { 790Sigor@sysoev.ru return NXT_OK; 800Sigor@sysoev.ru } 810Sigor@sysoev.ru 820Sigor@sysoev.ru started = 1; 830Sigor@sysoev.ru 840Sigor@sysoev.ru thr = nxt_thread(); 850Sigor@sysoev.ru 860Sigor@sysoev.ru /* TODO: CyaSSL_Cleanup() */ 870Sigor@sysoev.ru 880Sigor@sysoev.ru err = CyaSSL_Init(); 890Sigor@sysoev.ru if (err != SSL_SUCCESS) { 90*564Svbart@nginx.com nxt_cyassl_log_error(NXT_LOG_ALERT, thr->log, err, 910Sigor@sysoev.ru "CyaSSL_Init() failed"); 920Sigor@sysoev.ru return NXT_ERROR; 930Sigor@sysoev.ru } 940Sigor@sysoev.ru 950Sigor@sysoev.ru nxt_thread_log_error(NXT_LOG_INFO, "CyaSSL version: %s", 960Sigor@sysoev.ru LIBCYASSL_VERSION_STRING); 970Sigor@sysoev.ru 980Sigor@sysoev.ru /* CyaSSL_SetLoggingCb */ 990Sigor@sysoev.ru /* CyaSSL_SetAllocators */ 1000Sigor@sysoev.ru 1010Sigor@sysoev.ru return NXT_OK; 1020Sigor@sysoev.ru } 1030Sigor@sysoev.ru 1040Sigor@sysoev.ru 1050Sigor@sysoev.ru static nxt_int_t 1060Sigor@sysoev.ru nxt_cyassl_server_init(nxt_ssltls_conf_t *conf) 1070Sigor@sysoev.ru { 1080Sigor@sysoev.ru int err; 1090Sigor@sysoev.ru char *certificate, *key; 1100Sigor@sysoev.ru CYASSL_CTX *ctx; 1110Sigor@sysoev.ru nxt_thread_t *thr; 1120Sigor@sysoev.ru 1130Sigor@sysoev.ru thr = nxt_thread(); 1140Sigor@sysoev.ru 1150Sigor@sysoev.ru if (nxt_slow_path(nxt_cyassl_start() != NXT_OK)) { 1160Sigor@sysoev.ru return NXT_ERROR; 1170Sigor@sysoev.ru } 1180Sigor@sysoev.ru 1190Sigor@sysoev.ru ctx = CyaSSL_CTX_new(CyaSSLv23_server_method()); 1200Sigor@sysoev.ru if (ctx == NULL) { 121*564Svbart@nginx.com nxt_cyassl_log_error(NXT_LOG_ALERT, thr->log, 0, 1220Sigor@sysoev.ru "CyaSSL_CTX_new() failed"); 1230Sigor@sysoev.ru return NXT_ERROR; 1240Sigor@sysoev.ru } 1250Sigor@sysoev.ru 1260Sigor@sysoev.ru conf->ctx = ctx; 1270Sigor@sysoev.ru conf->conn_init = nxt_cyassl_conn_init; 1280Sigor@sysoev.ru 1290Sigor@sysoev.ru certificate = conf->certificate; 1300Sigor@sysoev.ru 1310Sigor@sysoev.ru err = CyaSSL_CTX_use_certificate_file(ctx, certificate, SSL_FILETYPE_PEM); 1320Sigor@sysoev.ru if (err != SSL_SUCCESS) { 133*564Svbart@nginx.com nxt_cyassl_log_error(NXT_LOG_ALERT, thr->log, err, 1340Sigor@sysoev.ru "CyaSSL_CTX_use_certificate_file(\"%s\") failed", 1350Sigor@sysoev.ru certificate); 1360Sigor@sysoev.ru goto fail; 1370Sigor@sysoev.ru } 1380Sigor@sysoev.ru 1390Sigor@sysoev.ru key = conf->certificate_key; 1400Sigor@sysoev.ru 1410Sigor@sysoev.ru err = CyaSSL_CTX_use_PrivateKey_file(ctx, key, SSL_FILETYPE_PEM); 1420Sigor@sysoev.ru if (err != SSL_SUCCESS) { 143*564Svbart@nginx.com nxt_cyassl_log_error(NXT_LOG_ALERT, thr->log, err, 1440Sigor@sysoev.ru "CyaSSL_CTX_use_PrivateKey_file(\"%s\") failed", 1450Sigor@sysoev.ru key); 1460Sigor@sysoev.ru goto fail; 1470Sigor@sysoev.ru } 1480Sigor@sysoev.ru 1490Sigor@sysoev.ru if (conf->ciphers != NULL) { 1500Sigor@sysoev.ru err = CyaSSL_CTX_set_cipher_list(ctx, conf->ciphers); 1510Sigor@sysoev.ru if (err != SSL_SUCCESS) { 152*564Svbart@nginx.com nxt_cyassl_log_error(NXT_LOG_ALERT, thr->log, err, 1530Sigor@sysoev.ru "CyaSSL_CTX_set_cipher_list(\"%s\") failed", 1540Sigor@sysoev.ru conf->ciphers); 1550Sigor@sysoev.ru goto fail; 1560Sigor@sysoev.ru } 1570Sigor@sysoev.ru } 1580Sigor@sysoev.ru 1590Sigor@sysoev.ru /* TODO: ca_certificate */ 1600Sigor@sysoev.ru 1610Sigor@sysoev.ru CyaSSL_SetIORecv(ctx, nxt_cyassl_io_recv); 1620Sigor@sysoev.ru CyaSSL_SetIOSend(ctx, nxt_cyassl_io_send); 1630Sigor@sysoev.ru 1640Sigor@sysoev.ru return NXT_OK; 1650Sigor@sysoev.ru 1660Sigor@sysoev.ru fail: 1670Sigor@sysoev.ru 1680Sigor@sysoev.ru CyaSSL_CTX_free(ctx); 1690Sigor@sysoev.ru 1700Sigor@sysoev.ru return NXT_ERROR; 1710Sigor@sysoev.ru } 1720Sigor@sysoev.ru 1730Sigor@sysoev.ru 1740Sigor@sysoev.ru static void 1750Sigor@sysoev.ru nxt_cyassl_conn_init(nxt_thread_t *thr, nxt_ssltls_conf_t *conf, 1760Sigor@sysoev.ru nxt_event_conn_t *c) 1770Sigor@sysoev.ru { 1780Sigor@sysoev.ru CYASSL *s; 1790Sigor@sysoev.ru CYASSL_CTX *ctx; 1800Sigor@sysoev.ru nxt_cyassl_conn_t *ssltls; 1810Sigor@sysoev.ru nxt_mem_pool_cleanup_t *mpcl; 1820Sigor@sysoev.ru 1830Sigor@sysoev.ru nxt_log_debug(c->socket.log, "cyassl conn init"); 1840Sigor@sysoev.ru 18565Sigor@sysoev.ru ssltls = nxt_mp_zget(c->mem_pool, sizeof(nxt_cyassl_conn_t)); 1860Sigor@sysoev.ru if (ssltls == NULL) { 1870Sigor@sysoev.ru goto fail; 1880Sigor@sysoev.ru } 1890Sigor@sysoev.ru 1900Sigor@sysoev.ru c->u.ssltls = ssltls; 1910Sigor@sysoev.ru nxt_buf_mem_set_size(&ssltls->buffer, conf->buffer_size); 1920Sigor@sysoev.ru 1930Sigor@sysoev.ru mpcl = nxt_mem_pool_cleanup(c->mem_pool, 0); 1940Sigor@sysoev.ru if (mpcl == NULL) { 1950Sigor@sysoev.ru goto fail; 1960Sigor@sysoev.ru } 1970Sigor@sysoev.ru 1980Sigor@sysoev.ru ctx = conf->ctx; 1990Sigor@sysoev.ru 2000Sigor@sysoev.ru s = CyaSSL_new(ctx); 2010Sigor@sysoev.ru if (s == NULL) { 202*564Svbart@nginx.com nxt_cyassl_log_error(NXT_LOG_ALERT, c->socket.log, 0, 2030Sigor@sysoev.ru "CyaSSL_new() failed"); 2040Sigor@sysoev.ru goto fail; 2050Sigor@sysoev.ru } 2060Sigor@sysoev.ru 2070Sigor@sysoev.ru ssltls->session = s; 2080Sigor@sysoev.ru mpcl->handler = nxt_cyassl_session_cleanup; 2090Sigor@sysoev.ru mpcl->data = ssltls; 2100Sigor@sysoev.ru 2110Sigor@sysoev.ru CyaSSL_SetIOReadCtx(s, c); 2120Sigor@sysoev.ru CyaSSL_SetIOWriteCtx(s, c); 2130Sigor@sysoev.ru 2140Sigor@sysoev.ru c->io = &nxt_cyassl_event_conn_io; 2150Sigor@sysoev.ru c->sendfile = NXT_CONN_SENDFILE_OFF; 2160Sigor@sysoev.ru 2170Sigor@sysoev.ru nxt_cyassl_conn_handshake(thr, c, c->socket.data); 2180Sigor@sysoev.ru return; 2190Sigor@sysoev.ru 2200Sigor@sysoev.ru fail: 2210Sigor@sysoev.ru 2220Sigor@sysoev.ru nxt_event_conn_io_handle(thr, c->read_work_queue, 2230Sigor@sysoev.ru c->read_state->error_handler, c, c->socket.data); 2240Sigor@sysoev.ru } 2250Sigor@sysoev.ru 2260Sigor@sysoev.ru 2270Sigor@sysoev.ru static void 2280Sigor@sysoev.ru nxt_cyassl_session_cleanup(void *data) 2290Sigor@sysoev.ru { 2300Sigor@sysoev.ru nxt_cyassl_conn_t *ssltls; 2310Sigor@sysoev.ru 2320Sigor@sysoev.ru ssltls = data; 2330Sigor@sysoev.ru 2340Sigor@sysoev.ru nxt_thread_log_debug("cyassl session cleanup"); 2350Sigor@sysoev.ru 2360Sigor@sysoev.ru nxt_free(ssltls->buffer.start); 2370Sigor@sysoev.ru 2380Sigor@sysoev.ru CyaSSL_free(ssltls->session); 2390Sigor@sysoev.ru } 2400Sigor@sysoev.ru 2410Sigor@sysoev.ru 2420Sigor@sysoev.ru static int 2430Sigor@sysoev.ru nxt_cyassl_io_recv(CYASSL *ssl, char *buf, int size, void *data) 2440Sigor@sysoev.ru { 2450Sigor@sysoev.ru ssize_t n; 2460Sigor@sysoev.ru nxt_thread_t *thr; 2470Sigor@sysoev.ru nxt_event_conn_t *c; 2480Sigor@sysoev.ru 2490Sigor@sysoev.ru c = data; 2500Sigor@sysoev.ru thr = nxt_thread(); 2510Sigor@sysoev.ru 2520Sigor@sysoev.ru n = thr->engine->event->io->recv(c, (u_char *) buf, size, 0); 2530Sigor@sysoev.ru 2540Sigor@sysoev.ru if (n > 0) { 2550Sigor@sysoev.ru return n; 2560Sigor@sysoev.ru } 2570Sigor@sysoev.ru 2580Sigor@sysoev.ru if (n == 0) { 2590Sigor@sysoev.ru return CYASSL_CBIO_ERR_CONN_CLOSE; 2600Sigor@sysoev.ru } 2610Sigor@sysoev.ru 2620Sigor@sysoev.ru if (n == NXT_AGAIN) { 2630Sigor@sysoev.ru return CYASSL_CBIO_ERR_WANT_READ; 2640Sigor@sysoev.ru } 2650Sigor@sysoev.ru 2660Sigor@sysoev.ru return CYASSL_CBIO_ERR_GENERAL; 2670Sigor@sysoev.ru } 2680Sigor@sysoev.ru 2690Sigor@sysoev.ru 2700Sigor@sysoev.ru static int 2710Sigor@sysoev.ru nxt_cyassl_io_send(CYASSL *ssl, char *buf, int size, void *data) 2720Sigor@sysoev.ru { 2730Sigor@sysoev.ru ssize_t n; 2740Sigor@sysoev.ru nxt_thread_t *thr; 2750Sigor@sysoev.ru nxt_event_conn_t *c; 2760Sigor@sysoev.ru 2770Sigor@sysoev.ru c = data; 2780Sigor@sysoev.ru thr = nxt_thread(); 2790Sigor@sysoev.ru 2800Sigor@sysoev.ru n = thr->engine->event->io->send(c, (u_char *) buf, size); 2810Sigor@sysoev.ru 2820Sigor@sysoev.ru if (n > 0) { 2830Sigor@sysoev.ru return n; 2840Sigor@sysoev.ru } 2850Sigor@sysoev.ru 2860Sigor@sysoev.ru if (n == NXT_AGAIN) { 2870Sigor@sysoev.ru return CYASSL_CBIO_ERR_WANT_WRITE; 2880Sigor@sysoev.ru } 2890Sigor@sysoev.ru 2900Sigor@sysoev.ru return CYASSL_CBIO_ERR_GENERAL; 2910Sigor@sysoev.ru } 2920Sigor@sysoev.ru 2930Sigor@sysoev.ru 2940Sigor@sysoev.ru static void 2950Sigor@sysoev.ru nxt_cyassl_conn_handshake(nxt_thread_t *thr, void *obj, void *data) 2960Sigor@sysoev.ru { 2970Sigor@sysoev.ru int ret; 2980Sigor@sysoev.ru nxt_int_t n; 2990Sigor@sysoev.ru nxt_err_t err; 3000Sigor@sysoev.ru nxt_event_conn_t *c; 3010Sigor@sysoev.ru nxt_cyassl_conn_t *ssltls; 3020Sigor@sysoev.ru 3030Sigor@sysoev.ru c = obj; 3040Sigor@sysoev.ru ssltls = c->u.ssltls; 3050Sigor@sysoev.ru 3060Sigor@sysoev.ru nxt_log_debug(thr->log, "cyassl conn handshake: %d", ssltls->times); 3070Sigor@sysoev.ru 3080Sigor@sysoev.ru /* "ssltls->times == 1" is suitable to run CyaSSL_negotiate() in job. */ 3090Sigor@sysoev.ru 3100Sigor@sysoev.ru ret = CyaSSL_negotiate(ssltls->session); 3110Sigor@sysoev.ru 3120Sigor@sysoev.ru err = (ret != 0) ? nxt_socket_errno : 0; 3130Sigor@sysoev.ru 3140Sigor@sysoev.ru nxt_thread_time_debug_update(thr); 3150Sigor@sysoev.ru 3160Sigor@sysoev.ru nxt_log_debug(thr->log, "CyaSSL_negotiate(%d): %d", c->socket.fd, ret); 3170Sigor@sysoev.ru 3180Sigor@sysoev.ru if (ret == 0) { 3190Sigor@sysoev.ru nxt_cyassl_conn_io_read(thr, c, data); 3200Sigor@sysoev.ru return; 3210Sigor@sysoev.ru } 3220Sigor@sysoev.ru 3230Sigor@sysoev.ru n = nxt_cyassl_conn_test_error(thr, c, ret, nxt_cyassl_conn_handshake); 3240Sigor@sysoev.ru 3250Sigor@sysoev.ru if (n == NXT_ERROR) { 3260Sigor@sysoev.ru nxt_cyassl_conn_error(c, err, "CyaSSL_negotiate(%d) failed", 3270Sigor@sysoev.ru c->socket.fd); 3280Sigor@sysoev.ru 3290Sigor@sysoev.ru nxt_event_conn_io_handle(thr, c->read_work_queue, 3300Sigor@sysoev.ru c->read_state->error_handler, c, data); 3310Sigor@sysoev.ru 3320Sigor@sysoev.ru } else if (ssltls->ssl_error == SSL_ERROR_WANT_READ && ssltls->times < 2) { 3330Sigor@sysoev.ru ssltls->times++; 3340Sigor@sysoev.ru } 3350Sigor@sysoev.ru } 3360Sigor@sysoev.ru 3370Sigor@sysoev.ru 3380Sigor@sysoev.ru static void 3390Sigor@sysoev.ru nxt_cyassl_conn_io_read(nxt_thread_t *thr, void *obj, void *data) 3400Sigor@sysoev.ru { 3410Sigor@sysoev.ru int ret; 3420Sigor@sysoev.ru nxt_buf_t *b; 3430Sigor@sysoev.ru nxt_err_t err; 3440Sigor@sysoev.ru nxt_int_t n; 3450Sigor@sysoev.ru nxt_event_conn_t *c; 3460Sigor@sysoev.ru nxt_cyassl_conn_t *ssltls; 3470Sigor@sysoev.ru nxt_work_handler_t handler; 3480Sigor@sysoev.ru 3490Sigor@sysoev.ru c = obj; 3500Sigor@sysoev.ru 3510Sigor@sysoev.ru nxt_log_debug(thr->log, "cyassl conn read"); 3520Sigor@sysoev.ru 3530Sigor@sysoev.ru handler = c->read_state->ready_handler; 3540Sigor@sysoev.ru b = c->read; 3550Sigor@sysoev.ru 3560Sigor@sysoev.ru /* b == NULL is used to test descriptor readiness. */ 3570Sigor@sysoev.ru 3580Sigor@sysoev.ru if (b != NULL) { 3590Sigor@sysoev.ru ssltls = c->u.ssltls; 3600Sigor@sysoev.ru 3610Sigor@sysoev.ru ret = CyaSSL_read(ssltls->session, b->mem.free, 3620Sigor@sysoev.ru b->mem.end - b->mem.free); 3630Sigor@sysoev.ru 3640Sigor@sysoev.ru err = (ret <= 0) ? nxt_socket_errno : 0; 3650Sigor@sysoev.ru 3660Sigor@sysoev.ru nxt_log_debug(thr->log, "CyaSSL_read(%d, %p, %uz): %d", 3670Sigor@sysoev.ru c->socket.fd, b->mem.free, b->mem.end - b->mem.free, ret); 3680Sigor@sysoev.ru 3690Sigor@sysoev.ru if (ret > 0) { 3700Sigor@sysoev.ru /* c->socket.read_ready is kept. */ 3710Sigor@sysoev.ru b->mem.free += ret; 3720Sigor@sysoev.ru handler = c->read_state->ready_handler; 3730Sigor@sysoev.ru 3740Sigor@sysoev.ru } else { 3750Sigor@sysoev.ru n = nxt_cyassl_conn_test_error(thr, c, ret, 3760Sigor@sysoev.ru nxt_cyassl_conn_io_read); 3770Sigor@sysoev.ru 3780Sigor@sysoev.ru if (nxt_fast_path(n != NXT_ERROR)) { 3790Sigor@sysoev.ru return; 3800Sigor@sysoev.ru } 3810Sigor@sysoev.ru 3820Sigor@sysoev.ru nxt_cyassl_conn_error(c, err, "CyaSSL_read(%d, %p, %uz) failed", 3830Sigor@sysoev.ru c->socket.fd, b->mem.free, 3840Sigor@sysoev.ru b->mem.end - b->mem.free); 3850Sigor@sysoev.ru 3860Sigor@sysoev.ru handler = c->read_state->error_handler; 3870Sigor@sysoev.ru } 3880Sigor@sysoev.ru } 3890Sigor@sysoev.ru 3900Sigor@sysoev.ru nxt_event_conn_io_handle(thr, c->read_work_queue, handler, c, data); 3910Sigor@sysoev.ru } 3920Sigor@sysoev.ru 3930Sigor@sysoev.ru 3940Sigor@sysoev.ru static ssize_t 3950Sigor@sysoev.ru nxt_cyassl_conn_io_write_chunk(nxt_thread_t *thr, nxt_event_conn_t *c, 3960Sigor@sysoev.ru nxt_buf_t *b, size_t limit) 3970Sigor@sysoev.ru { 3980Sigor@sysoev.ru nxt_cyassl_conn_t *ssltls; 3990Sigor@sysoev.ru 4000Sigor@sysoev.ru nxt_log_debug(thr->log, "cyassl conn write chunk"); 4010Sigor@sysoev.ru 4020Sigor@sysoev.ru ssltls = c->u.ssltls; 4030Sigor@sysoev.ru 4040Sigor@sysoev.ru return nxt_sendbuf_copy_coalesce(c, &ssltls->buffer, b, limit); 4050Sigor@sysoev.ru } 4060Sigor@sysoev.ru 4070Sigor@sysoev.ru 4080Sigor@sysoev.ru static ssize_t 4090Sigor@sysoev.ru nxt_cyassl_conn_io_send(nxt_event_conn_t *c, void *buf, size_t size) 4100Sigor@sysoev.ru { 4110Sigor@sysoev.ru int ret; 4120Sigor@sysoev.ru nxt_err_t err; 4130Sigor@sysoev.ru nxt_int_t n; 4140Sigor@sysoev.ru nxt_cyassl_conn_t *ssltls; 4150Sigor@sysoev.ru 4160Sigor@sysoev.ru nxt_log_debug(c->socket.log, "cyassl send"); 4170Sigor@sysoev.ru 4180Sigor@sysoev.ru ssltls = c->u.ssltls; 4190Sigor@sysoev.ru 4200Sigor@sysoev.ru ret = CyaSSL_write(ssltls->session, buf, size); 4210Sigor@sysoev.ru 4220Sigor@sysoev.ru if (ret <= 0) { 4230Sigor@sysoev.ru err = nxt_socket_errno; 4240Sigor@sysoev.ru c->socket.error = err; 4250Sigor@sysoev.ru 4260Sigor@sysoev.ru } else { 4270Sigor@sysoev.ru err = 0; 4280Sigor@sysoev.ru } 4290Sigor@sysoev.ru 4300Sigor@sysoev.ru nxt_log_debug(c->socket.log, "CyaSSL_write(%d, %p, %uz): %d", 4310Sigor@sysoev.ru c->socket.fd, buf, size, ret); 4320Sigor@sysoev.ru 4330Sigor@sysoev.ru if (ret > 0) { 4340Sigor@sysoev.ru return ret; 4350Sigor@sysoev.ru } 4360Sigor@sysoev.ru 4370Sigor@sysoev.ru n = nxt_cyassl_conn_test_error(nxt_thread(), c, ret, 4380Sigor@sysoev.ru nxt_event_conn_io_write); 4390Sigor@sysoev.ru 4400Sigor@sysoev.ru if (nxt_slow_path(n == NXT_ERROR)) { 4410Sigor@sysoev.ru nxt_cyassl_conn_error(c, err, "CyaSSL_write(%d, %p, %uz) failed", 4420Sigor@sysoev.ru c->socket.fd, buf, size); 4430Sigor@sysoev.ru } 4440Sigor@sysoev.ru 4450Sigor@sysoev.ru return n; 4460Sigor@sysoev.ru } 4470Sigor@sysoev.ru 4480Sigor@sysoev.ru 4490Sigor@sysoev.ru static void 4500Sigor@sysoev.ru nxt_cyassl_conn_io_shutdown(nxt_thread_t *thr, void *obj, void *data) 4510Sigor@sysoev.ru { 4520Sigor@sysoev.ru int ret; 4530Sigor@sysoev.ru nxt_event_conn_t *c; 4540Sigor@sysoev.ru nxt_cyassl_conn_t *ssltls; 4550Sigor@sysoev.ru 4560Sigor@sysoev.ru c = obj; 4570Sigor@sysoev.ru 4580Sigor@sysoev.ru nxt_log_debug(thr->log, "cyassl conn shutdown"); 4590Sigor@sysoev.ru 4600Sigor@sysoev.ru ssltls = c->u.ssltls; 4610Sigor@sysoev.ru 4620Sigor@sysoev.ru ret = CyaSSL_shutdown(ssltls->session); 4630Sigor@sysoev.ru 4640Sigor@sysoev.ru nxt_log_debug(thr->log, "CyaSSL_shutdown(%d): %d", c->socket.fd, ret); 4650Sigor@sysoev.ru 4660Sigor@sysoev.ru if (nxt_slow_path(ret != SSL_SUCCESS)) { 4670Sigor@sysoev.ru nxt_cyassl_conn_error(c, 0, "CyaSSL_shutdown(%d) failed", c->socket.fd); 4680Sigor@sysoev.ru } 4690Sigor@sysoev.ru 4700Sigor@sysoev.ru nxt_event_conn_io_handle(thr, c->write_work_queue, 4710Sigor@sysoev.ru c->write_state->close_handler, c, data); 4720Sigor@sysoev.ru } 4730Sigor@sysoev.ru 4740Sigor@sysoev.ru 4750Sigor@sysoev.ru static nxt_int_t 4760Sigor@sysoev.ru nxt_cyassl_conn_test_error(nxt_thread_t *thr, nxt_event_conn_t *c, int ret, 4770Sigor@sysoev.ru nxt_work_handler_t handler) 4780Sigor@sysoev.ru { 4790Sigor@sysoev.ru nxt_work_queue_t *wq; 4800Sigor@sysoev.ru nxt_cyassl_conn_t *ssltls; 4810Sigor@sysoev.ru 4820Sigor@sysoev.ru ssltls = c->u.ssltls; 4830Sigor@sysoev.ru ssltls->ssl_error = CyaSSL_get_error(ssltls->session, ret); 4840Sigor@sysoev.ru 4850Sigor@sysoev.ru nxt_log_debug(thr->log, "CyaSSL_get_error(): %d", ssltls->ssl_error); 4860Sigor@sysoev.ru 4870Sigor@sysoev.ru switch (ssltls->ssl_error) { 4880Sigor@sysoev.ru 4890Sigor@sysoev.ru case SSL_ERROR_WANT_READ: 4900Sigor@sysoev.ru nxt_event_fd_block_write(thr->engine, &c->socket); 4910Sigor@sysoev.ru 4920Sigor@sysoev.ru c->socket.read_ready = 0; 4930Sigor@sysoev.ru c->socket.read_handler = handler; 4940Sigor@sysoev.ru 4950Sigor@sysoev.ru if (nxt_event_fd_is_disabled(c->socket.read)) { 4960Sigor@sysoev.ru nxt_event_fd_enable_read(thr->engine, &c->socket); 4970Sigor@sysoev.ru } 4980Sigor@sysoev.ru 4990Sigor@sysoev.ru return NXT_AGAIN; 5000Sigor@sysoev.ru 5010Sigor@sysoev.ru case SSL_ERROR_WANT_WRITE: 5020Sigor@sysoev.ru nxt_event_fd_block_read(thr->engine, &c->socket); 5030Sigor@sysoev.ru 5040Sigor@sysoev.ru c->socket.write_ready = 0; 5050Sigor@sysoev.ru c->socket.write_handler = handler; 5060Sigor@sysoev.ru 5070Sigor@sysoev.ru if (nxt_event_fd_is_disabled(c->socket.write)) { 5080Sigor@sysoev.ru nxt_event_fd_enable_write(thr->engine, &c->socket); 5090Sigor@sysoev.ru } 5100Sigor@sysoev.ru 5110Sigor@sysoev.ru return NXT_AGAIN; 5120Sigor@sysoev.ru 5130Sigor@sysoev.ru case SSL_ERROR_ZERO_RETURN: 5140Sigor@sysoev.ru /* A "close notify" alert */ 5150Sigor@sysoev.ru 5160Sigor@sysoev.ru if (c->read_state != NULL) { 5170Sigor@sysoev.ru wq = c->read_work_queue; 5180Sigor@sysoev.ru handler = c->read_state->close_handler; 5190Sigor@sysoev.ru 5200Sigor@sysoev.ru } else { 5210Sigor@sysoev.ru wq = c->write_work_queue; 5220Sigor@sysoev.ru handler = c->write_state->close_handler; 5230Sigor@sysoev.ru } 5240Sigor@sysoev.ru 5250Sigor@sysoev.ru nxt_event_conn_io_handle(thr, wq, handler, c, c->socket.data); 5260Sigor@sysoev.ru 5270Sigor@sysoev.ru return 0; 5280Sigor@sysoev.ru 5290Sigor@sysoev.ru default: 5300Sigor@sysoev.ru return NXT_ERROR; 5310Sigor@sysoev.ru } 5320Sigor@sysoev.ru } 5330Sigor@sysoev.ru 5340Sigor@sysoev.ru 5350Sigor@sysoev.ru static void nxt_cdecl 5360Sigor@sysoev.ru nxt_cyassl_conn_error(nxt_event_conn_t *c, nxt_err_t err, const char *fmt, ...) 5370Sigor@sysoev.ru { 5380Sigor@sysoev.ru u_char *p, *end; 5390Sigor@sysoev.ru va_list args; 5400Sigor@sysoev.ru nxt_uint_t level; 5410Sigor@sysoev.ru nxt_cyassl_conn_t *ssltls; 5420Sigor@sysoev.ru u_char msg[NXT_MAX_ERROR_STR]; 5430Sigor@sysoev.ru 5440Sigor@sysoev.ru ssltls = c->u.ssltls; 5450Sigor@sysoev.ru 5460Sigor@sysoev.ru level = nxt_cyassl_log_error_level(c, err, ssltls->ssl_error); 5470Sigor@sysoev.ru 5480Sigor@sysoev.ru if (nxt_log_level_enough(c->socket.log, level)) { 5490Sigor@sysoev.ru 5500Sigor@sysoev.ru end = msg + sizeof(msg); 5510Sigor@sysoev.ru 5520Sigor@sysoev.ru va_start(args, fmt); 5530Sigor@sysoev.ru p = nxt_vsprintf(msg, end, fmt, args); 5540Sigor@sysoev.ru va_end(args); 5550Sigor@sysoev.ru 5560Sigor@sysoev.ru if (err != 0) { 5570Sigor@sysoev.ru p = nxt_sprintf(p, end, " %E", err); 5580Sigor@sysoev.ru } 5590Sigor@sysoev.ru 5600Sigor@sysoev.ru p = nxt_cyassl_copy_error(ssltls->ssl_error, p, end); 5610Sigor@sysoev.ru 5620Sigor@sysoev.ru nxt_log_error(level, c->socket.log, "%*s", p - msg, msg); 5630Sigor@sysoev.ru } 5640Sigor@sysoev.ru } 5650Sigor@sysoev.ru 5660Sigor@sysoev.ru 5670Sigor@sysoev.ru static nxt_uint_t 5680Sigor@sysoev.ru nxt_cyassl_log_error_level(nxt_event_conn_t *c, nxt_err_t err, int ssl_error) 5690Sigor@sysoev.ru { 5700Sigor@sysoev.ru switch (ssl_error) { 5710Sigor@sysoev.ru 5720Sigor@sysoev.ru case SOCKET_ERROR_E: /* -208 */ 5730Sigor@sysoev.ru case MATCH_SUITE_ERROR: /* -261 */ 5740Sigor@sysoev.ru break; 5750Sigor@sysoev.ru 5760Sigor@sysoev.ru default: 577*564Svbart@nginx.com return NXT_LOG_ALERT; 5780Sigor@sysoev.ru } 5790Sigor@sysoev.ru 5800Sigor@sysoev.ru return NXT_LOG_INFO; 5810Sigor@sysoev.ru } 5820Sigor@sysoev.ru 5830Sigor@sysoev.ru 5840Sigor@sysoev.ru static void nxt_cdecl 5850Sigor@sysoev.ru nxt_cyassl_log_error(nxt_uint_t level, nxt_log_t *log, int err, 5860Sigor@sysoev.ru const char *fmt, ...) 5870Sigor@sysoev.ru { 5880Sigor@sysoev.ru u_char *p, *end; 5890Sigor@sysoev.ru va_list args; 5900Sigor@sysoev.ru u_char msg[NXT_MAX_ERROR_STR]; 5910Sigor@sysoev.ru 5920Sigor@sysoev.ru if (nxt_log_level_enough(log, level)) { 5930Sigor@sysoev.ru 5940Sigor@sysoev.ru end = msg + sizeof(msg); 5950Sigor@sysoev.ru 5960Sigor@sysoev.ru va_start(args, fmt); 5970Sigor@sysoev.ru p = nxt_vsprintf(msg, end, fmt, args); 5980Sigor@sysoev.ru va_end(args); 5990Sigor@sysoev.ru 6000Sigor@sysoev.ru p = nxt_cyassl_copy_error(err, p, end); 6010Sigor@sysoev.ru 6020Sigor@sysoev.ru nxt_log_error(level, log, "%*s", p - msg, msg); 6030Sigor@sysoev.ru } 6040Sigor@sysoev.ru } 6050Sigor@sysoev.ru 6060Sigor@sysoev.ru 6070Sigor@sysoev.ru static u_char * 6080Sigor@sysoev.ru nxt_cyassl_copy_error(int err, u_char *p, u_char *end) 6090Sigor@sysoev.ru { 6100Sigor@sysoev.ru p = nxt_sprintf(p, end, " (SSL:%d ", err); 6110Sigor@sysoev.ru 6120Sigor@sysoev.ru CyaSSL_ERR_error_string_n(err, (char *) p, end - p); 6130Sigor@sysoev.ru 6140Sigor@sysoev.ru p += nxt_strlen(p); 6150Sigor@sysoev.ru 6160Sigor@sysoev.ru if (p < end) { 6170Sigor@sysoev.ru *p++ = ')'; 6180Sigor@sysoev.ru } 6190Sigor@sysoev.ru 6200Sigor@sysoev.ru return p; 6210Sigor@sysoev.ru } 622