1e18a033bSKonstantin Ananyev
2e18a033bSKonstantin Ananyev/*
3e18a033bSKonstantin Ananyev * Copyright (C) Igor Sysoev
4e18a033bSKonstantin Ananyev * Copyright (C) Nginx, Inc.
5e18a033bSKonstantin Ananyev */
6e18a033bSKonstantin Ananyev
7e18a033bSKonstantin Ananyev
8e18a033bSKonstantin Ananyev#include <ngx_config.h>
9e18a033bSKonstantin Ananyev#include <ngx_core.h>
10e18a033bSKonstantin Ananyev#include <ngx_event.h>
11e18a033bSKonstantin Ananyev
12e18a033bSKonstantin Ananyev
13e18a033bSKonstantin Ananyev#define NGX_SSL_PASSWORD_BUFFER_SIZE  4096
14e18a033bSKonstantin Ananyev
15e18a033bSKonstantin Ananyev
16e18a033bSKonstantin Ananyevtypedef struct {
17e18a033bSKonstantin Ananyev    ngx_uint_t  engine;   /* unsigned  engine:1; */
18e18a033bSKonstantin Ananyev} ngx_openssl_conf_t;
19e18a033bSKonstantin Ananyev
20e18a033bSKonstantin Ananyev
21e18a033bSKonstantin Ananyevstatic int ngx_ssl_password_callback(char *buf, int size, int rwflag,
22e18a033bSKonstantin Ananyev    void *userdata);
23e18a033bSKonstantin Ananyevstatic int ngx_ssl_verify_callback(int ok, X509_STORE_CTX *x509_store);
24e18a033bSKonstantin Ananyevstatic void ngx_ssl_info_callback(const ngx_ssl_conn_t *ssl_conn, int where,
25e18a033bSKonstantin Ananyev    int ret);
26e18a033bSKonstantin Ananyevstatic void ngx_ssl_passwords_cleanup(void *data);
27e18a033bSKonstantin Ananyevstatic void ngx_ssl_handshake_handler(ngx_event_t *ev);
28e18a033bSKonstantin Ananyevstatic ngx_int_t ngx_ssl_handle_recv(ngx_connection_t *c, int n);
29e18a033bSKonstantin Ananyevstatic void ngx_ssl_write_handler(ngx_event_t *wev);
30e18a033bSKonstantin Ananyevstatic void ngx_ssl_read_handler(ngx_event_t *rev);
31e18a033bSKonstantin Ananyevstatic void ngx_ssl_shutdown_handler(ngx_event_t *ev);
32e18a033bSKonstantin Ananyevstatic void ngx_ssl_connection_error(ngx_connection_t *c, int sslerr,
33e18a033bSKonstantin Ananyev    ngx_err_t err, char *text);
34e18a033bSKonstantin Ananyevstatic void ngx_ssl_clear_error(ngx_log_t *log);
35e18a033bSKonstantin Ananyev
36e18a033bSKonstantin Ananyevstatic ngx_int_t ngx_ssl_session_id_context(ngx_ssl_t *ssl,
37e18a033bSKonstantin Ananyev    ngx_str_t *sess_ctx);
38e18a033bSKonstantin Ananyevngx_int_t ngx_ssl_session_cache_init(ngx_shm_zone_t *shm_zone, void *data);
39e18a033bSKonstantin Ananyevstatic int ngx_ssl_new_session(ngx_ssl_conn_t *ssl_conn,
40e18a033bSKonstantin Ananyev    ngx_ssl_session_t *sess);
41e18a033bSKonstantin Ananyevstatic ngx_ssl_session_t *ngx_ssl_get_cached_session(ngx_ssl_conn_t *ssl_conn,
42e18a033bSKonstantin Ananyev#if OPENSSL_VERSION_NUMBER >= 0x10100003L
43e18a033bSKonstantin Ananyev    const
44e18a033bSKonstantin Ananyev#endif
45e18a033bSKonstantin Ananyev    u_char *id, int len, int *copy);
46e18a033bSKonstantin Ananyevstatic void ngx_ssl_remove_session(SSL_CTX *ssl, ngx_ssl_session_t *sess);
47e18a033bSKonstantin Ananyevstatic void ngx_ssl_expire_sessions(ngx_ssl_session_cache_t *cache,
48e18a033bSKonstantin Ananyev    ngx_slab_pool_t *shpool, ngx_uint_t n);
49e18a033bSKonstantin Ananyevstatic void ngx_ssl_session_rbtree_insert_value(ngx_rbtree_node_t *temp,
50e18a033bSKonstantin Ananyev    ngx_rbtree_node_t *node, ngx_rbtree_node_t *sentinel);
51e18a033bSKonstantin Ananyev
52e18a033bSKonstantin Ananyev#ifdef SSL_CTRL_SET_TLSEXT_TICKET_KEY_CB
53e18a033bSKonstantin Ananyevstatic int ngx_ssl_session_ticket_key_callback(ngx_ssl_conn_t *ssl_conn,
54e18a033bSKonstantin Ananyev    unsigned char *name, unsigned char *iv, EVP_CIPHER_CTX *ectx,
55e18a033bSKonstantin Ananyev    HMAC_CTX *hctx, int enc);
56e18a033bSKonstantin Ananyev#endif
57e18a033bSKonstantin Ananyev
58e18a033bSKonstantin Ananyev#ifndef X509_CHECK_FLAG_ALWAYS_CHECK_SUBJECT
59e18a033bSKonstantin Ananyevstatic ngx_int_t ngx_ssl_check_name(ngx_str_t *name, ASN1_STRING *str);
60e18a033bSKonstantin Ananyev#endif
61e18a033bSKonstantin Ananyev
62e18a033bSKonstantin Ananyevstatic time_t ngx_ssl_parse_time(
63e18a033bSKonstantin Ananyev#if OPENSSL_VERSION_NUMBER > 0x10100000L
64e18a033bSKonstantin Ananyev    const
65e18a033bSKonstantin Ananyev#endif
66e18a033bSKonstantin Ananyev    ASN1_TIME *asn1time);
67e18a033bSKonstantin Ananyev
68e18a033bSKonstantin Ananyevstatic void *ngx_openssl_create_conf(ngx_cycle_t *cycle);
69e18a033bSKonstantin Ananyevstatic char *ngx_openssl_engine(ngx_conf_t *cf, ngx_command_t *cmd, void *conf);
70e18a033bSKonstantin Ananyevstatic void ngx_openssl_exit(ngx_cycle_t *cycle);
71e18a033bSKonstantin Ananyev
72e18a033bSKonstantin Ananyev
73e18a033bSKonstantin Ananyevstatic ngx_command_t  ngx_openssl_commands[] = {
74e18a033bSKonstantin Ananyev
75e18a033bSKonstantin Ananyev    { ngx_string("ssl_engine"),
76e18a033bSKonstantin Ananyev      NGX_MAIN_CONF|NGX_DIRECT_CONF|NGX_CONF_TAKE1,
77e18a033bSKonstantin Ananyev      ngx_openssl_engine,
78e18a033bSKonstantin Ananyev      0,
79e18a033bSKonstantin Ananyev      0,
80e18a033bSKonstantin Ananyev      NULL },
81e18a033bSKonstantin Ananyev
82e18a033bSKonstantin Ananyev      ngx_null_command
83e18a033bSKonstantin Ananyev};
84e18a033bSKonstantin Ananyev
85e18a033bSKonstantin Ananyev
86e18a033bSKonstantin Ananyevstatic ngx_core_module_t  ngx_openssl_module_ctx = {
87e18a033bSKonstantin Ananyev    ngx_string("openssl"),
88e18a033bSKonstantin Ananyev    ngx_openssl_create_conf,
89e18a033bSKonstantin Ananyev    NULL
90e18a033bSKonstantin Ananyev};
91e18a033bSKonstantin Ananyev
92e18a033bSKonstantin Ananyev
93e18a033bSKonstantin Ananyevngx_module_t  ngx_openssl_module = {
94e18a033bSKonstantin Ananyev    NGX_MODULE_V1,
95e18a033bSKonstantin Ananyev    &ngx_openssl_module_ctx,               /* module context */
96e18a033bSKonstantin Ananyev    ngx_openssl_commands,                  /* module directives */
97e18a033bSKonstantin Ananyev    NGX_CORE_MODULE,                       /* module type */
98e18a033bSKonstantin Ananyev    NULL,                                  /* init master */
99e18a033bSKonstantin Ananyev    NULL,                                  /* init module */
100e18a033bSKonstantin Ananyev    NULL,                                  /* init process */
101e18a033bSKonstantin Ananyev    NULL,                                  /* init thread */
102e18a033bSKonstantin Ananyev    NULL,                                  /* exit thread */
103e18a033bSKonstantin Ananyev    NULL,                                  /* exit process */
104e18a033bSKonstantin Ananyev    ngx_openssl_exit,                      /* exit master */
105e18a033bSKonstantin Ananyev    NGX_MODULE_V1_PADDING
106e18a033bSKonstantin Ananyev};
107e18a033bSKonstantin Ananyev
108e18a033bSKonstantin Ananyev
109e18a033bSKonstantin Ananyevint  ngx_ssl_connection_index;
110e18a033bSKonstantin Ananyevint  ngx_ssl_server_conf_index;
111e18a033bSKonstantin Ananyevint  ngx_ssl_session_cache_index;
112e18a033bSKonstantin Ananyevint  ngx_ssl_session_ticket_keys_index;
113e18a033bSKonstantin Ananyevint  ngx_ssl_certificate_index;
114e18a033bSKonstantin Ananyevint  ngx_ssl_next_certificate_index;
115e18a033bSKonstantin Ananyevint  ngx_ssl_certificate_name_index;
116e18a033bSKonstantin Ananyevint  ngx_ssl_stapling_index;
117e18a033bSKonstantin Ananyev
118e18a033bSKonstantin Ananyev
119e18a033bSKonstantin Ananyevngx_int_t
120e18a033bSKonstantin Ananyevngx_ssl_init(ngx_log_t *log)
121e18a033bSKonstantin Ananyev{
122e18a033bSKonstantin Ananyev#if OPENSSL_VERSION_NUMBER >= 0x10100003L
123e18a033bSKonstantin Ananyev
124e18a033bSKonstantin Ananyev    if (OPENSSL_init_ssl(OPENSSL_INIT_LOAD_CONFIG, NULL) == 0) {
125e18a033bSKonstantin Ananyev        ngx_ssl_error(NGX_LOG_ALERT, log, 0, "OPENSSL_init_ssl() failed");
126e18a033bSKonstantin Ananyev        return NGX_ERROR;
127e18a033bSKonstantin Ananyev    }
128e18a033bSKonstantin Ananyev
129e18a033bSKonstantin Ananyev    /*
130e18a033bSKonstantin Ananyev     * OPENSSL_init_ssl() may leave errors in the error queue
131e18a033bSKonstantin Ananyev     * while returning success
132e18a033bSKonstantin Ananyev     */
133e18a033bSKonstantin Ananyev
134e18a033bSKonstantin Ananyev    ERR_clear_error();
135e18a033bSKonstantin Ananyev
136e18a033bSKonstantin Ananyev#else
137e18a033bSKonstantin Ananyev
138e18a033bSKonstantin Ananyev    OPENSSL_config(NULL);
139e18a033bSKonstantin Ananyev
140e18a033bSKonstantin Ananyev    SSL_library_init();
141e18a033bSKonstantin Ananyev    SSL_load_error_strings();
142e18a033bSKonstantin Ananyev
143e18a033bSKonstantin Ananyev    OpenSSL_add_all_algorithms();
144e18a033bSKonstantin Ananyev
145e18a033bSKonstantin Ananyev#endif
146e18a033bSKonstantin Ananyev
147e18a033bSKonstantin Ananyev#if OPENSSL_VERSION_NUMBER >= 0x0090800fL
148e18a033bSKonstantin Ananyev#ifndef SSL_OP_NO_COMPRESSION
149e18a033bSKonstantin Ananyev    {
150e18a033bSKonstantin Ananyev    /*
151e18a033bSKonstantin Ananyev     * Disable gzip compression in OpenSSL prior to 1.0.0 version,
152e18a033bSKonstantin Ananyev     * this saves about 522K per connection.
153e18a033bSKonstantin Ananyev     */
154e18a033bSKonstantin Ananyev    int                  n;
155e18a033bSKonstantin Ananyev    STACK_OF(SSL_COMP)  *ssl_comp_methods;
156e18a033bSKonstantin Ananyev
157e18a033bSKonstantin Ananyev    ssl_comp_methods = SSL_COMP_get_compression_methods();
158e18a033bSKonstantin Ananyev    n = sk_SSL_COMP_num(ssl_comp_methods);
159e18a033bSKonstantin Ananyev
160e18a033bSKonstantin Ananyev    while (n--) {
161e18a033bSKonstantin Ananyev        (void) sk_SSL_COMP_pop(ssl_comp_methods);
162e18a033bSKonstantin Ananyev    }
163e18a033bSKonstantin Ananyev    }
164e18a033bSKonstantin Ananyev#endif
165e18a033bSKonstantin Ananyev#endif
166e18a033bSKonstantin Ananyev
167e18a033bSKonstantin Ananyev    ngx_ssl_connection_index = SSL_get_ex_new_index(0, NULL, NULL, NULL, NULL);
168e18a033bSKonstantin Ananyev
169e18a033bSKonstantin Ananyev    if (ngx_ssl_connection_index == -1) {
170e18a033bSKonstantin Ananyev        ngx_ssl_error(NGX_LOG_ALERT, log, 0, "SSL_get_ex_new_index() failed");
171e18a033bSKonstantin Ananyev        return NGX_ERROR;
172e18a033bSKonstantin Ananyev    }
173e18a033bSKonstantin Ananyev
174e18a033bSKonstantin Ananyev    ngx_ssl_server_conf_index = SSL_CTX_get_ex_new_index(0, NULL, NULL, NULL,
175e18a033bSKonstantin Ananyev                                                         NULL);
176e18a033bSKonstantin Ananyev    if (ngx_ssl_server_conf_index == -1) {
177e18a033bSKonstantin Ananyev        ngx_ssl_error(NGX_LOG_ALERT, log, 0,
178e18a033bSKonstantin Ananyev                      "SSL_CTX_get_ex_new_index() failed");
179e18a033bSKonstantin Ananyev        return NGX_ERROR;
180e18a033bSKonstantin Ananyev    }
181e18a033bSKonstantin Ananyev
182e18a033bSKonstantin Ananyev    ngx_ssl_session_cache_index = SSL_CTX_get_ex_new_index(0, NULL, NULL, NULL,
183e18a033bSKonstantin Ananyev                                                           NULL);
184e18a033bSKonstantin Ananyev    if (ngx_ssl_session_cache_index == -1) {
185e18a033bSKonstantin Ananyev        ngx_ssl_error(NGX_LOG_ALERT, log, 0,
186e18a033bSKonstantin Ananyev                      "SSL_CTX_get_ex_new_index() failed");
187e18a033bSKonstantin Ananyev        return NGX_ERROR;
188e18a033bSKonstantin Ananyev    }
189e18a033bSKonstantin Ananyev
190e18a033bSKonstantin Ananyev    ngx_ssl_session_ticket_keys_index = SSL_CTX_get_ex_new_index(0, NULL, NULL,
191e18a033bSKonstantin Ananyev                                                                 NULL, NULL);
192e18a033bSKonstantin Ananyev    if (ngx_ssl_session_ticket_keys_index == -1) {
193e18a033bSKonstantin Ananyev        ngx_ssl_error(NGX_LOG_ALERT, log, 0,
194e18a033bSKonstantin Ananyev                      "SSL_CTX_get_ex_new_index() failed");
195e18a033bSKonstantin Ananyev        return NGX_ERROR;
196e18a033bSKonstantin Ananyev    }
197e18a033bSKonstantin Ananyev
198e18a033bSKonstantin Ananyev    ngx_ssl_certificate_index = SSL_CTX_get_ex_new_index(0, NULL, NULL, NULL,
199e18a033bSKonstantin Ananyev                                                         NULL);
200e18a033bSKonstantin Ananyev    if (ngx_ssl_certificate_index == -1) {
201e18a033bSKonstantin Ananyev        ngx_ssl_error(NGX_LOG_ALERT, log, 0,
202e18a033bSKonstantin Ananyev                      "SSL_CTX_get_ex_new_index() failed");
203e18a033bSKonstantin Ananyev        return NGX_ERROR;
204e18a033bSKonstantin Ananyev    }
205e18a033bSKonstantin Ananyev
206e18a033bSKonstantin Ananyev    ngx_ssl_next_certificate_index = X509_get_ex_new_index(0, NULL, NULL, NULL,
207e18a033bSKonstantin Ananyev                                                           NULL);
208e18a033bSKonstantin Ananyev    if (ngx_ssl_next_certificate_index == -1) {
209e18a033bSKonstantin Ananyev        ngx_ssl_error(NGX_LOG_ALERT, log, 0, "X509_get_ex_new_index() failed");
210e18a033bSKonstantin Ananyev        return NGX_ERROR;
211e18a033bSKonstantin Ananyev    }
212e18a033bSKonstantin Ananyev
213e18a033bSKonstantin Ananyev    ngx_ssl_certificate_name_index = X509_get_ex_new_index(0, NULL, NULL, NULL,
214e18a033bSKonstantin Ananyev                                                           NULL);
215e18a033bSKonstantin Ananyev
216e18a033bSKonstantin Ananyev    if (ngx_ssl_certificate_name_index == -1) {
217e18a033bSKonstantin Ananyev        ngx_ssl_error(NGX_LOG_ALERT, log, 0, "X509_get_ex_new_index() failed");
218e18a033bSKonstantin Ananyev        return NGX_ERROR;
219e18a033bSKonstantin Ananyev    }
220e18a033bSKonstantin Ananyev
221e18a033bSKonstantin Ananyev    ngx_ssl_stapling_index = X509_get_ex_new_index(0, NULL, NULL, NULL, NULL);
222e18a033bSKonstantin Ananyev
223e18a033bSKonstantin Ananyev    if (ngx_ssl_stapling_index == -1) {
224e18a033bSKonstantin Ananyev        ngx_ssl_error(NGX_LOG_ALERT, log, 0, "X509_get_ex_new_index() failed");
225e18a033bSKonstantin Ananyev        return NGX_ERROR;
226e18a033bSKonstantin Ananyev    }
227e18a033bSKonstantin Ananyev
228e18a033bSKonstantin Ananyev    return NGX_OK;
229e18a033bSKonstantin Ananyev}
230e18a033bSKonstantin Ananyev
231e18a033bSKonstantin Ananyev
232e18a033bSKonstantin Ananyevngx_int_t
233e18a033bSKonstantin Ananyevngx_ssl_create(ngx_ssl_t *ssl, ngx_uint_t protocols, void *data)
234e18a033bSKonstantin Ananyev{
235e18a033bSKonstantin Ananyev    ssl->ctx = SSL_CTX_new(SSLv23_method());
236e18a033bSKonstantin Ananyev
237e18a033bSKonstantin Ananyev    if (ssl->ctx == NULL) {
238e18a033bSKonstantin Ananyev        ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0, "SSL_CTX_new() failed");
239e18a033bSKonstantin Ananyev        return NGX_ERROR;
240e18a033bSKonstantin Ananyev    }
241e18a033bSKonstantin Ananyev
242e18a033bSKonstantin Ananyev    if (SSL_CTX_set_ex_data(ssl->ctx, ngx_ssl_server_conf_index, data) == 0) {
243e18a033bSKonstantin Ananyev        ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0,
244e18a033bSKonstantin Ananyev                      "SSL_CTX_set_ex_data() failed");
245e18a033bSKonstantin Ananyev        return NGX_ERROR;
246e18a033bSKonstantin Ananyev    }
247e18a033bSKonstantin Ananyev
248e18a033bSKonstantin Ananyev    if (SSL_CTX_set_ex_data(ssl->ctx, ngx_ssl_certificate_index, NULL) == 0) {
249e18a033bSKonstantin Ananyev        ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0,
250e18a033bSKonstantin Ananyev                      "SSL_CTX_set_ex_data() failed");
251e18a033bSKonstantin Ananyev        return NGX_ERROR;
252e18a033bSKonstantin Ananyev    }
253e18a033bSKonstantin Ananyev
254e18a033bSKonstantin Ananyev    ssl->buffer_size = NGX_SSL_BUFSIZE;
255e18a033bSKonstantin Ananyev
256e18a033bSKonstantin Ananyev    /* client side options */
257e18a033bSKonstantin Ananyev
258e18a033bSKonstantin Ananyev#ifdef SSL_OP_MICROSOFT_SESS_ID_BUG
259e18a033bSKonstantin Ananyev    SSL_CTX_set_options(ssl->ctx, SSL_OP_MICROSOFT_SESS_ID_BUG);
260e18a033bSKonstantin Ananyev#endif
261e18a033bSKonstantin Ananyev
262e18a033bSKonstantin Ananyev#ifdef SSL_OP_NETSCAPE_CHALLENGE_BUG
263e18a033bSKonstantin Ananyev    SSL_CTX_set_options(ssl->ctx, SSL_OP_NETSCAPE_CHALLENGE_BUG);
264e18a033bSKonstantin Ananyev#endif
265e18a033bSKonstantin Ananyev
266e18a033bSKonstantin Ananyev    /* server side options */
267e18a033bSKonstantin Ananyev
268e18a033bSKonstantin Ananyev#ifdef SSL_OP_SSLREF2_REUSE_CERT_TYPE_BUG
269e18a033bSKonstantin Ananyev    SSL_CTX_set_options(ssl->ctx, SSL_OP_SSLREF2_REUSE_CERT_TYPE_BUG);
270e18a033bSKonstantin Ananyev#endif
271e18a033bSKonstantin Ananyev
272e18a033bSKonstantin Ananyev#ifdef SSL_OP_MICROSOFT_BIG_SSLV3_BUFFER
273e18a033bSKonstantin Ananyev    SSL_CTX_set_options(ssl->ctx, SSL_OP_MICROSOFT_BIG_SSLV3_BUFFER);
274e18a033bSKonstantin Ananyev#endif
275e18a033bSKonstantin Ananyev
276e18a033bSKonstantin Ananyev#ifdef SSL_OP_MSIE_SSLV2_RSA_PADDING
277e18a033bSKonstantin Ananyev    /* this option allow a potential SSL 2.0 rollback (CAN-2005-2969) */
278e18a033bSKonstantin Ananyev    SSL_CTX_set_options(ssl->ctx, SSL_OP_MSIE_SSLV2_RSA_PADDING);
279e18a033bSKonstantin Ananyev#endif
280e18a033bSKonstantin Ananyev
281e18a033bSKonstantin Ananyev#ifdef SSL_OP_SSLEAY_080_CLIENT_DH_BUG
282e18a033bSKonstantin Ananyev    SSL_CTX_set_options(ssl->ctx, SSL_OP_SSLEAY_080_CLIENT_DH_BUG);
283e18a033bSKonstantin Ananyev#endif
284e18a033bSKonstantin Ananyev
285e18a033bSKonstantin Ananyev#ifdef SSL_OP_TLS_D5_BUG
286e18a033bSKonstantin Ananyev    SSL_CTX_set_options(ssl->ctx, SSL_OP_TLS_D5_BUG);
287e18a033bSKonstantin Ananyev#endif
288e18a033bSKonstantin Ananyev
289e18a033bSKonstantin Ananyev#ifdef SSL_OP_TLS_BLOCK_PADDING_BUG
290e18a033bSKonstantin Ananyev    SSL_CTX_set_options(ssl->ctx, SSL_OP_TLS_BLOCK_PADDING_BUG);
291e18a033bSKonstantin Ananyev#endif
292e18a033bSKonstantin Ananyev
293e18a033bSKonstantin Ananyev#ifdef SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS
294e18a033bSKonstantin Ananyev    SSL_CTX_set_options(ssl->ctx, SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS);
295e18a033bSKonstantin Ananyev#endif
296e18a033bSKonstantin Ananyev
297e18a033bSKonstantin Ananyev    SSL_CTX_set_options(ssl->ctx, SSL_OP_SINGLE_DH_USE);
298e18a033bSKonstantin Ananyev
299e18a033bSKonstantin Ananyev#ifdef SSL_CTRL_CLEAR_OPTIONS
300e18a033bSKonstantin Ananyev    /* only in 0.9.8m+ */
301e18a033bSKonstantin Ananyev    SSL_CTX_clear_options(ssl->ctx,
302e18a033bSKonstantin Ananyev                          SSL_OP_NO_SSLv2|SSL_OP_NO_SSLv3|SSL_OP_NO_TLSv1);
303e18a033bSKonstantin Ananyev#endif
304e18a033bSKonstantin Ananyev
305e18a033bSKonstantin Ananyev    if (!(protocols & NGX_SSL_SSLv2)) {
306e18a033bSKonstantin Ananyev        SSL_CTX_set_options(ssl->ctx, SSL_OP_NO_SSLv2);
307e18a033bSKonstantin Ananyev    }
308e18a033bSKonstantin Ananyev    if (!(protocols & NGX_SSL_SSLv3)) {
309e18a033bSKonstantin Ananyev        SSL_CTX_set_options(ssl->ctx, SSL_OP_NO_SSLv3);
310e18a033bSKonstantin Ananyev    }
311e18a033bSKonstantin Ananyev    if (!(protocols & NGX_SSL_TLSv1)) {
312e18a033bSKonstantin Ananyev        SSL_CTX_set_options(ssl->ctx, SSL_OP_NO_TLSv1);
313e18a033bSKonstantin Ananyev    }
314e18a033bSKonstantin Ananyev#ifdef SSL_OP_NO_TLSv1_1
315e18a033bSKonstantin Ananyev    SSL_CTX_clear_options(ssl->ctx, SSL_OP_NO_TLSv1_1);
316e18a033bSKonstantin Ananyev    if (!(protocols & NGX_SSL_TLSv1_1)) {
317e18a033bSKonstantin Ananyev        SSL_CTX_set_options(ssl->ctx, SSL_OP_NO_TLSv1_1);
318e18a033bSKonstantin Ananyev    }
319e18a033bSKonstantin Ananyev#endif
320e18a033bSKonstantin Ananyev#ifdef SSL_OP_NO_TLSv1_2
321e18a033bSKonstantin Ananyev    SSL_CTX_clear_options(ssl->ctx, SSL_OP_NO_TLSv1_2);
322e18a033bSKonstantin Ananyev    if (!(protocols & NGX_SSL_TLSv1_2)) {
323e18a033bSKonstantin Ananyev        SSL_CTX_set_options(ssl->ctx, SSL_OP_NO_TLSv1_2);
324e18a033bSKonstantin Ananyev    }
325e18a033bSKonstantin Ananyev#endif
326e18a033bSKonstantin Ananyev
327e18a033bSKonstantin Ananyev#ifdef SSL_OP_NO_COMPRESSION
328e18a033bSKonstantin Ananyev    SSL_CTX_set_options(ssl->ctx, SSL_OP_NO_COMPRESSION);
329e18a033bSKonstantin Ananyev#endif
330e18a033bSKonstantin Ananyev
331e18a033bSKonstantin Ananyev#ifdef SSL_MODE_RELEASE_BUFFERS
332e18a033bSKonstantin Ananyev    SSL_CTX_set_mode(ssl->ctx, SSL_MODE_RELEASE_BUFFERS);
333e18a033bSKonstantin Ananyev#endif
334e18a033bSKonstantin Ananyev
335e18a033bSKonstantin Ananyev#ifdef SSL_MODE_NO_AUTO_CHAIN
336e18a033bSKonstantin Ananyev    SSL_CTX_set_mode(ssl->ctx, SSL_MODE_NO_AUTO_CHAIN);
337e18a033bSKonstantin Ananyev#endif
338e18a033bSKonstantin Ananyev
339e18a033bSKonstantin Ananyev    SSL_CTX_set_read_ahead(ssl->ctx, 1);
340e18a033bSKonstantin Ananyev
341e18a033bSKonstantin Ananyev    SSL_CTX_set_info_callback(ssl->ctx, ngx_ssl_info_callback);
342e18a033bSKonstantin Ananyev
343e18a033bSKonstantin Ananyev    return NGX_OK;
344e18a033bSKonstantin Ananyev}
345e18a033bSKonstantin Ananyev
346e18a033bSKonstantin Ananyev
347e18a033bSKonstantin Ananyevngx_int_t
348e18a033bSKonstantin Ananyevngx_ssl_certificates(ngx_conf_t *cf, ngx_ssl_t *ssl, ngx_array_t *certs,
349e18a033bSKonstantin Ananyev    ngx_array_t *keys, ngx_array_t *passwords)
350e18a033bSKonstantin Ananyev{
351e18a033bSKonstantin Ananyev    ngx_str_t   *cert, *key;
352e18a033bSKonstantin Ananyev    ngx_uint_t   i;
353e18a033bSKonstantin Ananyev
354e18a033bSKonstantin Ananyev    cert = certs->elts;
355e18a033bSKonstantin Ananyev    key = keys->elts;
356e18a033bSKonstantin Ananyev
357e18a033bSKonstantin Ananyev    for (i = 0; i < certs->nelts; i++) {
358e18a033bSKonstantin Ananyev
359e18a033bSKonstantin Ananyev        if (ngx_ssl_certificate(cf, ssl, &cert[i], &key[i], passwords)
360e18a033bSKonstantin Ananyev            != NGX_OK)
361e18a033bSKonstantin Ananyev        {
362e18a033bSKonstantin Ananyev            return NGX_ERROR;
363e18a033bSKonstantin Ananyev        }
364e18a033bSKonstantin Ananyev    }
365e18a033bSKonstantin Ananyev
366e18a033bSKonstantin Ananyev    return NGX_OK;
367e18a033bSKonstantin Ananyev}
368e18a033bSKonstantin Ananyev
369e18a033bSKonstantin Ananyev
370e18a033bSKonstantin Ananyevngx_int_t
371e18a033bSKonstantin Ananyevngx_ssl_certificate(ngx_conf_t *cf, ngx_ssl_t *ssl, ngx_str_t *cert,
372e18a033bSKonstantin Ananyev    ngx_str_t *key, ngx_array_t *passwords)
373e18a033bSKonstantin Ananyev{
374e18a033bSKonstantin Ananyev    BIO         *bio;
375e18a033bSKonstantin Ananyev    X509        *x509;
376e18a033bSKonstantin Ananyev    u_long       n;
377e18a033bSKonstantin Ananyev    ngx_str_t   *pwd;
378e18a033bSKonstantin Ananyev    ngx_uint_t   tries;
379e18a033bSKonstantin Ananyev
380e18a033bSKonstantin Ananyev    if (ngx_conf_full_name(cf->cycle, cert, 1) != NGX_OK) {
381e18a033bSKonstantin Ananyev        return NGX_ERROR;
382e18a033bSKonstantin Ananyev    }
383e18a033bSKonstantin Ananyev
384e18a033bSKonstantin Ananyev    /*
385e18a033bSKonstantin Ananyev     * we can't use SSL_CTX_use_certificate_chain_file() as it doesn't
386e18a033bSKonstantin Ananyev     * allow to access certificate later from SSL_CTX, so we reimplement
387e18a033bSKonstantin Ananyev     * it here
388e18a033bSKonstantin Ananyev     */
389e18a033bSKonstantin Ananyev
390e18a033bSKonstantin Ananyev    bio = BIO_new_file((char *) cert->data, "r");
391e18a033bSKonstantin Ananyev    if (bio == NULL) {
392e18a033bSKonstantin Ananyev        ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0,
393e18a033bSKonstantin Ananyev                      "BIO_new_file(\"%s\") failed", cert->data);
394e18a033bSKonstantin Ananyev        return NGX_ERROR;
395e18a033bSKonstantin Ananyev    }
396e18a033bSKonstantin Ananyev
397e18a033bSKonstantin Ananyev    x509 = PEM_read_bio_X509_AUX(bio, NULL, NULL, NULL);
398e18a033bSKonstantin Ananyev    if (x509 == NULL) {
399e18a033bSKonstantin Ananyev        ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0,
400e18a033bSKonstantin Ananyev                      "PEM_read_bio_X509_AUX(\"%s\") failed", cert->data);
401e18a033bSKonstantin Ananyev        BIO_free(bio);
402e18a033bSKonstantin Ananyev        return NGX_ERROR;
403e18a033bSKonstantin Ananyev    }
404e18a033bSKonstantin Ananyev
405e18a033bSKonstantin Ananyev    if (SSL_CTX_use_certificate(ssl->ctx, x509) == 0) {
406e18a033bSKonstantin Ananyev        ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0,
407e18a033bSKonstantin Ananyev                      "SSL_CTX_use_certificate(\"%s\") failed", cert->data);
408e18a033bSKonstantin Ananyev        X509_free(x509);
409e18a033bSKonstantin Ananyev        BIO_free(bio);
410e18a033bSKonstantin Ananyev        return NGX_ERROR;
411e18a033bSKonstantin Ananyev    }
412e18a033bSKonstantin Ananyev
413e18a033bSKonstantin Ananyev    if (X509_set_ex_data(x509, ngx_ssl_certificate_name_index, cert->data)
414e18a033bSKonstantin Ananyev        == 0)
415e18a033bSKonstantin Ananyev    {
416e18a033b