xref: /unit/src/nxt_openssl.c (revision 1942)
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>
14*1942Sa.suvorov@f5.com #include <openssl/bio.h>
15*1942Sa.suvorov@f5.com #include <openssl/evp.h>
160Sigor@sysoev.ru 
170Sigor@sysoev.ru 
180Sigor@sysoev.ru typedef struct {
191828Sa.suvorov@f5.com     SSL             *session;
201828Sa.suvorov@f5.com     nxt_conn_t      *conn;
210Sigor@sysoev.ru 
221828Sa.suvorov@f5.com     int             ssl_error;
231828Sa.suvorov@f5.com     uint8_t         times;      /* 2 bits */
241828Sa.suvorov@f5.com     uint8_t         handshake;  /* 1 bit  */
250Sigor@sysoev.ru 
261828Sa.suvorov@f5.com     nxt_tls_conf_t  *conf;
271828Sa.suvorov@f5.com     nxt_buf_mem_t   buffer;
280Sigor@sysoev.ru } nxt_openssl_conn_t;
290Sigor@sysoev.ru 
300Sigor@sysoev.ru 
31771Sigor@sysoev.ru typedef enum {
32771Sigor@sysoev.ru     NXT_OPENSSL_HANDSHAKE = 0,
33771Sigor@sysoev.ru     NXT_OPENSSL_READ,
34771Sigor@sysoev.ru     NXT_OPENSSL_WRITE,
35771Sigor@sysoev.ru     NXT_OPENSSL_SHUTDOWN,
36771Sigor@sysoev.ru } nxt_openssl_io_t;
37771Sigor@sysoev.ru 
380Sigor@sysoev.ru 
39771Sigor@sysoev.ru static nxt_int_t nxt_openssl_library_init(nxt_task_t *task);
40771Sigor@sysoev.ru static void nxt_openssl_library_free(nxt_task_t *task);
41771Sigor@sysoev.ru #if OPENSSL_VERSION_NUMBER < 0x10100004L
42771Sigor@sysoev.ru static nxt_int_t nxt_openssl_locks_init(void);
43771Sigor@sysoev.ru static void nxt_openssl_lock(int mode, int type, const char *file, int line);
44771Sigor@sysoev.ru static unsigned long nxt_openssl_thread_id(void);
45771Sigor@sysoev.ru static void nxt_openssl_locks_free(void);
46771Sigor@sysoev.ru #endif
471920Sa.suvorov@f5.com static nxt_int_t nxt_openssl_server_init(nxt_task_t *task, nxt_mp_t *mp,
481920Sa.suvorov@f5.com     nxt_tls_init_t *tls_init, nxt_bool_t last);
491828Sa.suvorov@f5.com static nxt_int_t nxt_openssl_chain_file(nxt_task_t *task, SSL_CTX *ctx,
501828Sa.suvorov@f5.com     nxt_tls_conf_t *conf, nxt_mp_t *mp, nxt_bool_t single);
511885Sa.suvorov@f5.com #if (NXT_HAVE_OPENSSL_CONF_CMD)
521885Sa.suvorov@f5.com static nxt_int_t nxt_ssl_conf_commands(nxt_task_t *task, SSL_CTX *ctx,
531885Sa.suvorov@f5.com     nxt_conf_value_t *value, nxt_mp_t *mp);
541885Sa.suvorov@f5.com #endif
55*1942Sa.suvorov@f5.com #if (NXT_HAVE_OPENSSL_TLSEXT)
56*1942Sa.suvorov@f5.com static nxt_int_t nxt_tls_ticket_keys(nxt_task_t *task, SSL_CTX *ctx,
57*1942Sa.suvorov@f5.com     nxt_tls_init_t *tls_init, nxt_mp_t *mp);
58*1942Sa.suvorov@f5.com static int nxt_tls_ticket_key_callback(SSL *s, unsigned char *name,
59*1942Sa.suvorov@f5.com     unsigned char *iv, EVP_CIPHER_CTX *ectx,HMAC_CTX *hctx, int enc);
60*1942Sa.suvorov@f5.com #endif
611920Sa.suvorov@f5.com static void nxt_ssl_session_cache(SSL_CTX *ctx, size_t cache_size,
621920Sa.suvorov@f5.com     time_t timeout);
631828Sa.suvorov@f5.com static nxt_uint_t nxt_openssl_cert_get_names(nxt_task_t *task, X509 *cert,
641828Sa.suvorov@f5.com     nxt_tls_conf_t *conf, nxt_mp_t *mp);
651828Sa.suvorov@f5.com static nxt_int_t nxt_openssl_bundle_hash_test(nxt_lvlhsh_query_t *lhq,
661828Sa.suvorov@f5.com     void *data);
671828Sa.suvorov@f5.com static nxt_int_t nxt_openssl_bundle_hash_insert(nxt_task_t *task,
681828Sa.suvorov@f5.com     nxt_lvlhsh_t *lvlhsh, nxt_tls_bundle_hash_item_t *item, nxt_mp_t * mp);
691828Sa.suvorov@f5.com static nxt_int_t nxt_openssl_servername(SSL *s, int *ad, void *arg);
701828Sa.suvorov@f5.com static nxt_tls_bundle_conf_t *nxt_openssl_find_ctx(nxt_tls_conf_t *conf,
711828Sa.suvorov@f5.com     nxt_str_t *sn);
72771Sigor@sysoev.ru static void nxt_openssl_server_free(nxt_task_t *task, nxt_tls_conf_t *conf);
73771Sigor@sysoev.ru static void nxt_openssl_conn_init(nxt_task_t *task, nxt_tls_conf_t *conf,
7462Sigor@sysoev.ru     nxt_conn_t *c);
751Sigor@sysoev.ru static void nxt_openssl_conn_handshake(nxt_task_t *task, void *obj, void *data);
76771Sigor@sysoev.ru static ssize_t nxt_openssl_conn_io_recvbuf(nxt_conn_t *c, nxt_buf_t *b);
77771Sigor@sysoev.ru static ssize_t nxt_openssl_conn_io_sendbuf(nxt_task_t *task, nxt_sendbuf_t *sb);
78771Sigor@sysoev.ru static ssize_t nxt_openssl_conn_io_send(nxt_task_t *task, nxt_sendbuf_t *sb,
79771Sigor@sysoev.ru     void *buf, size_t size);
801Sigor@sysoev.ru static void nxt_openssl_conn_io_shutdown(nxt_task_t *task, void *obj,
810Sigor@sysoev.ru     void *data);
82771Sigor@sysoev.ru static nxt_int_t nxt_openssl_conn_test_error(nxt_task_t *task, nxt_conn_t *c,
83771Sigor@sysoev.ru     int ret, nxt_err_t sys_err, nxt_openssl_io_t io);
841884Sa.suvorov@f5.com static void nxt_openssl_conn_io_shutdown_timeout(nxt_task_t *task, void *obj,
851884Sa.suvorov@f5.com     void *data);
86771Sigor@sysoev.ru static void nxt_cdecl nxt_openssl_conn_error(nxt_task_t *task,
87771Sigor@sysoev.ru     nxt_err_t err, const char *fmt, ...);
88771Sigor@sysoev.ru static nxt_uint_t nxt_openssl_log_error_level(nxt_err_t err);
890Sigor@sysoev.ru 
900Sigor@sysoev.ru 
91771Sigor@sysoev.ru const nxt_tls_lib_t  nxt_openssl_lib = {
92771Sigor@sysoev.ru     .library_init = nxt_openssl_library_init,
93771Sigor@sysoev.ru     .library_free = nxt_openssl_library_free,
94771Sigor@sysoev.ru 
95771Sigor@sysoev.ru     .server_init = nxt_openssl_server_init,
96771Sigor@sysoev.ru     .server_free = nxt_openssl_server_free,
970Sigor@sysoev.ru };
980Sigor@sysoev.ru 
990Sigor@sysoev.ru 
10062Sigor@sysoev.ru static nxt_conn_io_t  nxt_openssl_conn_io = {
101771Sigor@sysoev.ru     .read = nxt_conn_io_read,
102771Sigor@sysoev.ru     .recvbuf = nxt_openssl_conn_io_recvbuf,
1030Sigor@sysoev.ru 
104771Sigor@sysoev.ru     .write = nxt_conn_io_write,
105771Sigor@sysoev.ru     .sendbuf = nxt_openssl_conn_io_sendbuf,
1060Sigor@sysoev.ru 
107771Sigor@sysoev.ru     .shutdown = nxt_openssl_conn_io_shutdown,
1080Sigor@sysoev.ru };
1090Sigor@sysoev.ru 
1100Sigor@sysoev.ru 
1110Sigor@sysoev.ru static long  nxt_openssl_version;
1120Sigor@sysoev.ru static int   nxt_openssl_connection_index;
1130Sigor@sysoev.ru 
1140Sigor@sysoev.ru 
1150Sigor@sysoev.ru static nxt_int_t
116771Sigor@sysoev.ru nxt_openssl_library_init(nxt_task_t *task)
1170Sigor@sysoev.ru {
1180Sigor@sysoev.ru     int  index;
1190Sigor@sysoev.ru 
1200Sigor@sysoev.ru     if (nxt_fast_path(nxt_openssl_version != 0)) {
1210Sigor@sysoev.ru         return NXT_OK;
1220Sigor@sysoev.ru     }
1230Sigor@sysoev.ru 
124771Sigor@sysoev.ru #if OPENSSL_VERSION_NUMBER >= 0x10100003L
125771Sigor@sysoev.ru 
126771Sigor@sysoev.ru     OPENSSL_init_ssl(OPENSSL_INIT_LOAD_CONFIG, NULL);
1270Sigor@sysoev.ru 
128771Sigor@sysoev.ru #else
129771Sigor@sysoev.ru     {
130771Sigor@sysoev.ru         nxt_int_t  ret;
131771Sigor@sysoev.ru 
132771Sigor@sysoev.ru         SSL_load_error_strings();
133771Sigor@sysoev.ru 
134771Sigor@sysoev.ru         OPENSSL_config(NULL);
1350Sigor@sysoev.ru 
136771Sigor@sysoev.ru         /*
137771Sigor@sysoev.ru          * SSL_library_init(3):
138771Sigor@sysoev.ru          *
139771Sigor@sysoev.ru          *   SSL_library_init() always returns "1",
140771Sigor@sysoev.ru          *   so it is safe to discard the return value.
141771Sigor@sysoev.ru          */
142771Sigor@sysoev.ru         (void) SSL_library_init();
143771Sigor@sysoev.ru 
144771Sigor@sysoev.ru         ret = nxt_openssl_locks_init();
145771Sigor@sysoev.ru         if (nxt_slow_path(ret != NXT_OK)) {
146771Sigor@sysoev.ru             return ret;
147771Sigor@sysoev.ru         }
148771Sigor@sysoev.ru     }
149771Sigor@sysoev.ru 
150771Sigor@sysoev.ru #endif
1510Sigor@sysoev.ru 
1520Sigor@sysoev.ru     nxt_openssl_version = SSLeay();
1530Sigor@sysoev.ru 
154771Sigor@sysoev.ru     nxt_log(task, NXT_LOG_INFO, "%s, %xl",
155771Sigor@sysoev.ru             SSLeay_version(SSLEAY_VERSION), nxt_openssl_version);
1560Sigor@sysoev.ru 
1570Sigor@sysoev.ru #ifndef SSL_OP_NO_COMPRESSION
1580Sigor@sysoev.ru     {
1590Sigor@sysoev.ru         /*
1600Sigor@sysoev.ru          * Disable gzip compression in OpenSSL prior to 1.0.0
1610Sigor@sysoev.ru          * version, this saves about 522K per connection.
1620Sigor@sysoev.ru          */
1630Sigor@sysoev.ru         int                 n;
1640Sigor@sysoev.ru         STACK_OF(SSL_COMP)  *ssl_comp_methods;
1650Sigor@sysoev.ru 
1660Sigor@sysoev.ru         ssl_comp_methods = SSL_COMP_get_compression_methods();
1670Sigor@sysoev.ru 
1680Sigor@sysoev.ru         for (n = sk_SSL_COMP_num(ssl_comp_methods); n != 0; n--) {
1690Sigor@sysoev.ru             (void) sk_SSL_COMP_pop(ssl_comp_methods);
1700Sigor@sysoev.ru         }
1710Sigor@sysoev.ru     }
1720Sigor@sysoev.ru #endif
1730Sigor@sysoev.ru 
1740Sigor@sysoev.ru     index = SSL_get_ex_new_index(0, NULL, NULL, NULL, NULL);
1750Sigor@sysoev.ru 
1760Sigor@sysoev.ru     if (index == -1) {
177771Sigor@sysoev.ru         nxt_openssl_log_error(task, NXT_LOG_ALERT,
1780Sigor@sysoev.ru                               "SSL_get_ex_new_index() failed");
1790Sigor@sysoev.ru         return NXT_ERROR;
1800Sigor@sysoev.ru     }
1810Sigor@sysoev.ru 
1820Sigor@sysoev.ru     nxt_openssl_connection_index = index;
1830Sigor@sysoev.ru 
1840Sigor@sysoev.ru     return NXT_OK;
1850Sigor@sysoev.ru }
1860Sigor@sysoev.ru 
1870Sigor@sysoev.ru 
188771Sigor@sysoev.ru #if OPENSSL_VERSION_NUMBER >= 0x10100003L
189771Sigor@sysoev.ru 
190771Sigor@sysoev.ru static void
191771Sigor@sysoev.ru nxt_openssl_library_free(nxt_task_t *task)
192771Sigor@sysoev.ru {
193771Sigor@sysoev.ru }
194771Sigor@sysoev.ru 
195771Sigor@sysoev.ru #else
196771Sigor@sysoev.ru 
197771Sigor@sysoev.ru static nxt_thread_mutex_t  *nxt_openssl_locks;
198771Sigor@sysoev.ru 
1990Sigor@sysoev.ru static nxt_int_t
200771Sigor@sysoev.ru nxt_openssl_locks_init(void)
201771Sigor@sysoev.ru {
202771Sigor@sysoev.ru     int        i, n;
203771Sigor@sysoev.ru     nxt_int_t  ret;
204771Sigor@sysoev.ru 
205771Sigor@sysoev.ru     n = CRYPTO_num_locks();
206771Sigor@sysoev.ru 
207771Sigor@sysoev.ru     nxt_openssl_locks = OPENSSL_malloc(n * sizeof(nxt_thread_mutex_t));
208771Sigor@sysoev.ru     if (nxt_slow_path(nxt_openssl_locks == NULL)) {
209771Sigor@sysoev.ru         return NXT_ERROR;
210771Sigor@sysoev.ru     }
211771Sigor@sysoev.ru 
212771Sigor@sysoev.ru     for (i = 0; i < n; i++) {
213771Sigor@sysoev.ru         ret = nxt_thread_mutex_create(&nxt_openssl_locks[i]);
214771Sigor@sysoev.ru         if (nxt_slow_path(ret != NXT_OK)) {
215771Sigor@sysoev.ru             return ret;
216771Sigor@sysoev.ru         }
217771Sigor@sysoev.ru     }
218771Sigor@sysoev.ru 
219771Sigor@sysoev.ru     CRYPTO_set_locking_callback(nxt_openssl_lock);
220771Sigor@sysoev.ru 
221771Sigor@sysoev.ru     CRYPTO_set_id_callback(nxt_openssl_thread_id);
222771Sigor@sysoev.ru 
223771Sigor@sysoev.ru     return NXT_OK;
224771Sigor@sysoev.ru }
225771Sigor@sysoev.ru 
226771Sigor@sysoev.ru 
227771Sigor@sysoev.ru static void
228771Sigor@sysoev.ru nxt_openssl_lock(int mode, int type, const char *file, int line)
229771Sigor@sysoev.ru {
230771Sigor@sysoev.ru     nxt_thread_mutex_t  *lock;
231771Sigor@sysoev.ru 
232771Sigor@sysoev.ru     lock = &nxt_openssl_locks[type];
233771Sigor@sysoev.ru 
234771Sigor@sysoev.ru     if ((mode & CRYPTO_LOCK) != 0) {
235771Sigor@sysoev.ru         (void) nxt_thread_mutex_lock(lock);
236771Sigor@sysoev.ru 
237771Sigor@sysoev.ru     } else {
238771Sigor@sysoev.ru         (void) nxt_thread_mutex_unlock(lock);
239771Sigor@sysoev.ru     }
240771Sigor@sysoev.ru }
241771Sigor@sysoev.ru 
242771Sigor@sysoev.ru 
243771Sigor@sysoev.ru static u_long
244771Sigor@sysoev.ru nxt_openssl_thread_id(void)
245771Sigor@sysoev.ru {
246771Sigor@sysoev.ru     return (u_long) nxt_thread_handle();
247771Sigor@sysoev.ru }
248771Sigor@sysoev.ru 
249771Sigor@sysoev.ru 
250771Sigor@sysoev.ru static void
251771Sigor@sysoev.ru nxt_openssl_library_free(nxt_task_t *task)
252771Sigor@sysoev.ru {
253771Sigor@sysoev.ru     nxt_openssl_locks_free();
254771Sigor@sysoev.ru }
255771Sigor@sysoev.ru 
256771Sigor@sysoev.ru 
257771Sigor@sysoev.ru static void
258771Sigor@sysoev.ru nxt_openssl_locks_free(void)
259771Sigor@sysoev.ru {
260771Sigor@sysoev.ru     int  i, n;
261771Sigor@sysoev.ru 
262771Sigor@sysoev.ru     n = CRYPTO_num_locks();
263771Sigor@sysoev.ru 
264771Sigor@sysoev.ru     CRYPTO_set_locking_callback(NULL);
265771Sigor@sysoev.ru 
266771Sigor@sysoev.ru     for (i = 0; i < n; i++) {
267771Sigor@sysoev.ru         nxt_thread_mutex_destroy(&nxt_openssl_locks[i]);
268771Sigor@sysoev.ru     }
269771Sigor@sysoev.ru 
270771Sigor@sysoev.ru     OPENSSL_free(nxt_openssl_locks);
271771Sigor@sysoev.ru }
272771Sigor@sysoev.ru 
273771Sigor@sysoev.ru #endif
274771Sigor@sysoev.ru 
275771Sigor@sysoev.ru 
276771Sigor@sysoev.ru static nxt_int_t
2771920Sa.suvorov@f5.com nxt_openssl_server_init(nxt_task_t *task, nxt_mp_t *mp,
2781920Sa.suvorov@f5.com     nxt_tls_init_t *tls_init, nxt_bool_t last)
2790Sigor@sysoev.ru {
2801828Sa.suvorov@f5.com     SSL_CTX                *ctx;
2811828Sa.suvorov@f5.com     const char             *ciphers, *ca_certificate;
2821920Sa.suvorov@f5.com     nxt_tls_conf_t         *conf;
2831828Sa.suvorov@f5.com     STACK_OF(X509_NAME)    *list;
2841828Sa.suvorov@f5.com     nxt_tls_bundle_conf_t  *bundle;
2850Sigor@sysoev.ru 
2860Sigor@sysoev.ru     ctx = SSL_CTX_new(SSLv23_server_method());
2870Sigor@sysoev.ru     if (ctx == NULL) {
288771Sigor@sysoev.ru         nxt_openssl_log_error(task, NXT_LOG_ALERT, "SSL_CTX_new() failed");
2890Sigor@sysoev.ru         return NXT_ERROR;
2900Sigor@sysoev.ru     }
2910Sigor@sysoev.ru 
2921920Sa.suvorov@f5.com     conf = tls_init->conf;
2931920Sa.suvorov@f5.com 
2941828Sa.suvorov@f5.com     bundle = conf->bundle;
2951828Sa.suvorov@f5.com     nxt_assert(bundle != NULL);
2961828Sa.suvorov@f5.com 
2971828Sa.suvorov@f5.com     bundle->ctx = ctx;
2980Sigor@sysoev.ru 
299771Sigor@sysoev.ru #ifdef SSL_OP_NO_RENEGOTIATION
300771Sigor@sysoev.ru     /* Renegration is not currently supported. */
301771Sigor@sysoev.ru     SSL_CTX_set_options(ctx, SSL_OP_NO_RENEGOTIATION);
302771Sigor@sysoev.ru #endif
303771Sigor@sysoev.ru 
3040Sigor@sysoev.ru #ifdef SSL_OP_NO_COMPRESSION
3050Sigor@sysoev.ru     /*
3060Sigor@sysoev.ru      * Disable gzip compression in OpenSSL 1.0.0,
3070Sigor@sysoev.ru      * this saves about 522K per connection.
3080Sigor@sysoev.ru      */
3090Sigor@sysoev.ru     SSL_CTX_set_options(ctx, SSL_OP_NO_COMPRESSION);
3100Sigor@sysoev.ru #endif
3110Sigor@sysoev.ru 
3120Sigor@sysoev.ru #ifdef SSL_MODE_RELEASE_BUFFERS
3130Sigor@sysoev.ru 
3140Sigor@sysoev.ru     if (nxt_openssl_version >= 10001078) {
3150Sigor@sysoev.ru         /*
3160Sigor@sysoev.ru          * Allow to release read and write buffers in OpenSSL 1.0.0,
3170Sigor@sysoev.ru          * this saves about 34K per idle connection.  It is not safe
3180Sigor@sysoev.ru          * before OpenSSL 1.0.1h (CVE-2010-5298).
3190Sigor@sysoev.ru          */
3200Sigor@sysoev.ru         SSL_CTX_set_mode(ctx, SSL_MODE_RELEASE_BUFFERS);
3210Sigor@sysoev.ru     }
3220Sigor@sysoev.ru 
3230Sigor@sysoev.ru #endif
3240Sigor@sysoev.ru 
3251828Sa.suvorov@f5.com     if (nxt_openssl_chain_file(task, ctx, conf, mp,
3261828Sa.suvorov@f5.com                                last && bundle->next == NULL)
3271828Sa.suvorov@f5.com         != NXT_OK)
3281828Sa.suvorov@f5.com     {
3290Sigor@sysoev.ru         goto fail;
3300Sigor@sysoev.ru     }
331774Svbart@nginx.com /*
3320Sigor@sysoev.ru     key = conf->certificate_key;
3330Sigor@sysoev.ru 
3340Sigor@sysoev.ru     if (SSL_CTX_use_PrivateKey_file(ctx, key, SSL_FILETYPE_PEM) == 0) {
335771Sigor@sysoev.ru         nxt_openssl_log_error(task, NXT_LOG_ALERT,
3360Sigor@sysoev.ru                               "SSL_CTX_use_PrivateKey_file(\"%s\") failed",
3370Sigor@sysoev.ru                               key);
3380Sigor@sysoev.ru         goto fail;
3390Sigor@sysoev.ru     }
340774Svbart@nginx.com */
3411885Sa.suvorov@f5.com 
3420Sigor@sysoev.ru     ciphers = (conf->ciphers != NULL) ? conf->ciphers : "HIGH:!aNULL:!MD5";
3430Sigor@sysoev.ru 
3440Sigor@sysoev.ru     if (SSL_CTX_set_cipher_list(ctx, ciphers) == 0) {
345771Sigor@sysoev.ru         nxt_openssl_log_error(task, NXT_LOG_ALERT,
3460Sigor@sysoev.ru                               "SSL_CTX_set_cipher_list(\"%s\") failed",
3470Sigor@sysoev.ru                               ciphers);
3480Sigor@sysoev.ru         goto fail;
3490Sigor@sysoev.ru     }
3500Sigor@sysoev.ru 
3511885Sa.suvorov@f5.com #if (NXT_HAVE_OPENSSL_CONF_CMD)
3521920Sa.suvorov@f5.com     if (tls_init->conf_cmds != NULL
3531920Sa.suvorov@f5.com         && nxt_ssl_conf_commands(task, ctx, tls_init->conf_cmds, mp) != NXT_OK)
3541885Sa.suvorov@f5.com     {
3551885Sa.suvorov@f5.com         goto fail;
3561885Sa.suvorov@f5.com     }
3571885Sa.suvorov@f5.com #endif
3581885Sa.suvorov@f5.com 
3591920Sa.suvorov@f5.com     nxt_ssl_session_cache(ctx, tls_init->cache_size, tls_init->timeout);
3601920Sa.suvorov@f5.com 
361*1942Sa.suvorov@f5.com #if (NXT_HAVE_OPENSSL_TLSEXT)
362*1942Sa.suvorov@f5.com     if (nxt_tls_ticket_keys(task, ctx, tls_init, mp) != NXT_OK) {
363*1942Sa.suvorov@f5.com         goto fail;
364*1942Sa.suvorov@f5.com     }
365*1942Sa.suvorov@f5.com #endif
366*1942Sa.suvorov@f5.com 
3670Sigor@sysoev.ru     SSL_CTX_set_options(ctx, SSL_OP_CIPHER_SERVER_PREFERENCE);
3680Sigor@sysoev.ru 
3690Sigor@sysoev.ru     if (conf->ca_certificate != NULL) {
3700Sigor@sysoev.ru 
3710Sigor@sysoev.ru         /* TODO: verify callback */
3720Sigor@sysoev.ru         SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER, NULL);
3730Sigor@sysoev.ru 
3740Sigor@sysoev.ru         /* TODO: verify depth */
3750Sigor@sysoev.ru         SSL_CTX_set_verify_depth(ctx, 1);
3760Sigor@sysoev.ru 
3770Sigor@sysoev.ru         ca_certificate = conf->ca_certificate;
3780Sigor@sysoev.ru 
3790Sigor@sysoev.ru         if (SSL_CTX_load_verify_locations(ctx, ca_certificate, NULL) == 0) {
380771Sigor@sysoev.ru             nxt_openssl_log_error(task, NXT_LOG_ALERT,
3810Sigor@sysoev.ru                               "SSL_CTX_load_verify_locations(\"%s\") failed",
3820Sigor@sysoev.ru                               ca_certificate);
3830Sigor@sysoev.ru             goto fail;
3840Sigor@sysoev.ru         }
3850Sigor@sysoev.ru 
3860Sigor@sysoev.ru         list = SSL_load_client_CA_file(ca_certificate);
3870Sigor@sysoev.ru 
3880Sigor@sysoev.ru         if (list == NULL) {
389771Sigor@sysoev.ru             nxt_openssl_log_error(task, NXT_LOG_ALERT,
3900Sigor@sysoev.ru                               "SSL_load_client_CA_file(\"%s\") failed",
3910Sigor@sysoev.ru                               ca_certificate);
3920Sigor@sysoev.ru             goto fail;
3930Sigor@sysoev.ru         }
3940Sigor@sysoev.ru 
3950Sigor@sysoev.ru         /*
3960Sigor@sysoev.ru          * SSL_load_client_CA_file() in OpenSSL prior to 0.9.7h and
3970Sigor@sysoev.ru          * 0.9.8 versions always leaves an error in the error queue.
3980Sigor@sysoev.ru          */
3990Sigor@sysoev.ru         ERR_clear_error();
4000Sigor@sysoev.ru 
4010Sigor@sysoev.ru         SSL_CTX_set_client_CA_list(ctx, list);
4020Sigor@sysoev.ru     }
4030Sigor@sysoev.ru 
4041828Sa.suvorov@f5.com     if (last) {
4051828Sa.suvorov@f5.com         conf->conn_init = nxt_openssl_conn_init;
4061828Sa.suvorov@f5.com 
4071828Sa.suvorov@f5.com         if (bundle->next != NULL) {
4081828Sa.suvorov@f5.com             SSL_CTX_set_tlsext_servername_callback(ctx, nxt_openssl_servername);
4091828Sa.suvorov@f5.com         }
4101828Sa.suvorov@f5.com     }
4111828Sa.suvorov@f5.com 
4120Sigor@sysoev.ru     return NXT_OK;
4130Sigor@sysoev.ru 
4140Sigor@sysoev.ru fail:
4150Sigor@sysoev.ru 
4160Sigor@sysoev.ru     SSL_CTX_free(ctx);
4170Sigor@sysoev.ru 
4181818Smax.romanov@nginx.com #if (OPENSSL_VERSION_NUMBER >= 0x1010100fL \
4191818Smax.romanov@nginx.com      && OPENSSL_VERSION_NUMBER < 0x1010101fL)
4201818Smax.romanov@nginx.com     RAND_keep_random_devices_open(0);
4211818Smax.romanov@nginx.com #endif
4221818Smax.romanov@nginx.com 
4230Sigor@sysoev.ru     return NXT_ERROR;
4240Sigor@sysoev.ru }
4250Sigor@sysoev.ru 
4260Sigor@sysoev.ru 
427833Svbart@nginx.com static nxt_int_t
4281828Sa.suvorov@f5.com nxt_openssl_chain_file(nxt_task_t *task, SSL_CTX *ctx, nxt_tls_conf_t *conf,
4291828Sa.suvorov@f5.com     nxt_mp_t *mp, nxt_bool_t single)
430774Svbart@nginx.com {
4311828Sa.suvorov@f5.com     BIO                    *bio;
4321828Sa.suvorov@f5.com     X509                   *cert, *ca;
4331828Sa.suvorov@f5.com     long                   reason;
4341828Sa.suvorov@f5.com     EVP_PKEY               *key;
4351828Sa.suvorov@f5.com     nxt_int_t              ret;
4361828Sa.suvorov@f5.com     nxt_tls_bundle_conf_t  *bundle;
4371828Sa.suvorov@f5.com 
4381828Sa.suvorov@f5.com     ret = NXT_ERROR;
4391828Sa.suvorov@f5.com     cert = NULL;
440774Svbart@nginx.com 
441774Svbart@nginx.com     bio = BIO_new(BIO_s_fd());
442774Svbart@nginx.com     if (bio == NULL) {
4431828Sa.suvorov@f5.com         goto end;
444774Svbart@nginx.com     }
445774Svbart@nginx.com 
4461828Sa.suvorov@f5.com     bundle = conf->bundle;
447774Svbart@nginx.com 
4481828Sa.suvorov@f5.com     BIO_set_fd(bio, bundle->chain_file, BIO_CLOSE);
449774Svbart@nginx.com 
450774Svbart@nginx.com     cert = PEM_read_bio_X509_AUX(bio, NULL, NULL, NULL);
451774Svbart@nginx.com     if (cert == NULL) {
452774Svbart@nginx.com         goto end;
453774Svbart@nginx.com     }
454774Svbart@nginx.com 
455774Svbart@nginx.com     if (SSL_CTX_use_certificate(ctx, cert) != 1) {
456774Svbart@nginx.com         goto end;
457774Svbart@nginx.com     }
458774Svbart@nginx.com 
4591828Sa.suvorov@f5.com     if (!single && nxt_openssl_cert_get_names(task, cert, conf, mp) != NXT_OK) {
4601828Sa.suvorov@f5.com         goto clean;
4611828Sa.suvorov@f5.com     }
4621828Sa.suvorov@f5.com 
463774Svbart@nginx.com     for ( ;; ) {
464774Svbart@nginx.com         ca = PEM_read_bio_X509(bio, NULL, NULL, NULL);
465774Svbart@nginx.com 
466774Svbart@nginx.com         if (ca == NULL) {
467774Svbart@nginx.com             reason = ERR_GET_REASON(ERR_peek_last_error());
468774Svbart@nginx.com             if (reason != PEM_R_NO_START_LINE) {
469774Svbart@nginx.com                 goto end;
470774Svbart@nginx.com             }
471774Svbart@nginx.com 
472774Svbart@nginx.com             ERR_clear_error();
473774Svbart@nginx.com             break;
474774Svbart@nginx.com         }
475774Svbart@nginx.com 
476774Svbart@nginx.com         /*
477774Svbart@nginx.com          * Note that ca isn't freed if it was successfully added to the chain,
478774Svbart@nginx.com          * while the main certificate needs a X509_free() call, since
479774Svbart@nginx.com          * its reference count is increased by SSL_CTX_use_certificate().
480774Svbart@nginx.com          */
481808Spluknet@nginx.com #ifdef SSL_CTX_add0_chain_cert
482774Svbart@nginx.com         if (SSL_CTX_add0_chain_cert(ctx, ca) != 1) {
483774Svbart@nginx.com #else
484774Svbart@nginx.com         if (SSL_CTX_add_extra_chain_cert(ctx, ca) != 1) {
485774Svbart@nginx.com #endif
486774Svbart@nginx.com             X509_free(ca);
487774Svbart@nginx.com             goto end;
488774Svbart@nginx.com         }
489774Svbart@nginx.com     }
490774Svbart@nginx.com 
491774Svbart@nginx.com     if (BIO_reset(bio) != 0) {
492774Svbart@nginx.com         goto end;
493774Svbart@nginx.com     }
494774Svbart@nginx.com 
495774Svbart@nginx.com     key = PEM_read_bio_PrivateKey(bio, NULL, NULL, NULL);
496774Svbart@nginx.com     if (key == NULL) {
497774Svbart@nginx.com         goto end;
498774Svbart@nginx.com     }
499774Svbart@nginx.com 
500774Svbart@nginx.com     if (SSL_CTX_use_PrivateKey(ctx, key) == 1) {
501774Svbart@nginx.com         ret = NXT_OK;
502774Svbart@nginx.com     }
503774Svbart@nginx.com 
504774Svbart@nginx.com     EVP_PKEY_free(key);
505774Svbart@nginx.com 
506774Svbart@nginx.com end:
507774Svbart@nginx.com 
5081828Sa.suvorov@f5.com     if (ret != NXT_OK) {
5091828Sa.suvorov@f5.com         nxt_openssl_log_error(task, NXT_LOG_ALERT,
5101828Sa.suvorov@f5.com                               "nxt_openssl_chain_file() failed");
5111828Sa.suvorov@f5.com     }
5121828Sa.suvorov@f5.com 
5131828Sa.suvorov@f5.com clean:
5141828Sa.suvorov@f5.com 
5151828Sa.suvorov@f5.com     BIO_free(bio);
516774Svbart@nginx.com     X509_free(cert);
517774Svbart@nginx.com 
518774Svbart@nginx.com     return ret;
519774Svbart@nginx.com }
520774Svbart@nginx.com 
521774Svbart@nginx.com 
5221885Sa.suvorov@f5.com #if (NXT_HAVE_OPENSSL_CONF_CMD)
5231885Sa.suvorov@f5.com 
5241885Sa.suvorov@f5.com static nxt_int_t
5251885Sa.suvorov@f5.com nxt_ssl_conf_commands(nxt_task_t *task, SSL_CTX *ctx, nxt_conf_value_t *conf,
5261885Sa.suvorov@f5.com     nxt_mp_t *mp)
5271885Sa.suvorov@f5.com {
5281885Sa.suvorov@f5.com     int               ret;
5291885Sa.suvorov@f5.com     char              *zcmd, *zvalue;
5301885Sa.suvorov@f5.com     uint32_t          index;
5311885Sa.suvorov@f5.com     nxt_str_t         cmd, value;
5321885Sa.suvorov@f5.com     SSL_CONF_CTX      *cctx;
5331885Sa.suvorov@f5.com     nxt_conf_value_t  *member;
5341885Sa.suvorov@f5.com 
5351885Sa.suvorov@f5.com     cctx = SSL_CONF_CTX_new();
5361885Sa.suvorov@f5.com     if (nxt_slow_path(cctx == NULL)) {
5371885Sa.suvorov@f5.com         nxt_openssl_log_error(task, NXT_LOG_ALERT,
5381885Sa.suvorov@f5.com                               "SSL_CONF_CTX_new() failed");
5391885Sa.suvorov@f5.com         return NXT_ERROR;
5401885Sa.suvorov@f5.com     }
5411885Sa.suvorov@f5.com 
5421885Sa.suvorov@f5.com     SSL_CONF_CTX_set_flags(cctx, SSL_CONF_FLAG_FILE
5431885Sa.suvorov@f5.com                                  | SSL_CONF_FLAG_SERVER
5441885Sa.suvorov@f5.com                                  | SSL_CONF_FLAG_CERTIFICATE
5451885Sa.suvorov@f5.com                                  | SSL_CONF_FLAG_SHOW_ERRORS);
5461885Sa.suvorov@f5.com 
5471885Sa.suvorov@f5.com     SSL_CONF_CTX_set_ssl_ctx(cctx, ctx);
5481885Sa.suvorov@f5.com 
5491885Sa.suvorov@f5.com     index = 0;
5501885Sa.suvorov@f5.com 
5511885Sa.suvorov@f5.com     for ( ;; ) {
5521885Sa.suvorov@f5.com         member = nxt_conf_next_object_member(conf, &cmd, &index);
5531885Sa.suvorov@f5.com         if (nxt_slow_path(member == NULL)) {
5541885Sa.suvorov@f5.com             break;
5551885Sa.suvorov@f5.com         }
5561885Sa.suvorov@f5.com 
5571885Sa.suvorov@f5.com         nxt_conf_get_string(member, &value);
5581885Sa.suvorov@f5.com 
5591885Sa.suvorov@f5.com         zcmd = nxt_str_cstrz(mp, &cmd);
5601885Sa.suvorov@f5.com         zvalue = nxt_str_cstrz(mp, &value);
5611885Sa.suvorov@f5.com 
5621885Sa.suvorov@f5.com         if (nxt_slow_path(zcmd == NULL || zvalue == NULL)) {
5631885Sa.suvorov@f5.com             goto fail;
5641885Sa.suvorov@f5.com         }
5651885Sa.suvorov@f5.com 
5661885Sa.suvorov@f5.com         ret = SSL_CONF_cmd(cctx, zcmd, zvalue);
5671885Sa.suvorov@f5.com         if (ret == -2) {
5681885Sa.suvorov@f5.com             nxt_openssl_log_error(task, NXT_LOG_ERR,
5691885Sa.suvorov@f5.com                                   "unknown command \"%s\" in "
5701885Sa.suvorov@f5.com                                   "\"conf_commands\" option", zcmd);
5711885Sa.suvorov@f5.com             goto fail;
5721885Sa.suvorov@f5.com         }
5731885Sa.suvorov@f5.com 
5741885Sa.suvorov@f5.com         if (ret <= 0) {
5751885Sa.suvorov@f5.com             nxt_openssl_log_error(task, NXT_LOG_ERR,
5761885Sa.suvorov@f5.com                                   "invalid value \"%s\" for command \"%s\" "
5771885Sa.suvorov@f5.com                                   "in \"conf_commands\" option",
5781885Sa.suvorov@f5.com                                   zvalue, zcmd);
5791885Sa.suvorov@f5.com             goto fail;
5801885Sa.suvorov@f5.com         }
5811885Sa.suvorov@f5.com 
5821885Sa.suvorov@f5.com         nxt_debug(task, "SSL_CONF_cmd(\"%s\", \"%s\")", zcmd, zvalue);
5831885Sa.suvorov@f5.com     }
5841885Sa.suvorov@f5.com 
5851885Sa.suvorov@f5.com     if (SSL_CONF_CTX_finish(cctx) != 1) {
5861885Sa.suvorov@f5.com         nxt_openssl_log_error(task, NXT_LOG_ALERT,
5871885Sa.suvorov@f5.com                               "SSL_CONF_finish() failed");
5881885Sa.suvorov@f5.com         goto fail;
5891885Sa.suvorov@f5.com     }
5901885Sa.suvorov@f5.com 
5911885Sa.suvorov@f5.com     SSL_CONF_CTX_free(cctx);
5921885Sa.suvorov@f5.com 
5931885Sa.suvorov@f5.com     return NXT_OK;
5941885Sa.suvorov@f5.com 
5951885Sa.suvorov@f5.com fail:
5961885Sa.suvorov@f5.com 
5971885Sa.suvorov@f5.com     SSL_CONF_CTX_free(cctx);
5981885Sa.suvorov@f5.com 
5991885Sa.suvorov@f5.com     return NXT_ERROR;
6001885Sa.suvorov@f5.com }
6011885Sa.suvorov@f5.com 
6021885Sa.suvorov@f5.com #endif
6031885Sa.suvorov@f5.com 
604*1942Sa.suvorov@f5.com #if (NXT_HAVE_OPENSSL_TLSEXT)
605*1942Sa.suvorov@f5.com 
606*1942Sa.suvorov@f5.com static nxt_int_t
607*1942Sa.suvorov@f5.com nxt_tls_ticket_keys(nxt_task_t *task, SSL_CTX *ctx, nxt_tls_init_t *tls_init,
608*1942Sa.suvorov@f5.com     nxt_mp_t *mp)
609*1942Sa.suvorov@f5.com {
610*1942Sa.suvorov@f5.com     uint32_t           i;
611*1942Sa.suvorov@f5.com     nxt_int_t          ret;
612*1942Sa.suvorov@f5.com     nxt_str_t          value;
613*1942Sa.suvorov@f5.com     nxt_uint_t         count;
614*1942Sa.suvorov@f5.com     nxt_conf_value_t   *member, *tickets_conf;
615*1942Sa.suvorov@f5.com     nxt_tls_ticket_t   *ticket;
616*1942Sa.suvorov@f5.com     nxt_tls_tickets_t  *tickets;
617*1942Sa.suvorov@f5.com     u_char             buf[80];
618*1942Sa.suvorov@f5.com 
619*1942Sa.suvorov@f5.com     tickets_conf = tls_init->tickets_conf;
620*1942Sa.suvorov@f5.com 
621*1942Sa.suvorov@f5.com     if (tickets_conf == NULL) {
622*1942Sa.suvorov@f5.com         goto no_ticket;
623*1942Sa.suvorov@f5.com     }
624*1942Sa.suvorov@f5.com 
625*1942Sa.suvorov@f5.com     if (nxt_conf_type(tickets_conf) == NXT_CONF_BOOLEAN) {
626*1942Sa.suvorov@f5.com         if (nxt_conf_get_boolean(tickets_conf) == 0) {
627*1942Sa.suvorov@f5.com             goto no_ticket;
628*1942Sa.suvorov@f5.com         }
629*1942Sa.suvorov@f5.com 
630*1942Sa.suvorov@f5.com         return NXT_OK;
631*1942Sa.suvorov@f5.com     }
632*1942Sa.suvorov@f5.com 
633*1942Sa.suvorov@f5.com     if (nxt_conf_type(tickets_conf) == NXT_CONF_ARRAY) {
634*1942Sa.suvorov@f5.com         count = nxt_conf_array_elements_count(tickets_conf);
635*1942Sa.suvorov@f5.com 
636*1942Sa.suvorov@f5.com         if (count == 0) {
637*1942Sa.suvorov@f5.com             goto no_ticket;
638*1942Sa.suvorov@f5.com         }
639*1942Sa.suvorov@f5.com 
640*1942Sa.suvorov@f5.com     } else {
641*1942Sa.suvorov@f5.com         /* nxt_conf_type(tickets_conf) == NXT_CONF_STRING */
642*1942Sa.suvorov@f5.com         count = 1;
643*1942Sa.suvorov@f5.com     }
644*1942Sa.suvorov@f5.com 
645*1942Sa.suvorov@f5.com #ifdef SSL_CTRL_SET_TLSEXT_TICKET_KEY_CB
646*1942Sa.suvorov@f5.com 
647*1942Sa.suvorov@f5.com     tickets = nxt_mp_get(mp, sizeof(nxt_tls_tickets_t)
648*1942Sa.suvorov@f5.com                              + count * sizeof(nxt_tls_ticket_t));
649*1942Sa.suvorov@f5.com     if (nxt_slow_path(tickets == NULL)) {
650*1942Sa.suvorov@f5.com         return NXT_ERROR;
651*1942Sa.suvorov@f5.com     }
652*1942Sa.suvorov@f5.com 
653*1942Sa.suvorov@f5.com     tickets->count = count;
654*1942Sa.suvorov@f5.com     tls_init->conf->tickets = tickets;
655*1942Sa.suvorov@f5.com     i = 0;
656*1942Sa.suvorov@f5.com 
657*1942Sa.suvorov@f5.com     do {
658*1942Sa.suvorov@f5.com         ticket = &tickets->tickets[i];
659*1942Sa.suvorov@f5.com 
660*1942Sa.suvorov@f5.com         i++;
661*1942Sa.suvorov@f5.com 
662*1942Sa.suvorov@f5.com         if (nxt_conf_type(tickets_conf) == NXT_CONF_ARRAY) {
663*1942Sa.suvorov@f5.com             member = nxt_conf_get_array_element(tickets_conf, count - i);
664*1942Sa.suvorov@f5.com             if (member == NULL) {
665*1942Sa.suvorov@f5.com                 break;
666*1942Sa.suvorov@f5.com             }
667*1942Sa.suvorov@f5.com 
668*1942Sa.suvorov@f5.com         } else {
669*1942Sa.suvorov@f5.com             /* nxt_conf_type(tickets_conf) == NXT_CONF_STRING */
670*1942Sa.suvorov@f5.com             member = tickets_conf;
671*1942Sa.suvorov@f5.com         }
672*1942Sa.suvorov@f5.com 
673*1942Sa.suvorov@f5.com         nxt_conf_get_string(member, &value);
674*1942Sa.suvorov@f5.com 
675*1942Sa.suvorov@f5.com         ret = nxt_openssl_base64_decode(buf, 80, value.start, value.length);
676*1942Sa.suvorov@f5.com         if (nxt_slow_path(ret == NXT_ERROR)) {
677*1942Sa.suvorov@f5.com             return NXT_ERROR;
678*1942Sa.suvorov@f5.com         }
679*1942Sa.suvorov@f5.com 
680*1942Sa.suvorov@f5.com         if (ret == 48) {
681*1942Sa.suvorov@f5.com             ticket->aes128 = 1;
682*1942Sa.suvorov@f5.com             nxt_memcpy(ticket->aes_key, buf + 16, 16);
683*1942Sa.suvorov@f5.com             nxt_memcpy(ticket->hmac_key, buf + 32, 16);
684*1942Sa.suvorov@f5.com 
685*1942Sa.suvorov@f5.com         } else {
686*1942Sa.suvorov@f5.com             ticket->aes128 = 0;
687*1942Sa.suvorov@f5.com             nxt_memcpy(ticket->hmac_key, buf + 16, 32);
688*1942Sa.suvorov@f5.com             nxt_memcpy(ticket->aes_key, buf + 48, 32);
689*1942Sa.suvorov@f5.com         }
690*1942Sa.suvorov@f5.com 
691*1942Sa.suvorov@f5.com         nxt_memcpy(ticket->name, buf, 16);
692*1942Sa.suvorov@f5.com     } while (i < count);
693*1942Sa.suvorov@f5.com 
694*1942Sa.suvorov@f5.com     if (SSL_CTX_set_tlsext_ticket_key_cb(ctx, nxt_tls_ticket_key_callback)
695*1942Sa.suvorov@f5.com         == 0)
696*1942Sa.suvorov@f5.com     {
697*1942Sa.suvorov@f5.com         nxt_openssl_log_error(task, NXT_LOG_ALERT,
698*1942Sa.suvorov@f5.com                       "Unit was built with Session Tickets support, however, "
699*1942Sa.suvorov@f5.com                       "now it is linked dynamically to an OpenSSL library "
700*1942Sa.suvorov@f5.com                       "which has no tlsext support, therefore Session Tickets "
701*1942Sa.suvorov@f5.com                       "are not available");
702*1942Sa.suvorov@f5.com 
703*1942Sa.suvorov@f5.com         return NXT_ERROR;
704*1942Sa.suvorov@f5.com     }
705*1942Sa.suvorov@f5.com 
706*1942Sa.suvorov@f5.com     return NXT_OK;
707*1942Sa.suvorov@f5.com 
708*1942Sa.suvorov@f5.com #else
709*1942Sa.suvorov@f5.com     nxt_alert(task, "Setting custom session ticket keys is not supported with "
710*1942Sa.suvorov@f5.com                     "this version of OpenSSL library");
711*1942Sa.suvorov@f5.com 
712*1942Sa.suvorov@f5.com     return NXT_ERROR;
713*1942Sa.suvorov@f5.com 
714*1942Sa.suvorov@f5.com #endif
715*1942Sa.suvorov@f5.com 
716*1942Sa.suvorov@f5.com no_ticket:
717*1942Sa.suvorov@f5.com 
718*1942Sa.suvorov@f5.com     SSL_CTX_set_options(ctx, SSL_OP_NO_TICKET);
719*1942Sa.suvorov@f5.com 
720*1942Sa.suvorov@f5.com     return NXT_OK;
721*1942Sa.suvorov@f5.com }
722*1942Sa.suvorov@f5.com 
723*1942Sa.suvorov@f5.com 
724*1942Sa.suvorov@f5.com #ifdef SSL_CTRL_SET_TLSEXT_TICKET_KEY_CB
725*1942Sa.suvorov@f5.com 
726*1942Sa.suvorov@f5.com static int
727*1942Sa.suvorov@f5.com nxt_tls_ticket_key_callback(SSL *s, unsigned char *name, unsigned char *iv,
728*1942Sa.suvorov@f5.com     EVP_CIPHER_CTX *ectx, HMAC_CTX *hctx, int enc)
729*1942Sa.suvorov@f5.com {
730*1942Sa.suvorov@f5.com     size_t              size;
731*1942Sa.suvorov@f5.com     nxt_uint_t          i;
732*1942Sa.suvorov@f5.com     nxt_conn_t          *c;
733*1942Sa.suvorov@f5.com     const EVP_MD        *digest;
734*1942Sa.suvorov@f5.com     const EVP_CIPHER    *cipher;
735*1942Sa.suvorov@f5.com     nxt_tls_ticket_t    *ticket;
736*1942Sa.suvorov@f5.com     nxt_openssl_conn_t  *tls;
737*1942Sa.suvorov@f5.com 
738*1942Sa.suvorov@f5.com     c = SSL_get_ex_data(s, nxt_openssl_connection_index);
739*1942Sa.suvorov@f5.com 
740*1942Sa.suvorov@f5.com     if (nxt_slow_path(c == NULL)) {
741*1942Sa.suvorov@f5.com         nxt_thread_log_alert("SSL_get_ex_data() failed");
742*1942Sa.suvorov@f5.com         return -1;
743*1942Sa.suvorov@f5.com     }
744*1942Sa.suvorov@f5.com 
745*1942Sa.suvorov@f5.com     tls = c->u.tls;
746*1942Sa.suvorov@f5.com     ticket = tls->conf->tickets->tickets;
747*1942Sa.suvorov@f5.com 
748*1942Sa.suvorov@f5.com #ifdef OPENSSL_NO_SHA256
749*1942Sa.suvorov@f5.com     digest = EVP_sha1();
750*1942Sa.suvorov@f5.com #else
751*1942Sa.suvorov@f5.com     digest = EVP_sha256();
752*1942Sa.suvorov@f5.com #endif
753*1942Sa.suvorov@f5.com 
754*1942Sa.suvorov@f5.com     if (enc == 1) {
755*1942Sa.suvorov@f5.com         /* encrypt session ticket */
756*1942Sa.suvorov@f5.com 
757*1942Sa.suvorov@f5.com         nxt_debug(c->socket.task, "TLS session ticket encrypt");
758*1942Sa.suvorov@f5.com 
759*1942Sa.suvorov@f5.com         if (ticket[0].aes128 == 1) {
760*1942Sa.suvorov@f5.com             cipher = EVP_aes_128_cbc();
761*1942Sa.suvorov@f5.com             size = 16;
762*1942Sa.suvorov@f5.com 
763*1942Sa.suvorov@f5.com         } else {
764*1942Sa.suvorov@f5.com             cipher = EVP_aes_256_cbc();
765*1942Sa.suvorov@f5.com             size = 32;
766*1942Sa.suvorov@f5.com         }
767*1942Sa.suvorov@f5.com 
768*1942Sa.suvorov@f5.com         if (RAND_bytes(iv, EVP_CIPHER_iv_length(cipher)) != 1) {
769*1942Sa.suvorov@f5.com             nxt_openssl_log_error(c->socket.task, NXT_LOG_ALERT,
770*1942Sa.suvorov@f5.com                                   "RAND_bytes() failed");
771*1942Sa.suvorov@f5.com             return -1;
772*1942Sa.suvorov@f5.com         }
773*1942Sa.suvorov@f5.com 
774*1942Sa.suvorov@f5.com         if (EVP_EncryptInit_ex(ectx, cipher, NULL, ticket[0].aes_key, iv)
775*1942Sa.suvorov@f5.com             != 1)
776*1942Sa.suvorov@f5.com         {
777*1942Sa.suvorov@f5.com             nxt_openssl_log_error(c->socket.task, NXT_LOG_ALERT,
778*1942Sa.suvorov@f5.com                                   "EVP_EncryptInit_ex() failed");
779*1942Sa.suvorov@f5.com             return -1;
780*1942Sa.suvorov@f5.com         }
781*1942Sa.suvorov@f5.com 
782*1942Sa.suvorov@f5.com         if (HMAC_Init_ex(hctx, ticket[0].hmac_key, size, digest, NULL) != 1) {
783*1942Sa.suvorov@f5.com             nxt_openssl_log_error(c->socket.task, NXT_LOG_ALERT,
784*1942Sa.suvorov@f5.com                                   "HMAC_Init_ex() failed");
785*1942Sa.suvorov@f5.com             return -1;
786*1942Sa.suvorov@f5.com         }
787*1942Sa.suvorov@f5.com 
788*1942Sa.suvorov@f5.com         nxt_memcpy(name, ticket[0].name, 16);
789*1942Sa.suvorov@f5.com 
790*1942Sa.suvorov@f5.com         return 1;
791*1942Sa.suvorov@f5.com 
792*1942Sa.suvorov@f5.com     } else {
793*1942Sa.suvorov@f5.com         /* decrypt session ticket */
794*1942Sa.suvorov@f5.com 
795*1942Sa.suvorov@f5.com         for (i = 0; i < tls->conf->tickets->count; i++) {
796*1942Sa.suvorov@f5.com             if (nxt_memcmp(name, ticket[i].name, 16) == 0) {
797*1942Sa.suvorov@f5.com                 goto found;
798*1942Sa.suvorov@f5.com             }
799*1942Sa.suvorov@f5.com         }
800*1942Sa.suvorov@f5.com 
801*1942Sa.suvorov@f5.com         nxt_debug(c->socket.task, "TLS session ticket decrypt, key not found");
802*1942Sa.suvorov@f5.com 
803*1942Sa.suvorov@f5.com         return 0;
804*1942Sa.suvorov@f5.com 
805*1942Sa.suvorov@f5.com     found:
806*1942Sa.suvorov@f5.com 
807*1942Sa.suvorov@f5.com         nxt_debug(c->socket.task,
808*1942Sa.suvorov@f5.com                   "TLS session ticket decrypt, key number: \"%d\"", i);
809*1942Sa.suvorov@f5.com 
810*1942Sa.suvorov@f5.com         if (ticket[i].aes128 == 1) {
811*1942Sa.suvorov@f5.com             cipher = EVP_aes_128_cbc();
812*1942Sa.suvorov@f5.com             size = 16;
813*1942Sa.suvorov@f5.com 
814*1942Sa.suvorov@f5.com         } else {
815*1942Sa.suvorov@f5.com             cipher = EVP_aes_256_cbc();
816*1942Sa.suvorov@f5.com             size = 32;
817*1942Sa.suvorov@f5.com         }
818*1942Sa.suvorov@f5.com 
819*1942Sa.suvorov@f5.com         if (EVP_DecryptInit_ex(ectx, cipher, NULL, ticket[i].aes_key, iv) != 1) {
820*1942Sa.suvorov@f5.com             nxt_openssl_log_error(c->socket.task, NXT_LOG_ALERT,
821*1942Sa.suvorov@f5.com                                   "EVP_DecryptInit_ex() failed");
822*1942Sa.suvorov@f5.com             return -1;
823*1942Sa.suvorov@f5.com         }
824*1942Sa.suvorov@f5.com 
825*1942Sa.suvorov@f5.com         if (HMAC_Init_ex(hctx, ticket[i].hmac_key, size, digest, NULL) != 1) {
826*1942Sa.suvorov@f5.com             nxt_openssl_log_error(c->socket.task, NXT_LOG_ALERT,
827*1942Sa.suvorov@f5.com                                   "HMAC_Init_ex() failed");
828*1942Sa.suvorov@f5.com             return -1;
829*1942Sa.suvorov@f5.com         }
830*1942Sa.suvorov@f5.com 
831*1942Sa.suvorov@f5.com         return (i == 0) ? 1 : 2 /* renew */;
832*1942Sa.suvorov@f5.com     }
833*1942Sa.suvorov@f5.com }
834*1942Sa.suvorov@f5.com 
835*1942Sa.suvorov@f5.com #endif /* SSL_CTRL_SET_TLSEXT_TICKET_KEY_CB */
836*1942Sa.suvorov@f5.com 
837*1942Sa.suvorov@f5.com #endif /* NXT_HAVE_OPENSSL_TLSEXT */
838*1942Sa.suvorov@f5.com 
8391885Sa.suvorov@f5.com 
8401920Sa.suvorov@f5.com static void
8411920Sa.suvorov@f5.com nxt_ssl_session_cache(SSL_CTX *ctx, size_t cache_size, time_t timeout)
8421920Sa.suvorov@f5.com {
8431920Sa.suvorov@f5.com     if (cache_size == 0) {
8441920Sa.suvorov@f5.com         SSL_CTX_set_session_cache_mode(ctx, SSL_SESS_CACHE_OFF);
8451920Sa.suvorov@f5.com         return;
8461920Sa.suvorov@f5.com     }
8471920Sa.suvorov@f5.com 
8481920Sa.suvorov@f5.com     SSL_CTX_set_session_cache_mode(ctx, SSL_SESS_CACHE_SERVER);
8491920Sa.suvorov@f5.com 
8501920Sa.suvorov@f5.com     SSL_CTX_sess_set_cache_size(ctx, cache_size);
8511920Sa.suvorov@f5.com 
8521920Sa.suvorov@f5.com     SSL_CTX_set_timeout(ctx, (long) timeout);
8531920Sa.suvorov@f5.com }
8541920Sa.suvorov@f5.com 
8551920Sa.suvorov@f5.com 
8561828Sa.suvorov@f5.com static nxt_uint_t
8571828Sa.suvorov@f5.com nxt_openssl_cert_get_names(nxt_task_t *task, X509 *cert, nxt_tls_conf_t *conf,
8581828Sa.suvorov@f5.com     nxt_mp_t *mp)
8591828Sa.suvorov@f5.com {
8601828Sa.suvorov@f5.com     int                         len;
8611828Sa.suvorov@f5.com     nxt_str_t                   domain, str;
8621828Sa.suvorov@f5.com     X509_NAME                   *x509_name;
8631828Sa.suvorov@f5.com     nxt_uint_t                  i, n;
8641828Sa.suvorov@f5.com     GENERAL_NAME                *name;
8651828Sa.suvorov@f5.com     nxt_tls_bundle_conf_t       *bundle;
8661828Sa.suvorov@f5.com     STACK_OF(GENERAL_NAME)      *alt_names;
8671828Sa.suvorov@f5.com     nxt_tls_bundle_hash_item_t  *item;
8681828Sa.suvorov@f5.com 
8691828Sa.suvorov@f5.com     bundle = conf->bundle;
8701828Sa.suvorov@f5.com 
8711828Sa.suvorov@f5.com     alt_names = X509_get_ext_d2i(cert, NID_subject_alt_name, NULL, NULL);
8721828Sa.suvorov@f5.com 
8731828Sa.suvorov@f5.com     if (alt_names != NULL) {
8741828Sa.suvorov@f5.com         n = sk_GENERAL_NAME_num(alt_names);
8751828Sa.suvorov@f5.com 
8761828Sa.suvorov@f5.com         for (i = 0; i != n; i++) {
8771828Sa.suvorov@f5.com             name = sk_GENERAL_NAME_value(alt_names, i);
8781828Sa.suvorov@f5.com 
8791828Sa.suvorov@f5.com             if (name->type != GEN_DNS) {
8801828Sa.suvorov@f5.com                 continue;
8811828Sa.suvorov@f5.com             }
8821828Sa.suvorov@f5.com 
8831828Sa.suvorov@f5.com             str.length = ASN1_STRING_length(name->d.dNSName);
8841828Sa.suvorov@f5.com #if OPENSSL_VERSION_NUMBER > 0x10100000L
8851828Sa.suvorov@f5.com             str.start = (u_char *) ASN1_STRING_get0_data(name->d.dNSName);
8861828Sa.suvorov@f5.com #else
8871828Sa.suvorov@f5.com             str.start = ASN1_STRING_data(name->d.dNSName);
8881828Sa.suvorov@f5.com #endif
8891828Sa.suvorov@f5.com 
8901828Sa.suvorov@f5.com             domain.start = nxt_mp_nget(mp, str.length);
8911828Sa.suvorov@f5.com             if (nxt_slow_path(domain.start == NULL)) {
8921828Sa.suvorov@f5.com                 goto fail;
8931828Sa.suvorov@f5.com             }
8941828Sa.suvorov@f5.com 
8951828Sa.suvorov@f5.com             domain.length = str.length;
8961828Sa.suvorov@f5.com             nxt_memcpy_lowcase(domain.start, str.start, str.length);
8971828Sa.suvorov@f5.com 
8981828Sa.suvorov@f5.com             item = nxt_mp_get(mp, sizeof(nxt_tls_bundle_hash_item_t));
8991828Sa.suvorov@f5.com             if (nxt_slow_path(item == NULL)) {
9001828Sa.suvorov@f5.com                 goto fail;
9011828Sa.suvorov@f5.com             }
9021828Sa.suvorov@f5.com 
9031828Sa.suvorov@f5.com             item->name = domain;
9041828Sa.suvorov@f5.com             item->bundle = bundle;
9051828Sa.suvorov@f5.com 
9061828Sa.suvorov@f5.com             if (nxt_openssl_bundle_hash_insert(task, &conf->bundle_hash,
9071828Sa.suvorov@f5.com                                                item, mp)
9081828Sa.suvorov@f5.com                 == NXT_ERROR)
9091828Sa.suvorov@f5.com             {
9101828Sa.suvorov@f5.com                 goto fail;
9111828Sa.suvorov@f5.com             }
9121828Sa.suvorov@f5.com         }
9131828Sa.suvorov@f5.com 
9141828Sa.suvorov@f5.com         sk_GENERAL_NAME_pop_free(alt_names, GENERAL_NAME_free);
9151828Sa.suvorov@f5.com 
9161828Sa.suvorov@f5.com     } else {
9171828Sa.suvorov@f5.com         x509_name = X509_get_subject_name(cert);
9181828Sa.suvorov@f5.com         len = X509_NAME_get_text_by_NID(x509_name, NID_commonName,
9191828Sa.suvorov@f5.com                                         NULL, 0);
9201828Sa.suvorov@f5.com         if (len <= 0) {
9211828Sa.suvorov@f5.com             nxt_log(task, NXT_LOG_WARN, "certificate \"%V\" has neither "
9221885Sa.suvorov@f5.com                     "Subject Alternative Name nor Common Name", &bundle->name);
9231828Sa.suvorov@f5.com             return NXT_OK;
9241828Sa.suvorov@f5.com         }
9251828Sa.suvorov@f5.com 
9261828Sa.suvorov@f5.com         domain.start = nxt_mp_nget(mp, len + 1);
9271828Sa.suvorov@f5.com         if (nxt_slow_path(domain.start == NULL)) {
9281828Sa.suvorov@f5.com             return NXT_ERROR;
9291828Sa.suvorov@f5.com         }
9301828Sa.suvorov@f5.com 
9311828Sa.suvorov@f5.com         domain.length = X509_NAME_get_text_by_NID(x509_name, NID_commonName,
9321828Sa.suvorov@f5.com                                                   (char *) domain.start,
9331828Sa.suvorov@f5.com                                                   len + 1);
9341828Sa.suvorov@f5.com         nxt_memcpy_lowcase(domain.start, domain.start, domain.length);
9351828Sa.suvorov@f5.com 
9361828Sa.suvorov@f5.com         item = nxt_mp_get(mp, sizeof(nxt_tls_bundle_hash_item_t));
9371828Sa.suvorov@f5.com         if (nxt_slow_path(item == NULL)) {
9381828Sa.suvorov@f5.com             return NXT_ERROR;
9391828Sa.suvorov@f5.com         }
9401828Sa.suvorov@f5.com 
9411828Sa.suvorov@f5.com         item->name = domain;
9421828Sa.suvorov@f5.com         item->bundle = bundle;
9431828Sa.suvorov@f5.com 
9441828Sa.suvorov@f5.com         if (nxt_openssl_bundle_hash_insert(task, &conf->bundle_hash, item,
9451828Sa.suvorov@f5.com                                            mp)
9461828Sa.suvorov@f5.com             == NXT_ERROR)
9471828Sa.suvorov@f5.com         {
9481828Sa.suvorov@f5.com             return NXT_ERROR;
9491828Sa.suvorov@f5.com         }
9501828Sa.suvorov@f5.com     }
9511828Sa.suvorov@f5.com 
9521828Sa.suvorov@f5.com     return NXT_OK;
9531828Sa.suvorov@f5.com 
9541828Sa.suvorov@f5.com fail:
9551828Sa.suvorov@f5.com 
9561828Sa.suvorov@f5.com     sk_GENERAL_NAME_pop_free(alt_names, GENERAL_NAME_free);
9571828Sa.suvorov@f5.com 
9581828Sa.suvorov@f5.com     return NXT_ERROR;
9591828Sa.suvorov@f5.com }
9601828Sa.suvorov@f5.com 
9611828Sa.suvorov@f5.com 
9621828Sa.suvorov@f5.com static const nxt_lvlhsh_proto_t  nxt_openssl_bundle_hash_proto
9631828Sa.suvorov@f5.com     nxt_aligned(64) =
9641828Sa.suvorov@f5.com {
9651828Sa.suvorov@f5.com     NXT_LVLHSH_DEFAULT,
9661828Sa.suvorov@f5.com     nxt_openssl_bundle_hash_test,
9671828Sa.suvorov@f5.com     nxt_mp_lvlhsh_alloc,
9681828Sa.suvorov@f5.com     nxt_mp_lvlhsh_free,
9691828Sa.suvorov@f5.com };
9701828Sa.suvorov@f5.com 
9711828Sa.suvorov@f5.com 
9721828Sa.suvorov@f5.com static nxt_int_t
9731828Sa.suvorov@f5.com nxt_openssl_bundle_hash_test(nxt_lvlhsh_query_t *lhq, void *data)
9741828Sa.suvorov@f5.com {
9751828Sa.suvorov@f5.com     nxt_tls_bundle_hash_item_t  *item;
9761828Sa.suvorov@f5.com 
9771828Sa.suvorov@f5.com     item = data;
9781828Sa.suvorov@f5.com 
9791828Sa.suvorov@f5.com     return nxt_strstr_eq(&lhq->key, &item->name) ? NXT_OK : NXT_DECLINED;
9801828Sa.suvorov@f5.com }
9811828Sa.suvorov@f5.com 
982