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; 15*771Sigor@sysoev.ru nxt_conn_t *conn; 160Sigor@sysoev.ru 170Sigor@sysoev.ru int ssl_error; 180Sigor@sysoev.ru uint8_t times; /* 2 bits */ 19*771Sigor@sysoev.ru uint8_t handshake; /* 1 bit */ 200Sigor@sysoev.ru 210Sigor@sysoev.ru nxt_buf_mem_t buffer; 220Sigor@sysoev.ru } nxt_openssl_conn_t; 230Sigor@sysoev.ru 240Sigor@sysoev.ru 25*771Sigor@sysoev.ru typedef enum { 26*771Sigor@sysoev.ru NXT_OPENSSL_HANDSHAKE = 0, 27*771Sigor@sysoev.ru NXT_OPENSSL_READ, 28*771Sigor@sysoev.ru NXT_OPENSSL_WRITE, 29*771Sigor@sysoev.ru NXT_OPENSSL_SHUTDOWN, 30*771Sigor@sysoev.ru } nxt_openssl_io_t; 31*771Sigor@sysoev.ru 320Sigor@sysoev.ru 33*771Sigor@sysoev.ru static nxt_int_t nxt_openssl_library_init(nxt_task_t *task); 34*771Sigor@sysoev.ru static void nxt_openssl_library_free(nxt_task_t *task); 35*771Sigor@sysoev.ru #if OPENSSL_VERSION_NUMBER < 0x10100004L 36*771Sigor@sysoev.ru static nxt_int_t nxt_openssl_locks_init(void); 37*771Sigor@sysoev.ru static void nxt_openssl_lock(int mode, int type, const char *file, int line); 38*771Sigor@sysoev.ru static unsigned long nxt_openssl_thread_id(void); 39*771Sigor@sysoev.ru static void nxt_openssl_locks_free(void); 40*771Sigor@sysoev.ru #endif 41*771Sigor@sysoev.ru static nxt_int_t nxt_openssl_server_init(nxt_task_t *task, 42*771Sigor@sysoev.ru nxt_tls_conf_t *conf); 43*771Sigor@sysoev.ru static void nxt_openssl_server_free(nxt_task_t *task, nxt_tls_conf_t *conf); 44*771Sigor@sysoev.ru static void nxt_openssl_conn_init(nxt_task_t *task, nxt_tls_conf_t *conf, 4562Sigor@sysoev.ru nxt_conn_t *c); 461Sigor@sysoev.ru static void nxt_openssl_conn_handshake(nxt_task_t *task, void *obj, void *data); 47*771Sigor@sysoev.ru static ssize_t nxt_openssl_conn_io_recvbuf(nxt_conn_t *c, nxt_buf_t *b); 48*771Sigor@sysoev.ru static ssize_t nxt_openssl_conn_io_sendbuf(nxt_task_t *task, nxt_sendbuf_t *sb); 49*771Sigor@sysoev.ru static ssize_t nxt_openssl_conn_io_send(nxt_task_t *task, nxt_sendbuf_t *sb, 50*771Sigor@sysoev.ru void *buf, size_t size); 511Sigor@sysoev.ru static void nxt_openssl_conn_io_shutdown(nxt_task_t *task, void *obj, 520Sigor@sysoev.ru void *data); 53*771Sigor@sysoev.ru static nxt_int_t nxt_openssl_conn_test_error(nxt_task_t *task, nxt_conn_t *c, 54*771Sigor@sysoev.ru int ret, nxt_err_t sys_err, nxt_openssl_io_t io); 55*771Sigor@sysoev.ru static void nxt_cdecl nxt_openssl_conn_error(nxt_task_t *task, 56*771Sigor@sysoev.ru nxt_err_t err, const char *fmt, ...); 57*771Sigor@sysoev.ru static nxt_uint_t nxt_openssl_log_error_level(nxt_err_t err); 580Sigor@sysoev.ru 590Sigor@sysoev.ru 60*771Sigor@sysoev.ru const nxt_tls_lib_t nxt_openssl_lib = { 61*771Sigor@sysoev.ru .library_init = nxt_openssl_library_init, 62*771Sigor@sysoev.ru .library_free = nxt_openssl_library_free, 63*771Sigor@sysoev.ru 64*771Sigor@sysoev.ru .server_init = nxt_openssl_server_init, 65*771Sigor@sysoev.ru .server_free = nxt_openssl_server_free, 660Sigor@sysoev.ru }; 670Sigor@sysoev.ru 680Sigor@sysoev.ru 6962Sigor@sysoev.ru static nxt_conn_io_t nxt_openssl_conn_io = { 70*771Sigor@sysoev.ru .read = nxt_conn_io_read, 71*771Sigor@sysoev.ru .recvbuf = nxt_openssl_conn_io_recvbuf, 720Sigor@sysoev.ru 73*771Sigor@sysoev.ru .write = nxt_conn_io_write, 74*771Sigor@sysoev.ru .sendbuf = nxt_openssl_conn_io_sendbuf, 750Sigor@sysoev.ru 76*771Sigor@sysoev.ru .shutdown = nxt_openssl_conn_io_shutdown, 770Sigor@sysoev.ru }; 780Sigor@sysoev.ru 790Sigor@sysoev.ru 800Sigor@sysoev.ru static long nxt_openssl_version; 810Sigor@sysoev.ru static int nxt_openssl_connection_index; 820Sigor@sysoev.ru 830Sigor@sysoev.ru 840Sigor@sysoev.ru static nxt_int_t 85*771Sigor@sysoev.ru nxt_openssl_library_init(nxt_task_t *task) 860Sigor@sysoev.ru { 870Sigor@sysoev.ru int index; 880Sigor@sysoev.ru 890Sigor@sysoev.ru if (nxt_fast_path(nxt_openssl_version != 0)) { 900Sigor@sysoev.ru return NXT_OK; 910Sigor@sysoev.ru } 920Sigor@sysoev.ru 93*771Sigor@sysoev.ru #if OPENSSL_VERSION_NUMBER >= 0x10100003L 94*771Sigor@sysoev.ru 95*771Sigor@sysoev.ru OPENSSL_init_ssl(OPENSSL_INIT_LOAD_CONFIG, NULL); 960Sigor@sysoev.ru 97*771Sigor@sysoev.ru #else 98*771Sigor@sysoev.ru { 99*771Sigor@sysoev.ru nxt_int_t ret; 100*771Sigor@sysoev.ru 101*771Sigor@sysoev.ru SSL_load_error_strings(); 102*771Sigor@sysoev.ru 103*771Sigor@sysoev.ru OPENSSL_config(NULL); 1040Sigor@sysoev.ru 105*771Sigor@sysoev.ru /* 106*771Sigor@sysoev.ru * SSL_library_init(3): 107*771Sigor@sysoev.ru * 108*771Sigor@sysoev.ru * SSL_library_init() always returns "1", 109*771Sigor@sysoev.ru * so it is safe to discard the return value. 110*771Sigor@sysoev.ru */ 111*771Sigor@sysoev.ru (void) SSL_library_init(); 112*771Sigor@sysoev.ru 113*771Sigor@sysoev.ru ret = nxt_openssl_locks_init(); 114*771Sigor@sysoev.ru if (nxt_slow_path(ret != NXT_OK)) { 115*771Sigor@sysoev.ru return ret; 116*771Sigor@sysoev.ru } 117*771Sigor@sysoev.ru } 118*771Sigor@sysoev.ru 119*771Sigor@sysoev.ru #endif 1200Sigor@sysoev.ru 1210Sigor@sysoev.ru nxt_openssl_version = SSLeay(); 1220Sigor@sysoev.ru 123*771Sigor@sysoev.ru nxt_log(task, NXT_LOG_INFO, "%s, %xl", 124*771Sigor@sysoev.ru SSLeay_version(SSLEAY_VERSION), nxt_openssl_version); 1250Sigor@sysoev.ru 1260Sigor@sysoev.ru #ifndef SSL_OP_NO_COMPRESSION 1270Sigor@sysoev.ru { 1280Sigor@sysoev.ru /* 1290Sigor@sysoev.ru * Disable gzip compression in OpenSSL prior to 1.0.0 1300Sigor@sysoev.ru * version, this saves about 522K per connection. 1310Sigor@sysoev.ru */ 1320Sigor@sysoev.ru int n; 1330Sigor@sysoev.ru STACK_OF(SSL_COMP) *ssl_comp_methods; 1340Sigor@sysoev.ru 1350Sigor@sysoev.ru ssl_comp_methods = SSL_COMP_get_compression_methods(); 1360Sigor@sysoev.ru 1370Sigor@sysoev.ru for (n = sk_SSL_COMP_num(ssl_comp_methods); n != 0; n--) { 1380Sigor@sysoev.ru (void) sk_SSL_COMP_pop(ssl_comp_methods); 1390Sigor@sysoev.ru } 1400Sigor@sysoev.ru } 1410Sigor@sysoev.ru #endif 1420Sigor@sysoev.ru 1430Sigor@sysoev.ru index = SSL_get_ex_new_index(0, NULL, NULL, NULL, NULL); 1440Sigor@sysoev.ru 1450Sigor@sysoev.ru if (index == -1) { 146*771Sigor@sysoev.ru nxt_openssl_log_error(task, NXT_LOG_ALERT, 1470Sigor@sysoev.ru "SSL_get_ex_new_index() failed"); 1480Sigor@sysoev.ru return NXT_ERROR; 1490Sigor@sysoev.ru } 1500Sigor@sysoev.ru 1510Sigor@sysoev.ru nxt_openssl_connection_index = index; 1520Sigor@sysoev.ru 1530Sigor@sysoev.ru return NXT_OK; 1540Sigor@sysoev.ru } 1550Sigor@sysoev.ru 1560Sigor@sysoev.ru 157*771Sigor@sysoev.ru #if OPENSSL_VERSION_NUMBER >= 0x10100003L 158*771Sigor@sysoev.ru 159*771Sigor@sysoev.ru static void 160*771Sigor@sysoev.ru nxt_openssl_library_free(nxt_task_t *task) 161*771Sigor@sysoev.ru { 162*771Sigor@sysoev.ru } 163*771Sigor@sysoev.ru 164*771Sigor@sysoev.ru #else 165*771Sigor@sysoev.ru 166*771Sigor@sysoev.ru static nxt_thread_mutex_t *nxt_openssl_locks; 167*771Sigor@sysoev.ru 1680Sigor@sysoev.ru static nxt_int_t 169*771Sigor@sysoev.ru nxt_openssl_locks_init(void) 170*771Sigor@sysoev.ru { 171*771Sigor@sysoev.ru int i, n; 172*771Sigor@sysoev.ru nxt_int_t ret; 173*771Sigor@sysoev.ru 174*771Sigor@sysoev.ru n = CRYPTO_num_locks(); 175*771Sigor@sysoev.ru 176*771Sigor@sysoev.ru nxt_openssl_locks = OPENSSL_malloc(n * sizeof(nxt_thread_mutex_t)); 177*771Sigor@sysoev.ru if (nxt_slow_path(nxt_openssl_locks == NULL)) { 178*771Sigor@sysoev.ru return NXT_ERROR; 179*771Sigor@sysoev.ru } 180*771Sigor@sysoev.ru 181*771Sigor@sysoev.ru for (i = 0; i < n; i++) { 182*771Sigor@sysoev.ru ret = nxt_thread_mutex_create(&nxt_openssl_locks[i]); 183*771Sigor@sysoev.ru if (nxt_slow_path(ret != NXT_OK)) { 184*771Sigor@sysoev.ru return ret; 185*771Sigor@sysoev.ru } 186*771Sigor@sysoev.ru } 187*771Sigor@sysoev.ru 188*771Sigor@sysoev.ru CRYPTO_set_locking_callback(nxt_openssl_lock); 189*771Sigor@sysoev.ru 190*771Sigor@sysoev.ru CRYPTO_set_id_callback(nxt_openssl_thread_id); 191*771Sigor@sysoev.ru 192*771Sigor@sysoev.ru return NXT_OK; 193*771Sigor@sysoev.ru } 194*771Sigor@sysoev.ru 195*771Sigor@sysoev.ru 196*771Sigor@sysoev.ru static void 197*771Sigor@sysoev.ru nxt_openssl_lock(int mode, int type, const char *file, int line) 198*771Sigor@sysoev.ru { 199*771Sigor@sysoev.ru nxt_thread_mutex_t *lock; 200*771Sigor@sysoev.ru 201*771Sigor@sysoev.ru lock = &nxt_openssl_locks[type]; 202*771Sigor@sysoev.ru 203*771Sigor@sysoev.ru if ((mode & CRYPTO_LOCK) != 0) { 204*771Sigor@sysoev.ru (void) nxt_thread_mutex_lock(lock); 205*771Sigor@sysoev.ru 206*771Sigor@sysoev.ru } else { 207*771Sigor@sysoev.ru (void) nxt_thread_mutex_unlock(lock); 208*771Sigor@sysoev.ru } 209*771Sigor@sysoev.ru } 210*771Sigor@sysoev.ru 211*771Sigor@sysoev.ru 212*771Sigor@sysoev.ru static u_long 213*771Sigor@sysoev.ru nxt_openssl_thread_id(void) 214*771Sigor@sysoev.ru { 215*771Sigor@sysoev.ru return (u_long) nxt_thread_handle(); 216*771Sigor@sysoev.ru } 217*771Sigor@sysoev.ru 218*771Sigor@sysoev.ru 219*771Sigor@sysoev.ru static void 220*771Sigor@sysoev.ru nxt_openssl_library_free(nxt_task_t *task) 221*771Sigor@sysoev.ru { 222*771Sigor@sysoev.ru nxt_openssl_locks_free(); 223*771Sigor@sysoev.ru } 224*771Sigor@sysoev.ru 225*771Sigor@sysoev.ru 226*771Sigor@sysoev.ru static void 227*771Sigor@sysoev.ru nxt_openssl_locks_free(void) 228*771Sigor@sysoev.ru { 229*771Sigor@sysoev.ru int i, n; 230*771Sigor@sysoev.ru 231*771Sigor@sysoev.ru n = CRYPTO_num_locks(); 232*771Sigor@sysoev.ru 233*771Sigor@sysoev.ru CRYPTO_set_locking_callback(NULL); 234*771Sigor@sysoev.ru 235*771Sigor@sysoev.ru for (i = 0; i < n; i++) { 236*771Sigor@sysoev.ru nxt_thread_mutex_destroy(&nxt_openssl_locks[i]); 237*771Sigor@sysoev.ru } 238*771Sigor@sysoev.ru 239*771Sigor@sysoev.ru OPENSSL_free(nxt_openssl_locks); 240*771Sigor@sysoev.ru } 241*771Sigor@sysoev.ru 242*771Sigor@sysoev.ru #endif 243*771Sigor@sysoev.ru 244*771Sigor@sysoev.ru 245*771Sigor@sysoev.ru static nxt_int_t 246*771Sigor@sysoev.ru nxt_openssl_server_init(nxt_task_t *task, nxt_tls_conf_t *conf) 2470Sigor@sysoev.ru { 2480Sigor@sysoev.ru SSL_CTX *ctx; 2490Sigor@sysoev.ru const char *certificate, *key, *ciphers, *ca_certificate; 2500Sigor@sysoev.ru STACK_OF(X509_NAME) *list; 2510Sigor@sysoev.ru 2520Sigor@sysoev.ru ctx = SSL_CTX_new(SSLv23_server_method()); 2530Sigor@sysoev.ru if (ctx == NULL) { 254*771Sigor@sysoev.ru nxt_openssl_log_error(task, NXT_LOG_ALERT, "SSL_CTX_new() failed"); 2550Sigor@sysoev.ru return NXT_ERROR; 2560Sigor@sysoev.ru } 2570Sigor@sysoev.ru 2580Sigor@sysoev.ru conf->ctx = ctx; 2590Sigor@sysoev.ru conf->conn_init = nxt_openssl_conn_init; 2600Sigor@sysoev.ru 261*771Sigor@sysoev.ru #ifdef SSL_OP_NO_RENEGOTIATION 262*771Sigor@sysoev.ru /* Renegration is not currently supported. */ 263*771Sigor@sysoev.ru SSL_CTX_set_options(ctx, SSL_OP_NO_RENEGOTIATION); 264*771Sigor@sysoev.ru #endif 265*771Sigor@sysoev.ru 2660Sigor@sysoev.ru #ifdef SSL_OP_NO_COMPRESSION 2670Sigor@sysoev.ru /* 2680Sigor@sysoev.ru * Disable gzip compression in OpenSSL 1.0.0, 2690Sigor@sysoev.ru * this saves about 522K per connection. 2700Sigor@sysoev.ru */ 2710Sigor@sysoev.ru SSL_CTX_set_options(ctx, SSL_OP_NO_COMPRESSION); 2720Sigor@sysoev.ru #endif 2730Sigor@sysoev.ru 2740Sigor@sysoev.ru #ifdef SSL_MODE_RELEASE_BUFFERS 2750Sigor@sysoev.ru 2760Sigor@sysoev.ru if (nxt_openssl_version >= 10001078) { 2770Sigor@sysoev.ru /* 2780Sigor@sysoev.ru * Allow to release read and write buffers in OpenSSL 1.0.0, 2790Sigor@sysoev.ru * this saves about 34K per idle connection. It is not safe 2800Sigor@sysoev.ru * before OpenSSL 1.0.1h (CVE-2010-5298). 2810Sigor@sysoev.ru */ 2820Sigor@sysoev.ru SSL_CTX_set_mode(ctx, SSL_MODE_RELEASE_BUFFERS); 2830Sigor@sysoev.ru } 2840Sigor@sysoev.ru 2850Sigor@sysoev.ru #endif 2860Sigor@sysoev.ru 2870Sigor@sysoev.ru certificate = conf->certificate; 2880Sigor@sysoev.ru 2890Sigor@sysoev.ru if (SSL_CTX_use_certificate_chain_file(ctx, certificate) == 0) { 290*771Sigor@sysoev.ru nxt_openssl_log_error(task, NXT_LOG_ALERT, 2910Sigor@sysoev.ru "SSL_CTX_use_certificate_file(\"%s\") failed", 2920Sigor@sysoev.ru certificate); 2930Sigor@sysoev.ru goto fail; 2940Sigor@sysoev.ru } 2950Sigor@sysoev.ru 2960Sigor@sysoev.ru key = conf->certificate_key; 2970Sigor@sysoev.ru 2980Sigor@sysoev.ru if (SSL_CTX_use_PrivateKey_file(ctx, key, SSL_FILETYPE_PEM) == 0) { 299*771Sigor@sysoev.ru nxt_openssl_log_error(task, NXT_LOG_ALERT, 3000Sigor@sysoev.ru "SSL_CTX_use_PrivateKey_file(\"%s\") failed", 3010Sigor@sysoev.ru key); 3020Sigor@sysoev.ru goto fail; 3030Sigor@sysoev.ru } 3040Sigor@sysoev.ru 3050Sigor@sysoev.ru ciphers = (conf->ciphers != NULL) ? conf->ciphers : "HIGH:!aNULL:!MD5"; 3060Sigor@sysoev.ru 3070Sigor@sysoev.ru if (SSL_CTX_set_cipher_list(ctx, ciphers) == 0) { 308*771Sigor@sysoev.ru nxt_openssl_log_error(task, NXT_LOG_ALERT, 3090Sigor@sysoev.ru "SSL_CTX_set_cipher_list(\"%s\") failed", 3100Sigor@sysoev.ru ciphers); 3110Sigor@sysoev.ru goto fail; 3120Sigor@sysoev.ru } 3130Sigor@sysoev.ru 3140Sigor@sysoev.ru SSL_CTX_set_options(ctx, SSL_OP_CIPHER_SERVER_PREFERENCE); 3150Sigor@sysoev.ru 3160Sigor@sysoev.ru if (conf->ca_certificate != NULL) { 3170Sigor@sysoev.ru 3180Sigor@sysoev.ru /* TODO: verify callback */ 3190Sigor@sysoev.ru SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER, NULL); 3200Sigor@sysoev.ru 3210Sigor@sysoev.ru /* TODO: verify depth */ 3220Sigor@sysoev.ru SSL_CTX_set_verify_depth(ctx, 1); 3230Sigor@sysoev.ru 3240Sigor@sysoev.ru ca_certificate = conf->ca_certificate; 3250Sigor@sysoev.ru 3260Sigor@sysoev.ru if (SSL_CTX_load_verify_locations(ctx, ca_certificate, NULL) == 0) { 327*771Sigor@sysoev.ru nxt_openssl_log_error(task, NXT_LOG_ALERT, 3280Sigor@sysoev.ru "SSL_CTX_load_verify_locations(\"%s\") failed", 3290Sigor@sysoev.ru ca_certificate); 3300Sigor@sysoev.ru goto fail; 3310Sigor@sysoev.ru } 3320Sigor@sysoev.ru 3330Sigor@sysoev.ru list = SSL_load_client_CA_file(ca_certificate); 3340Sigor@sysoev.ru 3350Sigor@sysoev.ru if (list == NULL) { 336*771Sigor@sysoev.ru nxt_openssl_log_error(task, NXT_LOG_ALERT, 3370Sigor@sysoev.ru "SSL_load_client_CA_file(\"%s\") failed", 3380Sigor@sysoev.ru ca_certificate); 3390Sigor@sysoev.ru goto fail; 3400Sigor@sysoev.ru } 3410Sigor@sysoev.ru 3420Sigor@sysoev.ru /* 3430Sigor@sysoev.ru * SSL_load_client_CA_file() in OpenSSL prior to 0.9.7h and 3440Sigor@sysoev.ru * 0.9.8 versions always leaves an error in the error queue. 3450Sigor@sysoev.ru */ 3460Sigor@sysoev.ru ERR_clear_error(); 3470Sigor@sysoev.ru 3480Sigor@sysoev.ru SSL_CTX_set_client_CA_list(ctx, list); 3490Sigor@sysoev.ru } 3500Sigor@sysoev.ru 3510Sigor@sysoev.ru return NXT_OK; 3520Sigor@sysoev.ru 3530Sigor@sysoev.ru fail: 3540Sigor@sysoev.ru 3550Sigor@sysoev.ru SSL_CTX_free(ctx); 3560Sigor@sysoev.ru 3570Sigor@sysoev.ru return NXT_ERROR; 3580Sigor@sysoev.ru } 3590Sigor@sysoev.ru 3600Sigor@sysoev.ru 3610Sigor@sysoev.ru static void 362*771Sigor@sysoev.ru nxt_openssl_server_free(nxt_task_t *task, nxt_tls_conf_t *conf) 3630Sigor@sysoev.ru { 364*771Sigor@sysoev.ru SSL_CTX_free(conf->ctx); 365*771Sigor@sysoev.ru } 366*771Sigor@sysoev.ru 367*771Sigor@sysoev.ru 368*771Sigor@sysoev.ru static void 369*771Sigor@sysoev.ru nxt_openssl_conn_init(nxt_task_t *task, nxt_tls_conf_t *conf, nxt_conn_t *c) 370*771Sigor@sysoev.ru { 371*771Sigor@sysoev.ru int ret; 372*771Sigor@sysoev.ru SSL *s; 373*771Sigor@sysoev.ru SSL_CTX *ctx; 374*771Sigor@sysoev.ru nxt_openssl_conn_t *tls; 3750Sigor@sysoev.ru 3760Sigor@sysoev.ru nxt_log_debug(c->socket.log, "openssl conn init"); 3770Sigor@sysoev.ru 378*771Sigor@sysoev.ru tls = nxt_mp_zget(c->mem_pool, sizeof(nxt_openssl_conn_t)); 379*771Sigor@sysoev.ru if (tls == NULL) { 3800Sigor@sysoev.ru goto fail; 3810Sigor@sysoev.ru } 3820Sigor@sysoev.ru 383*771Sigor@sysoev.ru c->u.tls = tls; 384*771Sigor@sysoev.ru nxt_buf_mem_set_size(&tls->buffer, conf->buffer_size); 3850Sigor@sysoev.ru 3860Sigor@sysoev.ru ctx = conf->ctx; 3870Sigor@sysoev.ru 3880Sigor@sysoev.ru s = SSL_new(ctx); 3890Sigor@sysoev.ru if (s == NULL) { 390*771Sigor@sysoev.ru nxt_openssl_log_error(task, NXT_LOG_ALERT, "SSL_new() failed"); 3910Sigor@sysoev.ru goto fail; 3920Sigor@sysoev.ru } 3930Sigor@sysoev.ru 394*771Sigor@sysoev.ru tls->session = s; 395*771Sigor@sysoev.ru tls->conn = c; 3960Sigor@sysoev.ru 3970Sigor@sysoev.ru ret = SSL_set_fd(s, c->socket.fd); 3980Sigor@sysoev.ru 3990Sigor@sysoev.ru if (ret == 0) { 400*771Sigor@sysoev.ru nxt_openssl_log_error(task, NXT_LOG_ALERT, "SSL_set_fd(%d) failed", 401*771Sigor@sysoev.ru c->socket.fd); 4020Sigor@sysoev.ru goto fail; 4030Sigor@sysoev.ru } 4040Sigor@sysoev.ru 4050Sigor@sysoev.ru SSL_set_accept_state(s); 4060Sigor@sysoev.ru 4070Sigor@sysoev.ru if (SSL_set_ex_data(s, nxt_openssl_connection_index, c) == 0) { 408*771Sigor@sysoev.ru nxt_openssl_log_error(task, NXT_LOG_ALERT, "SSL_set_ex_data() failed"); 4090Sigor@sysoev.ru goto fail; 4100Sigor@sysoev.ru } 4110Sigor@sysoev.ru 41262Sigor@sysoev.ru c->io = &nxt_openssl_conn_io; 4130Sigor@sysoev.ru c->sendfile = NXT_CONN_SENDFILE_OFF; 4140Sigor@sysoev.ru 4151Sigor@sysoev.ru nxt_openssl_conn_handshake(task, c, c->socket.data); 4160Sigor@sysoev.ru return; 4170Sigor@sysoev.ru 4180Sigor@sysoev.ru fail: 4190Sigor@sysoev.ru 42013Sigor@sysoev.ru nxt_work_queue_add(c->read_work_queue, c->read_state->error_handler, 42113Sigor@sysoev.ru task, c, c->socket.data); 4220Sigor@sysoev.ru } 4230Sigor@sysoev.ru 4240Sigor@sysoev.ru 425*771Sigor@sysoev.ru nxt_inline void 426*771Sigor@sysoev.ru nxt_openssl_conn_free(nxt_task_t *task, nxt_openssl_conn_t *tls) 4270Sigor@sysoev.ru { 428*771Sigor@sysoev.ru nxt_debug(task, "openssl conn free"); 4290Sigor@sysoev.ru 430*771Sigor@sysoev.ru nxt_free(tls->buffer.start); 4310Sigor@sysoev.ru 432*771Sigor@sysoev.ru SSL_free(tls->session); 4330Sigor@sysoev.ru } 4340Sigor@sysoev.ru 4350Sigor@sysoev.ru 4360Sigor@sysoev.ru static void 4371Sigor@sysoev.ru nxt_openssl_conn_handshake(nxt_task_t *task, void *obj, void *data) 4380Sigor@sysoev.ru { 439*771Sigor@sysoev.ru int ret; 440*771Sigor@sysoev.ru nxt_int_t n; 441*771Sigor@sysoev.ru nxt_err_t err; 442*771Sigor@sysoev.ru nxt_conn_t *c; 443*771Sigor@sysoev.ru nxt_work_queue_t *wq; 444*771Sigor@sysoev.ru nxt_work_handler_t handler; 445*771Sigor@sysoev.ru nxt_openssl_conn_t *tls; 446*771Sigor@sysoev.ru const nxt_conn_state_t *state; 4470Sigor@sysoev.ru 4480Sigor@sysoev.ru c = obj; 449*771Sigor@sysoev.ru tls = c->u.tls; 4500Sigor@sysoev.ru 451*771Sigor@sysoev.ru nxt_debug(task, "openssl conn handshake: %d", tls->times); 4520Sigor@sysoev.ru 453*771Sigor@sysoev.ru /* "tls->times == 1" is suitable to run SSL_do_handshake() in job. */ 4540Sigor@sysoev.ru 455*771Sigor@sysoev.ru ret = SSL_do_handshake(tls->session); 4560Sigor@sysoev.ru 4570Sigor@sysoev.ru err = (ret <= 0) ? nxt_socket_errno : 0; 4580Sigor@sysoev.ru 4591Sigor@sysoev.ru nxt_thread_time_debug_update(task->thread); 4600Sigor@sysoev.ru 4611Sigor@sysoev.ru nxt_debug(task, "SSL_do_handshake(%d): %d err:%d", c->socket.fd, ret, err); 4620Sigor@sysoev.ru 463*771Sigor@sysoev.ru state = (c->read_state != NULL) ? c->read_state : c->write_state; 464*771Sigor@sysoev.ru 4650Sigor@sysoev.ru if (ret > 0) { 4660Sigor@sysoev.ru /* ret == 1, the handshake was successfully completed. */ 467*771Sigor@sysoev.ru tls->handshake = 1; 4680Sigor@sysoev.ru 469*771Sigor@sysoev.ru if (c->read_state != NULL) { 470*771Sigor@sysoev.ru if (state->io_read_handler != NULL || c->read != NULL) { 471*771Sigor@sysoev.ru nxt_conn_read(task->thread->engine, c); 4720Sigor@sysoev.ru return; 4730Sigor@sysoev.ru } 4740Sigor@sysoev.ru 475*771Sigor@sysoev.ru } else { 476*771Sigor@sysoev.ru if (c->write != NULL) { 477*771Sigor@sysoev.ru nxt_conn_write(task->thread->engine, c); 478*771Sigor@sysoev.ru return; 479*771Sigor@sysoev.ru } 480*771Sigor@sysoev.ru } 481*771Sigor@sysoev.ru 482*771Sigor@sysoev.ru handler = state->ready_handler; 483*771Sigor@sysoev.ru 484*771Sigor@sysoev.ru } else { 485*771Sigor@sysoev.ru c->socket.read_handler = nxt_openssl_conn_handshake; 486*771Sigor@sysoev.ru c->socket.write_handler = nxt_openssl_conn_handshake; 487*771Sigor@sysoev.ru 488*771Sigor@sysoev.ru n = nxt_openssl_conn_test_error(task, c, ret, err, 489*771Sigor@sysoev.ru NXT_OPENSSL_HANDSHAKE); 490*771Sigor@sysoev.ru switch (n) { 4910Sigor@sysoev.ru 492*771Sigor@sysoev.ru case NXT_AGAIN: 493*771Sigor@sysoev.ru if (tls->ssl_error == SSL_ERROR_WANT_READ && tls->times < 2) { 494*771Sigor@sysoev.ru tls->times++; 495*771Sigor@sysoev.ru } 496*771Sigor@sysoev.ru 497*771Sigor@sysoev.ru return; 498*771Sigor@sysoev.ru 499*771Sigor@sysoev.ru case 0: 500*771Sigor@sysoev.ru handler = state->close_handler; 501*771Sigor@sysoev.ru break; 502*771Sigor@sysoev.ru 503*771Sigor@sysoev.ru default: 504*771Sigor@sysoev.ru case NXT_ERROR: 505*771Sigor@sysoev.ru c->socket.error = err; 506*771Sigor@sysoev.ru nxt_openssl_conn_error(task, err, "SSL_do_handshake(%d) failed", 507*771Sigor@sysoev.ru c->socket.fd); 508*771Sigor@sysoev.ru 509*771Sigor@sysoev.ru handler = state->error_handler; 510*771Sigor@sysoev.ru break; 5110Sigor@sysoev.ru } 5120Sigor@sysoev.ru } 5130Sigor@sysoev.ru 514*771Sigor@sysoev.ru wq = (c->read_state != NULL) ? c->read_work_queue : c->write_work_queue; 515*771Sigor@sysoev.ru 516*771Sigor@sysoev.ru nxt_work_queue_add(wq, handler, task, c, data); 5170Sigor@sysoev.ru } 5180Sigor@sysoev.ru 5190Sigor@sysoev.ru 5200Sigor@sysoev.ru static ssize_t 521*771Sigor@sysoev.ru nxt_openssl_conn_io_recvbuf(nxt_conn_t *c, nxt_buf_t *b) 5220Sigor@sysoev.ru { 523*771Sigor@sysoev.ru int ret; 524*771Sigor@sysoev.ru size_t size; 525*771Sigor@sysoev.ru nxt_int_t n; 526*771Sigor@sysoev.ru nxt_err_t err; 527*771Sigor@sysoev.ru nxt_openssl_conn_t *tls; 528*771Sigor@sysoev.ru 529*771Sigor@sysoev.ru tls = c->u.tls; 530*771Sigor@sysoev.ru size = b->mem.end - b->mem.free; 531*771Sigor@sysoev.ru 532*771Sigor@sysoev.ru ret = SSL_read(tls->session, b->mem.free, size); 533*771Sigor@sysoev.ru 534*771Sigor@sysoev.ru err = (ret <= 0) ? nxt_socket_errno : 0; 535*771Sigor@sysoev.ru 536*771Sigor@sysoev.ru nxt_debug(c->socket.task, "SSL_read(%d, %p, %uz): %d err:%d", 537*771Sigor@sysoev.ru c->socket.fd, b->mem.free, size, ret, err); 5380Sigor@sysoev.ru 539*771Sigor@sysoev.ru if (ret > 0) { 540*771Sigor@sysoev.ru if ((size_t) ret < size) { 541*771Sigor@sysoev.ru c->socket.read_ready = 0; 542*771Sigor@sysoev.ru } 543*771Sigor@sysoev.ru 544*771Sigor@sysoev.ru return ret; 545*771Sigor@sysoev.ru } 5460Sigor@sysoev.ru 547*771Sigor@sysoev.ru n = nxt_openssl_conn_test_error(c->socket.task, c, ret, err, 548*771Sigor@sysoev.ru NXT_OPENSSL_READ); 549*771Sigor@sysoev.ru if (n == NXT_ERROR) { 550*771Sigor@sysoev.ru c->socket.error = err; 551*771Sigor@sysoev.ru nxt_openssl_conn_error(c->socket.task, err, 552*771Sigor@sysoev.ru "SSL_read(%d, %p, %uz) failed", 553*771Sigor@sysoev.ru c->socket.fd, b->mem.free, size); 554*771Sigor@sysoev.ru } 5550Sigor@sysoev.ru 556*771Sigor@sysoev.ru return n; 5570Sigor@sysoev.ru } 5580Sigor@sysoev.ru 5590Sigor@sysoev.ru 5600Sigor@sysoev.ru static ssize_t 561*771Sigor@sysoev.ru nxt_openssl_conn_io_sendbuf(nxt_task_t *task, nxt_sendbuf_t *sb) 562*771Sigor@sysoev.ru { 563*771Sigor@sysoev.ru nxt_uint_t niov; 564*771Sigor@sysoev.ru struct iovec iov; 565*771Sigor@sysoev.ru 566*771Sigor@sysoev.ru niov = nxt_sendbuf_mem_coalesce0(task, sb, &iov, 1); 567*771Sigor@sysoev.ru 568*771Sigor@sysoev.ru if (niov == 0 && sb->sync) { 569*771Sigor@sysoev.ru return 0; 570*771Sigor@sysoev.ru } 571*771Sigor@sysoev.ru 572*771Sigor@sysoev.ru return nxt_openssl_conn_io_send(task, sb, iov.iov_base, iov.iov_len); 573*771Sigor@sysoev.ru } 574*771Sigor@sysoev.ru 575*771Sigor@sysoev.ru 576*771Sigor@sysoev.ru static ssize_t 577*771Sigor@sysoev.ru nxt_openssl_conn_io_send(nxt_task_t *task, nxt_sendbuf_t *sb, void *buf, 578*771Sigor@sysoev.ru size_t size) 5790Sigor@sysoev.ru { 5800Sigor@sysoev.ru int ret; 5810Sigor@sysoev.ru nxt_err_t err; 5820Sigor@sysoev.ru nxt_int_t n; 583*771Sigor@sysoev.ru nxt_conn_t *c; 584*771Sigor@sysoev.ru nxt_openssl_conn_t *tls; 5850Sigor@sysoev.ru 586*771Sigor@sysoev.ru tls = sb->tls; 5870Sigor@sysoev.ru 588*771Sigor@sysoev.ru ret = SSL_write(tls->session, buf, size); 5890Sigor@sysoev.ru 5900Sigor@sysoev.ru if (ret <= 0) { 5910Sigor@sysoev.ru err = nxt_socket_errno; 592*771Sigor@sysoev.ru sb->error = err; 5930Sigor@sysoev.ru 5940Sigor@sysoev.ru } else { 5950Sigor@sysoev.ru err = 0; 5960Sigor@sysoev.ru } 5970Sigor@sysoev.ru 598*771Sigor@sysoev.ru nxt_debug(task, "SSL_write(%d, %p, %uz): %d err:%d", 599*771Sigor@sysoev.ru sb->socket, buf, size, ret, err); 6000Sigor@sysoev.ru 6010Sigor@sysoev.ru if (ret > 0) { 6020Sigor@sysoev.ru return ret; 6030Sigor@sysoev.ru } 6040Sigor@sysoev.ru 605*771Sigor@sysoev.ru c = tls->conn; 606*771Sigor@sysoev.ru c->socket.write_ready = sb->ready; 607*771Sigor@sysoev.ru c->socket.error = sb->error; 608*771Sigor@sysoev.ru 609*771Sigor@sysoev.ru n = nxt_openssl_conn_test_error(task, c, ret, err, NXT_OPENSSL_WRITE); 610*771Sigor@sysoev.ru 611*771Sigor@sysoev.ru sb->ready = c->socket.write_ready; 612*771Sigor@sysoev.ru sb->error = c->socket.error; 6130Sigor@sysoev.ru 6140Sigor@sysoev.ru if (n == NXT_ERROR) { 615*771Sigor@sysoev.ru sb->error = err; 616*771Sigor@sysoev.ru nxt_openssl_conn_error(task, err, "SSL_write(%d, %p, %uz) failed", 617*771Sigor@sysoev.ru sb->socket, buf, size); 6180Sigor@sysoev.ru } 6190Sigor@sysoev.ru 6200Sigor@sysoev.ru return n; 6210Sigor@sysoev.ru } 6220Sigor@sysoev.ru 6230Sigor@sysoev.ru 6240Sigor@sysoev.ru static void 6251Sigor@sysoev.ru nxt_openssl_conn_io_shutdown(nxt_task_t *task, void *obj, void *data) 6260Sigor@sysoev.ru { 6270Sigor@sysoev.ru int ret, mode; 6280Sigor@sysoev.ru SSL *s; 6290Sigor@sysoev.ru nxt_err_t err; 6300Sigor@sysoev.ru nxt_int_t n; 6310Sigor@sysoev.ru nxt_bool_t quiet, once; 63262Sigor@sysoev.ru nxt_conn_t *c; 633*771Sigor@sysoev.ru nxt_openssl_conn_t *tls; 6340Sigor@sysoev.ru nxt_work_handler_t handler; 6350Sigor@sysoev.ru 6360Sigor@sysoev.ru c = obj; 6370Sigor@sysoev.ru 6381Sigor@sysoev.ru nxt_debug(task, "openssl conn shutdown"); 6390Sigor@sysoev.ru 640*771Sigor@sysoev.ru c->read_state = NULL; 641*771Sigor@sysoev.ru tls = c->u.tls; 642*771Sigor@sysoev.ru s = tls->session; 6430Sigor@sysoev.ru 644*771Sigor@sysoev.ru if (s == NULL || !tls->handshake) { 645*771Sigor@sysoev.ru handler = c->write_state->ready_handler; 6460Sigor@sysoev.ru goto done; 6470Sigor@sysoev.ru } 6480Sigor@sysoev.ru 6490Sigor@sysoev.ru mode = SSL_get_shutdown(s); 6500Sigor@sysoev.ru 6510Sigor@sysoev.ru if (c->socket.timedout || c->socket.error != 0) { 6520Sigor@sysoev.ru quiet = 1; 6530Sigor@sysoev.ru 6540Sigor@sysoev.ru } else if (c->socket.closed && !(mode & SSL_RECEIVED_SHUTDOWN)) { 6550Sigor@sysoev.ru quiet = 1; 6560Sigor@sysoev.ru 6570Sigor@sysoev.ru } else { 6580Sigor@sysoev.ru quiet = 0; 6590Sigor@sysoev.ru } 6600Sigor@sysoev.ru 6610Sigor@sysoev.ru SSL_set_quiet_shutdown(s, quiet); 6620Sigor@sysoev.ru 6630Sigor@sysoev.ru once = 1; 6640Sigor@sysoev.ru 6650Sigor@sysoev.ru for ( ;; ) { 6660Sigor@sysoev.ru SSL_set_shutdown(s, mode); 6670Sigor@sysoev.ru 6680Sigor@sysoev.ru ret = SSL_shutdown(s); 6690Sigor@sysoev.ru 6700Sigor@sysoev.ru err = (ret <= 0) ? nxt_socket_errno : 0; 6710Sigor@sysoev.ru 6721Sigor@sysoev.ru nxt_debug(task, "SSL_shutdown(%d, %d, %b): %d err:%d", 6731Sigor@sysoev.ru c->socket.fd, mode, quiet, ret, err); 6740Sigor@sysoev.ru 6750Sigor@sysoev.ru if (ret > 0) { 6760Sigor@sysoev.ru /* ret == 1, the shutdown was successfully completed. */ 677*771Sigor@sysoev.ru handler = c->write_state->ready_handler; 6780Sigor@sysoev.ru goto done; 6790Sigor@sysoev.ru } 6800Sigor@sysoev.ru 6810Sigor@sysoev.ru if (ret == 0) { 6820Sigor@sysoev.ru /* 6830Sigor@sysoev.ru * If SSL_shutdown() returns 0 then it should be called 684*771Sigor@sysoev.ru * again. The second SSL_shutdown() call should return 6850Sigor@sysoev.ru * -1/SSL_ERROR_WANT_READ or -1/SSL_ERROR_WANT_WRITE. 6860Sigor@sysoev.ru * OpenSSL prior to 0.9.8m version however never returns 687*771Sigor@sysoev.ru * -1 at all. Fortunately, OpenSSL preserves internally 6880Sigor@sysoev.ru * correct status available via SSL_get_error(-1). 6890Sigor@sysoev.ru */ 6900Sigor@sysoev.ru if (once) { 691*771Sigor@sysoev.ru once = 0; 6920Sigor@sysoev.ru mode = SSL_get_shutdown(s); 6930Sigor@sysoev.ru continue; 6940Sigor@sysoev.ru } 6950Sigor@sysoev.ru 6960Sigor@sysoev.ru ret = -1; 6970Sigor@sysoev.ru } 6980Sigor@sysoev.ru 6990Sigor@sysoev.ru /* ret == -1 */ 7000Sigor@sysoev.ru 7010Sigor@sysoev.ru break; 7020Sigor@sysoev.ru } 7030Sigor@sysoev.ru 704*771Sigor@sysoev.ru c->socket.read_handler = nxt_openssl_conn_io_shutdown; 705*771Sigor@sysoev.ru c->socket.write_handler = nxt_openssl_conn_io_shutdown; 706*771Sigor@sysoev.ru c->socket.error_handler = c->write_state->error_handler; 707*771Sigor@sysoev.ru 708*771Sigor@sysoev.ru n = nxt_openssl_conn_test_error(task, c, ret, err, NXT_OPENSSL_SHUTDOWN); 709*771Sigor@sysoev.ru 710*771Sigor@sysoev.ru switch (n) { 7110Sigor@sysoev.ru 712*771Sigor@sysoev.ru case 0: 713*771Sigor@sysoev.ru handler = c->write_state->close_handler; 714*771Sigor@sysoev.ru break; 715*771Sigor@sysoev.ru 716*771Sigor@sysoev.ru case NXT_AGAIN: 717*771Sigor@sysoev.ru nxt_timer_add(task->thread->engine, &c->read_timer, 5000); 7180Sigor@sysoev.ru return; 719*771Sigor@sysoev.ru 720*771Sigor@sysoev.ru default: 721*771Sigor@sysoev.ru case NXT_ERROR: 722*771Sigor@sysoev.ru c->socket.error = err; 723*771Sigor@sysoev.ru nxt_openssl_conn_error(task, err, "SSL_shutdown(%d) failed", 724*771Sigor@sysoev.ru c->socket.fd); 725*771Sigor@sysoev.ru handler = c->write_state->error_handler; 7260Sigor@sysoev.ru } 7270Sigor@sysoev.ru 728*771Sigor@sysoev.ru done: 7290Sigor@sysoev.ru 730*771Sigor@sysoev.ru nxt_openssl_conn_free(task, tls); 7310Sigor@sysoev.ru 73213Sigor@sysoev.ru nxt_work_queue_add(c->write_work_queue, handler, task, c, data); 7330Sigor@sysoev.ru } 7340Sigor@sysoev.ru 7350Sigor@sysoev.ru 7360Sigor@sysoev.ru static nxt_int_t 73762Sigor@sysoev.ru nxt_openssl_conn_test_error(nxt_task_t *task, nxt_conn_t *c, int ret, 738*771Sigor@sysoev.ru nxt_err_t sys_err, nxt_openssl_io_t io) 7390Sigor@sysoev.ru { 7400Sigor@sysoev.ru u_long lib_err; 741*771Sigor@sysoev.ru nxt_openssl_conn_t *tls; 7420Sigor@sysoev.ru 743*771Sigor@sysoev.ru tls = c->u.tls; 7440Sigor@sysoev.ru 745*771Sigor@sysoev.ru tls->ssl_error = SSL_get_error(tls->session, ret); 7460Sigor@sysoev.ru 747*771Sigor@sysoev.ru nxt_debug(task, "SSL_get_error(): %d", tls->ssl_error); 7480Sigor@sysoev.ru 749*771Sigor@sysoev.ru switch (tls->ssl_error) { 7500Sigor@sysoev.ru 7510Sigor@sysoev.ru case SSL_ERROR_WANT_READ: 752*771Sigor@sysoev.ru 753*771Sigor@sysoev.ru if (io != NXT_OPENSSL_READ) { 754*771Sigor@sysoev.ru nxt_fd_event_block_write(task->thread->engine, &c->socket); 7550Sigor@sysoev.ru 756*771Sigor@sysoev.ru c->socket.read_ready = 0; 7570Sigor@sysoev.ru 758*771Sigor@sysoev.ru if (nxt_fd_event_is_disabled(c->socket.read)) { 759*771Sigor@sysoev.ru nxt_fd_event_enable_read(task->thread->engine, &c->socket); 760*771Sigor@sysoev.ru } 7610Sigor@sysoev.ru } 7620Sigor@sysoev.ru 7630Sigor@sysoev.ru return NXT_AGAIN; 7640Sigor@sysoev.ru 7650Sigor@sysoev.ru case SSL_ERROR_WANT_WRITE: 766*771Sigor@sysoev.ru 767*771Sigor@sysoev.ru if (io != NXT_OPENSSL_WRITE) { 768*771Sigor@sysoev.ru nxt_fd_event_block_read(task->thread->engine, &c->socket); 7690Sigor@sysoev.ru 770*771Sigor@sysoev.ru c->socket.write_ready = 0; 7710Sigor@sysoev.ru 772*771Sigor@sysoev.ru if (nxt_fd_event_is_disabled(c->socket.write)) { 773*771Sigor@sysoev.ru nxt_fd_event_enable_write(task->thread->engine, &c->socket); 774*771Sigor@sysoev.ru } 7750Sigor@sysoev.ru } 7760Sigor@sysoev.ru 7770Sigor@sysoev.ru return NXT_AGAIN; 7780Sigor@sysoev.ru 7790Sigor@sysoev.ru case SSL_ERROR_SYSCALL: 7800Sigor@sysoev.ru lib_err = ERR_peek_error(); 7810Sigor@sysoev.ru 7821Sigor@sysoev.ru nxt_debug(task, "ERR_peek_error(): %l", lib_err); 7830Sigor@sysoev.ru 7840Sigor@sysoev.ru if (sys_err != 0 || lib_err != 0) { 7850Sigor@sysoev.ru return NXT_ERROR; 7860Sigor@sysoev.ru } 7870Sigor@sysoev.ru 7880Sigor@sysoev.ru /* A connection was just closed. */ 7890Sigor@sysoev.ru c->socket.closed = 1; 790*771Sigor@sysoev.ru return 0; 7910Sigor@sysoev.ru 7920Sigor@sysoev.ru case SSL_ERROR_ZERO_RETURN: 7930Sigor@sysoev.ru /* A "close notify" alert. */ 7940Sigor@sysoev.ru return 0; 7950Sigor@sysoev.ru 7960Sigor@sysoev.ru default: /* SSL_ERROR_SSL, etc. */ 7970Sigor@sysoev.ru c->socket.error = 1000; /* Nonexistent errno code. */ 7980Sigor@sysoev.ru return NXT_ERROR; 7990Sigor@sysoev.ru } 8000Sigor@sysoev.ru } 8010Sigor@sysoev.ru 8020Sigor@sysoev.ru 8030Sigor@sysoev.ru static void nxt_cdecl 804*771Sigor@sysoev.ru nxt_openssl_conn_error(nxt_task_t *task, nxt_err_t err, const char *fmt, ...) 8050Sigor@sysoev.ru { 8060Sigor@sysoev.ru u_char *p, *end; 8070Sigor@sysoev.ru va_list args; 8080Sigor@sysoev.ru nxt_uint_t level; 8090Sigor@sysoev.ru u_char msg[NXT_MAX_ERROR_STR]; 8100Sigor@sysoev.ru 811*771Sigor@sysoev.ru level = nxt_openssl_log_error_level(err); 8120Sigor@sysoev.ru 813*771Sigor@sysoev.ru if (nxt_log_level_enough(task->log, level)) { 8140Sigor@sysoev.ru 8150Sigor@sysoev.ru end = msg + sizeof(msg); 8160Sigor@sysoev.ru 8170Sigor@sysoev.ru va_start(args, fmt); 8180Sigor@sysoev.ru p = nxt_vsprintf(msg, end, fmt, args); 8190Sigor@sysoev.ru va_end(args); 8200Sigor@sysoev.ru 8210Sigor@sysoev.ru if (err != 0) { 8220Sigor@sysoev.ru p = nxt_sprintf(p, end, " %E", err); 8230Sigor@sysoev.ru } 8240Sigor@sysoev.ru 8250Sigor@sysoev.ru p = nxt_openssl_copy_error(p, end); 8260Sigor@sysoev.ru 827*771Sigor@sysoev.ru nxt_log(task, level, "%*s", p - msg, msg); 8280Sigor@sysoev.ru 8290Sigor@sysoev.ru } else { 8300Sigor@sysoev.ru ERR_clear_error(); 8310Sigor@sysoev.ru } 8320Sigor@sysoev.ru } 8330Sigor@sysoev.ru 8340Sigor@sysoev.ru 8350Sigor@sysoev.ru static nxt_uint_t 836*771Sigor@sysoev.ru nxt_openssl_log_error_level(nxt_err_t err) 8370Sigor@sysoev.ru { 8380Sigor@sysoev.ru switch (ERR_GET_REASON(ERR_peek_error())) { 8390Sigor@sysoev.ru 8400Sigor@sysoev.ru case 0: 84113Sigor@sysoev.ru return nxt_socket_error_level(err); 8420Sigor@sysoev.ru 8430Sigor@sysoev.ru case SSL_R_BAD_CHANGE_CIPHER_SPEC: /* 103 */ 8440Sigor@sysoev.ru case SSL_R_BLOCK_CIPHER_PAD_IS_WRONG: /* 129 */ 8450Sigor@sysoev.ru case SSL_R_DIGEST_CHECK_FAILED: /* 149 */ 8460Sigor@sysoev.ru case SSL_R_ERROR_IN_RECEIVED_CIPHER_LIST: /* 151 */ 8470Sigor@sysoev.ru case SSL_R_EXCESSIVE_MESSAGE_SIZE: /* 152 */ 8480Sigor@sysoev.ru case SSL_R_LENGTH_MISMATCH: /* 159 */ 849*771Sigor@sysoev.ru #ifdef SSL_R_NO_CIPHERS_PASSED 8500Sigor@sysoev.ru case SSL_R_NO_CIPHERS_PASSED: /* 182 */ 851*771Sigor@sysoev.ru #endif 8520Sigor@sysoev.ru case SSL_R_NO_CIPHERS_SPECIFIED: /* 183 */ 8530Sigor@sysoev.ru case SSL_R_NO_COMPRESSION_SPECIFIED: /* 187 */ 8540Sigor@sysoev.ru case SSL_R_NO_SHARED_CIPHER: /* 193 */ 8550Sigor@sysoev.ru case SSL_R_RECORD_LENGTH_MISMATCH: /* 213 */ 8560Sigor@sysoev.ru #ifdef SSL_R_PARSE_TLSEXT 8570Sigor@sysoev.ru case SSL_R_PARSE_TLSEXT: /* 227 */ 8580Sigor@sysoev.ru #endif 8590Sigor@sysoev.ru case SSL_R_UNEXPECTED_MESSAGE: /* 244 */ 8600Sigor@sysoev.ru case SSL_R_UNEXPECTED_RECORD: /* 245 */ 8610Sigor@sysoev.ru case SSL_R_UNKNOWN_ALERT_TYPE: /* 246 */ 8620Sigor@sysoev.ru case SSL_R_UNKNOWN_PROTOCOL: /* 252 */ 8630Sigor@sysoev.ru case SSL_R_WRONG_VERSION_NUMBER: /* 267 */ 8640Sigor@sysoev.ru case SSL_R_DECRYPTION_FAILED_OR_BAD_RECORD_MAC: /* 281 */ 8650Sigor@sysoev.ru #ifdef SSL_R_RENEGOTIATE_EXT_TOO_LONG 8660Sigor@sysoev.ru case SSL_R_RENEGOTIATE_EXT_TOO_LONG: /* 335 */ 8670Sigor@sysoev.ru case SSL_R_RENEGOTIATION_ENCODING_ERR: /* 336 */ 8680Sigor@sysoev.ru case SSL_R_RENEGOTIATION_MISMATCH: /* 337 */ 8690Sigor@sysoev.ru #endif 8700Sigor@sysoev.ru #ifdef SSL_R_UNSAFE_LEGACY_RENEGOTIATION_DISABLED 8710Sigor@sysoev.ru case SSL_R_UNSAFE_LEGACY_RENEGOTIATION_DISABLED: /* 338 */ 8720Sigor@sysoev.ru #endif 8730Sigor@sysoev.ru #ifdef SSL_R_SCSV_RECEIVED_WHEN_RENEGOTIATING 8740Sigor@sysoev.ru case SSL_R_SCSV_RECEIVED_WHEN_RENEGOTIATING: /* 345 */ 8750Sigor@sysoev.ru #endif 8760Sigor@sysoev.ru case 1000:/* SSL_R_SSLV3_ALERT_CLOSE_NOTIFY */ 8770Sigor@sysoev.ru case SSL_R_SSLV3_ALERT_UNEXPECTED_MESSAGE: /* 1010 */ 8780Sigor@sysoev.ru case SSL_R_SSLV3_ALERT_BAD_RECORD_MAC: /* 1020 */ 8790Sigor@sysoev.ru case SSL_R_TLSV1_ALERT_DECRYPTION_FAILED: /* 1021 */ 8800Sigor@sysoev.ru case SSL_R_TLSV1_ALERT_RECORD_OVERFLOW: /* 1022 */ 8810Sigor@sysoev.ru case SSL_R_SSLV3_ALERT_DECOMPRESSION_FAILURE: /* 1030 */ 8820Sigor@sysoev.ru case SSL_R_SSLV3_ALERT_HANDSHAKE_FAILURE: /* 1040 */ 8830Sigor@sysoev.ru case SSL_R_SSLV3_ALERT_ILLEGAL_PARAMETER: /* 1047 */ 8840Sigor@sysoev.ru break; 8850Sigor@sysoev.ru 8860Sigor@sysoev.ru case SSL_R_SSLV3_ALERT_NO_CERTIFICATE: /* 1041 */ 8870Sigor@sysoev.ru case SSL_R_SSLV3_ALERT_BAD_CERTIFICATE: /* 1042 */ 8880Sigor@sysoev.ru case SSL_R_SSLV3_ALERT_UNSUPPORTED_CERTIFICATE: /* 1043 */ 8890Sigor@sysoev.ru case SSL_R_SSLV3_ALERT_CERTIFICATE_REVOKED: /* 1044 */ 8900Sigor@sysoev.ru case SSL_R_SSLV3_ALERT_CERTIFICATE_EXPIRED: /* 1045 */ 8910Sigor@sysoev.ru case SSL_R_SSLV3_ALERT_CERTIFICATE_UNKNOWN: /* 1046 */ 8920Sigor@sysoev.ru case SSL_R_TLSV1_ALERT_UNKNOWN_CA: /* 1048 */ 8930Sigor@sysoev.ru case SSL_R_TLSV1_ALERT_ACCESS_DENIED: /* 1049 */ 8940Sigor@sysoev.ru case SSL_R_TLSV1_ALERT_DECODE_ERROR: /* 1050 */ 8950Sigor@sysoev.ru case SSL_R_TLSV1_ALERT_DECRYPT_ERROR: /* 1051 */ 8960Sigor@sysoev.ru case SSL_R_TLSV1_ALERT_EXPORT_RESTRICTION: /* 1060 */ 8970Sigor@sysoev.ru case SSL_R_TLSV1_ALERT_PROTOCOL_VERSION: /* 1070 */ 8980Sigor@sysoev.ru case SSL_R_TLSV1_ALERT_INSUFFICIENT_SECURITY: /* 1071 */ 8990Sigor@sysoev.ru case SSL_R_TLSV1_ALERT_INTERNAL_ERROR: /* 1080 */ 9000Sigor@sysoev.ru case SSL_R_TLSV1_ALERT_USER_CANCELLED: /* 1090 */ 9010Sigor@sysoev.ru case SSL_R_TLSV1_ALERT_NO_RENEGOTIATION: /* 1100 */ 9020Sigor@sysoev.ru return NXT_LOG_ERR; 9030Sigor@sysoev.ru 9040Sigor@sysoev.ru default: 905564Svbart@nginx.com return NXT_LOG_ALERT; 9060Sigor@sysoev.ru } 9070Sigor@sysoev.ru 9080Sigor@sysoev.ru return NXT_LOG_INFO; 9090Sigor@sysoev.ru } 9100Sigor@sysoev.ru 9110Sigor@sysoev.ru 912*771Sigor@sysoev.ru void nxt_cdecl 913*771Sigor@sysoev.ru nxt_openssl_log_error(nxt_task_t *task, nxt_uint_t level, const char *fmt, ...) 9140Sigor@sysoev.ru { 9150Sigor@sysoev.ru u_char *p, *end; 9160Sigor@sysoev.ru va_list args; 9170Sigor@sysoev.ru u_char msg[NXT_MAX_ERROR_STR]; 9180Sigor@sysoev.ru 9190Sigor@sysoev.ru end = msg + sizeof(msg); 9200Sigor@sysoev.ru 9210Sigor@sysoev.ru va_start(args, fmt); 9220Sigor@sysoev.ru p = nxt_vsprintf(msg, end, fmt, args); 9230Sigor@sysoev.ru va_end(args); 9240Sigor@sysoev.ru 9250Sigor@sysoev.ru p = nxt_openssl_copy_error(p, end); 9260Sigor@sysoev.ru 927*771Sigor@sysoev.ru nxt_log(task, level, "%*s", p - msg, msg); 9280Sigor@sysoev.ru } 9290Sigor@sysoev.ru 9300Sigor@sysoev.ru 931*771Sigor@sysoev.ru u_char * 9320Sigor@sysoev.ru nxt_openssl_copy_error(u_char *p, u_char *end) 9330Sigor@sysoev.ru { 9340Sigor@sysoev.ru int flags; 9350Sigor@sysoev.ru u_long err; 9360Sigor@sysoev.ru nxt_bool_t clear; 9370Sigor@sysoev.ru const char *data, *delimiter; 9380Sigor@sysoev.ru 9390Sigor@sysoev.ru err = ERR_peek_error(); 9400Sigor@sysoev.ru if (err == 0) { 9410Sigor@sysoev.ru return p; 9420Sigor@sysoev.ru } 9430Sigor@sysoev.ru 9440Sigor@sysoev.ru /* Log the most relevant error message ... */ 9450Sigor@sysoev.ru data = ERR_reason_error_string(err); 9460Sigor@sysoev.ru 9470Sigor@sysoev.ru p = nxt_sprintf(p, end, " (%d: %s) (OpenSSL: ", ERR_GET_REASON(err), data); 9480Sigor@sysoev.ru 9490Sigor@sysoev.ru /* 950*771Sigor@sysoev.ru * ... followed by all queued cumbersome OpenSSL error messages 951*771Sigor@sysoev.ru * and drain the error queue. 9520Sigor@sysoev.ru */ 9530Sigor@sysoev.ru delimiter = ""; 9540Sigor@sysoev.ru clear = 0; 9550Sigor@sysoev.ru 9560Sigor@sysoev.ru for ( ;; ) { 9570Sigor@sysoev.ru err = ERR_get_error_line_data(NULL, NULL, &data, &flags); 9580Sigor@sysoev.ru if (err == 0) { 9590Sigor@sysoev.ru break; 9600Sigor@sysoev.ru } 9610Sigor@sysoev.ru 9620Sigor@sysoev.ru p = nxt_sprintf(p, end, "%s", delimiter); 9630Sigor@sysoev.ru 9640Sigor@sysoev.ru ERR_error_string_n(err, (char *) p, end - p); 9650Sigor@sysoev.ru 9660Sigor@sysoev.ru while (p < end && *p != '\0') { 9670Sigor@sysoev.ru p++; 9680Sigor@sysoev.ru } 9690Sigor@sysoev.ru 9700Sigor@sysoev.ru if ((flags & ERR_TXT_STRING) != 0) { 9710Sigor@sysoev.ru p = nxt_sprintf(p, end, ":%s", data); 9720Sigor@sysoev.ru } 9730Sigor@sysoev.ru 9740Sigor@sysoev.ru clear |= ((flags & ERR_TXT_MALLOCED) != 0); 9750Sigor@sysoev.ru 9760Sigor@sysoev.ru delimiter = "; "; 9770Sigor@sysoev.ru } 9780Sigor@sysoev.ru 9790Sigor@sysoev.ru /* Deallocate additional data. */ 9800Sigor@sysoev.ru 9810Sigor@sysoev.ru if (clear) { 9820Sigor@sysoev.ru ERR_clear_error(); 9830Sigor@sysoev.ru } 9840Sigor@sysoev.ru 9850Sigor@sysoev.ru if (p < end) { 9860Sigor@sysoev.ru *p++ = ')'; 9870Sigor@sysoev.ru } 9880Sigor@sysoev.ru 9890Sigor@sysoev.ru return p; 9900Sigor@sysoev.ru } 991