1
2/*
3 * Copyright (C) Igor Sysoev
4 * Copyright (C) Nginx, Inc.
5 */
6
7
8#include <ngx_config.h>
9#include <ngx_core.h>
10#include <ngx_event.h>
11
12
13#define NGX_SSL_PASSWORD_BUFFER_SIZE  4096
14
15
16typedef struct {
17    ngx_uint_t  engine;   /* unsigned  engine:1; */
18} ngx_openssl_conf_t;
19
20
21static int ngx_ssl_password_callback(char *buf, int size, int rwflag,
22    void *userdata);
23static int ngx_ssl_verify_callback(int ok, X509_STORE_CTX *x509_store);
24static void ngx_ssl_info_callback(const ngx_ssl_conn_t *ssl_conn, int where,
25    int ret);
26static void ngx_ssl_passwords_cleanup(void *data);
27static void ngx_ssl_handshake_handler(ngx_event_t *ev);
28static ngx_int_t ngx_ssl_handle_recv(ngx_connection_t *c, int n);
29static void ngx_ssl_write_handler(ngx_event_t *wev);
30static void ngx_ssl_read_handler(ngx_event_t *rev);
31static void ngx_ssl_shutdown_handler(ngx_event_t *ev);
32static void ngx_ssl_connection_error(ngx_connection_t *c, int sslerr,
33    ngx_err_t err, char *text);
34static void ngx_ssl_clear_error(ngx_log_t *log);
35
36static ngx_int_t ngx_ssl_session_id_context(ngx_ssl_t *ssl,
37    ngx_str_t *sess_ctx);
38ngx_int_t ngx_ssl_session_cache_init(ngx_shm_zone_t *shm_zone, void *data);
39static int ngx_ssl_new_session(ngx_ssl_conn_t *ssl_conn,
40    ngx_ssl_session_t *sess);
41static ngx_ssl_session_t *ngx_ssl_get_cached_session(ngx_ssl_conn_t *ssl_conn,
42#if OPENSSL_VERSION_NUMBER >= 0x10100003L
43    const
44#endif
45    u_char *id, int len, int *copy);
46static void ngx_ssl_remove_session(SSL_CTX *ssl, ngx_ssl_session_t *sess);
47static void ngx_ssl_expire_sessions(ngx_ssl_session_cache_t *cache,
48    ngx_slab_pool_t *shpool, ngx_uint_t n);
49static void ngx_ssl_session_rbtree_insert_value(ngx_rbtree_node_t *temp,
50    ngx_rbtree_node_t *node, ngx_rbtree_node_t *sentinel);
51
52#ifdef SSL_CTRL_SET_TLSEXT_TICKET_KEY_CB
53static int ngx_ssl_session_ticket_key_callback(ngx_ssl_conn_t *ssl_conn,
54    unsigned char *name, unsigned char *iv, EVP_CIPHER_CTX *ectx,
55    HMAC_CTX *hctx, int enc);
56#endif
57
58#ifndef X509_CHECK_FLAG_ALWAYS_CHECK_SUBJECT
59static ngx_int_t ngx_ssl_check_name(ngx_str_t *name, ASN1_STRING *str);
60#endif
61
62static time_t ngx_ssl_parse_time(
63#if OPENSSL_VERSION_NUMBER > 0x10100000L
64    const
65#endif
66    ASN1_TIME *asn1time);
67
68static void *ngx_openssl_create_conf(ngx_cycle_t *cycle);
69static char *ngx_openssl_engine(ngx_conf_t *cf, ngx_command_t *cmd, void *conf);
70static void ngx_openssl_exit(ngx_cycle_t *cycle);
71
72
73static ngx_command_t  ngx_openssl_commands[] = {
74
75    { ngx_string("ssl_engine"),
76      NGX_MAIN_CONF|NGX_DIRECT_CONF|NGX_CONF_TAKE1,
77      ngx_openssl_engine,
78      0,
79      0,
80      NULL },
81
82      ngx_null_command
83};
84
85
86static ngx_core_module_t  ngx_openssl_module_ctx = {
87    ngx_string("openssl"),
88    ngx_openssl_create_conf,
89    NULL
90};
91
92
93ngx_module_t  ngx_openssl_module = {
94    NGX_MODULE_V1,
95    &ngx_openssl_module_ctx,               /* module context */
96    ngx_openssl_commands,                  /* module directives */
97    NGX_CORE_MODULE,                       /* module type */
98    NULL,                                  /* init master */
99    NULL,                                  /* init module */
100    NULL,                                  /* init process */
101    NULL,                                  /* init thread */
102    NULL,                                  /* exit thread */
103    NULL,                                  /* exit process */
104    ngx_openssl_exit,                      /* exit master */
105    NGX_MODULE_V1_PADDING
106};
107
108
109int  ngx_ssl_connection_index;
110int  ngx_ssl_server_conf_index;
111int  ngx_ssl_session_cache_index;
112int  ngx_ssl_session_ticket_keys_index;
113int  ngx_ssl_certificate_index;
114int  ngx_ssl_next_certificate_index;
115int  ngx_ssl_certificate_name_index;
116int  ngx_ssl_stapling_index;
117
118
119ngx_int_t
120ngx_ssl_init(ngx_log_t *log)
121{
122#if OPENSSL_VERSION_NUMBER >= 0x10100003L
123
124    if (OPENSSL_init_ssl(OPENSSL_INIT_LOAD_CONFIG, NULL) == 0) {
125        ngx_ssl_error(NGX_LOG_ALERT, log, 0, "OPENSSL_init_ssl() failed");
126        return NGX_ERROR;
127    }
128
129    /*
130     * OPENSSL_init_ssl() may leave errors in the error queue
131     * while returning success
132     */
133
134    ERR_clear_error();
135
136#else
137
138    OPENSSL_config(NULL);
139
140    SSL_library_init();
141    SSL_load_error_strings();
142
143    OpenSSL_add_all_algorithms();
144
145#endif
146
147#if OPENSSL_VERSION_NUMBER >= 0x0090800fL
148#ifndef SSL_OP_NO_COMPRESSION
149    {
150    /*
151     * Disable gzip compression in OpenSSL prior to 1.0.0 version,
152     * this saves about 522K per connection.
153     */
154    int                  n;
155    STACK_OF(SSL_COMP)  *ssl_comp_methods;
156
157    ssl_comp_methods = SSL_COMP_get_compression_methods();
158    n = sk_SSL_COMP_num(ssl_comp_methods);
159
160    while (n--) {
161        (void) sk_SSL_COMP_pop(ssl_comp_methods);
162    }
163    }
164#endif
165#endif
166
167    ngx_ssl_connection_index = SSL_get_ex_new_index(0, NULL, NULL, NULL, NULL);
168
169    if (ngx_ssl_connection_index == -1) {
170        ngx_ssl_error(NGX_LOG_ALERT, log, 0, "SSL_get_ex_new_index() failed");
171        return NGX_ERROR;
172    }
173
174    ngx_ssl_server_conf_index = SSL_CTX_get_ex_new_index(0, NULL, NULL, NULL,
175                                                         NULL);
176    if (ngx_ssl_server_conf_index == -1) {
177        ngx_ssl_error(NGX_LOG_ALERT, log, 0,
178                      "SSL_CTX_get_ex_new_index() failed");
179        return NGX_ERROR;
180    }
181
182    ngx_ssl_session_cache_index = SSL_CTX_get_ex_new_index(0, NULL, NULL, NULL,
183                                                           NULL);
184    if (ngx_ssl_session_cache_index == -1) {
185        ngx_ssl_error(NGX_LOG_ALERT, log, 0,
186                      "SSL_CTX_get_ex_new_index() failed");
187        return NGX_ERROR;
188    }
189
190    ngx_ssl_session_ticket_keys_index = SSL_CTX_get_ex_new_index(0, NULL, NULL,
191                                                                 NULL, NULL);
192    if (ngx_ssl_session_ticket_keys_index == -1) {
193        ngx_ssl_error(NGX_LOG_ALERT, log, 0,
194                      "SSL_CTX_get_ex_new_index() failed");
195        return NGX_ERROR;
196    }
197
198    ngx_ssl_certificate_index = SSL_CTX_get_ex_new_index(0, NULL, NULL, NULL,
199                                                         NULL);
200    if (ngx_ssl_certificate_index == -1) {
201        ngx_ssl_error(NGX_LOG_ALERT, log, 0,
202                      "SSL_CTX_get_ex_new_index() failed");
203        return NGX_ERROR;
204    }
205
206    ngx_ssl_next_certificate_index = X509_get_ex_new_index(0, NULL, NULL, NULL,
207                                                           NULL);
208    if (ngx_ssl_next_certificate_index == -1) {
209        ngx_ssl_error(NGX_LOG_ALERT, log, 0, "X509_get_ex_new_index() failed");
210        return NGX_ERROR;
211    }
212
213    ngx_ssl_certificate_name_index = X509_get_ex_new_index(0, NULL, NULL, NULL,
214                                                           NULL);
215
216    if (ngx_ssl_certificate_name_index == -1) {
217        ngx_ssl_error(NGX_LOG_ALERT, log, 0, "X509_get_ex_new_index() failed");
218        return NGX_ERROR;
219    }
220
221    ngx_ssl_stapling_index = X509_get_ex_new_index(0, NULL, NULL, NULL, NULL);
222
223    if (ngx_ssl_stapling_index == -1) {
224        ngx_ssl_error(NGX_LOG_ALERT, log, 0, "X509_get_ex_new_index() failed");
225        return NGX_ERROR;
226    }
227
228    return NGX_OK;
229}
230
231
232ngx_int_t
233ngx_ssl_create(ngx_ssl_t *ssl, ngx_uint_t protocols, void *data)
234{
235    ssl->ctx = SSL_CTX_new(SSLv23_method());
236
237    if (ssl->ctx == NULL) {
238        ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0, "SSL_CTX_new() failed");
239        return NGX_ERROR;
240    }
241
242    if (SSL_CTX_set_ex_data(ssl->ctx, ngx_ssl_server_conf_index, data) == 0) {
243        ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0,
244                      "SSL_CTX_set_ex_data() failed");
245        return NGX_ERROR;
246    }
247
248    if (SSL_CTX_set_ex_data(ssl->ctx, ngx_ssl_certificate_index, NULL) == 0) {
249        ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0,
250                      "SSL_CTX_set_ex_data() failed");
251        return NGX_ERROR;
252    }
253
254    ssl->buffer_size = NGX_SSL_BUFSIZE;
255
256    /* client side options */
257
258#ifdef SSL_OP_MICROSOFT_SESS_ID_BUG
259    SSL_CTX_set_options(ssl->ctx, SSL_OP_MICROSOFT_SESS_ID_BUG);
260#endif
261
262#ifdef SSL_OP_NETSCAPE_CHALLENGE_BUG
263    SSL_CTX_set_options(ssl->ctx, SSL_OP_NETSCAPE_CHALLENGE_BUG);
264#endif
265
266    /* server side options */
267
268#ifdef SSL_OP_SSLREF2_REUSE_CERT_TYPE_BUG
269    SSL_CTX_set_options(ssl->ctx, SSL_OP_SSLREF2_REUSE_CERT_TYPE_BUG);
270#endif
271
272#ifdef SSL_OP_MICROSOFT_BIG_SSLV3_BUFFER
273    SSL_CTX_set_options(ssl->ctx, SSL_OP_MICROSOFT_BIG_SSLV3_BUFFER);
274#endif
275
276#ifdef SSL_OP_MSIE_SSLV2_RSA_PADDING
277    /* this option allow a potential SSL 2.0 rollback (CAN-2005-2969) */
278    SSL_CTX_set_options(ssl->ctx, SSL_OP_MSIE_SSLV2_RSA_PADDING);
279#endif
280
281#ifdef SSL_OP_SSLEAY_080_CLIENT_DH_BUG
282    SSL_CTX_set_options(ssl->ctx, SSL_OP_SSLEAY_080_CLIENT_DH_BUG);
283#endif
284
285#ifdef SSL_OP_TLS_D5_BUG
286    SSL_CTX_set_options(ssl->ctx, SSL_OP_TLS_D5_BUG);
287#endif
288
289#ifdef SSL_OP_TLS_BLOCK_PADDING_BUG
290    SSL_CTX_set_options(ssl->ctx, SSL_OP_TLS_BLOCK_PADDING_BUG);
291#endif
292
293#ifdef SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS
294    SSL_CTX_set_options(ssl->ctx, SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS);
295#endif
296
297    SSL_CTX_set_options(ssl->ctx, SSL_OP_SINGLE_DH_USE);
298
299#ifdef SSL_CTRL_CLEAR_OPTIONS
300    /* only in 0.9.8m+ */
301    SSL_CTX_clear_options(ssl->ctx,
302                          SSL_OP_NO_SSLv2|SSL_OP_NO_SSLv3|SSL_OP_NO_TLSv1);
303#endif
304
305    if (!(protocols & NGX_SSL_SSLv2)) {
306        SSL_CTX_set_options(ssl->ctx, SSL_OP_NO_SSLv2);
307    }
308    if (!(protocols & NGX_SSL_SSLv3)) {
309        SSL_CTX_set_options(ssl->ctx, SSL_OP_NO_SSLv3);
310    }
311    if (!(protocols & NGX_SSL_TLSv1)) {
312        SSL_CTX_set_options(ssl->ctx, SSL_OP_NO_TLSv1);
313    }
314#ifdef SSL_OP_NO_TLSv1_1
315    SSL_CTX_clear_options(ssl->ctx, SSL_OP_NO_TLSv1_1);
316    if (!(protocols & NGX_SSL_TLSv1_1)) {
317        SSL_CTX_set_options(ssl->ctx, SSL_OP_NO_TLSv1_1);
318    }
319#endif
320#ifdef SSL_OP_NO_TLSv1_2
321    SSL_CTX_clear_options(ssl->ctx, SSL_OP_NO_TLSv1_2);
322    if (!(protocols & NGX_SSL_TLSv1_2)) {
323        SSL_CTX_set_options(ssl->ctx, SSL_OP_NO_TLSv1_2);
324    }
325#endif
326
327#ifdef SSL_OP_NO_COMPRESSION
328    SSL_CTX_set_options(ssl->ctx, SSL_OP_NO_COMPRESSION);
329#endif
330
331#ifdef SSL_MODE_RELEASE_BUFFERS
332    SSL_CTX_set_mode(ssl->ctx, SSL_MODE_RELEASE_BUFFERS);
333#endif
334
335#ifdef SSL_MODE_NO_AUTO_CHAIN
336    SSL_CTX_set_mode(ssl->ctx, SSL_MODE_NO_AUTO_CHAIN);
337#endif
338
339    SSL_CTX_set_read_ahead(ssl->ctx, 1);
340
341    SSL_CTX_set_info_callback(ssl->ctx, ngx_ssl_info_callback);
342
343    return NGX_OK;
344}
345
346
347ngx_int_t
348ngx_ssl_certificates(ngx_conf_t *cf, ngx_ssl_t *ssl, ngx_array_t *certs,
349    ngx_array_t *keys, ngx_array_t *passwords)
350{
351    ngx_str_t   *cert, *key;
352    ngx_uint_t   i;
353
354    cert = certs->elts;
355    key = keys->elts;
356
357    for (i = 0; i < certs->nelts; i++) {
358
359        if (ngx_ssl_certificate(cf, ssl, &cert[i], &key[i], passwords)
360            != NGX_OK)
361        {
362            return NGX_ERROR;
363        }
364    }
365
366    return NGX_OK;
367}
368
369
370ngx_int_t
371ngx_ssl_certificate(ngx_conf_t *cf, ngx_ssl_t *ssl, ngx_str_t *cert,
372    ngx_str_t *key, ngx_array_t *passwords)
373{
374    BIO         *bio;
375    X509        *x509;
376    u_long       n;
377    ngx_str_t   *pwd;
378    ngx_uint_t   tries;
379
380    if (ngx_conf_full_name(cf->cycle, cert, 1) != NGX_OK) {
381        return NGX_ERROR;
382    }
383
384    /*
385     * we can't use SSL_CTX_use_certificate_chain_file() as it doesn't
386     * allow to access certificate later from SSL_CTX, so we reimplement
387     * it here
388     */
389
390    bio = BIO_new_file((char *) cert->data, "r");
391    if (bio == NULL) {
392        ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0,
393                      "BIO_new_file(\"%s\") failed", cert->data);
394        return NGX_ERROR;
395    }
396
397    x509 = PEM_read_bio_X509_AUX(bio, NULL, NULL, NULL);
398    if (x509 == NULL) {
399        ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0,
400                      "PEM_read_bio_X509_AUX(\"%s\") failed", cert->data);
401        BIO_free(bio);
402        return NGX_ERROR;
403    }
404
405    if (SSL_CTX_use_certificate(ssl->ctx, x509) == 0) {
406        ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0,
407                      "SSL_CTX_use_certificate(\"%s\") failed", cert->data);
408        X509_free(x509);
409        BIO_free(bio);
410        return NGX_ERROR;
411    }
412
413    if (X509_set_ex_data(x509, ngx_ssl_certificate_name_index, cert->data)
414        == 0)
415    {
416        ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0, "X509_set_ex_data() failed");
417        X509_free(x509);
418        BIO_free(bio);
419        return NGX_ERROR;
420    }
421
422    if (X509_set_ex_data(x509, ngx_ssl_next_certificate_index,
423                      SSL_CTX_get_ex_data(ssl->ctx, ngx_ssl_certificate_index))
424        == 0)
425    {
426        ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0, "X509_set_ex_data() failed");
427        X509_free(x509);
428        BIO_free(bio);
429        return NGX_ERROR;
430    }
431
432    if (SSL_CTX_set_ex_data(ssl->ctx, ngx_ssl_certificate_index, x509)
433        == 0)
434    {
435        ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0,
436                      "SSL_CTX_set_ex_data() failed");
437        X509_free(x509);
438        BIO_free(bio);
439        return NGX_ERROR;
440    }
441
442    /* read rest of the chain */
443
444    for ( ;; ) {
445
446        x509 = PEM_read_bio_X509(bio, NULL, NULL, NULL);
447        if (x509 == NULL) {
448            n = ERR_peek_last_error();
449
450            if (ERR_GET_LIB(n) == ERR_LIB_PEM
451                && ERR_GET_REASON(n) == PEM_R_NO_START_LINE)
452            {
453                /* end of file */
454                ERR_clear_error();
455                break;
456            }
457
458            /* some real error */
459
460            ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0,
461                          "PEM_read_bio_X509(\"%s\") failed", cert->data);
462            BIO_free(bio);
463            return NGX_ERROR;
464        }
465
466#ifdef SSL_CTRL_CHAIN_CERT
467
468        /*
469         * SSL_CTX_add0_chain_cert() is needed to add chain to
470         * a particular certificate when multiple certificates are used;
471         * only available in OpenSSL 1.0.2+
472         */
473
474        if (SSL_CTX_add0_chain_cert(ssl->ctx, x509) == 0) {
475            ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0,
476                          "SSL_CTX_add0_chain_cert(\"%s\") failed",
477                          cert->data);
478            X509_free(x509);
479            BIO_free(bio);
480            return NGX_ERROR;
481        }
482
483#else
484        if (SSL_CTX_add_extra_chain_cert(ssl->ctx, x509) == 0) {
485            ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0,
486                          "SSL_CTX_add_extra_chain_cert(\"%s\") failed",
487                          cert->data);
488            X509_free(x509);
489            BIO_free(bio);
490            return NGX_ERROR;
491        }
492#endif
493    }
494
495    BIO_free(bio);
496
497    if (ngx_strncmp(key->data, "engine:", sizeof("engine:") - 1) == 0) {
498
499#ifndef OPENSSL_NO_ENGINE
500
501        u_char      *p, *last;
502        ENGINE      *engine;
503        EVP_PKEY    *pkey;
504
505        p = key->data + sizeof("engine:") - 1;
506        last = (u_char *) ngx_strchr(p, ':');
507
508        if (last == NULL) {
509            ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
510                               "invalid syntax in \"%V\"", key);
511            return NGX_ERROR;
512        }
513
514        *last = '\0';
515
516        engine = ENGINE_by_id((char *) p);
517
518        if (engine == NULL) {
519            ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0,
520                          "ENGINE_by_id(\"%s\") failed", p);
521            return NGX_ERROR;
522        }
523
524        *last++ = ':';
525
526        pkey = ENGINE_load_private_key(engine, (char *) last, 0, 0);
527
528        if (pkey == NULL) {
529            ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0,
530                          "ENGINE_load_private_key(\"%s\") failed", last);
531            ENGINE_free(engine);
532            return NGX_ERROR;
533        }
534
535        ENGINE_free(engine);
536
537        if (SSL_CTX_use_PrivateKey(ssl->ctx, pkey) == 0) {
538            ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0,
539                          "SSL_CTX_use_PrivateKey(\"%s\") failed", last);
540            EVP_PKEY_free(pkey);
541            return NGX_ERROR;
542        }
543
544        EVP_PKEY_free(pkey);
545
546        return NGX_OK;
547
548#else
549
550        ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
551                           "loading \"engine:...\" certificate keys "
552                           "is not supported");
553        return NGX_ERROR;
554
555#endif
556    }
557
558    if (ngx_conf_full_name(cf->cycle, key, 1) != NGX_OK) {
559        return NGX_ERROR;
560    }
561
562    if (passwords) {
563        tries = passwords->nelts;
564        pwd = passwords->elts;
565
566        SSL_CTX_set_default_passwd_cb(ssl->ctx, ngx_ssl_password_callback);
567        SSL_CTX_set_default_passwd_cb_userdata(ssl->ctx, pwd);
568
569    } else {
570        tries = 1;
571#if (NGX_SUPPRESS_WARN)
572        pwd = NULL;
573#endif
574    }
575
576    for ( ;; ) {
577
578        if (SSL_CTX_use_PrivateKey_file(ssl->ctx, (char *) key->data,
579                                        SSL_FILETYPE_PEM)
580            != 0)
581        {
582            break;
583        }
584
585        if (--tries) {
586            ERR_clear_error();
587            SSL_CTX_set_default_passwd_cb_userdata(ssl->ctx, ++pwd);
588            continue;
589        }
590
591        ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0,
592                      "SSL_CTX_use_PrivateKey_file(\"%s\") failed", key->data);
593        return NGX_ERROR;
594    }
595
596    SSL_CTX_set_default_passwd_cb(ssl->ctx, NULL);
597
598    return NGX_OK;
599}
600
601
602static int
603ngx_ssl_password_callback(char *buf, int size, int rwflag, void *userdata)
604{
605    ngx_str_t *pwd = userdata;
606
607    if (rwflag) {
608        ngx_log_error(NGX_LOG_ALERT, ngx_cycle->log, 0,
609                      "ngx_ssl_password_callback() is called for encryption");
610        return 0;
611    }
612
613    if (pwd->len > (size_t) size) {
614        ngx_log_error(NGX_LOG_ERR, ngx_cycle->log, 0,
615                      "password is truncated to %d bytes", size);
616    } else {
617        size = pwd->len;
618    }
619
620    ngx_memcpy(buf, pwd->data, size);
621
622    return size;
623}
624
625
626ngx_int_t
627ngx_ssl_ciphers(ngx_conf_t *cf, ngx_ssl_t *ssl, ngx_str_t *ciphers,
628    ngx_uint_t prefer_server_ciphers)
629{
630    if (SSL_CTX_set_cipher_list(ssl->ctx, (char *) ciphers->data) == 0) {
631        ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0,
632                      "SSL_CTX_set_cipher_list(\"%V\") failed",
633                      ciphers);
634        return NGX_ERROR;
635    }
636
637    if (prefer_server_ciphers) {
638        SSL_CTX_set_options(ssl->ctx, SSL_OP_CIPHER_SERVER_PREFERENCE);
639    }
640
641#if (OPENSSL_VERSION_NUMBER < 0x10100001L && !defined LIBRESSL_VERSION_NUMBER)
642    /* a temporary 512-bit RSA key is required for export versions of MSIE */
643    SSL_CTX_set_tmp_rsa_callback(ssl->ctx, ngx_ssl_rsa512_key_callback);
644#endif
645
646    return NGX_OK;
647}
648
649
650ngx_int_t
651ngx_ssl_client_certificate(ngx_conf_t *cf, ngx_ssl_t *ssl, ngx_str_t *cert,
652    ngx_int_t depth)
653{
654    STACK_OF(X509_NAME)  *list;
655
656    SSL_CTX_set_verify(ssl->ctx, SSL_VERIFY_PEER, ngx_ssl_verify_callback);
657
658    SSL_CTX_set_verify_depth(ssl->ctx, depth);
659
660    if (cert->len == 0) {
661        return NGX_OK;
662    }
663
664    if (ngx_conf_full_name(cf->cycle, cert, 1) != NGX_OK) {
665        return NGX_ERROR;
666    }
667
668    if (SSL_CTX_load_verify_locations(ssl->ctx, (char *) cert->data, NULL)
669        == 0)
670    {
671        ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0,
672                      "SSL_CTX_load_verify_locations(\"%s\") failed",
673                      cert->data);
674        return NGX_ERROR;
675    }
676
677    /*
678     * SSL_CTX_load_verify_locations() may leave errors in the error queue
679     * while returning success
680     */
681
682    ERR_clear_error();
683
684    list = SSL_load_client_CA_file((char *) cert->data);
685
686    if (list == NULL) {
687        ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0,
688                      "SSL_load_client_CA_file(\"%s\") failed", cert->data);
689        return NGX_ERROR;
690    }
691
692    /*
693     * before 0.9.7h and 0.9.8 SSL_load_client_CA_file()
694     * always leaved an error in the error queue
695     */
696
697    ERR_clear_error();
698
699    SSL_CTX_set_client_CA_list(ssl->ctx, list);
700
701    return NGX_OK;
702}
703
704
705ngx_int_t
706ngx_ssl_trusted_certificate(ngx_conf_t *cf, ngx_ssl_t *ssl, ngx_str_t *cert,
707    ngx_int_t depth)
708{
709    SSL_CTX_set_verify_depth(ssl->ctx, depth);
710
711    if (cert->len == 0) {
712        return NGX_OK;
713    }
714
715    if (ngx_conf_full_name(cf->cycle, cert, 1) != NGX_OK) {
716        return NGX_ERROR;
717    }
718
719    if (SSL_CTX_load_verify_locations(ssl->ctx, (char *) cert->data, NULL)
720        == 0)
721    {
722        ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0,
723                      "SSL_CTX_load_verify_locations(\"%s\") failed",
724                      cert->data);
725        return NGX_ERROR;
726    }
727
728    /*
729     * SSL_CTX_load_verify_locations() may leave errors in the error queue
730     * while returning success
731     */
732
733    ERR_clear_error();
734
735    return NGX_OK;
736}
737
738
739ngx_int_t
740ngx_ssl_crl(ngx_conf_t *cf, ngx_ssl_t *ssl, ngx_str_t *crl)
741{
742    X509_STORE   *store;
743    X509_LOOKUP  *lookup;
744
745    if (crl->len == 0) {
746        return NGX_OK;
747    }
748
749    if (ngx_conf_full_name(cf->cycle, crl, 1) != NGX_OK) {
750        return NGX_ERROR;
751    }
752
753    store = SSL_CTX_get_cert_store(ssl->ctx);
754
755    if (store == NULL) {
756        ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0,
757                      "SSL_CTX_get_cert_store() failed");
758        return NGX_ERROR;
759    }
760
761    lookup = X509_STORE_add_lookup(store, X509_LOOKUP_file());
762
763    if (lookup == NULL) {
764        ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0,
765                      "X509_STORE_add_lookup() failed");
766        return NGX_ERROR;
767    }
768
769    if (X509_LOOKUP_load_file(lookup, (char *) crl->data, X509_FILETYPE_PEM)
770        == 0)
771    {
772        ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0,
773                      "X509_LOOKUP_load_file(\"%s\") failed", crl->data);
774        return NGX_ERROR;
775    }
776
777    X509_STORE_set_flags(store,
778                         X509_V_FLAG_CRL_CHECK|X509_V_FLAG_CRL_CHECK_ALL);
779
780    return NGX_OK;
781}
782
783
784static int
785ngx_ssl_verify_callback(int ok, X509_STORE_CTX *x509_store)
786{
787#if (NGX_DEBUG)
788    char              *subject, *issuer;
789    int                err, depth;
790    X509              *cert;
791    X509_NAME         *sname, *iname;
792    ngx_connection_t  *c;
793    ngx_ssl_conn_t    *ssl_conn;
794
795    ssl_conn = X509_STORE_CTX_get_ex_data(x509_store,
796                                          SSL_get_ex_data_X509_STORE_CTX_idx());
797
798    c = ngx_ssl_get_connection(ssl_conn);
799
800    cert = X509_STORE_CTX_get_current_cert(x509_store);
801    err = X509_STORE_CTX_get_error(x509_store);
802    depth = X509_STORE_CTX_get_error_depth(x509_store);
803
804    sname = X509_get_subject_name(cert);
805    subject = sname ? X509_NAME_oneline(sname, NULL, 0) : "(none)";
806
807    iname = X509_get_issuer_name(cert);
808    issuer = iname ? X509_NAME_oneline(iname, NULL, 0) : "(none)";
809
810    ngx_log_debug5(NGX_LOG_DEBUG_EVENT, c->log, 0,
811                   "verify:%d, error:%d, depth:%d, "
812                   "subject:\"%s\", issuer:\"%s\"",
813                   ok, err, depth, subject, issuer);
814
815    if (sname) {
816        OPENSSL_free(subject);
817    }
818
819    if (iname) {
820        OPENSSL_free(issuer);
821    }
822#endif
823
824    return 1;
825}
826
827
828static void
829ngx_ssl_info_callback(const ngx_ssl_conn_t *ssl_conn, int where, int ret)
830{
831    BIO               *rbio, *wbio;
832    ngx_connection_t  *c;
833
834    if (where & SSL_CB_HANDSHAKE_START) {
835        c = ngx_ssl_get_connection((ngx_ssl_conn_t *) ssl_conn);
836
837        if (c->ssl->handshaked) {
838            c->ssl->renegotiation = 1;
839            ngx_log_debug0(NGX_LOG_DEBUG_EVENT, c->log, 0, "SSL renegotiation");
840        }
841    }
842
843    if ((where & SSL_CB_ACCEPT_LOOP) == SSL_CB_ACCEPT_LOOP) {
844        c = ngx_ssl_get_connection((ngx_ssl_conn_t *) ssl_conn);
845
846        if (!c->ssl->handshake_buffer_set) {
847            /*
848             * By default OpenSSL uses 4k buffer during a handshake,
849             * which is too low for long certificate chains and might
850             * result in extra round-trips.
851             *
852             * To adjust a buffer size we detect that buffering was added
853             * to write side of the connection by comparing rbio and wbio.
854             * If they are different, we assume that it's due to buffering
855             * added to wbio, and set buffer size.
856             */
857
858            rbio = SSL_get_rbio((ngx_ssl_conn_t *) ssl_conn);
859            wbio = SSL_get_wbio((ngx_ssl_conn_t *) ssl_conn);
860
861            if (rbio != wbio) {
862                (void) BIO_set_write_buffer_size(wbio, NGX_SSL_BUFSIZE);
863                c->ssl->handshake_buffer_set = 1;
864            }
865        }
866    }
867}
868
869
870RSA *
871ngx_ssl_rsa512_key_callback(ngx_ssl_conn_t *ssl_conn, int is_export,
872    int key_length)
873{
874    static RSA  *key;
875
876    if (key_length != 512) {
877        return NULL;
878    }
879
880#if (OPENSSL_VERSION_NUMBER < 0x10100003L && !defined OPENSSL_NO_DEPRECATED)
881
882    if (key == NULL) {
883        key = RSA_generate_key(512, RSA_F4, NULL, NULL);
884    }
885
886#endif
887
888    return key;
889}
890
891
892ngx_array_t *
893ngx_ssl_read_password_file(ngx_conf_t *cf, ngx_str_t *file)
894{
895    u_char              *p, *last, *end;
896    size_t               len;
897    ssize_t              n;
898    ngx_fd_t             fd;
899    ngx_str_t           *pwd;
900    ngx_array_t         *passwords;
901    ngx_pool_cleanup_t  *cln;
902    u_char               buf[NGX_SSL_PASSWORD_BUFFER_SIZE];
903
904    if (ngx_conf_full_name(cf->cycle, file, 1) != NGX_OK) {
905        return NULL;
906    }
907
908    cln = ngx_pool_cleanup_add(cf->temp_pool, 0);
909    passwords = ngx_array_create(cf->temp_pool, 4, sizeof(ngx_str_t));
910
911    if (cln == NULL || passwords == NULL) {
912        return NULL;
913    }
914
915    cln->handler = ngx_ssl_passwords_cleanup;
916    cln->data = passwords;
917
918    fd = ngx_open_file(file->data, NGX_FILE_RDONLY, NGX_FILE_OPEN, 0);
919    if (fd == NGX_INVALID_FILE) {
920        ngx_conf_log_error(NGX_LOG_EMERG, cf, ngx_errno,
921                           ngx_open_file_n " \"%s\" failed", file->data);
922        return NULL;
923    }
924
925    len = 0;
926    last = buf;
927
928    do {
929        n = ngx_read_fd(fd, last, NGX_SSL_PASSWORD_BUFFER_SIZE - len);
930
931        if (n == -1) {
932            ngx_conf_log_error(NGX_LOG_EMERG, cf, ngx_errno,
933                               ngx_read_fd_n " \"%s\" failed", file->data);
934            passwords = NULL;
935            goto cleanup;
936        }
937
938        end = last + n;
939
940        if (len && n == 0) {
941            *end++ = LF;
942        }
943
944        p = buf;
945
946        for ( ;; ) {
947            last = ngx_strlchr(last, end, LF);
948
949            if (last == NULL) {
950                break;
951            }
952
953            len = last++ - p;
954
955            if (len && p[len - 1] == CR) {
956                len--;
957            }
958
959            if (len) {
960                pwd = ngx_array_push(passwords);
961                if (pwd == NULL) {
962                    passwords = NULL;
963                    goto cleanup;
964                }
965
966                pwd->len = len;
967                pwd->data = ngx_pnalloc(cf->temp_pool, len);
968
969                if (pwd->data == NULL) {
970                    passwords->nelts--;
971                    passwords = NULL;
972                    goto cleanup;
973                }
974
975                ngx_memcpy(pwd->data, p, len);
976            }
977
978            p = last;
979        }
980
981        len = end - p;
982
983        if (len == NGX_SSL_PASSWORD_BUFFER_SIZE) {
984            ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
985                               "too long line in \"%s\"", file->data);
986            passwords = NULL;
987            goto cleanup;
988        }
989
990        ngx_memmove(buf, p, len);
991        last = buf + len;
992
993    } while (n != 0);
994
995    if (passwords->nelts == 0) {
996        pwd = ngx_array_push(passwords);
997        if (pwd == NULL) {
998            passwords = NULL;
999            goto cleanup;
1000        }
1001
1002        ngx_memzero(pwd, sizeof(ngx_str_t));
1003    }
1004
1005cleanup:
1006
1007    if (ngx_close_file(fd) == NGX_FILE_ERROR) {
1008        ngx_conf_log_error(NGX_LOG_ALERT, cf, ngx_errno,
1009                           ngx_close_file_n " \"%s\" failed", file->data);
1010    }
1011
1012    ngx_memzero(buf, NGX_SSL_PASSWORD_BUFFER_SIZE);
1013
1014    return passwords;
1015}
1016
1017
1018static void
1019ngx_ssl_passwords_cleanup(void *data)
1020{
1021    ngx_array_t *passwords = data;
1022
1023    ngx_str_t   *pwd;
1024    ngx_uint_t   i;
1025
1026    pwd = passwords->elts;
1027
1028    for (i = 0; i < passwords->nelts; i++) {
1029        ngx_memzero(pwd[i].data, pwd[i].len);
1030    }
1031}
1032
1033
1034ngx_int_t
1035ngx_ssl_dhparam(ngx_conf_t *cf, ngx_ssl_t *ssl, ngx_str_t *file)
1036{
1037    DH   *dh;
1038    BIO  *bio;
1039
1040    if (file->len == 0) {
1041        return NGX_OK;
1042    }
1043
1044    if (ngx_conf_full_name(cf->cycle, file, 1) != NGX_OK) {
1045        return NGX_ERROR;
1046    }
1047
1048    bio = BIO_new_file((char *) file->data, "r");
1049    if (bio == NULL) {
1050        ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0,
1051                      "BIO_new_file(\"%s\") failed", file->data);
1052        return NGX_ERROR;
1053    }
1054
1055    dh = PEM_read_bio_DHparams(bio, NULL, NULL, NULL);
1056    if (dh == NULL) {
1057        ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0,
1058                      "PEM_read_bio_DHparams(\"%s\") failed", file->data);
1059        BIO_free(bio);
1060        return NGX_ERROR;
1061    }
1062
1063    SSL_CTX_set_tmp_dh(ssl->ctx, dh);
1064
1065    DH_free(dh);
1066    BIO_free(bio);
1067
1068    return NGX_OK;
1069}
1070
1071
1072ngx_int_t
1073ngx_ssl_ecdh_curve(ngx_conf_t *cf, ngx_ssl_t *ssl, ngx_str_t *name)
1074{
1075#if OPENSSL_VERSION_NUMBER >= 0x0090800fL
1076#ifndef OPENSSL_NO_ECDH
1077
1078    /*
1079     * Elliptic-Curve Diffie-Hellman parameters are either "named curves"
1080     * from RFC 4492 section 5.1.1, or explicitly described curves over
1081     * binary fields.  OpenSSL only supports the "named curves", which provide
1082     * maximum interoperability.
1083     */
1084
1085#ifdef SSL_CTRL_SET_CURVES_LIST
1086
1087    /*
1088     * OpenSSL 1.0.2+ allows configuring a curve list instead of a single
1089     * curve previously supported.  By default an internal list is used,
1090     * with prime256v1 being preferred by server in OpenSSL 1.0.2b+
1091     * and X25519 in OpenSSL 1.1.0+.
1092     *
1093     * By default a curve preferred by the client will be used for
1094     * key exchange.  The SSL_OP_CIPHER_SERVER_PREFERENCE option can
1095     * be used to prefer server curves instead, similar to what it
1096     * does for ciphers.
1097     */
1098
1099    SSL_CTX_set_options(ssl->ctx, SSL_OP_SINGLE_ECDH_USE);
1100
1101#if SSL_CTRL_SET_ECDH_AUTO
1102    /* not needed in OpenSSL 1.1.0+ */
1103    SSL_CTX_set_ecdh_auto(ssl->ctx, 1);
1104#endif
1105
1106    if (ngx_strcmp(name->data, "auto") == 0) {
1107        return NGX_OK;
1108    }
1109
1110    if (SSL_CTX_set1_curves_list(ssl->ctx, (char *) name->data) == 0) {
1111        ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0,
1112                      "SSL_CTX_set1_curves_list(\"%s\") failed", name->data);
1113        return NGX_ERROR;
1114    }
1115
1116#else
1117
1118    int      nid;
1119    char    *curve;
1120    EC_KEY  *ecdh;
1121
1122    if (ngx_strcmp(name->data, "auto") == 0) {
1123        curve = "prime256v1";
1124
1125    } else {
1126        curve = (char *) name->data;
1127    }
1128
1129    nid = OBJ_sn2nid(curve);
1130    if (nid == 0) {
1131        ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0,
1132                      "OBJ_sn2nid(\"%s\") failed: unknown curve", curve);
1133        return NGX_ERROR;
1134    }
1135
1136    ecdh = EC_KEY_new_by_curve_name(nid);
1137    if (ecdh == NULL) {
1138        ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0,
1139                      "EC_KEY_new_by_curve_name(\"%s\") failed", curve);
1140        return NGX_ERROR;
1141    }
1142
1143    SSL_CTX_set_options(ssl->ctx, SSL_OP_SINGLE_ECDH_USE);
1144
1145    SSL_CTX_set_tmp_ecdh(ssl->ctx, ecdh);
1146
1147    EC_KEY_free(ecdh);
1148#endif
1149#endif
1150#endif
1151
1152    return NGX_OK;
1153}
1154
1155
1156ngx_int_t
1157ngx_ssl_create_connection(ngx_ssl_t *ssl, ngx_connection_t *c, ngx_uint_t flags)
1158{
1159    ngx_ssl_connection_t  *sc;
1160
1161    sc = ngx_pcalloc(c->pool, sizeof(ngx_ssl_connection_t));
1162    if (sc == NULL) {
1163        return NGX_ERROR;
1164    }
1165
1166    sc->buffer = ((flags & NGX_SSL_BUFFER) != 0);
1167    sc->buffer_size = ssl->buffer_size;
1168
1169    sc->session_ctx = ssl->ctx;
1170
1171    sc->connection = SSL_new(ssl->ctx);
1172
1173    if (sc->connection == NULL) {
1174        ngx_ssl_error(NGX_LOG_ALERT, c->log, 0, "SSL_new() failed");
1175        return NGX_ERROR;
1176    }
1177
1178    if (SSL_set_fd(sc->connection, c->fd) == 0) {
1179        ngx_ssl_error(NGX_LOG_ALERT, c->log, 0, "SSL_set_fd() failed");
1180        return NGX_ERROR;
1181    }
1182
1183    if (flags & NGX_SSL_CLIENT) {
1184        SSL_set_connect_state(sc->connection);
1185
1186    } else {
1187        SSL_set_accept_state(sc->connection);
1188    }
1189
1190    if (SSL_set_ex_data(sc->connection, ngx_ssl_connection_index, c) == 0) {
1191        ngx_ssl_error(NGX_LOG_ALERT, c->log, 0, "SSL_set_ex_data() failed");
1192        return NGX_ERROR;
1193    }
1194
1195    c->ssl = sc;
1196
1197    return NGX_OK;
1198}
1199
1200
1201ngx_int_t
1202ngx_ssl_set_session(ngx_connection_t *c, ngx_ssl_session_t *session)
1203{
1204    if (session) {
1205        if (SSL_set_session(c->ssl->connection, session) == 0) {
1206            ngx_ssl_error(NGX_LOG_ALERT, c->log, 0, "SSL_set_session() failed");
1207            return NGX_ERROR;
1208        }
1209    }
1210
1211    return NGX_OK;
1212}
1213
1214
1215ngx_int_t
1216ngx_ssl_handshake(ngx_connection_t *c)
1217{
1218    int        n, sslerr;
1219    ngx_err_t  err;
1220
1221    ngx_ssl_clear_error(c->log);
1222
1223    n = SSL_do_handshake(c->ssl->connection);
1224
1225    ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0, "SSL_do_handshake: %d", n);
1226
1227    if (n == 1) {
1228
1229        if (ngx_handle_read_event(c->read, 0) != NGX_OK) {
1230            return NGX_ERROR;
1231        }
1232
1233        if (ngx_handle_write_event(c->write, 0) != NGX_OK) {
1234            return NGX_ERROR;
1235        }
1236
1237#if (NGX_DEBUG)
1238        {
1239        char         buf[129], *s, *d;
1240#if OPENSSL_VERSION_NUMBER >= 0x10000000L
1241        const
1242#endif
1243        SSL_CIPHER  *cipher;
1244
1245        cipher = SSL_get_current_cipher(c->ssl->connection);
1246
1247        if (cipher) {
1248            SSL_CIPHER_description(cipher, &buf[1], 128);
1249
1250            for (s = &buf[1], d = buf; *s; s++) {
1251                if (*s == ' ' && *d == ' ') {
1252                    continue;
1253                }
1254
1255                if (*s == LF || *s == CR) {
1256                    continue;
1257                }
1258
1259                *++d = *s;
1260            }
1261
1262            if (*d != ' ') {
1263                d++;
1264            }
1265
1266            *d = '\0';
1267
1268            ngx_log_debug2(NGX_LOG_DEBUG_EVENT, c->log, 0,
1269                           "SSL: %s, cipher: \"%s\"",
1270                           SSL_get_version(c->ssl->connection), &buf[1]);
1271
1272            if (SSL_session_reused(c->ssl->connection)) {
1273                ngx_log_debug0(NGX_LOG_DEBUG_EVENT, c->log, 0,
1274                               "SSL reused session");
1275            }
1276
1277        } else {
1278            ngx_log_debug0(NGX_LOG_DEBUG_EVENT, c->log, 0,
1279                           "SSL no shared ciphers");
1280        }
1281        }
1282#endif
1283
1284        c->ssl->handshaked = 1;
1285
1286        c->recv = ngx_ssl_recv;
1287        c->send = ngx_ssl_write;
1288        c->recv_chain = ngx_ssl_recv_chain;
1289        c->send_chain = ngx_ssl_send_chain;
1290
1291#if OPENSSL_VERSION_NUMBER < 0x10100000L
1292#ifdef SSL3_FLAGS_NO_RENEGOTIATE_CIPHERS
1293
1294        /* initial handshake done, disable renegotiation (CVE-2009-3555) */
1295        if (c->ssl->connection->s3) {
1296            c->ssl->connection->s3->flags |= SSL3_FLAGS_NO_RENEGOTIATE_CIPHERS;
1297        }
1298
1299#endif
1300#endif
1301
1302        return NGX_OK;
1303    }
1304
1305    sslerr = SSL_get_error(c->ssl->connection, n);
1306
1307    ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0, "SSL_get_error: %d", sslerr);
1308
1309    if (sslerr == SSL_ERROR_WANT_READ) {
1310        c->read->ready = 0;
1311        c->read->handler = ngx_ssl_handshake_handler;
1312        c->write->handler = ngx_ssl_handshake_handler;
1313
1314        if (ngx_handle_read_event(c->read, 0) != NGX_OK) {
1315            return NGX_ERROR;
1316        }
1317
1318        if (ngx_handle_write_event(c->write, 0) != NGX_OK) {
1319            return NGX_ERROR;
1320        }
1321
1322        return NGX_AGAIN;
1323    }
1324
1325    if (sslerr == SSL_ERROR_WANT_WRITE) {
1326        c->write->ready = 0;
1327        c->read->handler = ngx_ssl_handshake_handler;
1328        c->write->handler = ngx_ssl_handshake_handler;
1329
1330        if (ngx_handle_read_event(c->read, 0) != NGX_OK) {
1331            return NGX_ERROR;
1332        }
1333
1334        if (ngx_handle_write_event(c->write, 0) != NGX_OK) {
1335            return NGX_ERROR;
1336        }
1337
1338        return NGX_AGAIN;
1339    }
1340
1341    err = (sslerr == SSL_ERROR_SYSCALL) ? ngx_errno : 0;
1342
1343    c->ssl->no_wait_shutdown = 1;
1344    c->ssl->no_send_shutdown = 1;
1345    c->read->eof = 1;
1346
1347    if (sslerr == SSL_ERROR_ZERO_RETURN || ERR_peek_error() == 0) {
1348        ngx_connection_error(c, err,
1349                             "peer closed connection in SSL handshake");
1350
1351        return NGX_ERROR;
1352    }
1353
1354    c->read->error = 1;
1355
1356    ngx_ssl_connection_error(c, sslerr, err, "SSL_do_handshake() failed");
1357
1358    return NGX_ERROR;
1359}
1360
1361
1362static void
1363ngx_ssl_handshake_handler(ngx_event_t *ev)
1364{
1365    ngx_connection_t  *c;
1366
1367    c = ev->data;
1368
1369    ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0,
1370                   "SSL handshake handler: %d", ev->write);
1371
1372    if (ev->timedout) {
1373        c->ssl->handler(c);
1374        return;
1375    }
1376
1377    if (ngx_ssl_handshake(c) == NGX_AGAIN) {
1378        return;
1379    }
1380
1381    c->ssl->handler(c);
1382}
1383
1384
1385ssize_t
1386ngx_ssl_recv_chain(ngx_connection_t *c, ngx_chain_t *cl, off_t limit)
1387{
1388    u_char     *last;
1389    ssize_t     n, bytes, size;
1390    ngx_buf_t  *b;
1391
1392    bytes = 0;
1393
1394    b = cl->buf;
1395    last = b->last;
1396
1397    for ( ;; ) {
1398        size = b->end - last;
1399
1400        if (limit) {
1401            if (bytes >= limit) {
1402                return bytes;
1403            }
1404
1405            if (bytes + size > limit) {
1406                size = (ssize_t) (limit - bytes);
1407            }
1408        }
1409
1410        n = ngx_ssl_recv(c, last, size);
1411
1412        if (n > 0) {
1413            last += n;
1414            bytes += n;
1415
1416            if (last == b->end) {
1417                cl = cl->next;
1418
1419                if (cl == NULL) {
1420                    return bytes;
1421                }
1422
1423                b = cl->buf;
1424                last = b->last;
1425            }
1426
1427            continue;
1428        }
1429
1430        if (bytes) {
1431
1432            if (n == 0 || n == NGX_ERROR) {
1433                c->read->ready = 1;
1434            }
1435
1436            return bytes;
1437        }
1438
1439        return n;
1440    }
1441}
1442
1443
1444ssize_t
1445ngx_ssl_recv(ngx_connection_t *c, u_char *buf, size_t size)
1446{
1447    int  n, bytes;
1448
1449    if (c->ssl->last == NGX_ERROR) {
1450        c->read->error = 1;
1451        return NGX_ERROR;
1452    }
1453
1454    if (c->ssl->last == NGX_DONE) {
1455        c->read->ready = 0;
1456        c->read->eof = 1;
1457        return 0;
1458    }
1459
1460    bytes = 0;
1461
1462    ngx_ssl_clear_error(c->log);
1463
1464    /*
1465     * SSL_read() may return data in parts, so try to read
1466     * until SSL_read() would return no data
1467     */
1468
1469    for ( ;; ) {
1470
1471        n = SSL_read(c->ssl->connection, buf, size);
1472
1473        ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0, "SSL_read: %d", n);
1474
1475        if (n > 0) {
1476            bytes += n;
1477        }
1478
1479        c->ssl->last = ngx_ssl_handle_recv(c, n);
1480
1481        if (c->ssl->last == NGX_OK) {
1482
1483            size -= n;
1484
1485            if (size == 0) {
1486                c->read->ready = 1;
1487                return bytes;
1488            }
1489
1490            buf += n;
1491
1492            continue;
1493        }
1494
1495        if (bytes) {
1496            if (c->ssl->last != NGX_AGAIN) {
1497                c->read->ready = 1;
1498            }
1499
1500            return bytes;
1501        }
1502
1503        switch (c->ssl->last) {
1504
1505        case NGX_DONE:
1506            c->read->ready = 0;
1507            c->read->eof = 1;
1508            return 0;
1509
1510        case NGX_ERROR:
1511            c->read->error = 1;
1512
1513            /* fall through */
1514
1515        case NGX_AGAIN:
1516            return c->ssl->last;
1517        }
1518    }
1519}
1520
1521
1522static ngx_int_t
1523ngx_ssl_handle_recv(ngx_connection_t *c, int n)
1524{
1525    int        sslerr;
1526    ngx_err_t  err;
1527
1528    if (c->ssl->renegotiation) {
1529        /*
1530         * disable renegotiation (CVE-2009-3555):
1531         * OpenSSL (at least up to 0.9.8l) does not handle disabled
1532         * renegotiation gracefully, so drop connection here
1533         */
1534
1535        ngx_log_error(NGX_LOG_NOTICE, c->log, 0, "SSL renegotiation disabled");
1536
1537        while (ERR_peek_error()) {
1538            ngx_ssl_error(NGX_LOG_DEBUG, c->log, 0,
1539                          "ignoring stale global SSL error");
1540        }
1541
1542        ERR_clear_error();
1543
1544        c->ssl->no_wait_shutdown = 1;
1545        c->ssl->no_send_shutdown = 1;
1546
1547        return NGX_ERROR;
1548    }
1549
1550    if (n > 0) {
1551
1552        if (c->ssl->saved_write_handler) {
1553
1554            c->write->handler = c->ssl->saved_write_handler;
1555            c->ssl->saved_write_handler = NULL;
1556            c->write->ready = 1;
1557
1558            if (ngx_handle_write_event(c->write, 0) != NGX_OK) {
1559                return NGX_ERROR;
1560            }
1561
1562            ngx_post_event(c->write, &ngx_posted_events);
1563        }
1564
1565        return NGX_OK;
1566    }
1567
1568    sslerr = SSL_get_error(c->ssl->connection, n);
1569
1570    err = (sslerr == SSL_ERROR_SYSCALL) ? ngx_errno : 0;
1571
1572    ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0, "SSL_get_error: %d", sslerr);
1573
1574    if (sslerr == SSL_ERROR_WANT_READ) {
1575        c->read->ready = 0;
1576        return NGX_AGAIN;
1577    }
1578
1579    if (sslerr == SSL_ERROR_WANT_WRITE) {
1580
1581        ngx_log_error(NGX_LOG_INFO, c->log, 0,
1582                      "peer started SSL renegotiation");
1583
1584        c->write->ready = 0;
1585
1586        if (ngx_handle_write_event(c->write, 0) != NGX_OK) {
1587            return NGX_ERROR;
1588        }
1589
1590        /*
1591         * we do not set the timer because there is already the read event timer
1592         */
1593
1594        if (c->ssl->saved_write_handler == NULL) {
1595            c->ssl->saved_write_handler = c->write->handler;
1596            c->write->handler = ngx_ssl_write_handler;
1597        }
1598
1599        return NGX_AGAIN;
1600    }
1601
1602    c->ssl->no_wait_shutdown = 1;
1603    c->ssl->no_send_shutdown = 1;
1604
1605    if (sslerr == SSL_ERROR_ZERO_RETURN || ERR_peek_error() == 0) {
1606        ngx_log_debug0(NGX_LOG_DEBUG_EVENT, c->log, 0,
1607                       "peer shutdown SSL cleanly");
1608        return NGX_DONE;
1609    }
1610
1611    ngx_ssl_connection_error(c, sslerr, err, "SSL_read() failed");
1612
1613    return NGX_ERROR;
1614}
1615
1616
1617static void
1618ngx_ssl_write_handler(ngx_event_t *wev)
1619{
1620    ngx_connection_t  *c;
1621
1622    c = wev->data;
1623
1624    c->read->handler(c->read);
1625}
1626
1627
1628/*
1629 * OpenSSL has no SSL_writev() so we copy several bufs into our 16K buffer
1630 * before the SSL_write() call to decrease a SSL overhead.
1631 *
1632 * Besides for protocols such as HTTP it is possible to always buffer
1633 * the output to decrease a SSL overhead some more.
1634 */
1635
1636ngx_chain_t *
1637ngx_ssl_send_chain(ngx_connection_t *c, ngx_chain_t *in, off_t limit)
1638{
1639    int          n;
1640    ngx_uint_t   flush;
1641    ssize_t      send, size;
1642    ngx_buf_t   *buf;
1643
1644    if (!c->ssl->buffer) {
1645
1646        while (in) {
1647            if (ngx_buf_special(in->buf)) {
1648                in = in->next;
1649                continue;
1650            }
1651
1652            n = ngx_ssl_write(c, in->buf->pos, in->buf->last - in->buf->pos);
1653
1654            if (n == NGX_ERROR) {
1655                return NGX_CHAIN_ERROR;
1656            }
1657
1658            if (n == NGX_AGAIN) {
1659                return in;
1660            }
1661
1662            in->buf->pos += n;
1663
1664            if (in->buf->pos == in->buf->last) {
1665                in = in->next;
1666            }
1667        }
1668
1669        return in;
1670    }
1671
1672
1673    /* the maximum limit size is the maximum int32_t value - the page size */
1674
1675    if (limit == 0 || limit > (off_t) (NGX_MAX_INT32_VALUE - ngx_pagesize)) {
1676        limit = NGX_MAX_INT32_VALUE - ngx_pagesize;
1677    }
1678
1679    buf = c->ssl->buf;
1680
1681    if (buf == NULL) {
1682        buf = ngx_create_temp_buf(c->pool, c->ssl->buffer_size);
1683        if (buf == NULL) {
1684            return NGX_CHAIN_ERROR;
1685        }
1686
1687        c->ssl->buf = buf;
1688    }
1689
1690    if (buf->start == NULL) {
1691        buf->start = ngx_palloc(c->pool, c->ssl->buffer_size);
1692        if (buf->start == NULL) {
1693            return NGX_CHAIN_ERROR;
1694        }
1695
1696        buf->pos = buf->start;
1697        buf->last = buf->start;
1698        buf->end = buf->start + c->ssl->buffer_size;
1699    }
1700
1701    send = buf->last - buf->pos;
1702    flush = (in == NULL) ? 1 : buf->flush;
1703
1704    for ( ;; ) {
1705
1706        while (in && buf->last < buf->end && send < limit) {
1707            if (in->buf->last_buf || in->buf->flush) {
1708                flush = 1;
1709            }
1710
1711            if (ngx_buf_special(in->buf)) {
1712                in = in->next;
1713                continue;
1714            }
1715
1716            size = in->buf->last - in->buf->pos;
1717
1718            if (size > buf->end - buf->last) {
1719                size = buf->end - buf->last;
1720            }
1721
1722            if (send + size > limit) {
1723                size = (ssize_t) (limit - send);
1724            }
1725
1726            ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0,
1727                           "SSL buf copy: %z", size);
1728
1729            ngx_memcpy(buf->last, in->buf->pos, size);
1730
1731            buf->last += size;
1732            in->buf->pos += size;
1733            send += size;
1734
1735            if (in->buf->pos == in->buf->last) {
1736                in = in->next;
1737            }
1738        }
1739
1740        if (!flush && send < limit && buf->last < buf->end) {
1741            break;
1742        }
1743
1744        size = buf->last - buf->pos;
1745
1746        if (size == 0) {
1747            buf->flush = 0;
1748            c->buffered &= ~NGX_SSL_BUFFERED;
1749            return in;
1750        }
1751
1752        n = ngx_ssl_write(c, buf->pos, size);
1753
1754        if (n == NGX_ERROR) {
1755            return NGX_CHAIN_ERROR;
1756        }
1757
1758        if (n == NGX_AGAIN) {
1759            break;
1760        }
1761
1762        buf->pos += n;
1763
1764        if (n < size) {
1765            break;
1766        }
1767
1768        flush = 0;
1769
1770        buf->pos = buf->start;
1771        buf->last = buf->start;
1772
1773        if (in == NULL || send == limit) {
1774            break;
1775        }
1776    }
1777
1778    buf->flush = flush;
1779
1780    if (buf->pos < buf->last) {
1781        c->buffered |= NGX_SSL_BUFFERED;
1782
1783    } else {
1784        c->buffered &= ~NGX_SSL_BUFFERED;
1785    }
1786
1787    return in;
1788}
1789
1790
1791ssize_t
1792ngx_ssl_write(ngx_connection_t *c, u_char *data, size_t size)
1793{
1794    int        n, sslerr;
1795    ngx_err_t  err;
1796
1797    ngx_ssl_clear_error(c->log);
1798
1799    ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0, "SSL to write: %uz", size);
1800
1801    n = SSL_write(c->ssl->connection, data, size);
1802
1803    ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0, "SSL_write: %d", n);
1804
1805    if (n > 0) {
1806
1807        if (c->ssl->saved_read_handler) {
1808
1809            c->read->handler = c->ssl->saved_read_handler;
1810            c->ssl->saved_read_handler = NULL;
1811            c->read->ready = 1;
1812
1813            if (ngx_handle_read_event(c->read, 0) != NGX_OK) {
1814                return NGX_ERROR;
1815            }
1816
1817            ngx_post_event(c->read, &ngx_posted_events);
1818        }
1819
1820        c->sent += n;
1821
1822        return n;
1823    }
1824
1825    sslerr = SSL_get_error(c->ssl->connection, n);
1826
1827    err = (sslerr == SSL_ERROR_SYSCALL) ? ngx_errno : 0;
1828
1829    ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0, "SSL_get_error: %d", sslerr);
1830
1831    if (sslerr == SSL_ERROR_WANT_WRITE) {
1832        c->write->ready = 0;
1833        return NGX_AGAIN;
1834    }
1835
1836    if (sslerr == SSL_ERROR_WANT_READ) {
1837
1838        ngx_log_error(NGX_LOG_INFO, c->log, 0,
1839                      "peer started SSL renegotiation");
1840
1841        c->read->ready = 0;
1842
1843        if (ngx_handle_read_event(c->read, 0) != NGX_OK) {
1844            return NGX_ERROR;
1845        }
1846
1847        /*
1848         * we do not set the timer because there is already
1849         * the write event timer
1850         */
1851
1852        if (c->ssl->saved_read_handler == NULL) {
1853            c->ssl->saved_read_handler = c->read->handler;
1854            c->read->handler = ngx_ssl_read_handler;
1855        }
1856
1857        return NGX_AGAIN;
1858    }
1859
1860    c->ssl->no_wait_shutdown = 1;
1861    c->ssl->no_send_shutdown = 1;
1862    c->write->error = 1;
1863
1864    ngx_ssl_connection_error(c, sslerr, err, "SSL_write() failed");
1865
1866    return NGX_ERROR;
1867}
1868
1869
1870static void
1871ngx_ssl_read_handler(ngx_event_t *rev)
1872{
1873    ngx_connection_t  *c;
1874
1875    c = rev->data;
1876
1877    c->write->handler(c->write);
1878}
1879
1880
1881void
1882ngx_ssl_free_buffer(ngx_connection_t *c)
1883{
1884    if (c->ssl->buf && c->ssl->buf->start) {
1885        if (ngx_pfree(c->pool, c->ssl->buf->start) == NGX_OK) {
1886            c->ssl->buf->start = NULL;
1887        }
1888    }
1889}
1890
1891
1892ngx_int_t
1893ngx_ssl_shutdown(ngx_connection_t *c)
1894{
1895    int        n, sslerr, mode;
1896    ngx_err_t  err;
1897
1898    if (SSL_in_init(c->ssl->connection)) {
1899        /*
1900         * OpenSSL 1.0.2f complains if SSL_shutdown() is called during
1901         * an SSL handshake, while previous versions always return 0.
1902         * Avoid calling SSL_shutdown() if handshake wasn't completed.
1903         */
1904
1905        SSL_free(c->ssl->connection);
1906        c->ssl = NULL;
1907
1908        return NGX_OK;
1909    }
1910
1911    if (c->timedout) {
1912        mode = SSL_RECEIVED_SHUTDOWN|SSL_SENT_SHUTDOWN;
1913        SSL_set_quiet_shutdown(c->ssl->connection, 1);
1914
1915    } else {
1916        mode = SSL_get_shutdown(c->ssl->connection);
1917
1918        if (c->ssl->no_wait_shutdown) {
1919            mode |= SSL_RECEIVED_SHUTDOWN;
1920        }
1921
1922        if (c->ssl->no_send_shutdown) {
1923            mode |= SSL_SENT_SHUTDOWN;
1924        }
1925
1926        if (c->ssl->no_wait_shutdown && c->ssl->no_send_shutdown) {
1927            SSL_set_quiet_shutdown(c->ssl->connection, 1);
1928        }
1929    }
1930
1931    SSL_set_shutdown(c->ssl->connection, mode);
1932
1933    ngx_ssl_clear_error(c->log);
1934
1935    n = SSL_shutdown(c->ssl->connection);
1936
1937    ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0, "SSL_shutdown: %d", n);
1938
1939    sslerr = 0;
1940
1941    /* before 0.9.8m SSL_shutdown() returned 0 instead of -1 on errors */
1942
1943    if (n != 1 && ERR_peek_error()) {
1944        sslerr = SSL_get_error(c->ssl->connection, n);
1945
1946        ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0,
1947                       "SSL_get_error: %d", sslerr);
1948    }
1949
1950    if (n == 1 || sslerr == 0 || sslerr == SSL_ERROR_ZERO_RETURN) {
1951        SSL_free(c->ssl->connection);
1952        c->ssl = NULL;
1953
1954        return NGX_OK;
1955    }
1956
1957    if (sslerr == SSL_ERROR_WANT_READ || sslerr == SSL_ERROR_WANT_WRITE) {
1958        c->read->handler = ngx_ssl_shutdown_handler;
1959        c->write->handler = ngx_ssl_shutdown_handler;
1960
1961        if (ngx_handle_read_event(c->read, 0) != NGX_OK) {
1962            return NGX_ERROR;
1963        }
1964
1965        if (ngx_handle_write_event(c->write, 0) != NGX_OK) {
1966            return NGX_ERROR;
1967        }
1968
1969        if (sslerr == SSL_ERROR_WANT_READ) {
1970            ngx_add_timer(c->read, 30000);
1971        }
1972
1973        return NGX_AGAIN;
1974    }
1975
1976    err = (sslerr == SSL_ERROR_SYSCALL) ? ngx_errno : 0;
1977
1978    ngx_ssl_connection_error(c, sslerr, err, "SSL_shutdown() failed");
1979
1980    SSL_free(c->ssl->connection);
1981    c->ssl = NULL;
1982
1983    return NGX_ERROR;
1984}
1985
1986
1987static void
1988ngx_ssl_shutdown_handler(ngx_event_t *ev)
1989{
1990    ngx_connection_t           *c;
1991    ngx_connection_handler_pt   handler;
1992
1993    c = ev->data;
1994    handler = c->ssl->handler;
1995
1996    if (ev->timedout) {
1997        c->timedout = 1;
1998    }
1999
2000    ngx_log_debug0(NGX_LOG_DEBUG_EVENT, ev->log, 0, "SSL shutdown handler");
2001
2002    if (ngx_ssl_shutdown(c) == NGX_AGAIN) {
2003        return;
2004    }
2005
2006    handler(c);
2007}
2008
2009
2010static void
2011ngx_ssl_connection_error(ngx_connection_t *c, int sslerr, ngx_err_t err,
2012    char *text)
2013{
2014    int         n;
2015    ngx_uint_t  level;
2016
2017    level = NGX_LOG_CRIT;
2018
2019    if (sslerr == SSL_ERROR_SYSCALL) {
2020
2021        if (err == NGX_ECONNRESET
2022            || err == NGX_EPIPE
2023            || err == NGX_ENOTCONN
2024            || err == NGX_ETIMEDOUT
2025            || err == NGX_ECONNREFUSED
2026            || err == NGX_ENETDOWN
2027            || err == NGX_ENETUNREACH
2028            || err == NGX_EHOSTDOWN
2029            || err == NGX_EHOSTUNREACH)
2030        {
2031            switch (c->log_error) {
2032
2033            case NGX_ERROR_IGNORE_ECONNRESET:
2034            case NGX_ERROR_INFO:
2035                level = NGX_LOG_INFO;
2036                break;
2037
2038            case NGX_ERROR_ERR:
2039                level = NGX_LOG_ERR;
2040                break;
2041
2042            default:
2043                break;
2044            }
2045        }
2046
2047    } else if (sslerr == SSL_ERROR_SSL) {
2048
2049        n = ERR_GET_REASON(ERR_peek_error());
2050
2051            /* handshake failures */
2052        if (n == SSL_R_BAD_CHANGE_CIPHER_SPEC                        /*  103 */
2053            || n == SSL_R_BLOCK_CIPHER_PAD_IS_WRONG                  /*  129 */
2054            || n == SSL_R_DIGEST_CHECK_FAILED                        /*  149 */
2055            || n == SSL_R_ERROR_IN_RECEIVED_CIPHER_LIST              /*  151 */
2056            || n == SSL_R_EXCESSIVE_MESSAGE_SIZE                     /*  152 */
2057            || n == SSL_R_LENGTH_MISMATCH                            /*  159 */
2058#ifdef SSL_R_NO_CIPHERS_PASSED
2059            || n == SSL_R_NO_CIPHERS_PASSED                          /*  182 */
2060#endif
2061            || n == SSL_R_NO_CIPHERS_SPECIFIED                       /*  183 */
2062            || n == SSL_R_NO_COMPRESSION_SPECIFIED                   /*  187 */
2063            || n == SSL_R_NO_SHARED_CIPHER                           /*  193 */
2064            || n == SSL_R_RECORD_LENGTH_MISMATCH                     /*  213 */
2065#ifdef SSL_R_PARSE_TLSEXT
2066            || n == SSL_R_PARSE_TLSEXT                               /*  227 */
2067#endif
2068            || n == SSL_R_UNEXPECTED_MESSAGE                         /*  244 */
2069            || n == SSL_R_UNEXPECTED_RECORD                          /*  245 */
2070            || n == SSL_R_UNKNOWN_ALERT_TYPE                         /*  246 */
2071            || n == SSL_R_UNKNOWN_PROTOCOL                           /*  252 */
2072            || n == SSL_R_WRONG_VERSION_NUMBER                       /*  267 */
2073            || n == SSL_R_DECRYPTION_FAILED_OR_BAD_RECORD_MAC        /*  281 */
2074#ifdef SSL_R_RENEGOTIATE_EXT_TOO_LONG
2075            || n == SSL_R_RENEGOTIATE_EXT_TOO_LONG                   /*  335 */
2076            || n == SSL_R_RENEGOTIATION_ENCODING_ERR                 /*  336 */
2077            || n == SSL_R_RENEGOTIATION_MISMATCH                     /*  337 */
2078#endif
2079#ifdef SSL_R_UNSAFE_LEGACY_RENEGOTIATION_DISABLED
2080            || n == SSL_R_UNSAFE_LEGACY_RENEGOTIATION_DISABLED       /*  338 */
2081#endif
2082#ifdef SSL_R_SCSV_RECEIVED_WHEN_RENEGOTIATING
2083            || n == SSL_R_SCSV_RECEIVED_WHEN_RENEGOTIATING           /*  345 */
2084#endif
2085#ifdef SSL_R_INAPPROPRIATE_FALLBACK
2086            || n == SSL_R_INAPPROPRIATE_FALLBACK                     /*  373 */
2087#endif
2088            || n == 1000 /* SSL_R_SSLV3_ALERT_CLOSE_NOTIFY */
2089#ifdef SSL_R_SSLV3_ALERT_UNEXPECTED_MESSAGE
2090            || n == SSL_R_SSLV3_ALERT_UNEXPECTED_MESSAGE             /* 1010 */
2091            || n == SSL_R_SSLV3_ALERT_BAD_RECORD_MAC                 /* 1020 */
2092            || n == SSL_R_TLSV1_ALERT_DECRYPTION_FAILED              /* 1021 */
2093            || n == SSL_R_TLSV1_ALERT_RECORD_OVERFLOW                /* 1022 */
2094            || n == SSL_R_SSLV3_ALERT_DECOMPRESSION_FAILURE          /* 1030 */
2095            || n == SSL_R_SSLV3_ALERT_HANDSHAKE_FAILURE              /* 1040 */
2096            || n == SSL_R_SSLV3_ALERT_NO_CERTIFICATE                 /* 1041 */
2097            || n == SSL_R_SSLV3_ALERT_BAD_CERTIFICATE                /* 1042 */
2098            || n == SSL_R_SSLV3_ALERT_UNSUPPORTED_CERTIFICATE        /* 1043 */
2099            || n == SSL_R_SSLV3_ALERT_CERTIFICATE_REVOKED            /* 1044 */
2100            || n == SSL_R_SSLV3_ALERT_CERTIFICATE_EXPIRED            /* 1045 */
2101            || n == SSL_R_SSLV3_ALERT_CERTIFICATE_UNKNOWN            /* 1046 */
2102            || n == SSL_R_SSLV3_ALERT_ILLEGAL_PARAMETER              /* 1047 */
2103            || n == SSL_R_TLSV1_ALERT_UNKNOWN_CA                     /* 1048 */
2104            || n == SSL_R_TLSV1_ALERT_ACCESS_DENIED                  /* 1049 */
2105            || n == SSL_R_TLSV1_ALERT_DECODE_ERROR                   /* 1050 */
2106            || n == SSL_R_TLSV1_ALERT_DECRYPT_ERROR                  /* 1051 */
2107            || n == SSL_R_TLSV1_ALERT_EXPORT_RESTRICTION             /* 1060 */
2108            || n == SSL_R_TLSV1_ALERT_PROTOCOL_VERSION               /* 1070 */
2109            || n == SSL_R_TLSV1_ALERT_INSUFFICIENT_SECURITY          /* 1071 */
2110            || n == SSL_R_TLSV1_ALERT_INTERNAL_ERROR                 /* 1080 */
2111            || n == SSL_R_TLSV1_ALERT_USER_CANCELLED                 /* 1090 */
2112            || n == SSL_R_TLSV1_ALERT_NO_RENEGOTIATION               /* 1100 */
2113#endif
2114            )
2115        {
2116            switch (c->log_error) {
2117
2118            case NGX_ERROR_IGNORE_ECONNRESET:
2119            case NGX_ERROR_INFO:
2120                level = NGX_LOG_INFO;
2121                break;
2122
2123            case NGX_ERROR_ERR:
2124                level = NGX_LOG_ERR;
2125                break;
2126
2127            default:
2128                break;
2129            }
2130        }
2131    }
2132
2133    ngx_ssl_error(level, c->log, err, text);
2134}
2135
2136
2137static void
2138ngx_ssl_clear_error(ngx_log_t *log)
2139{
2140    while (ERR_peek_error()) {
2141        ngx_ssl_error(NGX_LOG_ALERT, log, 0, "ignoring stale global SSL error");
2142    }
2143
2144    ERR_clear_error();
2145}
2146
2147
2148void ngx_cdecl
2149ngx_ssl_error(ngx_uint_t level, ngx_log_t *log, ngx_err_t err, char *fmt, ...)
2150{
2151    int          flags;
2152    u_long       n;
2153    va_list      args;
2154    u_char      *p, *last;
2155    u_char       errstr[NGX_MAX_CONF_ERRSTR];
2156    const char  *data;
2157
2158    last = errstr + NGX_MAX_CONF_ERRSTR;
2159
2160    va_start(args, fmt);
2161    p = ngx_vslprintf(errstr, last - 1, fmt, args);
2162    va_end(args);
2163
2164    p = ngx_cpystrn(p, (u_char *) " (SSL:", last - p);
2165
2166    for ( ;; ) {
2167
2168        n = ERR_peek_error_line_data(NULL, NULL, &data, &flags);
2169
2170        if (n == 0) {
2171            break;
2172        }
2173
2174        /* ERR_error_string_n() requires at least one byte */
2175
2176        if (p >= last - 1) {
2177            goto next;
2178        }
2179
2180        *p++ = ' ';
2181
2182        ERR_error_string_n(n, (char *) p, last - p);
2183
2184        while (p < last && *p) {
2185            p++;
2186        }
2187
2188        if (p < last && *data && (flags & ERR_TXT_STRING)) {
2189            *p++ = ':';
2190            p = ngx_cpystrn(p, (u_char *) data, last - p);
2191        }
2192
2193    next:
2194
2195        (void) ERR_get_error();
2196    }
2197
2198    ngx_log_error(level, log, err, "%*s)", p - errstr, errstr);
2199}
2200
2201
2202ngx_int_t
2203ngx_ssl_session_cache(ngx_ssl_t *ssl, ngx_str_t *sess_ctx,
2204    ssize_t builtin_session_cache, ngx_shm_zone_t *shm_zone, time_t timeout)
2205{
2206    long  cache_mode;
2207
2208    SSL_CTX_set_timeout(ssl->ctx, (long) timeout);
2209
2210    if (ngx_ssl_session_id_context(ssl, sess_ctx) != NGX_OK) {
2211        return NGX_ERROR;
2212    }
2213
2214    if (builtin_session_cache == NGX_SSL_NO_SCACHE) {
2215        SSL_CTX_set_session_cache_mode(ssl->ctx, SSL_SESS_CACHE_OFF);
2216        return NGX_OK;
2217    }
2218
2219    if (builtin_session_cache == NGX_SSL_NONE_SCACHE) {
2220
2221        /*
2222         * If the server explicitly says that it does not support
2223         * session reuse (see SSL_SESS_CACHE_OFF above), then
2224         * Outlook Express fails to upload a sent email to
2225         * the Sent Items folder on the IMAP server via a separate IMAP
2226         * connection in the background.  Therefore we have a special
2227         * mode (SSL_SESS_CACHE_SERVER|SSL_SESS_CACHE_NO_INTERNAL_STORE)
2228         * where the server pretends that it supports session reuse,
2229         * but it does not actually store any session.
2230         */
2231
2232        SSL_CTX_set_session_cache_mode(ssl->ctx,
2233                                       SSL_SESS_CACHE_SERVER
2234                                       |SSL_SESS_CACHE_NO_AUTO_CLEAR
2235                                       |SSL_SESS_CACHE_NO_INTERNAL_STORE);
2236
2237        SSL_CTX_sess_set_cache_size(ssl->ctx, 1);
2238
2239        return NGX_OK;
2240    }
2241
2242    cache_mode = SSL_SESS_CACHE_SERVER;
2243
2244    if (shm_zone && builtin_session_cache == NGX_SSL_NO_BUILTIN_SCACHE) {
2245        cache_mode |= SSL_SESS_CACHE_NO_INTERNAL;
2246    }
2247
2248    SSL_CTX_set_session_cache_mode(ssl->ctx, cache_mode);
2249
2250    if (builtin_session_cache != NGX_SSL_NO_BUILTIN_SCACHE) {
2251
2252        if (builtin_session_cache != NGX_SSL_DFLT_BUILTIN_SCACHE) {
2253            SSL_CTX_sess_set_cache_size(ssl->ctx, builtin_session_cache);
2254        }
2255    }
2256
2257    if (shm_zone) {
2258        SSL_CTX_sess_set_new_cb(ssl->ctx, ngx_ssl_new_session);
2259        SSL_CTX_sess_set_get_cb(ssl->ctx, ngx_ssl_get_cached_session);
2260        SSL_CTX_sess_set_remove_cb(ssl->ctx, ngx_ssl_remove_session);
2261
2262        if (SSL_CTX_set_ex_data(ssl->ctx, ngx_ssl_session_cache_index, shm_zone)
2263            == 0)
2264        {
2265            ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0,
2266                          "SSL_CTX_set_ex_data() failed");
2267            return NGX_ERROR;
2268        }
2269    }
2270
2271    return NGX_OK;
2272}
2273
2274
2275static ngx_int_t
2276ngx_ssl_session_id_context(ngx_ssl_t *ssl, ngx_str_t *sess_ctx)
2277{
2278    int                   n, i;
2279    X509                 *cert;
2280    X509_NAME            *name;
2281    EVP_MD_CTX           *md;
2282    unsigned int          len;
2283    STACK_OF(X509_NAME)  *list;
2284    u_char                buf[EVP_MAX_MD_SIZE];
2285
2286    /*
2287     * Session ID context is set based on the string provided,
2288     * the server certificates, and the client CA list.
2289     */
2290
2291    md = EVP_MD_CTX_create();
2292    if (md == NULL) {
2293        return NGX_ERROR;
2294    }
2295
2296    if (EVP_DigestInit_ex(md, EVP_sha1(), NULL) == 0) {
2297        ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0,
2298                      "EVP_DigestInit_ex() failed");
2299        goto failed;
2300    }
2301
2302    if (EVP_DigestUpdate(md, sess_ctx->data, sess_ctx->len) == 0) {
2303        ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0,
2304                      "EVP_DigestUpdate() failed");
2305        goto failed;
2306    }
2307
2308    for (cert = SSL_CTX_get_ex_data(ssl->ctx, ngx_ssl_certificate_index);
2309         cert;
2310         cert = X509_get_ex_data(cert, ngx_ssl_next_certificate_index))
2311    {
2312        if (X509_digest(cert, EVP_sha1(), buf, &len) == 0) {
2313            ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0,
2314                          "X509_digest() failed");
2315            goto failed;
2316        }
2317
2318        if (EVP_DigestUpdate(md, buf, len) == 0) {
2319            ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0,
2320                          "EVP_DigestUpdate() failed");
2321            goto failed;
2322        }
2323    }
2324
2325    list = SSL_CTX_get_client_CA_list(ssl->ctx);
2326
2327    if (list != NULL) {
2328        n = sk_X509_NAME_num(list);
2329
2330        for (i = 0; i < n; i++) {
2331            name = sk_X509_NAME_value(list, i);
2332
2333            if (X509_NAME_digest(name, EVP_sha1(), buf, &len) == 0) {
2334                ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0,
2335                              "X509_NAME_digest() failed");
2336                goto failed;
2337            }
2338
2339            if (EVP_DigestUpdate(md, buf, len) == 0) {
2340                ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0,
2341                              "EVP_DigestUpdate() failed");
2342                goto failed;
2343            }
2344        }
2345    }
2346
2347    if (EVP_DigestFinal_ex(md, buf, &len) == 0) {
2348        ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0,
2349                      "EVP_DigestUpdate() failed");
2350        goto failed;
2351    }
2352
2353    EVP_MD_CTX_destroy(md);
2354
2355    if (SSL_CTX_set_session_id_context(ssl->ctx, buf, len) == 0) {
2356        ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0,
2357                      "SSL_CTX_set_session_id_context() failed");
2358        return NGX_ERROR;
2359    }
2360
2361    return NGX_OK;
2362
2363failed:
2364
2365    EVP_MD_CTX_destroy(md);
2366
2367    return NGX_ERROR;
2368}
2369
2370
2371ngx_int_t
2372ngx_ssl_session_cache_init(ngx_shm_zone_t *shm_zone, void *data)
2373{
2374    size_t                    len;
2375    ngx_slab_pool_t          *shpool;
2376    ngx_ssl_session_cache_t  *cache;
2377
2378    if (data) {
2379        shm_zone->data = data;
2380        return NGX_OK;
2381    }
2382
2383    shpool = (ngx_slab_pool_t *) shm_zone->shm.addr;
2384
2385    if (shm_zone->shm.exists) {
2386        shm_zone->data = shpool->data;
2387        return NGX_OK;
2388    }
2389
2390    cache = ngx_slab_alloc(shpool, sizeof(ngx_ssl_session_cache_t));
2391    if (cache == NULL) {
2392        return NGX_ERROR;
2393    }
2394
2395    shpool->data = cache;
2396    shm_zone->data = cache;
2397
2398    ngx_rbtree_init(&cache->session_rbtree, &cache->sentinel,
2399                    ngx_ssl_session_rbtree_insert_value);
2400
2401    ngx_queue_init(&cache->expire_queue);
2402
2403    len = sizeof(" in SSL session shared cache \"\"") + shm_zone->shm.name.len;
2404
2405    shpool->log_ctx = ngx_slab_alloc(shpool, len);
2406    if (shpool->log_ctx == NULL) {
2407        return NGX_ERROR;
2408    }
2409
2410    ngx_sprintf(shpool->log_ctx, " in SSL session shared cache \"%V\"%Z",
2411                &shm_zone->shm.name);
2412
2413    shpool->log_nomem = 0;
2414
2415    return NGX_OK;
2416}
2417
2418
2419/*
2420 * The length of the session id is 16 bytes for SSLv2 sessions and
2421 * between 1 and 32 bytes for SSLv3/TLSv1, typically 32 bytes.
2422 * It seems that the typical length of the external ASN1 representation
2423 * of a session is 118 or 119 bytes for SSLv3/TSLv1.
2424 *
2425 * Thus on 32-bit platforms we allocate separately an rbtree node,
2426 * a session id, and an ASN1 representation, they take accordingly
2427 * 64, 32, and 128 bytes.
2428 *
2429 * On 64-bit platforms we allocate separately an rbtree node + session_id,
2430 * and an ASN1 representation, they take accordingly 128 and 128 bytes.
2431 *
2432 * OpenSSL's i2d_SSL_SESSION() and d2i_SSL_SESSION are slow,
2433 * so they are outside the code locked by shared pool mutex
2434 */
2435
2436static int
2437ngx_ssl_new_session(ngx_ssl_conn_t *ssl_conn, ngx_ssl_session_t *sess)
2438{
2439    int                       len;
2440    u_char                   *p, *id, *cached_sess, *session_id;
2441    uint32_t                  hash;
2442    SSL_CTX                  *ssl_ctx;
2443    unsigned int              session_id_length;
2444    ngx_shm_zone_t           *shm_zone;
2445    ngx_connection_t         *c;
2446    ngx_slab_pool_t          *shpool;
2447    ngx_ssl_sess_id_t        *sess_id;
2448    ngx_ssl_session_cache_t  *cache;
2449    u_char                    buf[NGX_SSL_MAX_SESSION_SIZE];
2450
2451    len = i2d_SSL_SESSION(sess, NULL);
2452
2453    /* do not cache too big session */
2454
2455    if (len > (int) NGX_SSL_MAX_SESSION_SIZE) {
2456        return 0;
2457    }
2458
2459    p = buf;
2460    i2d_SSL_SESSION(sess, &p);
2461
2462    c = ngx_ssl_get_connection(ssl_conn);
2463
2464    ssl_ctx = c->ssl->session_ctx;
2465    shm_zone = SSL_CTX_get_ex_data(ssl_ctx, ngx_ssl_session_cache_index);
2466
2467    cache = shm_zone->data;
2468    shpool = (ngx_slab_pool_t *) shm_zone->shm.addr;
2469
2470    ngx_shmtx_lock(&shpool->mutex);
2471
2472    /* drop one or two expired sessions */
2473    ngx_ssl_expire_sessions(cache, shpool, 1);
2474
2475    cached_sess = ngx_slab_alloc_locked(shpool, len);
2476
2477    if (cached_sess == NULL) {
2478
2479        /* drop the oldest non-expired session and try once more */
2480
2481        ngx_ssl_expire_sessions(cache, shpool, 0);
2482
2483        cached_sess = ngx_slab_alloc_locked(shpool, len);
2484
2485        if (cached_sess == NULL) {
2486            sess_id = NULL;
2487            goto failed;
2488        }
2489    }
2490
2491    sess_id = ngx_slab_alloc_locked(shpool, sizeof(ngx_ssl_sess_id_t));
2492
2493    if (sess_id == NULL) {
2494
2495        /* drop the oldest non-expired session and try once more */
2496
2497        ngx_ssl_expire_sessions(cache, shpool, 0);
2498
2499        sess_id = ngx_slab_alloc_locked(shpool, sizeof(ngx_ssl_sess_id_t));
2500
2501        if (sess_id == NULL) {
2502            goto failed;
2503        }
2504    }
2505
2506#if OPENSSL_VERSION_NUMBER >= 0x0090800fL
2507
2508    session_id = (u_char *) SSL_SESSION_get_id(sess, &session_id_length);
2509
2510#else
2511
2512    session_id = sess->session_id;
2513    session_id_length = sess->session_id_length;
2514
2515#endif
2516
2517#if (NGX_PTR_SIZE == 8)
2518
2519    id = sess_id->sess_id;
2520
2521#else
2522
2523    id = ngx_slab_alloc_locked(shpool, session_id_length);
2524
2525    if (id == NULL) {
2526
2527        /* drop the oldest non-expired session and try once more */
2528
2529        ngx_ssl_expire_sessions(cache, shpool, 0);
2530
2531        id = ngx_slab_alloc_locked(shpool, session_id_length);
2532
2533        if (id == NULL) {
2534            goto failed;
2535        }
2536    }
2537
2538#endif
2539
2540    ngx_memcpy(cached_sess, buf, len);
2541
2542    ngx_memcpy(id, session_id, session_id_length);
2543
2544    hash = ngx_crc32_short(session_id, session_id_length);
2545
2546    ngx_log_debug3(NGX_LOG_DEBUG_EVENT, c->log, 0,
2547                   "ssl new session: %08XD:%ud:%d",
2548                   hash, session_id_length, len);
2549
2550    sess_id->node.key = hash;
2551    sess_id->node.data = (u_char) session_id_length;
2552    sess_id->id = id;
2553    sess_id->len = len;
2554    sess_id->session = cached_sess;
2555
2556    sess_id->expire = ngx_time() + SSL_CTX_get_timeout(ssl_ctx);
2557
2558    ngx_queue_insert_head(&cache->expire_queue, &sess_id->queue);
2559
2560    ngx_rbtree_insert(&cache->session_rbtree, &sess_id->node);
2561
2562    ngx_shmtx_unlock(&shpool->mutex);
2563
2564    return 0;
2565
2566failed:
2567
2568    if (cached_sess) {
2569        ngx_slab_free_locked(shpool, cached_sess);
2570    }
2571
2572    if (sess_id) {
2573        ngx_slab_free_locked(shpool, sess_id);
2574    }
2575
2576    ngx_shmtx_unlock(&shpool->mutex);
2577
2578    ngx_log_error(NGX_LOG_ALERT, c->log, 0,
2579                  "could not allocate new session%s", shpool->log_ctx);
2580
2581    return 0;
2582}
2583
2584
2585static ngx_ssl_session_t *
2586ngx_ssl_get_cached_session(ngx_ssl_conn_t *ssl_conn,
2587#if OPENSSL_VERSION_NUMBER >= 0x10100003L
2588    const
2589#endif
2590    u_char *id, int len, int *copy)
2591{
2592#if OPENSSL_VERSION_NUMBER >= 0x0090707fL
2593    const
2594#endif
2595    u_char                   *p;
2596    uint32_t                  hash;
2597    ngx_int_t                 rc;
2598    ngx_shm_zone_t           *shm_zone;
2599    ngx_slab_pool_t          *shpool;
2600    ngx_rbtree_node_t        *node, *sentinel;
2601    ngx_ssl_session_t        *sess;
2602    ngx_ssl_sess_id_t        *sess_id;
2603    ngx_ssl_session_cache_t  *cache;
2604    u_char                    buf[NGX_SSL_MAX_SESSION_SIZE];
2605    ngx_connection_t         *c;
2606
2607    hash = ngx_crc32_short((u_char *) (uintptr_t) id, (size_t) len);
2608    *copy = 0;
2609
2610    c = ngx_ssl_get_connection(ssl_conn);
2611
2612    ngx_log_debug2(NGX_LOG_DEBUG_EVENT, c->log, 0,
2613                   "ssl get session: %08XD:%d", hash, len);
2614
2615    shm_zone = SSL_CTX_get_ex_data(c->ssl->session_ctx,
2616                                   ngx_ssl_session_cache_index);
2617
2618    cache = shm_zone->data;
2619
2620    sess = NULL;
2621
2622    shpool = (ngx_slab_pool_t *) shm_zone->shm.addr;
2623
2624    ngx_shmtx_lock(&shpool->mutex);
2625
2626    node = cache->session_rbtree.root;
2627    sentinel = cache->session_rbtree.sentinel;
2628
2629    while (node != sentinel) {
2630
2631        if (hash < node->key) {
2632            node = node->left;
2633            continue;
2634        }
2635
2636        if (hash > node->key) {
2637            node = node->right;
2638            continue;
2639        }
2640
2641        /* hash == node->key */
2642
2643        sess_id = (ngx_ssl_sess_id_t *) node;
2644
2645        rc = ngx_memn2cmp((u_char *) (uintptr_t) id, sess_id->id,
2646                          (size_t) len, (size_t) node->data);
2647
2648        if (rc == 0) {
2649
2650            if (sess_id->expire > ngx_time()) {
2651                ngx_memcpy(buf, sess_id->session, sess_id->len);
2652
2653                ngx_shmtx_unlock(&shpool->mutex);
2654
2655                p = buf;
2656                sess = d2i_SSL_SESSION(NULL, &p, sess_id->len);
2657
2658                return sess;
2659            }
2660
2661            ngx_queue_remove(&sess_id->queue);
2662
2663            ngx_rbtree_delete(&cache->session_rbtree, node);
2664
2665            ngx_slab_free_locked(shpool, sess_id->session);
2666#if (NGX_PTR_SIZE == 4)
2667            ngx_slab_free_locked(shpool, sess_id->id);
2668#endif
2669            ngx_slab_free_locked(shpool, sess_id);
2670
2671            sess = NULL;
2672
2673            goto done;
2674        }
2675
2676        node = (rc < 0) ? node->left : node->right;
2677    }
2678
2679done:
2680
2681    ngx_shmtx_unlock(&shpool->mutex);
2682
2683    return sess;
2684}
2685
2686
2687void
2688ngx_ssl_remove_cached_session(SSL_CTX *ssl, ngx_ssl_session_t *sess)
2689{
2690    SSL_CTX_remove_session(ssl, sess);
2691
2692    ngx_ssl_remove_session(ssl, sess);
2693}
2694
2695
2696static void
2697ngx_ssl_remove_session(SSL_CTX *ssl, ngx_ssl_session_t *sess)
2698{
2699    u_char                   *id;
2700    uint32_t                  hash;
2701    ngx_int_t                 rc;
2702    unsigned int              len;
2703    ngx_shm_zone_t           *shm_zone;
2704    ngx_slab_pool_t          *shpool;
2705    ngx_rbtree_node_t        *node, *sentinel;
2706    ngx_ssl_sess_id_t        *sess_id;
2707    ngx_ssl_session_cache_t  *cache;
2708
2709    shm_zone = SSL_CTX_get_ex_data(ssl, ngx_ssl_session_cache_index);
2710
2711    if (shm_zone == NULL) {
2712        return;
2713    }
2714
2715    cache = shm_zone->data;
2716
2717#if OPENSSL_VERSION_NUMBER >= 0x0090800fL
2718
2719    id = (u_char *) SSL_SESSION_get_id(sess, &len);
2720
2721#else
2722
2723    id = sess->session_id;
2724    len = sess->session_id_length;
2725
2726#endif
2727
2728    hash = ngx_crc32_short(id, len);
2729
2730    ngx_log_debug2(NGX_LOG_DEBUG_EVENT, ngx_cycle->log, 0,
2731                   "ssl remove session: %08XD:%ud", hash, len);
2732
2733    shpool = (ngx_slab_pool_t *) shm_zone->shm.addr;
2734
2735    ngx_shmtx_lock(&shpool->mutex);
2736
2737    node = cache->session_rbtree.root;
2738    sentinel = cache->session_rbtree.sentinel;
2739
2740    while (node != sentinel) {
2741
2742        if (hash < node->key) {
2743            node = node->left;
2744            continue;
2745        }
2746
2747        if (hash > node->key) {
2748            node = node->right;
2749            continue;
2750        }
2751
2752        /* hash == node->key */
2753
2754        sess_id = (ngx_ssl_sess_id_t *) node;
2755
2756        rc = ngx_memn2cmp(id, sess_id->id, len, (size_t) node->data);
2757
2758        if (rc == 0) {
2759
2760            ngx_queue_remove(&sess_id->queue);
2761
2762            ngx_rbtree_delete(&cache->session_rbtree, node);
2763
2764            ngx_slab_free_locked(shpool, sess_id->session);
2765#if (NGX_PTR_SIZE == 4)
2766            ngx_slab_free_locked(shpool, sess_id->id);
2767#endif
2768            ngx_slab_free_locked(shpool, sess_id);
2769
2770            goto done;
2771        }
2772
2773        node = (rc < 0) ? node->left : node->right;
2774    }
2775
2776done:
2777
2778    ngx_shmtx_unlock(&shpool->mutex);
2779}
2780
2781
2782static void
2783ngx_ssl_expire_sessions(ngx_ssl_session_cache_t *cache,
2784    ngx_slab_pool_t *shpool, ngx_uint_t n)
2785{
2786    time_t              now;
2787    ngx_queue_t        *q;
2788    ngx_ssl_sess_id_t  *sess_id;
2789
2790    now = ngx_time();
2791
2792    while (n < 3) {
2793
2794        if (ngx_queue_empty(&cache->expire_queue)) {
2795            return;
2796        }
2797
2798        q = ngx_queue_last(&cache->expire_queue);
2799
2800        sess_id = ngx_queue_data(q, ngx_ssl_sess_id_t, queue);
2801
2802        if (n++ != 0 && sess_id->expire > now) {
2803            return;
2804        }
2805
2806        ngx_queue_remove(q);
2807
2808        ngx_log_debug1(NGX_LOG_DEBUG_EVENT, ngx_cycle->log, 0,
2809                       "expire session: %08Xi", sess_id->node.key);
2810
2811        ngx_rbtree_delete(&cache->session_rbtree, &sess_id->node);
2812
2813        ngx_slab_free_locked(shpool, sess_id->session);
2814#if (NGX_PTR_SIZE == 4)
2815        ngx_slab_free_locked(shpool, sess_id->id);
2816#endif
2817        ngx_slab_free_locked(shpool, sess_id);
2818    }
2819}
2820
2821
2822static void
2823ngx_ssl_session_rbtree_insert_value(ngx_rbtree_node_t *temp,
2824    ngx_rbtree_node_t *node, ngx_rbtree_node_t *sentinel)
2825{
2826    ngx_rbtree_node_t  **p;
2827    ngx_ssl_sess_id_t   *sess_id, *sess_id_temp;
2828
2829    for ( ;; ) {
2830
2831        if (node->key < temp->key) {
2832
2833            p = &temp->left;
2834
2835        } else if (node->key > temp->key) {
2836
2837            p = &temp->right;
2838
2839        } else { /* node->key == temp->key */
2840
2841            sess_id = (ngx_ssl_sess_id_t *) node;
2842            sess_id_temp = (ngx_ssl_sess_id_t *) temp;
2843
2844            p = (ngx_memn2cmp(sess_id->id, sess_id_temp->id,
2845                              (size_t) node->data, (size_t) temp->data)
2846                 < 0) ? &temp->left : &temp->right;
2847        }
2848
2849        if (*p == sentinel) {
2850            break;
2851        }
2852
2853        temp = *p;
2854    }
2855
2856    *p = node;
2857    node->parent = temp;
2858    node->left = sentinel;
2859    node->right = sentinel;
2860    ngx_rbt_red(node);
2861}
2862
2863
2864#ifdef SSL_CTRL_SET_TLSEXT_TICKET_KEY_CB
2865
2866ngx_int_t
2867ngx_ssl_session_ticket_keys(ngx_conf_t *cf, ngx_ssl_t *ssl, ngx_array_t *paths)
2868{
2869    u_char                         buf[80];
2870    size_t                         size;
2871    ssize_t                        n;
2872    ngx_str_t                     *path;
2873    ngx_file_t                     file;
2874    ngx_uint_t                     i;
2875    ngx_array_t                   *keys;
2876    ngx_file_info_t                fi;
2877    ngx_ssl_session_ticket_key_t  *key;
2878
2879    if (paths == NULL) {
2880        return NGX_OK;
2881    }
2882
2883    keys = ngx_array_create(cf->pool, paths->nelts,
2884                            sizeof(ngx_ssl_session_ticket_key_t));
2885    if (keys == NULL) {
2886        return NGX_ERROR;
2887    }
2888
2889    path = paths->elts;
2890    for (i = 0; i < paths->nelts; i++) {
2891
2892        if (ngx_conf_full_name(cf->cycle, &path[i], 1) != NGX_OK) {
2893            return NGX_ERROR;
2894        }
2895
2896        ngx_memzero(&file, sizeof(ngx_file_t));
2897        file.name = path[i];
2898        file.log = cf->log;
2899
2900        file.fd = ngx_open_file(file.name.data, NGX_FILE_RDONLY, 0, 0);
2901        if (file.fd == NGX_INVALID_FILE) {
2902            ngx_conf_log_error(NGX_LOG_EMERG, cf, ngx_errno,
2903                               ngx_open_file_n " \"%V\" failed", &file.name);
2904            return NGX_ERROR;
2905        }
2906
2907        if (ngx_fd_info(file.fd, &fi) == NGX_FILE_ERROR) {
2908            ngx_conf_log_error(NGX_LOG_CRIT, cf, ngx_errno,
2909                               ngx_fd_info_n " \"%V\" failed", &file.name);
2910            goto failed;
2911        }
2912
2913        size = ngx_file_size(&fi);
2914
2915        if (size != 48 && size != 80) {
2916            ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
2917                               "\"%V\" must be 48 or 80 bytes", &file.name);
2918            goto failed;
2919        }
2920
2921        n = ngx_read_file(&file, buf, size, 0);
2922
2923        if (n == NGX_ERROR) {
2924            ngx_conf_log_error(NGX_LOG_CRIT, cf, ngx_errno,
2925                               ngx_read_file_n " \"%V\" failed", &file.name);
2926            goto failed;
2927        }
2928
2929        if ((size_t) n != size) {
2930            ngx_conf_log_error(NGX_LOG_CRIT, cf, 0,
2931                               ngx_read_file_n " \"%V\" returned only "
2932                               "%z bytes instead of %uz", &file.name, n, size);
2933            goto failed;
2934        }
2935
2936        key = ngx_array_push(keys);
2937        if (key == NULL) {
2938            goto failed;
2939        }
2940
2941        if (size == 48) {
2942            key->size = 48;
2943            ngx_memcpy(key->name, buf, 16);
2944            ngx_memcpy(key->aes_key, buf + 16, 16);
2945            ngx_memcpy(key->hmac_key, buf + 32, 16);
2946
2947        } else {
2948            key->size = 80;
2949            ngx_memcpy(key->name, buf, 16);
2950            ngx_memcpy(key->hmac_key, buf + 16, 32);
2951            ngx_memcpy(key->aes_key, buf + 48, 32);
2952        }
2953
2954        if (ngx_close_file(file.fd) == NGX_FILE_ERROR) {
2955            ngx_log_error(NGX_LOG_ALERT, cf->log, ngx_errno,
2956                          ngx_close_file_n " \"%V\" failed", &file.name);
2957        }
2958    }
2959
2960    if (SSL_CTX_set_ex_data(ssl->ctx, ngx_ssl_session_ticket_keys_index, keys)
2961        == 0)
2962    {
2963        ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0,
2964                      "SSL_CTX_set_ex_data() failed");
2965        return NGX_ERROR;
2966    }
2967
2968    if (SSL_CTX_set_tlsext_ticket_key_cb(ssl->ctx,
2969                                         ngx_ssl_session_ticket_key_callback)
2970        == 0)
2971    {
2972        ngx_log_error(NGX_LOG_WARN, cf->log, 0,
2973                      "nginx was built with Session Tickets support, however, "
2974                      "now it is linked dynamically to an OpenSSL library "
2975                      "which has no tlsext support, therefore Session Tickets "
2976                      "are not available");
2977    }
2978
2979    return NGX_OK;
2980
2981failed:
2982
2983    if (ngx_close_file(file.fd) == NGX_FILE_ERROR) {
2984        ngx_log_error(NGX_LOG_ALERT, cf->log, ngx_errno,
2985                      ngx_close_file_n " \"%V\" failed", &file.name);
2986    }
2987
2988    return NGX_ERROR;
2989}
2990
2991
2992static int
2993ngx_ssl_session_ticket_key_callback(ngx_ssl_conn_t *ssl_conn,
2994    unsigned char *name, unsigned char *iv, EVP_CIPHER_CTX *ectx,
2995    HMAC_CTX *hctx, int enc)
2996{
2997    size_t                         size;
2998    SSL_CTX                       *ssl_ctx;
2999    ngx_uint_t                     i;
3000    ngx_array_t                   *keys;
3001    ngx_connection_t              *c;
3002    ngx_ssl_session_ticket_key_t  *key;
3003    const EVP_MD                  *digest;
3004    const EVP_CIPHER              *cipher;
3005#if (NGX_DEBUG)
3006    u_char                         buf[32];
3007#endif
3008
3009    c = ngx_ssl_get_connection(ssl_conn);
3010    ssl_ctx = c->ssl->session_ctx;
3011
3012#ifdef OPENSSL_NO_SHA256
3013    digest = EVP_sha1();
3014#else
3015    digest = EVP_sha256();
3016#endif
3017
3018    keys = SSL_CTX_get_ex_data(ssl_ctx, ngx_ssl_session_ticket_keys_index);
3019    if (keys == NULL) {
3020        return -1;
3021    }
3022
3023    key = keys->elts;
3024
3025    if (enc == 1) {
3026        /* encrypt session ticket */
3027
3028        ngx_log_debug3(NGX_LOG_DEBUG_EVENT, c->log, 0,
3029                       "ssl session ticket encrypt, key: \"%*s\" (%s session)",
3030                       ngx_hex_dump(buf, key[0].name, 16) - buf, buf,
3031                       SSL_session_reused(ssl_conn) ? "reused" : "new");
3032
3033        if (key[0].size == 48) {
3034            cipher = EVP_aes_128_cbc();
3035            size = 16;
3036
3037        } else {
3038            cipher = EVP_aes_256_cbc();
3039            size = 32;
3040        }
3041
3042        if (RAND_bytes(iv, EVP_CIPHER_iv_length(cipher)) != 1) {
3043            ngx_ssl_error(NGX_LOG_ALERT, c->log, 0, "RAND_bytes() failed");
3044            return -1;
3045        }
3046
3047        if (EVP_EncryptInit_ex(ectx, cipher, NULL, key[0].aes_key, iv) != 1) {
3048            ngx_ssl_error(NGX_LOG_ALERT, c->log, 0,
3049                          "EVP_EncryptInit_ex() failed");
3050            return -1;
3051        }
3052
3053#if OPENSSL_VERSION_NUMBER >= 0x10000000L
3054        if (HMAC_Init_ex(hctx, key[0].hmac_key, size, digest, NULL) != 1) {
3055            ngx_ssl_error(NGX_LOG_ALERT, c->log, 0, "HMAC_Init_ex() failed");
3056            return -1;
3057        }
3058#else
3059        HMAC_Init_ex(hctx, key[0].hmac_key, size, digest, NULL);
3060#endif
3061
3062        ngx_memcpy(name, key[0].name, 16);
3063
3064        return 1;
3065
3066    } else {
3067        /* decrypt session ticket */
3068
3069        for (i = 0; i < keys->nelts; i++) {
3070            if (ngx_memcmp(name, key[i].name, 16) == 0) {
3071                goto found;
3072            }
3073        }
3074
3075        ngx_log_debug2(NGX_LOG_DEBUG_EVENT, c->log, 0,
3076                       "ssl session ticket decrypt, key: \"%*s\" not found",
3077                       ngx_hex_dump(buf, name, 16) - buf, buf);
3078
3079        return 0;
3080
3081    found:
3082
3083        ngx_log_debug3(NGX_LOG_DEBUG_EVENT, c->log, 0,
3084                       "ssl session ticket decrypt, key: \"%*s\"%s",
3085                       ngx_hex_dump(buf, key[i].name, 16) - buf, buf,
3086                       (i == 0) ? " (default)" : "");
3087
3088        if (key[i].size == 48) {
3089            cipher = EVP_aes_128_cbc();
3090            size = 16;
3091
3092        } else {
3093            cipher = EVP_aes_256_cbc();
3094            size = 32;
3095        }
3096
3097#if OPENSSL_VERSION_NUMBER >= 0x10000000L
3098        if (HMAC_Init_ex(hctx, key[i].hmac_key, size, digest, NULL) != 1) {
3099            ngx_ssl_error(NGX_LOG_ALERT, c->log, 0, "HMAC_Init_ex() failed");
3100            return -1;
3101        }
3102#else
3103        HMAC_Init_ex(hctx, key[i].hmac_key, size, digest, NULL);
3104#endif
3105
3106        if (EVP_DecryptInit_ex(ectx, cipher, NULL, key[i].aes_key, iv) != 1) {
3107            ngx_ssl_error(NGX_LOG_ALERT, c->log, 0,
3108                          "EVP_DecryptInit_ex() failed");
3109            return -1;
3110        }
3111
3112        return (i == 0) ? 1 : 2 /* renew */;
3113    }
3114}
3115
3116#else
3117
3118ngx_int_t
3119ngx_ssl_session_ticket_keys(ngx_conf_t *cf, ngx_ssl_t *ssl, ngx_array_t *paths)
3120{
3121    if (paths) {
3122        ngx_log_error(NGX_LOG_WARN, ssl->log, 0,
3123                      "\"ssl_session_ticket_keys\" ignored, not supported");
3124    }
3125
3126    return NGX_OK;
3127}
3128
3129#endif
3130
3131
3132void
3133ngx_ssl_cleanup_ctx(void *data)
3134{
3135    ngx_ssl_t  *ssl = data;
3136
3137    X509  *cert, *next;
3138
3139    cert = SSL_CTX_get_ex_data(ssl->ctx, ngx_ssl_certificate_index);
3140
3141    while (cert) {
3142        next = X509_get_ex_data(cert, ngx_ssl_next_certificate_index);
3143        X509_free(cert);
3144        cert = next;
3145    }
3146
3147    SSL_CTX_free(ssl->ctx);
3148}
3149
3150
3151ngx_int_t
3152ngx_ssl_check_host(ngx_connection_t *c, ngx_str_t *name)
3153{
3154    X509   *cert;
3155
3156    cert = SSL_get_peer_certificate(c->ssl->connection);
3157    if (cert == NULL) {
3158        return NGX_ERROR;
3159    }
3160
3161#ifdef X509_CHECK_FLAG_ALWAYS_CHECK_SUBJECT
3162
3163    /* X509_check_host() is only available in OpenSSL 1.0.2+ */
3164
3165    if (name->len == 0) {
3166        goto failed;
3167    }
3168
3169    if (X509_check_host(cert, (char *) name->data, name->len, 0, NULL) != 1) {
3170        ngx_log_debug0(NGX_LOG_DEBUG_EVENT, c->log, 0,
3171                       "X509_check_host(): no match");
3172        goto failed;
3173    }
3174
3175    ngx_log_debug0(NGX_LOG_DEBUG_EVENT, c->log, 0,
3176                   "X509_check_host(): match");
3177
3178    goto found;
3179
3180#else
3181    {
3182    int                      n, i;
3183    X509_NAME               *sname;
3184    ASN1_STRING             *str;
3185    X509_NAME_ENTRY         *entry;
3186    GENERAL_NAME            *altname;
3187    STACK_OF(GENERAL_NAME)  *altnames;
3188
3189    /*
3190     * As per RFC6125 and RFC2818, we check subjectAltName extension,
3191     * and if it's not present - commonName in Subject is checked.
3192     */
3193
3194    altnames = X509_get_ext_d2i(cert, NID_subject_alt_name, NULL, NULL);
3195
3196    if (altnames) {
3197        n = sk_GENERAL_NAME_num(altnames);
3198
3199        for (i = 0; i < n; i++) {
3200            altname = sk_GENERAL_NAME_value(altnames, i);
3201
3202            if (altname->type != GEN_DNS) {
3203                continue;
3204            }
3205
3206            str = altname->d.dNSName;
3207
3208            ngx_log_debug2(NGX_LOG_DEBUG_EVENT, c->log, 0,
3209                           "SSL subjectAltName: \"%*s\"",
3210                           ASN1_STRING_length(str), ASN1_STRING_data(str));
3211
3212            if (ngx_ssl_check_name(name, str) == NGX_OK) {
3213                ngx_log_debug0(NGX_LOG_DEBUG_EVENT, c->log, 0,
3214                               "SSL subjectAltName: match");
3215                GENERAL_NAMES_free(altnames);
3216                goto found;
3217            }
3218        }
3219
3220        ngx_log_debug0(NGX_LOG_DEBUG_EVENT, c->log, 0,
3221                       "SSL subjectAltName: no match");
3222
3223        GENERAL_NAMES_free(altnames);
3224        goto failed;
3225    }
3226
3227    /*
3228     * If there is no subjectAltName extension, check commonName
3229     * in Subject.  While RFC2818 requires to only check "most specific"
3230     * CN, both Apache and OpenSSL check all CNs, and so do we.
3231     */
3232
3233    sname = X509_get_subject_name(cert);
3234
3235    if (sname == NULL) {
3236        goto failed;
3237    }
3238
3239    i = -1;
3240    for ( ;; ) {
3241        i = X509_NAME_get_index_by_NID(sname, NID_commonName, i);
3242
3243        if (i < 0) {
3244            break;
3245        }
3246
3247        entry = X509_NAME_get_entry(sname, i);
3248        str = X509_NAME_ENTRY_get_data(entry);
3249
3250        ngx_log_debug2(NGX_LOG_DEBUG_EVENT, c->log, 0,
3251                       "SSL commonName: \"%*s\"",
3252                       ASN1_STRING_length(str), ASN1_STRING_data(str));
3253
3254        if (ngx_ssl_check_name(name, str) == NGX_OK) {
3255            ngx_log_debug0(NGX_LOG_DEBUG_EVENT, c->log, 0,
3256                           "SSL commonName: match");
3257            goto found;
3258        }
3259    }
3260
3261    ngx_log_debug0(NGX_LOG_DEBUG_EVENT, c->log, 0,
3262                   "SSL commonName: no match");
3263    }
3264#endif
3265
3266failed:
3267
3268    X509_free(cert);
3269    return NGX_ERROR;
3270
3271found:
3272
3273    X509_free(cert);
3274    return NGX_OK;
3275}
3276
3277
3278#ifndef X509_CHECK_FLAG_ALWAYS_CHECK_SUBJECT
3279
3280static ngx_int_t
3281ngx_ssl_check_name(ngx_str_t *name, ASN1_STRING *pattern)
3282{
3283    u_char  *s, *p, *end;
3284    size_t   slen, plen;
3285
3286    s = name->data;
3287    slen = name->len;
3288
3289    p = ASN1_STRING_data(pattern);
3290    plen = ASN1_STRING_length(pattern);
3291
3292    if (slen == plen && ngx_strncasecmp(s, p, plen) == 0) {
3293        return NGX_OK;
3294    }
3295
3296    if (plen > 2 && p[0] == '*' && p[1] == '.') {
3297        plen -= 1;
3298        p += 1;
3299
3300        end = s + slen;
3301        s = ngx_strlchr(s, end, '.');
3302
3303        if (s == NULL) {
3304            return NGX_ERROR;
3305        }
3306
3307        slen = end - s;
3308
3309        if (plen == slen && ngx_strncasecmp(s, p, plen) == 0) {
3310            return NGX_OK;
3311        }
3312    }
3313
3314    return NGX_ERROR;
3315}
3316
3317#endif
3318
3319
3320ngx_int_t
3321ngx_ssl_get_protocol(ngx_connection_t *c, ngx_pool_t *pool, ngx_str_t *s)
3322{
3323    s->data = (u_char *) SSL_get_version(c->ssl->connection);
3324    return NGX_OK;
3325}
3326
3327
3328ngx_int_t
3329ngx_ssl_get_cipher_name(ngx_connection_t *c, ngx_pool_t *pool, ngx_str_t *s)
3330{
3331    s->data = (u_char *) SSL_get_cipher_name(c->ssl->connection);
3332    return NGX_OK;
3333}
3334
3335
3336ngx_int_t
3337ngx_ssl_get_ciphers(ngx_connection_t *c, ngx_pool_t *pool, ngx_str_t *s)
3338{
3339#ifdef SSL_CTRL_GET_RAW_CIPHERLIST
3340
3341    int                n, i, bytes;
3342    size_t             len;
3343    u_char            *ciphers, *p;
3344    const SSL_CIPHER  *cipher;
3345
3346    bytes = SSL_get0_raw_cipherlist(c->ssl->connection, NULL);
3347    n = SSL_get0_raw_cipherlist(c->ssl->connection, &ciphers);
3348
3349    if (n <= 0) {
3350        s->len = 0;
3351        return NGX_OK;
3352    }
3353
3354    len = 0;
3355    n /= bytes;
3356
3357    for (i = 0; i < n; i++) {
3358        cipher = SSL_CIPHER_find(c->ssl->connection, ciphers + i * bytes);
3359
3360        if (cipher) {
3361            len += ngx_strlen(SSL_CIPHER_get_name(cipher));
3362
3363        } else {
3364            len += sizeof("0x") - 1 + bytes * (sizeof("00") - 1);
3365        }
3366
3367        len += sizeof(":") - 1;
3368    }
3369
3370    s->data = ngx_pnalloc(pool, len);
3371    if (s->data == NULL) {
3372        return NGX_ERROR;
3373    }
3374
3375    p = s->data;
3376
3377    for (i = 0; i < n; i++) {
3378        cipher = SSL_CIPHER_find(c->ssl->connection, ciphers + i * bytes);
3379
3380        if (cipher) {
3381            p = ngx_sprintf(p, "%s", SSL_CIPHER_get_name(cipher));
3382
3383        } else {
3384            p = ngx_sprintf(p, "0x");
3385            p = ngx_hex_dump(p, ciphers + i * bytes, bytes);
3386        }
3387
3388        *p++ = ':';
3389    }
3390
3391    p--;
3392
3393    s->len = p - s->data;
3394
3395#else
3396
3397    u_char  buf[4096];
3398
3399    if (SSL_get_shared_ciphers(c->ssl->connection, (char *) buf, 4096)
3400        == NULL)
3401    {
3402        s->len = 0;
3403        return NGX_OK;
3404    }
3405
3406    s->len = ngx_strlen(buf);
3407    s->data = ngx_pnalloc(pool, s->len);
3408    if (s->data == NULL) {
3409        return NGX_ERROR;
3410    }
3411
3412    ngx_memcpy(s->data, buf, s->len);
3413
3414#endif
3415
3416    return NGX_OK;
3417}
3418
3419
3420ngx_int_t
3421ngx_ssl_get_curves(ngx_connection_t *c, ngx_pool_t *pool, ngx_str_t *s)
3422{
3423#ifdef SSL_CTRL_GET_CURVES
3424
3425    int         *curves, n, i, nid;
3426    u_char      *p;
3427    size_t       len;
3428
3429    n = SSL_get1_curves(c->ssl->connection, NULL);
3430
3431    if (n <= 0) {
3432        s->len = 0;
3433        return NGX_OK;
3434    }
3435
3436    curves = ngx_palloc(pool, n * sizeof(int));
3437
3438    n = SSL_get1_curves(c->ssl->connection, curves);
3439    len = 0;
3440
3441    for (i = 0; i < n; i++) {
3442        nid = curves[i];
3443
3444        if (nid & TLSEXT_nid_unknown) {
3445            len += sizeof("0x0000") - 1;
3446
3447        } else {
3448            len += ngx_strlen(OBJ_nid2sn(nid));
3449        }
3450
3451        len += sizeof(":") - 1;
3452    }
3453
3454    s->data = ngx_pnalloc(pool, len);
3455    if (s->data == NULL) {
3456        return NGX_ERROR;
3457    }
3458
3459    p = s->data;
3460
3461    for (i = 0; i < n; i++) {
3462        nid = curves[i];
3463
3464        if (nid & TLSEXT_nid_unknown) {
3465            p = ngx_sprintf(p, "0x%04xd", nid & 0xffff);
3466
3467        } else {
3468            p = ngx_sprintf(p, "%s", OBJ_nid2sn(nid));
3469        }
3470
3471        *p++ = ':';
3472    }
3473
3474    p--;
3475
3476    s->len = p - s->data;
3477
3478#else
3479
3480    s->len = 0;
3481
3482#endif
3483
3484    return NGX_OK;
3485}
3486
3487
3488ngx_int_t
3489ngx_ssl_get_session_id(ngx_connection_t *c, ngx_pool_t *pool, ngx_str_t *s)
3490{
3491    u_char        *buf;
3492    SSL_SESSION   *sess;
3493    unsigned int   len;
3494
3495    sess = SSL_get0_session(c->ssl->connection);
3496    if (sess == NULL) {
3497        s->len = 0;
3498        return NGX_OK;
3499    }
3500
3501#if OPENSSL_VERSION_NUMBER >= 0x0090800fL
3502
3503    buf = (u_char *) SSL_SESSION_get_id(sess, &len);
3504
3505#else
3506
3507    buf = sess->session_id;
3508    len = sess->session_id_length;
3509
3510#endif
3511
3512    s->len = 2 * len;
3513    s->data = ngx_pnalloc(pool, 2 * len);
3514    if (s->data == NULL) {
3515        return NGX_ERROR;
3516    }
3517
3518    ngx_hex_dump(s->data, buf, len);
3519
3520    return NGX_OK;
3521}
3522
3523
3524ngx_int_t
3525ngx_ssl_get_session_reused(ngx_connection_t *c, ngx_pool_t *pool, ngx_str_t *s)
3526{
3527    if (SSL_session_reused(c->ssl->connection)) {
3528        ngx_str_set(s, "r");
3529
3530    } else {
3531        ngx_str_set(s, ".");
3532    }
3533
3534    return NGX_OK;
3535}
3536
3537
3538ngx_int_t
3539ngx_ssl_get_server_name(ngx_connection_t *c, ngx_pool_t *pool, ngx_str_t *s)
3540{
3541#ifdef SSL_CTRL_SET_TLSEXT_HOSTNAME
3542
3543    const char  *servername;
3544
3545    servername = SSL_get_servername(c->ssl->connection,
3546                                    TLSEXT_NAMETYPE_host_name);
3547    if (servername) {
3548        s->data = (u_char *) servername;
3549        s->len = ngx_strlen(servername);
3550        return NGX_OK;
3551    }
3552
3553#endif
3554
3555    s->len = 0;
3556    return NGX_OK;
3557}
3558
3559
3560ngx_int_t
3561ngx_ssl_get_raw_certificate(ngx_connection_t *c, ngx_pool_t *pool, ngx_str_t *s)
3562{
3563    size_t   len;
3564    BIO     *bio;
3565    X509    *cert;
3566
3567    s->len = 0;
3568
3569    cert = SSL_get_peer_certificate(c->ssl->connection);
3570    if (cert == NULL) {
3571        return NGX_OK;
3572    }
3573
3574    bio = BIO_new(BIO_s_mem());
3575    if (bio == NULL) {
3576        ngx_ssl_error(NGX_LOG_ALERT, c->log, 0, "BIO_new() failed");
3577        X509_free(cert);
3578        return NGX_ERROR;
3579    }
3580
3581    if (PEM_write_bio_X509(bio, cert) == 0) {
3582        ngx_ssl_error(NGX_LOG_ALERT, c->log, 0, "PEM_write_bio_X509() failed");
3583        goto failed;
3584    }
3585
3586    len = BIO_pending(bio);
3587    s->len = len;
3588
3589    s->data = ngx_pnalloc(pool, len);
3590    if (s->data == NULL) {
3591        goto failed;
3592    }
3593
3594    BIO_read(bio, s->data, len);
3595
3596    BIO_free(bio);
3597    X509_free(cert);
3598
3599    return NGX_OK;
3600
3601failed:
3602
3603    BIO_free(bio);
3604    X509_free(cert);
3605
3606    return NGX_ERROR;
3607}
3608
3609
3610ngx_int_t
3611ngx_ssl_get_certificate(ngx_connection_t *c, ngx_pool_t *pool, ngx_str_t *s)
3612{
3613    u_char      *p;
3614    size_t       len;
3615    ngx_uint_t   i;
3616    ngx_str_t    cert;
3617
3618    if (ngx_ssl_get_raw_certificate(c, pool, &cert) != NGX_OK) {
3619        return NGX_ERROR;
3620    }
3621
3622    if (cert.len == 0) {
3623        s->len = 0;
3624        return NGX_OK;
3625    }
3626
3627    len = cert.len - 1;
3628
3629    for (i = 0; i < cert.len - 1; i++) {
3630        if (cert.data[i] == LF) {
3631            len++;
3632        }
3633    }
3634
3635    s->len = len;
3636    s->data = ngx_pnalloc(pool, len);
3637    if (s->data == NULL) {
3638        return NGX_ERROR;
3639    }
3640
3641    p = s->data;
3642
3643    for (i = 0; i < cert.len - 1; i++) {
3644        *p++ = cert.data[i];
3645        if (cert.data[i] == LF) {
3646            *p++ = '\t';
3647        }
3648    }
3649
3650    return NGX_OK;
3651}
3652
3653
3654ngx_int_t
3655ngx_ssl_get_subject_dn(ngx_connection_t *c, ngx_pool_t *pool, ngx_str_t *s)
3656{
3657    BIO        *bio;
3658    X509       *cert;
3659    X509_NAME  *name;
3660
3661    s->len = 0;
3662
3663    cert = SSL_get_peer_certificate(c->ssl->connection);
3664    if (cert == NULL) {
3665        return NGX_OK;
3666    }
3667
3668    name = X509_get_subject_name(cert);
3669    if (name == NULL) {
3670        return NGX_ERROR;
3671    }
3672
3673    bio = BIO_new(BIO_s_mem());
3674    if (bio == NULL) {
3675        X509_free(cert);
3676        return NGX_ERROR;
3677    }
3678
3679    if (X509_NAME_print_ex(bio, name, 0, XN_FLAG_RFC2253) < 0) {
3680        goto failed;
3681    }
3682
3683    s->len = BIO_pending(bio);
3684    s->data = ngx_pnalloc(pool, s->len);
3685    if (s->data == NULL) {
3686        goto failed;
3687    }
3688
3689    BIO_read(bio, s->data, s->len);
3690
3691    BIO_free(bio);
3692    X509_free(cert);
3693
3694    return NGX_OK;
3695
3696failed:
3697
3698    BIO_free(bio);
3699    X509_free(cert);
3700
3701    return NGX_ERROR;
3702}
3703
3704
3705ngx_int_t
3706ngx_ssl_get_issuer_dn(ngx_connection_t *c, ngx_pool_t *pool, ngx_str_t *s)
3707{
3708    BIO        *bio;
3709    X509       *cert;
3710    X509_NAME  *name;
3711
3712    s->len = 0;
3713
3714    cert = SSL_get_peer_certificate(c->ssl->connection);
3715    if (cert == NULL) {
3716        return NGX_OK;
3717    }
3718
3719    name = X509_get_issuer_name(cert);
3720    if (name == NULL) {
3721        return NGX_ERROR;
3722    }
3723
3724    bio = BIO_new(BIO_s_mem());
3725    if (bio == NULL) {
3726        X509_free(cert);
3727        return NGX_ERROR;
3728    }
3729
3730    if (X509_NAME_print_ex(bio, name, 0, XN_FLAG_RFC2253) < 0) {
3731        goto failed;
3732    }
3733
3734    s->len = BIO_pending(bio);
3735    s->data = ngx_pnalloc(pool, s->len);
3736    if (s->data == NULL) {
3737        goto failed;
3738    }
3739
3740    BIO_read(bio, s->data, s->len);
3741
3742    BIO_free(bio);
3743    X509_free(cert);
3744
3745    return NGX_OK;
3746
3747failed:
3748
3749    BIO_free(bio);
3750    X509_free(cert);
3751
3752    return NGX_ERROR;
3753}
3754
3755
3756ngx_int_t
3757ngx_ssl_get_subject_dn_legacy(ngx_connection_t *c, ngx_pool_t *pool,
3758    ngx_str_t *s)
3759{
3760    char       *p;
3761    size_t      len;
3762    X509       *cert;
3763    X509_NAME  *name;
3764
3765    s->len = 0;
3766
3767    cert = SSL_get_peer_certificate(c->ssl->connection);
3768    if (cert == NULL) {
3769        return NGX_OK;
3770    }
3771
3772    name = X509_get_subject_name(cert);
3773    if (name == NULL) {
3774        X509_free(cert);
3775        return NGX_ERROR;
3776    }
3777
3778    p = X509_NAME_oneline(name, NULL, 0);
3779
3780    for (len = 0; p[len]; len++) { /* void */ }
3781
3782    s->len = len;
3783    s->data = ngx_pnalloc(pool, len);
3784    if (s->data == NULL) {
3785        OPENSSL_free(p);
3786        X509_free(cert);
3787        return NGX_ERROR;
3788    }
3789
3790    ngx_memcpy(s->data, p, len);
3791
3792    OPENSSL_free(p);
3793    X509_free(cert);
3794
3795    return NGX_OK;
3796}
3797
3798
3799ngx_int_t
3800ngx_ssl_get_issuer_dn_legacy(ngx_connection_t *c, ngx_pool_t *pool,
3801    ngx_str_t *s)
3802{
3803    char       *p;
3804    size_t      len;
3805    X509       *cert;
3806    X509_NAME  *name;
3807
3808    s->len = 0;
3809
3810    cert = SSL_get_peer_certificate(c->ssl->connection);
3811    if (cert == NULL) {
3812        return NGX_OK;
3813    }
3814
3815    name = X509_get_issuer_name(cert);
3816    if (name == NULL) {
3817        X509_free(cert);
3818        return NGX_ERROR;
3819    }
3820
3821    p = X509_NAME_oneline(name, NULL, 0);
3822
3823    for (len = 0; p[len]; len++) { /* void */ }
3824
3825    s->len = len;
3826    s->data = ngx_pnalloc(pool, len);
3827    if (s->data == NULL) {
3828        OPENSSL_free(p);
3829        X509_free(cert);
3830        return NGX_ERROR;
3831    }
3832
3833    ngx_memcpy(s->data, p, len);
3834
3835    OPENSSL_free(p);
3836    X509_free(cert);
3837
3838    return NGX_OK;
3839}
3840
3841
3842ngx_int_t
3843ngx_ssl_get_serial_number(ngx_connection_t *c, ngx_pool_t *pool, ngx_str_t *s)
3844{
3845    size_t   len;
3846    X509    *cert;
3847    BIO     *bio;
3848
3849    s->len = 0;
3850
3851    cert = SSL_get_peer_certificate(c->ssl->connection);
3852    if (cert == NULL) {
3853        return NGX_OK;
3854    }
3855
3856    bio = BIO_new(BIO_s_mem());
3857    if (bio == NULL) {
3858        X509_free(cert);
3859        return NGX_ERROR;
3860    }
3861
3862    i2a_ASN1_INTEGER(bio, X509_get_serialNumber(cert));
3863    len = BIO_pending(bio);
3864
3865    s->len = len;
3866    s->data = ngx_pnalloc(pool, len);
3867    if (s->data == NULL) {
3868        BIO_free(bio);
3869        X509_free(cert);
3870        return NGX_ERROR;
3871    }
3872
3873    BIO_read(bio, s->data, len);
3874    BIO_free(bio);
3875    X509_free(cert);
3876
3877    return NGX_OK;
3878}
3879
3880
3881ngx_int_t
3882ngx_ssl_get_fingerprint(ngx_connection_t *c, ngx_pool_t *pool, ngx_str_t *s)
3883{
3884    X509          *cert;
3885    unsigned int   len;
3886    u_char         buf[EVP_MAX_MD_SIZE];
3887
3888    s->len = 0;
3889
3890    cert = SSL_get_peer_certificate(c->ssl->connection);
3891    if (cert == NULL) {
3892        return NGX_OK;
3893    }
3894
3895    if (!X509_digest(cert, EVP_sha1(), buf, &len)) {
3896        X509_free(cert);
3897        return NGX_ERROR;
3898    }
3899
3900    s->len = 2 * len;
3901    s->data = ngx_pnalloc(pool, 2 * len);
3902    if (s->data == NULL) {
3903        X509_free(cert);
3904        return NGX_ERROR;
3905    }
3906
3907    ngx_hex_dump(s->data, buf, len);
3908
3909    X509_free(cert);
3910
3911    return NGX_OK;
3912}
3913
3914
3915ngx_int_t
3916ngx_ssl_get_client_verify(ngx_connection_t *c, ngx_pool_t *pool, ngx_str_t *s)
3917{
3918    X509        *cert;
3919    long         rc;
3920    const char  *str;
3921
3922    cert = SSL_get_peer_certificate(c->ssl->connection);
3923    if (cert == NULL) {
3924        ngx_str_set(s, "NONE");
3925        return NGX_OK;
3926    }
3927
3928    X509_free(cert);
3929
3930    rc = SSL_get_verify_result(c->ssl->connection);
3931
3932    if (rc == X509_V_OK) {
3933        ngx_str_set(s, "SUCCESS");
3934        return NGX_OK;
3935    }
3936
3937    str = X509_verify_cert_error_string(rc);
3938
3939    s->data = ngx_pnalloc(pool, sizeof("FAILED:") - 1 + ngx_strlen(str));
3940    if (s->data == NULL) {
3941        return NGX_ERROR;
3942    }
3943
3944    s->len = ngx_sprintf(s->data, "FAILED:%s", str) - s->data;
3945
3946    return NGX_OK;
3947}
3948
3949
3950ngx_int_t
3951ngx_ssl_get_client_v_start(ngx_connection_t *c, ngx_pool_t *pool, ngx_str_t *s)
3952{
3953    BIO     *bio;
3954    X509    *cert;
3955    size_t   len;
3956
3957    s->len = 0;
3958
3959    cert = SSL_get_peer_certificate(c->ssl->connection);
3960    if (cert == NULL) {
3961        return NGX_OK;
3962    }
3963
3964    bio = BIO_new(BIO_s_mem());
3965    if (bio == NULL) {
3966        X509_free(cert);
3967        return NGX_ERROR;
3968    }
3969
3970#if OPENSSL_VERSION_NUMBER > 0x10100000L
3971    ASN1_TIME_print(bio, X509_get0_notBefore(cert));
3972#else
3973    ASN1_TIME_print(bio, X509_get_notBefore(cert));
3974#endif
3975
3976    len = BIO_pending(bio);
3977
3978    s->len = len;
3979    s->data = ngx_pnalloc(pool, len);
3980    if (s->data == NULL) {
3981        BIO_free(bio);
3982        X509_free(cert);
3983        return NGX_ERROR;
3984    }
3985
3986    BIO_read(bio, s->data, len);
3987    BIO_free(bio);
3988    X509_free(cert);
3989
3990    return NGX_OK;
3991}
3992
3993
3994ngx_int_t
3995ngx_ssl_get_client_v_end(ngx_connection_t *c, ngx_pool_t *pool, ngx_str_t *s)
3996{
3997    BIO     *bio;
3998    X509    *cert;
3999    size_t   len;
4000
4001    s->len = 0;
4002
4003    cert = SSL_get_peer_certificate(c->ssl->connection);
4004    if (cert == NULL) {
4005        return NGX_OK;
4006    }
4007
4008    bio = BIO_new(BIO_s_mem());
4009    if (bio == NULL) {
4010        X509_free(cert);
4011        return NGX_ERROR;
4012    }
4013
4014#if OPENSSL_VERSION_NUMBER > 0x10100000L
4015    ASN1_TIME_print(bio, X509_get0_notAfter(cert));
4016#else
4017    ASN1_TIME_print(bio, X509_get_notAfter(cert));
4018#endif
4019
4020    len = BIO_pending(bio);
4021
4022    s->len = len;
4023    s->data = ngx_pnalloc(pool, len);
4024    if (s->data == NULL) {
4025        BIO_free(bio);
4026        X509_free(cert);
4027        return NGX_ERROR;
4028    }
4029
4030    BIO_read(bio, s->data, len);
4031    BIO_free(bio);
4032    X509_free(cert);
4033
4034    return NGX_OK;
4035}
4036
4037
4038ngx_int_t
4039ngx_ssl_get_client_v_remain(ngx_connection_t *c, ngx_pool_t *pool, ngx_str_t *s)
4040{
4041    X509    *cert;
4042    time_t   now, end;
4043
4044    s->len = 0;
4045
4046    cert = SSL_get_peer_certificate(c->ssl->connection);
4047    if (cert == NULL) {
4048        return NGX_OK;
4049    }
4050
4051#if OPENSSL_VERSION_NUMBER > 0x10100000L
4052    end = ngx_ssl_parse_time(X509_get0_notAfter(cert));
4053#else
4054    end = ngx_ssl_parse_time(X509_get_notAfter(cert));
4055#endif
4056
4057    if (end == (time_t) NGX_ERROR) {
4058        X509_free(cert);
4059        return NGX_OK;
4060    }
4061
4062    now = ngx_time();
4063
4064    if (end < now + 86400) {
4065        ngx_str_set(s, "0");
4066        X509_free(cert);
4067        return NGX_OK;
4068    }
4069
4070    s->data = ngx_pnalloc(pool, NGX_TIME_T_LEN);
4071    if (s->data == NULL) {
4072        X509_free(cert);
4073        return NGX_ERROR;
4074    }
4075
4076    s->len = ngx_sprintf(s->data, "%T", (end - now) / 86400) - s->data;
4077
4078    X509_free(cert);
4079
4080    return NGX_OK;
4081}
4082
4083
4084static time_t
4085ngx_ssl_parse_time(
4086#if OPENSSL_VERSION_NUMBER > 0x10100000L
4087    const
4088#endif
4089    ASN1_TIME *asn1time)
4090{
4091    BIO     *bio;
4092    char    *value;
4093    size_t   len;
4094    time_t   time;
4095
4096    /*
4097     * OpenSSL doesn't provide a way to convert ASN1_TIME
4098     * into time_t.  To do this, we use ASN1_TIME_print(),
4099     * which uses the "MMM DD HH:MM:SS YYYY [GMT]" format (e.g.,
4100     * "Feb  3 00:55:52 2015 GMT"), and parse the result.
4101     */
4102
4103    bio = BIO_new(BIO_s_mem());
4104    if (bio == NULL) {
4105        return NGX_ERROR;
4106    }
4107
4108    /* fake weekday prepended to match C asctime() format */
4109
4110    BIO_write(bio, "Tue ", sizeof("Tue ") - 1);
4111    ASN1_TIME_print(bio, asn1time);
4112    len = BIO_get_mem_data(bio, &value);
4113
4114    time = ngx_parse_http_time((u_char *) value, len);
4115
4116    BIO_free(bio);
4117
4118    return time;
4119}
4120
4121
4122static void *
4123ngx_openssl_create_conf(ngx_cycle_t *cycle)
4124{
4125    ngx_openssl_conf_t  *oscf;
4126
4127    oscf = ngx_pcalloc(cycle->pool, sizeof(ngx_openssl_conf_t));
4128    if (oscf == NULL) {
4129        return NULL;
4130    }
4131
4132    /*
4133     * set by ngx_pcalloc():
4134     *
4135     *     oscf->engine = 0;
4136     */
4137
4138    return oscf;
4139}
4140
4141
4142static char *
4143ngx_openssl_engine(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
4144{
4145#ifndef OPENSSL_NO_ENGINE
4146
4147    ngx_openssl_conf_t *oscf = conf;
4148
4149    ENGINE     *engine;
4150    ngx_str_t  *value;
4151
4152    if (oscf->engine) {
4153        return "is duplicate";
4154    }
4155
4156    oscf->engine = 1;
4157
4158    value = cf->args->elts;
4159
4160    engine = ENGINE_by_id((char *) value[1].data);
4161
4162    if (engine == NULL) {
4163        ngx_ssl_error(NGX_LOG_EMERG, cf->log, 0,
4164                      "ENGINE_by_id(\"%V\") failed", &value[1]);
4165        return NGX_CONF_ERROR;
4166    }
4167
4168    if (ENGINE_set_default(engine, ENGINE_METHOD_ALL) == 0) {
4169        ngx_ssl_error(NGX_LOG_EMERG, cf->log, 0,
4170                      "ENGINE_set_default(\"%V\", ENGINE_METHOD_ALL) failed",
4171                      &value[1]);
4172
4173        ENGINE_free(engine);
4174
4175        return NGX_CONF_ERROR;
4176    }
4177
4178    ENGINE_free(engine);
4179
4180    return NGX_CONF_OK;
4181
4182#else
4183
4184    return "is not supported";
4185
4186#endif
4187}
4188
4189
4190static void
4191ngx_openssl_exit(ngx_cycle_t *cycle)
4192{
4193#if OPENSSL_VERSION_NUMBER < 0x10100003L
4194
4195    EVP_cleanup();
4196#ifndef OPENSSL_NO_ENGINE
4197    ENGINE_cleanup();
4198#endif
4199
4200#endif
4201}
4202