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> 8*1885Sa.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 45771Sigor@sysoev.ru static nxt_int_t nxt_openssl_server_init(nxt_task_t *task, 46*1885Sa.suvorov@f5.com nxt_tls_conf_t *conf, nxt_mp_t *mp, nxt_conf_value_t *conf_cmds, 47*1885Sa.suvorov@f5.com nxt_bool_t last); 481828Sa.suvorov@f5.com static nxt_int_t nxt_openssl_chain_file(nxt_task_t *task, SSL_CTX *ctx, 491828Sa.suvorov@f5.com nxt_tls_conf_t *conf, nxt_mp_t *mp, nxt_bool_t single); 50*1885Sa.suvorov@f5.com #if (NXT_HAVE_OPENSSL_CONF_CMD) 51*1885Sa.suvorov@f5.com static nxt_int_t nxt_ssl_conf_commands(nxt_task_t *task, SSL_CTX *ctx, 52*1885Sa.suvorov@f5.com nxt_conf_value_t *value, nxt_mp_t *mp); 53*1885Sa.suvorov@f5.com #endif 541828Sa.suvorov@f5.com static nxt_uint_t nxt_openssl_cert_get_names(nxt_task_t *task, X509 *cert, 551828Sa.suvorov@f5.com nxt_tls_conf_t *conf, nxt_mp_t *mp); 561828Sa.suvorov@f5.com static nxt_int_t nxt_openssl_bundle_hash_test(nxt_lvlhsh_query_t *lhq, 571828Sa.suvorov@f5.com void *data); 581828Sa.suvorov@f5.com static nxt_int_t nxt_openssl_bundle_hash_insert(nxt_task_t *task, 591828Sa.suvorov@f5.com nxt_lvlhsh_t *lvlhsh, nxt_tls_bundle_hash_item_t *item, nxt_mp_t * mp); 601828Sa.suvorov@f5.com static nxt_int_t nxt_openssl_servername(SSL *s, int *ad, void *arg); 611828Sa.suvorov@f5.com static nxt_tls_bundle_conf_t *nxt_openssl_find_ctx(nxt_tls_conf_t *conf, 621828Sa.suvorov@f5.com nxt_str_t *sn); 63771Sigor@sysoev.ru static void nxt_openssl_server_free(nxt_task_t *task, nxt_tls_conf_t *conf); 64771Sigor@sysoev.ru static void nxt_openssl_conn_init(nxt_task_t *task, nxt_tls_conf_t *conf, 6562Sigor@sysoev.ru nxt_conn_t *c); 661Sigor@sysoev.ru static void nxt_openssl_conn_handshake(nxt_task_t *task, void *obj, void *data); 67771Sigor@sysoev.ru static ssize_t nxt_openssl_conn_io_recvbuf(nxt_conn_t *c, nxt_buf_t *b); 68771Sigor@sysoev.ru static ssize_t nxt_openssl_conn_io_sendbuf(nxt_task_t *task, nxt_sendbuf_t *sb); 69771Sigor@sysoev.ru static ssize_t nxt_openssl_conn_io_send(nxt_task_t *task, nxt_sendbuf_t *sb, 70771Sigor@sysoev.ru void *buf, size_t size); 711Sigor@sysoev.ru static void nxt_openssl_conn_io_shutdown(nxt_task_t *task, void *obj, 720Sigor@sysoev.ru void *data); 73771Sigor@sysoev.ru static nxt_int_t nxt_openssl_conn_test_error(nxt_task_t *task, nxt_conn_t *c, 74771Sigor@sysoev.ru int ret, nxt_err_t sys_err, nxt_openssl_io_t io); 751884Sa.suvorov@f5.com static void nxt_openssl_conn_io_shutdown_timeout(nxt_task_t *task, void *obj, 761884Sa.suvorov@f5.com void *data); 77771Sigor@sysoev.ru static void nxt_cdecl nxt_openssl_conn_error(nxt_task_t *task, 78771Sigor@sysoev.ru nxt_err_t err, const char *fmt, ...); 79771Sigor@sysoev.ru static nxt_uint_t nxt_openssl_log_error_level(nxt_err_t err); 800Sigor@sysoev.ru 810Sigor@sysoev.ru 82771Sigor@sysoev.ru const nxt_tls_lib_t nxt_openssl_lib = { 83771Sigor@sysoev.ru .library_init = nxt_openssl_library_init, 84771Sigor@sysoev.ru .library_free = nxt_openssl_library_free, 85771Sigor@sysoev.ru 86771Sigor@sysoev.ru .server_init = nxt_openssl_server_init, 87771Sigor@sysoev.ru .server_free = nxt_openssl_server_free, 880Sigor@sysoev.ru }; 890Sigor@sysoev.ru 900Sigor@sysoev.ru 9162Sigor@sysoev.ru static nxt_conn_io_t nxt_openssl_conn_io = { 92771Sigor@sysoev.ru .read = nxt_conn_io_read, 93771Sigor@sysoev.ru .recvbuf = nxt_openssl_conn_io_recvbuf, 940Sigor@sysoev.ru 95771Sigor@sysoev.ru .write = nxt_conn_io_write, 96771Sigor@sysoev.ru .sendbuf = nxt_openssl_conn_io_sendbuf, 970Sigor@sysoev.ru 98771Sigor@sysoev.ru .shutdown = nxt_openssl_conn_io_shutdown, 990Sigor@sysoev.ru }; 1000Sigor@sysoev.ru 1010Sigor@sysoev.ru 1020Sigor@sysoev.ru static long nxt_openssl_version; 1030Sigor@sysoev.ru static int nxt_openssl_connection_index; 1040Sigor@sysoev.ru 1050Sigor@sysoev.ru 1060Sigor@sysoev.ru static nxt_int_t 107771Sigor@sysoev.ru nxt_openssl_library_init(nxt_task_t *task) 1080Sigor@sysoev.ru { 1090Sigor@sysoev.ru int index; 1100Sigor@sysoev.ru 1110Sigor@sysoev.ru if (nxt_fast_path(nxt_openssl_version != 0)) { 1120Sigor@sysoev.ru return NXT_OK; 1130Sigor@sysoev.ru } 1140Sigor@sysoev.ru 115771Sigor@sysoev.ru #if OPENSSL_VERSION_NUMBER >= 0x10100003L 116771Sigor@sysoev.ru 117771Sigor@sysoev.ru OPENSSL_init_ssl(OPENSSL_INIT_LOAD_CONFIG, NULL); 1180Sigor@sysoev.ru 119771Sigor@sysoev.ru #else 120771Sigor@sysoev.ru { 121771Sigor@sysoev.ru nxt_int_t ret; 122771Sigor@sysoev.ru 123771Sigor@sysoev.ru SSL_load_error_strings(); 124771Sigor@sysoev.ru 125771Sigor@sysoev.ru OPENSSL_config(NULL); 1260Sigor@sysoev.ru 127771Sigor@sysoev.ru /* 128771Sigor@sysoev.ru * SSL_library_init(3): 129771Sigor@sysoev.ru * 130771Sigor@sysoev.ru * SSL_library_init() always returns "1", 131771Sigor@sysoev.ru * so it is safe to discard the return value. 132771Sigor@sysoev.ru */ 133771Sigor@sysoev.ru (void) SSL_library_init(); 134771Sigor@sysoev.ru 135771Sigor@sysoev.ru ret = nxt_openssl_locks_init(); 136771Sigor@sysoev.ru if (nxt_slow_path(ret != NXT_OK)) { 137771Sigor@sysoev.ru return ret; 138771Sigor@sysoev.ru } 139771Sigor@sysoev.ru } 140771Sigor@sysoev.ru 141771Sigor@sysoev.ru #endif 1420Sigor@sysoev.ru 1430Sigor@sysoev.ru nxt_openssl_version = SSLeay(); 1440Sigor@sysoev.ru 145771Sigor@sysoev.ru nxt_log(task, NXT_LOG_INFO, "%s, %xl", 146771Sigor@sysoev.ru SSLeay_version(SSLEAY_VERSION), nxt_openssl_version); 1470Sigor@sysoev.ru 1480Sigor@sysoev.ru #ifndef SSL_OP_NO_COMPRESSION 1490Sigor@sysoev.ru { 1500Sigor@sysoev.ru /* 1510Sigor@sysoev.ru * Disable gzip compression in OpenSSL prior to 1.0.0 1520Sigor@sysoev.ru * version, this saves about 522K per connection. 1530Sigor@sysoev.ru */ 1540Sigor@sysoev.ru int n; 1550Sigor@sysoev.ru STACK_OF(SSL_COMP) *ssl_comp_methods; 1560Sigor@sysoev.ru 1570Sigor@sysoev.ru ssl_comp_methods = SSL_COMP_get_compression_methods(); 1580Sigor@sysoev.ru 1590Sigor@sysoev.ru for (n = sk_SSL_COMP_num(ssl_comp_methods); n != 0; n--) { 1600Sigor@sysoev.ru (void) sk_SSL_COMP_pop(ssl_comp_methods); 1610Sigor@sysoev.ru } 1620Sigor@sysoev.ru } 1630Sigor@sysoev.ru #endif 1640Sigor@sysoev.ru 1650Sigor@sysoev.ru index = SSL_get_ex_new_index(0, NULL, NULL, NULL, NULL); 1660Sigor@sysoev.ru 1670Sigor@sysoev.ru if (index == -1) { 168771Sigor@sysoev.ru nxt_openssl_log_error(task, NXT_LOG_ALERT, 1690Sigor@sysoev.ru "SSL_get_ex_new_index() failed"); 1700Sigor@sysoev.ru return NXT_ERROR; 1710Sigor@sysoev.ru } 1720Sigor@sysoev.ru 1730Sigor@sysoev.ru nxt_openssl_connection_index = index; 1740Sigor@sysoev.ru 1750Sigor@sysoev.ru return NXT_OK; 1760Sigor@sysoev.ru } 1770Sigor@sysoev.ru 1780Sigor@sysoev.ru 179771Sigor@sysoev.ru #if OPENSSL_VERSION_NUMBER >= 0x10100003L 180771Sigor@sysoev.ru 181771Sigor@sysoev.ru static void 182771Sigor@sysoev.ru nxt_openssl_library_free(nxt_task_t *task) 183771Sigor@sysoev.ru { 184771Sigor@sysoev.ru } 185771Sigor@sysoev.ru 186771Sigor@sysoev.ru #else 187771Sigor@sysoev.ru 188771Sigor@sysoev.ru static nxt_thread_mutex_t *nxt_openssl_locks; 189771Sigor@sysoev.ru 1900Sigor@sysoev.ru static nxt_int_t 191771Sigor@sysoev.ru nxt_openssl_locks_init(void) 192771Sigor@sysoev.ru { 193771Sigor@sysoev.ru int i, n; 194771Sigor@sysoev.ru nxt_int_t ret; 195771Sigor@sysoev.ru 196771Sigor@sysoev.ru n = CRYPTO_num_locks(); 197771Sigor@sysoev.ru 198771Sigor@sysoev.ru nxt_openssl_locks = OPENSSL_malloc(n * sizeof(nxt_thread_mutex_t)); 199771Sigor@sysoev.ru if (nxt_slow_path(nxt_openssl_locks == NULL)) { 200771Sigor@sysoev.ru return NXT_ERROR; 201771Sigor@sysoev.ru } 202771Sigor@sysoev.ru 203771Sigor@sysoev.ru for (i = 0; i < n; i++) { 204771Sigor@sysoev.ru ret = nxt_thread_mutex_create(&nxt_openssl_locks[i]); 205771Sigor@sysoev.ru if (nxt_slow_path(ret != NXT_OK)) { 206771Sigor@sysoev.ru return ret; 207771Sigor@sysoev.ru } 208771Sigor@sysoev.ru } 209771Sigor@sysoev.ru 210771Sigor@sysoev.ru CRYPTO_set_locking_callback(nxt_openssl_lock); 211771Sigor@sysoev.ru 212771Sigor@sysoev.ru CRYPTO_set_id_callback(nxt_openssl_thread_id); 213771Sigor@sysoev.ru 214771Sigor@sysoev.ru return NXT_OK; 215771Sigor@sysoev.ru } 216771Sigor@sysoev.ru 217771Sigor@sysoev.ru 218771Sigor@sysoev.ru static void 219771Sigor@sysoev.ru nxt_openssl_lock(int mode, int type, const char *file, int line) 220771Sigor@sysoev.ru { 221771Sigor@sysoev.ru nxt_thread_mutex_t *lock; 222771Sigor@sysoev.ru 223771Sigor@sysoev.ru lock = &nxt_openssl_locks[type]; 224771Sigor@sysoev.ru 225771Sigor@sysoev.ru if ((mode & CRYPTO_LOCK) != 0) { 226771Sigor@sysoev.ru (void) nxt_thread_mutex_lock(lock); 227771Sigor@sysoev.ru 228771Sigor@sysoev.ru } else { 229771Sigor@sysoev.ru (void) nxt_thread_mutex_unlock(lock); 230771Sigor@sysoev.ru } 231771Sigor@sysoev.ru } 232771Sigor@sysoev.ru 233771Sigor@sysoev.ru 234771Sigor@sysoev.ru static u_long 235771Sigor@sysoev.ru nxt_openssl_thread_id(void) 236771Sigor@sysoev.ru { 237771Sigor@sysoev.ru return (u_long) nxt_thread_handle(); 238771Sigor@sysoev.ru } 239771Sigor@sysoev.ru 240771Sigor@sysoev.ru 241771Sigor@sysoev.ru static void 242771Sigor@sysoev.ru nxt_openssl_library_free(nxt_task_t *task) 243771Sigor@sysoev.ru { 244771Sigor@sysoev.ru nxt_openssl_locks_free(); 245771Sigor@sysoev.ru } 246771Sigor@sysoev.ru 247771Sigor@sysoev.ru 248771Sigor@sysoev.ru static void 249771Sigor@sysoev.ru nxt_openssl_locks_free(void) 250771Sigor@sysoev.ru { 251771Sigor@sysoev.ru int i, n; 252771Sigor@sysoev.ru 253771Sigor@sysoev.ru n = CRYPTO_num_locks(); 254771Sigor@sysoev.ru 255771Sigor@sysoev.ru CRYPTO_set_locking_callback(NULL); 256771Sigor@sysoev.ru 257771Sigor@sysoev.ru for (i = 0; i < n; i++) { 258771Sigor@sysoev.ru nxt_thread_mutex_destroy(&nxt_openssl_locks[i]); 259771Sigor@sysoev.ru } 260771Sigor@sysoev.ru 261771Sigor@sysoev.ru OPENSSL_free(nxt_openssl_locks); 262771Sigor@sysoev.ru } 263771Sigor@sysoev.ru 264771Sigor@sysoev.ru #endif 265771Sigor@sysoev.ru 266771Sigor@sysoev.ru 267771Sigor@sysoev.ru static nxt_int_t 2681828Sa.suvorov@f5.com nxt_openssl_server_init(nxt_task_t *task, nxt_tls_conf_t *conf, 269*1885Sa.suvorov@f5.com nxt_mp_t *mp, nxt_conf_value_t *conf_cmds, nxt_bool_t last) 2700Sigor@sysoev.ru { 2711828Sa.suvorov@f5.com SSL_CTX *ctx; 2721828Sa.suvorov@f5.com const char *ciphers, *ca_certificate; 2731828Sa.suvorov@f5.com STACK_OF(X509_NAME) *list; 2741828Sa.suvorov@f5.com nxt_tls_bundle_conf_t *bundle; 2750Sigor@sysoev.ru 2760Sigor@sysoev.ru ctx = SSL_CTX_new(SSLv23_server_method()); 2770Sigor@sysoev.ru if (ctx == NULL) { 278771Sigor@sysoev.ru nxt_openssl_log_error(task, NXT_LOG_ALERT, "SSL_CTX_new() failed"); 2790Sigor@sysoev.ru return NXT_ERROR; 2800Sigor@sysoev.ru } 2810Sigor@sysoev.ru 2821828Sa.suvorov@f5.com bundle = conf->bundle; 2831828Sa.suvorov@f5.com nxt_assert(bundle != NULL); 2841828Sa.suvorov@f5.com 2851828Sa.suvorov@f5.com bundle->ctx = ctx; 2860Sigor@sysoev.ru 287771Sigor@sysoev.ru #ifdef SSL_OP_NO_RENEGOTIATION 288771Sigor@sysoev.ru /* Renegration is not currently supported. */ 289771Sigor@sysoev.ru SSL_CTX_set_options(ctx, SSL_OP_NO_RENEGOTIATION); 290771Sigor@sysoev.ru #endif 291771Sigor@sysoev.ru 2920Sigor@sysoev.ru #ifdef SSL_OP_NO_COMPRESSION 2930Sigor@sysoev.ru /* 2940Sigor@sysoev.ru * Disable gzip compression in OpenSSL 1.0.0, 2950Sigor@sysoev.ru * this saves about 522K per connection. 2960Sigor@sysoev.ru */ 2970Sigor@sysoev.ru SSL_CTX_set_options(ctx, SSL_OP_NO_COMPRESSION); 2980Sigor@sysoev.ru #endif 2990Sigor@sysoev.ru 3000Sigor@sysoev.ru #ifdef SSL_MODE_RELEASE_BUFFERS 3010Sigor@sysoev.ru 3020Sigor@sysoev.ru if (nxt_openssl_version >= 10001078) { 3030Sigor@sysoev.ru /* 3040Sigor@sysoev.ru * Allow to release read and write buffers in OpenSSL 1.0.0, 3050Sigor@sysoev.ru * this saves about 34K per idle connection. It is not safe 3060Sigor@sysoev.ru * before OpenSSL 1.0.1h (CVE-2010-5298). 3070Sigor@sysoev.ru */ 3080Sigor@sysoev.ru SSL_CTX_set_mode(ctx, SSL_MODE_RELEASE_BUFFERS); 3090Sigor@sysoev.ru } 3100Sigor@sysoev.ru 3110Sigor@sysoev.ru #endif 3120Sigor@sysoev.ru 3131828Sa.suvorov@f5.com if (nxt_openssl_chain_file(task, ctx, conf, mp, 3141828Sa.suvorov@f5.com last && bundle->next == NULL) 3151828Sa.suvorov@f5.com != NXT_OK) 3161828Sa.suvorov@f5.com { 3170Sigor@sysoev.ru goto fail; 3180Sigor@sysoev.ru } 319774Svbart@nginx.com /* 3200Sigor@sysoev.ru key = conf->certificate_key; 3210Sigor@sysoev.ru 3220Sigor@sysoev.ru if (SSL_CTX_use_PrivateKey_file(ctx, key, SSL_FILETYPE_PEM) == 0) { 323771Sigor@sysoev.ru nxt_openssl_log_error(task, NXT_LOG_ALERT, 3240Sigor@sysoev.ru "SSL_CTX_use_PrivateKey_file(\"%s\") failed", 3250Sigor@sysoev.ru key); 3260Sigor@sysoev.ru goto fail; 3270Sigor@sysoev.ru } 328774Svbart@nginx.com */ 329*1885Sa.suvorov@f5.com 3300Sigor@sysoev.ru ciphers = (conf->ciphers != NULL) ? conf->ciphers : "HIGH:!aNULL:!MD5"; 3310Sigor@sysoev.ru 3320Sigor@sysoev.ru if (SSL_CTX_set_cipher_list(ctx, ciphers) == 0) { 333771Sigor@sysoev.ru nxt_openssl_log_error(task, NXT_LOG_ALERT, 3340Sigor@sysoev.ru "SSL_CTX_set_cipher_list(\"%s\") failed", 3350Sigor@sysoev.ru ciphers); 3360Sigor@sysoev.ru goto fail; 3370Sigor@sysoev.ru } 3380Sigor@sysoev.ru 339*1885Sa.suvorov@f5.com #if (NXT_HAVE_OPENSSL_CONF_CMD) 340*1885Sa.suvorov@f5.com if (conf_cmds != NULL 341*1885Sa.suvorov@f5.com && nxt_ssl_conf_commands(task, ctx, conf_cmds, mp) != NXT_OK) 342*1885Sa.suvorov@f5.com { 343*1885Sa.suvorov@f5.com goto fail; 344*1885Sa.suvorov@f5.com } 345*1885Sa.suvorov@f5.com #endif 346*1885Sa.suvorov@f5.com 3470Sigor@sysoev.ru SSL_CTX_set_options(ctx, SSL_OP_CIPHER_SERVER_PREFERENCE); 3480Sigor@sysoev.ru 3490Sigor@sysoev.ru if (conf->ca_certificate != NULL) { 3500Sigor@sysoev.ru 3510Sigor@sysoev.ru /* TODO: verify callback */ 3520Sigor@sysoev.ru SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER, NULL); 3530Sigor@sysoev.ru 3540Sigor@sysoev.ru /* TODO: verify depth */ 3550Sigor@sysoev.ru SSL_CTX_set_verify_depth(ctx, 1); 3560Sigor@sysoev.ru 3570Sigor@sysoev.ru ca_certificate = conf->ca_certificate; 3580Sigor@sysoev.ru 3590Sigor@sysoev.ru if (SSL_CTX_load_verify_locations(ctx, ca_certificate, NULL) == 0) { 360771Sigor@sysoev.ru nxt_openssl_log_error(task, NXT_LOG_ALERT, 3610Sigor@sysoev.ru "SSL_CTX_load_verify_locations(\"%s\") failed", 3620Sigor@sysoev.ru ca_certificate); 3630Sigor@sysoev.ru goto fail; 3640Sigor@sysoev.ru } 3650Sigor@sysoev.ru 3660Sigor@sysoev.ru list = SSL_load_client_CA_file(ca_certificate); 3670Sigor@sysoev.ru 3680Sigor@sysoev.ru if (list == NULL) { 369771Sigor@sysoev.ru nxt_openssl_log_error(task, NXT_LOG_ALERT, 3700Sigor@sysoev.ru "SSL_load_client_CA_file(\"%s\") failed", 3710Sigor@sysoev.ru ca_certificate); 3720Sigor@sysoev.ru goto fail; 3730Sigor@sysoev.ru } 3740Sigor@sysoev.ru 3750Sigor@sysoev.ru /* 3760Sigor@sysoev.ru * SSL_load_client_CA_file() in OpenSSL prior to 0.9.7h and 3770Sigor@sysoev.ru * 0.9.8 versions always leaves an error in the error queue. 3780Sigor@sysoev.ru */ 3790Sigor@sysoev.ru ERR_clear_error(); 3800Sigor@sysoev.ru 3810Sigor@sysoev.ru SSL_CTX_set_client_CA_list(ctx, list); 3820Sigor@sysoev.ru } 3830Sigor@sysoev.ru 3841828Sa.suvorov@f5.com if (last) { 3851828Sa.suvorov@f5.com conf->conn_init = nxt_openssl_conn_init; 3861828Sa.suvorov@f5.com 3871828Sa.suvorov@f5.com if (bundle->next != NULL) { 3881828Sa.suvorov@f5.com SSL_CTX_set_tlsext_servername_callback(ctx, nxt_openssl_servername); 3891828Sa.suvorov@f5.com } 3901828Sa.suvorov@f5.com } 3911828Sa.suvorov@f5.com 3920Sigor@sysoev.ru return NXT_OK; 3930Sigor@sysoev.ru 3940Sigor@sysoev.ru fail: 3950Sigor@sysoev.ru 3960Sigor@sysoev.ru SSL_CTX_free(ctx); 3970Sigor@sysoev.ru 3981818Smax.romanov@nginx.com #if (OPENSSL_VERSION_NUMBER >= 0x1010100fL \ 3991818Smax.romanov@nginx.com && OPENSSL_VERSION_NUMBER < 0x1010101fL) 4001818Smax.romanov@nginx.com RAND_keep_random_devices_open(0); 4011818Smax.romanov@nginx.com #endif 4021818Smax.romanov@nginx.com 4030Sigor@sysoev.ru return NXT_ERROR; 4040Sigor@sysoev.ru } 4050Sigor@sysoev.ru 4060Sigor@sysoev.ru 407833Svbart@nginx.com static nxt_int_t 4081828Sa.suvorov@f5.com nxt_openssl_chain_file(nxt_task_t *task, SSL_CTX *ctx, nxt_tls_conf_t *conf, 4091828Sa.suvorov@f5.com nxt_mp_t *mp, nxt_bool_t single) 410774Svbart@nginx.com { 4111828Sa.suvorov@f5.com BIO *bio; 4121828Sa.suvorov@f5.com X509 *cert, *ca; 4131828Sa.suvorov@f5.com long reason; 4141828Sa.suvorov@f5.com EVP_PKEY *key; 4151828Sa.suvorov@f5.com nxt_int_t ret; 4161828Sa.suvorov@f5.com nxt_tls_bundle_conf_t *bundle; 4171828Sa.suvorov@f5.com 4181828Sa.suvorov@f5.com ret = NXT_ERROR; 4191828Sa.suvorov@f5.com cert = NULL; 420774Svbart@nginx.com 421774Svbart@nginx.com bio = BIO_new(BIO_s_fd()); 422774Svbart@nginx.com if (bio == NULL) { 4231828Sa.suvorov@f5.com goto end; 424774Svbart@nginx.com } 425774Svbart@nginx.com 4261828Sa.suvorov@f5.com bundle = conf->bundle; 427774Svbart@nginx.com 4281828Sa.suvorov@f5.com BIO_set_fd(bio, bundle->chain_file, BIO_CLOSE); 429774Svbart@nginx.com 430774Svbart@nginx.com cert = PEM_read_bio_X509_AUX(bio, NULL, NULL, NULL); 431774Svbart@nginx.com if (cert == NULL) { 432774Svbart@nginx.com goto end; 433774Svbart@nginx.com } 434774Svbart@nginx.com 435774Svbart@nginx.com if (SSL_CTX_use_certificate(ctx, cert) != 1) { 436774Svbart@nginx.com goto end; 437774Svbart@nginx.com } 438774Svbart@nginx.com 4391828Sa.suvorov@f5.com if (!single && nxt_openssl_cert_get_names(task, cert, conf, mp) != NXT_OK) { 4401828Sa.suvorov@f5.com goto clean; 4411828Sa.suvorov@f5.com } 4421828Sa.suvorov@f5.com 443774Svbart@nginx.com for ( ;; ) { 444774Svbart@nginx.com ca = PEM_read_bio_X509(bio, NULL, NULL, NULL); 445774Svbart@nginx.com 446774Svbart@nginx.com if (ca == NULL) { 447774Svbart@nginx.com reason = ERR_GET_REASON(ERR_peek_last_error()); 448774Svbart@nginx.com if (reason != PEM_R_NO_START_LINE) { 449774Svbart@nginx.com goto end; 450774Svbart@nginx.com } 451774Svbart@nginx.com 452774Svbart@nginx.com ERR_clear_error(); 453774Svbart@nginx.com break; 454774Svbart@nginx.com } 455774Svbart@nginx.com 456774Svbart@nginx.com /* 457774Svbart@nginx.com * Note that ca isn't freed if it was successfully added to the chain, 458774Svbart@nginx.com * while the main certificate needs a X509_free() call, since 459774Svbart@nginx.com * its reference count is increased by SSL_CTX_use_certificate(). 460774Svbart@nginx.com */ 461808Spluknet@nginx.com #ifdef SSL_CTX_add0_chain_cert 462774Svbart@nginx.com if (SSL_CTX_add0_chain_cert(ctx, ca) != 1) { 463774Svbart@nginx.com #else 464774Svbart@nginx.com if (SSL_CTX_add_extra_chain_cert(ctx, ca) != 1) { 465774Svbart@nginx.com #endif 466774Svbart@nginx.com X509_free(ca); 467774Svbart@nginx.com goto end; 468774Svbart@nginx.com } 469774Svbart@nginx.com } 470774Svbart@nginx.com 471774Svbart@nginx.com if (BIO_reset(bio) != 0) { 472774Svbart@nginx.com goto end; 473774Svbart@nginx.com } 474774Svbart@nginx.com 475774Svbart@nginx.com key = PEM_read_bio_PrivateKey(bio, NULL, NULL, NULL); 476774Svbart@nginx.com if (key == NULL) { 477774Svbart@nginx.com goto end; 478774Svbart@nginx.com } 479774Svbart@nginx.com 480774Svbart@nginx.com if (SSL_CTX_use_PrivateKey(ctx, key) == 1) { 481774Svbart@nginx.com ret = NXT_OK; 482774Svbart@nginx.com } 483774Svbart@nginx.com 484774Svbart@nginx.com EVP_PKEY_free(key); 485774Svbart@nginx.com 486774Svbart@nginx.com end: 487774Svbart@nginx.com 4881828Sa.suvorov@f5.com if (ret != NXT_OK) { 4891828Sa.suvorov@f5.com nxt_openssl_log_error(task, NXT_LOG_ALERT, 4901828Sa.suvorov@f5.com "nxt_openssl_chain_file() failed"); 4911828Sa.suvorov@f5.com } 4921828Sa.suvorov@f5.com 4931828Sa.suvorov@f5.com clean: 4941828Sa.suvorov@f5.com 4951828Sa.suvorov@f5.com BIO_free(bio); 496774Svbart@nginx.com X509_free(cert); 497774Svbart@nginx.com 498774Svbart@nginx.com return ret; 499774Svbart@nginx.com } 500774Svbart@nginx.com 501774Svbart@nginx.com 502*1885Sa.suvorov@f5.com #if (NXT_HAVE_OPENSSL_CONF_CMD) 503*1885Sa.suvorov@f5.com 504*1885Sa.suvorov@f5.com static nxt_int_t 505*1885Sa.suvorov@f5.com nxt_ssl_conf_commands(nxt_task_t *task, SSL_CTX *ctx, nxt_conf_value_t *conf, 506*1885Sa.suvorov@f5.com nxt_mp_t *mp) 507*1885Sa.suvorov@f5.com { 508*1885Sa.suvorov@f5.com int ret; 509*1885Sa.suvorov@f5.com char *zcmd, *zvalue; 510*1885Sa.suvorov@f5.com uint32_t index; 511*1885Sa.suvorov@f5.com nxt_str_t cmd, value; 512*1885Sa.suvorov@f5.com SSL_CONF_CTX *cctx; 513*1885Sa.suvorov@f5.com nxt_conf_value_t *member; 514*1885Sa.suvorov@f5.com 515*1885Sa.suvorov@f5.com cctx = SSL_CONF_CTX_new(); 516*1885Sa.suvorov@f5.com if (nxt_slow_path(cctx == NULL)) { 517*1885Sa.suvorov@f5.com nxt_openssl_log_error(task, NXT_LOG_ALERT, 518*1885Sa.suvorov@f5.com "SSL_CONF_CTX_new() failed"); 519*1885Sa.suvorov@f5.com return NXT_ERROR; 520*1885Sa.suvorov@f5.com } 521*1885Sa.suvorov@f5.com 522*1885Sa.suvorov@f5.com SSL_CONF_CTX_set_flags(cctx, SSL_CONF_FLAG_FILE 523*1885Sa.suvorov@f5.com | SSL_CONF_FLAG_SERVER 524*1885Sa.suvorov@f5.com | SSL_CONF_FLAG_CERTIFICATE 525*1885Sa.suvorov@f5.com | SSL_CONF_FLAG_SHOW_ERRORS); 526*1885Sa.suvorov@f5.com 527*1885Sa.suvorov@f5.com SSL_CONF_CTX_set_ssl_ctx(cctx, ctx); 528*1885Sa.suvorov@f5.com 529*1885Sa.suvorov@f5.com index = 0; 530*1885Sa.suvorov@f5.com 531*1885Sa.suvorov@f5.com for ( ;; ) { 532*1885Sa.suvorov@f5.com member = nxt_conf_next_object_member(conf, &cmd, &index); 533*1885Sa.suvorov@f5.com if (nxt_slow_path(member == NULL)) { 534*1885Sa.suvorov@f5.com break; 535*1885Sa.suvorov@f5.com } 536*1885Sa.suvorov@f5.com 537*1885Sa.suvorov@f5.com nxt_conf_get_string(member, &value); 538*1885Sa.suvorov@f5.com 539*1885Sa.suvorov@f5.com zcmd = nxt_str_cstrz(mp, &cmd); 540*1885Sa.suvorov@f5.com zvalue = nxt_str_cstrz(mp, &value); 541*1885Sa.suvorov@f5.com 542*1885Sa.suvorov@f5.com if (nxt_slow_path(zcmd == NULL || zvalue == NULL)) { 543*1885Sa.suvorov@f5.com goto fail; 544*1885Sa.suvorov@f5.com } 545*1885Sa.suvorov@f5.com 546*1885Sa.suvorov@f5.com ret = SSL_CONF_cmd(cctx, zcmd, zvalue); 547*1885Sa.suvorov@f5.com if (ret == -2) { 548*1885Sa.suvorov@f5.com nxt_openssl_log_error(task, NXT_LOG_ERR, 549*1885Sa.suvorov@f5.com "unknown command \"%s\" in " 550*1885Sa.suvorov@f5.com "\"conf_commands\" option", zcmd); 551*1885Sa.suvorov@f5.com goto fail; 552*1885Sa.suvorov@f5.com } 553*1885Sa.suvorov@f5.com 554*1885Sa.suvorov@f5.com if (ret <= 0) { 555*1885Sa.suvorov@f5.com nxt_openssl_log_error(task, NXT_LOG_ERR, 556*1885Sa.suvorov@f5.com "invalid value \"%s\" for command \"%s\" " 557*1885Sa.suvorov@f5.com "in \"conf_commands\" option", 558*1885Sa.suvorov@f5.com zvalue, zcmd); 559*1885Sa.suvorov@f5.com goto fail; 560*1885Sa.suvorov@f5.com } 561*1885Sa.suvorov@f5.com 562*1885Sa.suvorov@f5.com nxt_debug(task, "SSL_CONF_cmd(\"%s\", \"%s\")", zcmd, zvalue); 563*1885Sa.suvorov@f5.com } 564*1885Sa.suvorov@f5.com 565*1885Sa.suvorov@f5.com if (SSL_CONF_CTX_finish(cctx) != 1) { 566*1885Sa.suvorov@f5.com nxt_openssl_log_error(task, NXT_LOG_ALERT, 567*1885Sa.suvorov@f5.com "SSL_CONF_finish() failed"); 568*1885Sa.suvorov@f5.com goto fail; 569*1885Sa.suvorov@f5.com } 570*1885Sa.suvorov@f5.com 571*1885Sa.suvorov@f5.com SSL_CONF_CTX_free(cctx); 572*1885Sa.suvorov@f5.com 573*1885Sa.suvorov@f5.com return NXT_OK; 574*1885Sa.suvorov@f5.com 575*1885Sa.suvorov@f5.com fail: 576*1885Sa.suvorov@f5.com 577*1885Sa.suvorov@f5.com SSL_CONF_CTX_free(cctx); 578*1885Sa.suvorov@f5.com 579*1885Sa.suvorov@f5.com return NXT_ERROR; 580*1885Sa.suvorov@f5.com } 581*1885Sa.suvorov@f5.com 582*1885Sa.suvorov@f5.com #endif 583*1885Sa.suvorov@f5.com 584*1885Sa.suvorov@f5.com 5851828Sa.suvorov@f5.com static nxt_uint_t 5861828Sa.suvorov@f5.com nxt_openssl_cert_get_names(nxt_task_t *task, X509 *cert, nxt_tls_conf_t *conf, 5871828Sa.suvorov@f5.com nxt_mp_t *mp) 5881828Sa.suvorov@f5.com { 5891828Sa.suvorov@f5.com int len; 5901828Sa.suvorov@f5.com nxt_str_t domain, str; 5911828Sa.suvorov@f5.com X509_NAME *x509_name; 5921828Sa.suvorov@f5.com nxt_uint_t i, n; 5931828Sa.suvorov@f5.com GENERAL_NAME *name; 5941828Sa.suvorov@f5.com nxt_tls_bundle_conf_t *bundle; 5951828Sa.suvorov@f5.com STACK_OF(GENERAL_NAME) *alt_names; 5961828Sa.suvorov@f5.com nxt_tls_bundle_hash_item_t *item; 5971828Sa.suvorov@f5.com 5981828Sa.suvorov@f5.com bundle = conf->bundle; 5991828Sa.suvorov@f5.com 6001828Sa.suvorov@f5.com alt_names = X509_get_ext_d2i(cert, NID_subject_alt_name, NULL, NULL); 6011828Sa.suvorov@f5.com 6021828Sa.suvorov@f5.com if (alt_names != NULL) { 6031828Sa.suvorov@f5.com n = sk_GENERAL_NAME_num(alt_names); 6041828Sa.suvorov@f5.com 6051828Sa.suvorov@f5.com for (i = 0; i != n; i++) { 6061828Sa.suvorov@f5.com name = sk_GENERAL_NAME_value(alt_names, i); 6071828Sa.suvorov@f5.com 6081828Sa.suvorov@f5.com if (name->type != GEN_DNS) { 6091828Sa.suvorov@f5.com continue; 6101828Sa.suvorov@f5.com } 6111828Sa.suvorov@f5.com 6121828Sa.suvorov@f5.com str.length = ASN1_STRING_length(name->d.dNSName); 6131828Sa.suvorov@f5.com #if OPENSSL_VERSION_NUMBER > 0x10100000L 6141828Sa.suvorov@f5.com str.start = (u_char *) ASN1_STRING_get0_data(name->d.dNSName); 6151828Sa.suvorov@f5.com #else 6161828Sa.suvorov@f5.com str.start = ASN1_STRING_data(name->d.dNSName); 6171828Sa.suvorov@f5.com #endif 6181828Sa.suvorov@f5.com 6191828Sa.suvorov@f5.com domain.start = nxt_mp_nget(mp, str.length); 6201828Sa.suvorov@f5.com if (nxt_slow_path(domain.start == NULL)) { 6211828Sa.suvorov@f5.com goto fail; 6221828Sa.suvorov@f5.com } 6231828Sa.suvorov@f5.com 6241828Sa.suvorov@f5.com domain.length = str.length; 6251828Sa.suvorov@f5.com nxt_memcpy_lowcase(domain.start, str.start, str.length); 6261828Sa.suvorov@f5.com 6271828Sa.suvorov@f5.com item = nxt_mp_get(mp, sizeof(nxt_tls_bundle_hash_item_t)); 6281828Sa.suvorov@f5.com if (nxt_slow_path(item == NULL)) { 6291828Sa.suvorov@f5.com goto fail; 6301828Sa.suvorov@f5.com } 6311828Sa.suvorov@f5.com 6321828Sa.suvorov@f5.com item->name = domain; 6331828Sa.suvorov@f5.com item->bundle = bundle; 6341828Sa.suvorov@f5.com 6351828Sa.suvorov@f5.com if (nxt_openssl_bundle_hash_insert(task, &conf->bundle_hash, 6361828Sa.suvorov@f5.com item, mp) 6371828Sa.suvorov@f5.com == NXT_ERROR) 6381828Sa.suvorov@f5.com { 6391828Sa.suvorov@f5.com goto fail; 6401828Sa.suvorov@f5.com } 6411828Sa.suvorov@f5.com } 6421828Sa.suvorov@f5.com 6431828Sa.suvorov@f5.com sk_GENERAL_NAME_pop_free(alt_names, GENERAL_NAME_free); 6441828Sa.suvorov@f5.com 6451828Sa.suvorov@f5.com } else { 6461828Sa.suvorov@f5.com x509_name = X509_get_subject_name(cert); 6471828Sa.suvorov@f5.com len = X509_NAME_get_text_by_NID(x509_name, NID_commonName, 6481828Sa.suvorov@f5.com NULL, 0); 6491828Sa.suvorov@f5.com if (len <= 0) { 6501828Sa.suvorov@f5.com nxt_log(task, NXT_LOG_WARN, "certificate \"%V\" has neither " 651*1885Sa.suvorov@f5.com "Subject Alternative Name nor Common Name", &bundle->name); 6521828Sa.suvorov@f5.com return NXT_OK; 6531828Sa.suvorov@f5.com } 6541828Sa.suvorov@f5.com 6551828Sa.suvorov@f5.com domain.start = nxt_mp_nget(mp, len + 1); 6561828Sa.suvorov@f5.com if (nxt_slow_path(domain.start == NULL)) { 6571828Sa.suvorov@f5.com return NXT_ERROR; 6581828Sa.suvorov@f5.com } 6591828Sa.suvorov@f5.com 6601828Sa.suvorov@f5.com domain.length = X509_NAME_get_text_by_NID(x509_name, NID_commonName, 6611828Sa.suvorov@f5.com (char *) domain.start, 6621828Sa.suvorov@f5.com len + 1); 6631828Sa.suvorov@f5.com nxt_memcpy_lowcase(domain.start, domain.start, domain.length); 6641828Sa.suvorov@f5.com 6651828Sa.suvorov@f5.com item = nxt_mp_get(mp, sizeof(nxt_tls_bundle_hash_item_t)); 6661828Sa.suvorov@f5.com if (nxt_slow_path(item == NULL)) { 6671828Sa.suvorov@f5.com return NXT_ERROR; 6681828Sa.suvorov@f5.com } 6691828Sa.suvorov@f5.com 6701828Sa.suvorov@f5.com item->name = domain; 6711828Sa.suvorov@f5.com item->bundle = bundle; 6721828Sa.suvorov@f5.com 6731828Sa.suvorov@f5.com if (nxt_openssl_bundle_hash_insert(task, &conf->bundle_hash, item, 6741828Sa.suvorov@f5.com mp) 6751828Sa.suvorov@f5.com == NXT_ERROR) 6761828Sa.suvorov@f5.com { 6771828Sa.suvorov@f5.com return NXT_ERROR; 6781828Sa.suvorov@f5.com } 6791828Sa.suvorov@f5.com } 6801828Sa.suvorov@f5.com 6811828Sa.suvorov@f5.com return NXT_OK; 6821828Sa.suvorov@f5.com 6831828Sa.suvorov@f5.com fail: 6841828Sa.suvorov@f5.com 6851828Sa.suvorov@f5.com sk_GENERAL_NAME_pop_free(alt_names, GENERAL_NAME_free); 6861828Sa.suvorov@f5.com 6871828Sa.suvorov@f5.com return NXT_ERROR; 6881828Sa.suvorov@f5.com } 6891828Sa.suvorov@f5.com 6901828Sa.suvorov@f5.com 6911828Sa.suvorov@f5.com static const nxt_lvlhsh_proto_t nxt_openssl_bundle_hash_proto 6921828Sa.suvorov@f5.com nxt_aligned(64) = 6931828Sa.suvorov@f5.com { 6941828Sa.suvorov@f5.com NXT_LVLHSH_DEFAULT, 6951828Sa.suvorov@f5.com nxt_openssl_bundle_hash_test, 6961828Sa.suvorov@f5.com nxt_mp_lvlhsh_alloc, 6971828Sa.suvorov@f5.com nxt_mp_lvlhsh_free, 6981828Sa.suvorov@f5.com }; 6991828Sa.suvorov@f5.com 7001828Sa.suvorov@f5.com 7011828Sa.suvorov@f5.com static nxt_int_t 7021828Sa.suvorov@f5.com nxt_openssl_bundle_hash_test(nxt_lvlhsh_query_t *lhq, void *data) 7031828Sa.suvorov@f5.com { 7041828Sa.suvorov@f5.com nxt_tls_bundle_hash_item_t *item; 7051828Sa.suvorov@f5.com 7061828Sa.suvorov@f5.com item = data; 7071828Sa.suvorov@f5.com 7081828Sa.suvorov@f5.com return nxt_strstr_eq(&lhq->key, &item->name) ? NXT_OK : NXT_DECLINED; 7091828Sa.suvorov@f5.com } 7101828Sa.suvorov@f5.com 7111828Sa.suvorov@f5.com 7121828Sa.suvorov@f5.com static nxt_int_t 7131828Sa.suvorov@f5.com nxt_openssl_bundle_hash_insert(nxt_task_t *task, nxt_lvlhsh_t *lvlhsh, 7141828Sa.suvorov@f5.com nxt_tls_bundle_hash_item_t *item, nxt_mp_t *mp) 7151828Sa.suvorov@f5.com { 7161828Sa.suvorov@f5.com nxt_str_t str; 7171828Sa.suvorov@f5.com nxt_int_t ret; 7181828Sa.suvorov@f5.com nxt_lvlhsh_query_t lhq; 7191828Sa.suvorov@f5.com nxt_tls_bundle_hash_item_t *old; 7201828Sa.suvorov@f5.com 7211828Sa.suvorov@f5.com str = item->name; 7221828Sa.suvorov@f5.com 7231828Sa.suvorov@f5.com if (item->name.start[0] == '*') { 7241828Sa.suvorov@f5.com item->name.start++; 7251828Sa.suvorov@f5.com item->name.length--; 7261828Sa.suvorov@f5.com 7271828Sa.suvorov@f5.com if (item->name.length == 0 || item->name.start[0] != '.') { 7281828Sa.suvorov@f5.com nxt_log(task, NXT_LOG_WARN, "ignored invalid name \"%V\" " 7291828Sa.suvorov@f5.com "in certificate \"%V\": missing \".\" " 730*1885Sa.suvorov@f5.com "after wildcard symbol", &str, &item->bundle->name); 7311828Sa.suvorov@f5.com return NXT_OK; 7321828Sa.suvorov@f5.com } 7331828Sa.suvorov@f5.com } 7341828Sa.suvorov@f5.com 7351828Sa.suvorov@f5.com lhq.pool = mp; 7361828Sa.suvorov@f5.com lhq.key = item->name; 7371828Sa.suvorov@f5.com lhq.value = item; 7381828Sa.suvorov@f5.com lhq.proto = &nxt_openssl_bundle_hash_proto; 7391828Sa.suvorov@f5.com lhq.replace = 0; 7401828Sa.suvorov@f5.com lhq.key_hash = nxt_murmur_hash2(item->name.start, item->name.length); 7411828Sa.suvorov@f5.com 7421828Sa.suvorov@f5.com ret = nxt_lvlhsh_insert(lvlhsh, &lhq); 7431828Sa.suvorov@f5.com if (nxt_fast_path(ret == NXT_OK)) { 7441828Sa.suvorov@f5.com nxt_debug(task, "name \"%V\" for certificate \"%V\" is inserted", 745*1885Sa.suvorov@f5.com &str, &item->bundle->name); 7461828Sa.suvorov@f5.com return NXT_OK; 7471828Sa.suvorov@f5.com } 7481828Sa.suvorov@f5.com 7491828Sa.suvorov@f5.com if (nxt_fast_path(ret == NXT_DECLINED)) { 7501828Sa.suvorov@f5.com old = lhq.value; 7511828Sa.suvorov@f5.com if (old->bundle != item->bundle) { 7521828Sa.suvorov@f5.com nxt_log(task, NXT_LOG_WARN, "ignored duplicate name \"%V\" " 7531828Sa.suvorov@f5.com "in certificate \"%V\", identical name appears in \"%V\"", 754*1885Sa.suvorov@f5.com &str, &old->bundle->name, &item->bundle->name); 7551828Sa.suvorov@f5.com 7561828Sa.suvorov@f5.com old->bundle = item->bundle; 7571828Sa.suvorov@f5.com } 7581828Sa.suvorov@f5.com 7591828Sa.suvorov@f5.com return NXT_OK; 7601828Sa.suvorov@f5.com } 7611828Sa.suvorov@f5.com 7621828Sa.suvorov@f5.com return NXT_ERROR; 7631828Sa.suvorov@f5.com } 7641828Sa.suvorov@f5.com 7651828Sa.suvorov@f5.com 7661828Sa.suvorov@f5.com static nxt_int_t 7671828Sa.suvorov@f5.com nxt_openssl_servername(SSL *s, int *ad, void *arg) 7681828Sa.suvorov@f5.com { 7691828Sa.suvorov@f5.com nxt_str_t str; 7701828Sa.suvorov@f5.com nxt_uint_t i; 7711828Sa.suvorov@f5.com nxt_conn_t *c; 7721828Sa.suvorov@f5.com const char *servername; 7731828Sa.suvorov@f5.com nxt_tls_conf_t *conf; 7741828Sa.suvorov@f5.com nxt_openssl_conn_t *tls; 7751828Sa.suvorov@f5.com nxt_tls_bundle_conf_t *bundle; 7761828Sa.suvorov@f5.com 7771828Sa.suvorov@f5.com c = SSL_get_ex_data(s, nxt_openssl_connection_index); 7781828Sa.suvorov@f5.com 7791828Sa.suvorov@f5.com if (nxt_slow_path(c == NULL)) { 7801828Sa.suvorov@f5.com nxt_thread_log_alert("SSL_get_ex_data() failed"); 7811828Sa.suvorov@f5.com return SSL_TLSEXT_ERR_ALERT_FATAL; 7821828Sa.suvorov@f5.com } 7831828Sa.suvorov@f5.com 7841828Sa.suvorov@f5.com servername = SSL_get_servername(s, TLSEXT_NAMETYPE_host_name); 7851828Sa.suvorov@f5.com if (nxt_slow_path(servername == NULL)) { 7861828Sa.suvorov@f5.com nxt_log(c->socket.task, NXT_LOG_ALERT, "SSL_get_servername() returned " 7871828Sa.suvorov@f5.com "NULL in server name callback"); 7881828Sa.suvorov@f5.com return SSL_TLSEXT_ERR_ALERT_FATAL; 7891828Sa.suvorov@f5.com } 7901828Sa.suvorov@f5.com 7911828Sa.suvorov@f5.com str.length = nxt_strlen(servername); 7921828Sa.suvorov@f5.com if (str.length == 0) { 7931828Sa.suvorov@f5.com nxt_debug(c->socket.task, "client sent zero-length server name"); 7941828Sa.suvorov@f5.com goto done; 7951828Sa.suvorov@f5.com } 7961828Sa.suvorov@f5.com 7971828Sa.suvorov@f5.com if (servername[0] == '.') { 7981828Sa.suvorov@f5.com nxt_debug(c->socket.task, "ignored the server name \"%s\": " 7991828Sa.suvorov@f5.com "leading \".\"", servername); 8001828Sa.suvorov@f5.com goto done; 8011828Sa.suvorov@f5.com } 8021828Sa.suvorov@f5.com 8031828Sa.suvorov@f5.com nxt_debug(c->socket.task, "tls with servername \"%s\"", servername); 8041828Sa.suvorov@f5.com 8051828Sa.suvorov@f5.com str.start = nxt_mp_nget(c->mem_pool, str.length); 8061828Sa.suvorov@f5.com if (nxt_slow_path(str.start == NULL)) { 8071828Sa.suvorov@f5.com return SSL_TLSEXT_ERR_ALERT_FATAL; 8081828Sa.suvorov@f5.com } 8091828Sa.suvorov@f5.com 8101828Sa.suvorov@f5.com nxt_memcpy_lowcase(str.start, (const u_char *) servername, str.length); 8111828Sa.suvorov@f5.com 8121828Sa.suvorov@f5.com tls = c->u.tls; 8131828Sa.suvorov@f5.com conf = tls->conf; 8141828Sa.suvorov@f5.com 8151828Sa.suvorov@f5.com bundle = nxt_openssl_find_ctx(conf, &str); 8161828Sa.suvorov@f5.com 8171828Sa.suvorov@f5.com if (bundle == NULL) { 8181828Sa.suvorov@f5.com for (i = 1; i < str.length; i++) { 8191828Sa.suvorov@f5.com if (str.start[i] == '.') { 8201828Sa.suvorov@f5.com str.start += i; 8211828Sa.suvorov@f5.com str.length -= i; 8221828Sa.suvorov@f5.com 8231828Sa.suvorov@f5.com bundle = nxt_openssl_find_ctx(conf, &str); 8241828Sa.suvorov@f5.com break; 8251828Sa.suvorov@f5.com } 8261828Sa.suvorov@f5.com } 8271828Sa.suvorov@f5.com } 8281828Sa.suvorov@f5.com 8291828Sa.suvorov@f5.com if (bundle != NULL) { 8301828Sa.suvorov@f5.com nxt_debug(c->socket.task, "new tls context found for \"%V\": \"%V\" " 831*1885Sa.suvorov@f5.com "(old: \"%V\")", &str, &bundle->name, 832*1885Sa.suvorov@f5.com &conf->bundle->name); 8331828Sa.suvorov@f5.com 8341828Sa.suvorov@f5.com if (bundle != conf->bundle) { 8351828Sa.suvorov@f5.com if (SSL_set_SSL_CTX(s, bundle->ctx) == NULL) { 8361828Sa.suvorov@f5.com nxt_openssl_log_error(c->socket.task, NXT_LOG_ALERT, 8371828Sa.suvorov@f5.com "SSL_set_SSL_CTX() failed"); 8381828Sa.suvorov@f5.com 8391828Sa.suvorov@f5.com return SSL_TLSEXT_ERR_ALERT_FATAL; 8401828Sa.suvorov@f5.com } 8411828Sa.suvorov@f5.com } 8421828Sa.suvorov@f5.com } 8431828Sa.suvorov@f5.com 8441828Sa.suvorov@f5.com done: 8451828Sa.suvorov@f5.com 8461828Sa.suvorov@f5.com return SSL_TLSEXT_ERR_OK; 8471828Sa.suvorov@f5.com } 8481828Sa.suvorov@f5.com 8491828Sa.suvorov@f5.com 8501828Sa.suvorov@f5.com static nxt_tls_bundle_conf_t * 8511828Sa.suvorov@f5.com nxt_openssl_find_ctx(nxt_tls_conf_t *conf, nxt_str_t *sn) 8521828Sa.suvorov@f5.com { 8531828Sa.suvorov@f5.com nxt_int_t ret; 8541828Sa.suvorov@f5.com nxt_lvlhsh_query_t lhq; 8551828Sa.suvorov@f5.com nxt_tls_bundle_hash_item_t *item; 8561828Sa.suvorov@f5.com 8571828Sa.suvorov@f5.com lhq.key_hash = nxt_murmur_hash2(sn->start, sn->length); 8581828Sa.suvorov@f5.com lhq.key = *sn; 8591828Sa.suvorov@f5.com lhq.proto = &nxt_openssl_bundle_hash_proto; 8601828Sa.suvorov@f5.com 8611828Sa.suvorov@f5.com ret = nxt_lvlhsh_find(&conf->bundle_hash, &lhq); 8621828Sa.suvorov@f5.com if (ret != NXT_OK) { 8631828Sa.suvorov@f5.com return NULL; 8641828Sa.suvorov@f5.com } 8651828Sa.suvorov@f5.com 8661828Sa.suvorov@f5.com item = lhq.value; 8671828Sa.suvorov@f5.com 8681828Sa.suvorov@f5.com return item->bundle; 8691828Sa.suvorov@f5.com } 8701828Sa.suvorov@f5.com 8711828Sa.suvorov@f5.com 8720Sigor@sysoev.ru static void 873771Sigor@sysoev.ru nxt_openssl_server_free(nxt_task_t *task, nxt_tls_conf_t *conf) 8740Sigor@sysoev.ru { 8751828Sa.suvorov@f5.com nxt_tls_bundle_conf_t *bundle; 8761828Sa.suvorov@f5.com 8771828Sa.suvorov@f5.com bundle = conf->bundle; 8781828Sa.suvorov@f5.com nxt_assert(bundle != NULL); 8791828Sa.suvorov@f5.com 8801828Sa.suvorov@f5.com do { 8811828Sa.suvorov@f5.com SSL_CTX_free(bundle->ctx); 8821828Sa.suvorov@f5.com bundle = bundle->next; 8831828Sa.suvorov@f5.com } while (bundle != NULL); 8841818Smax.romanov@nginx.com 8851818Smax.romanov@nginx.com #if (OPENSSL_VERSION_NUMBER >= 0x1010100fL \ 8861818Smax.romanov@nginx.com && OPENSSL_VERSION_NUMBER < 0x1010101fL) 8871818Smax.romanov@nginx.com RAND_keep_random_devices_open(0); 8881818Smax.romanov@nginx.com #endif 889771Sigor@sysoev.ru } 890771Sigor@sysoev.ru 891771Sigor@sysoev.ru 892771Sigor@sysoev.ru static void 893771Sigor@sysoev.ru nxt_openssl_conn_init(nxt_task_t *task, nxt_tls_conf_t *conf, nxt_conn_t *c) 894771Sigor@sysoev.ru { 895771Sigor@sysoev.ru int ret; 896771Sigor@sysoev.ru SSL *s; 897771Sigor@sysoev.ru SSL_CTX *ctx; 898771Sigor@sysoev.ru nxt_openssl_conn_t *tls; 8990Sigor@sysoev.ru 9000Sigor@sysoev.ru nxt_log_debug(c->socket.log, "openssl conn init"); 9010Sigor@sysoev.ru 902771Sigor@sysoev.ru tls = nxt_mp_zget(c->mem_pool, sizeof(nxt_openssl_conn_t)); 903771Sigor@sysoev.ru if (tls == NULL) { 9040Sigor@sysoev.ru goto fail; 9050Sigor@sysoev.ru } 906