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> 81885Sa.suvorov@f5.com #include <nxt_conf.h> 90Sigor@sysoev.ru #include <openssl/ssl.h> 100Sigor@sysoev.ru #include <openssl/conf.h> 110Sigor@sysoev.ru #include <openssl/err.h> 121818Smax.romanov@nginx.com #include <openssl/rand.h> 131828Sa.suvorov@f5.com #include <openssl/x509v3.h> 141942Sa.suvorov@f5.com #include <openssl/bio.h> 151942Sa.suvorov@f5.com #include <openssl/evp.h> 160Sigor@sysoev.ru 170Sigor@sysoev.ru 180Sigor@sysoev.ru typedef struct { 19*1952Svbart@nginx.com SSL *session; 20*1952Svbart@nginx.com nxt_conn_t *conn; 21*1952Svbart@nginx.com 22*1952Svbart@nginx.com int ssl_error; 23*1952Svbart@nginx.com uint8_t times; /* 2 bits */ 24*1952Svbart@nginx.com uint8_t handshake; /* 1 bit */ 25*1952Svbart@nginx.com 26*1952Svbart@nginx.com nxt_tls_conf_t *conf; 27*1952Svbart@nginx.com nxt_buf_mem_t buffer; 28*1952Svbart@nginx.com } nxt_openssl_conn_t; 29*1952Svbart@nginx.com 300Sigor@sysoev.ru 31*1952Svbart@nginx.com struct nxt_tls_ticket_s { 32*1952Svbart@nginx.com u_char name[16]; 33*1952Svbart@nginx.com u_char hmac_key[32]; 34*1952Svbart@nginx.com u_char aes_key[32]; 35*1952Svbart@nginx.com uint8_t size; 36*1952Svbart@nginx.com }; 370Sigor@sysoev.ru 38*1952Svbart@nginx.com 39*1952Svbart@nginx.com struct nxt_tls_tickets_s { 40*1952Svbart@nginx.com nxt_uint_t count; 41*1952Svbart@nginx.com nxt_tls_ticket_t tickets[]; 42*1952Svbart@nginx.com }; 430Sigor@sysoev.ru 440Sigor@sysoev.ru 45771Sigor@sysoev.ru typedef enum { 46771Sigor@sysoev.ru NXT_OPENSSL_HANDSHAKE = 0, 47771Sigor@sysoev.ru NXT_OPENSSL_READ, 48771Sigor@sysoev.ru NXT_OPENSSL_WRITE, 49771Sigor@sysoev.ru NXT_OPENSSL_SHUTDOWN, 50771Sigor@sysoev.ru } nxt_openssl_io_t; 51771Sigor@sysoev.ru 520Sigor@sysoev.ru 53771Sigor@sysoev.ru static nxt_int_t nxt_openssl_library_init(nxt_task_t *task); 54771Sigor@sysoev.ru static void nxt_openssl_library_free(nxt_task_t *task); 55771Sigor@sysoev.ru #if OPENSSL_VERSION_NUMBER < 0x10100004L 56771Sigor@sysoev.ru static nxt_int_t nxt_openssl_locks_init(void); 57771Sigor@sysoev.ru static void nxt_openssl_lock(int mode, int type, const char *file, int line); 58771Sigor@sysoev.ru static unsigned long nxt_openssl_thread_id(void); 59771Sigor@sysoev.ru static void nxt_openssl_locks_free(void); 60771Sigor@sysoev.ru #endif 611920Sa.suvorov@f5.com static nxt_int_t nxt_openssl_server_init(nxt_task_t *task, nxt_mp_t *mp, 621920Sa.suvorov@f5.com nxt_tls_init_t *tls_init, nxt_bool_t last); 631828Sa.suvorov@f5.com static nxt_int_t nxt_openssl_chain_file(nxt_task_t *task, SSL_CTX *ctx, 641828Sa.suvorov@f5.com nxt_tls_conf_t *conf, nxt_mp_t *mp, nxt_bool_t single); 651885Sa.suvorov@f5.com #if (NXT_HAVE_OPENSSL_CONF_CMD) 661885Sa.suvorov@f5.com static nxt_int_t nxt_ssl_conf_commands(nxt_task_t *task, SSL_CTX *ctx, 671885Sa.suvorov@f5.com nxt_conf_value_t *value, nxt_mp_t *mp); 681885Sa.suvorov@f5.com #endif 691942Sa.suvorov@f5.com #if (NXT_HAVE_OPENSSL_TLSEXT) 701942Sa.suvorov@f5.com static nxt_int_t nxt_tls_ticket_keys(nxt_task_t *task, SSL_CTX *ctx, 711942Sa.suvorov@f5.com nxt_tls_init_t *tls_init, nxt_mp_t *mp); 721942Sa.suvorov@f5.com static int nxt_tls_ticket_key_callback(SSL *s, unsigned char *name, 731942Sa.suvorov@f5.com unsigned char *iv, EVP_CIPHER_CTX *ectx,HMAC_CTX *hctx, int enc); 741942Sa.suvorov@f5.com #endif 751920Sa.suvorov@f5.com static void nxt_ssl_session_cache(SSL_CTX *ctx, size_t cache_size, 761920Sa.suvorov@f5.com time_t timeout); 771828Sa.suvorov@f5.com static nxt_uint_t nxt_openssl_cert_get_names(nxt_task_t *task, X509 *cert, 781828Sa.suvorov@f5.com nxt_tls_conf_t *conf, nxt_mp_t *mp); 791828Sa.suvorov@f5.com static nxt_int_t nxt_openssl_bundle_hash_test(nxt_lvlhsh_query_t *lhq, 801828Sa.suvorov@f5.com void *data); 811828Sa.suvorov@f5.com static nxt_int_t nxt_openssl_bundle_hash_insert(nxt_task_t *task, 821828Sa.suvorov@f5.com nxt_lvlhsh_t *lvlhsh, nxt_tls_bundle_hash_item_t *item, nxt_mp_t * mp); 831828Sa.suvorov@f5.com static nxt_int_t nxt_openssl_servername(SSL *s, int *ad, void *arg); 841828Sa.suvorov@f5.com static nxt_tls_bundle_conf_t *nxt_openssl_find_ctx(nxt_tls_conf_t *conf, 851828Sa.suvorov@f5.com nxt_str_t *sn); 86771Sigor@sysoev.ru static void nxt_openssl_server_free(nxt_task_t *task, nxt_tls_conf_t *conf); 87771Sigor@sysoev.ru static void nxt_openssl_conn_init(nxt_task_t *task, nxt_tls_conf_t *conf, 8862Sigor@sysoev.ru nxt_conn_t *c); 891Sigor@sysoev.ru static void nxt_openssl_conn_handshake(nxt_task_t *task, void *obj, void *data); 90771Sigor@sysoev.ru static ssize_t nxt_openssl_conn_io_recvbuf(nxt_conn_t *c, nxt_buf_t *b); 91771Sigor@sysoev.ru static ssize_t nxt_openssl_conn_io_sendbuf(nxt_task_t *task, nxt_sendbuf_t *sb); 92771Sigor@sysoev.ru static ssize_t nxt_openssl_conn_io_send(nxt_task_t *task, nxt_sendbuf_t *sb, 93771Sigor@sysoev.ru void *buf, size_t size); 941Sigor@sysoev.ru static void nxt_openssl_conn_io_shutdown(nxt_task_t *task, void *obj, 950Sigor@sysoev.ru void *data); 96771Sigor@sysoev.ru static nxt_int_t nxt_openssl_conn_test_error(nxt_task_t *task, nxt_conn_t *c, 97771Sigor@sysoev.ru int ret, nxt_err_t sys_err, nxt_openssl_io_t io); 981884Sa.suvorov@f5.com static void nxt_openssl_conn_io_shutdown_timeout(nxt_task_t *task, void *obj, 991884Sa.suvorov@f5.com void *data); 100771Sigor@sysoev.ru static void nxt_cdecl nxt_openssl_conn_error(nxt_task_t *task, 101771Sigor@sysoev.ru nxt_err_t err, const char *fmt, ...); 102771Sigor@sysoev.ru static nxt_uint_t nxt_openssl_log_error_level(nxt_err_t err); 1030Sigor@sysoev.ru 1040Sigor@sysoev.ru 105771Sigor@sysoev.ru const nxt_tls_lib_t nxt_openssl_lib = { 106771Sigor@sysoev.ru .library_init = nxt_openssl_library_init, 107771Sigor@sysoev.ru .library_free = nxt_openssl_library_free, 108771Sigor@sysoev.ru 109771Sigor@sysoev.ru .server_init = nxt_openssl_server_init, 110771Sigor@sysoev.ru .server_free = nxt_openssl_server_free, 1110Sigor@sysoev.ru }; 1120Sigor@sysoev.ru 1130Sigor@sysoev.ru 11462Sigor@sysoev.ru static nxt_conn_io_t nxt_openssl_conn_io = { 115771Sigor@sysoev.ru .read = nxt_conn_io_read, 116771Sigor@sysoev.ru .recvbuf = nxt_openssl_conn_io_recvbuf, 1170Sigor@sysoev.ru 118771Sigor@sysoev.ru .write = nxt_conn_io_write, 119771Sigor@sysoev.ru .sendbuf = nxt_openssl_conn_io_sendbuf, 1200Sigor@sysoev.ru 121771Sigor@sysoev.ru .shutdown = nxt_openssl_conn_io_shutdown, 1220Sigor@sysoev.ru }; 1230Sigor@sysoev.ru 1240Sigor@sysoev.ru 1250Sigor@sysoev.ru static long nxt_openssl_version; 1260Sigor@sysoev.ru static int nxt_openssl_connection_index; 1270Sigor@sysoev.ru 1280Sigor@sysoev.ru 1290Sigor@sysoev.ru static nxt_int_t 130771Sigor@sysoev.ru nxt_openssl_library_init(nxt_task_t *task) 1310Sigor@sysoev.ru { 1320Sigor@sysoev.ru int index; 1330Sigor@sysoev.ru 1340Sigor@sysoev.ru if (nxt_fast_path(nxt_openssl_version != 0)) { 1350Sigor@sysoev.ru return NXT_OK; 1360Sigor@sysoev.ru } 1370Sigor@sysoev.ru 138771Sigor@sysoev.ru #if OPENSSL_VERSION_NUMBER >= 0x10100003L 139771Sigor@sysoev.ru 140771Sigor@sysoev.ru OPENSSL_init_ssl(OPENSSL_INIT_LOAD_CONFIG, NULL); 1410Sigor@sysoev.ru 142771Sigor@sysoev.ru #else 143771Sigor@sysoev.ru { 144771Sigor@sysoev.ru nxt_int_t ret; 145771Sigor@sysoev.ru 146771Sigor@sysoev.ru SSL_load_error_strings(); 147771Sigor@sysoev.ru 148771Sigor@sysoev.ru OPENSSL_config(NULL); 1490Sigor@sysoev.ru 150771Sigor@sysoev.ru /* 151771Sigor@sysoev.ru * SSL_library_init(3): 152771Sigor@sysoev.ru * 153771Sigor@sysoev.ru * SSL_library_init() always returns "1", 154771Sigor@sysoev.ru * so it is safe to discard the return value. 155771Sigor@sysoev.ru */ 156771Sigor@sysoev.ru (void) SSL_library_init(); 157771Sigor@sysoev.ru 158771Sigor@sysoev.ru ret = nxt_openssl_locks_init(); 159771Sigor@sysoev.ru if (nxt_slow_path(ret != NXT_OK)) { 160771Sigor@sysoev.ru return ret; 161771Sigor@sysoev.ru } 162771Sigor@sysoev.ru } 163771Sigor@sysoev.ru 164771Sigor@sysoev.ru #endif 1650Sigor@sysoev.ru 1660Sigor@sysoev.ru nxt_openssl_version = SSLeay(); 1670Sigor@sysoev.ru 168771Sigor@sysoev.ru nxt_log(task, NXT_LOG_INFO, "%s, %xl", 169771Sigor@sysoev.ru SSLeay_version(SSLEAY_VERSION), nxt_openssl_version); 1700Sigor@sysoev.ru 1710Sigor@sysoev.ru #ifndef SSL_OP_NO_COMPRESSION 1720Sigor@sysoev.ru { 1730Sigor@sysoev.ru /* 1740Sigor@sysoev.ru * Disable gzip compression in OpenSSL prior to 1.0.0 1750Sigor@sysoev.ru * version, this saves about 522K per connection. 1760Sigor@sysoev.ru */ 1770Sigor@sysoev.ru int n; 1780Sigor@sysoev.ru STACK_OF(SSL_COMP) *ssl_comp_methods; 1790Sigor@sysoev.ru 1800Sigor@sysoev.ru ssl_comp_methods = SSL_COMP_get_compression_methods(); 1810Sigor@sysoev.ru 1820Sigor@sysoev.ru for (n = sk_SSL_COMP_num(ssl_comp_methods); n != 0; n--) { 1830Sigor@sysoev.ru (void) sk_SSL_COMP_pop(ssl_comp_methods); 1840Sigor@sysoev.ru } 1850Sigor@sysoev.ru } 1860Sigor@sysoev.ru #endif 1870Sigor@sysoev.ru 1880Sigor@sysoev.ru index = SSL_get_ex_new_index(0, NULL, NULL, NULL, NULL); 1890Sigor@sysoev.ru 1900Sigor@sysoev.ru if (index == -1) { 191771Sigor@sysoev.ru nxt_openssl_log_error(task, NXT_LOG_ALERT, 1920Sigor@sysoev.ru "SSL_get_ex_new_index() failed"); 1930Sigor@sysoev.ru return NXT_ERROR; 1940Sigor@sysoev.ru } 1950Sigor@sysoev.ru 1960Sigor@sysoev.ru nxt_openssl_connection_index = index; 1970Sigor@sysoev.ru 1980Sigor@sysoev.ru return NXT_OK; 1990Sigor@sysoev.ru } 2000Sigor@sysoev.ru 2010Sigor@sysoev.ru 202771Sigor@sysoev.ru #if OPENSSL_VERSION_NUMBER >= 0x10100003L 203771Sigor@sysoev.ru 204771Sigor@sysoev.ru static void 205771Sigor@sysoev.ru nxt_openssl_library_free(nxt_task_t *task) 206771Sigor@sysoev.ru { 207771Sigor@sysoev.ru } 208771Sigor@sysoev.ru 209771Sigor@sysoev.ru #else 210771Sigor@sysoev.ru 211771Sigor@sysoev.ru static nxt_thread_mutex_t *nxt_openssl_locks; 212771Sigor@sysoev.ru 2130Sigor@sysoev.ru static nxt_int_t 214771Sigor@sysoev.ru nxt_openssl_locks_init(void) 215771Sigor@sysoev.ru { 216771Sigor@sysoev.ru int i, n; 217771Sigor@sysoev.ru nxt_int_t ret; 218771Sigor@sysoev.ru 219771Sigor@sysoev.ru n = CRYPTO_num_locks(); 220771Sigor@sysoev.ru 221771Sigor@sysoev.ru nxt_openssl_locks = OPENSSL_malloc(n * sizeof(nxt_thread_mutex_t)); 222771Sigor@sysoev.ru if (nxt_slow_path(nxt_openssl_locks == NULL)) { 223771Sigor@sysoev.ru return NXT_ERROR; 224771Sigor@sysoev.ru } 225771Sigor@sysoev.ru 226771Sigor@sysoev.ru for (i = 0; i < n; i++) { 227771Sigor@sysoev.ru ret = nxt_thread_mutex_create(&nxt_openssl_locks[i]); 228771Sigor@sysoev.ru if (nxt_slow_path(ret != NXT_OK)) { 229771Sigor@sysoev.ru return ret; 230771Sigor@sysoev.ru } 231771Sigor@sysoev.ru } 232771Sigor@sysoev.ru 233771Sigor@sysoev.ru CRYPTO_set_locking_callback(nxt_openssl_lock); 234771Sigor@sysoev.ru 235771Sigor@sysoev.ru CRYPTO_set_id_callback(nxt_openssl_thread_id); 236771Sigor@sysoev.ru 237771Sigor@sysoev.ru return NXT_OK; 238771Sigor@sysoev.ru } 239771Sigor@sysoev.ru 240771Sigor@sysoev.ru 241771Sigor@sysoev.ru static void 242771Sigor@sysoev.ru nxt_openssl_lock(int mode, int type, const char *file, int line) 243771Sigor@sysoev.ru { 244771Sigor@sysoev.ru nxt_thread_mutex_t *lock; 245771Sigor@sysoev.ru 246771Sigor@sysoev.ru lock = &nxt_openssl_locks[type]; 247771Sigor@sysoev.ru 248771Sigor@sysoev.ru if ((mode & CRYPTO_LOCK) != 0) { 249771Sigor@sysoev.ru (void) nxt_thread_mutex_lock(lock); 250771Sigor@sysoev.ru 251771Sigor@sysoev.ru } else { 252771Sigor@sysoev.ru (void) nxt_thread_mutex_unlock(lock); 253771Sigor@sysoev.ru } 254771Sigor@sysoev.ru } 255771Sigor@sysoev.ru 256771Sigor@sysoev.ru 257771Sigor@sysoev.ru static u_long 258771Sigor@sysoev.ru nxt_openssl_thread_id(void) 259771Sigor@sysoev.ru { 260771Sigor@sysoev.ru return (u_long) nxt_thread_handle(); 261771Sigor@sysoev.ru } 262771Sigor@sysoev.ru 263771Sigor@sysoev.ru 264771Sigor@sysoev.ru static void 265771Sigor@sysoev.ru nxt_openssl_library_free(nxt_task_t *task) 266771Sigor@sysoev.ru { 267771Sigor@sysoev.ru nxt_openssl_locks_free(); 268771Sigor@sysoev.ru } 269771Sigor@sysoev.ru 270771Sigor@sysoev.ru 271771Sigor@sysoev.ru static void 272771Sigor@sysoev.ru nxt_openssl_locks_free(void) 273771Sigor@sysoev.ru { 274771Sigor@sysoev.ru int i, n; 275771Sigor@sysoev.ru 276771Sigor@sysoev.ru n = CRYPTO_num_locks(); 277771Sigor@sysoev.ru 278771Sigor@sysoev.ru CRYPTO_set_locking_callback(NULL); 279771Sigor@sysoev.ru 280771Sigor@sysoev.ru for (i = 0; i < n; i++) { 281771Sigor@sysoev.ru nxt_thread_mutex_destroy(&nxt_openssl_locks[i]); 282771Sigor@sysoev.ru } 283771Sigor@sysoev.ru 284771Sigor@sysoev.ru OPENSSL_free(nxt_openssl_locks); 285771Sigor@sysoev.ru } 286771Sigor@sysoev.ru 287771Sigor@sysoev.ru #endif 288771Sigor@sysoev.ru 289771Sigor@sysoev.ru 290771Sigor@sysoev.ru static nxt_int_t 2911920Sa.suvorov@f5.com nxt_openssl_server_init(nxt_task_t *task, nxt_mp_t *mp, 2921920Sa.suvorov@f5.com nxt_tls_init_t *tls_init, nxt_bool_t last) 2930Sigor@sysoev.ru { 2941828Sa.suvorov@f5.com SSL_CTX *ctx; 2951828Sa.suvorov@f5.com const char *ciphers, *ca_certificate; 2961920Sa.suvorov@f5.com nxt_tls_conf_t *conf; 2971828Sa.suvorov@f5.com STACK_OF(X509_NAME) *list; 2981828Sa.suvorov@f5.com nxt_tls_bundle_conf_t *bundle; 2990Sigor@sysoev.ru 3000Sigor@sysoev.ru ctx = SSL_CTX_new(SSLv23_server_method()); 3010Sigor@sysoev.ru if (ctx == NULL) { 302771Sigor@sysoev.ru nxt_openssl_log_error(task, NXT_LOG_ALERT, "SSL_CTX_new() failed"); 3030Sigor@sysoev.ru return NXT_ERROR; 3040Sigor@sysoev.ru } 3050Sigor@sysoev.ru 3061920Sa.suvorov@f5.com conf = tls_init->conf; 3071920Sa.suvorov@f5.com 3081828Sa.suvorov@f5.com bundle = conf->bundle; 3091828Sa.suvorov@f5.com nxt_assert(bundle != NULL); 3101828Sa.suvorov@f5.com 3111828Sa.suvorov@f5.com bundle->ctx = ctx; 3120Sigor@sysoev.ru 313771Sigor@sysoev.ru #ifdef SSL_OP_NO_RENEGOTIATION 314771Sigor@sysoev.ru /* Renegration is not currently supported. */ 315771Sigor@sysoev.ru SSL_CTX_set_options(ctx, SSL_OP_NO_RENEGOTIATION); 316771Sigor@sysoev.ru #endif 317771Sigor@sysoev.ru 3180Sigor@sysoev.ru #ifdef SSL_OP_NO_COMPRESSION 3190Sigor@sysoev.ru /* 3200Sigor@sysoev.ru * Disable gzip compression in OpenSSL 1.0.0, 3210Sigor@sysoev.ru * this saves about 522K per connection. 3220Sigor@sysoev.ru */ 3230Sigor@sysoev.ru SSL_CTX_set_options(ctx, SSL_OP_NO_COMPRESSION); 3240Sigor@sysoev.ru #endif 3250Sigor@sysoev.ru 3260Sigor@sysoev.ru #ifdef SSL_MODE_RELEASE_BUFFERS 3270Sigor@sysoev.ru 3280Sigor@sysoev.ru if (nxt_openssl_version >= 10001078) { 3290Sigor@sysoev.ru /* 3300Sigor@sysoev.ru * Allow to release read and write buffers in OpenSSL 1.0.0, 3310Sigor@sysoev.ru * this saves about 34K per idle connection. It is not safe 3320Sigor@sysoev.ru * before OpenSSL 1.0.1h (CVE-2010-5298). 3330Sigor@sysoev.ru */ 3340Sigor@sysoev.ru SSL_CTX_set_mode(ctx, SSL_MODE_RELEASE_BUFFERS); 3350Sigor@sysoev.ru } 3360Sigor@sysoev.ru 3370Sigor@sysoev.ru #endif 3380Sigor@sysoev.ru 3391828Sa.suvorov@f5.com if (nxt_openssl_chain_file(task, ctx, conf, mp, 3401828Sa.suvorov@f5.com last && bundle->next == NULL) 3411828Sa.suvorov@f5.com != NXT_OK) 3421828Sa.suvorov@f5.com { 3430Sigor@sysoev.ru goto fail; 3440Sigor@sysoev.ru } 345774Svbart@nginx.com /* 3460Sigor@sysoev.ru key = conf->certificate_key; 3470Sigor@sysoev.ru 3480Sigor@sysoev.ru if (SSL_CTX_use_PrivateKey_file(ctx, key, SSL_FILETYPE_PEM) == 0) { 349771Sigor@sysoev.ru nxt_openssl_log_error(task, NXT_LOG_ALERT, 3500Sigor@sysoev.ru "SSL_CTX_use_PrivateKey_file(\"%s\") failed", 3510Sigor@sysoev.ru key); 3520Sigor@sysoev.ru goto fail; 3530Sigor@sysoev.ru } 354774Svbart@nginx.com */ 3551885Sa.suvorov@f5.com 3560Sigor@sysoev.ru ciphers = (conf->ciphers != NULL) ? conf->ciphers : "HIGH:!aNULL:!MD5"; 3570Sigor@sysoev.ru 3580Sigor@sysoev.ru if (SSL_CTX_set_cipher_list(ctx, ciphers) == 0) { 359771Sigor@sysoev.ru nxt_openssl_log_error(task, NXT_LOG_ALERT, 3600Sigor@sysoev.ru "SSL_CTX_set_cipher_list(\"%s\") failed", 3610Sigor@sysoev.ru ciphers); 3620Sigor@sysoev.ru goto fail; 3630Sigor@sysoev.ru } 3640Sigor@sysoev.ru 3651885Sa.suvorov@f5.com #if (NXT_HAVE_OPENSSL_CONF_CMD) 3661920Sa.suvorov@f5.com if (tls_init->conf_cmds != NULL 3671920Sa.suvorov@f5.com && nxt_ssl_conf_commands(task, ctx, tls_init->conf_cmds, mp) != NXT_OK) 3681885Sa.suvorov@f5.com { 3691885Sa.suvorov@f5.com goto fail; 3701885Sa.suvorov@f5.com } 3711885Sa.suvorov@f5.com #endif 3721885Sa.suvorov@f5.com 3731920Sa.suvorov@f5.com nxt_ssl_session_cache(ctx, tls_init->cache_size, tls_init->timeout); 3741920Sa.suvorov@f5.com 3751942Sa.suvorov@f5.com #if (NXT_HAVE_OPENSSL_TLSEXT) 3761942Sa.suvorov@f5.com if (nxt_tls_ticket_keys(task, ctx, tls_init, mp) != NXT_OK) { 3771942Sa.suvorov@f5.com goto fail; 3781942Sa.suvorov@f5.com } 3791942Sa.suvorov@f5.com #endif 3801942Sa.suvorov@f5.com 3810Sigor@sysoev.ru SSL_CTX_set_options(ctx, SSL_OP_CIPHER_SERVER_PREFERENCE); 3820Sigor@sysoev.ru 3830Sigor@sysoev.ru if (conf->ca_certificate != NULL) { 3840Sigor@sysoev.ru 3850Sigor@sysoev.ru /* TODO: verify callback */ 3860Sigor@sysoev.ru SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER, NULL); 3870Sigor@sysoev.ru 3880Sigor@sysoev.ru /* TODO: verify depth */ 3890Sigor@sysoev.ru SSL_CTX_set_verify_depth(ctx, 1); 3900Sigor@sysoev.ru 3910Sigor@sysoev.ru ca_certificate = conf->ca_certificate; 3920Sigor@sysoev.ru 3930Sigor@sysoev.ru if (SSL_CTX_load_verify_locations(ctx, ca_certificate, NULL) == 0) { 394771Sigor@sysoev.ru nxt_openssl_log_error(task, NXT_LOG_ALERT, 3950Sigor@sysoev.ru "SSL_CTX_load_verify_locations(\"%s\") failed", 3960Sigor@sysoev.ru ca_certificate); 3970Sigor@sysoev.ru goto fail; 3980Sigor@sysoev.ru } 3990Sigor@sysoev.ru 4000Sigor@sysoev.ru list = SSL_load_client_CA_file(ca_certificate); 4010Sigor@sysoev.ru 4020Sigor@sysoev.ru if (list == NULL) { 403771Sigor@sysoev.ru nxt_openssl_log_error(task, NXT_LOG_ALERT, 4040Sigor@sysoev.ru "SSL_load_client_CA_file(\"%s\") failed", 4050Sigor@sysoev.ru ca_certificate); 4060Sigor@sysoev.ru goto fail; 4070Sigor@sysoev.ru } 4080Sigor@sysoev.ru 4090Sigor@sysoev.ru /* 4100Sigor@sysoev.ru * SSL_load_client_CA_file() in OpenSSL prior to 0.9.7h and 4110Sigor@sysoev.ru * 0.9.8 versions always leaves an error in the error queue. 4120Sigor@sysoev.ru */ 4130Sigor@sysoev.ru ERR_clear_error(); 4140Sigor@sysoev.ru 4150Sigor@sysoev.ru SSL_CTX_set_client_CA_list(ctx, list); 4160Sigor@sysoev.ru } 4170Sigor@sysoev.ru 4181828Sa.suvorov@f5.com if (last) { 4191828Sa.suvorov@f5.com conf->conn_init = nxt_openssl_conn_init; 4201828Sa.suvorov@f5.com 4211828Sa.suvorov@f5.com if (bundle->next != NULL) { 4221828Sa.suvorov@f5.com SSL_CTX_set_tlsext_servername_callback(ctx, nxt_openssl_servername); 4231828Sa.suvorov@f5.com } 4241828Sa.suvorov@f5.com } 4251828Sa.suvorov@f5.com 4260Sigor@sysoev.ru return NXT_OK; 4270Sigor@sysoev.ru 4280Sigor@sysoev.ru fail: 4290Sigor@sysoev.ru 4300Sigor@sysoev.ru SSL_CTX_free(ctx); 4310Sigor@sysoev.ru 4321818Smax.romanov@nginx.com #if (OPENSSL_VERSION_NUMBER >= 0x1010100fL \ 4331818Smax.romanov@nginx.com && OPENSSL_VERSION_NUMBER < 0x1010101fL) 4341818Smax.romanov@nginx.com RAND_keep_random_devices_open(0); 4351818Smax.romanov@nginx.com #endif 4361818Smax.romanov@nginx.com 4370Sigor@sysoev.ru return NXT_ERROR; 4380Sigor@sysoev.ru } 4390Sigor@sysoev.ru 4400Sigor@sysoev.ru 441833Svbart@nginx.com static nxt_int_t 4421828Sa.suvorov@f5.com nxt_openssl_chain_file(nxt_task_t *task, SSL_CTX *ctx, nxt_tls_conf_t *conf, 4431828Sa.suvorov@f5.com nxt_mp_t *mp, nxt_bool_t single) 444774Svbart@nginx.com { 4451828Sa.suvorov@f5.com BIO *bio; 4461828Sa.suvorov@f5.com X509 *cert, *ca; 4471828Sa.suvorov@f5.com long reason; 4481828Sa.suvorov@f5.com EVP_PKEY *key; 4491828Sa.suvorov@f5.com nxt_int_t ret; 4501828Sa.suvorov@f5.com nxt_tls_bundle_conf_t *bundle; 4511828Sa.suvorov@f5.com 4521828Sa.suvorov@f5.com ret = NXT_ERROR; 4531828Sa.suvorov@f5.com cert = NULL; 454774Svbart@nginx.com 455774Svbart@nginx.com bio = BIO_new(BIO_s_fd()); 456774Svbart@nginx.com if (bio == NULL) { 4571828Sa.suvorov@f5.com goto end; 458774Svbart@nginx.com } 459774Svbart@nginx.com 4601828Sa.suvorov@f5.com bundle = conf->bundle; 461774Svbart@nginx.com 4621828Sa.suvorov@f5.com BIO_set_fd(bio, bundle->chain_file, BIO_CLOSE); 463774Svbart@nginx.com 464774Svbart@nginx.com cert = PEM_read_bio_X509_AUX(bio, NULL, NULL, NULL); 465774Svbart@nginx.com if (cert == NULL) { 466774Svbart@nginx.com goto end; 467774Svbart@nginx.com } 468774Svbart@nginx.com 469774Svbart@nginx.com if (SSL_CTX_use_certificate(ctx, cert) != 1) { 470774Svbart@nginx.com goto end; 471774Svbart@nginx.com } 472774Svbart@nginx.com 4731828Sa.suvorov@f5.com if (!single && nxt_openssl_cert_get_names(task, cert, conf, mp) != NXT_OK) { 4741828Sa.suvorov@f5.com goto clean; 4751828Sa.suvorov@f5.com } 4761828Sa.suvorov@f5.com 477774Svbart@nginx.com for ( ;; ) { 478774Svbart@nginx.com ca = PEM_read_bio_X509(bio, NULL, NULL, NULL); 479774Svbart@nginx.com 480774Svbart@nginx.com if (ca == NULL) { 481774Svbart@nginx.com reason = ERR_GET_REASON(ERR_peek_last_error()); 482774Svbart@nginx.com if (reason != PEM_R_NO_START_LINE) { 483774Svbart@nginx.com goto end; 484774Svbart@nginx.com } 485774Svbart@nginx.com 486774Svbart@nginx.com ERR_clear_error(); 487774Svbart@nginx.com break; 488774Svbart@nginx.com } 489774Svbart@nginx.com 490774Svbart@nginx.com /* 491774Svbart@nginx.com * Note that ca isn't freed if it was successfully added to the chain, 492774Svbart@nginx.com * while the main certificate needs a X509_free() call, since 493774Svbart@nginx.com * its reference count is increased by SSL_CTX_use_certificate(). 494774Svbart@nginx.com */ 495808Spluknet@nginx.com #ifdef SSL_CTX_add0_chain_cert 496774Svbart@nginx.com if (SSL_CTX_add0_chain_cert(ctx, ca) != 1) { 497774Svbart@nginx.com #else 498774Svbart@nginx.com if (SSL_CTX_add_extra_chain_cert(ctx, ca) != 1) { 499774Svbart@nginx.com #endif 500774Svbart@nginx.com X509_free(ca); 501774Svbart@nginx.com goto end; 502774Svbart@nginx.com } 503774Svbart@nginx.com } 504774Svbart@nginx.com 505774Svbart@nginx.com if (BIO_reset(bio) != 0) { 506774Svbart@nginx.com goto end; 507774Svbart@nginx.com } 508774Svbart@nginx.com 509774Svbart@nginx.com key = PEM_read_bio_PrivateKey(bio, NULL, NULL, NULL); 510774Svbart@nginx.com if (key == NULL) { 511774Svbart@nginx.com goto end; 512774Svbart@nginx.com } 513774Svbart@nginx.com 514774Svbart@nginx.com if (SSL_CTX_use_PrivateKey(ctx, key) == 1) { 515774Svbart@nginx.com ret = NXT_OK; 516774Svbart@nginx.com } 517774Svbart@nginx.com 518774Svbart@nginx.com EVP_PKEY_free(key); 519774Svbart@nginx.com 520774Svbart@nginx.com end: 521774Svbart@nginx.com 5221828Sa.suvorov@f5.com if (ret != NXT_OK) { 5231828Sa.suvorov@f5.com nxt_openssl_log_error(task, NXT_LOG_ALERT, 5241828Sa.suvorov@f5.com "nxt_openssl_chain_file() failed"); 5251828Sa.suvorov@f5.com } 5261828Sa.suvorov@f5.com 5271828Sa.suvorov@f5.com clean: 5281828Sa.suvorov@f5.com 5291828Sa.suvorov@f5.com BIO_free(bio); 530774Svbart@nginx.com X509_free(cert); 531774Svbart@nginx.com 532774Svbart@nginx.com return ret; 533774Svbart@nginx.com } 534774Svbart@nginx.com 535774Svbart@nginx.com 5361885Sa.suvorov@f5.com #if (NXT_HAVE_OPENSSL_CONF_CMD) 5371885Sa.suvorov@f5.com 5381885Sa.suvorov@f5.com static nxt_int_t 5391885Sa.suvorov@f5.com nxt_ssl_conf_commands(nxt_task_t *task, SSL_CTX *ctx, nxt_conf_value_t *conf, 5401885Sa.suvorov@f5.com nxt_mp_t *mp) 5411885Sa.suvorov@f5.com { 5421885Sa.suvorov@f5.com int ret; 5431885Sa.suvorov@f5.com char *zcmd, *zvalue; 5441885Sa.suvorov@f5.com uint32_t index; 5451885Sa.suvorov@f5.com nxt_str_t cmd, value; 5461885Sa.suvorov@f5.com SSL_CONF_CTX *cctx; 5471885Sa.suvorov@f5.com nxt_conf_value_t *member; 5481885Sa.suvorov@f5.com 5491885Sa.suvorov@f5.com cctx = SSL_CONF_CTX_new(); 5501885Sa.suvorov@f5.com if (nxt_slow_path(cctx == NULL)) { 5511885Sa.suvorov@f5.com nxt_openssl_log_error(task, NXT_LOG_ALERT, 5521885Sa.suvorov@f5.com "SSL_CONF_CTX_new() failed"); 5531885Sa.suvorov@f5.com return NXT_ERROR; 5541885Sa.suvorov@f5.com } 5551885Sa.suvorov@f5.com 5561885Sa.suvorov@f5.com SSL_CONF_CTX_set_flags(cctx, SSL_CONF_FLAG_FILE 5571885Sa.suvorov@f5.com | SSL_CONF_FLAG_SERVER 5581885Sa.suvorov@f5.com | SSL_CONF_FLAG_CERTIFICATE 5591885Sa.suvorov@f5.com | SSL_CONF_FLAG_SHOW_ERRORS); 5601885Sa.suvorov@f5.com 5611885Sa.suvorov@f5.com SSL_CONF_CTX_set_ssl_ctx(cctx, ctx); 5621885Sa.suvorov@f5.com 5631885Sa.suvorov@f5.com index = 0; 5641885Sa.suvorov@f5.com 5651885Sa.suvorov@f5.com for ( ;; ) { 5661885Sa.suvorov@f5.com member = nxt_conf_next_object_member(conf, &cmd, &index); 5671885Sa.suvorov@f5.com if (nxt_slow_path(member == NULL)) { 5681885Sa.suvorov@f5.com break; 5691885Sa.suvorov@f5.com } 5701885Sa.suvorov@f5.com 5711885Sa.suvorov@f5.com nxt_conf_get_string(member, &value); 5721885Sa.suvorov@f5.com 5731885Sa.suvorov@f5.com zcmd = nxt_str_cstrz(mp, &cmd); 5741885Sa.suvorov@f5.com zvalue = nxt_str_cstrz(mp, &value); 5751885Sa.suvorov@f5.com 5761885Sa.suvorov@f5.com if (nxt_slow_path(zcmd == NULL || zvalue == NULL)) { 5771885Sa.suvorov@f5.com goto fail; 5781885Sa.suvorov@f5.com } 5791885Sa.suvorov@f5.com 5801885Sa.suvorov@f5.com ret = SSL_CONF_cmd(cctx, zcmd, zvalue); 5811885Sa.suvorov@f5.com if (ret == -2) { 5821885Sa.suvorov@f5.com nxt_openssl_log_error(task, NXT_LOG_ERR, 5831885Sa.suvorov@f5.com "unknown command \"%s\" in " 5841885Sa.suvorov@f5.com "\"conf_commands\" option", zcmd); 5851885Sa.suvorov@f5.com goto fail; 5861885Sa.suvorov@f5.com } 5871885Sa.suvorov@f5.com 5881885Sa.suvorov@f5.com if (ret <= 0) { 5891885Sa.suvorov@f5.com nxt_openssl_log_error(task, NXT_LOG_ERR, 5901885Sa.suvorov@f5.com "invalid value \"%s\" for command \"%s\" " 5911885Sa.suvorov@f5.com "in \"conf_commands\" option", 5921885Sa.suvorov@f5.com zvalue, zcmd); 5931885Sa.suvorov@f5.com goto fail; 5941885Sa.suvorov@f5.com } 5951885Sa.suvorov@f5.com 5961885Sa.suvorov@f5.com nxt_debug(task, "SSL_CONF_cmd(\"%s\", \"%s\")", zcmd, zvalue); 5971885Sa.suvorov@f5.com } 5981885Sa.suvorov@f5.com 5991885Sa.suvorov@f5.com if (SSL_CONF_CTX_finish(cctx) != 1) { 6001885Sa.suvorov@f5.com nxt_openssl_log_error(task, NXT_LOG_ALERT, 6011885Sa.suvorov@f5.com "SSL_CONF_finish() failed"); 6021885Sa.suvorov@f5.com goto fail; 6031885Sa.suvorov@f5.com } 6041885Sa.suvorov@f5.com 6051885Sa.suvorov@f5.com SSL_CONF_CTX_free(cctx); 6061885Sa.suvorov@f5.com 6071885Sa.suvorov@f5.com return NXT_OK; 6081885Sa.suvorov@f5.com 6091885Sa.suvorov@f5.com fail: 6101885Sa.suvorov@f5.com 6111885Sa.suvorov@f5.com SSL_CONF_CTX_free(cctx); 6121885Sa.suvorov@f5.com 6131885Sa.suvorov@f5.com return NXT_ERROR; 6141885Sa.suvorov@f5.com } 6151885Sa.suvorov@f5.com 6161885Sa.suvorov@f5.com #endif 6171885Sa.suvorov@f5.com 6181942Sa.suvorov@f5.com #if (NXT_HAVE_OPENSSL_TLSEXT) 6191942Sa.suvorov@f5.com 6201942Sa.suvorov@f5.com static nxt_int_t 6211942Sa.suvorov@f5.com nxt_tls_ticket_keys(nxt_task_t *task, SSL_CTX *ctx, nxt_tls_init_t *tls_init, 6221942Sa.suvorov@f5.com nxt_mp_t *mp) 6231942Sa.suvorov@f5.com { 6241942Sa.suvorov@f5.com uint32_t i; 6251942Sa.suvorov@f5.com nxt_int_t ret; 6261942Sa.suvorov@f5.com nxt_str_t value; 6271942Sa.suvorov@f5.com nxt_uint_t count; 6281942Sa.suvorov@f5.com nxt_conf_value_t *member, *tickets_conf; 6291942Sa.suvorov@f5.com nxt_tls_ticket_t *ticket; 6301942Sa.suvorov@f5.com nxt_tls_tickets_t *tickets; 6311942Sa.suvorov@f5.com u_char buf[80]; 6321942Sa.suvorov@f5.com 6331942Sa.suvorov@f5.com tickets_conf = tls_init->tickets_conf; 6341942Sa.suvorov@f5.com 6351942Sa.suvorov@f5.com if (tickets_conf == NULL) { 6361942Sa.suvorov@f5.com goto no_ticket; 6371942Sa.suvorov@f5.com } 6381942Sa.suvorov@f5.com 6391942Sa.suvorov@f5.com if (nxt_conf_type(tickets_conf) == NXT_CONF_BOOLEAN) { 6401942Sa.suvorov@f5.com if (nxt_conf_get_boolean(tickets_conf) == 0) { 6411942Sa.suvorov@f5.com goto no_ticket; 6421942Sa.suvorov@f5.com } 6431942Sa.suvorov@f5.com 6441942Sa.suvorov@f5.com return NXT_OK; 6451942Sa.suvorov@f5.com } 6461942Sa.suvorov@f5.com 6471942Sa.suvorov@f5.com if (nxt_conf_type(tickets_conf) == NXT_CONF_ARRAY) { 6481942Sa.suvorov@f5.com count = nxt_conf_array_elements_count(tickets_conf); 6491942Sa.suvorov@f5.com 6501942Sa.suvorov@f5.com if (count == 0) { 6511942Sa.suvorov@f5.com goto no_ticket; 6521942Sa.suvorov@f5.com } 6531942Sa.suvorov@f5.com 6541942Sa.suvorov@f5.com } else { 6551942Sa.suvorov@f5.com /* nxt_conf_type(tickets_conf) == NXT_CONF_STRING */ 6561942Sa.suvorov@f5.com count = 1; 6571942Sa.suvorov@f5.com } 6581942Sa.suvorov@f5.com 6591942Sa.suvorov@f5.com #ifdef SSL_CTRL_SET_TLSEXT_TICKET_KEY_CB 6601942Sa.suvorov@f5.com 6611942Sa.suvorov@f5.com tickets = nxt_mp_get(mp, sizeof(nxt_tls_tickets_t) 6621942Sa.suvorov@f5.com + count * sizeof(nxt_tls_ticket_t)); 6631942Sa.suvorov@f5.com if (nxt_slow_path(tickets == NULL)) { 6641942Sa.suvorov@f5.com return NXT_ERROR; 6651942Sa.suvorov@f5.com } 6661942Sa.suvorov@f5.com 6671942Sa.suvorov@f5.com tickets->count = count; 6681942Sa.suvorov@f5.com tls_init->conf->tickets = tickets; 6691942Sa.suvorov@f5.com i = 0; 6701942Sa.suvorov@f5.com 6711942Sa.suvorov@f5.com do { 6721942Sa.suvorov@f5.com ticket = &tickets->tickets[i]; 6731942Sa.suvorov@f5.com 6741942Sa.suvorov@f5.com i++; 6751942Sa.suvorov@f5.com 6761942Sa.suvorov@f5.com if (nxt_conf_type(tickets_conf) == NXT_CONF_ARRAY) { 6771942Sa.suvorov@f5.com member = nxt_conf_get_array_element(tickets_conf, count - i); 6781942Sa.suvorov@f5.com if (member == NULL) { 6791942Sa.suvorov@f5.com break; 6801942Sa.suvorov@f5.com } 6811942Sa.suvorov@f5.com 6821942Sa.suvorov@f5.com } else { 6831942Sa.suvorov@f5.com /* nxt_conf_type(tickets_conf) == NXT_CONF_STRING */ 6841942Sa.suvorov@f5.com member = tickets_conf; 6851942Sa.suvorov@f5.com } 6861942Sa.suvorov@f5.com 6871942Sa.suvorov@f5.com nxt_conf_get_string(member, &value); 6881942Sa.suvorov@f5.com 6891942Sa.suvorov@f5.com ret = nxt_openssl_base64_decode(buf, 80, value.start, value.length); 6901942Sa.suvorov@f5.com if (nxt_slow_path(ret == NXT_ERROR)) { 6911942Sa.suvorov@f5.com return NXT_ERROR; 6921942Sa.suvorov@f5.com } 6931942Sa.suvorov@f5.com 694*1952Svbart@nginx.com nxt_memcpy(ticket->name, buf, 16); 695*1952Svbart@nginx.com 6961942Sa.suvorov@f5.com if (ret == 48) { 6971942Sa.suvorov@f5.com nxt_memcpy(ticket->aes_key, buf + 16, 16); 6981942Sa.suvorov@f5.com nxt_memcpy(ticket->hmac_key, buf + 32, 16); 699*1952Svbart@nginx.com ticket->size = 16; 7001942Sa.suvorov@f5.com 7011942Sa.suvorov@f5.com } else { 7021942Sa.suvorov@f5.com nxt_memcpy(ticket->hmac_key, buf + 16, 32); 7031942Sa.suvorov@f5.com nxt_memcpy(ticket->aes_key, buf + 48, 32); 704*1952Svbart@nginx.com ticket->size = 32; 7051942Sa.suvorov@f5.com } 7061942Sa.suvorov@f5.com 7071942Sa.suvorov@f5.com } while (i < count); 7081942Sa.suvorov@f5.com 7091942Sa.suvorov@f5.com if (SSL_CTX_set_tlsext_ticket_key_cb(ctx, nxt_tls_ticket_key_callback) 7101942Sa.suvorov@f5.com == 0) 7111942Sa.suvorov@f5.com { 7121942Sa.suvorov@f5.com nxt_openssl_log_error(task, NXT_LOG_ALERT, 7131942Sa.suvorov@f5.com "Unit was built with Session Tickets support, however, " 7141942Sa.suvorov@f5.com "now it is linked dynamically to an OpenSSL library " 7151942Sa.suvorov@f5.com "which has no tlsext support, therefore Session Tickets " 7161942Sa.suvorov@f5.com "are not available"); 7171942Sa.suvorov@f5.com 7181942Sa.suvorov@f5.com return NXT_ERROR; 7191942Sa.suvorov@f5.com } 7201942Sa.suvorov@f5.com 7211942Sa.suvorov@f5.com return NXT_OK; 7221942Sa.suvorov@f5.com 7231942Sa.suvorov@f5.com #else 7241942Sa.suvorov@f5.com nxt_alert(task, "Setting custom session ticket keys is not supported with " 7251942Sa.suvorov@f5.com "this version of OpenSSL library"); 7261942Sa.suvorov@f5.com 7271942Sa.suvorov@f5.com return NXT_ERROR; 7281942Sa.suvorov@f5.com 7291942Sa.suvorov@f5.com #endif 7301942Sa.suvorov@f5.com 7311942Sa.suvorov@f5.com no_ticket: 7321942Sa.suvorov@f5.com 7331942Sa.suvorov@f5.com SSL_CTX_set_options(ctx, SSL_OP_NO_TICKET); 7341942Sa.suvorov@f5.com 7351942Sa.suvorov@f5.com return NXT_OK; 7361942Sa.suvorov@f5.com } 7371942Sa.suvorov@f5.com 7381942Sa.suvorov@f5.com 7391942Sa.suvorov@f5.com #ifdef SSL_CTRL_SET_TLSEXT_TICKET_KEY_CB 7401942Sa.suvorov@f5.com 7411942Sa.suvorov@f5.com static int 7421942Sa.suvorov@f5.com nxt_tls_ticket_key_callback(SSL *s, unsigned char *name, unsigned char *iv, 7431942Sa.suvorov@f5.com EVP_CIPHER_CTX *ectx, HMAC_CTX *hctx, int enc) 7441942Sa.suvorov@f5.com { 7451942Sa.suvorov@f5.com nxt_uint_t i; 7461942Sa.suvorov@f5.com nxt_conn_t *c; 7471942Sa.suvorov@f5.com const EVP_MD *digest; 7481942Sa.suvorov@f5.com const EVP_CIPHER *cipher; 7491942Sa.suvorov@f5.com nxt_tls_ticket_t *ticket; 7501942Sa.suvorov@f5.com nxt_openssl_conn_t *tls; 7511942Sa.suvorov@f5.com 7521942Sa.suvorov@f5.com c = SSL_get_ex_data(s, nxt_openssl_connection_index); 7531942Sa.suvorov@f5.com 7541942Sa.suvorov@f5.com if (nxt_slow_path(c == NULL)) { 7551942Sa.suvorov@f5.com nxt_thread_log_alert("SSL_get_ex_data() failed"); 7561942Sa.suvorov@f5.com return -1; 7571942Sa.suvorov@f5.com } 7581942Sa.suvorov@f5.com 7591942Sa.suvorov@f5.com tls = c->u.tls; 7601942Sa.suvorov@f5.com ticket = tls->conf->tickets->tickets; 7611942Sa.suvorov@f5.com 762*1952Svbart@nginx.com i = 0; 7631942Sa.suvorov@f5.com 7641942Sa.suvorov@f5.com if (enc == 1) { 7651942Sa.suvorov@f5.com /* encrypt session ticket */ 7661942Sa.suvorov@f5.com 7671942Sa.suvorov@f5.com nxt_debug(c->socket.task, "TLS session ticket encrypt"); 7681942Sa.suvorov@f5.com 769*1952Svbart@nginx.com cipher = (ticket[0].size == 16) ? EVP_aes_128_cbc() : EVP_aes_256_cbc(); 7701942Sa.suvorov@f5.com 7711942Sa.suvorov@f5.com if (RAND_bytes(iv, EVP_CIPHER_iv_length(cipher)) != 1) { 7721942Sa.suvorov@f5.com nxt_openssl_log_error(c->socket.task, NXT_LOG_ALERT, 7731942Sa.suvorov@f5.com "RAND_bytes() failed"); 7741942Sa.suvorov@f5.com return -1; 7751942Sa.suvorov@f5.com } 7761942Sa.suvorov@f5.com 7771942Sa.suvorov@f5.com nxt_memcpy(name, ticket[0].name, 16); 7781942Sa.suvorov@f5.com 7791942Sa.suvorov@f5.com } else { 7801942Sa.suvorov@f5.com /* decrypt session ticket */ 7811942Sa.suvorov@f5.com 782*1952Svbart@nginx.com do { 7831942Sa.suvorov@f5.com if (nxt_memcmp(name, ticket[i].name, 16) == 0) { 7841942Sa.suvorov@f5.com goto found; 7851942Sa.suvorov@f5.com } 786*1952Svbart@nginx.com 787*1952Svbart@nginx.com } while (++i < tls->conf->tickets->count); 7881942Sa.suvorov@f5.com 7891942Sa.suvorov@f5.com nxt_debug(c->socket.task, "TLS session ticket decrypt, key not found"); 7901942Sa.suvorov@f5.com 7911942Sa.suvorov@f5.com return 0; 7921942Sa.suvorov@f5.com 7931942Sa.suvorov@f5.com found: 7941942Sa.suvorov@f5.com 7951942Sa.suvorov@f5.com nxt_debug(c->socket.task, 7961942Sa.suvorov@f5.com "TLS session ticket decrypt, key number: \"%d\"", i); 7971942Sa.suvorov@f5.com 798*1952Svbart@nginx.com enc = (i == 0) ? 1 : 2 /* renew */; 799*1952Svbart@nginx.com 800*1952Svbart@nginx.com cipher = (ticket[i].size == 16) ? EVP_aes_128_cbc() : EVP_aes_256_cbc(); 801*1952Svbart@nginx.com } 8021942Sa.suvorov@f5.com 803*1952Svbart@nginx.com if (EVP_DecryptInit_ex(ectx, cipher, NULL, ticket[i].aes_key, iv) != 1) { 804*1952Svbart@nginx.com nxt_openssl_log_error(c->socket.task, NXT_LOG_ALERT, 805*1952Svbart@nginx.com "EVP_DecryptInit_ex() failed"); 806*1952Svbart@nginx.com return -1; 807*1952Svbart@nginx.com } 8081942Sa.suvorov@f5.com 809*1952Svbart@nginx.com #ifdef OPENSSL_NO_SHA256 810*1952Svbart@nginx.com digest = EVP_sha1(); 811*1952Svbart@nginx.com #else 812*1952Svbart@nginx.com digest = EVP_sha256(); 813*1952Svbart@nginx.com #endif 8141942Sa.suvorov@f5.com 815*1952Svbart@nginx.com if (HMAC_Init_ex(hctx, ticket[i].hmac_key, ticket[i].size, digest, NULL) 816*1952Svbart@nginx.com != 1) 817*1952Svbart@nginx.com { 818*1952Svbart@nginx.com nxt_openssl_log_error(c->socket.task, NXT_LOG_ALERT, 819*1952Svbart@nginx.com "HMAC_Init_ex() failed"); 820*1952Svbart@nginx.com return -1; 821*1952Svbart@nginx.com } 8221942Sa.suvorov@f5.com 823*1952Svbart@nginx.com return enc; 8241942Sa.suvorov@f5.com } 8251942Sa.suvorov@f5.com 8261942Sa.suvorov@f5.com #endif /* SSL_CTRL_SET_TLSEXT_TICKET_KEY_CB */ 8271942Sa.suvorov@f5.com 8281942Sa.suvorov@f5.com #endif /* NXT_HAVE_OPENSSL_TLSEXT */ 8291942Sa.suvorov@f5.com 8301885Sa.suvorov@f5.com 8311920Sa.suvorov@f5.com static void 8321920Sa.suvorov@f5.com nxt_ssl_session_cache(SSL_CTX *ctx, size_t cache_size, time_t timeout) 8331920Sa.suvorov@f5.com { 8341920Sa.suvorov@f5.com if (cache_size == 0) { 8351920Sa.suvorov@f5.com SSL_CTX_set_session_cache_mode(ctx, SSL_SESS_CACHE_OFF); 8361920Sa.suvorov@f5.com return; 8371920Sa.suvorov@f5.com } 8381920Sa.suvorov@f5.com 8391920Sa.suvorov@f5.com SSL_CTX_set_session_cache_mode(ctx, SSL_SESS_CACHE_SERVER); 8401920Sa.suvorov@f5.com 8411920Sa.suvorov@f5.com SSL_CTX_sess_set_cache_size(ctx, cache_size); 8421920Sa.suvorov@f5.com 8431920Sa.suvorov@f5.com SSL_CTX_set_timeout(ctx, (long) timeout); 8441920Sa.suvorov@f5.com } 8451920Sa.suvorov@f5.com 8461920Sa.suvorov@f5.com 8471828Sa.suvorov@f5.com static nxt_uint_t 8481828Sa.suvorov@f5.com nxt_openssl_cert_get_names(nxt_task_t *task, X509 *cert, nxt_tls_conf_t *conf, 8491828Sa.suvorov@f5.com nxt_mp_t *mp) 8501828Sa.suvorov@f5.com { 8511828Sa.suvorov@f5.com int len; 8521828Sa.suvorov@f5.com nxt_str_t domain, str; 8531828Sa.suvorov@f5.com X509_NAME *x509_name; 8541828Sa.suvorov@f5.com nxt_uint_t i, n; 8551828Sa.suvorov@f5.com GENERAL_NAME *name; 8561828Sa.suvorov@f5.com nxt_tls_bundle_conf_t *bundle; 8571828Sa.suvorov@f5.com STACK_OF(GENERAL_NAME) *alt_names; 8581828Sa.suvorov@f5.com nxt_tls_bundle_hash_item_t *item; 8591828Sa.suvorov@f5.com 8601828Sa.suvorov@f5.com bundle = conf->bundle; 8611828Sa.suvorov@f5.com 8621828Sa.suvorov@f5.com alt_names = X509_get_ext_d2i(cert, NID_subject_alt_name, NULL, NULL); 8631828Sa.suvorov@f5.com 8641828Sa.suvorov@f5.com if (alt_names != NULL) { 8651828Sa.suvorov@f5.com n = sk_GENERAL_NAME_num(alt_names); 8661828Sa.suvorov@f5.com 8671828Sa.suvorov@f5.com for (i = 0; i != n; i++) { 8681828Sa.suvorov@f5.com name = sk_GENERAL_NAME_value(alt_names, i); 8691828Sa.suvorov@f5.com 8701828Sa.suvorov@f5.com if (name->type != GEN_DNS) { 8711828Sa.suvorov@f5.com continue; 8721828Sa.suvorov@f5.com } 8731828Sa.suvorov@f5.com 8741828Sa.suvorov@f5.com str.length = ASN1_STRING_length(name->d.dNSName); 8751828Sa.suvorov@f5.com #if OPENSSL_VERSION_NUMBER > 0x10100000L 8761828Sa.suvorov@f5.com str.start = (u_char *) ASN1_STRING_get0_data(name->d.dNSName); 8771828Sa.suvorov@f5.com #else 8781828Sa.suvorov@f5.com str.start = ASN1_STRING_data(name->d.dNSName); 8791828Sa.suvorov@f5.com #endif 8801828Sa.suvorov@f5.com 8811828Sa.suvorov@f5.com domain.start = nxt_mp_nget(mp, str.length); 8821828Sa.suvorov@f5.com if (nxt_slow_path(domain.start == NULL)) { 8831828Sa.suvorov@f5.com goto fail; 8841828Sa.suvorov@f5.com } 8851828Sa.suvorov@f5.com 8861828Sa.suvorov@f5.com domain.length = str.length; 8871828Sa.suvorov@f5.com nxt_memcpy_lowcase(domain.start, str.start, str.length); 8881828Sa.suvorov@f5.com 8891828Sa.suvorov@f5.com item = nxt_mp_get(mp, sizeof(nxt_tls_bundle_hash_item_t)); 8901828Sa.suvorov@f5.com if (nxt_slow_path(item == NULL)) { 8911828Sa.suvorov@f5.com goto fail; 8921828Sa.suvorov@f5.com } 8931828Sa.suvorov@f5.com 8941828Sa.suvorov@f5.com item->name = domain; 8951828Sa.suvorov@f5.com item->bundle = bundle; 8961828Sa.suvorov@f5.com 8971828Sa.suvorov@f5.com if (nxt_openssl_bundle_hash_insert(task, &conf->bundle_hash, 8981828Sa.suvorov@f5.com item, mp) 8991828Sa.suvorov@f5.com == NXT_ERROR) 9001828Sa.suvorov@f5.com { 9011828Sa.suvorov@f5.com goto fail; 9021828Sa.suvorov@f5.com } 9031828Sa.suvorov@f5.com } 9041828Sa.suvorov@f5.com 9051828Sa.suvorov@f5.com sk_GENERAL_NAME_pop_free(alt_names, GENERAL_NAME_free); 9061828Sa.suvorov@f5.com 9071828Sa.suvorov@f5.com } else { 9081828Sa.suvorov@f5.com x509_name = X509_get_subject_name(cert); 9091828Sa.suvorov@f5.com len = X509_NAME_get_text_by_NID(x509_name, NID_commonName, 9101828Sa.suvorov@f5.com NULL, 0); 9111828Sa.suvorov@f5.com if (len <= 0) { 9121828Sa.suvorov@f5.com nxt_log(task, NXT_LOG_WARN, "certificate \"%V\" has neither " 9131885Sa.suvorov@f5.com "Subject Alternative Name nor Common Name", &bundle->name); 9141828Sa.suvorov@f5.com return NXT_OK; 9151828Sa.suvorov@f5.com } 9161828Sa.suvorov@f5.com 9171828Sa.suvorov@f5.com domain.start = nxt_mp_nget(mp, len + 1); 9181828Sa.suvorov@f5.com if (nxt_slow_path(domain.start == NULL)) { 9191828Sa.suvorov@f5.com return NXT_ERROR; 9201828Sa.suvorov@f5.com } 9211828Sa.suvorov@f5.com 9221828Sa.suvorov@f5.com domain.length = X509_NAME_get_text_by_NID(x509_name, NID_commonName, 9231828Sa.suvorov@f5.com (char *) domain.start, 9241828Sa.suvorov@f5.com len + 1); 9251828Sa.suvorov@f5.com nxt_memcpy_lowcase(domain.start, domain.start, domain.length); 9261828Sa.suvorov@f5.com 9271828Sa.suvorov@f5.com item = nxt_mp_get(mp, sizeof(nxt_tls_bundle_hash_item_t)); 9281828Sa.suvorov@f5.com if (nxt_slow_path(item == NULL)) { 9291828Sa.suvorov@f5.com return NXT_ERROR; 9301828Sa.suvorov@f5.com } 9311828Sa.suvorov@f5.com 9321828Sa.suvorov@f5.com item->name = domain; 9331828Sa.suvorov@f5.com item->bundle = bundle; 9341828Sa.suvorov@f5.com 9351828Sa.suvorov@f5.com if (nxt_openssl_bundle_hash_insert(task, &conf->bundle_hash, item, 9361828Sa.suvorov@f5.com mp) 9371828Sa.suvorov@f5.com == NXT_ERROR) 9381828Sa.suvorov@f5.com { 9391828Sa.suvorov@f5.com return NXT_ERROR; 9401828Sa.suvorov@f5.com } 9411828Sa.suvorov@f5.com } 9421828Sa.suvorov@f5.com 9431828Sa.suvorov@f5.com return NXT_OK; 9441828Sa.suvorov@f5.com 9451828Sa.suvorov@f5.com fail: 9461828Sa.suvorov@f5.com 9471828Sa.suvorov@f5.com sk_GENERAL_NAME_pop_free(alt_names, GENERAL_NAME_free); 9481828Sa.suvorov@f5.com 9491828Sa.suvorov@f5.com return NXT_ERROR; 9501828Sa.suvorov@f5.com } 9511828Sa.suvorov@f5.com 9521828Sa.suvorov@f5.com 9531828Sa.suvorov@f5.com static const nxt_lvlhsh_proto_t nxt_openssl_bundle_hash_proto 9541828Sa.suvorov@f5.com nxt_aligned(64) = 9551828Sa.suvorov@f5.com { 9561828Sa.suvorov@f5.com NXT_LVLHSH_DEFAULT, 9571828Sa.suvorov@f5.com nxt_openssl_bundle_hash_test, 9581828Sa.suvorov@f5.com nxt_mp_lvlhsh_alloc, 9591828Sa.suvorov@f5.com nxt_mp_lvlhsh_free, 9601828Sa.suvorov@f5.com }; 9611828Sa.suvorov@f5.com 9621828Sa.suvorov@f5.com 9631828Sa.suvorov@f5.com static nxt_int_t 9641828Sa.suvorov@f5.com nxt_openssl_bundle_hash_test(nxt_lvlhsh_query_t *lhq, void *data) 9651828Sa.suvorov@f5.com { 9661828Sa.suvorov@f5.com nxt_tls_bundle_hash_item_t *item; 9671828Sa.suvorov@f5.com 9681828Sa.suvorov@f5.com item = data; 9691828Sa.suvorov@f5.com 9701828Sa.suvorov@f5.com return nxt_strstr_eq(&lhq->key, &item->name) ? NXT_OK : NXT_DECLINED; 9711828Sa.suvorov@f5.com } 9721828Sa.suvorov@f5.com 9731828Sa.suvorov@f5.com 9741828Sa.suvorov@f5.com static nxt_int_t 9751828Sa.suvorov@f5.com nxt_openssl_bundle_hash_insert(nxt_task_t *task, nxt_lvlhsh_t *lvlhsh, 9761828Sa.suvorov@f5.com nxt_tls_bundle_hash_item_t *item, nxt_mp_t *mp) 9771828Sa.suvorov@f5.com { 9781828Sa.suvorov@f5.com nxt_str_t str; 9791828Sa.suvorov@f5.com nxt_int_t ret; 9801828Sa.suvorov@f5.com nxt_lvlhsh_query_t lhq; 9811828Sa.suvorov@f5.com nxt_tls_bundle_hash_item_t *old; 9821828Sa.suvorov@f5.com 9831828Sa.suvorov@f5.com str = item->name; 9841828Sa.suvorov@f5.com 9851828Sa.suvorov@f5.com if (item->name.start[0] == '*') { 9861828Sa.suvorov@f5.com item->name.start++; 9871828Sa.suvorov@f5.com item->name.length--; 9881828Sa.suvorov@f5.com 9891828Sa.suvorov@f5.com if (item->name.length == 0 || item->name.start[0] != '.') { 9901828Sa.suvorov@f5.com nxt_log(task, NXT_LOG_WARN, "ignored invalid name \"%V\" " 9911828Sa.suvorov@f5.com "in certificate \"%V\": missing \".\" " 9921885Sa.suvorov@f5.com "after wildcard symbol", &str, &item->bundle->name); 9931828Sa.suvorov@f5.com return NXT_OK; 9941828Sa.suvorov@f5.com } 9951828Sa.suvorov@f5.com } 9961828Sa.suvorov@f5.com 9971828Sa.suvorov@f5.com lhq.pool = mp; 9981828Sa.suvorov@f5.com lhq.key = item->name; 9991828Sa.suvorov@f5.com lhq.value = item; 10001828Sa.suvorov@f5.com lhq.proto = &nxt_openssl_bundle_hash_proto; 10011828Sa.suvorov@f5.com lhq.replace = 0; 10021828Sa.suvorov@f5.com lhq.key_hash = nxt_murmur_hash2(item->name.start, item->name.length); 10031828Sa.suvorov@f5.com 10041828Sa.suvorov@f5.com ret = nxt_lvlhsh_insert(lvlhsh, &lhq); 10051828Sa.suvorov@f5.com if (nxt_fast_path(ret == NXT_OK)) { 10061828Sa.suvorov@f5.com nxt_debug(task, "name \"%V\" for certificate \"%V\" is inserted", 10071885Sa.suvorov@f5.com &str, &item->bundle->name); 10081828Sa.suvorov@f5.com return NXT_OK; 10091828Sa.suvorov@f5.com } 10101828Sa.suvorov@f5.com 10111828Sa.suvorov@f5.com if (nxt_fast_path(ret == NXT_DECLINED)) { 10121828Sa.suvorov@f5.com old = lhq.value; 10131828Sa.suvorov@f5.com if (old->bundle != item->bundle) { 10141828Sa.suvorov@f5.com nxt_log(task, NXT_LOG_WARN, "ignored duplicate name \"%V\" " 10151828Sa.suvorov@f5.com "in certificate \"%V\", identical name appears in \"%V\"", 10161885Sa.suvorov@f5.com &str, &old->bundle->name, &item->bundle->name); 10171828Sa.suvorov@f5.com 10181828Sa.suvorov@f5.com old->bundle = item->bundle; 10191828Sa.suvorov@f5.com } 10201828Sa.suvorov@f5.com 10211828Sa.suvorov@f5.com return NXT_OK; 10221828Sa.suvorov@f5.com } 10231828Sa.suvorov@f5.com 10241828Sa.suvorov@f5.com return NXT_ERROR; 10251828Sa.suvorov@f5.com } 10261828Sa.suvorov@f5.com 10271828Sa.suvorov@f5.com 10281828Sa.suvorov@f5.com static nxt_int_t 10291828Sa.suvorov@f5.com nxt_openssl_servername(SSL *s, int *ad, void *arg) 10301828Sa.suvorov@f5.com { 10311828Sa.suvorov@f5.com nxt_str_t str; 10321828Sa.suvorov@f5.com nxt_uint_t i; 10331828Sa.suvorov@f5.com nxt_conn_t *c; 10341828Sa.suvorov@f5.com const char *servername; 10351828Sa.suvorov@f5.com nxt_tls_conf_t *conf; 10361828Sa.suvorov@f5.com nxt_openssl_conn_t *tls; 10371828Sa.suvorov@f5.com nxt_tls_bundle_conf_t *bundle; 10381828Sa.suvorov@f5.com 10391828Sa.suvorov@f5.com c = SSL_get_ex_data(s, nxt_openssl_connection_index); 10401828Sa.suvorov@f5.com 10411828Sa.suvorov@f5.com if (nxt_slow_path(c == NULL)) { 10421828Sa.suvorov@f5.com nxt_thread_log_alert("SSL_get_ex_data() failed"); 10431828Sa.suvorov@f5.com return SSL_TLSEXT_ERR_ALERT_FATAL; 10441828Sa.suvorov@f5.com } 10451828Sa.suvorov@f5.com 10461828Sa.suvorov@f5.com servername = SSL_get_servername(s, TLSEXT_NAMETYPE_host_name); 10471921Sa.suvorov@f5.com 10481921Sa.suvorov@f5.com if (servername == NULL) { 10491921Sa.suvorov@f5.com nxt_debug(c->socket.task, "SSL_get_servername(): NULL"); 10501921Sa.suvorov@f5.com goto done; 10511828Sa.suvorov@f5.com } 10521828Sa.suvorov@f5.com 10531828Sa.suvorov@f5.com str.length = nxt_strlen(servername); 10541828Sa.suvorov@f5.com if (str.length == 0) { 10551921Sa.suvorov@f5.com nxt_debug(c->socket.task, "SSL_get_servername(): \"\" is empty"); 10561828Sa.suvorov@f5.com goto done; 10571828Sa.suvorov@f5.com } 10581828Sa.suvorov@f5.com 10591828Sa.suvorov@f5.com if (servername[0] == '.') { 10601828Sa.suvorov@f5.com nxt_debug(c->socket.task, "ignored the server name \"%s\": " 10611828Sa.suvorov@f5.com "leading \".\"", servername); 10621828Sa.suvorov@f5.com goto done; 10631828Sa.suvorov@f5.com } 10641828Sa.suvorov@f5.com 10651828Sa.suvorov@f5.com nxt_debug(c->socket.task, "tls with servername \"%s\"", servername); 10661828Sa.suvorov@f5.com 10671828Sa.suvorov@f5.com str.start = nxt_mp_nget(c->mem_pool, str.length); 10681828Sa.suvorov@f5.com if (nxt_slow_path(str.start == NULL)) { 10691828Sa.suvorov@f5.com return SSL_TLSEXT_ERR_ALERT_FATAL; 10701828Sa.suvorov@f5.com } 10711828Sa.suvorov@f5.com 10721828Sa.suvorov@f5.com nxt_memcpy_lowcase(str.start, (const u_char *) servername, str.length); 10731828Sa.suvorov@f5.com 10741828Sa.suvorov@f5.com tls = c->u.tls; 10751828Sa.suvorov@f5.com conf = tls->conf; 10761828Sa.suvorov@f5.com 10771828Sa.suvorov@f5.com bundle = nxt_openssl_find_ctx(conf, &str); 10781828Sa.suvorov@f5.com 10791828Sa.suvorov@f5.com if (bundle == NULL) { 10801828Sa.suvorov@f5.com for (i = 1; i < str.length; i++) { 10811828Sa.suvorov@f5.com if (str.start[i] == '.') { 10821828Sa.suvorov@f5.com str.start += i; 10831828Sa.suvorov@f5.com str.length -= i; 10841828Sa.suvorov@f5.com 10851828Sa.suvorov@f5.com bundle = nxt_openssl_find_ctx(conf, &str); 10861828Sa.suvorov@f5.com break; 10871828Sa.suvorov@f5.com } 10881828Sa.suvorov@f5.com } 10891828Sa.suvorov@f5.com } 10901828Sa.suvorov@f5.com 10911828Sa.suvorov@f5.com if (bundle != NULL) { 10921828Sa.suvorov@f5.com nxt_debug(c->socket.task, "new tls context found for \"%V\": \"%V\" " 10931885Sa.suvorov@f5.com "(old: \"%V\")", &str, &bundle->name, 10941885Sa.suvorov@f5.com &conf->bundle->name); 10951828Sa.suvorov@f5.com 10961828Sa.suvorov@f5.com if (bundle != conf->bundle) { 10971828Sa.suvorov@f5.com if (SSL_set_SSL_CTX(s, bundle->ctx) == NULL) { 10981828Sa.suvorov@f5.com nxt_openssl_log_error(c->socket.task, NXT_LOG_ALERT, 10991828Sa.suvorov@f5.com "SSL_set_SSL_CTX() failed"); 11001828Sa.suvorov@f5.com 11011828Sa.suvorov@f5.com return SSL_TLSEXT_ERR_ALERT_FATAL; 11021828Sa.suvorov@f5.com } 11031828Sa.suvorov@f5.com } 11041828Sa.suvorov@f5.com } 11051828Sa.suvorov@f5.com 11061828Sa.suvorov@f5.com done: 11071828Sa.suvorov@f5.com 11081828Sa.suvorov@f5.com return SSL_TLSEXT_ERR_OK; 11091828Sa.suvorov@f5.com } 11101828Sa.suvorov@f5.com 11111828Sa.suvorov@f5.com 11121828Sa.suvorov@f5.com static nxt_tls_bundle_conf_t * 11131828Sa.suvorov@f5.com nxt_openssl_find_ctx(nxt_tls_conf_t *conf, nxt_str_t *sn) 11141828Sa.suvorov@f5.com { 11151828Sa.suvorov@f5.com nxt_int_t ret; 11161828Sa.suvorov@f5.com nxt_lvlhsh_query_t lhq; 11171828Sa.suvorov@f5.com nxt_tls_bundle_hash_item_t *item; 11181828Sa.suvorov@f5.com 11191828Sa.suvorov@f5.com lhq.key_hash = nxt_murmur_hash2(sn->start, sn->length); 11201828Sa.suvorov@f5.com lhq.key = *sn; 11211828Sa.suvorov@f5.com lhq.proto = &nxt_openssl_bundle_hash_proto; 11221828Sa.suvorov@f5.com 11231828Sa.suvorov@f5.com ret = nxt_lvlhsh_find(&conf->bundle_hash, &lhq); 11241828Sa.suvorov@f5.com if (ret != NXT_OK) { 11251828Sa.suvorov@f5.com return NULL; 11261828Sa.suvorov@f5.com } 11271828Sa.suvorov@f5.com 11281828Sa.suvorov@f5.com item = lhq.value; 11291828Sa.suvorov@f5.com 11301828Sa.suvorov@f5.com return item->bundle; 11311828Sa.suvorov@f5.com } 11321828Sa.suvorov@f5.com 11331828Sa.suvorov@f5.com 11340Sigor@sysoev.ru static void 1135771Sigor@sysoev.ru nxt_openssl_server_free(nxt_task_t *task, nxt_tls_conf_t *conf) 11360Sigor@sysoev.ru { 11371828Sa.suvorov@f5.com nxt_tls_bundle_conf_t *bundle; 11381828Sa.suvorov@f5.com 11391828Sa.suvorov@f5.com bundle = conf->bundle; 11401828Sa.suvorov@f5.com nxt_assert(bundle != NULL); 11411828Sa.suvorov@f5.com 11421828Sa.suvorov@f5.com do { 11431828Sa.suvorov@f5.com SSL_CTX_free(bundle->ctx); 11441828Sa.suvorov@f5.com bundle = bundle->next; 11451828Sa.suvorov@f5.com } while (bundle != NULL); 11461818Smax.romanov@nginx.com 11471942Sa.suvorov@f5.com if (conf->tickets) { 11481942Sa.suvorov@f5.com nxt_memzero(conf->tickets->tickets, 11491942Sa.suvorov@f5.com conf->tickets->count * sizeof(nxt_tls_ticket_t)); 11501942Sa.suvorov@f5.com } 11511942Sa.suvorov@f5.com 11521818Smax.romanov@nginx.com #if (OPENSSL_VERSION_NUMBER >= 0x1010100fL \ 11531818Smax.romanov@nginx.com && OPENSSL_VERSION_NUMBER < 0x1010101fL) 11541818Smax.romanov@nginx.com RAND_keep_random_devices_open(0); 11551818Smax.romanov@nginx.com #endif 1156771Sigor@sysoev.ru } 1157771Sigor@sysoev.ru 1158771Sigor@sysoev.ru 1159771Sigor@sysoev.ru static void 1160771Sigor@sysoev.ru nxt_openssl_conn_init(nxt_task_t *task, nxt_tls_conf_t *conf, nxt_conn_t *c) 1161771Sigor@sysoev.ru { 1162771Sigor@sysoev.ru int ret; 1163771Sigor@sysoev.ru SSL *s; 1164771Sigor@sysoev.ru SSL_CTX *ctx; 1165771Sigor@sysoev.ru nxt_openssl_conn_t *tls; 11660Sigor@sysoev.ru 11670Sigor@sysoev.ru nxt_log_debug(c->socket.log, "openssl conn init"); 11680Sigor@sysoev.ru 1169771Sigor@sysoev.ru tls = nxt_mp_zget(c->mem_pool, sizeof(nxt_openssl_conn_t)); 1170771Sigor@sysoev.ru if (tls == NULL) { 11710Sigor@sysoev.ru goto fail; 11720Sigor@sysoev.ru } 11730Sigor@sysoev.ru 1174771Sigor@sysoev.ru c->u.tls = tls; 1175771Sigor@sysoev.ru nxt_buf_mem_set_size(&tls->buffer, conf->buffer_size); 11760Sigor@sysoev.ru 11771828Sa.suvorov@f5.com ctx = conf->bundle->ctx; 11780Sigor@sysoev.ru 11790Sigor@sysoev.ru s = SSL_new(ctx); 11800Sigor@sysoev.ru if (s == NULL) { 1181771Sigor@sysoev.ru nxt_openssl_log_error(task, NXT_LOG_ALERT, "SSL_new() failed"); 11820Sigor@sysoev.ru goto fail; 11830Sigor@sysoev.ru } 11840Sigor@sysoev.ru 1185771Sigor@sysoev.ru tls->session = s; 11861828Sa.suvorov@f5.com /* To pass TLS config to the nxt_openssl_servername() callback. */ 11871828Sa.suvorov@f5.com tls->conf = conf; 1188771Sigor@sysoev.ru tls->conn = c; 11890Sigor@sysoev.ru 11900Sigor@sysoev.ru ret = SSL_set_fd(s, c->socket.fd); 11910Sigor@sysoev.ru 11920Sigor@sysoev.ru if (ret == 0) { 1193771Sigor@sysoev.ru nxt_openssl_log_error(task, NXT_LOG_ALERT, "SSL_set_fd(%d) failed", 1194771Sigor@sysoev.ru c->socket.fd); 11950Sigor@sysoev.ru goto fail; 11960Sigor@sysoev.ru } 11970Sigor@sysoev.ru 11980Sigor@sysoev.ru SSL_set_accept_state(s); 11990Sigor@sysoev.ru 12000Sigor@sysoev.ru if (SSL_set_ex_data(s, nxt_openssl_connection_index, c) == 0) { 1201771Sigor@sysoev.ru nxt_openssl_log_error(task, NXT_LOG_ALERT, "SSL_set_ex_data() failed"); 12020Sigor@sysoev.ru goto fail; 12030Sigor@sysoev.ru } 12040Sigor@sysoev.ru 120562Sigor@sysoev.ru c->io = &nxt_openssl_conn_io; 12060Sigor@sysoev.ru c->sendfile = NXT_CONN_SENDFILE_OFF; 12070Sigor@sysoev.ru 12081Sigor@sysoev.ru nxt_openssl_conn_handshake(task, c, c->socket.data); 12091884Sa.suvorov@f5.com 12100Sigor@sysoev.ru return; 12110Sigor@sysoev.ru 12120Sigor@sysoev.ru fail: 12130Sigor@sysoev.ru 121413Sigor@sysoev.ru nxt_work_queue_add(c->read_work_queue, c->read_state->error_handler, 121513Sigor@sysoev.ru task, c, c->socket.data); 12160Sigor@sysoev.ru } 12170Sigor@sysoev.ru 12180Sigor@sysoev.ru 1219771Sigor@sysoev.ru nxt_inline void 1220836Sigor@sysoev.ru nxt_openssl_conn_free(nxt_task_t *task, nxt_conn_t *c) 12210Sigor@sysoev.ru { 1222836Sigor@sysoev.ru nxt_openssl_conn_t *tls; 1223836Sigor@sysoev.ru 1224771Sigor@sysoev.ru nxt_debug(task, "openssl conn free"); 12250Sigor@sysoev.ru 1226836Sigor@sysoev.ru tls = c->u.tls; 12270Sigor@sysoev.ru 1228836Sigor@sysoev.ru if (tls != NULL) { 1229836Sigor@sysoev.ru c->u.tls = NULL; 1230836Sigor@sysoev.ru nxt_free(tls->buffer.start); 1231836Sigor@sysoev.ru SSL_free(tls->session); 1232836Sigor@sysoev.ru } 12330Sigor@sysoev.ru } 12340Sigor@sysoev.ru 12350Sigor@sysoev.ru 12360Sigor@sysoev.ru static void 12371Sigor@sysoev.ru nxt_openssl_conn_handshake(nxt_task_t *task, void *obj, void *data) 12380Sigor@sysoev.ru { 1239771Sigor@sysoev.ru int ret; 1240771Sigor@sysoev.ru nxt_int_t n; 1241771Sigor@sysoev.ru nxt_err_t err; 1242771Sigor@sysoev.ru nxt_conn_t *c; 1243771Sigor@sysoev.ru nxt_work_queue_t *wq; 1244771Sigor@sysoev.ru nxt_work_handler_t handler; 1245771Sigor@sysoev.ru nxt_openssl_conn_t *tls; 1246771Sigor@sysoev.ru const nxt_conn_state_t *state; 12470Sigor@sysoev.ru 12480Sigor@sysoev.ru c = obj; 1249836Sigor@sysoev.ru 1250836Sigor@sysoev.ru nxt_debug(task, "openssl conn handshake fd:%d", c->socket.fd); 1251836Sigor@sysoev.ru 1252836Sigor@sysoev.ru if (c->socket.error != 0) { 1253836Sigor@sysoev.ru return; 1254836Sigor@sysoev.ru } 1255836Sigor@sysoev.ru 1256771Sigor@sysoev.ru tls = c->u.tls; 12570Sigor@sysoev.ru 1258836Sigor@sysoev.ru if (tls == NULL) { 1259836Sigor@sysoev.ru return; 1260836Sigor@sysoev.ru } 1261836Sigor@sysoev.ru 1262836Sigor@sysoev.ru nxt_debug(task, "openssl conn handshake: %d times", tls->times); 12630Sigor@sysoev.ru 1264771Sigor@sysoev.ru /* "tls->times == 1" is suitable to run SSL_do_handshake() in job. */ 12650Sigor@sysoev.ru 1266771Sigor@sysoev.ru ret = SSL_do_handshake(tls->session); 12670Sigor@sysoev.ru 12680Sigor@sysoev.ru err = (ret <= 0) ? nxt_socket_errno : 0; 12690Sigor@sysoev.ru 12701Sigor@sysoev.ru nxt_thread_time_debug_update(task->thread); 12710Sigor@sysoev.ru 12721Sigor@sysoev.ru nxt_debug(task, "SSL_do_handshake(%d): %d err:%d", c->socket.fd, ret, err); 12730Sigor@sysoev.ru 1274771Sigor@sysoev.ru state = (c->read_state != NULL) ? c->read_state : c->write_state; 1275771Sigor@sysoev.ru 12760Sigor@sysoev.ru if (ret > 0) { 12770Sigor@sysoev.ru /* ret == 1, the handshake was successfully completed. */ 1278771Sigor@sysoev.ru tls->handshake = 1; 12790Sigor@sysoev.ru 1280771Sigor@sysoev.ru if (c->read_state != NULL) { 1281771Sigor@sysoev.ru if (state->io_read_handler != NULL || c->read != NULL) { 1282771Sigor@sysoev.ru nxt_conn_read(task->thread->engine, c); 12830Sigor@sysoev.ru return; 12840Sigor@sysoev.ru } 12850Sigor@sysoev.ru 1286771Sigor@sysoev.ru } else { 1287771Sigor@sysoev.ru if (c->write != NULL) { 1288771Sigor@sysoev.ru nxt_conn_write(task->thread->engine, c); 1289771Sigor@sysoev.ru return; 1290771Sigor@sysoev.ru } 1291771Sigor@sysoev.ru } 1292771Sigor@sysoev.ru 1293771Sigor@sysoev.ru handler = state->ready_handler; 1294771Sigor@sysoev.ru 1295771Sigor@sysoev.ru } else { 1296771Sigor@sysoev.ru c->socket.read_handler = nxt_openssl_conn_handshake; 1297771Sigor@sysoev.ru c->socket.write_handler = nxt_openssl_conn_handshake; 1298771Sigor@sysoev.ru 1299771Sigor@sysoev.ru n = nxt_openssl_conn_test_error(task, c, ret, err, 1300771Sigor@sysoev.ru NXT_OPENSSL_HANDSHAKE); 1301771Sigor@sysoev.ru switch (n) { 13020Sigor@sysoev.ru 1303771Sigor@sysoev.ru case NXT_AGAIN: 1304771Sigor@sysoev.ru if (tls->ssl_error == SSL_ERROR_WANT_READ && tls->times < 2) { 1305771Sigor@sysoev.ru tls->times++; 1306771Sigor@sysoev.ru } 1307771Sigor@sysoev.ru 1308771Sigor@sysoev.ru return; 1309771Sigor@sysoev.ru 1310771Sigor@sysoev.ru case 0: 1311771Sigor@sysoev.ru handler = state->close_handler; 1312771Sigor@sysoev.ru break; 1313771Sigor@sysoev.ru 1314771Sigor@sysoev.ru default: 1315771Sigor@sysoev.ru case NXT_ERROR: 1316771Sigor@sysoev.ru nxt_openssl_conn_error(task, err, "SSL_do_handshake(%d) failed", 1317771Sigor@sysoev.ru c->socket.fd); 1318771Sigor@sysoev.ru 1319771Sigor@sysoev.ru handler = state->error_handler; 1320771Sigor@sysoev.ru break; 13210Sigor@sysoev.ru } 13220Sigor@sysoev.ru } 13230Sigor@sysoev.ru 1324771Sigor@sysoev.ru wq = (c->read_state != NULL) ? c->read_work_queue : c->write_work_queue; 1325771Sigor@sysoev.ru 1326771Sigor@sysoev.ru nxt_work_queue_add(wq, handler, task, c, data); 13270Sigor@sysoev.ru } 13280Sigor@sysoev.ru 13290Sigor@sysoev.ru 13300Sigor@sysoev.ru static ssize_t 1331771Sigor@sysoev.ru nxt_openssl_conn_io_recvbuf(nxt_conn_t *c, nxt_buf_t *b) 13320Sigor@sysoev.ru { 1333771Sigor@sysoev.ru int ret; 1334771Sigor@sysoev.ru size_t size; 1335771Sigor@sysoev.ru nxt_int_t n; 1336771Sigor@sysoev.ru nxt_err_t err; 1337771Sigor@sysoev.ru nxt_openssl_conn_t *tls; 1338771Sigor@sysoev.ru 1339771Sigor@sysoev.ru tls = c->u.tls; 1340771Sigor@sysoev.ru size = b->mem.end - b->mem.free; 1341771Sigor@sysoev.ru 1342771Sigor@sysoev.ru ret = SSL_read(tls->session, b->mem.free, size); 1343771Sigor@sysoev.ru 1344771Sigor@sysoev.ru err = (ret <= 0) ? nxt_socket_errno : 0; 1345771Sigor@sysoev.ru 1346771Sigor@sysoev.ru nxt_debug(c->socket.task, "SSL_read(%d, %p, %uz): %d err:%d", 1347771Sigor@sysoev.ru c->socket.fd, b->mem.free, size, ret, err); 13480Sigor@sysoev.ru 1349771Sigor@sysoev.ru if (ret > 0) { 1350771Sigor@sysoev.ru return ret; 1351771Sigor@sysoev.ru } 13520Sigor@sysoev.ru 1353771Sigor@sysoev.ru n = nxt_openssl_conn_test_error(c->socket.task, c, ret, err, 1354771Sigor@sysoev.ru NXT_OPENSSL_READ); 1355771Sigor@sysoev.ru if (n == NXT_ERROR) { 1356771Sigor@sysoev.ru nxt_openssl_conn_error(c->socket.task, err, 1357771Sigor@sysoev.ru "SSL_read(%d, %p, %uz) failed", 1358771Sigor@sysoev.ru c->socket.fd, b->mem.free, size); 1359771Sigor@sysoev.ru } 13600Sigor@sysoev.ru 1361771Sigor@sysoev.ru return n; 13620Sigor@sysoev.ru } 13630Sigor@sysoev.ru 13640Sigor@sysoev.ru 13650Sigor@sysoev.ru static ssize_t 1366771Sigor@sysoev.ru nxt_openssl_conn_io_sendbuf(nxt_task_t *task, nxt_sendbuf_t *sb) 1367771Sigor@sysoev.ru { 1368771Sigor@sysoev.ru nxt_uint_t niov; 1369771Sigor@sysoev.ru struct iovec iov; 1370771Sigor@sysoev.ru 1371771Sigor@sysoev.ru niov = nxt_sendbuf_mem_coalesce0(task, sb, &iov, 1); 1372771Sigor@sysoev.ru 1373771Sigor@sysoev.ru if (niov == 0 && sb->sync) { 1374771Sigor@sysoev.ru return 0; 1375771Sigor@sysoev.ru } 1376771Sigor@sysoev.ru 1377771Sigor@sysoev.ru return nxt_openssl_conn_io_send(task, sb, iov.iov_base, iov.iov_len); 1378771Sigor@sysoev.ru } 1379771Sigor@sysoev.ru 1380771Sigor@sysoev.ru 1381771Sigor@sysoev.ru static ssize_t 1382771Sigor@sysoev.ru nxt_openssl_conn_io_send(nxt_task_t *task, nxt_sendbuf_t *sb, void *buf, 1383771Sigor@sysoev.ru size_t size) 13840Sigor@sysoev.ru { 13850Sigor@sysoev.ru int ret; 13860Sigor@sysoev.ru nxt_err_t err; 13870Sigor@sysoev.ru nxt_int_t n; 1388771Sigor@sysoev.ru nxt_conn_t *c; 1389771Sigor@sysoev.ru nxt_openssl_conn_t *tls; 13900Sigor@sysoev.ru 1391771Sigor@sysoev.ru tls = sb->tls; 13920Sigor@sysoev.ru 1393771Sigor@sysoev.ru ret = SSL_write(tls->session, buf, size); 13940Sigor@sysoev.ru 13951212Sigor@sysoev.ru err = (ret <= 0) ? nxt_socket_errno : 0; 13960Sigor@sysoev.ru 1397771Sigor@sysoev.ru nxt_debug(task, "SSL_write(%d, %p, %uz): %d err:%d", 1398771Sigor@sysoev.ru sb->socket, buf, size, ret, err); 13990Sigor@sysoev.ru 14000Sigor@sysoev.ru if (ret > 0) { 14010Sigor@sysoev.ru return ret; 14020Sigor@sysoev.ru } 14030Sigor@sysoev.ru 1404771Sigor@sysoev.ru c = tls->conn; 1405771Sigor@sysoev.ru c->socket.write_ready = sb->ready; 1406771Sigor@sysoev.ru 1407771Sigor@sysoev.ru n = nxt_openssl_conn_test_error(task, c, ret, err, NXT_OPENSSL_WRITE); 1408771Sigor@sysoev.ru 1409771Sigor@sysoev.ru sb->ready = c->socket.write_ready; 14100Sigor@sysoev.ru 14110Sigor@sysoev.ru if (n == NXT_ERROR) { 14121212Sigor@sysoev.ru sb->error = c->socket.error; 1413771Sigor@sysoev.ru nxt_openssl_conn_error(task, err, "SSL_write(%d, %p, %uz) failed", 1414771Sigor@sysoev.ru sb->socket, buf, size); 14150Sigor@sysoev.ru } 14160Sigor@sysoev.ru 14170Sigor@sysoev.ru return n; 14180Sigor@sysoev.ru } 14190Sigor@sysoev.ru 14200Sigor@sysoev.ru 14210Sigor@sysoev.ru static void 14221Sigor@sysoev.ru nxt_openssl_conn_io_shutdown(nxt_task_t *task, void *obj, void *data) 14230Sigor@sysoev.ru { 14240Sigor@sysoev.ru int ret, mode; 14250Sigor@sysoev.ru SSL *s; 14260Sigor@sysoev.ru nxt_err_t err; 14270Sigor@sysoev.ru nxt_int_t n; 14280Sigor@sysoev.ru nxt_bool_t quiet, once; 142962Sigor@sysoev.ru nxt_conn_t *c; 1430771Sigor@sysoev.ru nxt_openssl_conn_t *tls; 14310Sigor@sysoev.ru nxt_work_handler_t handler; 14320Sigor@sysoev.ru 14330Sigor@sysoev.ru c = obj; 14340Sigor@sysoev.ru 1435836Sigor@sysoev.ru nxt_debug(task, "openssl conn shutdown fd:%d", c->socket.fd); 1436836Sigor@sysoev.ru 1437771Sigor@sysoev.ru c->read_state = NULL; 1438771Sigor@sysoev.ru tls = c->u.tls; 1439836Sigor@sysoev.ru 1440836Sigor@sysoev.ru if (tls == NULL) { 1441836Sigor@sysoev.ru return; 1442836Sigor@sysoev.ru } 1443836Sigor@sysoev.ru 1444771Sigor@sysoev.ru s = tls->session; 14450Sigor@sysoev.ru 1446771Sigor@sysoev.ru if (s == NULL || !tls->handshake) { 1447771Sigor@sysoev.ru handler = c->write_state->ready_handler; 14480Sigor@sysoev.ru goto done; 14490Sigor@sysoev.ru } 14500Sigor@sysoev.ru 14510Sigor@sysoev.ru mode = SSL_get_shutdown(s); 14520Sigor@sysoev.ru 14530Sigor@sysoev.ru if (c->socket.timedout || c->socket.error != 0) { 14540Sigor@sysoev.ru quiet = 1; 14550Sigor@sysoev.ru 14560Sigor@sysoev.ru } else if (c->socket.closed && !(mode & SSL_RECEIVED_SHUTDOWN)) { 14570Sigor@sysoev.ru quiet = 1; 14580Sigor@sysoev.ru 14590Sigor@sysoev.ru } else { 14600Sigor@sysoev.ru quiet = 0; 14610Sigor@sysoev.ru } 14620Sigor@sysoev.ru 14630Sigor@sysoev.ru SSL_set_quiet_shutdown(s, quiet); 14640Sigor@sysoev.ru 14651884Sa.suvorov@f5.com if (tls->conf->no_wait_shutdown) { 14661884Sa.suvorov@f5.com mode |= SSL_RECEIVED_SHUTDOWN; 14671884Sa.suvorov@f5.com } 14681884Sa.suvorov@f5.com 14690Sigor@sysoev.ru once = 1; 14700Sigor@sysoev.ru 14710Sigor@sysoev.ru for ( ;; ) { 14720Sigor@sysoev.ru SSL_set_shutdown(s, mode); 14730Sigor@sysoev.ru 14740Sigor@sysoev.ru ret = SSL_shutdown(s); 14750Sigor@sysoev.ru 14760Sigor@sysoev.ru err = (ret <= 0) ? nxt_socket_errno : 0; 14770Sigor@sysoev.ru 14781Sigor@sysoev.ru nxt_debug(task, "SSL_shutdown(%d, %d, %b): %d err:%d", 14791Sigor@sysoev.ru c->socket.fd, mode, quiet, ret, err); 14800Sigor@sysoev.ru 14810Sigor@sysoev.ru if (ret > 0) { 14820Sigor@sysoev.ru /* ret == 1, the shutdown was successfully completed. */ 1483771Sigor@sysoev.ru handler = c->write_state->ready_handler; 14840Sigor@sysoev.ru goto done; 14850Sigor@sysoev.ru } 14860Sigor@sysoev.ru 14870Sigor@sysoev.ru if (ret == 0) { 14880Sigor@sysoev.ru /* 14890Sigor@sysoev.ru * If SSL_shutdown() returns 0 then it should be called 1490771Sigor@sysoev.ru * again. The second SSL_shutdown() call should return 14910Sigor@sysoev.ru * -1/SSL_ERROR_WANT_READ or -1/SSL_ERROR_WANT_WRITE. 14920Sigor@sysoev.ru * OpenSSL prior to 0.9.8m version however never returns 1493771Sigor@sysoev.ru * -1 at all. Fortunately, OpenSSL preserves internally 14940Sigor@sysoev.ru * correct status available via SSL_get_error(-1). 14950Sigor@sysoev.ru */ 14960Sigor@sysoev.ru if (once) { 1497771Sigor@sysoev.ru once = 0; 14980Sigor@sysoev.ru mode = SSL_get_shutdown(s); 14990Sigor@sysoev.ru continue; 15000Sigor@sysoev.ru } 15010Sigor@sysoev.ru 15020Sigor@sysoev.ru ret = -1; 15030Sigor@sysoev.ru } 15040Sigor@sysoev.ru 15050Sigor@sysoev.ru /* ret == -1 */ 15060Sigor@sysoev.ru 15070Sigor@sysoev.ru break; 15080Sigor@sysoev.ru } 15090Sigor@sysoev.ru 1510771Sigor@sysoev.ru c->socket.read_handler = nxt_openssl_conn_io_shutdown; 1511771Sigor@sysoev.ru c->socket.write_handler = nxt_openssl_conn_io_shutdown; 1512771Sigor@sysoev.ru c->socket.error_handler = c->write_state->error_handler; 1513771Sigor@sysoev.ru 1514771Sigor@sysoev.ru n = nxt_openssl_conn_test_error(task, c, ret, err, NXT_OPENSSL_SHUTDOWN); 1515771Sigor@sysoev.ru 1516771Sigor@sysoev.ru switch (n) { 15170Sigor@sysoev.ru 1518771Sigor@sysoev.ru case 0: 1519771Sigor@sysoev.ru handler = c->write_state->close_handler; 1520771Sigor@sysoev.ru break; 1521771Sigor@sysoev.ru 1522771Sigor@sysoev.ru case NXT_AGAIN: 15231884Sa.suvorov@f5.com c->write_timer.handler = nxt_openssl_conn_io_shutdown_timeout; 15241884Sa.suvorov@f5.com nxt_timer_add(task->thread->engine, &c->write_timer, 5000); 15250Sigor@sysoev.ru return; 1526771Sigor@sysoev.ru 1527771Sigor@sysoev.ru default: 1528771Sigor@sysoev.ru case NXT_ERROR: 1529771Sigor@sysoev.ru nxt_openssl_conn_error(task, err, "SSL_shutdown(%d) failed", 1530771Sigor@sysoev.ru c->socket.fd); 1531771Sigor@sysoev.ru handler = c->write_state->error_handler; 15320Sigor@sysoev.ru } 15330Sigor@sysoev.ru 1534771Sigor@sysoev.ru done: 15350Sigor@sysoev.ru 1536836Sigor@sysoev.ru nxt_openssl_conn_free(task, c); 15370Sigor@sysoev.ru 153813Sigor@sysoev.ru nxt_work_queue_add(c->write_work_queue, handler, task, c, data); 15390Sigor@sysoev.ru } 15400Sigor@sysoev.ru 15410Sigor@sysoev.ru 15420Sigor@sysoev.ru static nxt_int_t 154362Sigor@sysoev.ru nxt_openssl_conn_test_error(nxt_task_t *task, nxt_conn_t *c, int ret, 1544771Sigor@sysoev.ru nxt_err_t sys_err, nxt_openssl_io_t io) 15450Sigor@sysoev.ru { 15460Sigor@sysoev.ru u_long lib_err; 1547771Sigor@sysoev.ru nxt_openssl_conn_t *tls; 15480Sigor@sysoev.ru 1549771Sigor@sysoev.ru tls = c->u.tls; 15500Sigor@sysoev.ru 1551771Sigor@sysoev.ru tls->ssl_error = SSL_get_error(tls->session, ret); 15520Sigor@sysoev.ru 1553771Sigor@sysoev.ru nxt_debug(task, "SSL_get_error(): %d", tls->ssl_error); 15540Sigor@sysoev.ru 1555771Sigor@sysoev.ru switch (tls->ssl_error) { 15560Sigor@sysoev.ru 15570Sigor@sysoev.ru case SSL_ERROR_WANT_READ: 1558990Sigor@sysoev.ru c->socket.read_ready = 0; 1559771Sigor@sysoev.ru 1560771Sigor@sysoev.ru if (io != NXT_OPENSSL_READ) { 1561771Sigor@sysoev.ru nxt_fd_event_block_write(task->thread->engine, &c->socket); 15620Sigor@sysoev.ru 1563771Sigor@sysoev.ru if (nxt_fd_event_is_disabled(c->socket.read)) { 1564771Sigor@sysoev.ru nxt_fd_event_enable_read(task->thread->engine, &c->socket); 1565771Sigor@sysoev.ru } 15660Sigor@sysoev.ru } 15670Sigor@sysoev.ru 15680Sigor@sysoev.ru return NXT_AGAIN; 15690Sigor@sysoev.ru 15700Sigor@sysoev.ru case SSL_ERROR_WANT_WRITE: 1571990Sigor@sysoev.ru c->socket.write_ready = 0; 1572771Sigor@sysoev.ru 1573771Sigor@sysoev.ru if (io != NXT_OPENSSL_WRITE) { 1574771Sigor@sysoev.ru nxt_fd_event_block_read(task->thread->engine, &c->socket); 15750Sigor@sysoev.ru 1576771Sigor@sysoev.ru if (nxt_fd_event_is_disabled(c->socket.write)) { 1577771Sigor@sysoev.ru nxt_fd_event_enable_write(task->thread->engine, &c->socket); 1578771Sigor@sysoev.ru } 15790Sigor@sysoev.ru } 15800Sigor@sysoev.ru 15810Sigor@sysoev.ru return NXT_AGAIN; 15820Sigor@sysoev.ru 15830Sigor@sysoev.ru case SSL_ERROR_SYSCALL: 15840Sigor@sysoev.ru lib_err = ERR_peek_error(); 15850Sigor@sysoev.ru 15861Sigor@sysoev.ru nxt_debug(task, "ERR_peek_error(): %l", lib_err); 15870Sigor@sysoev.ru 15880Sigor@sysoev.ru if (sys_err != 0 || lib_err != 0) { 15891212Sigor@sysoev.ru c->socket.error = sys_err; 15900Sigor@sysoev.ru return NXT_ERROR; 15910Sigor@sysoev.ru } 15920Sigor@sysoev.ru 15930Sigor@sysoev.ru /* A connection was just closed. */ 15940Sigor@sysoev.ru c->socket.closed = 1; 1595771Sigor@sysoev.ru return 0; 15960Sigor@sysoev.ru 15970Sigor@sysoev.ru case SSL_ERROR_ZERO_RETURN: 15980Sigor@sysoev.ru /* A "close notify" alert. */ 15990Sigor@sysoev.ru return 0; 16000Sigor@sysoev.ru 16010Sigor@sysoev.ru default: /* SSL_ERROR_SSL, etc. */ 16020Sigor@sysoev.ru c->socket.error = 1000; /* Nonexistent errno code. */ 16030Sigor@sysoev.ru return NXT_ERROR; 16040Sigor@sysoev.ru } 16050Sigor@sysoev.ru } 16060Sigor@sysoev.ru 16070Sigor@sysoev.ru 16081884Sa.suvorov@f5.com static void 16091884Sa.suvorov@f5.com nxt_openssl_conn_io_shutdown_timeout(nxt_task_t *task, void *obj, void *data) 16101884Sa.suvorov@f5.com { 16111884Sa.suvorov@f5.com nxt_conn_t *c; 16121884Sa.suvorov@f5.com nxt_timer_t *timer; 16131884Sa.suvorov@f5.com 16141884Sa.suvorov@f5.com timer = obj; 16151884Sa.suvorov@f5.com 16161884Sa.suvorov@f5.com nxt_debug(task, "openssl conn shutdown timeout"); 16171884Sa.suvorov@f5.com 16181884Sa.suvorov@f5.com c = nxt_write_timer_conn(timer); 16191884Sa.suvorov@f5.com 16201884Sa.suvorov@f5.com c->socket.timedout = 1; 16211884Sa.suvorov@f5.com nxt_openssl_conn_io_shutdown(task, c, NULL); 16221884Sa.suvorov@f5.com } 16231884Sa.suvorov@f5.com 16241884Sa.suvorov@f5.com 16250Sigor@sysoev.ru static void nxt_cdecl 1626771Sigor@sysoev.ru nxt_openssl_conn_error(nxt_task_t *task, nxt_err_t err, const char *fmt, ...) 16270Sigor@sysoev.ru { 16280Sigor@sysoev.ru u_char *p, *end; 16290Sigor@sysoev.ru va_list args; 16300Sigor@sysoev.ru nxt_uint_t level; 16310Sigor@sysoev.ru u_char msg[NXT_MAX_ERROR_STR]; 16320Sigor@sysoev.ru 1633771Sigor@sysoev.ru level = nxt_openssl_log_error_level(err); 16340Sigor@sysoev.ru 1635771Sigor@sysoev.ru if (nxt_log_level_enough(task->log, level)) { 16360Sigor@sysoev.ru 16370Sigor@sysoev.ru end = msg + sizeof(msg); 16380Sigor@sysoev.ru 16390Sigor@sysoev.ru va_start(args, fmt); 16400Sigor@sysoev.ru p = nxt_vsprintf(msg, end, fmt, args); 16410Sigor@sysoev.ru va_end(args); 16420Sigor@sysoev.ru 16430Sigor@sysoev.ru if (err != 0) { 16440Sigor@sysoev.ru p = nxt_sprintf(p, end, " %E", err); 16450Sigor@sysoev.ru } 16460Sigor@sysoev.ru 16470Sigor@sysoev.ru p = nxt_openssl_copy_error(p, end); 16480Sigor@sysoev.ru 1649771Sigor@sysoev.ru nxt_log(task, level, "%*s", p - msg, msg); 16500Sigor@sysoev.ru 16510Sigor@sysoev.ru } else { 16520Sigor@sysoev.ru ERR_clear_error(); 16530Sigor@sysoev.ru } 16540Sigor@sysoev.ru } 16550Sigor@sysoev.ru 16560Sigor@sysoev.ru 16570Sigor@sysoev.ru static nxt_uint_t 1658771Sigor@sysoev.ru nxt_openssl_log_error_level(nxt_err_t err) 16590Sigor@sysoev.ru { 16600Sigor@sysoev.ru switch (ERR_GET_REASON(ERR_peek_error())) { 16610Sigor@sysoev.ru 16620Sigor@sysoev.ru case 0: 166313Sigor@sysoev.ru return nxt_socket_error_level(err); 16640Sigor@sysoev.ru 16650Sigor@sysoev.ru case SSL_R_BAD_CHANGE_CIPHER_SPEC: /* 103 */ 16660Sigor@sysoev.ru case SSL_R_BLOCK_CIPHER_PAD_IS_WRONG: /* 129 */ 16670Sigor@sysoev.ru case SSL_R_DIGEST_CHECK_FAILED: /* 149 */ 16680Sigor@sysoev.ru case SSL_R_ERROR_IN_RECEIVED_CIPHER_LIST: /* 151 */ 16690Sigor@sysoev.ru case SSL_R_EXCESSIVE_MESSAGE_SIZE: /* 152 */ 16700Sigor@sysoev.ru case SSL_R_LENGTH_MISMATCH: /* 159 */ 1671771Sigor@sysoev.ru #ifdef SSL_R_NO_CIPHERS_PASSED 16720Sigor@sysoev.ru case SSL_R_NO_CIPHERS_PASSED: /* 182 */ 1673771Sigor@sysoev.ru #endif 16740Sigor@sysoev.ru case SSL_R_NO_CIPHERS_SPECIFIED: /* 183 */ 16750Sigor@sysoev.ru case SSL_R_NO_COMPRESSION_SPECIFIED: /* 187 */ 16760Sigor@sysoev.ru case SSL_R_NO_SHARED_CIPHER: /* 193 */ 16770Sigor@sysoev.ru case SSL_R_RECORD_LENGTH_MISMATCH: /* 213 */ 16780Sigor@sysoev.ru #ifdef SSL_R_PARSE_TLSEXT 16790Sigor@sysoev.ru case SSL_R_PARSE_TLSEXT: /* 227 */ 16800Sigor@sysoev.ru #endif 16810Sigor@sysoev.ru case SSL_R_UNEXPECTED_MESSAGE: /* 244 */ 16820Sigor@sysoev.ru case SSL_R_UNEXPECTED_RECORD: /* 245 */ 16830Sigor@sysoev.ru case SSL_R_UNKNOWN_ALERT_TYPE: /* 246 */ 16840Sigor@sysoev.ru case SSL_R_UNKNOWN_PROTOCOL: /* 252 */ 16850Sigor@sysoev.ru case SSL_R_WRONG_VERSION_NUMBER: /* 267 */ 16860Sigor@sysoev.ru case SSL_R_DECRYPTION_FAILED_OR_BAD_RECORD_MAC: /* 281 */ 16870Sigor@sysoev.ru #ifdef SSL_R_RENEGOTIATE_EXT_TOO_LONG 16880Sigor@sysoev.ru case SSL_R_RENEGOTIATE_EXT_TOO_LONG: /* 335 */ 16890Sigor@sysoev.ru case SSL_R_RENEGOTIATION_ENCODING_ERR: /* 336 */ 16900Sigor@sysoev.ru case SSL_R_RENEGOTIATION_MISMATCH: /* 337 */ 16910Sigor@sysoev.ru #endif 16920Sigor@sysoev.ru #ifdef SSL_R_UNSAFE_LEGACY_RENEGOTIATION_DISABLED 16930Sigor@sysoev.ru case SSL_R_UNSAFE_LEGACY_RENEGOTIATION_DISABLED: /* 338 */ 16940Sigor@sysoev.ru #endif 16950Sigor@sysoev.ru #ifdef SSL_R_SCSV_RECEIVED_WHEN_RENEGOTIATING 16960Sigor@sysoev.ru case SSL_R_SCSV_RECEIVED_WHEN_RENEGOTIATING: /* 345 */ 16970Sigor@sysoev.ru #endif 16980Sigor@sysoev.ru case 1000:/* SSL_R_SSLV3_ALERT_CLOSE_NOTIFY */ 16990Sigor@sysoev.ru case SSL_R_SSLV3_ALERT_UNEXPECTED_MESSAGE: /* 1010 */ 17000Sigor@sysoev.ru case SSL_R_SSLV3_ALERT_BAD_RECORD_MAC: /* 1020 */ 17010Sigor@sysoev.ru case SSL_R_TLSV1_ALERT_DECRYPTION_FAILED: /* 1021 */ 17020Sigor@sysoev.ru case SSL_R_TLSV1_ALERT_RECORD_OVERFLOW: /* 1022 */ 17030Sigor@sysoev.ru case SSL_R_SSLV3_ALERT_DECOMPRESSION_FAILURE: /* 1030 */ 17040Sigor@sysoev.ru case SSL_R_SSLV3_ALERT_HANDSHAKE_FAILURE: /* 1040 */ 17050Sigor@sysoev.ru case SSL_R_SSLV3_ALERT_ILLEGAL_PARAMETER: /* 1047 */ 17060Sigor@sysoev.ru break; 17070Sigor@sysoev.ru 17080Sigor@sysoev.ru case SSL_R_SSLV3_ALERT_NO_CERTIFICATE: /* 1041 */ 17090Sigor@sysoev.ru case SSL_R_SSLV3_ALERT_BAD_CERTIFICATE: /* 1042 */ 17100Sigor@sysoev.ru case SSL_R_SSLV3_ALERT_UNSUPPORTED_CERTIFICATE: /* 1043 */ 17110Sigor@sysoev.ru case SSL_R_SSLV3_ALERT_CERTIFICATE_REVOKED: /* 1044 */ 17120Sigor@sysoev.ru case SSL_R_SSLV3_ALERT_CERTIFICATE_EXPIRED: /* 1045 */ 17130Sigor@sysoev.ru case SSL_R_SSLV3_ALERT_CERTIFICATE_UNKNOWN: /* 1046 */ 17140Sigor@sysoev.ru case SSL_R_TLSV1_ALERT_UNKNOWN_CA: /* 1048 */ 17150Sigor@sysoev.ru case SSL_R_TLSV1_ALERT_ACCESS_DENIED: /* 1049 */ 17160Sigor@sysoev.ru case SSL_R_TLSV1_ALERT_DECODE_ERROR: /* 1050 */ 17170Sigor@sysoev.ru case SSL_R_TLSV1_ALERT_DECRYPT_ERROR: /* 1051 */ 17180Sigor@sysoev.ru case SSL_R_TLSV1_ALERT_EXPORT_RESTRICTION: /* 1060 */ 17190Sigor@sysoev.ru case SSL_R_TLSV1_ALERT_PROTOCOL_VERSION: /* 1070 */ 17200Sigor@sysoev.ru case SSL_R_TLSV1_ALERT_INSUFFICIENT_SECURITY: /* 1071 */ 17210Sigor@sysoev.ru case SSL_R_TLSV1_ALERT_INTERNAL_ERROR: /* 1080 */ 17220Sigor@sysoev.ru case SSL_R_TLSV1_ALERT_USER_CANCELLED: /* 1090 */ 17230Sigor@sysoev.ru case SSL_R_TLSV1_ALERT_NO_RENEGOTIATION: /* 1100 */ 17240Sigor@sysoev.ru return NXT_LOG_ERR; 17250Sigor@sysoev.ru 17260Sigor@sysoev.ru default: 1727564Svbart@nginx.com return NXT_LOG_ALERT; 17280Sigor@sysoev.ru } 17290Sigor@sysoev.ru 17300Sigor@sysoev.ru return NXT_LOG_INFO; 17310Sigor@sysoev.ru } 17320Sigor@sysoev.ru 17330Sigor@sysoev.ru 1734771Sigor@sysoev.ru void nxt_cdecl 1735771Sigor@sysoev.ru nxt_openssl_log_error(nxt_task_t *task, nxt_uint_t level, const char *fmt, ...) 17360Sigor@sysoev.ru { 17370Sigor@sysoev.ru u_char *p, *end; 17380Sigor@sysoev.ru va_list args; 17390Sigor@sysoev.ru u_char msg[NXT_MAX_ERROR_STR]; 17400Sigor@sysoev.ru 17410Sigor@sysoev.ru end = msg + sizeof(msg); 17420Sigor@sysoev.ru 17430Sigor@sysoev.ru va_start(args, fmt); 17440Sigor@sysoev.ru p = nxt_vsprintf(msg, end, fmt, args); 17450Sigor@sysoev.ru va_end(args); 17460Sigor@sysoev.ru 17470Sigor@sysoev.ru p = nxt_openssl_copy_error(p, end); 17480Sigor@sysoev.ru 1749771Sigor@sysoev.ru nxt_log(task, level, "%*s", p - msg, msg); 17500Sigor@sysoev.ru } 17510Sigor@sysoev.ru 17520Sigor@sysoev.ru 1753771Sigor@sysoev.ru u_char * 17540Sigor@sysoev.ru nxt_openssl_copy_error(u_char *p, u_char *end) 17550Sigor@sysoev.ru { 17560Sigor@sysoev.ru int flags; 17570Sigor@sysoev.ru u_long err; 17580Sigor@sysoev.ru nxt_bool_t clear; 17590Sigor@sysoev.ru const char *data, *delimiter; 17600Sigor@sysoev.ru 17610Sigor@sysoev.ru err = ERR_peek_error(); 17620Sigor@sysoev.ru if (err == 0) { 17630Sigor@sysoev.ru return p; 17640Sigor@sysoev.ru } 17650Sigor@sysoev.ru 17660Sigor@sysoev.ru /* Log the most relevant error message ... */ 17670Sigor@sysoev.ru data = ERR_reason_error_string(err); 17680Sigor@sysoev.ru 17690Sigor@sysoev.ru p = nxt_sprintf(p, end, " (%d: %s) (OpenSSL: ", ERR_GET_REASON(err), data); 17700Sigor@sysoev.ru 17710Sigor@sysoev.ru /* 1772771Sigor@sysoev.ru * ... followed by all queued cumbersome OpenSSL error messages 1773771Sigor@sysoev.ru * and drain the error queue. 17740Sigor@sysoev.ru */ 17750Sigor@sysoev.ru delimiter = ""; 17760Sigor@sysoev.ru clear = 0; 17770Sigor@sysoev.ru 17780Sigor@sysoev.ru for ( ;; ) { 17790Sigor@sysoev.ru err = ERR_get_error_line_data(NULL, NULL, &data, &flags); 17800Sigor@sysoev.ru if (err == 0) { 17810Sigor@sysoev.ru break; 17820Sigor@sysoev.ru } 17830Sigor@sysoev.ru 17840Sigor@sysoev.ru p = nxt_sprintf(p, end, "%s", delimiter); 17850Sigor@sysoev.ru 17860Sigor@sysoev.ru ERR_error_string_n(err, (char *) p, end - p); 17870Sigor@sysoev.ru 17880Sigor@sysoev.ru while (p < end && *p != '\0') { 17890Sigor@sysoev.ru p++; 17900Sigor@sysoev.ru } 17910Sigor@sysoev.ru 17920Sigor@sysoev.ru if ((flags & ERR_TXT_STRING) != 0) { 17930Sigor@sysoev.ru p = nxt_sprintf(p, end, ":%s", data); 17940Sigor@sysoev.ru } 17950Sigor@sysoev.ru 17960Sigor@sysoev.ru clear |= ((flags & ERR_TXT_MALLOCED) != 0); 17970Sigor@sysoev.ru 17980Sigor@sysoev.ru delimiter = "; "; 17990Sigor@sysoev.ru } 18000Sigor@sysoev.ru 18010Sigor@sysoev.ru /* Deallocate additional data. */ 18020Sigor@sysoev.ru 18030Sigor@sysoev.ru if (clear) { 18040Sigor@sysoev.ru ERR_clear_error(); 18050Sigor@sysoev.ru } 18060Sigor@sysoev.ru 18070Sigor@sysoev.ru if (p < end) { 18080Sigor@sysoev.ru *p++ = ')'; 18090Sigor@sysoev.ru } 18100Sigor@sysoev.ru 18110Sigor@sysoev.ru return p; 18120Sigor@sysoev.ru } 18131942Sa.suvorov@f5.com 18141942Sa.suvorov@f5.com 18151942Sa.suvorov@f5.com nxt_int_t 18161942Sa.suvorov@f5.com nxt_openssl_base64_decode(u_char *d, size_t dlen, const u_char *s, size_t slen) 18171942Sa.suvorov@f5.com { 18181942Sa.suvorov@f5.com BIO *bio, *b64; 18191942Sa.suvorov@f5.com nxt_int_t count, ret; 18201942Sa.suvorov@f5.com u_char buf[128]; 18211942Sa.suvorov@f5.com 18221942Sa.suvorov@f5.com b64 = BIO_new(BIO_f_base64()); 18231942Sa.suvorov@f5.com if (nxt_slow_path(b64 == NULL)) { 18241942Sa.suvorov@f5.com goto error; 18251942Sa.suvorov@f5.com } 18261942Sa.suvorov@f5.com 18271942Sa.suvorov@f5.com bio = BIO_new_mem_buf(s, slen); 18281942Sa.suvorov@f5.com if (nxt_slow_path(bio == NULL)) { 18291942Sa.suvorov@f5.com goto error; 18301942Sa.suvorov@f5.com } 18311942Sa.suvorov@f5.com 18321942Sa.suvorov@f5.com bio = BIO_push(b64, bio); 18331942Sa.suvorov@f5.com 18341942Sa.suvorov@f5.com BIO_set_flags(bio, BIO_FLAGS_BASE64_NO_NL); 18351942Sa.suvorov@f5.com 18361942Sa.suvorov@f5.com count = 0; 18371942Sa.suvorov@f5.com 18381942Sa.suvorov@f5.com if (d == NULL) { 18391942Sa.suvorov@f5.com 18401942Sa.suvorov@f5.com for ( ;; ) { 18411942Sa.suvorov@f5.com ret = BIO_read(bio, buf, 128); 18421942Sa.suvorov@f5.com 18431942Sa.suvorov@f5.com if (ret < 0) { 18441942Sa.suvorov@f5.com goto invalid; 18451942Sa.suvorov@f5.com } 18461942Sa.suvorov@f5.com 18471942Sa.suvorov@f5.com count += ret; 18481942Sa.suvorov@f5.com 18491942Sa.suvorov@f5.com if (ret != 128) { 18501942Sa.suvorov@f5.com break; 18511942Sa.suvorov@f5.com } 18521942Sa.suvorov@f5.com } 18531942Sa.suvorov@f5.com 18541942Sa.suvorov@f5.com } else { 18551942Sa.suvorov@f5.com count = BIO_read(bio, d, dlen); 18561942Sa.suvorov@f5.com 18571942Sa.suvorov@f5.com if (count < 0) { 18581942Sa.suvorov@f5.com goto invalid; 18591942Sa.suvorov@f5.com } 18601942Sa.suvorov@f5.com } 18611942Sa.suvorov@f5.com 18621942Sa.suvorov@f5.com BIO_free_all(bio); 18631942Sa.suvorov@f5.com 18641942Sa.suvorov@f5.com return count; 18651942Sa.suvorov@f5.com 18661942Sa.suvorov@f5.com error: 18671942Sa.suvorov@f5.com 18681942Sa.suvorov@f5.com BIO_vfree(b64); 18691942Sa.suvorov@f5.com ERR_clear_error(); 18701942Sa.suvorov@f5.com 18711942Sa.suvorov@f5.com return NXT_ERROR; 18721942Sa.suvorov@f5.com 18731942Sa.suvorov@f5.com invalid: 18741942Sa.suvorov@f5.com 18751942Sa.suvorov@f5.com BIO_free_all(bio); 18761942Sa.suvorov@f5.com ERR_clear_error(); 18771942Sa.suvorov@f5.com 18781942Sa.suvorov@f5.com return NXT_DECLINED; 18791942Sa.suvorov@f5.com } 1880