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> 9*2089Spluknet@nginx.com 10*2089Spluknet@nginx.com #define OPENSSL_SUPPRESS_DEPRECATED 11*2089Spluknet@nginx.com 120Sigor@sysoev.ru #include <openssl/ssl.h> 130Sigor@sysoev.ru #include <openssl/conf.h> 140Sigor@sysoev.ru #include <openssl/err.h> 151818Smax.romanov@nginx.com #include <openssl/rand.h> 161828Sa.suvorov@f5.com #include <openssl/x509v3.h> 171942Sa.suvorov@f5.com #include <openssl/bio.h> 181942Sa.suvorov@f5.com #include <openssl/evp.h> 190Sigor@sysoev.ru 200Sigor@sysoev.ru 210Sigor@sysoev.ru typedef struct { 221952Svbart@nginx.com SSL *session; 231952Svbart@nginx.com nxt_conn_t *conn; 241952Svbart@nginx.com 251952Svbart@nginx.com int ssl_error; 261952Svbart@nginx.com uint8_t times; /* 2 bits */ 271952Svbart@nginx.com uint8_t handshake; /* 1 bit */ 281952Svbart@nginx.com 291952Svbart@nginx.com nxt_tls_conf_t *conf; 301952Svbart@nginx.com nxt_buf_mem_t buffer; 311952Svbart@nginx.com } nxt_openssl_conn_t; 321952Svbart@nginx.com 330Sigor@sysoev.ru 341952Svbart@nginx.com struct nxt_tls_ticket_s { 351952Svbart@nginx.com u_char name[16]; 361952Svbart@nginx.com u_char hmac_key[32]; 371952Svbart@nginx.com u_char aes_key[32]; 381952Svbart@nginx.com uint8_t size; 391952Svbart@nginx.com }; 400Sigor@sysoev.ru 411952Svbart@nginx.com 421952Svbart@nginx.com struct nxt_tls_tickets_s { 431952Svbart@nginx.com nxt_uint_t count; 441952Svbart@nginx.com nxt_tls_ticket_t tickets[]; 451952Svbart@nginx.com }; 460Sigor@sysoev.ru 470Sigor@sysoev.ru 48771Sigor@sysoev.ru typedef enum { 49771Sigor@sysoev.ru NXT_OPENSSL_HANDSHAKE = 0, 50771Sigor@sysoev.ru NXT_OPENSSL_READ, 51771Sigor@sysoev.ru NXT_OPENSSL_WRITE, 52771Sigor@sysoev.ru NXT_OPENSSL_SHUTDOWN, 53771Sigor@sysoev.ru } nxt_openssl_io_t; 54771Sigor@sysoev.ru 550Sigor@sysoev.ru 56771Sigor@sysoev.ru static nxt_int_t nxt_openssl_library_init(nxt_task_t *task); 57771Sigor@sysoev.ru static void nxt_openssl_library_free(nxt_task_t *task); 58771Sigor@sysoev.ru #if OPENSSL_VERSION_NUMBER < 0x10100004L 59771Sigor@sysoev.ru static nxt_int_t nxt_openssl_locks_init(void); 60771Sigor@sysoev.ru static void nxt_openssl_lock(int mode, int type, const char *file, int line); 61771Sigor@sysoev.ru static unsigned long nxt_openssl_thread_id(void); 62771Sigor@sysoev.ru static void nxt_openssl_locks_free(void); 63771Sigor@sysoev.ru #endif 641920Sa.suvorov@f5.com static nxt_int_t nxt_openssl_server_init(nxt_task_t *task, nxt_mp_t *mp, 651920Sa.suvorov@f5.com nxt_tls_init_t *tls_init, nxt_bool_t last); 661828Sa.suvorov@f5.com static nxt_int_t nxt_openssl_chain_file(nxt_task_t *task, SSL_CTX *ctx, 671828Sa.suvorov@f5.com nxt_tls_conf_t *conf, nxt_mp_t *mp, nxt_bool_t single); 681885Sa.suvorov@f5.com #if (NXT_HAVE_OPENSSL_CONF_CMD) 691885Sa.suvorov@f5.com static nxt_int_t nxt_ssl_conf_commands(nxt_task_t *task, SSL_CTX *ctx, 701885Sa.suvorov@f5.com nxt_conf_value_t *value, nxt_mp_t *mp); 711885Sa.suvorov@f5.com #endif 721942Sa.suvorov@f5.com #if (NXT_HAVE_OPENSSL_TLSEXT) 731942Sa.suvorov@f5.com static nxt_int_t nxt_tls_ticket_keys(nxt_task_t *task, SSL_CTX *ctx, 741942Sa.suvorov@f5.com nxt_tls_init_t *tls_init, nxt_mp_t *mp); 751942Sa.suvorov@f5.com static int nxt_tls_ticket_key_callback(SSL *s, unsigned char *name, 761942Sa.suvorov@f5.com unsigned char *iv, EVP_CIPHER_CTX *ectx,HMAC_CTX *hctx, int enc); 771942Sa.suvorov@f5.com #endif 781920Sa.suvorov@f5.com static void nxt_ssl_session_cache(SSL_CTX *ctx, size_t cache_size, 791920Sa.suvorov@f5.com time_t timeout); 801828Sa.suvorov@f5.com static nxt_uint_t nxt_openssl_cert_get_names(nxt_task_t *task, X509 *cert, 811828Sa.suvorov@f5.com nxt_tls_conf_t *conf, nxt_mp_t *mp); 821828Sa.suvorov@f5.com static nxt_int_t nxt_openssl_bundle_hash_test(nxt_lvlhsh_query_t *lhq, 831828Sa.suvorov@f5.com void *data); 841828Sa.suvorov@f5.com static nxt_int_t nxt_openssl_bundle_hash_insert(nxt_task_t *task, 851828Sa.suvorov@f5.com nxt_lvlhsh_t *lvlhsh, nxt_tls_bundle_hash_item_t *item, nxt_mp_t * mp); 861828Sa.suvorov@f5.com static nxt_int_t nxt_openssl_servername(SSL *s, int *ad, void *arg); 871828Sa.suvorov@f5.com static nxt_tls_bundle_conf_t *nxt_openssl_find_ctx(nxt_tls_conf_t *conf, 881828Sa.suvorov@f5.com nxt_str_t *sn); 89771Sigor@sysoev.ru static void nxt_openssl_server_free(nxt_task_t *task, nxt_tls_conf_t *conf); 90771Sigor@sysoev.ru static void nxt_openssl_conn_init(nxt_task_t *task, nxt_tls_conf_t *conf, 9162Sigor@sysoev.ru nxt_conn_t *c); 921Sigor@sysoev.ru static void nxt_openssl_conn_handshake(nxt_task_t *task, void *obj, void *data); 93771Sigor@sysoev.ru static ssize_t nxt_openssl_conn_io_recvbuf(nxt_conn_t *c, nxt_buf_t *b); 94771Sigor@sysoev.ru static ssize_t nxt_openssl_conn_io_sendbuf(nxt_task_t *task, nxt_sendbuf_t *sb); 95771Sigor@sysoev.ru static ssize_t nxt_openssl_conn_io_send(nxt_task_t *task, nxt_sendbuf_t *sb, 96771Sigor@sysoev.ru void *buf, size_t size); 971Sigor@sysoev.ru static void nxt_openssl_conn_io_shutdown(nxt_task_t *task, void *obj, 980Sigor@sysoev.ru void *data); 99771Sigor@sysoev.ru static nxt_int_t nxt_openssl_conn_test_error(nxt_task_t *task, nxt_conn_t *c, 100771Sigor@sysoev.ru int ret, nxt_err_t sys_err, nxt_openssl_io_t io); 1011884Sa.suvorov@f5.com static void nxt_openssl_conn_io_shutdown_timeout(nxt_task_t *task, void *obj, 1021884Sa.suvorov@f5.com void *data); 103771Sigor@sysoev.ru static void nxt_cdecl nxt_openssl_conn_error(nxt_task_t *task, 104771Sigor@sysoev.ru nxt_err_t err, const char *fmt, ...); 105771Sigor@sysoev.ru static nxt_uint_t nxt_openssl_log_error_level(nxt_err_t err); 1060Sigor@sysoev.ru 1070Sigor@sysoev.ru 108771Sigor@sysoev.ru const nxt_tls_lib_t nxt_openssl_lib = { 109771Sigor@sysoev.ru .library_init = nxt_openssl_library_init, 110771Sigor@sysoev.ru .library_free = nxt_openssl_library_free, 111771Sigor@sysoev.ru 112771Sigor@sysoev.ru .server_init = nxt_openssl_server_init, 113771Sigor@sysoev.ru .server_free = nxt_openssl_server_free, 1140Sigor@sysoev.ru }; 1150Sigor@sysoev.ru 1160Sigor@sysoev.ru 11762Sigor@sysoev.ru static nxt_conn_io_t nxt_openssl_conn_io = { 118771Sigor@sysoev.ru .read = nxt_conn_io_read, 119771Sigor@sysoev.ru .recvbuf = nxt_openssl_conn_io_recvbuf, 1200Sigor@sysoev.ru 121771Sigor@sysoev.ru .write = nxt_conn_io_write, 122771Sigor@sysoev.ru .sendbuf = nxt_openssl_conn_io_sendbuf, 1230Sigor@sysoev.ru 124771Sigor@sysoev.ru .shutdown = nxt_openssl_conn_io_shutdown, 1250Sigor@sysoev.ru }; 1260Sigor@sysoev.ru 1270Sigor@sysoev.ru 1280Sigor@sysoev.ru static long nxt_openssl_version; 1290Sigor@sysoev.ru static int nxt_openssl_connection_index; 1300Sigor@sysoev.ru 1310Sigor@sysoev.ru 1320Sigor@sysoev.ru static nxt_int_t 133771Sigor@sysoev.ru nxt_openssl_library_init(nxt_task_t *task) 1340Sigor@sysoev.ru { 1350Sigor@sysoev.ru int index; 1360Sigor@sysoev.ru 1370Sigor@sysoev.ru if (nxt_fast_path(nxt_openssl_version != 0)) { 1380Sigor@sysoev.ru return NXT_OK; 1390Sigor@sysoev.ru } 1400Sigor@sysoev.ru 141771Sigor@sysoev.ru #if OPENSSL_VERSION_NUMBER >= 0x10100003L 142771Sigor@sysoev.ru 143771Sigor@sysoev.ru OPENSSL_init_ssl(OPENSSL_INIT_LOAD_CONFIG, NULL); 1440Sigor@sysoev.ru 145771Sigor@sysoev.ru #else 146771Sigor@sysoev.ru { 147771Sigor@sysoev.ru nxt_int_t ret; 148771Sigor@sysoev.ru 149771Sigor@sysoev.ru SSL_load_error_strings(); 150771Sigor@sysoev.ru 151771Sigor@sysoev.ru OPENSSL_config(NULL); 1520Sigor@sysoev.ru 153771Sigor@sysoev.ru /* 154771Sigor@sysoev.ru * SSL_library_init(3): 155771Sigor@sysoev.ru * 156771Sigor@sysoev.ru * SSL_library_init() always returns "1", 157771Sigor@sysoev.ru * so it is safe to discard the return value. 158771Sigor@sysoev.ru */ 159771Sigor@sysoev.ru (void) SSL_library_init(); 160771Sigor@sysoev.ru 161771Sigor@sysoev.ru ret = nxt_openssl_locks_init(); 162771Sigor@sysoev.ru if (nxt_slow_path(ret != NXT_OK)) { 163771Sigor@sysoev.ru return ret; 164771Sigor@sysoev.ru } 165771Sigor@sysoev.ru } 166771Sigor@sysoev.ru 167771Sigor@sysoev.ru #endif 1680Sigor@sysoev.ru 1690Sigor@sysoev.ru nxt_openssl_version = SSLeay(); 1700Sigor@sysoev.ru 171771Sigor@sysoev.ru nxt_log(task, NXT_LOG_INFO, "%s, %xl", 172771Sigor@sysoev.ru SSLeay_version(SSLEAY_VERSION), nxt_openssl_version); 1730Sigor@sysoev.ru 1740Sigor@sysoev.ru #ifndef SSL_OP_NO_COMPRESSION 1750Sigor@sysoev.ru { 1760Sigor@sysoev.ru /* 1770Sigor@sysoev.ru * Disable gzip compression in OpenSSL prior to 1.0.0 1780Sigor@sysoev.ru * version, this saves about 522K per connection. 1790Sigor@sysoev.ru */ 1800Sigor@sysoev.ru int n; 1810Sigor@sysoev.ru STACK_OF(SSL_COMP) *ssl_comp_methods; 1820Sigor@sysoev.ru 1830Sigor@sysoev.ru ssl_comp_methods = SSL_COMP_get_compression_methods(); 1840Sigor@sysoev.ru 1850Sigor@sysoev.ru for (n = sk_SSL_COMP_num(ssl_comp_methods); n != 0; n--) { 1860Sigor@sysoev.ru (void) sk_SSL_COMP_pop(ssl_comp_methods); 1870Sigor@sysoev.ru } 1880Sigor@sysoev.ru } 1890Sigor@sysoev.ru #endif 1900Sigor@sysoev.ru 1910Sigor@sysoev.ru index = SSL_get_ex_new_index(0, NULL, NULL, NULL, NULL); 1920Sigor@sysoev.ru 1930Sigor@sysoev.ru if (index == -1) { 194771Sigor@sysoev.ru nxt_openssl_log_error(task, NXT_LOG_ALERT, 1950Sigor@sysoev.ru "SSL_get_ex_new_index() failed"); 1960Sigor@sysoev.ru return NXT_ERROR; 1970Sigor@sysoev.ru } 1980Sigor@sysoev.ru 1990Sigor@sysoev.ru nxt_openssl_connection_index = index; 2000Sigor@sysoev.ru 2010Sigor@sysoev.ru return NXT_OK; 2020Sigor@sysoev.ru } 2030Sigor@sysoev.ru 2040Sigor@sysoev.ru 205771Sigor@sysoev.ru #if OPENSSL_VERSION_NUMBER >= 0x10100003L 206771Sigor@sysoev.ru 207771Sigor@sysoev.ru static void 208771Sigor@sysoev.ru nxt_openssl_library_free(nxt_task_t *task) 209771Sigor@sysoev.ru { 210771Sigor@sysoev.ru } 211771Sigor@sysoev.ru 212771Sigor@sysoev.ru #else 213771Sigor@sysoev.ru 214771Sigor@sysoev.ru static nxt_thread_mutex_t *nxt_openssl_locks; 215771Sigor@sysoev.ru 2160Sigor@sysoev.ru static nxt_int_t 217771Sigor@sysoev.ru nxt_openssl_locks_init(void) 218771Sigor@sysoev.ru { 219771Sigor@sysoev.ru int i, n; 220771Sigor@sysoev.ru nxt_int_t ret; 221771Sigor@sysoev.ru 222771Sigor@sysoev.ru n = CRYPTO_num_locks(); 223771Sigor@sysoev.ru 224771Sigor@sysoev.ru nxt_openssl_locks = OPENSSL_malloc(n * sizeof(nxt_thread_mutex_t)); 225771Sigor@sysoev.ru if (nxt_slow_path(nxt_openssl_locks == NULL)) { 226771Sigor@sysoev.ru return NXT_ERROR; 227771Sigor@sysoev.ru } 228771Sigor@sysoev.ru 229771Sigor@sysoev.ru for (i = 0; i < n; i++) { 230771Sigor@sysoev.ru ret = nxt_thread_mutex_create(&nxt_openssl_locks[i]); 231771Sigor@sysoev.ru if (nxt_slow_path(ret != NXT_OK)) { 232771Sigor@sysoev.ru return ret; 233771Sigor@sysoev.ru } 234771Sigor@sysoev.ru } 235771Sigor@sysoev.ru 236771Sigor@sysoev.ru CRYPTO_set_locking_callback(nxt_openssl_lock); 237771Sigor@sysoev.ru 238771Sigor@sysoev.ru CRYPTO_set_id_callback(nxt_openssl_thread_id); 239771Sigor@sysoev.ru 240771Sigor@sysoev.ru return NXT_OK; 241771Sigor@sysoev.ru } 242771Sigor@sysoev.ru 243771Sigor@sysoev.ru 244771Sigor@sysoev.ru static void 245771Sigor@sysoev.ru nxt_openssl_lock(int mode, int type, const char *file, int line) 246771Sigor@sysoev.ru { 247771Sigor@sysoev.ru nxt_thread_mutex_t *lock; 248771Sigor@sysoev.ru 249771Sigor@sysoev.ru lock = &nxt_openssl_locks[type]; 250771Sigor@sysoev.ru 251771Sigor@sysoev.ru if ((mode & CRYPTO_LOCK) != 0) { 252771Sigor@sysoev.ru (void) nxt_thread_mutex_lock(lock); 253771Sigor@sysoev.ru 254771Sigor@sysoev.ru } else { 255771Sigor@sysoev.ru (void) nxt_thread_mutex_unlock(lock); 256771Sigor@sysoev.ru } 257771Sigor@sysoev.ru } 258771Sigor@sysoev.ru 259771Sigor@sysoev.ru 260771Sigor@sysoev.ru static u_long 261771Sigor@sysoev.ru nxt_openssl_thread_id(void) 262771Sigor@sysoev.ru { 263771Sigor@sysoev.ru return (u_long) nxt_thread_handle(); 264771Sigor@sysoev.ru } 265771Sigor@sysoev.ru 266771Sigor@sysoev.ru 267771Sigor@sysoev.ru static void 268771Sigor@sysoev.ru nxt_openssl_library_free(nxt_task_t *task) 269771Sigor@sysoev.ru { 270771Sigor@sysoev.ru nxt_openssl_locks_free(); 271771Sigor@sysoev.ru } 272771Sigor@sysoev.ru 273771Sigor@sysoev.ru 274771Sigor@sysoev.ru static void 275771Sigor@sysoev.ru nxt_openssl_locks_free(void) 276771Sigor@sysoev.ru { 277771Sigor@sysoev.ru int i, n; 278771Sigor@sysoev.ru 279771Sigor@sysoev.ru n = CRYPTO_num_locks(); 280771Sigor@sysoev.ru 281771Sigor@sysoev.ru CRYPTO_set_locking_callback(NULL); 282771Sigor@sysoev.ru 283771Sigor@sysoev.ru for (i = 0; i < n; i++) { 284771Sigor@sysoev.ru nxt_thread_mutex_destroy(&nxt_openssl_locks[i]); 285771Sigor@sysoev.ru } 286771Sigor@sysoev.ru 287771Sigor@sysoev.ru OPENSSL_free(nxt_openssl_locks); 288771Sigor@sysoev.ru } 289771Sigor@sysoev.ru 290771Sigor@sysoev.ru #endif 291771Sigor@sysoev.ru 292771Sigor@sysoev.ru 293771Sigor@sysoev.ru static nxt_int_t 2941920Sa.suvorov@f5.com nxt_openssl_server_init(nxt_task_t *task, nxt_mp_t *mp, 2951920Sa.suvorov@f5.com nxt_tls_init_t *tls_init, nxt_bool_t last) 2960Sigor@sysoev.ru { 2971828Sa.suvorov@f5.com SSL_CTX *ctx; 2981828Sa.suvorov@f5.com const char *ciphers, *ca_certificate; 2991920Sa.suvorov@f5.com nxt_tls_conf_t *conf; 3001828Sa.suvorov@f5.com STACK_OF(X509_NAME) *list; 3011828Sa.suvorov@f5.com nxt_tls_bundle_conf_t *bundle; 3020Sigor@sysoev.ru 3030Sigor@sysoev.ru ctx = SSL_CTX_new(SSLv23_server_method()); 3040Sigor@sysoev.ru if (ctx == NULL) { 305771Sigor@sysoev.ru nxt_openssl_log_error(task, NXT_LOG_ALERT, "SSL_CTX_new() failed"); 3060Sigor@sysoev.ru return NXT_ERROR; 3070Sigor@sysoev.ru } 3080Sigor@sysoev.ru 3091920Sa.suvorov@f5.com conf = tls_init->conf; 3101920Sa.suvorov@f5.com 3111828Sa.suvorov@f5.com bundle = conf->bundle; 3121828Sa.suvorov@f5.com nxt_assert(bundle != NULL); 3131828Sa.suvorov@f5.com 3141828Sa.suvorov@f5.com bundle->ctx = ctx; 3150Sigor@sysoev.ru 316771Sigor@sysoev.ru #ifdef SSL_OP_NO_RENEGOTIATION 317771Sigor@sysoev.ru /* Renegration is not currently supported. */ 318771Sigor@sysoev.ru SSL_CTX_set_options(ctx, SSL_OP_NO_RENEGOTIATION); 319771Sigor@sysoev.ru #endif 320771Sigor@sysoev.ru 3210Sigor@sysoev.ru #ifdef SSL_OP_NO_COMPRESSION 3220Sigor@sysoev.ru /* 3230Sigor@sysoev.ru * Disable gzip compression in OpenSSL 1.0.0, 3240Sigor@sysoev.ru * this saves about 522K per connection. 3250Sigor@sysoev.ru */ 3260Sigor@sysoev.ru SSL_CTX_set_options(ctx, SSL_OP_NO_COMPRESSION); 3270Sigor@sysoev.ru #endif 3280Sigor@sysoev.ru 3290Sigor@sysoev.ru #ifdef SSL_MODE_RELEASE_BUFFERS 3300Sigor@sysoev.ru 3310Sigor@sysoev.ru if (nxt_openssl_version >= 10001078) { 3320Sigor@sysoev.ru /* 3330Sigor@sysoev.ru * Allow to release read and write buffers in OpenSSL 1.0.0, 3340Sigor@sysoev.ru * this saves about 34K per idle connection. It is not safe 3350Sigor@sysoev.ru * before OpenSSL 1.0.1h (CVE-2010-5298). 3360Sigor@sysoev.ru */ 3370Sigor@sysoev.ru SSL_CTX_set_mode(ctx, SSL_MODE_RELEASE_BUFFERS); 3380Sigor@sysoev.ru } 3390Sigor@sysoev.ru 3400Sigor@sysoev.ru #endif 3410Sigor@sysoev.ru 3421828Sa.suvorov@f5.com if (nxt_openssl_chain_file(task, ctx, conf, mp, 3431828Sa.suvorov@f5.com last && bundle->next == NULL) 3441828Sa.suvorov@f5.com != NXT_OK) 3451828Sa.suvorov@f5.com { 3460Sigor@sysoev.ru goto fail; 3470Sigor@sysoev.ru } 348774Svbart@nginx.com /* 3490Sigor@sysoev.ru key = conf->certificate_key; 3500Sigor@sysoev.ru 3510Sigor@sysoev.ru if (SSL_CTX_use_PrivateKey_file(ctx, key, SSL_FILETYPE_PEM) == 0) { 352771Sigor@sysoev.ru nxt_openssl_log_error(task, NXT_LOG_ALERT, 3530Sigor@sysoev.ru "SSL_CTX_use_PrivateKey_file(\"%s\") failed", 3540Sigor@sysoev.ru key); 3550Sigor@sysoev.ru goto fail; 3560Sigor@sysoev.ru } 357774Svbart@nginx.com */ 3581885Sa.suvorov@f5.com 3590Sigor@sysoev.ru ciphers = (conf->ciphers != NULL) ? conf->ciphers : "HIGH:!aNULL:!MD5"; 3600Sigor@sysoev.ru 3610Sigor@sysoev.ru if (SSL_CTX_set_cipher_list(ctx, ciphers) == 0) { 362771Sigor@sysoev.ru nxt_openssl_log_error(task, NXT_LOG_ALERT, 3630Sigor@sysoev.ru "SSL_CTX_set_cipher_list(\"%s\") failed", 3640Sigor@sysoev.ru ciphers); 3650Sigor@sysoev.ru goto fail; 3660Sigor@sysoev.ru } 3670Sigor@sysoev.ru 3681885Sa.suvorov@f5.com #if (NXT_HAVE_OPENSSL_CONF_CMD) 3691920Sa.suvorov@f5.com if (tls_init->conf_cmds != NULL 3701920Sa.suvorov@f5.com && nxt_ssl_conf_commands(task, ctx, tls_init->conf_cmds, mp) != NXT_OK) 3711885Sa.suvorov@f5.com { 3721885Sa.suvorov@f5.com goto fail; 3731885Sa.suvorov@f5.com } 3741885Sa.suvorov@f5.com #endif 3751885Sa.suvorov@f5.com 3761920Sa.suvorov@f5.com nxt_ssl_session_cache(ctx, tls_init->cache_size, tls_init->timeout); 3771920Sa.suvorov@f5.com 3781942Sa.suvorov@f5.com #if (NXT_HAVE_OPENSSL_TLSEXT) 3791942Sa.suvorov@f5.com if (nxt_tls_ticket_keys(task, ctx, tls_init, mp) != NXT_OK) { 3801942Sa.suvorov@f5.com goto fail; 3811942Sa.suvorov@f5.com } 3821942Sa.suvorov@f5.com #endif 3831942Sa.suvorov@f5.com 3840Sigor@sysoev.ru SSL_CTX_set_options(ctx, SSL_OP_CIPHER_SERVER_PREFERENCE); 3850Sigor@sysoev.ru 3860Sigor@sysoev.ru if (conf->ca_certificate != NULL) { 3870Sigor@sysoev.ru 3880Sigor@sysoev.ru /* TODO: verify callback */ 3890Sigor@sysoev.ru SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER, NULL); 3900Sigor@sysoev.ru 3910Sigor@sysoev.ru /* TODO: verify depth */ 3920Sigor@sysoev.ru SSL_CTX_set_verify_depth(ctx, 1); 3930Sigor@sysoev.ru 3940Sigor@sysoev.ru ca_certificate = conf->ca_certificate; 3950Sigor@sysoev.ru 3960Sigor@sysoev.ru if (SSL_CTX_load_verify_locations(ctx, ca_certificate, NULL) == 0) { 397771Sigor@sysoev.ru nxt_openssl_log_error(task, NXT_LOG_ALERT, 3980Sigor@sysoev.ru "SSL_CTX_load_verify_locations(\"%s\") failed", 3990Sigor@sysoev.ru ca_certificate); 4000Sigor@sysoev.ru goto fail; 4010Sigor@sysoev.ru } 4020Sigor@sysoev.ru 4030Sigor@sysoev.ru list = SSL_load_client_CA_file(ca_certificate); 4040Sigor@sysoev.ru 4050Sigor@sysoev.ru if (list == NULL) { 406771Sigor@sysoev.ru nxt_openssl_log_error(task, NXT_LOG_ALERT, 4070Sigor@sysoev.ru "SSL_load_client_CA_file(\"%s\") failed", 4080Sigor@sysoev.ru ca_certificate); 4090Sigor@sysoev.ru goto fail; 4100Sigor@sysoev.ru } 4110Sigor@sysoev.ru 4120Sigor@sysoev.ru /* 4130Sigor@sysoev.ru * SSL_load_client_CA_file() in OpenSSL prior to 0.9.7h and 4140Sigor@sysoev.ru * 0.9.8 versions always leaves an error in the error queue. 4150Sigor@sysoev.ru */ 4160Sigor@sysoev.ru ERR_clear_error(); 4170Sigor@sysoev.ru 4180Sigor@sysoev.ru SSL_CTX_set_client_CA_list(ctx, list); 4190Sigor@sysoev.ru } 4200Sigor@sysoev.ru 4211828Sa.suvorov@f5.com if (last) { 4221828Sa.suvorov@f5.com conf->conn_init = nxt_openssl_conn_init; 4231828Sa.suvorov@f5.com 4241828Sa.suvorov@f5.com if (bundle->next != NULL) { 4251828Sa.suvorov@f5.com SSL_CTX_set_tlsext_servername_callback(ctx, nxt_openssl_servername); 4261828Sa.suvorov@f5.com } 4271828Sa.suvorov@f5.com } 4281828Sa.suvorov@f5.com 4290Sigor@sysoev.ru return NXT_OK; 4300Sigor@sysoev.ru 4310Sigor@sysoev.ru fail: 4320Sigor@sysoev.ru 4330Sigor@sysoev.ru SSL_CTX_free(ctx); 4340Sigor@sysoev.ru 4351818Smax.romanov@nginx.com #if (OPENSSL_VERSION_NUMBER >= 0x1010100fL \ 4361818Smax.romanov@nginx.com && OPENSSL_VERSION_NUMBER < 0x1010101fL) 4371818Smax.romanov@nginx.com RAND_keep_random_devices_open(0); 4381818Smax.romanov@nginx.com #endif 4391818Smax.romanov@nginx.com 4400Sigor@sysoev.ru return NXT_ERROR; 4410Sigor@sysoev.ru } 4420Sigor@sysoev.ru 4430Sigor@sysoev.ru 444833Svbart@nginx.com static nxt_int_t 4451828Sa.suvorov@f5.com nxt_openssl_chain_file(nxt_task_t *task, SSL_CTX *ctx, nxt_tls_conf_t *conf, 4461828Sa.suvorov@f5.com nxt_mp_t *mp, nxt_bool_t single) 447774Svbart@nginx.com { 4481828Sa.suvorov@f5.com BIO *bio; 4491828Sa.suvorov@f5.com X509 *cert, *ca; 4501828Sa.suvorov@f5.com long reason; 4511828Sa.suvorov@f5.com EVP_PKEY *key; 4521828Sa.suvorov@f5.com nxt_int_t ret; 4531828Sa.suvorov@f5.com nxt_tls_bundle_conf_t *bundle; 4541828Sa.suvorov@f5.com 4551828Sa.suvorov@f5.com ret = NXT_ERROR; 4561828Sa.suvorov@f5.com cert = NULL; 457774Svbart@nginx.com 458774Svbart@nginx.com bio = BIO_new(BIO_s_fd()); 459774Svbart@nginx.com if (bio == NULL) { 4601828Sa.suvorov@f5.com goto end; 461774Svbart@nginx.com } 462774Svbart@nginx.com 4631828Sa.suvorov@f5.com bundle = conf->bundle; 464774Svbart@nginx.com 4651828Sa.suvorov@f5.com BIO_set_fd(bio, bundle->chain_file, BIO_CLOSE); 466774Svbart@nginx.com 467774Svbart@nginx.com cert = PEM_read_bio_X509_AUX(bio, NULL, NULL, NULL); 468774Svbart@nginx.com if (cert == NULL) { 469774Svbart@nginx.com goto end; 470774Svbart@nginx.com } 471774Svbart@nginx.com 472774Svbart@nginx.com if (SSL_CTX_use_certificate(ctx, cert) != 1) { 473774Svbart@nginx.com goto end; 474774Svbart@nginx.com } 475774Svbart@nginx.com 4761828Sa.suvorov@f5.com if (!single && nxt_openssl_cert_get_names(task, cert, conf, mp) != NXT_OK) { 4771828Sa.suvorov@f5.com goto clean; 4781828Sa.suvorov@f5.com } 4791828Sa.suvorov@f5.com 480774Svbart@nginx.com for ( ;; ) { 481774Svbart@nginx.com ca = PEM_read_bio_X509(bio, NULL, NULL, NULL); 482774Svbart@nginx.com 483774Svbart@nginx.com if (ca == NULL) { 484774Svbart@nginx.com reason = ERR_GET_REASON(ERR_peek_last_error()); 485774Svbart@nginx.com if (reason != PEM_R_NO_START_LINE) { 486774Svbart@nginx.com goto end; 487774Svbart@nginx.com } 488774Svbart@nginx.com 489774Svbart@nginx.com ERR_clear_error(); 490774Svbart@nginx.com break; 491774Svbart@nginx.com } 492774Svbart@nginx.com 493774Svbart@nginx.com /* 494774Svbart@nginx.com * Note that ca isn't freed if it was successfully added to the chain, 495774Svbart@nginx.com * while the main certificate needs a X509_free() call, since 496774Svbart@nginx.com * its reference count is increased by SSL_CTX_use_certificate(). 497774Svbart@nginx.com */ 498808Spluknet@nginx.com #ifdef SSL_CTX_add0_chain_cert 499774Svbart@nginx.com if (SSL_CTX_add0_chain_cert(ctx, ca) != 1) { 500774Svbart@nginx.com #else 501774Svbart@nginx.com if (SSL_CTX_add_extra_chain_cert(ctx, ca) != 1) { 502774Svbart@nginx.com #endif 503774Svbart@nginx.com X509_free(ca); 504774Svbart@nginx.com goto end; 505774Svbart@nginx.com } 506774Svbart@nginx.com } 507774Svbart@nginx.com 508774Svbart@nginx.com if (BIO_reset(bio) != 0) { 509774Svbart@nginx.com goto end; 510774Svbart@nginx.com } 511774Svbart@nginx.com 512774Svbart@nginx.com key = PEM_read_bio_PrivateKey(bio, NULL, NULL, NULL); 513774Svbart@nginx.com if (key == NULL) { 514774Svbart@nginx.com goto end; 515774Svbart@nginx.com } 516774Svbart@nginx.com 517774Svbart@nginx.com if (SSL_CTX_use_PrivateKey(ctx, key) == 1) { 518774Svbart@nginx.com ret = NXT_OK; 519774Svbart@nginx.com } 520774Svbart@nginx.com 521774Svbart@nginx.com EVP_PKEY_free(key); 522774Svbart@nginx.com 523774Svbart@nginx.com end: 524774Svbart@nginx.com 5251828Sa.suvorov@f5.com if (ret != NXT_OK) { 5261828Sa.suvorov@f5.com nxt_openssl_log_error(task, NXT_LOG_ALERT, 5271828Sa.suvorov@f5.com "nxt_openssl_chain_file() failed"); 5281828Sa.suvorov@f5.com } 5291828Sa.suvorov@f5.com 5301828Sa.suvorov@f5.com clean: 5311828Sa.suvorov@f5.com 5321828Sa.suvorov@f5.com BIO_free(bio); 533774Svbart@nginx.com X509_free(cert); 534774Svbart@nginx.com 535774Svbart@nginx.com return ret; 536774Svbart@nginx.com } 537774Svbart@nginx.com 538774Svbart@nginx.com 5391885Sa.suvorov@f5.com #if (NXT_HAVE_OPENSSL_CONF_CMD) 5401885Sa.suvorov@f5.com 5411885Sa.suvorov@f5.com static nxt_int_t 5421885Sa.suvorov@f5.com nxt_ssl_conf_commands(nxt_task_t *task, SSL_CTX *ctx, nxt_conf_value_t *conf, 5431885Sa.suvorov@f5.com nxt_mp_t *mp) 5441885Sa.suvorov@f5.com { 5451885Sa.suvorov@f5.com int ret; 5461885Sa.suvorov@f5.com char *zcmd, *zvalue; 5471885Sa.suvorov@f5.com uint32_t index; 5481885Sa.suvorov@f5.com nxt_str_t cmd, value; 5491885Sa.suvorov@f5.com SSL_CONF_CTX *cctx; 5501885Sa.suvorov@f5.com nxt_conf_value_t *member; 5511885Sa.suvorov@f5.com 5521885Sa.suvorov@f5.com cctx = SSL_CONF_CTX_new(); 5531885Sa.suvorov@f5.com if (nxt_slow_path(cctx == NULL)) { 5541885Sa.suvorov@f5.com nxt_openssl_log_error(task, NXT_LOG_ALERT, 5551885Sa.suvorov@f5.com "SSL_CONF_CTX_new() failed"); 5561885Sa.suvorov@f5.com return NXT_ERROR; 5571885Sa.suvorov@f5.com } 5581885Sa.suvorov@f5.com 5591885Sa.suvorov@f5.com SSL_CONF_CTX_set_flags(cctx, SSL_CONF_FLAG_FILE 5601885Sa.suvorov@f5.com | SSL_CONF_FLAG_SERVER 5611885Sa.suvorov@f5.com | SSL_CONF_FLAG_CERTIFICATE 5621885Sa.suvorov@f5.com | SSL_CONF_FLAG_SHOW_ERRORS); 5631885Sa.suvorov@f5.com 5641885Sa.suvorov@f5.com SSL_CONF_CTX_set_ssl_ctx(cctx, ctx); 5651885Sa.suvorov@f5.com 5661885Sa.suvorov@f5.com index = 0; 5671885Sa.suvorov@f5.com 5681885Sa.suvorov@f5.com for ( ;; ) { 5691885Sa.suvorov@f5.com member = nxt_conf_next_object_member(conf, &cmd, &index); 5701885Sa.suvorov@f5.com if (nxt_slow_path(member == NULL)) { 5711885Sa.suvorov@f5.com break; 5721885Sa.suvorov@f5.com } 5731885Sa.suvorov@f5.com 5741885Sa.suvorov@f5.com nxt_conf_get_string(member, &value); 5751885Sa.suvorov@f5.com 5761885Sa.suvorov@f5.com zcmd = nxt_str_cstrz(mp, &cmd); 5771885Sa.suvorov@f5.com zvalue = nxt_str_cstrz(mp, &value); 5781885Sa.suvorov@f5.com 5791885Sa.suvorov@f5.com if (nxt_slow_path(zcmd == NULL || zvalue == NULL)) { 5801885Sa.suvorov@f5.com goto fail; 5811885Sa.suvorov@f5.com } 5821885Sa.suvorov@f5.com 5831885Sa.suvorov@f5.com ret = SSL_CONF_cmd(cctx, zcmd, zvalue); 5841885Sa.suvorov@f5.com if (ret == -2) { 5851885Sa.suvorov@f5.com nxt_openssl_log_error(task, NXT_LOG_ERR, 5861885Sa.suvorov@f5.com "unknown command \"%s\" in " 5871885Sa.suvorov@f5.com "\"conf_commands\" option", zcmd); 5881885Sa.suvorov@f5.com goto fail; 5891885Sa.suvorov@f5.com } 5901885Sa.suvorov@f5.com 5911885Sa.suvorov@f5.com if (ret <= 0) { 5921885Sa.suvorov@f5.com nxt_openssl_log_error(task, NXT_LOG_ERR, 5931885Sa.suvorov@f5.com "invalid value \"%s\" for command \"%s\" " 5941885Sa.suvorov@f5.com "in \"conf_commands\" option", 5951885Sa.suvorov@f5.com zvalue, zcmd); 5961885Sa.suvorov@f5.com goto fail; 5971885Sa.suvorov@f5.com } 5981885Sa.suvorov@f5.com 5991885Sa.suvorov@f5.com nxt_debug(task, "SSL_CONF_cmd(\"%s\", \"%s\")", zcmd, zvalue); 6001885Sa.suvorov@f5.com } 6011885Sa.suvorov@f5.com 6021885Sa.suvorov@f5.com if (SSL_CONF_CTX_finish(cctx) != 1) { 6031885Sa.suvorov@f5.com nxt_openssl_log_error(task, NXT_LOG_ALERT, 6041885Sa.suvorov@f5.com "SSL_CONF_finish() failed"); 6051885Sa.suvorov@f5.com goto fail; 6061885Sa.suvorov@f5.com } 6071885Sa.suvorov@f5.com 6081885Sa.suvorov@f5.com SSL_CONF_CTX_free(cctx); 6091885Sa.suvorov@f5.com 6101885Sa.suvorov@f5.com return NXT_OK; 6111885Sa.suvorov@f5.com 6121885Sa.suvorov@f5.com fail: 6131885Sa.suvorov@f5.com 6141885Sa.suvorov@f5.com SSL_CONF_CTX_free(cctx); 6151885Sa.suvorov@f5.com 6161885Sa.suvorov@f5.com return NXT_ERROR; 6171885Sa.suvorov@f5.com } 6181885Sa.suvorov@f5.com 6191885Sa.suvorov@f5.com #endif 6201885Sa.suvorov@f5.com 6211942Sa.suvorov@f5.com #if (NXT_HAVE_OPENSSL_TLSEXT) 6221942Sa.suvorov@f5.com 6231942Sa.suvorov@f5.com static nxt_int_t 6241942Sa.suvorov@f5.com nxt_tls_ticket_keys(nxt_task_t *task, SSL_CTX *ctx, nxt_tls_init_t *tls_init, 6251942Sa.suvorov@f5.com nxt_mp_t *mp) 6261942Sa.suvorov@f5.com { 6271975Svbart@nginx.com size_t len; 6281942Sa.suvorov@f5.com uint32_t i; 6291942Sa.suvorov@f5.com nxt_str_t value; 6301942Sa.suvorov@f5.com nxt_uint_t count; 6311942Sa.suvorov@f5.com nxt_conf_value_t *member, *tickets_conf; 6321942Sa.suvorov@f5.com nxt_tls_ticket_t *ticket; 6331942Sa.suvorov@f5.com nxt_tls_tickets_t *tickets; 6341942Sa.suvorov@f5.com u_char buf[80]; 6351942Sa.suvorov@f5.com 6361942Sa.suvorov@f5.com tickets_conf = tls_init->tickets_conf; 6371942Sa.suvorov@f5.com 6381942Sa.suvorov@f5.com if (tickets_conf == NULL) { 6391942Sa.suvorov@f5.com goto no_ticket; 6401942Sa.suvorov@f5.com } 6411942Sa.suvorov@f5.com 6421942Sa.suvorov@f5.com if (nxt_conf_type(tickets_conf) == NXT_CONF_BOOLEAN) { 6431942Sa.suvorov@f5.com if (nxt_conf_get_boolean(tickets_conf) == 0) { 6441942Sa.suvorov@f5.com goto no_ticket; 6451942Sa.suvorov@f5.com } 6461942Sa.suvorov@f5.com 6471942Sa.suvorov@f5.com return NXT_OK; 6481942Sa.suvorov@f5.com } 6491942Sa.suvorov@f5.com 6502077Salx.manpages@gmail.com count = nxt_conf_array_elements_count_or_1(tickets_conf); 6511942Sa.suvorov@f5.com 6522077Salx.manpages@gmail.com if (count == 0) { 6532077Salx.manpages@gmail.com goto no_ticket; 6541942Sa.suvorov@f5.com } 6551942Sa.suvorov@f5.com 6561942Sa.suvorov@f5.com #ifdef SSL_CTRL_SET_TLSEXT_TICKET_KEY_CB 6571942Sa.suvorov@f5.com 6581942Sa.suvorov@f5.com tickets = nxt_mp_get(mp, sizeof(nxt_tls_tickets_t) 6591942Sa.suvorov@f5.com + count * sizeof(nxt_tls_ticket_t)); 6601942Sa.suvorov@f5.com if (nxt_slow_path(tickets == NULL)) { 6611942Sa.suvorov@f5.com return NXT_ERROR; 6621942Sa.suvorov@f5.com } 6631942Sa.suvorov@f5.com 6641942Sa.suvorov@f5.com tickets->count = count; 6651942Sa.suvorov@f5.com tls_init->conf->tickets = tickets; 6661942Sa.suvorov@f5.com i = 0; 6671942Sa.suvorov@f5.com 6681942Sa.suvorov@f5.com do { 6691942Sa.suvorov@f5.com ticket = &tickets->tickets[i]; 6701942Sa.suvorov@f5.com 6711942Sa.suvorov@f5.com i++; 6721942Sa.suvorov@f5.com 6732077Salx.manpages@gmail.com member = nxt_conf_get_array_element_or_itself(tickets_conf, count - i); 6742077Salx.manpages@gmail.com if (member == NULL) { 6752077Salx.manpages@gmail.com break; 6761942Sa.suvorov@f5.com } 6771942Sa.suvorov@f5.com 6781942Sa.suvorov@f5.com nxt_conf_get_string(member, &value); 6791942Sa.suvorov@f5.com 6801975Svbart@nginx.com len = nxt_base64_decode(buf, value.start, value.length); 6811942Sa.suvorov@f5.com 6821952Svbart@nginx.com nxt_memcpy(ticket->name, buf, 16); 6831952Svbart@nginx.com 6841975Svbart@nginx.com if (len == 48) { 6851942Sa.suvorov@f5.com nxt_memcpy(ticket->aes_key, buf + 16, 16); 6861942Sa.suvorov@f5.com nxt_memcpy(ticket->hmac_key, buf + 32, 16); 6871952Svbart@nginx.com ticket->size = 16; 6881942Sa.suvorov@f5.com 6891942Sa.suvorov@f5.com } else { 6901942Sa.suvorov@f5.com nxt_memcpy(ticket->hmac_key, buf + 16, 32); 6911942Sa.suvorov@f5.com nxt_memcpy(ticket->aes_key, buf + 48, 32); 6921952Svbart@nginx.com ticket->size = 32; 6931942Sa.suvorov@f5.com } 6941942Sa.suvorov@f5.com 6951942Sa.suvorov@f5.com } while (i < count); 6961942Sa.suvorov@f5.com 6971942Sa.suvorov@f5.com if (SSL_CTX_set_tlsext_ticket_key_cb(ctx, nxt_tls_ticket_key_callback) 6981942Sa.suvorov@f5.com == 0) 6991942Sa.suvorov@f5.com { 7001942Sa.suvorov@f5.com nxt_openssl_log_error(task, NXT_LOG_ALERT, 7011942Sa.suvorov@f5.com "Unit was built with Session Tickets support, however, " 7021942Sa.suvorov@f5.com "now it is linked dynamically to an OpenSSL library " 7031942Sa.suvorov@f5.com "which has no tlsext support, therefore Session Tickets " 7041942Sa.suvorov@f5.com "are not available"); 7051942Sa.suvorov@f5.com 7061942Sa.suvorov@f5.com return NXT_ERROR; 7071942Sa.suvorov@f5.com } 7081942Sa.suvorov@f5.com 7091942Sa.suvorov@f5.com return NXT_OK; 7101942Sa.suvorov@f5.com 7111942Sa.suvorov@f5.com #else 7121942Sa.suvorov@f5.com nxt_alert(task, "Setting custom session ticket keys is not supported with " 7131942Sa.suvorov@f5.com "this version of OpenSSL library"); 7141942Sa.suvorov@f5.com 7151942Sa.suvorov@f5.com return NXT_ERROR; 7161942Sa.suvorov@f5.com 7171942Sa.suvorov@f5.com #endif 7181942Sa.suvorov@f5.com 7191942Sa.suvorov@f5.com no_ticket: 7201942Sa.suvorov@f5.com 7211942Sa.suvorov@f5.com SSL_CTX_set_options(ctx, SSL_OP_NO_TICKET); 7221942Sa.suvorov@f5.com 7231942Sa.suvorov@f5.com return NXT_OK; 7241942Sa.suvorov@f5.com } 7251942Sa.suvorov@f5.com 7261942Sa.suvorov@f5.com 7271942Sa.suvorov@f5.com #ifdef SSL_CTRL_SET_TLSEXT_TICKET_KEY_CB 7281942Sa.suvorov@f5.com 7291942Sa.suvorov@f5.com static int 7301942Sa.suvorov@f5.com nxt_tls_ticket_key_callback(SSL *s, unsigned char *name, unsigned char *iv, 7311942Sa.suvorov@f5.com EVP_CIPHER_CTX *ectx, HMAC_CTX *hctx, int enc) 7321942Sa.suvorov@f5.com { 7331942Sa.suvorov@f5.com nxt_uint_t i; 7341942Sa.suvorov@f5.com nxt_conn_t *c; 7351942Sa.suvorov@f5.com const EVP_MD *digest; 7361942Sa.suvorov@f5.com const EVP_CIPHER *cipher; 7371942Sa.suvorov@f5.com nxt_tls_ticket_t *ticket; 7381942Sa.suvorov@f5.com nxt_openssl_conn_t *tls; 7391942Sa.suvorov@f5.com 7401942Sa.suvorov@f5.com c = SSL_get_ex_data(s, nxt_openssl_connection_index); 7411942Sa.suvorov@f5.com 7421942Sa.suvorov@f5.com if (nxt_slow_path(c == NULL)) { 7431942Sa.suvorov@f5.com nxt_thread_log_alert("SSL_get_ex_data() failed"); 7441942Sa.suvorov@f5.com return -1; 7451942Sa.suvorov@f5.com } 7461942Sa.suvorov@f5.com 7471942Sa.suvorov@f5.com tls = c->u.tls; 7481942Sa.suvorov@f5.com ticket = tls->conf->tickets->tickets; 7491942Sa.suvorov@f5.com 7501952Svbart@nginx.com i = 0; 7511942Sa.suvorov@f5.com 7521942Sa.suvorov@f5.com if (enc == 1) { 7531942Sa.suvorov@f5.com /* encrypt session ticket */ 7541942Sa.suvorov@f5.com 7551942Sa.suvorov@f5.com nxt_debug(c->socket.task, "TLS session ticket encrypt"); 7561942Sa.suvorov@f5.com 7571952Svbart@nginx.com cipher = (ticket[0].size == 16) ? EVP_aes_128_cbc() : EVP_aes_256_cbc(); 7581942Sa.suvorov@f5.com 7591942Sa.suvorov@f5.com if (RAND_bytes(iv, EVP_CIPHER_iv_length(cipher)) != 1) { 7601942Sa.suvorov@f5.com nxt_openssl_log_error(c->socket.task, NXT_LOG_ALERT, 7611942Sa.suvorov@f5.com "RAND_bytes() failed"); 7621942Sa.suvorov@f5.com return -1; 7631942Sa.suvorov@f5.com } 7641942Sa.suvorov@f5.com 7651942Sa.suvorov@f5.com nxt_memcpy(name, ticket[0].name, 16); 7661942Sa.suvorov@f5.com 7671967Sartem.konev@nginx.com if (EVP_EncryptInit_ex(ectx, cipher, NULL, ticket[0].aes_key, iv) != 1) 7681967Sartem.konev@nginx.com { 7691967Sartem.konev@nginx.com nxt_openssl_log_error(c->socket.task, NXT_LOG_ALERT, 7701967Sartem.konev@nginx.com "EVP_EncryptInit_ex() failed"); 7711967Sartem.konev@nginx.com return -1; 7721967Sartem.konev@nginx.com } 7731967Sartem.konev@nginx.com 7741942Sa.suvorov@f5.com } else { 7751942Sa.suvorov@f5.com /* decrypt session ticket */ 7761942Sa.suvorov@f5.com 7771952Svbart@nginx.com do { 7781942Sa.suvorov@f5.com if (nxt_memcmp(name, ticket[i].name, 16) == 0) { 7791942Sa.suvorov@f5.com goto found; 7801942Sa.suvorov@f5.com } 7811952Svbart@nginx.com 7821952Svbart@nginx.com } while (++i < tls->conf->tickets->count); 7831942Sa.suvorov@f5.com 7841942Sa.suvorov@f5.com nxt_debug(c->socket.task, "TLS session ticket decrypt, key not found"); 7851942Sa.suvorov@f5.com 7861942Sa.suvorov@f5.com return 0; 7871942Sa.suvorov@f5.com 7881942Sa.suvorov@f5.com found: 7891942Sa.suvorov@f5.com 7901942Sa.suvorov@f5.com nxt_debug(c->socket.task, 7911942Sa.suvorov@f5.com "TLS session ticket decrypt, key number: \"%d\"", i); 7921942Sa.suvorov@f5.com 7931952Svbart@nginx.com enc = (i == 0) ? 1 : 2 /* renew */; 7941952Svbart@nginx.com 7951952Svbart@nginx.com cipher = (ticket[i].size == 16) ? EVP_aes_128_cbc() : EVP_aes_256_cbc(); 7961942Sa.suvorov@f5.com 7971967Sartem.konev@nginx.com if (EVP_DecryptInit_ex(ectx, cipher, NULL, ticket[i].aes_key, iv) != 1) 7981967Sartem.konev@nginx.com { 7991967Sartem.konev@nginx.com nxt_openssl_log_error(c->socket.task, NXT_LOG_ALERT, 8001967Sartem.konev@nginx.com "EVP_DecryptInit_ex() failed"); 8011967Sartem.konev@nginx.com return -1; 8021967Sartem.konev@nginx.com } 8031952Svbart@nginx.com } 8041942Sa.suvorov@f5.com 8051952Svbart@nginx.com #ifdef OPENSSL_NO_SHA256 8061952Svbart@nginx.com digest = EVP_sha1(); 8071952Svbart@nginx.com #else 8081952Svbart@nginx.com digest = EVP_sha256(); 8091952Svbart@nginx.com #endif 8101942Sa.suvorov@f5.com 8111952Svbart@nginx.com if (HMAC_Init_ex(hctx, ticket[i].hmac_key, ticket[i].size, digest, NULL) 8121952Svbart@nginx.com != 1) 8131952Svbart@nginx.com { 8141952Svbart@nginx.com nxt_openssl_log_error(c->socket.task, NXT_LOG_ALERT, 8151952Svbart@nginx.com "HMAC_Init_ex() failed"); 8161952Svbart@nginx.com return -1; 8171952Svbart@nginx.com } 8181942Sa.suvorov@f5.com 8191952Svbart@nginx.com return enc; 8201942Sa.suvorov@f5.com } 8211942Sa.suvorov@f5.com 8221942Sa.suvorov@f5.com #endif /* SSL_CTRL_SET_TLSEXT_TICKET_KEY_CB */ 8231942Sa.suvorov@f5.com 8241942Sa.suvorov@f5.com #endif /* NXT_HAVE_OPENSSL_TLSEXT */ 8251942Sa.suvorov@f5.com 8261885Sa.suvorov@f5.com 8271920Sa.suvorov@f5.com static void 8281920Sa.suvorov@f5.com nxt_ssl_session_cache(SSL_CTX *ctx, size_t cache_size, time_t timeout) 8291920Sa.suvorov@f5.com { 8301920Sa.suvorov@f5.com if (cache_size == 0) { 8311920Sa.suvorov@f5.com SSL_CTX_set_session_cache_mode(ctx, SSL_SESS_CACHE_OFF); 8321920Sa.suvorov@f5.com return; 8331920Sa.suvorov@f5.com } 8341920Sa.suvorov@f5.com 8351920Sa.suvorov@f5.com SSL_CTX_set_session_cache_mode(ctx, SSL_SESS_CACHE_SERVER); 8361920Sa.suvorov@f5.com 8371920Sa.suvorov@f5.com SSL_CTX_sess_set_cache_size(ctx, cache_size); 8381920Sa.suvorov@f5.com 8391920Sa.suvorov@f5.com SSL_CTX_set_timeout(ctx, (long) timeout); 8401920Sa.suvorov@f5.com } 8411920Sa.suvorov@f5.com 8421920Sa.suvorov@f5.com 8431828Sa.suvorov@f5.com static nxt_uint_t 8441828Sa.suvorov@f5.com nxt_openssl_cert_get_names(nxt_task_t *task, X509 *cert, nxt_tls_conf_t *conf, 8451828Sa.suvorov@f5.com nxt_mp_t *mp) 8461828Sa.suvorov@f5.com { 8471828Sa.suvorov@f5.com int len; 8481828Sa.suvorov@f5.com nxt_str_t domain, str; 8491828Sa.suvorov@f5.com X509_NAME *x509_name; 8501828Sa.suvorov@f5.com nxt_uint_t i, n; 8511828Sa.suvorov@f5.com GENERAL_NAME *name; 8521828Sa.suvorov@f5.com nxt_tls_bundle_conf_t *bundle; 8531828Sa.suvorov@f5.com STACK_OF(GENERAL_NAME) *alt_names; 8541828Sa.suvorov@f5.com nxt_tls_bundle_hash_item_t *item; 8551828Sa.suvorov@f5.com 8561828Sa.suvorov@f5.com bundle = conf->bundle; 8571828Sa.suvorov@f5.com 8581828Sa.suvorov@f5.com alt_names = X509_get_ext_d2i(cert, NID_subject_alt_name, NULL, NULL); 8591828Sa.suvorov@f5.com 8601828Sa.suvorov@f5.com if (alt_names != NULL) { 8611828Sa.suvorov@f5.com n = sk_GENERAL_NAME_num(alt_names); 8621828Sa.suvorov@f5.com 8631828Sa.suvorov@f5.com for (i = 0; i != n; i++) { 8641828Sa.suvorov@f5.com name = sk_GENERAL_NAME_value(alt_names, i); 8651828Sa.suvorov@f5.com 8661828Sa.suvorov@f5.com if (name->type != GEN_DNS) { 8671828Sa.suvorov@f5.com continue; 8681828Sa.suvorov@f5.com } 8691828Sa.suvorov@f5.com 8701828Sa.suvorov@f5.com str.length = ASN1_STRING_length(name->d.dNSName); 8711828Sa.suvorov@f5.com #if OPENSSL_VERSION_NUMBER > 0x10100000L 8721828Sa.suvorov@f5.com str.start = (u_char *) ASN1_STRING_get0_data(name->d.dNSName); 8731828Sa.suvorov@f5.com #else 8741828Sa.suvorov@f5.com str.start = ASN1_STRING_data(name->d.dNSName); 8751828Sa.suvorov@f5.com #endif 8761828Sa.suvorov@f5.com 8771828Sa.suvorov@f5.com domain.start = nxt_mp_nget(mp, str.length); 8781828Sa.suvorov@f5.com if (nxt_slow_path(domain.start == NULL)) { 8791828Sa.suvorov@f5.com goto fail; 8801828Sa.suvorov@f5.com } 8811828Sa.suvorov@f5.com 8821828Sa.suvorov@f5.com domain.length = str.length; 8831828Sa.suvorov@f5.com nxt_memcpy_lowcase(domain.start, str.start, str.length); 8841828Sa.suvorov@f5.com 8851828Sa.suvorov@f5.com item = nxt_mp_get(mp, sizeof(nxt_tls_bundle_hash_item_t)); 8861828Sa.suvorov@f5.com if (nxt_slow_path(item == NULL)) { 8871828Sa.suvorov@f5.com goto fail; 8881828Sa.suvorov@f5.com } 8891828Sa.suvorov@f5.com 8901828Sa.suvorov@f5.com item->name = domain; 8911828Sa.suvorov@f5.com item->bundle = bundle; 8921828Sa.suvorov@f5.com 8931828Sa.suvorov@f5.com if (nxt_openssl_bundle_hash_insert(task, &conf->bundle_hash, 8941828Sa.suvorov@f5.com item, mp) 8951828Sa.suvorov@f5.com == NXT_ERROR) 8961828Sa.suvorov@f5.com { 8971828Sa.suvorov@f5.com goto fail; 8981828Sa.suvorov@f5.com } 8991828Sa.suvorov@f5.com } 9001828Sa.suvorov@f5.com 9011828Sa.suvorov@f5.com sk_GENERAL_NAME_pop_free(alt_names, GENERAL_NAME_free); 9021828Sa.suvorov@f5.com 9031828Sa.suvorov@f5.com } else { 9041828Sa.suvorov@f5.com x509_name = X509_get_subject_name(cert); 9051828Sa.suvorov@f5.com len = X509_NAME_get_text_by_NID(x509_name, NID_commonName, 9061828Sa.suvorov@f5.com NULL, 0); 9071828Sa.suvorov@f5.com if (len <= 0) { 9081828Sa.suvorov@f5.com nxt_log(task, NXT_LOG_WARN, "certificate \"%V\" has neither " 9091885Sa.suvorov@f5.com "Subject Alternative Name nor Common Name", &bundle->name); 9101828Sa.suvorov@f5.com return NXT_OK; 9111828Sa.suvorov@f5.com } 9121828Sa.suvorov@f5.com 9131828Sa.suvorov@f5.com domain.start = nxt_mp_nget(mp, len + 1); 9141828Sa.suvorov@f5.com if (nxt_slow_path(domain.start == NULL)) { 9151828Sa.suvorov@f5.com return NXT_ERROR; 9161828Sa.suvorov@f5.com } 9171828Sa.suvorov@f5.com 9181828Sa.suvorov@f5.com domain.length = X509_NAME_get_text_by_NID(x509_name, NID_commonName, 9191828Sa.suvorov@f5.com (char *) domain.start, 9201828Sa.suvorov@f5.com len + 1); 9211828Sa.suvorov@f5.com nxt_memcpy_lowcase(domain.start, domain.start, domain.length); 9221828Sa.suvorov@f5.com 9231828Sa.suvorov@f5.com item = nxt_mp_get(mp, sizeof(nxt_tls_bundle_hash_item_t)); 9241828Sa.suvorov@f5.com if (nxt_slow_path(item == NULL)) { 9251828Sa.suvorov@f5.com return NXT_ERROR; 9261828Sa.suvorov@f5.com } 9271828Sa.suvorov@f5.com 9281828Sa.suvorov@f5.com item->name = domain; 9291828Sa.suvorov@f5.com item->bundle = bundle; 9301828Sa.suvorov@f5.com 9311828Sa.suvorov@f5.com if (nxt_openssl_bundle_hash_insert(task, &conf->bundle_hash, item, 9321828Sa.suvorov@f5.com mp) 9331828Sa.suvorov@f5.com == NXT_ERROR) 9341828Sa.suvorov@f5.com { 9351828Sa.suvorov@f5.com return NXT_ERROR; 9361828Sa.suvorov@f5.com } 9371828Sa.suvorov@f5.com } 9381828Sa.suvorov@f5.com 9391828Sa.suvorov@f5.com return NXT_OK; 9401828Sa.suvorov@f5.com 9411828Sa.suvorov@f5.com fail: 9421828Sa.suvorov@f5.com 9431828Sa.suvorov@f5.com sk_GENERAL_NAME_pop_free(alt_names, GENERAL_NAME_free); 9441828Sa.suvorov@f5.com 9451828Sa.suvorov@f5.com return NXT_ERROR; 9461828Sa.suvorov@f5.com } 9471828Sa.suvorov@f5.com 9481828Sa.suvorov@f5.com 9491828Sa.suvorov@f5.com static const nxt_lvlhsh_proto_t nxt_openssl_bundle_hash_proto 9501828Sa.suvorov@f5.com nxt_aligned(64) = 9511828Sa.suvorov@f5.com { 9521828Sa.suvorov@f5.com NXT_LVLHSH_DEFAULT, 9531828Sa.suvorov@f5.com nxt_openssl_bundle_hash_test, 9541828Sa.suvorov@f5.com nxt_mp_lvlhsh_alloc, 9551828Sa.suvorov@f5.com nxt_mp_lvlhsh_free, 9561828Sa.suvorov@f5.com }; 9571828Sa.suvorov@f5.com 9581828Sa.suvorov@f5.com 9591828Sa.suvorov@f5.com static nxt_int_t 9601828Sa.suvorov@f5.com nxt_openssl_bundle_hash_test(nxt_lvlhsh_query_t *lhq, void *data) 9611828Sa.suvorov@f5.com { 9621828Sa.suvorov@f5.com nxt_tls_bundle_hash_item_t *item; 9631828Sa.suvorov@f5.com 9641828Sa.suvorov@f5.com item = data; 9651828Sa.suvorov@f5.com 9661828Sa.suvorov@f5.com return nxt_strstr_eq(&lhq->key, &item->name) ? NXT_OK : NXT_DECLINED; 9671828Sa.suvorov@f5.com } 9681828Sa.suvorov@f5.com 9691828Sa.suvorov@f5.com 9701828Sa.suvorov@f5.com static nxt_int_t 9711828Sa.suvorov@f5.com nxt_openssl_bundle_hash_insert(nxt_task_t *task, nxt_lvlhsh_t *lvlhsh, 9721828Sa.suvorov@f5.com nxt_tls_bundle_hash_item_t *item, nxt_mp_t *mp) 9731828Sa.suvorov@f5.com { 9741828Sa.suvorov@f5.com nxt_str_t str; 9751828Sa.suvorov@f5.com nxt_int_t ret; 9761828Sa.suvorov@f5.com&nbs