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> 11*1818Smax.romanov@nginx.com #include <openssl/rand.h> 120Sigor@sysoev.ru 130Sigor@sysoev.ru 140Sigor@sysoev.ru typedef struct { 150Sigor@sysoev.ru SSL *session; 16771Sigor@sysoev.ru nxt_conn_t *conn; 170Sigor@sysoev.ru 180Sigor@sysoev.ru int ssl_error; 190Sigor@sysoev.ru uint8_t times; /* 2 bits */ 20771Sigor@sysoev.ru uint8_t handshake; /* 1 bit */ 210Sigor@sysoev.ru 220Sigor@sysoev.ru nxt_buf_mem_t buffer; 230Sigor@sysoev.ru } nxt_openssl_conn_t; 240Sigor@sysoev.ru 250Sigor@sysoev.ru 26771Sigor@sysoev.ru typedef enum { 27771Sigor@sysoev.ru NXT_OPENSSL_HANDSHAKE = 0, 28771Sigor@sysoev.ru NXT_OPENSSL_READ, 29771Sigor@sysoev.ru NXT_OPENSSL_WRITE, 30771Sigor@sysoev.ru NXT_OPENSSL_SHUTDOWN, 31771Sigor@sysoev.ru } nxt_openssl_io_t; 32771Sigor@sysoev.ru 330Sigor@sysoev.ru 34771Sigor@sysoev.ru static nxt_int_t nxt_openssl_library_init(nxt_task_t *task); 35771Sigor@sysoev.ru static void nxt_openssl_library_free(nxt_task_t *task); 36771Sigor@sysoev.ru #if OPENSSL_VERSION_NUMBER < 0x10100004L 37771Sigor@sysoev.ru static nxt_int_t nxt_openssl_locks_init(void); 38771Sigor@sysoev.ru static void nxt_openssl_lock(int mode, int type, const char *file, int line); 39771Sigor@sysoev.ru static unsigned long nxt_openssl_thread_id(void); 40771Sigor@sysoev.ru static void nxt_openssl_locks_free(void); 41771Sigor@sysoev.ru #endif 42771Sigor@sysoev.ru static nxt_int_t nxt_openssl_server_init(nxt_task_t *task, 43771Sigor@sysoev.ru nxt_tls_conf_t *conf); 44833Svbart@nginx.com static nxt_int_t nxt_openssl_chain_file(SSL_CTX *ctx, nxt_fd_t fd); 45771Sigor@sysoev.ru static void nxt_openssl_server_free(nxt_task_t *task, nxt_tls_conf_t *conf); 46771Sigor@sysoev.ru static void nxt_openssl_conn_init(nxt_task_t *task, nxt_tls_conf_t *conf, 4762Sigor@sysoev.ru nxt_conn_t *c); 481Sigor@sysoev.ru static void nxt_openssl_conn_handshake(nxt_task_t *task, void *obj, void *data); 49771Sigor@sysoev.ru static ssize_t nxt_openssl_conn_io_recvbuf(nxt_conn_t *c, nxt_buf_t *b); 50771Sigor@sysoev.ru static ssize_t nxt_openssl_conn_io_sendbuf(nxt_task_t *task, nxt_sendbuf_t *sb); 51771Sigor@sysoev.ru static ssize_t nxt_openssl_conn_io_send(nxt_task_t *task, nxt_sendbuf_t *sb, 52771Sigor@sysoev.ru void *buf, size_t size); 531Sigor@sysoev.ru static void nxt_openssl_conn_io_shutdown(nxt_task_t *task, void *obj, 540Sigor@sysoev.ru void *data); 55771Sigor@sysoev.ru static nxt_int_t nxt_openssl_conn_test_error(nxt_task_t *task, nxt_conn_t *c, 56771Sigor@sysoev.ru int ret, nxt_err_t sys_err, nxt_openssl_io_t io); 57771Sigor@sysoev.ru static void nxt_cdecl nxt_openssl_conn_error(nxt_task_t *task, 58771Sigor@sysoev.ru nxt_err_t err, const char *fmt, ...); 59771Sigor@sysoev.ru static nxt_uint_t nxt_openssl_log_error_level(nxt_err_t err); 600Sigor@sysoev.ru 610Sigor@sysoev.ru 62771Sigor@sysoev.ru const nxt_tls_lib_t nxt_openssl_lib = { 63771Sigor@sysoev.ru .library_init = nxt_openssl_library_init, 64771Sigor@sysoev.ru .library_free = nxt_openssl_library_free, 65771Sigor@sysoev.ru 66771Sigor@sysoev.ru .server_init = nxt_openssl_server_init, 67771Sigor@sysoev.ru .server_free = nxt_openssl_server_free, 680Sigor@sysoev.ru }; 690Sigor@sysoev.ru 700Sigor@sysoev.ru 7162Sigor@sysoev.ru static nxt_conn_io_t nxt_openssl_conn_io = { 72771Sigor@sysoev.ru .read = nxt_conn_io_read, 73771Sigor@sysoev.ru .recvbuf = nxt_openssl_conn_io_recvbuf, 740Sigor@sysoev.ru 75771Sigor@sysoev.ru .write = nxt_conn_io_write, 76771Sigor@sysoev.ru .sendbuf = nxt_openssl_conn_io_sendbuf, 770Sigor@sysoev.ru 78771Sigor@sysoev.ru .shutdown = nxt_openssl_conn_io_shutdown, 790Sigor@sysoev.ru }; 800Sigor@sysoev.ru 810Sigor@sysoev.ru 820Sigor@sysoev.ru static long nxt_openssl_version; 830Sigor@sysoev.ru static int nxt_openssl_connection_index; 840Sigor@sysoev.ru 850Sigor@sysoev.ru 860Sigor@sysoev.ru static nxt_int_t 87771Sigor@sysoev.ru nxt_openssl_library_init(nxt_task_t *task) 880Sigor@sysoev.ru { 890Sigor@sysoev.ru int index; 900Sigor@sysoev.ru 910Sigor@sysoev.ru if (nxt_fast_path(nxt_openssl_version != 0)) { 920Sigor@sysoev.ru return NXT_OK; 930Sigor@sysoev.ru } 940Sigor@sysoev.ru 95771Sigor@sysoev.ru #if OPENSSL_VERSION_NUMBER >= 0x10100003L 96771Sigor@sysoev.ru 97771Sigor@sysoev.ru OPENSSL_init_ssl(OPENSSL_INIT_LOAD_CONFIG, NULL); 980Sigor@sysoev.ru 99771Sigor@sysoev.ru #else 100771Sigor@sysoev.ru { 101771Sigor@sysoev.ru nxt_int_t ret; 102771Sigor@sysoev.ru 103771Sigor@sysoev.ru SSL_load_error_strings(); 104771Sigor@sysoev.ru 105771Sigor@sysoev.ru OPENSSL_config(NULL); 1060Sigor@sysoev.ru 107771Sigor@sysoev.ru /* 108771Sigor@sysoev.ru * SSL_library_init(3): 109771Sigor@sysoev.ru * 110771Sigor@sysoev.ru * SSL_library_init() always returns "1", 111771Sigor@sysoev.ru * so it is safe to discard the return value. 112771Sigor@sysoev.ru */ 113771Sigor@sysoev.ru (void) SSL_library_init(); 114771Sigor@sysoev.ru 115771Sigor@sysoev.ru ret = nxt_openssl_locks_init(); 116771Sigor@sysoev.ru if (nxt_slow_path(ret != NXT_OK)) { 117771Sigor@sysoev.ru return ret; 118771Sigor@sysoev.ru } 119771Sigor@sysoev.ru } 120771Sigor@sysoev.ru 121771Sigor@sysoev.ru #endif 1220Sigor@sysoev.ru 1230Sigor@sysoev.ru nxt_openssl_version = SSLeay(); 1240Sigor@sysoev.ru 125771Sigor@sysoev.ru nxt_log(task, NXT_LOG_INFO, "%s, %xl", 126771Sigor@sysoev.ru SSLeay_version(SSLEAY_VERSION), nxt_openssl_version); 1270Sigor@sysoev.ru 1280Sigor@sysoev.ru #ifndef SSL_OP_NO_COMPRESSION 1290Sigor@sysoev.ru { 1300Sigor@sysoev.ru /* 1310Sigor@sysoev.ru * Disable gzip compression in OpenSSL prior to 1.0.0 1320Sigor@sysoev.ru * version, this saves about 522K per connection. 1330Sigor@sysoev.ru */ 1340Sigor@sysoev.ru int n; 1350Sigor@sysoev.ru STACK_OF(SSL_COMP) *ssl_comp_methods; 1360Sigor@sysoev.ru 1370Sigor@sysoev.ru ssl_comp_methods = SSL_COMP_get_compression_methods(); 1380Sigor@sysoev.ru 1390Sigor@sysoev.ru for (n = sk_SSL_COMP_num(ssl_comp_methods); n != 0; n--) { 1400Sigor@sysoev.ru (void) sk_SSL_COMP_pop(ssl_comp_methods); 1410Sigor@sysoev.ru } 1420Sigor@sysoev.ru } 1430Sigor@sysoev.ru #endif 1440Sigor@sysoev.ru 1450Sigor@sysoev.ru index = SSL_get_ex_new_index(0, NULL, NULL, NULL, NULL); 1460Sigor@sysoev.ru 1470Sigor@sysoev.ru if (index == -1) { 148771Sigor@sysoev.ru nxt_openssl_log_error(task, NXT_LOG_ALERT, 1490Sigor@sysoev.ru "SSL_get_ex_new_index() failed"); 1500Sigor@sysoev.ru return NXT_ERROR; 1510Sigor@sysoev.ru } 1520Sigor@sysoev.ru 1530Sigor@sysoev.ru nxt_openssl_connection_index = index; 1540Sigor@sysoev.ru 1550Sigor@sysoev.ru return NXT_OK; 1560Sigor@sysoev.ru } 1570Sigor@sysoev.ru 1580Sigor@sysoev.ru 159771Sigor@sysoev.ru #if OPENSSL_VERSION_NUMBER >= 0x10100003L 160771Sigor@sysoev.ru 161771Sigor@sysoev.ru static void 162771Sigor@sysoev.ru nxt_openssl_library_free(nxt_task_t *task) 163771Sigor@sysoev.ru { 164771Sigor@sysoev.ru } 165771Sigor@sysoev.ru 166771Sigor@sysoev.ru #else 167771Sigor@sysoev.ru 168771Sigor@sysoev.ru static nxt_thread_mutex_t *nxt_openssl_locks; 169771Sigor@sysoev.ru 1700Sigor@sysoev.ru static nxt_int_t 171771Sigor@sysoev.ru nxt_openssl_locks_init(void) 172771Sigor@sysoev.ru { 173771Sigor@sysoev.ru int i, n; 174771Sigor@sysoev.ru nxt_int_t ret; 175771Sigor@sysoev.ru 176771Sigor@sysoev.ru n = CRYPTO_num_locks(); 177771Sigor@sysoev.ru 178771Sigor@sysoev.ru nxt_openssl_locks = OPENSSL_malloc(n * sizeof(nxt_thread_mutex_t)); 179771Sigor@sysoev.ru if (nxt_slow_path(nxt_openssl_locks == NULL)) { 180771Sigor@sysoev.ru return NXT_ERROR; 181771Sigor@sysoev.ru } 182771Sigor@sysoev.ru 183771Sigor@sysoev.ru for (i = 0; i < n; i++) { 184771Sigor@sysoev.ru ret = nxt_thread_mutex_create(&nxt_openssl_locks[i]); 185771Sigor@sysoev.ru if (nxt_slow_path(ret != NXT_OK)) { 186771Sigor@sysoev.ru return ret; 187771Sigor@sysoev.ru } 188771Sigor@sysoev.ru } 189771Sigor@sysoev.ru 190771Sigor@sysoev.ru CRYPTO_set_locking_callback(nxt_openssl_lock); 191771Sigor@sysoev.ru 192771Sigor@sysoev.ru CRYPTO_set_id_callback(nxt_openssl_thread_id); 193771Sigor@sysoev.ru 194771Sigor@sysoev.ru return NXT_OK; 195771Sigor@sysoev.ru } 196771Sigor@sysoev.ru 197771Sigor@sysoev.ru 198771Sigor@sysoev.ru static void 199771Sigor@sysoev.ru nxt_openssl_lock(int mode, int type, const char *file, int line) 200771Sigor@sysoev.ru { 201771Sigor@sysoev.ru nxt_thread_mutex_t *lock; 202771Sigor@sysoev.ru 203771Sigor@sysoev.ru lock = &nxt_openssl_locks[type]; 204771Sigor@sysoev.ru 205771Sigor@sysoev.ru if ((mode & CRYPTO_LOCK) != 0) { 206771Sigor@sysoev.ru (void) nxt_thread_mutex_lock(lock); 207771Sigor@sysoev.ru 208771Sigor@sysoev.ru } else { 209771Sigor@sysoev.ru (void) nxt_thread_mutex_unlock(lock); 210771Sigor@sysoev.ru } 211771Sigor@sysoev.ru } 212771Sigor@sysoev.ru 213771Sigor@sysoev.ru 214771Sigor@sysoev.ru static u_long 215771Sigor@sysoev.ru nxt_openssl_thread_id(void) 216771Sigor@sysoev.ru { 217771Sigor@sysoev.ru return (u_long) nxt_thread_handle(); 218771Sigor@sysoev.ru } 219771Sigor@sysoev.ru 220771Sigor@sysoev.ru 221771Sigor@sysoev.ru static void 222771Sigor@sysoev.ru nxt_openssl_library_free(nxt_task_t *task) 223771Sigor@sysoev.ru { 224771Sigor@sysoev.ru nxt_openssl_locks_free(); 225771Sigor@sysoev.ru } 226771Sigor@sysoev.ru 227771Sigor@sysoev.ru 228771Sigor@sysoev.ru static void 229771Sigor@sysoev.ru nxt_openssl_locks_free(void) 230771Sigor@sysoev.ru { 231771Sigor@sysoev.ru int i, n; 232771Sigor@sysoev.ru 233771Sigor@sysoev.ru n = CRYPTO_num_locks(); 234771Sigor@sysoev.ru 235771Sigor@sysoev.ru CRYPTO_set_locking_callback(NULL); 236771Sigor@sysoev.ru 237771Sigor@sysoev.ru for (i = 0; i < n; i++) { 238771Sigor@sysoev.ru nxt_thread_mutex_destroy(&nxt_openssl_locks[i]); 239771Sigor@sysoev.ru } 240771Sigor@sysoev.ru 241771Sigor@sysoev.ru OPENSSL_free(nxt_openssl_locks); 242771Sigor@sysoev.ru } 243771Sigor@sysoev.ru 244771Sigor@sysoev.ru #endif 245771Sigor@sysoev.ru 246771Sigor@sysoev.ru 247771Sigor@sysoev.ru static nxt_int_t 248771Sigor@sysoev.ru nxt_openssl_server_init(nxt_task_t *task, nxt_tls_conf_t *conf) 2490Sigor@sysoev.ru { 2500Sigor@sysoev.ru SSL_CTX *ctx; 251774Svbart@nginx.com nxt_fd_t fd; 252774Svbart@nginx.com const char *ciphers, *ca_certificate; 2530Sigor@sysoev.ru STACK_OF(X509_NAME) *list; 2540Sigor@sysoev.ru 2550Sigor@sysoev.ru ctx = SSL_CTX_new(SSLv23_server_method()); 2560Sigor@sysoev.ru if (ctx == NULL) { 257771Sigor@sysoev.ru nxt_openssl_log_error(task, NXT_LOG_ALERT, "SSL_CTX_new() failed"); 2580Sigor@sysoev.ru return NXT_ERROR; 2590Sigor@sysoev.ru } 2600Sigor@sysoev.ru 2610Sigor@sysoev.ru conf->ctx = ctx; 2620Sigor@sysoev.ru conf->conn_init = nxt_openssl_conn_init; 2630Sigor@sysoev.ru 264771Sigor@sysoev.ru #ifdef SSL_OP_NO_RENEGOTIATION 265771Sigor@sysoev.ru /* Renegration is not currently supported. */ 266771Sigor@sysoev.ru SSL_CTX_set_options(ctx, SSL_OP_NO_RENEGOTIATION); 267771Sigor@sysoev.ru #endif 268771Sigor@sysoev.ru 2690Sigor@sysoev.ru #ifdef SSL_OP_NO_COMPRESSION 2700Sigor@sysoev.ru /* 2710Sigor@sysoev.ru * Disable gzip compression in OpenSSL 1.0.0, 2720Sigor@sysoev.ru * this saves about 522K per connection. 2730Sigor@sysoev.ru */ 2740Sigor@sysoev.ru SSL_CTX_set_options(ctx, SSL_OP_NO_COMPRESSION); 2750Sigor@sysoev.ru #endif 2760Sigor@sysoev.ru 2770Sigor@sysoev.ru #ifdef SSL_MODE_RELEASE_BUFFERS 2780Sigor@sysoev.ru 2790Sigor@sysoev.ru if (nxt_openssl_version >= 10001078) { 2800Sigor@sysoev.ru /* 2810Sigor@sysoev.ru * Allow to release read and write buffers in OpenSSL 1.0.0, 2820Sigor@sysoev.ru * this saves about 34K per idle connection. It is not safe 2830Sigor@sysoev.ru * before OpenSSL 1.0.1h (CVE-2010-5298). 2840Sigor@sysoev.ru */ 2850Sigor@sysoev.ru SSL_CTX_set_mode(ctx, SSL_MODE_RELEASE_BUFFERS); 2860Sigor@sysoev.ru } 2870Sigor@sysoev.ru 2880Sigor@sysoev.ru #endif 2890Sigor@sysoev.ru 290774Svbart@nginx.com fd = conf->chain_file; 2910Sigor@sysoev.ru 292774Svbart@nginx.com if (nxt_openssl_chain_file(ctx, fd) != NXT_OK) { 293771Sigor@sysoev.ru nxt_openssl_log_error(task, NXT_LOG_ALERT, 294774Svbart@nginx.com "nxt_openssl_chain_file() failed"); 2950Sigor@sysoev.ru goto fail; 2960Sigor@sysoev.ru } 297774Svbart@nginx.com /* 2980Sigor@sysoev.ru key = conf->certificate_key; 2990Sigor@sysoev.ru 3000Sigor@sysoev.ru if (SSL_CTX_use_PrivateKey_file(ctx, key, SSL_FILETYPE_PEM) == 0) { 301771Sigor@sysoev.ru nxt_openssl_log_error(task, NXT_LOG_ALERT, 3020Sigor@sysoev.ru "SSL_CTX_use_PrivateKey_file(\"%s\") failed", 3030Sigor@sysoev.ru key); 3040Sigor@sysoev.ru goto fail; 3050Sigor@sysoev.ru } 306774Svbart@nginx.com */ 3070Sigor@sysoev.ru ciphers = (conf->ciphers != NULL) ? conf->ciphers : "HIGH:!aNULL:!MD5"; 3080Sigor@sysoev.ru 3090Sigor@sysoev.ru if (SSL_CTX_set_cipher_list(ctx, ciphers) == 0) { 310771Sigor@sysoev.ru nxt_openssl_log_error(task, NXT_LOG_ALERT, 3110Sigor@sysoev.ru "SSL_CTX_set_cipher_list(\"%s\") failed", 3120Sigor@sysoev.ru ciphers); 3130Sigor@sysoev.ru goto fail; 3140Sigor@sysoev.ru } 3150Sigor@sysoev.ru 3160Sigor@sysoev.ru SSL_CTX_set_options(ctx, SSL_OP_CIPHER_SERVER_PREFERENCE); 3170Sigor@sysoev.ru 3180Sigor@sysoev.ru if (conf->ca_certificate != NULL) { 3190Sigor@sysoev.ru 3200Sigor@sysoev.ru /* TODO: verify callback */ 3210Sigor@sysoev.ru SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER, NULL); 3220Sigor@sysoev.ru 3230Sigor@sysoev.ru /* TODO: verify depth */ 3240Sigor@sysoev.ru SSL_CTX_set_verify_depth(ctx, 1); 3250Sigor@sysoev.ru 3260Sigor@sysoev.ru ca_certificate = conf->ca_certificate; 3270Sigor@sysoev.ru 3280Sigor@sysoev.ru if (SSL_CTX_load_verify_locations(ctx, ca_certificate, NULL) == 0) { 329771Sigor@sysoev.ru nxt_openssl_log_error(task, NXT_LOG_ALERT, 3300Sigor@sysoev.ru "SSL_CTX_load_verify_locations(\"%s\") failed", 3310Sigor@sysoev.ru ca_certificate); 3320Sigor@sysoev.ru goto fail; 3330Sigor@sysoev.ru } 3340Sigor@sysoev.ru 3350Sigor@sysoev.ru list = SSL_load_client_CA_file(ca_certificate); 3360Sigor@sysoev.ru 3370Sigor@sysoev.ru if (list == NULL) { 338771Sigor@sysoev.ru nxt_openssl_log_error(task, NXT_LOG_ALERT, 3390Sigor@sysoev.ru "SSL_load_client_CA_file(\"%s\") failed", 3400Sigor@sysoev.ru ca_certificate); 3410Sigor@sysoev.ru goto fail; 3420Sigor@sysoev.ru } 3430Sigor@sysoev.ru 3440Sigor@sysoev.ru /* 3450Sigor@sysoev.ru * SSL_load_client_CA_file() in OpenSSL prior to 0.9.7h and 3460Sigor@sysoev.ru * 0.9.8 versions always leaves an error in the error queue. 3470Sigor@sysoev.ru */ 3480Sigor@sysoev.ru ERR_clear_error(); 3490Sigor@sysoev.ru 3500Sigor@sysoev.ru SSL_CTX_set_client_CA_list(ctx, list); 3510Sigor@sysoev.ru } 3520Sigor@sysoev.ru 3530Sigor@sysoev.ru return NXT_OK; 3540Sigor@sysoev.ru 3550Sigor@sysoev.ru fail: 3560Sigor@sysoev.ru 3570Sigor@sysoev.ru SSL_CTX_free(ctx); 3580Sigor@sysoev.ru 359*1818Smax.romanov@nginx.com #if (OPENSSL_VERSION_NUMBER >= 0x1010100fL \ 360*1818Smax.romanov@nginx.com && OPENSSL_VERSION_NUMBER < 0x1010101fL) 361*1818Smax.romanov@nginx.com RAND_keep_random_devices_open(0); 362*1818Smax.romanov@nginx.com #endif 363*1818Smax.romanov@nginx.com 3640Sigor@sysoev.ru return NXT_ERROR; 3650Sigor@sysoev.ru } 3660Sigor@sysoev.ru 3670Sigor@sysoev.ru 368833Svbart@nginx.com static nxt_int_t 369774Svbart@nginx.com nxt_openssl_chain_file(SSL_CTX *ctx, nxt_fd_t fd) 370774Svbart@nginx.com { 371774Svbart@nginx.com BIO *bio; 372774Svbart@nginx.com X509 *cert, *ca; 373774Svbart@nginx.com long reason; 374774Svbart@nginx.com EVP_PKEY *key; 375833Svbart@nginx.com nxt_int_t ret; 376774Svbart@nginx.com 377774Svbart@nginx.com bio = BIO_new(BIO_s_fd()); 378774Svbart@nginx.com if (bio == NULL) { 379774Svbart@nginx.com return NXT_ERROR; 380774Svbart@nginx.com } 381774Svbart@nginx.com 382774Svbart@nginx.com BIO_set_fd(bio, fd, BIO_CLOSE); 383774Svbart@nginx.com 384774Svbart@nginx.com ret = NXT_ERROR; 385774Svbart@nginx.com 386774Svbart@nginx.com cert = PEM_read_bio_X509_AUX(bio, NULL, NULL, NULL); 387774Svbart@nginx.com if (cert == NULL) { 388774Svbart@nginx.com goto end; 389774Svbart@nginx.com } 390774Svbart@nginx.com 391774Svbart@nginx.com if (SSL_CTX_use_certificate(ctx, cert) != 1) { 392774Svbart@nginx.com goto end; 393774Svbart@nginx.com } 394774Svbart@nginx.com 395774Svbart@nginx.com for ( ;; ) { 396774Svbart@nginx.com ca = PEM_read_bio_X509(bio, NULL, NULL, NULL); 397774Svbart@nginx.com 398774Svbart@nginx.com if (ca == NULL) { 399774Svbart@nginx.com reason = ERR_GET_REASON(ERR_peek_last_error()); 400774Svbart@nginx.com if (reason != PEM_R_NO_START_LINE) { 401774Svbart@nginx.com goto end; 402774Svbart@nginx.com } 403774Svbart@nginx.com 404774Svbart@nginx.com ERR_clear_error(); 405774Svbart@nginx.com break; 406774Svbart@nginx.com } 407774Svbart@nginx.com 408774Svbart@nginx.com /* 409774Svbart@nginx.com * Note that ca isn't freed if it was successfully added to the chain, 410774Svbart@nginx.com * while the main certificate needs a X509_free() call, since 411774Svbart@nginx.com * its reference count is increased by SSL_CTX_use_certificate(). 412774Svbart@nginx.com */ 413808Spluknet@nginx.com #ifdef SSL_CTX_add0_chain_cert 414774Svbart@nginx.com if (SSL_CTX_add0_chain_cert(ctx, ca) != 1) { 415774Svbart@nginx.com #else 416774Svbart@nginx.com if (SSL_CTX_add_extra_chain_cert(ctx, ca) != 1) { 417774Svbart@nginx.com #endif 418774Svbart@nginx.com X509_free(ca); 419774Svbart@nginx.com goto end; 420774Svbart@nginx.com } 421774Svbart@nginx.com } 422774Svbart@nginx.com 423774Svbart@nginx.com if (BIO_reset(bio) != 0) { 424774Svbart@nginx.com goto end; 425774Svbart@nginx.com } 426774Svbart@nginx.com 427774Svbart@nginx.com key = PEM_read_bio_PrivateKey(bio, NULL, NULL, NULL); 428774Svbart@nginx.com if (key == NULL) { 429774Svbart@nginx.com goto end; 430774Svbart@nginx.com } 431774Svbart@nginx.com 432774Svbart@nginx.com if (SSL_CTX_use_PrivateKey(ctx, key) == 1) { 433774Svbart@nginx.com ret = NXT_OK; 434774Svbart@nginx.com } 435774Svbart@nginx.com 436774Svbart@nginx.com EVP_PKEY_free(key); 437774Svbart@nginx.com 438774Svbart@nginx.com end: 439774Svbart@nginx.com 440774Svbart@nginx.com X509_free(cert); 441774Svbart@nginx.com BIO_free(bio); 442774Svbart@nginx.com 443774Svbart@nginx.com return ret; 444774Svbart@nginx.com } 445774Svbart@nginx.com 446774Svbart@nginx.com 4470Sigor@sysoev.ru static void 448771Sigor@sysoev.ru nxt_openssl_server_free(nxt_task_t *task, nxt_tls_conf_t *conf) 4490Sigor@sysoev.ru { 450771Sigor@sysoev.ru SSL_CTX_free(conf->ctx); 451*1818Smax.romanov@nginx.com 452*1818Smax.romanov@nginx.com #if (OPENSSL_VERSION_NUMBER >= 0x1010100fL \ 453*1818Smax.romanov@nginx.com && OPENSSL_VERSION_NUMBER < 0x1010101fL) 454*1818Smax.romanov@nginx.com RAND_keep_random_devices_open(0); 455*1818Smax.romanov@nginx.com #endif 456771Sigor@sysoev.ru } 457771Sigor@sysoev.ru 458771Sigor@sysoev.ru 459771Sigor@sysoev.ru static void 460771Sigor@sysoev.ru nxt_openssl_conn_init(nxt_task_t *task, nxt_tls_conf_t *conf, nxt_conn_t *c) 461771Sigor@sysoev.ru { 462771Sigor@sysoev.ru int ret; 463771Sigor@sysoev.ru SSL *s; 464771Sigor@sysoev.ru SSL_CTX *ctx; 465771Sigor@sysoev.ru nxt_openssl_conn_t *tls; 4660Sigor@sysoev.ru 4670Sigor@sysoev.ru nxt_log_debug(c->socket.log, "openssl conn init"); 4680Sigor@sysoev.ru 469771Sigor@sysoev.ru tls = nxt_mp_zget(c->mem_pool, sizeof(nxt_openssl_conn_t)); 470771Sigor@sysoev.ru if (tls == NULL) { 4710Sigor@sysoev.ru goto fail; 4720Sigor@sysoev.ru } 4730Sigor@sysoev.ru 474771Sigor@sysoev.ru c->u.tls = tls; 475771Sigor@sysoev.ru nxt_buf_mem_set_size(&tls->buffer, conf->buffer_size); 4760Sigor@sysoev.ru 4770Sigor@sysoev.ru ctx = conf->ctx; 4780Sigor@sysoev.ru 4790Sigor@sysoev.ru s = SSL_new(ctx); 4800Sigor@sysoev.ru if (s == NULL) { 481771Sigor@sysoev.ru nxt_openssl_log_error(task, NXT_LOG_ALERT, "SSL_new() failed"); 4820Sigor@sysoev.ru goto fail; 4830Sigor@sysoev.ru } 4840Sigor@sysoev.ru 485771Sigor@sysoev.ru tls->session = s; 486771Sigor@sysoev.ru tls->conn = c; 4870Sigor@sysoev.ru 4880Sigor@sysoev.ru ret = SSL_set_fd(s, c->socket.fd); 4890Sigor@sysoev.ru 4900Sigor@sysoev.ru if (ret == 0) { 491771Sigor@sysoev.ru nxt_openssl_log_error(task, NXT_LOG_ALERT, "SSL_set_fd(%d) failed", 492771Sigor@sysoev.ru c->socket.fd); 4930Sigor@sysoev.ru goto fail; 4940Sigor@sysoev.ru } 4950Sigor@sysoev.ru 4960Sigor@sysoev.ru SSL_set_accept_state(s); 4970Sigor@sysoev.ru 4980Sigor@sysoev.ru if (SSL_set_ex_data(s, nxt_openssl_connection_index, c) == 0) { 499771Sigor@sysoev.ru nxt_openssl_log_error(task, NXT_LOG_ALERT, "SSL_set_ex_data() failed"); 5000Sigor@sysoev.ru goto fail; 5010Sigor@sysoev.ru } 5020Sigor@sysoev.ru 50362Sigor@sysoev.ru c->io = &nxt_openssl_conn_io; 5040Sigor@sysoev.ru c->sendfile = NXT_CONN_SENDFILE_OFF; 5050Sigor@sysoev.ru 5061Sigor@sysoev.ru nxt_openssl_conn_handshake(task, c, c->socket.data); 5070Sigor@sysoev.ru return; 5080Sigor@sysoev.ru 5090Sigor@sysoev.ru fail: 5100Sigor@sysoev.ru 51113Sigor@sysoev.ru nxt_work_queue_add(c->read_work_queue, c->read_state->error_handler, 51213Sigor@sysoev.ru task, c, c->socket.data); 5130Sigor@sysoev.ru } 5140Sigor@sysoev.ru 5150Sigor@sysoev.ru 516771Sigor@sysoev.ru nxt_inline void 517836Sigor@sysoev.ru nxt_openssl_conn_free(nxt_task_t *task, nxt_conn_t *c) 5180Sigor@sysoev.ru { 519836Sigor@sysoev.ru nxt_openssl_conn_t *tls; 520836Sigor@sysoev.ru 521771Sigor@sysoev.ru nxt_debug(task, "openssl conn free"); 5220Sigor@sysoev.ru 523836Sigor@sysoev.ru tls = c->u.tls; 5240Sigor@sysoev.ru 525836Sigor@sysoev.ru if (tls != NULL) { 526836Sigor@sysoev.ru c->u.tls = NULL; 527836Sigor@sysoev.ru nxt_free(tls->buffer.start); 528836Sigor@sysoev.ru SSL_free(tls->session); 529836Sigor@sysoev.ru } 5300Sigor@sysoev.ru } 5310Sigor@sysoev.ru 5320Sigor@sysoev.ru 5330Sigor@sysoev.ru static void 5341Sigor@sysoev.ru nxt_openssl_conn_handshake(nxt_task_t *task, void *obj, void *data) 5350Sigor@sysoev.ru { 536771Sigor@sysoev.ru int ret; 537771Sigor@sysoev.ru nxt_int_t n; 538771Sigor@sysoev.ru nxt_err_t err; 539771Sigor@sysoev.ru nxt_conn_t *c; 540771Sigor@sysoev.ru nxt_work_queue_t *wq; 541771Sigor@sysoev.ru nxt_work_handler_t handler; 542771Sigor@sysoev.ru nxt_openssl_conn_t *tls; 543771Sigor@sysoev.ru const nxt_conn_state_t *state; 5440Sigor@sysoev.ru 5450Sigor@sysoev.ru c = obj; 546836Sigor@sysoev.ru 547836Sigor@sysoev.ru nxt_debug(task, "openssl conn handshake fd:%d", c->socket.fd); 548836Sigor@sysoev.ru 549836Sigor@sysoev.ru if (c->socket.error != 0) { 550836Sigor@sysoev.ru return; 551836Sigor@sysoev.ru } 552836Sigor@sysoev.ru 553771Sigor@sysoev.ru tls = c->u.tls; 5540Sigor@sysoev.ru 555836Sigor@sysoev.ru if (tls == NULL) { 556836Sigor@sysoev.ru return; 557836Sigor@sysoev.ru } 558836Sigor@sysoev.ru 559836Sigor@sysoev.ru nxt_debug(task, "openssl conn handshake: %d times", tls->times); 5600Sigor@sysoev.ru 561771Sigor@sysoev.ru /* "tls->times == 1" is suitable to run SSL_do_handshake() in job. */ 5620Sigor@sysoev.ru 563771Sigor@sysoev.ru ret = SSL_do_handshake(tls->session); 5640Sigor@sysoev.ru 5650Sigor@sysoev.ru err = (ret <= 0) ? nxt_socket_errno : 0; 5660Sigor@sysoev.ru 5671Sigor@sysoev.ru nxt_thread_time_debug_update(task->thread); 5680Sigor@sysoev.ru 5691Sigor@sysoev.ru nxt_debug(task, "SSL_do_handshake(%d): %d err:%d", c->socket.fd, ret, err); 5700Sigor@sysoev.ru 571771Sigor@sysoev.ru state = (c->read_state != NULL) ? c->read_state : c->write_state; 572771Sigor@sysoev.ru 5730Sigor@sysoev.ru if (ret > 0) { 5740Sigor@sysoev.ru /* ret == 1, the handshake was successfully completed. */ 575771Sigor@sysoev.ru tls->handshake = 1; 5760Sigor@sysoev.ru 577771Sigor@sysoev.ru if (c->read_state != NULL) { 578771Sigor@sysoev.ru if (state->io_read_handler != NULL || c->read != NULL) { 579771Sigor@sysoev.ru nxt_conn_read(task->thread->engine, c); 5800Sigor@sysoev.ru return; 5810Sigor@sysoev.ru } 5820Sigor@sysoev.ru 583771Sigor@sysoev.ru } else { 584771Sigor@sysoev.ru if (c->write != NULL) { 585771Sigor@sysoev.ru nxt_conn_write(task->thread->engine, c); 586771Sigor@sysoev.ru return; 587771Sigor@sysoev.ru } 588771Sigor@sysoev.ru } 589771Sigor@sysoev.ru 590771Sigor@sysoev.ru handler = state->ready_handler; 591771Sigor@sysoev.ru 592771Sigor@sysoev.ru } else { 593771Sigor@sysoev.ru c->socket.read_handler = nxt_openssl_conn_handshake; 594771Sigor@sysoev.ru c->socket.write_handler = nxt_openssl_conn_handshake; 595771Sigor@sysoev.ru 596771Sigor@sysoev.ru n = nxt_openssl_conn_test_error(task, c, ret, err, 597771Sigor@sysoev.ru NXT_OPENSSL_HANDSHAKE); 598771Sigor@sysoev.ru switch (n) { 5990Sigor@sysoev.ru 600771Sigor@sysoev.ru case NXT_AGAIN: 601771Sigor@sysoev.ru if (tls->ssl_error == SSL_ERROR_WANT_READ && tls->times < 2) { 602771Sigor@sysoev.ru tls->times++; 603771Sigor@sysoev.ru } 604771Sigor@sysoev.ru 605771Sigor@sysoev.ru return; 606771Sigor@sysoev.ru 607771Sigor@sysoev.ru case 0: 608771Sigor@sysoev.ru handler = state->close_handler; 609771Sigor@sysoev.ru break; 610771Sigor@sysoev.ru 611771Sigor@sysoev.ru default: 612771Sigor@sysoev.ru case NXT_ERROR: 613771Sigor@sysoev.ru nxt_openssl_conn_error(task, err, "SSL_do_handshake(%d) failed", 614771Sigor@sysoev.ru c->socket.fd); 615771Sigor@sysoev.ru 616771Sigor@sysoev.ru handler = state->error_handler; 617771Sigor@sysoev.ru break; 6180Sigor@sysoev.ru } 6190Sigor@sysoev.ru } 6200Sigor@sysoev.ru 621771Sigor@sysoev.ru wq = (c->read_state != NULL) ? c->read_work_queue : c->write_work_queue; 622771Sigor@sysoev.ru 623771Sigor@sysoev.ru nxt_work_queue_add(wq, handler, task, c, data); 6240Sigor@sysoev.ru } 6250Sigor@sysoev.ru 6260Sigor@sysoev.ru 6270Sigor@sysoev.ru static ssize_t 628771Sigor@sysoev.ru nxt_openssl_conn_io_recvbuf(nxt_conn_t *c, nxt_buf_t *b) 6290Sigor@sysoev.ru { 630771Sigor@sysoev.ru int ret; 631771Sigor@sysoev.ru size_t size; 632771Sigor@sysoev.ru nxt_int_t n; 633771Sigor@sysoev.ru nxt_err_t err; 634771Sigor@sysoev.ru nxt_openssl_conn_t *tls; 635771Sigor@sysoev.ru 636771Sigor@sysoev.ru tls = c->u.tls; 637771Sigor@sysoev.ru size = b->mem.end - b->mem.free; 638771Sigor@sysoev.ru 639771Sigor@sysoev.ru ret = SSL_read(tls->session, b->mem.free, size); 640771Sigor@sysoev.ru 641771Sigor@sysoev.ru err = (ret <= 0) ? nxt_socket_errno : 0; 642771Sigor@sysoev.ru 643771Sigor@sysoev.ru nxt_debug(c->socket.task, "SSL_read(%d, %p, %uz): %d err:%d", 644771Sigor@sysoev.ru c->socket.fd, b->mem.free, size, ret, err); 6450Sigor@sysoev.ru 646771Sigor@sysoev.ru if (ret > 0) { 647771Sigor@sysoev.ru return ret; 648771Sigor@sysoev.ru } 6490Sigor@sysoev.ru 650771Sigor@sysoev.ru n = nxt_openssl_conn_test_error(c->socket.task, c, ret, err, 651771Sigor@sysoev.ru NXT_OPENSSL_READ); 652771Sigor@sysoev.ru if (n == NXT_ERROR) { 653771Sigor@sysoev.ru nxt_openssl_conn_error(c->socket.task, err, 654771Sigor@sysoev.ru "SSL_read(%d, %p, %uz) failed", 655771Sigor@sysoev.ru c->socket.fd, b->mem.free, size); 656771Sigor@sysoev.ru } 6570Sigor@sysoev.ru 658771Sigor@sysoev.ru return n; 6590Sigor@sysoev.ru } 6600Sigor@sysoev.ru 6610Sigor@sysoev.ru 6620Sigor@sysoev.ru static ssize_t 663771Sigor@sysoev.ru nxt_openssl_conn_io_sendbuf(nxt_task_t *task, nxt_sendbuf_t *sb) 664771Sigor@sysoev.ru { 665771Sigor@sysoev.ru nxt_uint_t niov; 666771Sigor@sysoev.ru struct iovec iov; 667771Sigor@sysoev.ru 668771Sigor@sysoev.ru niov = nxt_sendbuf_mem_coalesce0(task, sb, &iov, 1); 669771Sigor@sysoev.ru 670771Sigor@sysoev.ru if (niov == 0 && sb->sync) { 671771Sigor@sysoev.ru return 0; 672771Sigor@sysoev.ru } 673771Sigor@sysoev.ru 674771Sigor@sysoev.ru return nxt_openssl_conn_io_send(task, sb, iov.iov_base, iov.iov_len); 675771Sigor@sysoev.ru } 676771Sigor@sysoev.ru 677771Sigor@sysoev.ru 678771Sigor@sysoev.ru static ssize_t 679771Sigor@sysoev.ru nxt_openssl_conn_io_send(nxt_task_t *task, nxt_sendbuf_t *sb, void *buf, 680771Sigor@sysoev.ru size_t size) 6810Sigor@sysoev.ru { 6820Sigor@sysoev.ru int ret; 6830Sigor@sysoev.ru nxt_err_t err; 6840Sigor@sysoev.ru nxt_int_t n; 685771Sigor@sysoev.ru nxt_conn_t *c; 686771Sigor@sysoev.ru nxt_openssl_conn_t *tls; 6870Sigor@sysoev.ru 688771Sigor@sysoev.ru tls = sb->tls; 6890Sigor@sysoev.ru 690771Sigor@sysoev.ru ret = SSL_write(tls->session, buf, size); 6910Sigor@sysoev.ru 6921212Sigor@sysoev.ru err = (ret <= 0) ? nxt_socket_errno : 0; 6930Sigor@sysoev.ru 694771Sigor@sysoev.ru nxt_debug(task, "SSL_write(%d, %p, %uz): %d err:%d", 695771Sigor@sysoev.ru sb->socket, buf, size, ret, err); 6960Sigor@sysoev.ru 6970Sigor@sysoev.ru if (ret > 0) { 6980Sigor@sysoev.ru return ret; 6990Sigor@sysoev.ru } 7000Sigor@sysoev.ru 701771Sigor@sysoev.ru c = tls->conn; 702771Sigor@sysoev.ru c->socket.write_ready = sb->ready; 703771Sigor@sysoev.ru 704771Sigor@sysoev.ru n = nxt_openssl_conn_test_error(task, c, ret, err, NXT_OPENSSL_WRITE); 705771Sigor@sysoev.ru 706771Sigor@sysoev.ru sb->ready = c->socket.write_ready; 7070Sigor@sysoev.ru 7080Sigor@sysoev.ru if (n == NXT_ERROR) { 7091212Sigor@sysoev.ru sb->error = c->socket.error; 710771Sigor@sysoev.ru nxt_openssl_conn_error(task, err, "SSL_write(%d, %p, %uz) failed", 711771Sigor@sysoev.ru sb->socket, buf, size); 7120Sigor@sysoev.ru } 7130Sigor@sysoev.ru 7140Sigor@sysoev.ru return n; 7150Sigor@sysoev.ru } 7160Sigor@sysoev.ru 7170Sigor@sysoev.ru 7180Sigor@sysoev.ru static void 7191Sigor@sysoev.ru nxt_openssl_conn_io_shutdown(nxt_task_t *task, void *obj, void *data) 7200Sigor@sysoev.ru { 7210Sigor@sysoev.ru int ret, mode; 7220Sigor@sysoev.ru SSL *s; 7230Sigor@sysoev.ru nxt_err_t err; 7240Sigor@sysoev.ru nxt_int_t n; 7250Sigor@sysoev.ru nxt_bool_t quiet, once; 72662Sigor@sysoev.ru nxt_conn_t *c; 727771Sigor@sysoev.ru nxt_openssl_conn_t *tls; 7280Sigor@sysoev.ru nxt_work_handler_t handler; 7290Sigor@sysoev.ru 7300Sigor@sysoev.ru c = obj; 7310Sigor@sysoev.ru 732836Sigor@sysoev.ru nxt_debug(task, "openssl conn shutdown fd:%d", c->socket.fd); 733836Sigor@sysoev.ru 734771Sigor@sysoev.ru c->read_state = NULL; 735771Sigor@sysoev.ru tls = c->u.tls; 736836Sigor@sysoev.ru 737836Sigor@sysoev.ru if (tls == NULL) { 738836Sigor@sysoev.ru return; 739836Sigor@sysoev.ru } 740836Sigor@sysoev.ru 741771Sigor@sysoev.ru s = tls->session; 7420Sigor@sysoev.ru 743771Sigor@sysoev.ru if (s == NULL || !tls->handshake) { 744771Sigor@sysoev.ru handler = c->write_state->ready_handler; 7450Sigor@sysoev.ru goto done; 7460Sigor@sysoev.ru } 7470Sigor@sysoev.ru 7480Sigor@sysoev.ru mode = SSL_get_shutdown(s); 7490Sigor@sysoev.ru 7500Sigor@sysoev.ru if (c->socket.timedout || c->socket.error != 0) { 7510Sigor@sysoev.ru quiet = 1; 7520Sigor@sysoev.ru 7530Sigor@sysoev.ru } else if (c->socket.closed && !(mode & SSL_RECEIVED_SHUTDOWN)) { 7540Sigor@sysoev.ru quiet = 1; 7550Sigor@sysoev.ru 7560Sigor@sysoev.ru } else { 7570Sigor@sysoev.ru quiet = 0; 7580Sigor@sysoev.ru } 7590Sigor@sysoev.ru 7600Sigor@sysoev.ru SSL_set_quiet_shutdown(s, quiet); 7610Sigor@sysoev.ru 7620Sigor@sysoev.ru once = 1; 7630Sigor@sysoev.ru 7640Sigor@sysoev.ru for ( ;; ) { 7650Sigor@sysoev.ru SSL_set_shutdown(s, mode); 7660Sigor@sysoev.ru 7670Sigor@sysoev.ru ret = SSL_shutdown(s); 7680Sigor@sysoev.ru 7690Sigor@sysoev.ru err = (ret <= 0) ? nxt_socket_errno : 0; 7700Sigor@sysoev.ru 7711Sigor@sysoev.ru nxt_debug(task, "SSL_shutdown(%d, %d, %b): %d err:%d", 7721Sigor@sysoev.ru c->socket.fd, mode, quiet, ret, err); 7730Sigor@sysoev.ru 7740Sigor@sysoev.ru if (ret > 0) { 7750Sigor@sysoev.ru /* ret == 1, the shutdown was successfully completed. */ 776771Sigor@sysoev.ru handler = c->write_state->ready_handler; 7770Sigor@sysoev.ru goto done; 7780Sigor@sysoev.ru } 7790Sigor@sysoev.ru 7800Sigor@sysoev.ru if (ret == 0) { 7810Sigor@sysoev.ru /* 7820Sigor@sysoev.ru * If SSL_shutdown() returns 0 then it should be called 783771Sigor@sysoev.ru * again. The second SSL_shutdown() call should return 7840Sigor@sysoev.ru * -1/SSL_ERROR_WANT_READ or -1/SSL_ERROR_WANT_WRITE. 7850Sigor@sysoev.ru * OpenSSL prior to 0.9.8m version however never returns 786771Sigor@sysoev.ru * -1 at all. Fortunately, OpenSSL preserves internally 7870Sigor@sysoev.ru * correct status available via SSL_get_error(-1). 7880Sigor@sysoev.ru */ 7890Sigor@sysoev.ru if (once) { 790771Sigor@sysoev.ru once = 0; 7910Sigor@sysoev.ru mode = SSL_get_shutdown(s); 7920Sigor@sysoev.ru continue; 7930Sigor@sysoev.ru } 7940Sigor@sysoev.ru 7950Sigor@sysoev.ru ret = -1; 7960Sigor@sysoev.ru } 7970Sigor@sysoev.ru 7980Sigor@sysoev.ru /* ret == -1 */ 7990Sigor@sysoev.ru 8000Sigor@sysoev.ru break; 8010Sigor@sysoev.ru } 8020Sigor@sysoev.ru 803771Sigor@sysoev.ru c->socket.read_handler = nxt_openssl_conn_io_shutdown; 804771Sigor@sysoev.ru c->socket.write_handler = nxt_openssl_conn_io_shutdown; 805771Sigor@sysoev.ru c->socket.error_handler = c->write_state->error_handler; 806771Sigor@sysoev.ru 807771Sigor@sysoev.ru n = nxt_openssl_conn_test_error(task, c, ret, err, NXT_OPENSSL_SHUTDOWN); 808771Sigor@sysoev.ru 809771Sigor@sysoev.ru switch (n) { 8100Sigor@sysoev.ru 811771Sigor@sysoev.ru case 0: 812771Sigor@sysoev.ru handler = c->write_state->close_handler; 813771Sigor@sysoev.ru break; 814771Sigor@sysoev.ru 815771Sigor@sysoev.ru case NXT_AGAIN: 816771Sigor@sysoev.ru nxt_timer_add(task->thread->engine, &c->read_timer, 5000); 8170Sigor@sysoev.ru return; 818771Sigor@sysoev.ru 819771Sigor@sysoev.ru default: 820771Sigor@sysoev.ru case NXT_ERROR: 821771Sigor@sysoev.ru nxt_openssl_conn_error(task, err, "SSL_shutdown(%d) failed", 822771Sigor@sysoev.ru c->socket.fd); 823771Sigor@sysoev.ru handler = c->write_state->error_handler; 8240Sigor@sysoev.ru } 8250Sigor@sysoev.ru 826771Sigor@sysoev.ru done: 8270Sigor@sysoev.ru 828836Sigor@sysoev.ru nxt_openssl_conn_free(task, c); 8290Sigor@sysoev.ru 83013Sigor@sysoev.ru nxt_work_queue_add(c->write_work_queue, handler, task, c, data); 8310Sigor@sysoev.ru } 8320Sigor@sysoev.ru 8330Sigor@sysoev.ru 8340Sigor@sysoev.ru static nxt_int_t 83562Sigor@sysoev.ru nxt_openssl_conn_test_error(nxt_task_t *task, nxt_conn_t *c, int ret, 836771Sigor@sysoev.ru nxt_err_t sys_err, nxt_openssl_io_t io) 8370Sigor@sysoev.ru { 8380Sigor@sysoev.ru u_long lib_err; 839771Sigor@sysoev.ru nxt_openssl_conn_t *tls; 8400Sigor@sysoev.ru 841771Sigor@sysoev.ru tls = c->u.tls; 8420Sigor@sysoev.ru 843771Sigor@sysoev.ru tls->ssl_error = SSL_get_error(tls->session, ret); 8440Sigor@sysoev.ru 845771Sigor@sysoev.ru nxt_debug(task, "SSL_get_error(): %d", tls->ssl_error); 8460Sigor@sysoev.ru 847771Sigor@sysoev.ru switch (tls->ssl_error) { 8480Sigor@sysoev.ru 8490Sigor@sysoev.ru case SSL_ERROR_WANT_READ: 850990Sigor@sysoev.ru c->socket.read_ready = 0; 851771Sigor@sysoev.ru 852771Sigor@sysoev.ru if (io != NXT_OPENSSL_READ) { 853771Sigor@sysoev.ru nxt_fd_event_block_write(task->thread->engine, &c->socket); 8540Sigor@sysoev.ru 855771Sigor@sysoev.ru if (nxt_fd_event_is_disabled(c->socket.read)) { 856771Sigor@sysoev.ru nxt_fd_event_enable_read(task->thread->engine, &c->socket); 857771Sigor@sysoev.ru } 8580Sigor@sysoev.ru } 8590Sigor@sysoev.ru 8600Sigor@sysoev.ru return NXT_AGAIN; 8610Sigor@sysoev.ru 8620Sigor@sysoev.ru case SSL_ERROR_WANT_WRITE: 863990Sigor@sysoev.ru c->socket.write_ready = 0; 864771Sigor@sysoev.ru 865771Sigor@sysoev.ru if (io != NXT_OPENSSL_WRITE) { 866771Sigor@sysoev.ru nxt_fd_event_block_read(task->thread->engine, &c->socket); 8670Sigor@sysoev.ru 868771Sigor@sysoev.ru if (nxt_fd_event_is_disabled(c->socket.write)) { 869771Sigor@sysoev.ru nxt_fd_event_enable_write(task->thread->engine, &c->socket); 870771Sigor@sysoev.ru } 8710Sigor@sysoev.ru } 8720Sigor@sysoev.ru 8730Sigor@sysoev.ru return NXT_AGAIN; 8740Sigor@sysoev.ru 8750Sigor@sysoev.ru case SSL_ERROR_SYSCALL: 8760Sigor@sysoev.ru lib_err = ERR_peek_error(); 8770Sigor@sysoev.ru 8781Sigor@sysoev.ru nxt_debug(task, "ERR_peek_error(): %l", lib_err); 8790Sigor@sysoev.ru 8800Sigor@sysoev.ru if (sys_err != 0 || lib_err != 0) { 8811212Sigor@sysoev.ru c->socket.error = sys_err; 8820Sigor@sysoev.ru return NXT_ERROR; 8830Sigor@sysoev.ru } 8840Sigor@sysoev.ru 8850Sigor@sysoev.ru /* A connection was just closed. */ 8860Sigor@sysoev.ru c->socket.closed = 1; 887771Sigor@sysoev.ru return 0; 8880Sigor@sysoev.ru 8890Sigor@sysoev.ru case SSL_ERROR_ZERO_RETURN: 8900Sigor@sysoev.ru /* A "close notify" alert. */ 8910Sigor@sysoev.ru return 0; 8920Sigor@sysoev.ru 8930Sigor@sysoev.ru default: /* SSL_ERROR_SSL, etc. */ 8940Sigor@sysoev.ru c->socket.error = 1000; /* Nonexistent errno code. */ 8950Sigor@sysoev.ru return NXT_ERROR; 8960Sigor@sysoev.ru } 8970Sigor@sysoev.ru } 8980Sigor@sysoev.ru 8990Sigor@sysoev.ru 9000Sigor@sysoev.ru static void nxt_cdecl 901771Sigor@sysoev.ru nxt_openssl_conn_error(nxt_task_t *task, nxt_err_t err, const char *fmt, ...) 9020Sigor@sysoev.ru { 9030Sigor@sysoev.ru u_char *p, *end; 9040Sigor@sysoev.ru va_list args; 9050Sigor@sysoev.ru nxt_uint_t level; 9060Sigor@sysoev.ru u_char msg[NXT_MAX_ERROR_STR]; 9070Sigor@sysoev.ru 908771Sigor@sysoev.ru level = nxt_openssl_log_error_level(err); 9090Sigor@sysoev.ru 910771Sigor@sysoev.ru if (nxt_log_level_enough(task->log, level)) { 9110Sigor@sysoev.ru 9120Sigor@sysoev.ru end = msg + sizeof(msg); 9130Sigor@sysoev.ru 9140Sigor@sysoev.ru va_start(args, fmt); 9150Sigor@sysoev.ru p = nxt_vsprintf(msg, end, fmt, args); 9160Sigor@sysoev.ru va_end(args); 9170Sigor@sysoev.ru 9180Sigor@sysoev.ru if (err != 0) { 9190Sigor@sysoev.ru p = nxt_sprintf(p, end, " %E", err); 9200Sigor@sysoev.ru } 9210Sigor@sysoev.ru 9220Sigor@sysoev.ru p = nxt_openssl_copy_error(p, end); 9230Sigor@sysoev.ru 924771Sigor@sysoev.ru nxt_log(task, level, "%*s", p - msg, msg); 9250Sigor@sysoev.ru 9260Sigor@sysoev.ru } else { 9270Sigor@sysoev.ru ERR_clear_error(); 9280Sigor@sysoev.ru } 9290Sigor@sysoev.ru } 9300Sigor@sysoev.ru 9310Sigor@sysoev.ru 9320Sigor@sysoev.ru static nxt_uint_t 933771Sigor@sysoev.ru nxt_openssl_log_error_level(nxt_err_t err) 9340Sigor@sysoev.ru { 9350Sigor@sysoev.ru switch (ERR_GET_REASON(ERR_peek_error())) { 9360Sigor@sysoev.ru 9370Sigor@sysoev.ru case 0: 93813Sigor@sysoev.ru return nxt_socket_error_level(err); 9390Sigor@sysoev.ru 9400Sigor@sysoev.ru case SSL_R_BAD_CHANGE_CIPHER_SPEC: /* 103 */ 9410Sigor@sysoev.ru case SSL_R_BLOCK_CIPHER_PAD_IS_WRONG: /* 129 */ 9420Sigor@sysoev.ru case SSL_R_DIGEST_CHECK_FAILED: /* 149 */ 9430Sigor@sysoev.ru case SSL_R_ERROR_IN_RECEIVED_CIPHER_LIST: /* 151 */ 9440Sigor@sysoev.ru case SSL_R_EXCESSIVE_MESSAGE_SIZE: /* 152 */ 9450Sigor@sysoev.ru case SSL_R_LENGTH_MISMATCH: /* 159 */ 946771Sigor@sysoev.ru #ifdef SSL_R_NO_CIPHERS_PASSED 9470Sigor@sysoev.ru case SSL_R_NO_CIPHERS_PASSED: /* 182 */ 948771Sigor@sysoev.ru #endif 9490Sigor@sysoev.ru case SSL_R_NO_CIPHERS_SPECIFIED: /* 183 */ 9500Sigor@sysoev.ru case SSL_R_NO_COMPRESSION_SPECIFIED: /* 187 */ 9510Sigor@sysoev.ru case SSL_R_NO_SHARED_CIPHER: /* 193 */ 9520Sigor@sysoev.ru case SSL_R_RECORD_LENGTH_MISMATCH: /* 213 */ 9530Sigor@sysoev.ru #ifdef SSL_R_PARSE_TLSEXT 9540Sigor@sysoev.ru case SSL_R_PARSE_TLSEXT: /* 227 */ 9550Sigor@sysoev.ru #endif 9560Sigor@sysoev.ru case SSL_R_UNEXPECTED_MESSAGE: /* 244 */ 9570Sigor@sysoev.ru case SSL_R_UNEXPECTED_RECORD: /* 245 */ 9580Sigor@sysoev.ru case SSL_R_UNKNOWN_ALERT_TYPE: /* 246 */ 9590Sigor@sysoev.ru case SSL_R_UNKNOWN_PROTOCOL: /* 252 */ 9600Sigor@sysoev.ru case SSL_R_WRONG_VERSION_NUMBER: /* 267 */ 9610Sigor@sysoev.ru case SSL_R_DECRYPTION_FAILED_OR_BAD_RECORD_MAC: /* 281 */ 9620Sigor@sysoev.ru #ifdef SSL_R_RENEGOTIATE_EXT_TOO_LONG 9630Sigor@sysoev.ru case SSL_R_RENEGOTIATE_EXT_TOO_LONG: /* 335 */ 9640Sigor@sysoev.ru case SSL_R_RENEGOTIATION_ENCODING_ERR: /* 336 */ 9650Sigor@sysoev.ru case SSL_R_RENEGOTIATION_MISMATCH: /* 337 */ 9660Sigor@sysoev.ru #endif 9670Sigor@sysoev.ru #ifdef SSL_R_UNSAFE_LEGACY_RENEGOTIATION_DISABLED 9680Sigor@sysoev.ru case SSL_R_UNSAFE_LEGACY_RENEGOTIATION_DISABLED: /* 338 */ 9690Sigor@sysoev.ru #endif 9700Sigor@sysoev.ru #ifdef SSL_R_SCSV_RECEIVED_WHEN_RENEGOTIATING 9710Sigor@sysoev.ru case SSL_R_SCSV_RECEIVED_WHEN_RENEGOTIATING: /* 345 */ 9720Sigor@sysoev.ru #endif 9730Sigor@sysoev.ru case 1000:/* SSL_R_SSLV3_ALERT_CLOSE_NOTIFY */ 9740Sigor@sysoev.ru case SSL_R_SSLV3_ALERT_UNEXPECTED_MESSAGE: /* 1010 */ 9750Sigor@sysoev.ru case SSL_R_SSLV3_ALERT_BAD_RECORD_MAC: /* 1020 */ 9760Sigor@sysoev.ru case SSL_R_TLSV1_ALERT_DECRYPTION_FAILED: /* 1021 */ 9770Sigor@sysoev.ru case SSL_R_TLSV1_ALERT_RECORD_OVERFLOW: /* 1022 */ 9780Sigor@sysoev.ru case SSL_R_SSLV3_ALERT_DECOMPRESSION_FAILURE: /* 1030 */ 9790Sigor@sysoev.ru case SSL_R_SSLV3_ALERT_HANDSHAKE_FAILURE: /* 1040 */ 9800Sigor@sysoev.ru case SSL_R_SSLV3_ALERT_ILLEGAL_PARAMETER: /* 1047 */ 9810Sigor@sysoev.ru break; 9820Sigor@sysoev.ru 9830Sigor@sysoev.ru case SSL_R_SSLV3_ALERT_NO_CERTIFICATE: /* 1041 */ 9840Sigor@sysoev.ru case SSL_R_SSLV3_ALERT_BAD_CERTIFICATE: /* 1042 */ 9850Sigor@sysoev.ru case SSL_R_SSLV3_ALERT_UNSUPPORTED_CERTIFICATE: /* 1043 */ 9860Sigor@sysoev.ru case SSL_R_SSLV3_ALERT_CERTIFICATE_REVOKED: /* 1044 */ 9870Sigor@sysoev.ru case SSL_R_SSLV3_ALERT_CERTIFICATE_EXPIRED: /* 1045 */ 9880Sigor@sysoev.ru case SSL_R_SSLV3_ALERT_CERTIFICATE_UNKNOWN: /* 1046 */ 9890Sigor@sysoev.ru case SSL_R_TLSV1_ALERT_UNKNOWN_CA: /* 1048 */ 9900Sigor@sysoev.ru case SSL_R_TLSV1_ALERT_ACCESS_DENIED: /* 1049 */ 9910Sigor@sysoev.ru case SSL_R_TLSV1_ALERT_DECODE_ERROR: /* 1050 */ 9920Sigor@sysoev.ru case SSL_R_TLSV1_ALERT_DECRYPT_ERROR: /* 1051 */ 9930Sigor@sysoev.ru case SSL_R_TLSV1_ALERT_EXPORT_RESTRICTION: /* 1060 */ 9940Sigor@sysoev.ru case SSL_R_TLSV1_ALERT_PROTOCOL_VERSION: /* 1070 */ 9950Sigor@sysoev.ru case SSL_R_TLSV1_ALERT_INSUFFICIENT_SECURITY: /* 1071 */ 9960Sigor@sysoev.ru case SSL_R_TLSV1_ALERT_INTERNAL_ERROR: /* 1080 */ 9970Sigor@sysoev.ru case SSL_R_TLSV1_ALERT_USER_CANCELLED: /* 1090 */ 9980Sigor@sysoev.ru case SSL_R_TLSV1_ALERT_NO_RENEGOTIATION: /* 1100 */ 9990Sigor@sysoev.ru return NXT_LOG_ERR; 10000Sigor@sysoev.ru 10010Sigor@sysoev.ru default: 1002564Svbart@nginx.com return NXT_LOG_ALERT; 10030Sigor@sysoev.ru } 10040Sigor@sysoev.ru 10050Sigor@sysoev.ru return NXT_LOG_INFO; 10060Sigor@sysoev.ru } 10070Sigor@sysoev.ru 10080Sigor@sysoev.ru 1009771Sigor@sysoev.ru void nxt_cdecl 1010771Sigor@sysoev.ru nxt_openssl_log_error(nxt_task_t *task, nxt_uint_t level, const char *fmt, ...) 10110Sigor@sysoev.ru { 10120Sigor@sysoev.ru u_char *p, *end; 10130Sigor@sysoev.ru va_list args; 10140Sigor@sysoev.ru u_char msg[NXT_MAX_ERROR_STR]; 10150Sigor@sysoev.ru 10160Sigor@sysoev.ru end = msg + sizeof(msg); 10170Sigor@sysoev.ru 10180Sigor@sysoev.ru va_start(args, fmt); 10190Sigor@sysoev.ru p = nxt_vsprintf(msg, end, fmt, args); 10200Sigor@sysoev.ru va_end(args); 10210Sigor@sysoev.ru 10220Sigor@sysoev.ru p = nxt_openssl_copy_error(p, end); 10230Sigor@sysoev.ru 1024771Sigor@sysoev.ru nxt_log(task, level, "%*s", p - msg, msg); 10250Sigor@sysoev.ru } 10260Sigor@sysoev.ru 10270Sigor@sysoev.ru 1028771Sigor@sysoev.ru u_char * 10290Sigor@sysoev.ru nxt_openssl_copy_error(u_char *p, u_char *end) 10300Sigor@sysoev.ru { 10310Sigor@sysoev.ru int flags; 10320Sigor@sysoev.ru u_long err; 10330Sigor@sysoev.ru nxt_bool_t clear; 10340Sigor@sysoev.ru const char *data, *delimiter; 10350Sigor@sysoev.ru 10360Sigor@sysoev.ru err = ERR_peek_error(); 10370Sigor@sysoev.ru if (err == 0) { 10380Sigor@sysoev.ru return p; 10390Sigor@sysoev.ru } 10400Sigor@sysoev.ru 10410Sigor@sysoev.ru /* Log the most relevant error message ... */ 10420Sigor@sysoev.ru data = ERR_reason_error_string(err); 10430Sigor@sysoev.ru 10440Sigor@sysoev.ru p = nxt_sprintf(p, end, " (%d: %s) (OpenSSL: ", ERR_GET_REASON(err), data); 10450Sigor@sysoev.ru 10460Sigor@sysoev.ru /* 1047771Sigor@sysoev.ru * ... followed by all queued cumbersome OpenSSL error messages 1048771Sigor@sysoev.ru * and drain the error queue. 10490Sigor@sysoev.ru */ 10500Sigor@sysoev.ru delimiter = ""; 10510Sigor@sysoev.ru clear = 0; 10520Sigor@sysoev.ru 10530Sigor@sysoev.ru for ( ;; ) { 10540Sigor@sysoev.ru err = ERR_get_error_line_data(NULL, NULL, &data, &flags); 10550Sigor@sysoev.ru if (err == 0) { 10560Sigor@sysoev.ru break; 10570Sigor@sysoev.ru } 10580Sigor@sysoev.ru 10590Sigor@sysoev.ru p = nxt_sprintf(p, end, "%s", delimiter); 10600Sigor@sysoev.ru 10610Sigor@sysoev.ru ERR_error_string_n(err, (char *) p, end - p); 10620Sigor@sysoev.ru 10630Sigor@sysoev.ru while (p < end && *p != '\0') { 10640Sigor@sysoev.ru p++; 10650Sigor@sysoev.ru } 10660Sigor@sysoev.ru 10670Sigor@sysoev.ru if ((flags & ERR_TXT_STRING) != 0) { 10680Sigor@sysoev.ru p = nxt_sprintf(p, end, ":%s", data); 10690Sigor@sysoev.ru } 10700Sigor@sysoev.ru 10710Sigor@sysoev.ru clear |= ((flags & ERR_TXT_MALLOCED) != 0); 10720Sigor@sysoev.ru 10730Sigor@sysoev.ru delimiter = "; "; 10740Sigor@sysoev.ru } 10750Sigor@sysoev.ru 10760Sigor@sysoev.ru /* Deallocate additional data. */ 10770Sigor@sysoev.ru 10780Sigor@sysoev.ru if (clear) { 10790Sigor@sysoev.ru ERR_clear_error(); 10800Sigor@sysoev.ru } 10810Sigor@sysoev.ru 10820Sigor@sysoev.ru if (p < end) { 10830Sigor@sysoev.ru *p++ = ')'; 10840Sigor@sysoev.ru } 10850Sigor@sysoev.ru 10860Sigor@sysoev.ru return p; 10870Sigor@sysoev.ru } 1088