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> 140Sigor@sysoev.ru 150Sigor@sysoev.ru 160Sigor@sysoev.ru typedef struct { 171828Sa.suvorov@f5.com SSL *session; 181828Sa.suvorov@f5.com nxt_conn_t *conn; 190Sigor@sysoev.ru 201828Sa.suvorov@f5.com int ssl_error; 211828Sa.suvorov@f5.com uint8_t times; /* 2 bits */ 221828Sa.suvorov@f5.com uint8_t handshake; /* 1 bit */ 230Sigor@sysoev.ru 241828Sa.suvorov@f5.com nxt_tls_conf_t *conf; 251828Sa.suvorov@f5.com nxt_buf_mem_t buffer; 260Sigor@sysoev.ru } nxt_openssl_conn_t; 270Sigor@sysoev.ru 280Sigor@sysoev.ru 29771Sigor@sysoev.ru typedef enum { 30771Sigor@sysoev.ru NXT_OPENSSL_HANDSHAKE = 0, 31771Sigor@sysoev.ru NXT_OPENSSL_READ, 32771Sigor@sysoev.ru NXT_OPENSSL_WRITE, 33771Sigor@sysoev.ru NXT_OPENSSL_SHUTDOWN, 34771Sigor@sysoev.ru } nxt_openssl_io_t; 35771Sigor@sysoev.ru 360Sigor@sysoev.ru 37771Sigor@sysoev.ru static nxt_int_t nxt_openssl_library_init(nxt_task_t *task); 38771Sigor@sysoev.ru static void nxt_openssl_library_free(nxt_task_t *task); 39771Sigor@sysoev.ru #if OPENSSL_VERSION_NUMBER < 0x10100004L 40771Sigor@sysoev.ru static nxt_int_t nxt_openssl_locks_init(void); 41771Sigor@sysoev.ru static void nxt_openssl_lock(int mode, int type, const char *file, int line); 42771Sigor@sysoev.ru static unsigned long nxt_openssl_thread_id(void); 43771Sigor@sysoev.ru static void nxt_openssl_locks_free(void); 44771Sigor@sysoev.ru #endif 45*1920Sa.suvorov@f5.com static nxt_int_t nxt_openssl_server_init(nxt_task_t *task, nxt_mp_t *mp, 46*1920Sa.suvorov@f5.com nxt_tls_init_t *tls_init, nxt_bool_t last); 471828Sa.suvorov@f5.com static nxt_int_t nxt_openssl_chain_file(nxt_task_t *task, SSL_CTX *ctx, 481828Sa.suvorov@f5.com nxt_tls_conf_t *conf, nxt_mp_t *mp, nxt_bool_t single); 491885Sa.suvorov@f5.com #if (NXT_HAVE_OPENSSL_CONF_CMD) 501885Sa.suvorov@f5.com static nxt_int_t nxt_ssl_conf_commands(nxt_task_t *task, SSL_CTX *ctx, 511885Sa.suvorov@f5.com nxt_conf_value_t *value, nxt_mp_t *mp); 521885Sa.suvorov@f5.com #endif 53*1920Sa.suvorov@f5.com static void nxt_ssl_session_cache(SSL_CTX *ctx, size_t cache_size, 54*1920Sa.suvorov@f5.com time_t timeout); 551828Sa.suvorov@f5.com static nxt_uint_t nxt_openssl_cert_get_names(nxt_task_t *task, X509 *cert, 561828Sa.suvorov@f5.com nxt_tls_conf_t *conf, nxt_mp_t *mp); 571828Sa.suvorov@f5.com static nxt_int_t nxt_openssl_bundle_hash_test(nxt_lvlhsh_query_t *lhq, 581828Sa.suvorov@f5.com void *data); 591828Sa.suvorov@f5.com static nxt_int_t nxt_openssl_bundle_hash_insert(nxt_task_t *task, 601828Sa.suvorov@f5.com nxt_lvlhsh_t *lvlhsh, nxt_tls_bundle_hash_item_t *item, nxt_mp_t * mp); 611828Sa.suvorov@f5.com static nxt_int_t nxt_openssl_servername(SSL *s, int *ad, void *arg); 621828Sa.suvorov@f5.com static nxt_tls_bundle_conf_t *nxt_openssl_find_ctx(nxt_tls_conf_t *conf, 631828Sa.suvorov@f5.com nxt_str_t *sn); 64771Sigor@sysoev.ru static void nxt_openssl_server_free(nxt_task_t *task, nxt_tls_conf_t *conf); 65771Sigor@sysoev.ru static void nxt_openssl_conn_init(nxt_task_t *task, nxt_tls_conf_t *conf, 6662Sigor@sysoev.ru nxt_conn_t *c); 671Sigor@sysoev.ru static void nxt_openssl_conn_handshake(nxt_task_t *task, void *obj, void *data); 68771Sigor@sysoev.ru static ssize_t nxt_openssl_conn_io_recvbuf(nxt_conn_t *c, nxt_buf_t *b); 69771Sigor@sysoev.ru static ssize_t nxt_openssl_conn_io_sendbuf(nxt_task_t *task, nxt_sendbuf_t *sb); 70771Sigor@sysoev.ru static ssize_t nxt_openssl_conn_io_send(nxt_task_t *task, nxt_sendbuf_t *sb, 71771Sigor@sysoev.ru void *buf, size_t size); 721Sigor@sysoev.ru static void nxt_openssl_conn_io_shutdown(nxt_task_t *task, void *obj, 730Sigor@sysoev.ru void *data); 74771Sigor@sysoev.ru static nxt_int_t nxt_openssl_conn_test_error(nxt_task_t *task, nxt_conn_t *c, 75771Sigor@sysoev.ru int ret, nxt_err_t sys_err, nxt_openssl_io_t io); 761884Sa.suvorov@f5.com static void nxt_openssl_conn_io_shutdown_timeout(nxt_task_t *task, void *obj, 771884Sa.suvorov@f5.com void *data); 78771Sigor@sysoev.ru static void nxt_cdecl nxt_openssl_conn_error(nxt_task_t *task, 79771Sigor@sysoev.ru nxt_err_t err, const char *fmt, ...); 80771Sigor@sysoev.ru static nxt_uint_t nxt_openssl_log_error_level(nxt_err_t err); 810Sigor@sysoev.ru 820Sigor@sysoev.ru 83771Sigor@sysoev.ru const nxt_tls_lib_t nxt_openssl_lib = { 84771Sigor@sysoev.ru .library_init = nxt_openssl_library_init, 85771Sigor@sysoev.ru .library_free = nxt_openssl_library_free, 86771Sigor@sysoev.ru 87771Sigor@sysoev.ru .server_init = nxt_openssl_server_init, 88771Sigor@sysoev.ru .server_free = nxt_openssl_server_free, 890Sigor@sysoev.ru }; 900Sigor@sysoev.ru 910Sigor@sysoev.ru 9262Sigor@sysoev.ru static nxt_conn_io_t nxt_openssl_conn_io = { 93771Sigor@sysoev.ru .read = nxt_conn_io_read, 94771Sigor@sysoev.ru .recvbuf = nxt_openssl_conn_io_recvbuf, 950Sigor@sysoev.ru 96771Sigor@sysoev.ru .write = nxt_conn_io_write, 97771Sigor@sysoev.ru .sendbuf = nxt_openssl_conn_io_sendbuf, 980Sigor@sysoev.ru 99771Sigor@sysoev.ru .shutdown = nxt_openssl_conn_io_shutdown, 1000Sigor@sysoev.ru }; 1010Sigor@sysoev.ru 1020Sigor@sysoev.ru 1030Sigor@sysoev.ru static long nxt_openssl_version; 1040Sigor@sysoev.ru static int nxt_openssl_connection_index; 1050Sigor@sysoev.ru 1060Sigor@sysoev.ru 1070Sigor@sysoev.ru static nxt_int_t 108771Sigor@sysoev.ru nxt_openssl_library_init(nxt_task_t *task) 1090Sigor@sysoev.ru { 1100Sigor@sysoev.ru int index; 1110Sigor@sysoev.ru 1120Sigor@sysoev.ru if (nxt_fast_path(nxt_openssl_version != 0)) { 1130Sigor@sysoev.ru return NXT_OK; 1140Sigor@sysoev.ru } 1150Sigor@sysoev.ru 116771Sigor@sysoev.ru #if OPENSSL_VERSION_NUMBER >= 0x10100003L 117771Sigor@sysoev.ru 118771Sigor@sysoev.ru OPENSSL_init_ssl(OPENSSL_INIT_LOAD_CONFIG, NULL); 1190Sigor@sysoev.ru 120771Sigor@sysoev.ru #else 121771Sigor@sysoev.ru { 122771Sigor@sysoev.ru nxt_int_t ret; 123771Sigor@sysoev.ru 124771Sigor@sysoev.ru SSL_load_error_strings(); 125771Sigor@sysoev.ru 126771Sigor@sysoev.ru OPENSSL_config(NULL); 1270Sigor@sysoev.ru 128771Sigor@sysoev.ru /* 129771Sigor@sysoev.ru * SSL_library_init(3): 130771Sigor@sysoev.ru * 131771Sigor@sysoev.ru * SSL_library_init() always returns "1", 132771Sigor@sysoev.ru * so it is safe to discard the return value. 133771Sigor@sysoev.ru */ 134771Sigor@sysoev.ru (void) SSL_library_init(); 135771Sigor@sysoev.ru 136771Sigor@sysoev.ru ret = nxt_openssl_locks_init(); 137771Sigor@sysoev.ru if (nxt_slow_path(ret != NXT_OK)) { 138771Sigor@sysoev.ru return ret; 139771Sigor@sysoev.ru } 140771Sigor@sysoev.ru } 141771Sigor@sysoev.ru 142771Sigor@sysoev.ru #endif 1430Sigor@sysoev.ru 1440Sigor@sysoev.ru nxt_openssl_version = SSLeay(); 1450Sigor@sysoev.ru 146771Sigor@sysoev.ru nxt_log(task, NXT_LOG_INFO, "%s, %xl", 147771Sigor@sysoev.ru SSLeay_version(SSLEAY_VERSION), nxt_openssl_version); 1480Sigor@sysoev.ru 1490Sigor@sysoev.ru #ifndef SSL_OP_NO_COMPRESSION 1500Sigor@sysoev.ru { 1510Sigor@sysoev.ru /* 1520Sigor@sysoev.ru * Disable gzip compression in OpenSSL prior to 1.0.0 1530Sigor@sysoev.ru * version, this saves about 522K per connection. 1540Sigor@sysoev.ru */ 1550Sigor@sysoev.ru int n; 1560Sigor@sysoev.ru STACK_OF(SSL_COMP) *ssl_comp_methods; 1570Sigor@sysoev.ru 1580Sigor@sysoev.ru ssl_comp_methods = SSL_COMP_get_compression_methods(); 1590Sigor@sysoev.ru 1600Sigor@sysoev.ru for (n = sk_SSL_COMP_num(ssl_comp_methods); n != 0; n--) { 1610Sigor@sysoev.ru (void) sk_SSL_COMP_pop(ssl_comp_methods); 1620Sigor@sysoev.ru } 1630Sigor@sysoev.ru } 1640Sigor@sysoev.ru #endif 1650Sigor@sysoev.ru 1660Sigor@sysoev.ru index = SSL_get_ex_new_index(0, NULL, NULL, NULL, NULL); 1670Sigor@sysoev.ru 1680Sigor@sysoev.ru if (index == -1) { 169771Sigor@sysoev.ru nxt_openssl_log_error(task, NXT_LOG_ALERT, 1700Sigor@sysoev.ru "SSL_get_ex_new_index() failed"); 1710Sigor@sysoev.ru return NXT_ERROR; 1720Sigor@sysoev.ru } 1730Sigor@sysoev.ru 1740Sigor@sysoev.ru nxt_openssl_connection_index = index; 1750Sigor@sysoev.ru 1760Sigor@sysoev.ru return NXT_OK; 1770Sigor@sysoev.ru } 1780Sigor@sysoev.ru 1790Sigor@sysoev.ru 180771Sigor@sysoev.ru #if OPENSSL_VERSION_NUMBER >= 0x10100003L 181771Sigor@sysoev.ru 182771Sigor@sysoev.ru static void 183771Sigor@sysoev.ru nxt_openssl_library_free(nxt_task_t *task) 184771Sigor@sysoev.ru { 185771Sigor@sysoev.ru } 186771Sigor@sysoev.ru 187771Sigor@sysoev.ru #else 188771Sigor@sysoev.ru 189771Sigor@sysoev.ru static nxt_thread_mutex_t *nxt_openssl_locks; 190771Sigor@sysoev.ru 1910Sigor@sysoev.ru static nxt_int_t 192771Sigor@sysoev.ru nxt_openssl_locks_init(void) 193771Sigor@sysoev.ru { 194771Sigor@sysoev.ru int i, n; 195771Sigor@sysoev.ru nxt_int_t ret; 196771Sigor@sysoev.ru 197771Sigor@sysoev.ru n = CRYPTO_num_locks(); 198771Sigor@sysoev.ru 199771Sigor@sysoev.ru nxt_openssl_locks = OPENSSL_malloc(n * sizeof(nxt_thread_mutex_t)); 200771Sigor@sysoev.ru if (nxt_slow_path(nxt_openssl_locks == NULL)) { 201771Sigor@sysoev.ru return NXT_ERROR; 202771Sigor@sysoev.ru } 203771Sigor@sysoev.ru 204771Sigor@sysoev.ru for (i = 0; i < n; i++) { 205771Sigor@sysoev.ru ret = nxt_thread_mutex_create(&nxt_openssl_locks[i]); 206771Sigor@sysoev.ru if (nxt_slow_path(ret != NXT_OK)) { 207771Sigor@sysoev.ru return ret; 208771Sigor@sysoev.ru } 209771Sigor@sysoev.ru } 210771Sigor@sysoev.ru 211771Sigor@sysoev.ru CRYPTO_set_locking_callback(nxt_openssl_lock); 212771Sigor@sysoev.ru 213771Sigor@sysoev.ru CRYPTO_set_id_callback(nxt_openssl_thread_id); 214771Sigor@sysoev.ru 215771Sigor@sysoev.ru return NXT_OK; 216771Sigor@sysoev.ru } 217771Sigor@sysoev.ru 218771Sigor@sysoev.ru 219771Sigor@sysoev.ru static void 220771Sigor@sysoev.ru nxt_openssl_lock(int mode, int type, const char *file, int line) 221771Sigor@sysoev.ru { 222771Sigor@sysoev.ru nxt_thread_mutex_t *lock; 223771Sigor@sysoev.ru 224771Sigor@sysoev.ru lock = &nxt_openssl_locks[type]; 225771Sigor@sysoev.ru 226771Sigor@sysoev.ru if ((mode & CRYPTO_LOCK) != 0) { 227771Sigor@sysoev.ru (void) nxt_thread_mutex_lock(lock); 228771Sigor@sysoev.ru 229771Sigor@sysoev.ru } else { 230771Sigor@sysoev.ru (void) nxt_thread_mutex_unlock(lock); 231771Sigor@sysoev.ru } 232771Sigor@sysoev.ru } 233771Sigor@sysoev.ru 234771Sigor@sysoev.ru 235771Sigor@sysoev.ru static u_long 236771Sigor@sysoev.ru nxt_openssl_thread_id(void) 237771Sigor@sysoev.ru { 238771Sigor@sysoev.ru return (u_long) nxt_thread_handle(); 239771Sigor@sysoev.ru } 240771Sigor@sysoev.ru 241771Sigor@sysoev.ru 242771Sigor@sysoev.ru static void 243771Sigor@sysoev.ru nxt_openssl_library_free(nxt_task_t *task) 244771Sigor@sysoev.ru { 245771Sigor@sysoev.ru nxt_openssl_locks_free(); 246771Sigor@sysoev.ru } 247771Sigor@sysoev.ru 248771Sigor@sysoev.ru 249771Sigor@sysoev.ru static void 250771Sigor@sysoev.ru nxt_openssl_locks_free(void) 251771Sigor@sysoev.ru { 252771Sigor@sysoev.ru int i, n; 253771Sigor@sysoev.ru 254771Sigor@sysoev.ru n = CRYPTO_num_locks(); 255771Sigor@sysoev.ru 256771Sigor@sysoev.ru CRYPTO_set_locking_callback(NULL); 257771Sigor@sysoev.ru 258771Sigor@sysoev.ru for (i = 0; i < n; i++) { 259771Sigor@sysoev.ru nxt_thread_mutex_destroy(&nxt_openssl_locks[i]); 260771Sigor@sysoev.ru } 261771Sigor@sysoev.ru 262771Sigor@sysoev.ru OPENSSL_free(nxt_openssl_locks); 263771Sigor@sysoev.ru } 264771Sigor@sysoev.ru 265771Sigor@sysoev.ru #endif 266771Sigor@sysoev.ru 267771Sigor@sysoev.ru 268771Sigor@sysoev.ru static nxt_int_t 269*1920Sa.suvorov@f5.com nxt_openssl_server_init(nxt_task_t *task, nxt_mp_t *mp, 270*1920Sa.suvorov@f5.com nxt_tls_init_t *tls_init, nxt_bool_t last) 2710Sigor@sysoev.ru { 2721828Sa.suvorov@f5.com SSL_CTX *ctx; 2731828Sa.suvorov@f5.com const char *ciphers, *ca_certificate; 274*1920Sa.suvorov@f5.com nxt_tls_conf_t *conf; 2751828Sa.suvorov@f5.com STACK_OF(X509_NAME) *list; 2761828Sa.suvorov@f5.com nxt_tls_bundle_conf_t *bundle; 2770Sigor@sysoev.ru 2780Sigor@sysoev.ru ctx = SSL_CTX_new(SSLv23_server_method()); 2790Sigor@sysoev.ru if (ctx == NULL) { 280771Sigor@sysoev.ru nxt_openssl_log_error(task, NXT_LOG_ALERT, "SSL_CTX_new() failed"); 2810Sigor@sysoev.ru return NXT_ERROR; 2820Sigor@sysoev.ru } 2830Sigor@sysoev.ru 284*1920Sa.suvorov@f5.com conf = tls_init->conf; 285*1920Sa.suvorov@f5.com 2861828Sa.suvorov@f5.com bundle = conf->bundle; 2871828Sa.suvorov@f5.com nxt_assert(bundle != NULL); 2881828Sa.suvorov@f5.com 2891828Sa.suvorov@f5.com bundle->ctx = ctx; 2900Sigor@sysoev.ru 291771Sigor@sysoev.ru #ifdef SSL_OP_NO_RENEGOTIATION 292771Sigor@sysoev.ru /* Renegration is not currently supported. */ 293771Sigor@sysoev.ru SSL_CTX_set_options(ctx, SSL_OP_NO_RENEGOTIATION); 294771Sigor@sysoev.ru #endif 295771Sigor@sysoev.ru 2960Sigor@sysoev.ru #ifdef SSL_OP_NO_COMPRESSION 2970Sigor@sysoev.ru /* 2980Sigor@sysoev.ru * Disable gzip compression in OpenSSL 1.0.0, 2990Sigor@sysoev.ru * this saves about 522K per connection. 3000Sigor@sysoev.ru */ 3010Sigor@sysoev.ru SSL_CTX_set_options(ctx, SSL_OP_NO_COMPRESSION); 3020Sigor@sysoev.ru #endif 3030Sigor@sysoev.ru 3040Sigor@sysoev.ru #ifdef SSL_MODE_RELEASE_BUFFERS 3050Sigor@sysoev.ru 3060Sigor@sysoev.ru if (nxt_openssl_version >= 10001078) { 3070Sigor@sysoev.ru /* 3080Sigor@sysoev.ru * Allow to release read and write buffers in OpenSSL 1.0.0, 3090Sigor@sysoev.ru * this saves about 34K per idle connection. It is not safe 3100Sigor@sysoev.ru * before OpenSSL 1.0.1h (CVE-2010-5298). 3110Sigor@sysoev.ru */ 3120Sigor@sysoev.ru SSL_CTX_set_mode(ctx, SSL_MODE_RELEASE_BUFFERS); 3130Sigor@sysoev.ru } 3140Sigor@sysoev.ru 3150Sigor@sysoev.ru #endif 3160Sigor@sysoev.ru 3171828Sa.suvorov@f5.com if (nxt_openssl_chain_file(task, ctx, conf, mp, 3181828Sa.suvorov@f5.com last && bundle->next == NULL) 3191828Sa.suvorov@f5.com != NXT_OK) 3201828Sa.suvorov@f5.com { 3210Sigor@sysoev.ru goto fail; 3220Sigor@sysoev.ru } 323774Svbart@nginx.com /* 3240Sigor@sysoev.ru key = conf->certificate_key; 3250Sigor@sysoev.ru 3260Sigor@sysoev.ru if (SSL_CTX_use_PrivateKey_file(ctx, key, SSL_FILETYPE_PEM) == 0) { 327771Sigor@sysoev.ru nxt_openssl_log_error(task, NXT_LOG_ALERT, 3280Sigor@sysoev.ru "SSL_CTX_use_PrivateKey_file(\"%s\") failed", 3290Sigor@sysoev.ru key); 3300Sigor@sysoev.ru goto fail; 3310Sigor@sysoev.ru } 332774Svbart@nginx.com */ 3331885Sa.suvorov@f5.com 3340Sigor@sysoev.ru ciphers = (conf->ciphers != NULL) ? conf->ciphers : "HIGH:!aNULL:!MD5"; 3350Sigor@sysoev.ru 3360Sigor@sysoev.ru if (SSL_CTX_set_cipher_list(ctx, ciphers) == 0) { 337771Sigor@sysoev.ru nxt_openssl_log_error(task, NXT_LOG_ALERT, 3380Sigor@sysoev.ru "SSL_CTX_set_cipher_list(\"%s\") failed", 3390Sigor@sysoev.ru ciphers); 3400Sigor@sysoev.ru goto fail; 3410Sigor@sysoev.ru } 3420Sigor@sysoev.ru 3431885Sa.suvorov@f5.com #if (NXT_HAVE_OPENSSL_CONF_CMD) 344*1920Sa.suvorov@f5.com if (tls_init->conf_cmds != NULL 345*1920Sa.suvorov@f5.com && nxt_ssl_conf_commands(task, ctx, tls_init->conf_cmds, mp) != NXT_OK) 3461885Sa.suvorov@f5.com { 3471885Sa.suvorov@f5.com goto fail; 3481885Sa.suvorov@f5.com } 3491885Sa.suvorov@f5.com #endif 3501885Sa.suvorov@f5.com 351*1920Sa.suvorov@f5.com nxt_ssl_session_cache(ctx, tls_init->cache_size, tls_init->timeout); 352*1920Sa.suvorov@f5.com 3530Sigor@sysoev.ru SSL_CTX_set_options(ctx, SSL_OP_CIPHER_SERVER_PREFERENCE); 3540Sigor@sysoev.ru 3550Sigor@sysoev.ru if (conf->ca_certificate != NULL) { 3560Sigor@sysoev.ru 3570Sigor@sysoev.ru /* TODO: verify callback */ 3580Sigor@sysoev.ru SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER, NULL); 3590Sigor@sysoev.ru 3600Sigor@sysoev.ru /* TODO: verify depth */ 3610Sigor@sysoev.ru SSL_CTX_set_verify_depth(ctx, 1); 3620Sigor@sysoev.ru 3630Sigor@sysoev.ru ca_certificate = conf->ca_certificate; 3640Sigor@sysoev.ru 3650Sigor@sysoev.ru if (SSL_CTX_load_verify_locations(ctx, ca_certificate, NULL) == 0) { 366771Sigor@sysoev.ru nxt_openssl_log_error(task, NXT_LOG_ALERT, 3670Sigor@sysoev.ru "SSL_CTX_load_verify_locations(\"%s\") failed", 3680Sigor@sysoev.ru ca_certificate); 3690Sigor@sysoev.ru goto fail; 3700Sigor@sysoev.ru } 3710Sigor@sysoev.ru 3720Sigor@sysoev.ru list = SSL_load_client_CA_file(ca_certificate); 3730Sigor@sysoev.ru 3740Sigor@sysoev.ru if (list == NULL) { 375771Sigor@sysoev.ru nxt_openssl_log_error(task, NXT_LOG_ALERT, 3760Sigor@sysoev.ru "SSL_load_client_CA_file(\"%s\") failed", 3770Sigor@sysoev.ru ca_certificate); 3780Sigor@sysoev.ru goto fail; 3790Sigor@sysoev.ru } 3800Sigor@sysoev.ru 3810Sigor@sysoev.ru /* 3820Sigor@sysoev.ru * SSL_load_client_CA_file() in OpenSSL prior to 0.9.7h and 3830Sigor@sysoev.ru * 0.9.8 versions always leaves an error in the error queue. 3840Sigor@sysoev.ru */ 3850Sigor@sysoev.ru ERR_clear_error(); 3860Sigor@sysoev.ru 3870Sigor@sysoev.ru SSL_CTX_set_client_CA_list(ctx, list); 3880Sigor@sysoev.ru } 3890Sigor@sysoev.ru 3901828Sa.suvorov@f5.com if (last) { 3911828Sa.suvorov@f5.com conf->conn_init = nxt_openssl_conn_init; 3921828Sa.suvorov@f5.com 3931828Sa.suvorov@f5.com if (bundle->next != NULL) { 3941828Sa.suvorov@f5.com SSL_CTX_set_tlsext_servername_callback(ctx, nxt_openssl_servername); 3951828Sa.suvorov@f5.com } 3961828Sa.suvorov@f5.com } 3971828Sa.suvorov@f5.com 3980Sigor@sysoev.ru return NXT_OK; 3990Sigor@sysoev.ru 4000Sigor@sysoev.ru fail: 4010Sigor@sysoev.ru 4020Sigor@sysoev.ru SSL_CTX_free(ctx); 4030Sigor@sysoev.ru 4041818Smax.romanov@nginx.com #if (OPENSSL_VERSION_NUMBER >= 0x1010100fL \ 4051818Smax.romanov@nginx.com && OPENSSL_VERSION_NUMBER < 0x1010101fL) 4061818Smax.romanov@nginx.com RAND_keep_random_devices_open(0); 4071818Smax.romanov@nginx.com #endif 4081818Smax.romanov@nginx.com 4090Sigor@sysoev.ru return NXT_ERROR; 4100Sigor@sysoev.ru } 4110Sigor@sysoev.ru 4120Sigor@sysoev.ru 413833Svbart@nginx.com static nxt_int_t 4141828Sa.suvorov@f5.com nxt_openssl_chain_file(nxt_task_t *task, SSL_CTX *ctx, nxt_tls_conf_t *conf, 4151828Sa.suvorov@f5.com nxt_mp_t *mp, nxt_bool_t single) 416774Svbart@nginx.com { 4171828Sa.suvorov@f5.com BIO *bio; 4181828Sa.suvorov@f5.com X509 *cert, *ca; 4191828Sa.suvorov@f5.com long reason; 4201828Sa.suvorov@f5.com EVP_PKEY *key; 4211828Sa.suvorov@f5.com nxt_int_t ret; 4221828Sa.suvorov@f5.com nxt_tls_bundle_conf_t *bundle; 4231828Sa.suvorov@f5.com 4241828Sa.suvorov@f5.com ret = NXT_ERROR; 4251828Sa.suvorov@f5.com cert = NULL; 426774Svbart@nginx.com 427774Svbart@nginx.com bio = BIO_new(BIO_s_fd()); 428774Svbart@nginx.com if (bio == NULL) { 4291828Sa.suvorov@f5.com goto end; 430774Svbart@nginx.com } 431774Svbart@nginx.com 4321828Sa.suvorov@f5.com bundle = conf->bundle; 433774Svbart@nginx.com 4341828Sa.suvorov@f5.com BIO_set_fd(bio, bundle->chain_file, BIO_CLOSE); 435774Svbart@nginx.com 436774Svbart@nginx.com cert = PEM_read_bio_X509_AUX(bio, NULL, NULL, NULL); 437774Svbart@nginx.com if (cert == NULL) { 438774Svbart@nginx.com goto end; 439774Svbart@nginx.com } 440774Svbart@nginx.com 441774Svbart@nginx.com if (SSL_CTX_use_certificate(ctx, cert) != 1) { 442774Svbart@nginx.com goto end; 443774Svbart@nginx.com } 444774Svbart@nginx.com 4451828Sa.suvorov@f5.com if (!single && nxt_openssl_cert_get_names(task, cert, conf, mp) != NXT_OK) { 4461828Sa.suvorov@f5.com goto clean; 4471828Sa.suvorov@f5.com } 4481828Sa.suvorov@f5.com 449774Svbart@nginx.com for ( ;; ) { 450774Svbart@nginx.com ca = PEM_read_bio_X509(bio, NULL, NULL, NULL); 451774Svbart@nginx.com 452774Svbart@nginx.com if (ca == NULL) { 453774Svbart@nginx.com reason = ERR_GET_REASON(ERR_peek_last_error()); 454774Svbart@nginx.com if (reason != PEM_R_NO_START_LINE) { 455774Svbart@nginx.com goto end; 456774Svbart@nginx.com } 457774Svbart@nginx.com 458774Svbart@nginx.com ERR_clear_error(); 459774Svbart@nginx.com break; 460774Svbart@nginx.com } 461774Svbart@nginx.com 462774Svbart@nginx.com /* 463774Svbart@nginx.com * Note that ca isn't freed if it was successfully added to the chain, 464774Svbart@nginx.com * while the main certificate needs a X509_free() call, since 465774Svbart@nginx.com * its reference count is increased by SSL_CTX_use_certificate(). 466774Svbart@nginx.com */ 467808Spluknet@nginx.com #ifdef SSL_CTX_add0_chain_cert 468774Svbart@nginx.com if (SSL_CTX_add0_chain_cert(ctx, ca) != 1) { 469774Svbart@nginx.com #else 470774Svbart@nginx.com if (SSL_CTX_add_extra_chain_cert(ctx, ca) != 1) { 471774Svbart@nginx.com #endif 472774Svbart@nginx.com X509_free(ca); 473774Svbart@nginx.com goto end; 474774Svbart@nginx.com } 475774Svbart@nginx.com } 476774Svbart@nginx.com 477774Svbart@nginx.com if (BIO_reset(bio) != 0) { 478774Svbart@nginx.com goto end; 479774Svbart@nginx.com } 480774Svbart@nginx.com 481774Svbart@nginx.com key = PEM_read_bio_PrivateKey(bio, NULL, NULL, NULL); 482774Svbart@nginx.com if (key == NULL) { 483774Svbart@nginx.com goto end; 484774Svbart@nginx.com } 485774Svbart@nginx.com 486774Svbart@nginx.com if (SSL_CTX_use_PrivateKey(ctx, key) == 1) { 487774Svbart@nginx.com ret = NXT_OK; 488774Svbart@nginx.com } 489774Svbart@nginx.com 490774Svbart@nginx.com EVP_PKEY_free(key); 491774Svbart@nginx.com 492774Svbart@nginx.com end: 493774Svbart@nginx.com 4941828Sa.suvorov@f5.com if (ret != NXT_OK) { 4951828Sa.suvorov@f5.com nxt_openssl_log_error(task, NXT_LOG_ALERT, 4961828Sa.suvorov@f5.com "nxt_openssl_chain_file() failed"); 4971828Sa.suvorov@f5.com } 4981828Sa.suvorov@f5.com 4991828Sa.suvorov@f5.com clean: 5001828Sa.suvorov@f5.com 5011828Sa.suvorov@f5.com BIO_free(bio); 502774Svbart@nginx.com X509_free(cert); 503774Svbart@nginx.com 504774Svbart@nginx.com return ret; 505774Svbart@nginx.com } 506774Svbart@nginx.com 507774Svbart@nginx.com 5081885Sa.suvorov@f5.com #if (NXT_HAVE_OPENSSL_CONF_CMD) 5091885Sa.suvorov@f5.com 5101885Sa.suvorov@f5.com static nxt_int_t 5111885Sa.suvorov@f5.com nxt_ssl_conf_commands(nxt_task_t *task, SSL_CTX *ctx, nxt_conf_value_t *conf, 5121885Sa.suvorov@f5.com nxt_mp_t *mp) 5131885Sa.suvorov@f5.com { 5141885Sa.suvorov@f5.com int ret; 5151885Sa.suvorov@f5.com char *zcmd, *zvalue; 5161885Sa.suvorov@f5.com uint32_t index; 5171885Sa.suvorov@f5.com nxt_str_t cmd, value; 5181885Sa.suvorov@f5.com SSL_CONF_CTX *cctx; 5191885Sa.suvorov@f5.com nxt_conf_value_t *member; 5201885Sa.suvorov@f5.com 5211885Sa.suvorov@f5.com cctx = SSL_CONF_CTX_new(); 5221885Sa.suvorov@f5.com if (nxt_slow_path(cctx == NULL)) { 5231885Sa.suvorov@f5.com nxt_openssl_log_error(task, NXT_LOG_ALERT, 5241885Sa.suvorov@f5.com "SSL_CONF_CTX_new() failed"); 5251885Sa.suvorov@f5.com return NXT_ERROR; 5261885Sa.suvorov@f5.com } 5271885Sa.suvorov@f5.com 5281885Sa.suvorov@f5.com SSL_CONF_CTX_set_flags(cctx, SSL_CONF_FLAG_FILE 5291885Sa.suvorov@f5.com | SSL_CONF_FLAG_SERVER 5301885Sa.suvorov@f5.com | SSL_CONF_FLAG_CERTIFICATE 5311885Sa.suvorov@f5.com | SSL_CONF_FLAG_SHOW_ERRORS); 5321885Sa.suvorov@f5.com 5331885Sa.suvorov@f5.com SSL_CONF_CTX_set_ssl_ctx(cctx, ctx); 5341885Sa.suvorov@f5.com 5351885Sa.suvorov@f5.com index = 0; 5361885Sa.suvorov@f5.com 5371885Sa.suvorov@f5.com for ( ;; ) { 5381885Sa.suvorov@f5.com member = nxt_conf_next_object_member(conf, &cmd, &index); 5391885Sa.suvorov@f5.com if (nxt_slow_path(member == NULL)) { 5401885Sa.suvorov@f5.com break; 5411885Sa.suvorov@f5.com } 5421885Sa.suvorov@f5.com 5431885Sa.suvorov@f5.com nxt_conf_get_string(member, &value); 5441885Sa.suvorov@f5.com 5451885Sa.suvorov@f5.com zcmd = nxt_str_cstrz(mp, &cmd); 5461885Sa.suvorov@f5.com zvalue = nxt_str_cstrz(mp, &value); 5471885Sa.suvorov@f5.com 5481885Sa.suvorov@f5.com if (nxt_slow_path(zcmd == NULL || zvalue == NULL)) { 5491885Sa.suvorov@f5.com goto fail; 5501885Sa.suvorov@f5.com } 5511885Sa.suvorov@f5.com 5521885Sa.suvorov@f5.com ret = SSL_CONF_cmd(cctx, zcmd, zvalue); 5531885Sa.suvorov@f5.com if (ret == -2) { 5541885Sa.suvorov@f5.com nxt_openssl_log_error(task, NXT_LOG_ERR, 5551885Sa.suvorov@f5.com "unknown command \"%s\" in " 5561885Sa.suvorov@f5.com "\"conf_commands\" option", zcmd); 5571885Sa.suvorov@f5.com goto fail; 5581885Sa.suvorov@f5.com } 5591885Sa.suvorov@f5.com 5601885Sa.suvorov@f5.com if (ret <= 0) { 5611885Sa.suvorov@f5.com nxt_openssl_log_error(task, NXT_LOG_ERR, 5621885Sa.suvorov@f5.com "invalid value \"%s\" for command \"%s\" " 5631885Sa.suvorov@f5.com "in \"conf_commands\" option", 5641885Sa.suvorov@f5.com zvalue, zcmd); 5651885Sa.suvorov@f5.com goto fail; 5661885Sa.suvorov@f5.com } 5671885Sa.suvorov@f5.com 5681885Sa.suvorov@f5.com nxt_debug(task, "SSL_CONF_cmd(\"%s\", \"%s\")", zcmd, zvalue); 5691885Sa.suvorov@f5.com } 5701885Sa.suvorov@f5.com 5711885Sa.suvorov@f5.com if (SSL_CONF_CTX_finish(cctx) != 1) { 5721885Sa.suvorov@f5.com nxt_openssl_log_error(task, NXT_LOG_ALERT, 5731885Sa.suvorov@f5.com "SSL_CONF_finish() failed"); 5741885Sa.suvorov@f5.com goto fail; 5751885Sa.suvorov@f5.com } 5761885Sa.suvorov@f5.com 5771885Sa.suvorov@f5.com SSL_CONF_CTX_free(cctx); 5781885Sa.suvorov@f5.com 5791885Sa.suvorov@f5.com return NXT_OK; 5801885Sa.suvorov@f5.com 5811885Sa.suvorov@f5.com fail: 5821885Sa.suvorov@f5.com 5831885Sa.suvorov@f5.com SSL_CONF_CTX_free(cctx); 5841885Sa.suvorov@f5.com 5851885Sa.suvorov@f5.com return NXT_ERROR; 5861885Sa.suvorov@f5.com } 5871885Sa.suvorov@f5.com 5881885Sa.suvorov@f5.com #endif 5891885Sa.suvorov@f5.com 5901885Sa.suvorov@f5.com 591*1920Sa.suvorov@f5.com static void 592*1920Sa.suvorov@f5.com nxt_ssl_session_cache(SSL_CTX *ctx, size_t cache_size, time_t timeout) 593*1920Sa.suvorov@f5.com { 594*1920Sa.suvorov@f5.com if (cache_size == 0) { 595*1920Sa.suvorov@f5.com SSL_CTX_set_session_cache_mode(ctx, SSL_SESS_CACHE_OFF); 596*1920Sa.suvorov@f5.com return; 597*1920Sa.suvorov@f5.com } 598*1920Sa.suvorov@f5.com 599*1920Sa.suvorov@f5.com SSL_CTX_set_session_cache_mode(ctx, SSL_SESS_CACHE_SERVER); 600*1920Sa.suvorov@f5.com 601*1920Sa.suvorov@f5.com SSL_CTX_sess_set_cache_size(ctx, cache_size); 602*1920Sa.suvorov@f5.com 603*1920Sa.suvorov@f5.com SSL_CTX_set_timeout(ctx, (long) timeout); 604*1920Sa.suvorov@f5.com } 605*1920Sa.suvorov@f5.com 606*1920Sa.suvorov@f5.com 6071828Sa.suvorov@f5.com static nxt_uint_t 6081828Sa.suvorov@f5.com nxt_openssl_cert_get_names(nxt_task_t *task, X509 *cert, nxt_tls_conf_t *conf, 6091828Sa.suvorov@f5.com nxt_mp_t *mp) 6101828Sa.suvorov@f5.com { 6111828Sa.suvorov@f5.com int len; 6121828Sa.suvorov@f5.com nxt_str_t domain, str; 6131828Sa.suvorov@f5.com X509_NAME *x509_name; 6141828Sa.suvorov@f5.com nxt_uint_t i, n; 6151828Sa.suvorov@f5.com GENERAL_NAME *name; 6161828Sa.suvorov@f5.com nxt_tls_bundle_conf_t *bundle; 6171828Sa.suvorov@f5.com STACK_OF(GENERAL_NAME) *alt_names; 6181828Sa.suvorov@f5.com nxt_tls_bundle_hash_item_t *item; 6191828Sa.suvorov@f5.com 6201828Sa.suvorov@f5.com bundle = conf->bundle; 6211828Sa.suvorov@f5.com 6221828Sa.suvorov@f5.com alt_names = X509_get_ext_d2i(cert, NID_subject_alt_name, NULL, NULL); 6231828Sa.suvorov@f5.com 6241828Sa.suvorov@f5.com if (alt_names != NULL) { 6251828Sa.suvorov@f5.com n = sk_GENERAL_NAME_num(alt_names); 6261828Sa.suvorov@f5.com 6271828Sa.suvorov@f5.com for (i = 0; i != n; i++) { 6281828Sa.suvorov@f5.com name = sk_GENERAL_NAME_value(alt_names, i); 6291828Sa.suvorov@f5.com 6301828Sa.suvorov@f5.com if (name->type != GEN_DNS) { 6311828Sa.suvorov@f5.com continue; 6321828Sa.suvorov@f5.com } 6331828Sa.suvorov@f5.com 6341828Sa.suvorov@f5.com str.length = ASN1_STRING_length(name->d.dNSName); 6351828Sa.suvorov@f5.com #if OPENSSL_VERSION_NUMBER > 0x10100000L 6361828Sa.suvorov@f5.com str.start = (u_char *) ASN1_STRING_get0_data(name->d.dNSName); 6371828Sa.suvorov@f5.com #else 6381828Sa.suvorov@f5.com str.start = ASN1_STRING_data(name->d.dNSName); 6391828Sa.suvorov@f5.com #endif 6401828Sa.suvorov@f5.com 6411828Sa.suvorov@f5.com domain.start = nxt_mp_nget(mp, str.length); 6421828Sa.suvorov@f5.com if (nxt_slow_path(domain.start == NULL)) { 6431828Sa.suvorov@f5.com goto fail; 6441828Sa.suvorov@f5.com } 6451828Sa.suvorov@f5.com 6461828Sa.suvorov@f5.com domain.length = str.length; 6471828Sa.suvorov@f5.com nxt_memcpy_lowcase(domain.start, str.start, str.length); 6481828Sa.suvorov@f5.com 6491828Sa.suvorov@f5.com item = nxt_mp_get(mp, sizeof(nxt_tls_bundle_hash_item_t)); 6501828Sa.suvorov@f5.com if (nxt_slow_path(item == NULL)) { 6511828Sa.suvorov@f5.com goto fail; 6521828Sa.suvorov@f5.com } 6531828Sa.suvorov@f5.com 6541828Sa.suvorov@f5.com item->name = domain; 6551828Sa.suvorov@f5.com item->bundle = bundle; 6561828Sa.suvorov@f5.com 6571828Sa.suvorov@f5.com if (nxt_openssl_bundle_hash_insert(task, &conf->bundle_hash, 6581828Sa.suvorov@f5.com item, mp) 6591828Sa.suvorov@f5.com == NXT_ERROR) 6601828Sa.suvorov@f5.com { 6611828Sa.suvorov@f5.com goto fail; 6621828Sa.suvorov@f5.com } 6631828Sa.suvorov@f5.com } 6641828Sa.suvorov@f5.com 6651828Sa.suvorov@f5.com sk_GENERAL_NAME_pop_free(alt_names, GENERAL_NAME_free); 6661828Sa.suvorov@f5.com 6671828Sa.suvorov@f5.com } else { 6681828Sa.suvorov@f5.com x509_name = X509_get_subject_name(cert); 6691828Sa.suvorov@f5.com len = X509_NAME_get_text_by_NID(x509_name, NID_commonName, 6701828Sa.suvorov@f5.com NULL, 0); 6711828Sa.suvorov@f5.com if (len <= 0) { 6721828Sa.suvorov@f5.com nxt_log(task, NXT_LOG_WARN, "certificate \"%V\" has neither " 6731885Sa.suvorov@f5.com "Subject Alternative Name nor Common Name", &bundle->name); 6741828Sa.suvorov@f5.com return NXT_OK; 6751828Sa.suvorov@f5.com } 6761828Sa.suvorov@f5.com 6771828Sa.suvorov@f5.com domain.start = nxt_mp_nget(mp, len + 1); 6781828Sa.suvorov@f5.com if (nxt_slow_path(domain.start == NULL)) { 6791828Sa.suvorov@f5.com return NXT_ERROR; 6801828Sa.suvorov@f5.com } 6811828Sa.suvorov@f5.com 6821828Sa.suvorov@f5.com domain.length = X509_NAME_get_text_by_NID(x509_name, NID_commonName, 6831828Sa.suvorov@f5.com (char *) domain.start, 6841828Sa.suvorov@f5.com len + 1); 6851828Sa.suvorov@f5.com nxt_memcpy_lowcase(domain.start, domain.start, domain.length); 6861828Sa.suvorov@f5.com 6871828Sa.suvorov@f5.com item = nxt_mp_get(mp, sizeof(nxt_tls_bundle_hash_item_t)); 6881828Sa.suvorov@f5.com if (nxt_slow_path(item == NULL)) { 6891828Sa.suvorov@f5.com return NXT_ERROR; 6901828Sa.suvorov@f5.com } 6911828Sa.suvorov@f5.com 6921828Sa.suvorov@f5.com item->name = domain; 6931828Sa.suvorov@f5.com item->bundle = bundle; 6941828Sa.suvorov@f5.com 6951828Sa.suvorov@f5.com if (nxt_openssl_bundle_hash_insert(task, &conf->bundle_hash, item, 6961828Sa.suvorov@f5.com mp) 6971828Sa.suvorov@f5.com == NXT_ERROR) 6981828Sa.suvorov@f5.com { 6991828Sa.suvorov@f5.com return NXT_ERROR; 7001828Sa.suvorov@f5.com } 7011828Sa.suvorov@f5.com } 7021828Sa.suvorov@f5.com 7031828Sa.suvorov@f5.com return NXT_OK; 7041828Sa.suvorov@f5.com 7051828Sa.suvorov@f5.com fail: 7061828Sa.suvorov@f5.com 7071828Sa.suvorov@f5.com sk_GENERAL_NAME_pop_free(alt_names, GENERAL_NAME_free); 7081828Sa.suvorov@f5.com 7091828Sa.suvorov@f5.com return NXT_ERROR; 7101828Sa.suvorov@f5.com } 7111828Sa.suvorov@f5.com 7121828Sa.suvorov@f5.com 7131828Sa.suvorov@f5.com static const nxt_lvlhsh_proto_t nxt_openssl_bundle_hash_proto 7141828Sa.suvorov@f5.com nxt_aligned(64) = 7151828Sa.suvorov@f5.com { 7161828Sa.suvorov@f5.com NXT_LVLHSH_DEFAULT, 7171828Sa.suvorov@f5.com nxt_openssl_bundle_hash_test, 7181828Sa.suvorov@f5.com nxt_mp_lvlhsh_alloc, 7191828Sa.suvorov@f5.com nxt_mp_lvlhsh_free, 7201828Sa.suvorov@f5.com }; 7211828Sa.suvorov@f5.com 7221828Sa.suvorov@f5.com 7231828Sa.suvorov@f5.com static nxt_int_t 7241828Sa.suvorov@f5.com nxt_openssl_bundle_hash_test(nxt_lvlhsh_query_t *lhq, void *data) 7251828Sa.suvorov@f5.com { 7261828Sa.suvorov@f5.com nxt_tls_bundle_hash_item_t *item; 7271828Sa.suvorov@f5.com 7281828Sa.suvorov@f5.com item = data; 7291828Sa.suvorov@f5.com 7301828Sa.suvorov@f5.com return nxt_strstr_eq(&lhq->key, &item->name) ? NXT_OK : NXT_DECLINED; 7311828Sa.suvorov@f5.com } 7321828Sa.suvorov@f5.com 7331828Sa.suvorov@f5.com 7341828Sa.suvorov@f5.com static nxt_int_t 7351828Sa.suvorov@f5.com nxt_openssl_bundle_hash_insert(nxt_task_t *task, nxt_lvlhsh_t *lvlhsh, 7361828Sa.suvorov@f5.com nxt_tls_bundle_hash_item_t *item, nxt_mp_t *mp) 7371828Sa.suvorov@f5.com { 7381828Sa.suvorov@f5.com nxt_str_t str; 7391828Sa.suvorov@f5.com nxt_int_t ret; 7401828Sa.suvorov@f5.com nxt_lvlhsh_query_t lhq; 7411828Sa.suvorov@f5.com nxt_tls_bundle_hash_item_t *old; 7421828Sa.suvorov@f5.com 7431828Sa.suvorov@f5.com str = item->name; 7441828Sa.suvorov@f5.com 7451828Sa.suvorov@f5.com if (item->name.start[0] == '*') { 7461828Sa.suvorov@f5.com item->name.start++; 7471828Sa.suvorov@f5.com item->name.length--; 7481828Sa.suvorov@f5.com 7491828Sa.suvorov@f5.com if (item->name.length == 0 || item->name.start[0] != '.') { 7501828Sa.suvorov@f5.com nxt_log(task, NXT_LOG_WARN, "ignored invalid name \"%V\" " 7511828Sa.suvorov@f5.com "in certificate \"%V\": missing \".\" " 7521885Sa.suvorov@f5.com "after wildcard symbol", &str, &item->bundle->name); 7531828Sa.suvorov@f5.com return NXT_OK; 7541828Sa.suvorov@f5.com } 7551828Sa.suvorov@f5.com } 7561828Sa.suvorov@f5.com 7571828Sa.suvorov@f5.com lhq.pool = mp; 7581828Sa.suvorov@f5.com lhq.key = item->name; 7591828Sa.suvorov@f5.com lhq.value = item; 7601828Sa.suvorov@f5.com lhq.proto = &nxt_openssl_bundle_hash_proto; 7611828Sa.suvorov@f5.com lhq.replace = 0; 7621828Sa.suvorov@f5.com lhq.key_hash = nxt_murmur_hash2(item->name.start, item->name.length); 7631828Sa.suvorov@f5.com 7641828Sa.suvorov@f5.com ret = nxt_lvlhsh_insert(lvlhsh, &lhq); 7651828Sa.suvorov@f5.com if (nxt_fast_path(ret == NXT_OK)) { 7661828Sa.suvorov@f5.com nxt_debug(task, "name \"%V\" for certificate \"%V\" is inserted", 7671885Sa.suvorov@f5.com &str, &item->bundle->name); 7681828Sa.suvorov@f5.com return NXT_OK; 7691828Sa.suvorov@f5.com } 7701828Sa.suvorov@f5.com 7711828Sa.suvorov@f5.com if (nxt_fast_path(ret == NXT_DECLINED)) { 7721828Sa.suvorov@f5.com old = lhq.value; 7731828Sa.suvorov@f5.com if (old->bundle != item->bundle) { 7741828Sa.suvorov@f5.com nxt_log(task, NXT_LOG_WARN, "ignored duplicate name \"%V\" " 7751828Sa.suvorov@f5.com "in certificate \"%V\", identical name appears in \"%V\"", 7761885Sa.suvorov@f5.com &str, &old->bundle->name, &item->bundle->name); 7771828Sa.suvorov@f5.com 7781828Sa.suvorov@f5.com old->bundle = item->bundle; 7791828Sa.suvorov@f5.com } 7801828Sa.suvorov@f5.com 7811828Sa.suvorov@f5.com return NXT_OK; 7821828Sa.suvorov@f5.com } 7831828Sa.suvorov@f5.com 7841828Sa.suvorov@f5.com return NXT_ERROR; 7851828Sa.suvorov@f5.com } 7861828Sa.suvorov@f5.com 7871828Sa.suvorov@f5.com 7881828Sa.suvorov@f5.com static nxt_int_t 7891828Sa.suvorov@f5.com nxt_openssl_servername(SSL *s, int *ad, void *arg) 7901828Sa.suvorov@f5.com { 7911828Sa.suvorov@f5.com nxt_str_t str; 7921828Sa.suvorov@f5.com nxt_uint_t i; 7931828Sa.suvorov@f5.com nxt_conn_t *c; 7941828Sa.suvorov@f5.com const char *servername; 7951828Sa.suvorov@f5.com nxt_tls_conf_t *conf; 7961828Sa.suvorov@f5.com nxt_openssl_conn_t *tls; 7971828Sa.suvorov@f5.com nxt_tls_bundle_conf_t *bundle; 7981828Sa.suvorov@f5.com 7991828Sa.suvorov@f5.com c = SSL_get_ex_data(s, nxt_openssl_connection_index); 8001828Sa.suvorov@f5.com 8011828Sa.suvorov@f5.com if (nxt_slow_path(c == NULL)) { 8021828Sa.suvorov@f5.com nxt_thread_log_alert("SSL_get_ex_data() failed"); 8031828Sa.suvorov@f5.com return SSL_TLSEXT_ERR_ALERT_FATAL; 8041828Sa.suvorov@f5.com } 8051828Sa.suvorov@f5.com 8061828Sa.suvorov@f5.com servername = SSL_get_servername(s, TLSEXT_NAMETYPE_host_name); 8071828Sa.suvorov@f5.com if (nxt_slow_path(servername == NULL)) { 8081828Sa.suvorov@f5.com nxt_log(c->socket.task, NXT_LOG_ALERT, "SSL_get_servername() returned " 8091828Sa.suvorov@f5.com "NULL in server name callback"); 8101828Sa.suvorov@f5.com return SSL_TLSEXT_ERR_ALERT_FATAL; 8111828Sa.suvorov@f5.com } 8121828Sa.suvorov@f5.com 8131828Sa.suvorov@f5.com str.length = nxt_strlen(servername); 8141828Sa.suvorov@f5.com if (str.length == 0) { 8151828Sa.suvorov@f5.com nxt_debug(c->socket.task, "client sent zero-length server name"); 8161828Sa.suvorov@f5.com goto done; 8171828Sa.suvorov@f5.com } 8181828Sa.suvorov@f5.com 8191828Sa.suvorov@f5.com if (servername[0] == '.') { 8201828Sa.suvorov@f5.com nxt_debug(c->socket.task, "ignored the server name \"%s\": " 8211828Sa.suvorov@f5.com "leading \".\"", servername); 8221828Sa.suvorov@f5.com goto done; 8231828Sa.suvorov@f5.com } 8241828Sa.suvorov@f5.com 8251828Sa.suvorov@f5.com nxt_debug(c->socket.task, "tls with servername \"%s\"", servername); 8261828Sa.suvorov@f5.com 8271828Sa.suvorov@f5.com str.start = nxt_mp_nget(c->mem_pool, str.length); 8281828Sa.suvorov@f5.com if (nxt_slow_path(str.start == NULL)) { 8291828Sa.suvorov@f5.com return SSL_TLSEXT_ERR_ALERT_FATAL; 8301828Sa.suvorov@f5.com } 8311828Sa.suvorov@f5.com 8321828Sa.suvorov@f5.com nxt_memcpy_lowcase(str.start, (const u_char *) servername, str.length); 8331828Sa.suvorov@f5.com 8341828Sa.suvorov@f5.com tls = c->u.tls; 8351828Sa.suvorov@f5.com conf = tls->conf; 8361828Sa.suvorov@f5.com 8371828Sa.suvorov@f5.com bundle = nxt_openssl_find_ctx(conf, &str); 8381828Sa.suvorov@f5.com 8391828Sa.suvorov@f5.com if (bundle == NULL) { 8401828Sa.suvorov@f5.com for (i = 1; i < str.length; i++) { 8411828Sa.suvorov@f5.com if (str.start[i] == '.') { 8421828Sa.suvorov@f5.com str.start += i; 8431828Sa.suvorov@f5.com str.length -= i; 8441828Sa.suvorov@f5.com 8451828Sa.suvorov@f5.com bundle = nxt_openssl_find_ctx(conf, &str); 8461828Sa.suvorov@f5.com break; 8471828Sa.suvorov@f5.com } 8481828Sa.suvorov@f5.com } 8491828Sa.suvorov@f5.com } 8501828Sa.suvorov@f5.com 8511828Sa.suvorov@f5.com if (bundle != NULL) { 8521828Sa.suvorov@f5.com nxt_debug(c->socket.task, "new tls context found for \"%V\": \"%V\" " 8531885Sa.suvorov@f5.com "(old: \"%V\")", &str, &bundle->name, 8541885Sa.suvorov@f5.com &conf->bundle->name); 8551828Sa.suvorov@f5.com 8561828Sa.suvorov@f5.com if (bundle != conf->bundle) { 8571828Sa.suvorov@f5.com if (SSL_set_SSL_CTX(s, bundle->ctx) == NULL) { 8581828Sa.suvorov@f5.com nxt_openssl_log_error(c->socket.task, NXT_LOG_ALERT, 8591828Sa.suvorov@f5.com "SSL_set_SSL_CTX() failed"); 8601828Sa.suvorov@f5.com 8611828Sa.suvorov@f5.com return SSL_TLSEXT_ERR_ALERT_FATAL; 8621828Sa.suvorov@f5.com } 8631828Sa.suvorov@f5.com } 8641828Sa.suvorov@f5.com } 8651828Sa.suvorov@f5.com 8661828Sa.suvorov@f5.com done: 8671828Sa.suvorov@f5.com 8681828Sa.suvorov@f5.com return SSL_TLSEXT_ERR_OK; 8691828Sa.suvorov@f5.com } 8701828Sa.suvorov@f5.com 8711828Sa.suvorov@f5.com 8721828Sa.suvorov@f5.com static nxt_tls_bundle_conf_t * 8731828Sa.suvorov@f5.com nxt_openssl_find_ctx(nxt_tls_conf_t *conf, nxt_str_t *sn) 8741828Sa.suvorov@f5.com { 8751828Sa.suvorov@f5.com nxt_int_t ret; 8761828Sa.suvorov@f5.com nxt_lvlhsh_query_t lhq; 8771828Sa.suvorov@f5.com nxt_tls_bundle_hash_item_t *item; 8781828Sa.suvorov@f5.com 8791828Sa.suvorov@f5.com lhq.key_hash = nxt_murmur_hash2(sn->start, sn->length); 8801828Sa.suvorov@f5.com lhq.key = *sn; 8811828Sa.suvorov@f5.com lhq.proto = &nxt_openssl_bundle_hash_proto; 8821828Sa.suvorov@f5.com 8831828Sa.suvorov@f5.com ret = nxt_lvlhsh_find(&conf->bundle_hash, &lhq); 8841828Sa.suvorov@f5.com if (ret != NXT_OK) { 8851828Sa.suvorov@f5.com return NULL; 8861828Sa.suvorov@f5.com } 8871828Sa.suvorov@f5.com 8881828Sa.suvorov@f5.com item = lhq.value; 8891828Sa.suvorov@f5.com 8901828Sa.suvorov@f5.com return item->bundle; 8911828Sa.suvorov@f5.com } 8921828Sa.suvorov@f5.com 8931828Sa.suvorov@f5.com 8940Sigor@sysoev.ru static void 895771Sigor@sysoev.ru nxt_openssl_server_free(nxt_task_t *task, nxt_tls_conf_t *conf) 8960Sigor@sysoev.ru { 8971828Sa.suvorov@f5.com nxt_tls_bundle_conf_t *bundle; 8981828Sa.suvorov@f5.com 8991828Sa.suvorov@f5.com bundle = conf->bundle; 9001828Sa.suvorov@f5.com nxt_assert(bundle != NULL); 9011828Sa.suvorov@f5.com 9021828Sa.suvorov@f5.com do { 9031828Sa.suvorov@f5.com SSL_CTX_free(bundle->ctx); 904