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>
92089Spluknet@nginx.com
102089Spluknet@nginx.com #define OPENSSL_SUPPRESS_DEPRECATED
112089Spluknet@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,
76*2617Szelenkov@nginx.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
nxt_openssl_library_init(nxt_task_t * task)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
nxt_openssl_library_free(nxt_task_t * task)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
nxt_openssl_locks_init(void)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
nxt_openssl_lock(int mode,int type,const char * file,int line)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
nxt_openssl_thread_id(void)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
nxt_openssl_library_free(nxt_task_t * task)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
nxt_openssl_locks_free(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
nxt_openssl_server_init(nxt_task_t * task,nxt_mp_t * mp,nxt_tls_init_t * tls_init,nxt_bool_t last)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;
2982223Sremi@remirepo.net const char *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
3292090Spluknet@nginx.com #ifdef SSL_OP_IGNORE_UNEXPECTED_EOF
3302090Spluknet@nginx.com /* Request SSL_ERROR_ZERO_RETURN on EOF. */
3312090Spluknet@nginx.com SSL_CTX_set_options(ctx, SSL_OP_IGNORE_UNEXPECTED_EOF);
3322090Spluknet@nginx.com #endif
3332090Spluknet@nginx.com
3340Sigor@sysoev.ru #ifdef SSL_MODE_RELEASE_BUFFERS
3350Sigor@sysoev.ru
3360Sigor@sysoev.ru if (nxt_openssl_version >= 10001078) {
3370Sigor@sysoev.ru /*
3380Sigor@sysoev.ru * Allow to release read and write buffers in OpenSSL 1.0.0,
3390Sigor@sysoev.ru * this saves about 34K per idle connection. It is not safe
3400Sigor@sysoev.ru * before OpenSSL 1.0.1h (CVE-2010-5298).
3410Sigor@sysoev.ru */
3420Sigor@sysoev.ru SSL_CTX_set_mode(ctx, SSL_MODE_RELEASE_BUFFERS);
3430Sigor@sysoev.ru }
3440Sigor@sysoev.ru
3450Sigor@sysoev.ru #endif
3460Sigor@sysoev.ru
3471828Sa.suvorov@f5.com if (nxt_openssl_chain_file(task, ctx, conf, mp,
3481828Sa.suvorov@f5.com last && bundle->next == NULL)
3491828Sa.suvorov@f5.com != NXT_OK)
3501828Sa.suvorov@f5.com {
3510Sigor@sysoev.ru goto fail;
3520Sigor@sysoev.ru }
353774Svbart@nginx.com /*
3540Sigor@sysoev.ru key = conf->certificate_key;
3550Sigor@sysoev.ru
3560Sigor@sysoev.ru if (SSL_CTX_use_PrivateKey_file(ctx, key, SSL_FILETYPE_PEM) == 0) {
357771Sigor@sysoev.ru nxt_openssl_log_error(task, NXT_LOG_ALERT,
3580Sigor@sysoev.ru "SSL_CTX_use_PrivateKey_file(\"%s\") failed",
3590Sigor@sysoev.ru key);
3600Sigor@sysoev.ru goto fail;
3610Sigor@sysoev.ru }
362774Svbart@nginx.com */
3631885Sa.suvorov@f5.com
3642223Sremi@remirepo.net if (conf->ciphers) { /* else use system crypto policy */
3652223Sremi@remirepo.net if (SSL_CTX_set_cipher_list(ctx, conf->ciphers) == 0) {
3662223Sremi@remirepo.net nxt_openssl_log_error(task, NXT_LOG_ALERT,
3670Sigor@sysoev.ru "SSL_CTX_set_cipher_list(\"%s\") failed",
3682223Sremi@remirepo.net conf->ciphers);
3692223Sremi@remirepo.net goto fail;
3702223Sremi@remirepo.net }
3710Sigor@sysoev.ru }
3720Sigor@sysoev.ru
3731885Sa.suvorov@f5.com #if (NXT_HAVE_OPENSSL_CONF_CMD)
3741920Sa.suvorov@f5.com if (tls_init->conf_cmds != NULL
3751920Sa.suvorov@f5.com && nxt_ssl_conf_commands(task, ctx, tls_init->conf_cmds, mp) != NXT_OK)
3761885Sa.suvorov@f5.com {
3771885Sa.suvorov@f5.com goto fail;
3781885Sa.suvorov@f5.com }
3791885Sa.suvorov@f5.com #endif
3801885Sa.suvorov@f5.com
3811920Sa.suvorov@f5.com nxt_ssl_session_cache(ctx, tls_init->cache_size, tls_init->timeout);
3821920Sa.suvorov@f5.com
3831942Sa.suvorov@f5.com #if (NXT_HAVE_OPENSSL_TLSEXT)
3841942Sa.suvorov@f5.com if (nxt_tls_ticket_keys(task, ctx, tls_init, mp) != NXT_OK) {
3851942Sa.suvorov@f5.com goto fail;
3861942Sa.suvorov@f5.com }
3871942Sa.suvorov@f5.com #endif
3881942Sa.suvorov@f5.com
3890Sigor@sysoev.ru SSL_CTX_set_options(ctx, SSL_OP_CIPHER_SERVER_PREFERENCE);
3900Sigor@sysoev.ru
3910Sigor@sysoev.ru if (conf->ca_certificate != NULL) {
3920Sigor@sysoev.ru
3930Sigor@sysoev.ru /* TODO: verify callback */
3940Sigor@sysoev.ru SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER, NULL);
3950Sigor@sysoev.ru
3960Sigor@sysoev.ru /* TODO: verify depth */
3970Sigor@sysoev.ru SSL_CTX_set_verify_depth(ctx, 1);
3980Sigor@sysoev.ru
3990Sigor@sysoev.ru ca_certificate = conf->ca_certificate;
4000Sigor@sysoev.ru
4010Sigor@sysoev.ru if (SSL_CTX_load_verify_locations(ctx, ca_certificate, NULL) == 0) {
402771Sigor@sysoev.ru nxt_openssl_log_error(task, NXT_LOG_ALERT,
4030Sigor@sysoev.ru "SSL_CTX_load_verify_locations(\"%s\") failed",
4040Sigor@sysoev.ru ca_certificate);
4050Sigor@sysoev.ru goto fail;
4060Sigor@sysoev.ru }
4070Sigor@sysoev.ru
4080Sigor@sysoev.ru list = SSL_load_client_CA_file(ca_certificate);
4090Sigor@sysoev.ru
4100Sigor@sysoev.ru if (list == NULL) {
411771Sigor@sysoev.ru nxt_openssl_log_error(task, NXT_LOG_ALERT,
4120Sigor@sysoev.ru "SSL_load_client_CA_file(\"%s\") failed",
4130Sigor@sysoev.ru ca_certificate);
4140Sigor@sysoev.ru goto fail;
4150Sigor@sysoev.ru }
4160Sigor@sysoev.ru
4170Sigor@sysoev.ru /*
4180Sigor@sysoev.ru * SSL_load_client_CA_file() in OpenSSL prior to 0.9.7h and
4190Sigor@sysoev.ru * 0.9.8 versions always leaves an error in the error queue.
4200Sigor@sysoev.ru */
4210Sigor@sysoev.ru ERR_clear_error();
4220Sigor@sysoev.ru
4230Sigor@sysoev.ru SSL_CTX_set_client_CA_list(ctx, list);
4240Sigor@sysoev.ru }
4250Sigor@sysoev.ru
4261828Sa.suvorov@f5.com if (last) {
4271828Sa.suvorov@f5.com conf->conn_init = nxt_openssl_conn_init;
4281828Sa.suvorov@f5.com
4291828Sa.suvorov@f5.com if (bundle->next != NULL) {
4301828Sa.suvorov@f5.com SSL_CTX_set_tlsext_servername_callback(ctx, nxt_openssl_servername);
4311828Sa.suvorov@f5.com }
4321828Sa.suvorov@f5.com }
4331828Sa.suvorov@f5.com
4340Sigor@sysoev.ru return NXT_OK;
4350Sigor@sysoev.ru
4360Sigor@sysoev.ru fail:
4370Sigor@sysoev.ru
4380Sigor@sysoev.ru SSL_CTX_free(ctx);
4390Sigor@sysoev.ru
4401818Smax.romanov@nginx.com #if (OPENSSL_VERSION_NUMBER >= 0x1010100fL \
4411818Smax.romanov@nginx.com && OPENSSL_VERSION_NUMBER < 0x1010101fL)
4421818Smax.romanov@nginx.com RAND_keep_random_devices_open(0);
4431818Smax.romanov@nginx.com #endif
4441818Smax.romanov@nginx.com
4450Sigor@sysoev.ru return NXT_ERROR;
4460Sigor@sysoev.ru }
4470Sigor@sysoev.ru
4480Sigor@sysoev.ru
449833Svbart@nginx.com static nxt_int_t
nxt_openssl_chain_file(nxt_task_t * task,SSL_CTX * ctx,nxt_tls_conf_t * conf,nxt_mp_t * mp,nxt_bool_t single)4501828Sa.suvorov@f5.com nxt_openssl_chain_file(nxt_task_t *task, SSL_CTX *ctx, nxt_tls_conf_t *conf,
4511828Sa.suvorov@f5.com nxt_mp_t *mp, nxt_bool_t single)
452774Svbart@nginx.com {
4531828Sa.suvorov@f5.com BIO *bio;
4541828Sa.suvorov@f5.com X509 *cert, *ca;
4551828Sa.suvorov@f5.com long reason;
4561828Sa.suvorov@f5.com EVP_PKEY *key;
4571828Sa.suvorov@f5.com nxt_int_t ret;
4581828Sa.suvorov@f5.com nxt_tls_bundle_conf_t *bundle;
4591828Sa.suvorov@f5.com
4601828Sa.suvorov@f5.com ret = NXT_ERROR;
4611828Sa.suvorov@f5.com cert = NULL;
462774Svbart@nginx.com
463774Svbart@nginx.com bio = BIO_new(BIO_s_fd());
464774Svbart@nginx.com if (bio == NULL) {
4651828Sa.suvorov@f5.com goto end;
466774Svbart@nginx.com }
467774Svbart@nginx.com
4681828Sa.suvorov@f5.com bundle = conf->bundle;
469774Svbart@nginx.com
4701828Sa.suvorov@f5.com BIO_set_fd(bio, bundle->chain_file, BIO_CLOSE);
471774Svbart@nginx.com
472774Svbart@nginx.com cert = PEM_read_bio_X509_AUX(bio, NULL, NULL, NULL);
473774Svbart@nginx.com if (cert == NULL) {
474774Svbart@nginx.com goto end;
475774Svbart@nginx.com }
476774Svbart@nginx.com
477774Svbart@nginx.com if (SSL_CTX_use_certificate(ctx, cert) != 1) {
478774Svbart@nginx.com goto end;
479774Svbart@nginx.com }
480774Svbart@nginx.com
4811828Sa.suvorov@f5.com if (!single && nxt_openssl_cert_get_names(task, cert, conf, mp) != NXT_OK) {
4821828Sa.suvorov@f5.com goto clean;
4831828Sa.suvorov@f5.com }
4841828Sa.suvorov@f5.com
485774Svbart@nginx.com for ( ;; ) {
486774Svbart@nginx.com ca = PEM_read_bio_X509(bio, NULL, NULL, NULL);
487774Svbart@nginx.com
488774Svbart@nginx.com if (ca == NULL) {
489774Svbart@nginx.com reason = ERR_GET_REASON(ERR_peek_last_error());
490774Svbart@nginx.com if (reason != PEM_R_NO_START_LINE) {
491774Svbart@nginx.com goto end;
492774Svbart@nginx.com }
493774Svbart@nginx.com
494774Svbart@nginx.com ERR_clear_error();
495774Svbart@nginx.com break;
496774Svbart@nginx.com }
497774Svbart@nginx.com
498774Svbart@nginx.com /*
499774Svbart@nginx.com * Note that ca isn't freed if it was successfully added to the chain,
500774Svbart@nginx.com * while the main certificate needs a X509_free() call, since
501774Svbart@nginx.com * its reference count is increased by SSL_CTX_use_certificate().
502774Svbart@nginx.com */
503808Spluknet@nginx.com #ifdef SSL_CTX_add0_chain_cert
504774Svbart@nginx.com if (SSL_CTX_add0_chain_cert(ctx, ca) != 1) {
505774Svbart@nginx.com #else
506774Svbart@nginx.com if (SSL_CTX_add_extra_chain_cert(ctx, ca) != 1) {
507774Svbart@nginx.com #endif
508774Svbart@nginx.com X509_free(ca);
509774Svbart@nginx.com goto end;
510774Svbart@nginx.com }
511774Svbart@nginx.com }
512774Svbart@nginx.com
513774Svbart@nginx.com if (BIO_reset(bio) != 0) {
514774Svbart@nginx.com goto end;
515774Svbart@nginx.com }
516774Svbart@nginx.com
517774Svbart@nginx.com key = PEM_read_bio_PrivateKey(bio, NULL, NULL, NULL);
518774Svbart@nginx.com if (key == NULL) {
519774Svbart@nginx.com goto end;
520774Svbart@nginx.com }
521774Svbart@nginx.com
522774Svbart@nginx.com if (SSL_CTX_use_PrivateKey(ctx, key) == 1) {
523774Svbart@nginx.com ret = NXT_OK;
524774Svbart@nginx.com }
525774Svbart@nginx.com
526774Svbart@nginx.com EVP_PKEY_free(key);
527774Svbart@nginx.com
528774Svbart@nginx.com end:
529774Svbart@nginx.com
5301828Sa.suvorov@f5.com if (ret != NXT_OK) {
5311828Sa.suvorov@f5.com nxt_openssl_log_error(task, NXT_LOG_ALERT,
5321828Sa.suvorov@f5.com "nxt_openssl_chain_file() failed");
5331828Sa.suvorov@f5.com }
5341828Sa.suvorov@f5.com
5351828Sa.suvorov@f5.com clean:
5361828Sa.suvorov@f5.com
5371828Sa.suvorov@f5.com BIO_free(bio);
538774Svbart@nginx.com X509_free(cert);
539774Svbart@nginx.com
540774Svbart@nginx.com return ret;
541774Svbart@nginx.com }
542774Svbart@nginx.com
543774Svbart@nginx.com
5441885Sa.suvorov@f5.com #if (NXT_HAVE_OPENSSL_CONF_CMD)
5451885Sa.suvorov@f5.com
5461885Sa.suvorov@f5.com static nxt_int_t
5471885Sa.suvorov@f5.com nxt_ssl_conf_commands(nxt_task_t *task, SSL_CTX *ctx, nxt_conf_value_t *conf,
5481885Sa.suvorov@f5.com nxt_mp_t *mp)
5491885Sa.suvorov@f5.com {
5501885Sa.suvorov@f5.com int ret;
5511885Sa.suvorov@f5.com char *zcmd, *zvalue;
5521885Sa.suvorov@f5.com uint32_t index;
5531885Sa.suvorov@f5.com nxt_str_t cmd, value;
5541885Sa.suvorov@f5.com SSL_CONF_CTX *cctx;
5551885Sa.suvorov@f5.com nxt_conf_value_t *member;
5561885Sa.suvorov@f5.com
5571885Sa.suvorov@f5.com cctx = SSL_CONF_CTX_new();
5581885Sa.suvorov@f5.com if (nxt_slow_path(cctx == NULL)) {
5591885Sa.suvorov@f5.com nxt_openssl_log_error(task, NXT_LOG_ALERT,
5601885Sa.suvorov@f5.com "SSL_CONF_CTX_new() failed");
5611885Sa.suvorov@f5.com return NXT_ERROR;
5621885Sa.suvorov@f5.com }
5631885Sa.suvorov@f5.com
5641885Sa.suvorov@f5.com SSL_CONF_CTX_set_flags(cctx, SSL_CONF_FLAG_FILE
5651885Sa.suvorov@f5.com | SSL_CONF_FLAG_SERVER
5661885Sa.suvorov@f5.com | SSL_CONF_FLAG_CERTIFICATE
5671885Sa.suvorov@f5.com | SSL_CONF_FLAG_SHOW_ERRORS);
5681885Sa.suvorov@f5.com
5691885Sa.suvorov@f5.com SSL_CONF_CTX_set_ssl_ctx(cctx, ctx);
5701885Sa.suvorov@f5.com
5711885Sa.suvorov@f5.com index = 0;
5721885Sa.suvorov@f5.com
5731885Sa.suvorov@f5.com for ( ;; ) {
5741885Sa.suvorov@f5.com member = nxt_conf_next_object_member(conf, &cmd, &index);
5751885Sa.suvorov@f5.com if (nxt_slow_path(member == NULL)) {
5761885Sa.suvorov@f5.com break;
5771885Sa.suvorov@f5.com }
5781885Sa.suvorov@f5.com
5791885Sa.suvorov@f5.com nxt_conf_get_string(member, &value);
5801885Sa.suvorov@f5.com
5811885Sa.suvorov@f5.com zcmd = nxt_str_cstrz(mp, &cmd);
5821885Sa.suvorov@f5.com zvalue = nxt_str_cstrz(mp, &value);
5831885Sa.suvorov@f5.com
5841885Sa.suvorov@f5.com if (nxt_slow_path(zcmd == NULL || zvalue == NULL)) {
5851885Sa.suvorov@f5.com goto fail;
5861885Sa.suvorov@f5.com }
5871885Sa.suvorov@f5.com
5881885Sa.suvorov@f5.com ret = SSL_CONF_cmd(cctx, zcmd, zvalue);
5891885Sa.suvorov@f5.com if (ret == -2) {
5901885Sa.suvorov@f5.com nxt_openssl_log_error(task, NXT_LOG_ERR,
5911885Sa.suvorov@f5.com "unknown command \"%s\" in "
5921885Sa.suvorov@f5.com "\"conf_commands\" option", zcmd);
5931885Sa.suvorov@f5.com goto fail;
5941885Sa.suvorov@f5.com }
5951885Sa.suvorov@f5.com
5961885Sa.suvorov@f5.com if (ret <= 0) {
5971885Sa.suvorov@f5.com nxt_openssl_log_error(task, NXT_LOG_ERR,
5981885Sa.suvorov@f5.com "invalid value \"%s\" for command \"%s\" "
5991885Sa.suvorov@f5.com "in \"conf_commands\" option",
6001885Sa.suvorov@f5.com zvalue, zcmd);
6011885Sa.suvorov@f5.com goto fail;
6021885Sa.suvorov@f5.com }
6031885Sa.suvorov@f5.com
6041885Sa.suvorov@f5.com nxt_debug(task, "SSL_CONF_cmd(\"%s\", \"%s\")", zcmd, zvalue);
6051885Sa.suvorov@f5.com }
6061885Sa.suvorov@f5.com
6071885Sa.suvorov@f5.com if (SSL_CONF_CTX_finish(cctx) != 1) {
6081885Sa.suvorov@f5.com nxt_openssl_log_error(task, NXT_LOG_ALERT,
6091885Sa.suvorov@f5.com "SSL_CONF_finish() failed");
6101885Sa.suvorov@f5.com goto fail;
6111885Sa.suvorov@f5.com }
6121885Sa.suvorov@f5.com
6131885Sa.suvorov@f5.com SSL_CONF_CTX_free(cctx);
6141885Sa.suvorov@f5.com
6151885Sa.suvorov@f5.com return NXT_OK;
6161885Sa.suvorov@f5.com
6171885Sa.suvorov@f5.com fail:
6181885Sa.suvorov@f5.com
6191885Sa.suvorov@f5.com SSL_CONF_CTX_free(cctx);
6201885Sa.suvorov@f5.com
6211885Sa.suvorov@f5.com return NXT_ERROR;
6221885Sa.suvorov@f5.com }
6231885Sa.suvorov@f5.com
6241885Sa.suvorov@f5.com #endif
6251885Sa.suvorov@f5.com
6261942Sa.suvorov@f5.com #if (NXT_HAVE_OPENSSL_TLSEXT)
6271942Sa.suvorov@f5.com
6281942Sa.suvorov@f5.com static nxt_int_t
6291942Sa.suvorov@f5.com nxt_tls_ticket_keys(nxt_task_t *task, SSL_CTX *ctx, nxt_tls_init_t *tls_init,
6301942Sa.suvorov@f5.com nxt_mp_t *mp)
6311942Sa.suvorov@f5.com {
6321975Svbart@nginx.com size_t len;
6331942Sa.suvorov@f5.com uint32_t i;
6341942Sa.suvorov@f5.com nxt_str_t value;
6351942Sa.suvorov@f5.com nxt_uint_t count;
6361942Sa.suvorov@f5.com nxt_conf_value_t *member, *tickets_conf;
6371942Sa.suvorov@f5.com nxt_tls_ticket_t *ticket;
6381942Sa.suvorov@f5.com nxt_tls_tickets_t *tickets;
6391942Sa.suvorov@f5.com u_char buf[80];
6401942Sa.suvorov@f5.com
6411942Sa.suvorov@f5.com tickets_conf = tls_init->tickets_conf;
6421942Sa.suvorov@f5.com
6431942Sa.suvorov@f5.com if (tickets_conf == NULL) {
6441942Sa.suvorov@f5.com goto no_ticket;
6451942Sa.suvorov@f5.com }
6461942Sa.suvorov@f5.com
6471942Sa.suvorov@f5.com if (nxt_conf_type(tickets_conf) == NXT_CONF_BOOLEAN) {
6481942Sa.suvorov@f5.com if (nxt_conf_get_boolean(tickets_conf) == 0) {
6491942Sa.suvorov@f5.com goto no_ticket;
6501942Sa.suvorov@f5.com }
6511942Sa.suvorov@f5.com
6521942Sa.suvorov@f5.com return NXT_OK;
6531942Sa.suvorov@f5.com }
6541942Sa.suvorov@f5.com
6552077Salx.manpages@gmail.com count = nxt_conf_array_elements_count_or_1(tickets_conf);
6561942Sa.suvorov@f5.com
6572077Salx.manpages@gmail.com if (count == 0) {
6582077Salx.manpages@gmail.com goto no_ticket;
6591942Sa.suvorov@f5.com }
6601942Sa.suvorov@f5.com
6611942Sa.suvorov@f5.com #ifdef SSL_CTRL_SET_TLSEXT_TICKET_KEY_CB
6621942Sa.suvorov@f5.com
6631942Sa.suvorov@f5.com tickets = nxt_mp_get(mp, sizeof(nxt_tls_tickets_t)
6641942Sa.suvorov@f5.com + count * sizeof(nxt_tls_ticket_t));
6651942Sa.suvorov@f5.com if (nxt_slow_path(tickets == NULL)) {
6661942Sa.suvorov@f5.com return NXT_ERROR;
6671942Sa.suvorov@f5.com }
6681942Sa.suvorov@f5.com
6691942Sa.suvorov@f5.com tickets->count = count;
6701942Sa.suvorov@f5.com tls_init->conf->tickets = tickets;
6711942Sa.suvorov@f5.com i = 0;
6721942Sa.suvorov@f5.com
6731942Sa.suvorov@f5.com do {
6741942Sa.suvorov@f5.com ticket = &tickets->tickets[i];
6751942Sa.suvorov@f5.com
6761942Sa.suvorov@f5.com i++;
6771942Sa.suvorov@f5.com
6782077Salx.manpages@gmail.com member = nxt_conf_get_array_element_or_itself(tickets_conf, count - i);
6792077Salx.manpages@gmail.com if (member == NULL) {
6802077Salx.manpages@gmail.com break;
6811942Sa.suvorov@f5.com }
6821942Sa.suvorov@f5.com
6831942Sa.suvorov@f5.com nxt_conf_get_string(member, &value);
6841942Sa.suvorov@f5.com
6851975Svbart@nginx.com len = nxt_base64_decode(buf, value.start, value.length);
6861942Sa.suvorov@f5.com
6871952Svbart@nginx.com nxt_memcpy(ticket->name, buf, 16);
6881952Svbart@nginx.com
6891975Svbart@nginx.com if (len == 48) {
6901942Sa.suvorov@f5.com nxt_memcpy(ticket->aes_key, buf + 16, 16);
6911942Sa.suvorov@f5.com nxt_memcpy(ticket->hmac_key, buf + 32, 16);
6921952Svbart@nginx.com ticket->size = 16;
6931942Sa.suvorov@f5.com
6941942Sa.suvorov@f5.com } else {
6951942Sa.suvorov@f5.com nxt_memcpy(ticket->hmac_key, buf + 16, 32);
6961942Sa.suvorov@f5.com nxt_memcpy(ticket->aes_key, buf + 48, 32);
6971952Svbart@nginx.com ticket->size = 32;
6981942Sa.suvorov@f5.com }
6991942Sa.suvorov@f5.com
7001942Sa.suvorov@f5.com } while (i < count);
7011942Sa.suvorov@f5.com
7021942Sa.suvorov@f5.com if (SSL_CTX_set_tlsext_ticket_key_cb(ctx, nxt_tls_ticket_key_callback)
7031942Sa.suvorov@f5.com == 0)
7041942Sa.suvorov@f5.com {
7051942Sa.suvorov@f5.com nxt_openssl_log_error(task, NXT_LOG_ALERT,
7061942Sa.suvorov@f5.com "Unit was built with Session Tickets support, however, "
7071942Sa.suvorov@f5.com "now it is linked dynamically to an OpenSSL library "
7081942Sa.suvorov@f5.com "which has no tlsext support, therefore Session Tickets "
7091942Sa.suvorov@f5.com "are not available");
7101942Sa.suvorov@f5.com
7111942Sa.suvorov@f5.com return NXT_ERROR;
7121942Sa.suvorov@f5.com }
7131942Sa.suvorov@f5.com
7141942Sa.suvorov@f5.com return NXT_OK;
7151942Sa.suvorov@f5.com
7161942Sa.suvorov@f5.com #else
7171942Sa.suvorov@f5.com nxt_alert(task, "Setting custom session ticket keys is not supported with "
7181942Sa.suvorov@f5.com "this version of OpenSSL library");
7191942Sa.suvorov@f5.com
7201942Sa.suvorov@f5.com return NXT_ERROR;
7211942Sa.suvorov@f5.com
7221942Sa.suvorov@f5.com #endif
7231942Sa.suvorov@f5.com
7241942Sa.suvorov@f5.com no_ticket:
7251942Sa.suvorov@f5.com
7261942Sa.suvorov@f5.com SSL_CTX_set_options(ctx, SSL_OP_NO_TICKET);
7271942Sa.suvorov@f5.com
7281942Sa.suvorov@f5.com return NXT_OK;
7291942Sa.suvorov@f5.com }
7301942Sa.suvorov@f5.com
7311942Sa.suvorov@f5.com
7321942Sa.suvorov@f5.com #ifdef SSL_CTRL_SET_TLSEXT_TICKET_KEY_CB
7331942Sa.suvorov@f5.com
7341942Sa.suvorov@f5.com static int
7351942Sa.suvorov@f5.com nxt_tls_ticket_key_callback(SSL *s, unsigned char *name, unsigned char *iv,
7361942Sa.suvorov@f5.com EVP_CIPHER_CTX *ectx, HMAC_CTX *hctx, int enc)
7371942Sa.suvorov@f5.com {
7381942Sa.suvorov@f5.com nxt_uint_t i;
7391942Sa.suvorov@f5.com nxt_conn_t *c;
7401942Sa.suvorov@f5.com const EVP_MD *digest;
7411942Sa.suvorov@f5.com const EVP_CIPHER *cipher;
7421942Sa.suvorov@f5.com nxt_tls_ticket_t *ticket;
7431942Sa.suvorov@f5.com nxt_openssl_conn_t *tls;
7441942Sa.suvorov@f5.com
7451942Sa.suvorov@f5.com c = SSL_get_ex_data(s, nxt_openssl_connection_index);
7461942Sa.suvorov@f5.com
7471942Sa.suvorov@f5.com if (nxt_slow_path(c == NULL)) {
7481942Sa.suvorov@f5.com nxt_thread_log_alert("SSL_get_ex_data() failed");
7491942Sa.suvorov@f5.com return -1;
7501942Sa.suvorov@f5.com }
7511942Sa.suvorov@f5.com
7521942Sa.suvorov@f5.com tls = c->u.tls;
7531942Sa.suvorov@f5.com ticket = tls->conf->tickets->tickets;
7541942Sa.suvorov@f5.com
7551952Svbart@nginx.com i = 0;
7561942Sa.suvorov@f5.com
7571942Sa.suvorov@f5.com if (enc == 1) {
7581942Sa.suvorov@f5.com /* encrypt session ticket */
7591942Sa.suvorov@f5.com
7601942Sa.suvorov@f5.com nxt_debug(c->socket.task, "TLS session ticket encrypt");
7611942Sa.suvorov@f5.com
7621952Svbart@nginx.com cipher = (ticket[0].size == 16) ? EVP_aes_128_cbc() : EVP_aes_256_cbc();
7631942Sa.suvorov@f5.com
7641942Sa.suvorov@f5.com if (RAND_bytes(iv, EVP_CIPHER_iv_length(cipher)) != 1) {
7651942Sa.suvorov@f5.com nxt_openssl_log_error(c->socket.task, NXT_LOG_ALERT,
7661942Sa.suvorov@f5.com "RAND_bytes() failed");
7671942Sa.suvorov@f5.com return -1;
7681942Sa.suvorov@f5.com }
7691942Sa.suvorov@f5.com
7701942Sa.suvorov@f5.com nxt_memcpy(name, ticket[0].name, 16);
7711942Sa.suvorov@f5.com
7721967Sartem.konev@nginx.com if (EVP_EncryptInit_ex(ectx, cipher, NULL, ticket[0].aes_key, iv) != 1)
7731967Sartem.konev@nginx.com {
7741967Sartem.konev@nginx.com nxt_openssl_log_error(c->socket.task, NXT_LOG_ALERT,
7751967Sartem.konev@nginx.com "EVP_EncryptInit_ex() failed");
7761967Sartem.konev@nginx.com return -1;
7771967Sartem.konev@nginx.com }
7781967Sartem.konev@nginx.com
7791942Sa.suvorov@f5.com } else {
7801942Sa.suvorov@f5.com /* decrypt session ticket */
7811942Sa.suvorov@f5.com
7821952Svbart@nginx.com do {
7832231Salx@nginx.com if (memcmp(name, ticket[i].name, 16) == 0) {
7841942Sa.suvorov@f5.com goto found;
7851942Sa.suvorov@f5.com }
7861952Svbart@nginx.com
7871952Svbart@nginx.com } while (++i < tls->conf->tickets->count);
7881942Sa.suvorov@f5.com
7891942Sa.suvorov@f5.com nxt_debug(c->socket.task, "TLS session ticket decrypt, key not found");
7901942Sa.suvorov@f5.com
7911942Sa.suvorov@f5.com return 0;
7921942Sa.suvorov@f5.com
7931942Sa.suvorov@f5.com found:
7941942Sa.suvorov@f5.com
7951942Sa.suvorov@f5.com nxt_debug(c->socket.task,
7961942Sa.suvorov@f5.com "TLS session ticket decrypt, key number: \"%d\"", i);
7971942Sa.suvorov@f5.com
7981952Svbart@nginx.com enc = (i == 0) ? 1 : 2 /* renew */;
7991952Svbart@nginx.com
8001952Svbart@nginx.com cipher = (ticket[i].size == 16) ? EVP_aes_128_cbc() : EVP_aes_256_cbc();
8011942Sa.suvorov@f5.com
8021967Sartem.konev@nginx.com if (EVP_DecryptInit_ex(ectx, cipher, NULL, ticket[i].aes_key, iv) != 1)
8031967Sartem.konev@nginx.com {
8041967Sartem.konev@nginx.com nxt_openssl_log_error(c->socket.task, NXT_LOG_ALERT,
8051967Sartem.konev@nginx.com "EVP_DecryptInit_ex() failed");
8061967Sartem.konev@nginx.com return -1;
8071967Sartem.konev@nginx.com }
8081952Svbart@nginx.com }
8091942Sa.suvorov@f5.com
8101952Svbart@nginx.com #ifdef OPENSSL_NO_SHA256
8111952Svbart@nginx.com digest = EVP_sha1();
8121952Svbart@nginx.com #else
8131952Svbart@nginx.com digest = EVP_sha256();
8141952Svbart@nginx.com #endif
8151942Sa.suvorov@f5.com
8161952Svbart@nginx.com if (HMAC_Init_ex(hctx, ticket[i].hmac_key, ticket[i].size, digest, NULL)
8171952Svbart@nginx.com != 1)
8181952Svbart@nginx.com {
8191952Svbart@nginx.com nxt_openssl_log_error(c->socket.task, NXT_LOG_ALERT,
8201952Svbart@nginx.com "HMAC_Init_ex() failed");
8211952Svbart@nginx.com return -1;
8221952Svbart@nginx.com }
8231942Sa.suvorov@f5.com
8241952Svbart@nginx.com return enc;
8251942Sa.suvorov@f5.com }
8261942Sa.suvorov@f5.com
8271942Sa.suvorov@f5.com #endif /* SSL_CTRL_SET_TLSEXT_TICKET_KEY_CB */
8281942Sa.suvorov@f5.com
8291942Sa.suvorov@f5.com #endif /* NXT_HAVE_OPENSSL_TLSEXT */
8301942Sa.suvorov@f5.com
8311885Sa.suvorov@f5.com
8321920Sa.suvorov@f5.com static void
8331920Sa.suvorov@f5.com nxt_ssl_session_cache(SSL_CTX *ctx, size_t cache_size, time_t timeout)
8341920Sa.suvorov@f5.com {
8351920Sa.suvorov@f5.com if (cache_size == 0) {
8361920Sa.suvorov@f5.com SSL_CTX_set_session_cache_mode(ctx, SSL_SESS_CACHE_OFF);
8371920Sa.suvorov@f5.com return;
8381920Sa.suvorov@f5.com }
8391920Sa.suvorov@f5.com
8401920Sa.suvorov@f5.com SSL_CTX_set_session_cache_mode(ctx, SSL_SESS_CACHE_SERVER);
8411920Sa.suvorov@f5.com
8421920Sa.suvorov@f5.com SSL_CTX_sess_set_cache_size(ctx, cache_size);
8431920Sa.suvorov@f5.com
8441920Sa.suvorov@f5.com SSL_CTX_set_timeout(ctx, (long) timeout);
8451920Sa.suvorov@f5.com }
8461920Sa.suvorov@f5.com
8471920Sa.suvorov@f5.com
8481828Sa.suvorov@f5.com static nxt_uint_t
8491828Sa.suvorov@f5.com nxt_openssl_cert_get_names(nxt_task_t *task, X509 *cert, nxt_tls_conf_t *conf,
8501828Sa.suvorov@f5.com nxt_mp_t *mp)
8511828Sa.suvorov@f5.com {
8521828Sa.suvorov@f5.com int len;
8531828Sa.suvorov@f5.com nxt_str_t domain, str;
8541828Sa.suvorov@f5.com X509_NAME *x509_name;
8551828Sa.suvorov@f5.com nxt_uint_t i, n;
8561828Sa.suvorov@f5.com GENERAL_NAME *name;
8571828Sa.suvorov@f5.com nxt_tls_bundle_conf_t *bundle;
8581828Sa.suvorov@f5.com STACK_OF(GENERAL_NAME) *alt_names;
8591828Sa.suvorov@f5.com nxt_tls_bundle_hash_item_t *item;
8601828Sa.suvorov@f5.com
8611828Sa.suvorov@f5.com bundle = conf->bundle;
8621828Sa.suvorov@f5.com
8631828Sa.suvorov@f5.com alt_names = X509_get_ext_d2i(cert, NID_subject_alt_name, NULL, NULL);
8641828Sa.suvorov@f5.com
8651828Sa.suvorov@f5.com if (alt_names != NULL) {
8661828Sa.suvorov@f5.com n = sk_GENERAL_NAME_num(alt_names);
8671828Sa.suvorov@f5.com
8681828Sa.suvorov@f5.com for (i = 0; i != n; i++) {
8691828Sa.suvorov@f5.com name = sk_GENERAL_NAME_value(alt_names, i);
8701828Sa.suvorov@f5.com
8711828Sa.suvorov@f5.com if (name->type != GEN_DNS) {
8721828Sa.suvorov@f5.com continue;
8731828Sa.suvorov@f5.com }
8741828Sa.suvorov@f5.com
8751828Sa.suvorov@f5.com str.length = ASN1_STRING_length(name->d.dNSName);
8761828Sa.suvorov@f5.com #if OPENSSL_VERSION_NUMBER > 0x10100000L
8771828Sa.suvorov@f5.com str.start = (u_char *) ASN1_STRING_get0_data(name->d.dNSName);
8781828Sa.suvorov@f5.com #else
8791828Sa.suvorov@f5.com str.start = ASN1_STRING_data(name->d.dNSName);
8801828Sa.suvorov@f5.com #endif
8811828Sa.suvorov@f5.com
8821828Sa.suvorov@f5.com domain.start = nxt_mp_nget(mp, str.length);
8831828Sa.suvorov@f5.com if (nxt_slow_path(domain.start == NULL)) {
8841828Sa.suvorov@f5.com goto fail;
8851828Sa.suvorov@f5.com }
8861828Sa.suvorov@f5.com
8871828Sa.suvorov@f5.com domain.length = str.length;
8881828Sa.suvorov@f5.com nxt_memcpy_lowcase(domain.start, str.start, str.length);
8891828Sa.suvorov@f5.com
8901828Sa.suvorov@f5.com item = nxt_mp_get(mp, sizeof(nxt_tls_bundle_hash_item_t));
8911828Sa.suvorov@f5.com if (nxt_slow_path(item == NULL)) {
8921828Sa.suvorov@f5.com goto fail;
8931828Sa.suvorov@f5.com }
8941828Sa.suvorov@f5.com
8951828Sa.suvorov@f5.com item->name = domain;
8961828Sa.suvorov@f5.com item->bundle = bundle;
8971828Sa.suvorov@f5.com
8981828Sa.suvorov@f5.com if (nxt_openssl_bundle_hash_insert(task, &conf->bundle_hash,
8991828Sa.suvorov@f5.com item, mp)
9001828Sa.suvorov@f5.com == NXT_ERROR)
9011828Sa.suvorov@f5.com {
9021828Sa.suvorov@f5.com goto fail;
9031828Sa.suvorov@f5.com }
9041828Sa.suvorov@f5.com }
9051828Sa.suvorov@f5.com
9061828Sa.suvorov@f5.com sk_GENERAL_NAME_pop_free(alt_names, GENERAL_NAME_free);
9071828Sa.suvorov@f5.com
9081828Sa.suvorov@f5.com } else {
9091828Sa.suvorov@f5.com x509_name = X509_get_subject_name(cert);
9101828Sa.suvorov@f5.com len = X509_NAME_get_text_by_NID(x509_name, NID_commonName,
9111828Sa.suvorov@f5.com NULL, 0);
9121828Sa.suvorov@f5.com if (len <= 0) {
9131828Sa.suvorov@f5.com nxt_log(task, NXT_LOG_WARN, "certificate \"%V\" has neither "
9141885Sa.suvorov@f5.com "Subject Alternative Name nor Common Name", &bundle->name);
9151828Sa.suvorov@f5.com return NXT_OK;
9161828Sa.suvorov@f5.com }
9171828Sa.suvorov@f5.com
9181828Sa.suvorov@f5.com domain.start = nxt_mp_nget(mp, len + 1);
9191828Sa.suvorov@f5.com if (nxt_slow_path(domain.start == NULL)) {
9201828Sa.suvorov@f5.com return NXT_ERROR;
9211828Sa.suvorov@f5.com }
9221828Sa.suvorov@f5.com
9231828Sa.suvorov@f5.com domain.length = X509_NAME_get_text_by_NID(x509_name, NID_commonName,
9241828Sa.suvorov@f5.com (char *) domain.start,
9251828Sa.suvorov@f5.com len + 1);
9261828Sa.suvorov@f5.com nxt_memcpy_lowcase(domain.start, domain.start, domain.length);
9271828Sa.suvorov@f5.com
9281828Sa.suvorov@f5.com item = nxt_mp_get(mp, sizeof(nxt_tls_bundle_hash_item_t));
9291828Sa.suvorov@f5.com if (nxt_slow_path(item == NULL)) {
9301828Sa.suvorov@f5.com return NXT_ERROR;
9311828Sa.suvorov@f5.com }
9321828Sa.suvorov@f5.com
9331828Sa.suvorov@f5.com item->name = domain;
9341828Sa.suvorov@f5.com item->bundle = bundle;
9351828Sa.suvorov@f5.com
9361828Sa.suvorov@f5.com if (nxt_openssl_bundle_hash_insert(task, &conf->bundle_hash, item,
9371828Sa.suvorov@f5.com mp)
9381828Sa.suvorov@f5.com == NXT_ERROR)
9391828Sa.suvorov@f5.com {
9401828Sa.suvorov@f5.com return NXT_ERROR;
9411828Sa.suvorov@f5.com }
9421828Sa.suvorov@f5.com }
9431828Sa.suvorov@f5.com
9441828Sa.suvorov@f5.com return NXT_OK;
9451828Sa.suvorov@f5.com
9461828Sa.suvorov@f5.com fail:
9471828Sa.suvorov@f5.com
9481828Sa.suvorov@f5.com sk_GENERAL_NAME_pop_free(alt_names, GENERAL_NAME_free);
9491828Sa.suvorov@f5.com
9501828Sa.suvorov@f5.com return NXT_ERROR;
9511828Sa.suvorov@f5.com }
9521828Sa.suvorov@f5.com
9531828Sa.suvorov@f5.com
9541828Sa.suvorov@f5.com static const nxt_lvlhsh_proto_t nxt_openssl_bundle_hash_proto
9551828Sa.suvorov@f5.com nxt_aligned(64) =
9561828Sa.suvorov@f5.com {
9571828Sa.suvorov@f5.com NXT_LVLHSH_DEFAULT,
9581828Sa.suvorov@f5.com nxt_openssl_bundle_hash_test,
9591828Sa.suvorov@f5.com nxt_mp_lvlhsh_alloc,
9601828Sa.suvorov@f5.com nxt_mp_lvlhsh_free,
9611828Sa.suvorov@f5.com };
9621828Sa.suvorov@f5.com
9631828Sa.suvorov@f5.com
9641828Sa.suvorov@f5.com static nxt_int_t
9651828Sa.suvorov@f5.com nxt_openssl_bundle_hash_test(nxt_lvlhsh_query_t *lhq, void *data)
9661828Sa.suvorov@f5.com {
9671828Sa.suvorov@f5.com nxt_tls_bundle_hash_item_t *item;
9681828Sa.suvorov@f5.com
9691828Sa.suvorov@f5.com item = data;
9701828Sa.suvorov@f5.com
9711828Sa.suvorov@f5.com return nxt_strstr_eq(&lhq->key, &item->name) ? NXT_OK : NXT_DECLINED;
9721828Sa.suvorov@f5.com }
9731828Sa.suvorov@f5.com
9741828Sa.suvorov@f5.com
9751828Sa.suvorov@f5.com static nxt_int_t
9761828Sa.suvorov@f5.com nxt_openssl_bundle_hash_insert(nxt_task_t *task, nxt_lvlhsh_t *lvlhsh,
9771828Sa.suvorov@f5.com nxt_tls_bundle_hash_item_t *item, nxt_mp_t *mp)
9781828Sa.suvorov@f5.com {
9791828Sa.suvorov@f5.com nxt_str_t str;
9801828Sa.suvorov@f5.com nxt_int_t ret;
9811828Sa.suvorov@f5.com nxt_lvlhsh_query_t lhq;
9821828Sa.suvorov@f5.com nxt_tls_bundle_hash_item_t *old;
9831828Sa.suvorov@f5.com
9841828Sa.suvorov@f5.com str = item->name;
9851828Sa.suvorov@f5.com
9861828Sa.suvorov@f5.com if (item->name.start[0] == '*') {
9871828Sa.suvorov@f5.com item->name.start++;
9881828Sa.suvorov@f5.com item->name.length--;
9891828Sa.suvorov@f5.com
9901828Sa.suvorov@f5.com if (item->name.length == 0 || item->name.start[0] != '.') {
9911828Sa.suvorov@f5.com nxt_log(task, NXT_LOG_WARN, "ignored invalid name \"%V\" "
9921828Sa.suvorov@f5.com "in certificate \"%V\": missing \".\" "
9931885Sa.suvorov@f5.com "after wildcard symbol", &str, &item->bundle->name);
9941828Sa.suvorov@f5.com return NXT_OK;
9951828Sa.suvorov@f5.com }
9961828Sa.suvorov@f5.com }
9971828Sa.suvorov@f5.com
9981828Sa.suvorov@f5.com lhq.pool = mp;
9991828Sa.suvorov@f5.com lhq.key = item->name;
10001828Sa.suvorov@f5.com lhq.value = item;
10011828Sa.suvorov@f5.com lhq.proto = &nxt_openssl_bundle_hash_proto;
10021828Sa.suvorov@f5.com lhq.replace = 0;
10031828Sa.suvorov@f5.com lhq.key_hash = nxt_murmur_hash2(item->name.start, item->name.length);
10041828Sa.suvorov@f5.com
10051828Sa.suvorov@f5.com ret = nxt_lvlhsh_insert(lvlhsh, &lhq);
10061828Sa.suvorov@f5.com if (nxt_fast_path(ret == NXT_OK)) {
10071828Sa.suvorov@f5.com nxt_debug(task, "name \"%V\" for certificate \"%V\" is inserted",
10081885Sa.suvorov@f5.com &str, &item->bundle->name);
10091828Sa.suvorov@f5.com return NXT_OK;
10101828Sa.suvorov@f5.com }
10111828Sa.suvorov@f5.com
10121828Sa.suvorov@f5.com if (nxt_fast_path(ret == NXT_DECLINED)) {
10131828Sa.suvorov@f5.com old = lhq.value;
10141828Sa.suvorov@f5.com if (old->bundle != item->bundle) {
10151828Sa.suvorov@f5.com nxt_log(task, NXT_LOG_WARN, "ignored duplicate name \"%V\" "
10161828Sa.suvorov@f5.com "in certificate \"%V\", identical name appears in \"%V\"",
10171885Sa.suvorov@f5.com &str, &old->bundle->name, &item->bundle->name);
10181828Sa.suvorov@f5.com
10191828Sa.suvorov@f5.com old->bundle = item->bundle;
10201828Sa.suvorov@f5.com }
10211828Sa.suvorov@f5.com
10221828Sa.suvorov@f5.com return NXT_OK;
10231828Sa.suvorov@f5.com }
10241828Sa.suvorov@f5.com
10251828Sa.suvorov@f5.com return NXT_ERROR;
10261828Sa.suvorov@f5.com }
10271828Sa.suvorov@f5.com
10281828Sa.suvorov@f5.com
10291828Sa.suvorov@f5.com static nxt_int_t
10301828Sa.suvorov@f5.com nxt_openssl_servername(SSL *s, int *ad, void *arg)
10311828Sa.suvorov@f5.com {
10321828Sa.suvorov@f5.com nxt_str_t str;
10331828Sa.suvorov@f5.com nxt_uint_t i;
10341828Sa.suvorov@f5.com nxt_conn_t *c;
10351828Sa.suvorov@f5.com const char *servername;
10361828Sa.suvorov@f5.com nxt_tls_conf_t *conf;
10371828Sa.suvorov@f5.com nxt_openssl_conn_t *tls;
10381828Sa.suvorov@f5.com nxt_tls_bundle_conf_t *bundle;
10391828Sa.suvorov@f5.com
10401828Sa.suvorov@f5.com c = SSL_get_ex_data(s, nxt_openssl_connection_index);
10411828Sa.suvorov@f5.com
10421828Sa.suvorov@f5.com if (nxt_slow_path(c == NULL)) {
10431828Sa.suvorov@f5.com nxt_thread_log_alert("SSL_get_ex_data() failed");
10441828Sa.suvorov@f5.com return SSL_TLSEXT_ERR_ALERT_FATAL;
10451828Sa.suvorov@f5.com }
10461828Sa.suvorov@f5.com
10471828Sa.suvorov@f5.com servername = SSL_get_servername(s, TLSEXT_NAMETYPE_host_name);
10481921Sa.suvorov@f5.com
10491921Sa.suvorov@f5.com if (servername == NULL) {
10501921Sa.suvorov@f5.com nxt_debug(c->socket.task, "SSL_get_servername(): NULL");
10511921Sa.suvorov@f5.com goto done;
10521828Sa.suvorov@f5.com }
10531828Sa.suvorov@f5.com
10541828Sa.suvorov@f5.com str.length = nxt_strlen(servername);
10551828Sa.suvorov@f5.com if (str.length == 0) {
10561921Sa.suvorov@f5.com nxt_debug(c->socket.task, "SSL_get_servername(): \"\" is empty");
10571828Sa.suvorov@f5.com goto done;
10581828Sa.suvorov@f5.com }
10591828Sa.suvorov@f5.com
10601828Sa.suvorov@f5.com if (servername[0] == '.') {
10611828Sa.suvorov@f5.com nxt_debug(c->socket.task, "ignored the server name \"%s\": "
10621828Sa.suvorov@f5.com "leading \".\"", servername);
10631828Sa.suvorov@f5.com goto done;
10641828Sa.suvorov@f5.com }
10651828Sa.suvorov@f5.com
10661828Sa.suvorov@f5.com nxt_debug(c->socket.task, "tls with servername \"%s\"", servername);
10671828Sa.suvorov@f5.com
10681828Sa.suvorov@f5.com str.start = nxt_mp_nget(c->mem_pool, str.length);
10691828Sa.suvorov@f5.com if (nxt_slow_path(str.start == NULL)) {
10701828Sa.suvorov@f5.com return SSL_TLSEXT_ERR_ALERT_FATAL;
10711828Sa.suvorov@f5.com }
10721828Sa.suvorov@f5.com
10731828Sa.suvorov@f5.com nxt_memcpy_lowcase(str.start, (const u_char *) servername, str.length);
10741828Sa.suvorov@f5.com
10751828Sa.suvorov@f5.com tls = c->u.tls;
10761828Sa.suvorov@f5.com conf = tls->conf;
10771828Sa.suvorov@f5.com
10781828Sa.suvorov@f5.com bundle = nxt_openssl_find_ctx(conf, &str);
10791828Sa.suvorov@f5.com
10801828Sa.suvorov@f5.com if (bundle == NULL) {
10811828Sa.suvorov@f5.com for (i = 1; i < str.length; i++) {
10821828Sa.suvorov@f5.com if (str.start[i] == '.') {
10831828Sa.suvorov@f5.com str.start += i;
10841828Sa.suvorov@f5.com str.length -= i;
10851828Sa.suvorov@f5.com
10861828Sa.suvorov@f5.com bundle = nxt_openssl_find_ctx(conf, &str);
10871828Sa.suvorov@f5.com break;
10881828Sa.suvorov@f5.com }
10891828Sa.suvorov@f5.com }
10901828Sa.suvorov@f5.com }
10911828Sa.suvorov@f5.com
10921828Sa.suvorov@f5.com if (bundle != NULL) {
10931828Sa.suvorov@f5.com nxt_debug(c->socket.task, "new tls context found for \"%V\": \"%V\" "
10941885Sa.suvorov@f5.com "(old: \"%V\")", &str, &bundle->name,
10951885Sa.suvorov@f5.com &conf->bundle->name);
10961828Sa.suvorov@f5.com
10971828Sa.suvorov@f5.com if (bundle != conf->bundle) {
10981828Sa.suvorov@f5.com if (SSL_set_SSL_CTX(s, bundle->ctx) == NULL) {
10991828Sa.suvorov@f5.com nxt_openssl_log_error(c->socket.task, NXT_LOG_ALERT,
11001828Sa.suvorov@f5.com "SSL_set_SSL_CTX() failed");
11011828Sa.suvorov@f5.com
11021828Sa.suvorov@f5.com return SSL_TLSEXT_ERR_ALERT_FATAL;
11031828Sa.suvorov@f5.com }
11041828Sa.suvorov@f5.com }
11051828Sa.suvorov@f5.com }
11061828Sa.suvorov@f5.com
11071828Sa.suvorov@f5.com done:
11081828Sa.suvorov@f5.com
11091828Sa.suvorov@f5.com return SSL_TLSEXT_ERR_OK;
11101828Sa.suvorov@f5.com }
11111828Sa.suvorov@f5.com
11121828Sa.suvorov@f5.com
11131828Sa.suvorov@f5.com static nxt_tls_bundle_conf_t *
11141828Sa.suvorov@f5.com nxt_openssl_find_ctx(nxt_tls_conf_t *conf, nxt_str_t *sn)
11151828Sa.suvorov@f5.com {
11161828Sa.suvorov@f5.com nxt_int_t ret;
11171828Sa.suvorov@f5.com nxt_lvlhsh_query_t lhq;
11181828Sa.suvorov@f5.com nxt_tls_bundle_hash_item_t *item;
11191828Sa.suvorov@f5.com
11201828Sa.suvorov@f5.com lhq.key_hash = nxt_murmur_hash2(sn->start, sn->length);
11211828Sa.suvorov@f5.com lhq.key = *sn;
11221828Sa.suvorov@f5.com lhq.proto = &nxt_openssl_bundle_hash_proto;
11231828Sa.suvorov@f5.com
11241828Sa.suvorov@f5.com ret = nxt_lvlhsh_find(&conf->bundle_hash, &lhq);
11251828Sa.suvorov@f5.com if (ret != NXT_OK) {
11261828Sa.suvorov@f5.com return NULL;
11271828Sa.suvorov@f5.com }
11281828Sa.suvorov@f5.com
11291828Sa.suvorov@f5.com item = lhq.value;
11301828Sa.suvorov@f5.com
11311828Sa.suvorov@f5.com return item->bundle;
11321828Sa.suvorov@f5.com }
11331828Sa.suvorov@f5.com
11341828Sa.suvorov@f5.com
11350Sigor@sysoev.ru static void
1136771Sigor@sysoev.ru nxt_openssl_server_free(nxt_task_t *task, nxt_tls_conf_t *conf)
11370Sigor@sysoev.ru {
11381828Sa.suvorov@f5.com nxt_tls_bundle_conf_t *bundle;
11391828Sa.suvorov@f5.com
11401828Sa.suvorov@f5.com bundle = conf->bundle;
11411828Sa.suvorov@f5.com nxt_assert(bundle != NULL);
11421828Sa.suvorov@f5.com
11431828Sa.suvorov@f5.com do {
11441828Sa.suvorov@f5.com SSL_CTX_free(bundle->ctx);
11451828Sa.suvorov@f5.com bundle = bundle->next;
11461828Sa.suvorov@f5.com } while (bundle != NULL);
11471818Smax.romanov@nginx.com
11481942Sa.suvorov@f5.com if (conf->tickets) {
11491942Sa.suvorov@f5.com nxt_memzero(conf->tickets->tickets,
11501942Sa.suvorov@f5.com conf->tickets->count * sizeof(nxt_tls_ticket_t));
11511942Sa.suvorov@f5.com }
11521942Sa.suvorov@f5.com
11531818Smax.romanov@nginx.com #if (OPENSSL_VERSION_NUMBER >= 0x1010100fL \
11541818Smax.romanov@nginx.com && OPENSSL_VERSION_NUMBER < 0x1010101fL)
11551818Smax.romanov@nginx.com RAND_keep_random_devices_open(0);
11561818Smax.romanov@nginx.com #endif
1157771Sigor@sysoev.ru }
1158771Sigor@sysoev.ru
1159771Sigor@sysoev.ru
1160771Sigor@sysoev.ru static void
1161771Sigor@sysoev.ru nxt_openssl_conn_init(nxt_task_t *task, nxt_tls_conf_t *conf, nxt_conn_t *c)
1162771Sigor@sysoev.ru {
1163771Sigor@sysoev.ru int ret;
1164771Sigor@sysoev.ru SSL *s;
1165771Sigor@sysoev.ru SSL_CTX *ctx;
1166771Sigor@sysoev.ru nxt_openssl_conn_t *tls;
11670Sigor@sysoev.ru
11680Sigor@sysoev.ru nxt_log_debug(c->socket.log, "openssl conn init");
11690Sigor@sysoev.ru
1170771Sigor@sysoev.ru tls = nxt_mp_zget(c->mem_pool, sizeof(nxt_openssl_conn_t));
1171771Sigor@sysoev.ru if (tls == NULL) {
11720Sigor@sysoev.ru goto fail;
11730Sigor@sysoev.ru }
11740Sigor@sysoev.ru
1175771Sigor@sysoev.ru c->u.tls = tls;
1176771Sigor@sysoev.ru nxt_buf_mem_set_size(&tls->buffer, conf->buffer_size);
11770Sigor@sysoev.ru
11781828Sa.suvorov@f5.com ctx = conf->bundle->ctx;
11790Sigor@sysoev.ru
11800Sigor@sysoev.ru s = SSL_new(ctx);
11810Sigor@sysoev.ru if (s == NULL) {
1182771Sigor@sysoev.ru nxt_openssl_log_error(task, NXT_LOG_ALERT, "SSL_new() failed");
11830Sigor@sysoev.ru goto fail;
11840Sigor@sysoev.ru }
11850Sigor@sysoev.ru
1186771Sigor@sysoev.ru tls->session = s;
11871828Sa.suvorov@f5.com /* To pass TLS config to the nxt_openssl_servername() callback. */
11881828Sa.suvorov@f5.com tls->conf = conf;
1189771Sigor@sysoev.ru tls->conn = c;
11900Sigor@sysoev.ru
11910Sigor@sysoev.ru ret = SSL_set_fd(s, c->socket.fd);
11920Sigor@sysoev.ru
11930Sigor@sysoev.ru if (ret == 0) {
1194771Sigor@sysoev.ru nxt_openssl_log_error(task, NXT_LOG_ALERT, "SSL_set_fd(%d) failed",
1195771Sigor@sysoev.ru c->socket.fd);
11960Sigor@sysoev.ru goto fail;
11970Sigor@sysoev.ru }
11980Sigor@sysoev.ru
11990Sigor@sysoev.ru SSL_set_accept_state(s);
12000Sigor@sysoev.ru
12010Sigor@sysoev.ru if (SSL_set_ex_data(s, nxt_openssl_connection_index, c) == 0) {
1202771Sigor@sysoev.ru nxt_openssl_log_error(task, NXT_LOG_ALERT, "SSL_set_ex_data() failed");
12030Sigor@sysoev.ru goto fail;
12040Sigor@sysoev.ru }
12050Sigor@sysoev.ru
120662Sigor@sysoev.ru c->io = &nxt_openssl_conn_io;
12070Sigor@sysoev.ru c->sendfile = NXT_CONN_SENDFILE_OFF;
12080Sigor@sysoev.ru
12091Sigor@sysoev.ru nxt_openssl_conn_handshake(task, c, c->socket.data);
12101884Sa.suvorov@f5.com
12110Sigor@sysoev.ru return;
12120Sigor@sysoev.ru
12130Sigor@sysoev.ru fail:
12140Sigor@sysoev.ru
121513Sigor@sysoev.ru nxt_work_queue_add(c->read_work_queue, c->read_state->error_handler,
121613Sigor@sysoev.ru task, c, c->socket.data);
12170Sigor@sysoev.ru }
12180Sigor@sysoev.ru
12190Sigor@sysoev.ru
1220771Sigor@sysoev.ru nxt_inline void
1221836Sigor@sysoev.ru nxt_openssl_conn_free(nxt_task_t *task, nxt_conn_t *c)
12220Sigor@sysoev.ru {
1223836Sigor@sysoev.ru nxt_openssl_conn_t *tls;
1224836Sigor@sysoev.ru
1225771Sigor@sysoev.ru nxt_debug(task, "openssl conn free");
12260Sigor@sysoev.ru
1227836Sigor@sysoev.ru tls = c->u.tls;
12280Sigor@sysoev.ru
1229836Sigor@sysoev.ru if (tls != NULL) {
1230836Sigor@sysoev.ru c->u.tls = NULL;
1231836Sigor@sysoev.ru nxt_free(tls->buffer.start);
1232836Sigor@sysoev.ru SSL_free(tls->session);
1233836Sigor@sysoev.ru }
12340Sigor@sysoev.ru }
12350Sigor@sysoev.ru
12360Sigor@sysoev.ru
12370Sigor@sysoev.ru static void
12381Sigor@sysoev.ru nxt_openssl_conn_handshake(nxt_task_t *task, void *obj, void *data)
12390Sigor@sysoev.ru {
1240771Sigor@sysoev.ru int ret;
1241771Sigor@sysoev.ru nxt_int_t n;
1242771Sigor@sysoev.ru nxt_err_t err;
1243771Sigor@sysoev.ru nxt_conn_t *c;
1244771Sigor@sysoev.ru nxt_work_queue_t *wq;
1245771Sigor@sysoev.ru nxt_work_handler_t handler;
1246771Sigor@sysoev.ru nxt_openssl_conn_t *tls;
1247771Sigor@sysoev.ru const nxt_conn_state_t *state;
12480Sigor@sysoev.ru
12490Sigor@sysoev.ru c = obj;
1250836Sigor@sysoev.ru
1251836Sigor@sysoev.ru nxt_debug(task, "openssl conn handshake fd:%d", c->socket.fd);
1252836Sigor@sysoev.ru
1253836Sigor@sysoev.ru if (c->socket.error != 0) {
1254836Sigor@sysoev.ru return;
1255836Sigor@sysoev.ru }
1256836Sigor@sysoev.ru
1257771Sigor@sysoev.ru tls = c->u.tls;
12580Sigor@sysoev.ru
1259836Sigor@sysoev.ru if (tls == NULL) {
1260836Sigor@sysoev.ru return;
1261836Sigor@sysoev.ru }
1262836Sigor@sysoev.ru
1263836Sigor@sysoev.ru nxt_debug(task, "openssl conn handshake: %d times", tls->times);
12640Sigor@sysoev.ru
1265771Sigor@sysoev.ru /* "tls->times == 1" is suitable to run SSL_do_handshake() in job. */
12660Sigor@sysoev.ru
1267771Sigor@sysoev.ru ret = SSL_do_handshake(tls->session);
12680Sigor@sysoev.ru
12690Sigor@sysoev.ru err = (ret <= 0) ? nxt_socket_errno : 0;
12700Sigor@sysoev.ru
12711Sigor@sysoev.ru nxt_thread_time_debug_update(task->thread);
12720Sigor@sysoev.ru
12731Sigor@sysoev.ru nxt_debug(task, "SSL_do_handshake(%d): %d err:%d", c->socket.fd, ret, err);
12740Sigor@sysoev.ru
1275771Sigor@sysoev.ru state = (c->read_state != NULL) ? c->read_state : c->write_state;
1276771Sigor@sysoev.ru
12770Sigor@sysoev.ru if (ret > 0) {
12780Sigor@sysoev.ru /* ret == 1, the handshake was successfully completed. */
1279771Sigor@sysoev.ru tls->handshake = 1;
12800Sigor@sysoev.ru
1281771Sigor@sysoev.ru if (c->read_state != NULL) {
1282771Sigor@sysoev.ru if (state->io_read_handler != NULL || c->read != NULL) {
1283771Sigor@sysoev.ru nxt_conn_read(task->thread->engine, c);
12840Sigor@sysoev.ru return;
12850Sigor@sysoev.ru }
12860Sigor@sysoev.ru
1287771Sigor@sysoev.ru } else {
1288771Sigor@sysoev.ru if (c->write != NULL) {
1289771Sigor@sysoev.ru nxt_conn_write(task->thread->engine, c);
1290771Sigor@sysoev.ru return;
1291771Sigor@sysoev.ru }
1292771Sigor@sysoev.ru }
1293771Sigor@sysoev.ru
1294771Sigor@sysoev.ru handler = state->ready_handler;
1295771Sigor@sysoev.ru
1296771Sigor@sysoev.ru } else {
1297771Sigor@sysoev.ru c->socket.read_handler = nxt_openssl_conn_handshake;
1298771Sigor@sysoev.ru c->socket.write_handler = nxt_openssl_conn_handshake;
1299771Sigor@sysoev.ru
1300771Sigor@sysoev.ru n = nxt_openssl_conn_test_error(task, c, ret, err,
1301771Sigor@sysoev.ru NXT_OPENSSL_HANDSHAKE);
1302771Sigor@sysoev.ru switch (n) {
13030Sigor@sysoev.ru
1304771Sigor@sysoev.ru case NXT_AGAIN:
1305771Sigor@sysoev.ru if (tls->ssl_error == SSL_ERROR_WANT_READ && tls->times < 2) {
1306771Sigor@sysoev.ru tls->times++;
1307771Sigor@sysoev.ru }
1308771Sigor@sysoev.ru
1309771Sigor@sysoev.ru return;
1310771Sigor@sysoev.ru
1311771Sigor@sysoev.ru case 0:
1312771Sigor@sysoev.ru handler = state->close_handler;
1313771Sigor@sysoev.ru break;
1314771Sigor@sysoev.ru
1315771Sigor@sysoev.ru default:
1316771Sigor@sysoev.ru case NXT_ERROR:
1317771Sigor@sysoev.ru nxt_openssl_conn_error(task, err, "SSL_do_handshake(%d) failed",
1318771Sigor@sysoev.ru c->socket.fd);
1319771Sigor@sysoev.ru
1320771Sigor@sysoev.ru handler = state->error_handler;
1321771Sigor@sysoev.ru break;
13220Sigor@sysoev.ru }
13230Sigor@sysoev.ru }
13240Sigor@sysoev.ru
1325771Sigor@sysoev.ru wq = (c->read_state != NULL) ? c->read_work_queue : c->write_work_queue;
1326771Sigor@sysoev.ru
1327771Sigor@sysoev.ru nxt_work_queue_add(wq, handler, task, c, data);
13280Sigor@sysoev.ru }
13290Sigor@sysoev.ru
13300Sigor@sysoev.ru
13310Sigor@sysoev.ru static ssize_t
1332771Sigor@sysoev.ru nxt_openssl_conn_io_recvbuf(nxt_conn_t *c, nxt_buf_t *b)
13330Sigor@sysoev.ru {
1334771Sigor@sysoev.ru int ret;
1335771Sigor@sysoev.ru size_t size;
1336771Sigor@sysoev.ru nxt_int_t n;
1337771Sigor@sysoev.ru nxt_err_t err;
1338771Sigor@sysoev.ru nxt_openssl_conn_t *tls;
1339771Sigor@sysoev.ru
1340771Sigor@sysoev.ru tls = c->u.tls;
1341771Sigor@sysoev.ru size = b->mem.end - b->mem.free;
1342771Sigor@sysoev.ru
1343771Sigor@sysoev.ru ret = SSL_read(tls->session, b->mem.free, size);
1344771Sigor@sysoev.ru
1345771Sigor@sysoev.ru err = (ret <= 0) ? nxt_socket_errno : 0;
1346771Sigor@sysoev.ru
1347771Sigor@sysoev.ru nxt_debug(c->socket.task, "SSL_read(%d, %p, %uz): %d err:%d",
1348771Sigor@sysoev.ru c->socket.fd, b->mem.free, size, ret, err);
13490Sigor@sysoev.ru
1350771Sigor@sysoev.ru if (ret > 0) {
1351771Sigor@sysoev.ru return ret;
1352771Sigor@sysoev.ru }
13530Sigor@sysoev.ru
1354771Sigor@sysoev.ru n = nxt_openssl_conn_test_error(c->socket.task, c, ret, err,
1355771Sigor@sysoev.ru NXT_OPENSSL_READ);
1356771Sigor@sysoev.ru if (n == NXT_ERROR) {
1357771Sigor@sysoev.ru nxt_openssl_conn_error(c->socket.task, err,
1358771Sigor@sysoev.ru "SSL_read(%d, %p, %uz) failed",
1359771Sigor@sysoev.ru c->socket.fd, b->mem.free, size);
1360771Sigor@sysoev.ru }
13610Sigor@sysoev.ru
1362771Sigor@sysoev.ru return n;
13630Sigor@sysoev.ru }
13640Sigor@sysoev.ru
13650Sigor@sysoev.ru
13660Sigor@sysoev.ru static ssize_t
1367771Sigor@sysoev.ru nxt_openssl_conn_io_sendbuf(nxt_task_t *task, nxt_sendbuf_t *sb)
1368771Sigor@sysoev.ru {
1369771Sigor@sysoev.ru nxt_uint_t niov;
1370771Sigor@sysoev.ru struct iovec iov;
1371771Sigor@sysoev.ru
1372771Sigor@sysoev.ru niov = nxt_sendbuf_mem_coalesce0(task, sb, &iov, 1);
1373771Sigor@sysoev.ru
1374771Sigor@sysoev.ru if (niov == 0 && sb->sync) {
1375771Sigor@sysoev.ru return 0;
1376771Sigor@sysoev.ru }
1377771Sigor@sysoev.ru
1378771Sigor@sysoev.ru return nxt_openssl_conn_io_send(task, sb, iov.iov_base, iov.iov_len);
1379771Sigor@sysoev.ru }
1380771Sigor@sysoev.ru
1381771Sigor@sysoev.ru
1382771Sigor@sysoev.ru static ssize_t
1383771Sigor@sysoev.ru nxt_openssl_conn_io_send(nxt_task_t *task, nxt_sendbuf_t *sb, void *buf,
1384771Sigor@sysoev.ru size_t size)
13850Sigor@sysoev.ru {
13860Sigor@sysoev.ru int ret;
13870Sigor@sysoev.ru nxt_err_t err;
13880Sigor@sysoev.ru nxt_int_t n;
1389771Sigor@sysoev.ru nxt_conn_t *c;
1390771Sigor@sysoev.ru nxt_openssl_conn_t *tls;
13910Sigor@sysoev.ru
1392771Sigor@sysoev.ru tls = sb->tls;
13930Sigor@sysoev.ru
1394771Sigor@sysoev.ru ret = SSL_write(tls->session, buf, size);
13950Sigor@sysoev.ru
13961212Sigor@sysoev.ru err = (ret <= 0) ? nxt_socket_errno : 0;
13970Sigor@sysoev.ru
1398771Sigor@sysoev.ru nxt_debug(task, "SSL_write(%d, %p, %uz): %d err:%d",
1399771Sigor@sysoev.ru sb->socket, buf, size, ret, err);
14000Sigor@sysoev.ru
14010Sigor@sysoev.ru if (ret > 0) {
14020Sigor@sysoev.ru return ret;
14030Sigor@sysoev.ru }
14040Sigor@sysoev.ru
1405771Sigor@sysoev.ru c = tls->conn;
1406771Sigor@sysoev.ru c->socket.write_ready = sb->ready;
1407771Sigor@sysoev.ru
1408771Sigor@sysoev.ru n = nxt_openssl_conn_test_error(task, c, ret, err, NXT_OPENSSL_WRITE);
1409771Sigor@sysoev.ru
1410771Sigor@sysoev.ru sb->ready = c->socket.write_ready;
14110Sigor@sysoev.ru
14120Sigor@sysoev.ru if (n == NXT_ERROR) {
14131212Sigor@sysoev.ru sb->error = c->socket.error;
1414771Sigor@sysoev.ru nxt_openssl_conn_error(task, err, "SSL_write(%d, %p, %uz) failed",
1415771Sigor@sysoev.ru sb->socket, buf, size);
14160Sigor@sysoev.ru }
14170Sigor@sysoev.ru
14180Sigor@sysoev.ru return n;
14190Sigor@sysoev.ru }
14200Sigor@sysoev.ru
14210Sigor@sysoev.ru
14220Sigor@sysoev.ru static void
14231Sigor@sysoev.ru nxt_openssl_conn_io_shutdown(nxt_task_t *task, void *obj, void *data)
14240Sigor@sysoev.ru {
14250Sigor@sysoev.ru int ret, mode;
14260Sigor@sysoev.ru SSL *s;
14270Sigor@sysoev.ru nxt_err_t err;
14280Sigor@sysoev.ru nxt_int_t n;
14290Sigor@sysoev.ru nxt_bool_t quiet, once;
143062Sigor@sysoev.ru nxt_conn_t *c;
1431771Sigor@sysoev.ru nxt_openssl_conn_t *tls;
14320Sigor@sysoev.ru nxt_work_handler_t handler;
14330Sigor@sysoev.ru
14340Sigor@sysoev.ru c = obj;
14350Sigor@sysoev.ru
1436836Sigor@sysoev.ru nxt_debug(task, "openssl conn shutdown fd:%d", c->socket.fd);
1437836Sigor@sysoev.ru
1438771Sigor@sysoev.ru c->read_state = NULL;
1439771Sigor@sysoev.ru tls = c->u.tls;
1440836Sigor@sysoev.ru
1441836Sigor@sysoev.ru if (tls == NULL) {
1442836Sigor@sysoev.ru return;
1443836Sigor@sysoev.ru }
1444836Sigor@sysoev.ru
1445771Sigor@sysoev.ru s = tls->session;
14460Sigor@sysoev.ru
1447771Sigor@sysoev.ru if (s == NULL || !tls->handshake) {
1448771Sigor@sysoev.ru handler = c->write_state->ready_handler;
14490Sigor@sysoev.ru goto done;
14500Sigor@sysoev.ru }
14510Sigor@sysoev.ru
14520Sigor@sysoev.ru mode = SSL_get_shutdown(s);
14530Sigor@sysoev.ru
14540Sigor@sysoev.ru if (c->socket.timedout || c->socket.error != 0) {
14550Sigor@sysoev.ru quiet = 1;
14560Sigor@sysoev.ru
14570Sigor@sysoev.ru } else if (c->socket.closed && !(mode & SSL_RECEIVED_SHUTDOWN)) {
14580Sigor@sysoev.ru quiet = 1;
14590Sigor@sysoev.ru
14600Sigor@sysoev.ru } else {
14610Sigor@sysoev.ru quiet = 0;
14620Sigor@sysoev.ru }
14630Sigor@sysoev.ru
14640Sigor@sysoev.ru SSL_set_quiet_shutdown(s, quiet);
14650Sigor@sysoev.ru
14661884Sa.suvorov@f5.com if (tls->conf->no_wait_shutdown) {
14671884Sa.suvorov@f5.com mode |= SSL_RECEIVED_SHUTDOWN;
14681884Sa.suvorov@f5.com }
14691884Sa.suvorov@f5.com
14700Sigor@sysoev.ru once = 1;
14710Sigor@sysoev.ru
14720Sigor@sysoev.ru for ( ;; ) {
14730Sigor@sysoev.ru SSL_set_shutdown(s, mode);
14740Sigor@sysoev.ru
14750Sigor@sysoev.ru ret = SSL_shutdown(s);
14760Sigor@sysoev.ru
14770Sigor@sysoev.ru err = (ret <= 0) ? nxt_socket_errno : 0;
14780Sigor@sysoev.ru
14791Sigor@sysoev.ru nxt_debug(task, "SSL_shutdown(%d, %d, %b): %d err:%d",
14801Sigor@sysoev.ru c->socket.fd, mode, quiet, ret, err);
14810Sigor@sysoev.ru
14820Sigor@sysoev.ru if (ret > 0) {
14830Sigor@sysoev.ru /* ret == 1, the shutdown was successfully completed. */
1484771Sigor@sysoev.ru handler = c->write_state->ready_handler;
14850Sigor@sysoev.ru goto done;
14860Sigor@sysoev.ru }
14870Sigor@sysoev.ru
14880Sigor@sysoev.ru if (ret == 0) {
14890Sigor@sysoev.ru /*
14900Sigor@sysoev.ru * If SSL_shutdown() returns 0 then it should be called
1491771Sigor@sysoev.ru * again. The second SSL_shutdown() call should return
14920Sigor@sysoev.ru * -1/SSL_ERROR_WANT_READ or -1/SSL_ERROR_WANT_WRITE.
14930Sigor@sysoev.ru * OpenSSL prior to 0.9.8m version however never returns
1494771Sigor@sysoev.ru * -1 at all. Fortunately, OpenSSL preserves internally
14950Sigor@sysoev.ru * correct status available via SSL_get_error(-1).
14960Sigor@sysoev.ru */
14970Sigor@sysoev.ru if (once) {
1498771Sigor@sysoev.ru once = 0;
14990Sigor@sysoev.ru mode = SSL_get_shutdown(s);
15000Sigor@sysoev.ru continue;
15010Sigor@sysoev.ru }
15020Sigor@sysoev.ru
15030Sigor@sysoev.ru ret = -1;
15040Sigor@sysoev.ru }
15050Sigor@sysoev.ru
15060Sigor@sysoev.ru /* ret == -1 */
15070Sigor@sysoev.ru
15080Sigor@sysoev.ru break;
15090Sigor@sysoev.ru }
15100Sigor@sysoev.ru
1511771Sigor@sysoev.ru c->socket.read_handler = nxt_openssl_conn_io_shutdown;
1512771Sigor@sysoev.ru c->socket.write_handler = nxt_openssl_conn_io_shutdown;
1513771Sigor@sysoev.ru c->socket.error_handler = c->write_state->error_handler;
1514771Sigor@sysoev.ru
1515771Sigor@sysoev.ru n = nxt_openssl_conn_test_error(task, c, ret, err, NXT_OPENSSL_SHUTDOWN);
1516771Sigor@sysoev.ru
1517771Sigor@sysoev.ru switch (n) {
15180Sigor@sysoev.ru
1519771Sigor@sysoev.ru case 0:
1520771Sigor@sysoev.ru handler = c->write_state->close_handler;
1521771Sigor@sysoev.ru break;
1522771Sigor@sysoev.ru
1523771Sigor@sysoev.ru case NXT_AGAIN:
15241884Sa.suvorov@f5.com c->write_timer.handler = nxt_openssl_conn_io_shutdown_timeout;
15251884Sa.suvorov@f5.com nxt_timer_add(task->thread->engine, &c->write_timer, 5000);
15260Sigor@sysoev.ru return;
1527771Sigor@sysoev.ru
1528771Sigor@sysoev.ru default:
1529771Sigor@sysoev.ru case NXT_ERROR:
1530771Sigor@sysoev.ru nxt_openssl_conn_error(task, err, "SSL_shutdown(%d) failed",
1531771Sigor@sysoev.ru c->socket.fd);
1532771Sigor@sysoev.ru handler = c->write_state->error_handler;
15330Sigor@sysoev.ru }
15340Sigor@sysoev.ru
1535771Sigor@sysoev.ru done:
15360Sigor@sysoev.ru
1537836Sigor@sysoev.ru nxt_openssl_conn_free(task, c);
15380Sigor@sysoev.ru
153913Sigor@sysoev.ru nxt_work_queue_add(c->write_work_queue, handler, task, c, data);
15400Sigor@sysoev.ru }
15410Sigor@sysoev.ru
15420Sigor@sysoev.ru
15430Sigor@sysoev.ru static nxt_int_t
154462Sigor@sysoev.ru nxt_openssl_conn_test_error(nxt_task_t *task, nxt_conn_t *c, int ret,
1545771Sigor@sysoev.ru nxt_err_t sys_err, nxt_openssl_io_t io)
15460Sigor@sysoev.ru {
15470Sigor@sysoev.ru u_long lib_err;
1548771Sigor@sysoev.ru nxt_openssl_conn_t *tls;
15490Sigor@sysoev.ru
1550771Sigor@sysoev.ru tls = c->u.tls;
15510Sigor@sysoev.ru
1552771Sigor@sysoev.ru tls->ssl_error = SSL_get_error(tls->session, ret);
15530Sigor@sysoev.ru
1554771Sigor@sysoev.ru nxt_debug(task, "SSL_get_error(): %d", tls->ssl_error);
15550Sigor@sysoev.ru
1556771Sigor@sysoev.ru switch (tls->ssl_error) {
15570Sigor@sysoev.ru
15580Sigor@sysoev.ru case SSL_ERROR_WANT_READ:
1559990Sigor@sysoev.ru c->socket.read_ready = 0;
1560771Sigor@sysoev.ru
1561771Sigor@sysoev.ru if (io != NXT_OPENSSL_READ) {
1562771Sigor@sysoev.ru nxt_fd_event_block_write(task->thread->engine, &c->socket);
15630Sigor@sysoev.ru
1564771Sigor@sysoev.ru if (nxt_fd_event_is_disabled(c->socket.read)) {
1565771Sigor@sysoev.ru nxt_fd_event_enable_read(task->thread->engine, &c->socket);
1566771Sigor@sysoev.ru }
15670Sigor@sysoev.ru }
15680Sigor@sysoev.ru
15690Sigor@sysoev.ru return NXT_AGAIN;
15700Sigor@sysoev.ru
15710Sigor@sysoev.ru case SSL_ERROR_WANT_WRITE:
1572990Sigor@sysoev.ru c->socket.write_ready = 0;
1573771Sigor@sysoev.ru
1574771Sigor@sysoev.ru if (io != NXT_OPENSSL_WRITE) {
1575771Sigor@sysoev.ru nxt_fd_event_block_read(task->thread->engine, &c->socket);
15760Sigor@sysoev.ru
1577771Sigor@sysoev.ru if (nxt_fd_event_is_disabled(c->socket.write)) {
1578771Sigor@sysoev.ru nxt_fd_event_enable_write(task->thread->engine, &c->socket);
1579771Sigor@sysoev.ru }
15800Sigor@sysoev.ru }
15810Sigor@sysoev.ru
15820Sigor@sysoev.ru return NXT_AGAIN;
15830Sigor@sysoev.ru
15840Sigor@sysoev.ru case SSL_ERROR_SYSCALL:
15850Sigor@sysoev.ru lib_err = ERR_peek_error();
15860Sigor@sysoev.ru
15871Sigor@sysoev.ru nxt_debug(task, "ERR_peek_error(): %l", lib_err);
15880Sigor@sysoev.ru
15890Sigor@sysoev.ru if (sys_err != 0 || lib_err != 0) {
15901212Sigor@sysoev.ru c->socket.error = sys_err;
15910Sigor@sysoev.ru return NXT_ERROR;
15920Sigor@sysoev.ru }
15930Sigor@sysoev.ru
15940Sigor@sysoev.ru /* A connection was just closed. */
15950Sigor@sysoev.ru c->socket.closed = 1;
1596771Sigor@sysoev.ru return 0;
15970Sigor@sysoev.ru
15980Sigor@sysoev.ru case SSL_ERROR_ZERO_RETURN:
15990Sigor@sysoev.ru /* A "close notify" alert. */
16000Sigor@sysoev.ru return 0;
16010Sigor@sysoev.ru
16020Sigor@sysoev.ru default: /* SSL_ERROR_SSL, etc. */
16030Sigor@sysoev.ru c->socket.error = 1000; /* Nonexistent errno code. */
16040Sigor@sysoev.ru return NXT_ERROR;
16050Sigor@sysoev.ru }
16060Sigor@sysoev.ru }
16070Sigor@sysoev.ru
16080Sigor@sysoev.ru
16091884Sa.suvorov@f5.com static void
16101884Sa.suvorov@f5.com nxt_openssl_conn_io_shutdown_timeout(nxt_task_t *task, void *obj, void *data)
16111884Sa.suvorov@f5.com {
16121884Sa.suvorov@f5.com nxt_conn_t *c;
16131884Sa.suvorov@f5.com nxt_timer_t *timer;
16141884Sa.suvorov@f5.com
16151884Sa.suvorov@f5.com timer = obj;
16161884Sa.suvorov@f5.com
16171884Sa.suvorov@f5.com nxt_debug(task, "openssl conn shutdown timeout");
16181884Sa.suvorov@f5.com
16191884Sa.suvorov@f5.com c = nxt_write_timer_conn(timer);
16201884Sa.suvorov@f5.com
16211884Sa.suvorov@f5.com c->socket.timedout = 1;
16221884Sa.suvorov@f5.com nxt_openssl_conn_io_shutdown(task, c, NULL);
16231884Sa.suvorov@f5.com }
16241884Sa.suvorov@f5.com
16251884Sa.suvorov@f5.com
16260Sigor@sysoev.ru static void nxt_cdecl
1627771Sigor@sysoev.ru nxt_openssl_conn_error(nxt_task_t *task, nxt_err_t err, const char *fmt, ...)
16280Sigor@sysoev.ru {
16290Sigor@sysoev.ru u_char *p, *end;
16300Sigor@sysoev.ru va_list args;
16310Sigor@sysoev.ru nxt_uint_t level;
16320Sigor@sysoev.ru u_char msg[NXT_MAX_ERROR_STR];
16330Sigor@sysoev.ru
1634771Sigor@sysoev.ru level = nxt_openssl_log_error_level(err);
16350Sigor@sysoev.ru
1636771Sigor@sysoev.ru if (nxt_log_level_enough(task->log, level)) {
16370Sigor@sysoev.ru
16380Sigor@sysoev.ru end = msg + sizeof(msg);
16390Sigor@sysoev.ru
16400Sigor@sysoev.ru va_start(args, fmt);
16410Sigor@sysoev.ru p = nxt_vsprintf(msg, end, fmt, args);
16420Sigor@sysoev.ru va_end(args);
16430Sigor@sysoev.ru
16440Sigor@sysoev.ru if (err != 0) {
16450Sigor@sysoev.ru p = nxt_sprintf(p, end, " %E", err);
16460Sigor@sysoev.ru }
16470Sigor@sysoev.ru
16480Sigor@sysoev.ru p = nxt_openssl_copy_error(p, end);
16490Sigor@sysoev.ru
1650771Sigor@sysoev.ru nxt_log(task, level, "%*s", p - msg, msg);
16510Sigor@sysoev.ru
16520Sigor@sysoev.ru } else {
16530Sigor@sysoev.ru ERR_clear_error();
16540Sigor@sysoev.ru }
16550Sigor@sysoev.ru }
16560Sigor@sysoev.ru
16570Sigor@sysoev.ru
16580Sigor@sysoev.ru static nxt_uint_t
1659771Sigor@sysoev.ru nxt_openssl_log_error_level(nxt_err_t err)
16600Sigor@sysoev.ru {
16610Sigor@sysoev.ru switch (ERR_GET_REASON(ERR_peek_error())) {
16620Sigor@sysoev.ru
16630Sigor@sysoev.ru case 0:
166413Sigor@sysoev.ru return nxt_socket_error_level(err);
16650Sigor@sysoev.ru
16660Sigor@sysoev.ru case SSL_R_BAD_CHANGE_CIPHER_SPEC: /* 103 */
16670Sigor@sysoev.ru case SSL_R_BLOCK_CIPHER_PAD_IS_WRONG: /* 129 */
16680Sigor@sysoev.ru case SSL_R_DIGEST_CHECK_FAILED: /* 149 */
16690Sigor@sysoev.ru case SSL_R_ERROR_IN_RECEIVED_CIPHER_LIST: /* 151 */
16700Sigor@sysoev.ru case SSL_R_EXCESSIVE_MESSAGE_SIZE: /* 152 */
16710Sigor@sysoev.ru case SSL_R_LENGTH_MISMATCH: /* 159 */
1672771Sigor@sysoev.ru #ifdef SSL_R_NO_CIPHERS_PASSED
16730Sigor@sysoev.ru case SSL_R_NO_CIPHERS_PASSED: /* 182 */
1674771Sigor@sysoev.ru #endif
16750Sigor@sysoev.ru case SSL_R_NO_CIPHERS_SPECIFIED: /* 183 */
16760Sigor@sysoev.ru case SSL_R_NO_COMPRESSION_SPECIFIED: /* 187 */
16770Sigor@sysoev.ru case SSL_R_NO_SHARED_CIPHER: /* 193 */
16780Sigor@sysoev.ru case SSL_R_RECORD_LENGTH_MISMATCH: /* 213 */
16790Sigor@sysoev.ru #ifdef SSL_R_PARSE_TLSEXT
16800Sigor@sysoev.ru case SSL_R_PARSE_TLSEXT: /* 227 */
16810Sigor@sysoev.ru #endif
16820Sigor@sysoev.ru case SSL_R_UNEXPECTED_MESSAGE: /* 244 */
16830Sigor@sysoev.ru case SSL_R_UNEXPECTED_RECORD: /* 245 */
16840Sigor@sysoev.ru case SSL_R_UNKNOWN_ALERT_TYPE: /* 246 */
16850Sigor@sysoev.ru case SSL_R_UNKNOWN_PROTOCOL: /* 252 */
16860Sigor@sysoev.ru case SSL_R_WRONG_VERSION_NUMBER: /* 267 */
16870Sigor@sysoev.ru case SSL_R_DECRYPTION_FAILED_OR_BAD_RECORD_MAC: /* 281 */
16880Sigor@sysoev.ru #ifdef SSL_R_RENEGOTIATE_EXT_TOO_LONG
16890Sigor@sysoev.ru case SSL_R_RENEGOTIATE_EXT_TOO_LONG: /* 335 */
16900Sigor@sysoev.ru case SSL_R_RENEGOTIATION_ENCODING_ERR: /* 336 */
16910Sigor@sysoev.ru case SSL_R_RENEGOTIATION_MISMATCH: /* 337 */
16920Sigor@sysoev.ru #endif
16930Sigor@sysoev.ru #ifdef SSL_R_UNSAFE_LEGACY_RENEGOTIATION_DISABLED
16940Sigor@sysoev.ru case SSL_R_UNSAFE_LEGACY_RENEGOTIATION_DISABLED: /* 338 */
16950Sigor@sysoev.ru #endif
16960Sigor@sysoev.ru #ifdef SSL_R_SCSV_RECEIVED_WHEN_RENEGOTIATING
16970Sigor@sysoev.ru case SSL_R_SCSV_RECEIVED_WHEN_RENEGOTIATING: /* 345 */
16980Sigor@sysoev.ru #endif
16990Sigor@sysoev.ru case 1000:/* SSL_R_SSLV3_ALERT_CLOSE_NOTIFY */
17000Sigor@sysoev.ru case SSL_R_SSLV3_ALERT_UNEXPECTED_MESSAGE: /* 1010 */
17010Sigor@sysoev.ru case SSL_R_SSLV3_ALERT_BAD_RECORD_MAC: /* 1020 */
17020Sigor@sysoev.ru case SSL_R_TLSV1_ALERT_DECRYPTION_FAILED: /* 1021 */
17030Sigor@sysoev.ru case SSL_R_TLSV1_ALERT_RECORD_OVERFLOW: /* 1022 */
17040Sigor@sysoev.ru case SSL_R_SSLV3_ALERT_DECOMPRESSION_FAILURE: /* 1030 */
17050Sigor@sysoev.ru case SSL_R_SSLV3_ALERT_HANDSHAKE_FAILURE: /* 1040 */
17060Sigor@sysoev.ru case SSL_R_SSLV3_ALERT_ILLEGAL_PARAMETER: /* 1047 */
17070Sigor@sysoev.ru break;
17080Sigor@sysoev.ru
17090Sigor@sysoev.ru case SSL_R_SSLV3_ALERT_NO_CERTIFICATE: /* 1041 */
17100Sigor@sysoev.ru case SSL_R_SSLV3_ALERT_BAD_CERTIFICATE: /* 1042 */
17110Sigor@sysoev.ru case SSL_R_SSLV3_ALERT_UNSUPPORTED_CERTIFICATE: /* 1043 */
17120Sigor@sysoev.ru case SSL_R_SSLV3_ALERT_CERTIFICATE_REVOKED: /* 1044 */
17130Sigor@sysoev.ru case SSL_R_SSLV3_ALERT_CERTIFICATE_EXPIRED: /* 1045 */
17140Sigor@sysoev.ru case SSL_R_SSLV3_ALERT_CERTIFICATE_UNKNOWN: /* 1046 */
17150Sigor@sysoev.ru case SSL_R_TLSV1_ALERT_UNKNOWN_CA: /* 1048 */
17160Sigor@sysoev.ru case SSL_R_TLSV1_ALERT_ACCESS_DENIED: /* 1049 */
17170Sigor@sysoev.ru case SSL_R_TLSV1_ALERT_DECODE_ERROR: /* 1050 */
17180Sigor@sysoev.ru case SSL_R_TLSV1_ALERT_DECRYPT_ERROR: /* 1051 */
17190Sigor@sysoev.ru case SSL_R_TLSV1_ALERT_EXPORT_RESTRICTION: /* 1060 */
17200Sigor@sysoev.ru case SSL_R_TLSV1_ALERT_PROTOCOL_VERSION: /* 1070 */
17210Sigor@sysoev.ru case SSL_R_TLSV1_ALERT_INSUFFICIENT_SECURITY: /* 1071 */
17220Sigor@sysoev.ru case SSL_R_TLSV1_ALERT_INTERNAL_ERROR: /* 1080 */
17230Sigor@sysoev.ru case SSL_R_TLSV1_ALERT_USER_CANCELLED: /* 1090 */
17240Sigor@sysoev.ru case SSL_R_TLSV1_ALERT_NO_RENEGOTIATION: /* 1100 */
17250Sigor@sysoev.ru return NXT_LOG_ERR;
17260Sigor@sysoev.ru
17270Sigor@sysoev.ru default:
1728564Svbart@nginx.com return NXT_LOG_ALERT;
17290Sigor@sysoev.ru }
17300Sigor@sysoev.ru
17310Sigor@sysoev.ru return NXT_LOG_INFO;
17320Sigor@sysoev.ru }
17330Sigor@sysoev.ru
17340Sigor@sysoev.ru
1735771Sigor@sysoev.ru void nxt_cdecl
1736771Sigor@sysoev.ru nxt_openssl_log_error(nxt_task_t *task, nxt_uint_t level, const char *fmt, ...)
17370Sigor@sysoev.ru {
17380Sigor@sysoev.ru u_char *p, *end;
17390Sigor@sysoev.ru va_list args;
17400Sigor@sysoev.ru u_char msg[NXT_MAX_ERROR_STR];
17410Sigor@sysoev.ru
17420Sigor@sysoev.ru end = msg + sizeof(msg);
17430Sigor@sysoev.ru
17440Sigor@sysoev.ru va_start(args, fmt);
17450Sigor@sysoev.ru p = nxt_vsprintf(msg, end, fmt, args);
17460Sigor@sysoev.ru va_end(args);
17470Sigor@sysoev.ru
17480Sigor@sysoev.ru p = nxt_openssl_copy_error(p, end);
17490Sigor@sysoev.ru
1750771Sigor@sysoev.ru nxt_log(task, level, "%*s", p - msg, msg);
17510Sigor@sysoev.ru }
17520Sigor@sysoev.ru
17530Sigor@sysoev.ru
1754771Sigor@sysoev.ru u_char *
17550Sigor@sysoev.ru nxt_openssl_copy_error(u_char *p, u_char *end)
17560Sigor@sysoev.ru {
17570Sigor@sysoev.ru int flags;
17580Sigor@sysoev.ru u_long err;
17590Sigor@sysoev.ru nxt_bool_t clear;
17600Sigor@sysoev.ru const char *data, *delimiter;
17610Sigor@sysoev.ru
17620Sigor@sysoev.ru err = ERR_peek_error();
17630Sigor@sysoev.ru if (err == 0) {
17640Sigor@sysoev.ru return p;
17650Sigor@sysoev.ru }
17660Sigor@sysoev.ru
17670Sigor@sysoev.ru /* Log the most relevant error message ... */
17680Sigor@sysoev.ru data = ERR_reason_error_string(err);
17690Sigor@sysoev.ru
17700Sigor@sysoev.ru p = nxt_sprintf(p, end, " (%d: %s) (OpenSSL: ", ERR_GET_REASON(err), data);
17710Sigor@sysoev.ru
17720Sigor@sysoev.ru /*
1773771Sigor@sysoev.ru * ... followed by all queued cumbersome OpenSSL error messages
1774771Sigor@sysoev.ru * and drain the error queue.
17750Sigor@sysoev.ru */
17760Sigor@sysoev.ru delimiter = "";
17770Sigor@sysoev.ru clear = 0;
17780Sigor@sysoev.ru
17790Sigor@sysoev.ru for ( ;; ) {
17802224Sremi@remirepo.net #if OPENSSL_VERSION_NUMBER >= 0x30000000L
17812224Sremi@remirepo.net err = ERR_get_error_all(NULL, NULL, NULL, &data, &flags);
17822224Sremi@remirepo.net #else
17830Sigor@sysoev.ru err = ERR_get_error_line_data(NULL, NULL, &data, &flags);
17842224Sremi@remirepo.net #endif
17850Sigor@sysoev.ru if (err == 0) {
17860Sigor@sysoev.ru break;
17870Sigor@sysoev.ru }
17880Sigor@sysoev.ru
17890Sigor@sysoev.ru p = nxt_sprintf(p, end, "%s", delimiter);
17900Sigor@sysoev.ru
17910Sigor@sysoev.ru ERR_error_string_n(err, (char *) p, end - p);
17920Sigor@sysoev.ru
17930Sigor@sysoev.ru while (p < end && *p != '\0') {
17940Sigor@sysoev.ru p++;
17950Sigor@sysoev.ru }
17960Sigor@sysoev.ru
17970Sigor@sysoev.ru if ((flags & ERR_TXT_STRING) != 0) {
17980Sigor@sysoev.ru p = nxt_sprintf(p, end, ":%s", data);
17990Sigor@sysoev.ru }
18000Sigor@sysoev.ru
18010Sigor@sysoev.ru clear |= ((flags & ERR_TXT_MALLOCED) != 0);
18020Sigor@sysoev.ru
18030Sigor@sysoev.ru delimiter = "; ";
18040Sigor@sysoev.ru }
18050Sigor@sysoev.ru
18060Sigor@sysoev.ru /* Deallocate additional data. */
18070Sigor@sysoev.ru
18080Sigor@sysoev.ru if (clear) {
18090Sigor@sysoev.ru ERR_clear_error();
18100Sigor@sysoev.ru }
18110Sigor@sysoev.ru
18120Sigor@sysoev.ru if (p < end) {
18130Sigor@sysoev.ru *p++ = ')';
18140Sigor@sysoev.ru }
18150Sigor@sysoev.ru
18160Sigor@sysoev.ru return p;
18170Sigor@sysoev.ru }
1818