Latest update - GitHub 5917e9d

This commit is contained in:
2024-10-02 20:40:07 +09:00
parent c10ab73fe3
commit 15aa168406
9 changed files with 1376 additions and 413 deletions
-3
View File
@@ -1,3 +0,0 @@
Documentation is available at http://nginx.org
+230
View File
@@ -0,0 +1,230 @@
<picture>
<source media="(prefers-color-scheme: dark)" srcset="https://github.com/user-attachments/assets/9335b488-ffcc-4157-8364-2370a0b70ad0">
<source media="(prefers-color-scheme: light)" srcset="https://github.com/user-attachments/assets/3a7eeb08-1133-47f5-859c-fad4f5a6a013">
<img alt="NGINX Banner">
</picture>
NGINX (pronounced "engine x" or "en-jin-eks") is the world's most popular Web Server, high performance Load Balancer, Reverse Proxy, API Gateway and Content Cache.
NGINX is free and open source software, distributed under the terms of a simplified [2-clause BSD-like license](LICENSE).
Enterprise distributions, commercial support and training are available from [F5, Inc](https://www.f5.com/products/nginx).
> [!IMPORTANT]
> The goal of this README is to provide a basic, structured introduction to NGINX for novice users. Please refer to the [full NGINX documentation](https://nginx.org/en/docs/) for detailed information on [installing](https://nginx.org/en/docs/install.html), [building](https://nginx.org/en/docs/configure.html), [configuring](https://nginx.org/en/docs/dirindex.html), [debugging](https://nginx.org/en/docs/debugging_log.html), and more. These documentation pages also contain a more detailed [Beginners Guide](https://nginx.org/en/docs/beginners_guide.html), How-Tos, [Development guide](https://nginx.org/en/docs/dev/development_guide.html), and a complete module and [directive reference](https://nginx.org/en/docs/dirindex.html).
# Table of contents
- [How it works](#how-it-works)
- [Modules](#modules)
- [Configurations](#configurations)
- [Runtime](#runtime)
- [Downloading and installing](#downloading-and-installing)
- [Stable and Mainline binaries](#stable-and-mainline-binaries)
- [Linux binary installation process](#linux-binary-installation-process)
- [FreeBSD installation process](#freebsd-installation-process)
- [Windows executables](#windows-executables)
- [Dynamic modules](#dynamic-modules)
- [Getting started with NGINX](#getting-started-with-nginx)
- [Installing SSL certificates and enabling TLS encryption](#installing-ssl-certificates-and-enabling-tls-encryption)
- [Load Balancing](#load-balancing)
- [Rate limiting](#rate-limiting)
- [Content caching](#content-caching)
- [Building from source](#building-from-source)
- [Installing dependencies](#installing-dependencies)
- [Cloning the NGINX GitHub repository](#cloning-the-nginx-github-repository)
- [Configuring the build](#configuring-the-build)
- [Compiling](#compiling)
- [Location of binary and installation](#location-of-binary-and-installation)
- [Running and testing the installed binary](#running-and-testing-the-installed-binary)
- [Asking questions and reporting issues](#asking-questions-and-reporting-issues)
- [Contributing code](#contributing-code)
- [Additional help and resources](#additional-help-and-resources)
- [Changelog](#changelog)
- [License](#license)
# How it works
NGINX is installed software with binary packages available for all major operating systems and Linux distributions. See [Tested OS and Platforms](https://nginx.org/en/#tested_os_and_platforms) for a full list of compatible systems.
> [!IMPORTANT]
> While nearly all popular Linux-based operating systems are distributed with a community version of nginx, we highly advise installation and usage of official [packages](https://nginx.org/en/linux_packages.html) or sources from this repository. Doing so ensures that you're using the most recent release or source code, including the latest feature-set, fixes and security patches.
## Modules
NGINX is comprised of individual modules, each extending core functionality by providing additional, configurable features. See "Modules reference" at the bottom of [nginx documentation](https://nginx.org/en/docs/) for a complete list of official modules.
NGINX modules can be built and distributed as static or dynamic modules. Static modules are defined at build-time, compiled, and distributed in the resulting binaries. See [Dynamic Modules](#dynamic-modules) for more information on how they work, as well as, how to obtain, install, and configure them.
> [!TIP]
> You can issue the following command to see which static modules your NGINX binaries were built with:
```bash
nginx -V
```
> See [Configuring the build](#configuring-the-build) for information on how to include specific Static modules into your nginx build.
## Configurations
NGINX is highly flexible and configurable. Provisioning the software is achieved via text-based config file(s) accepting parameters called "[Directives](https://nginx.org/en/docs/dirindex.html)". See [Configuration File's Structure](https://nginx.org/en/docs/beginners_guide.html#conf_structure) for a comprehensive description of how NGINX configuration files work.
> [!NOTE]
> The set of directives available to your distribution of NGINX is dependent on which [modules](#modules) have been made available to it.
## Runtime
Rather than running in a single, monolithic process, NGINX is architected to scale beyond Operating System process limitations by operating as a collection of processes. They include:
- A "master" process that maintains worker processes, as well as, reads and evaluates configuration files.
- One or more "worker" processes that process data (eg. HTTP requests).
The number of [worker processes](https://nginx.org/en/docs/ngx_core_module.html#worker_processes) is defined in the configuration file and may be fixed for a given configuration or automatically adjusted to the number of available CPU cores. In most cases, the latter option optimally balances load across available system resources, as NGINX is designed to efficiently distribute work across all worker processes.
> [!TIP]
> Processes synchronize data through shared memory. For this reason, many NGINX directives require the allocation of shared memory zones. As an example, when configuring [rate limiting](https://nginx.org/en/docs/http/ngx_http_limit_req_module.html#limit_req), connecting clients may need to be tracked in a [common memory zone](https://nginx.org/en/docs/http/ngx_http_limit_req_module.html#limit_req_zone) so all worker processes can know how many times a particular client has accessed the server in a span of time.
# Downloading and installing
Follow these steps to download and install precompiled NGINX binaries. You may also choose to [build NGINX locally from source code](#building-from-source).
## Stable and Mainline binaries
NGINX binaries are built and distributed in two versions: stable and mainline. Stable binaries are built from stable branches and only contain critical fixes backported from the mainline version. Mainline binaries are built from the [master branch](https://github.com/nginx/nginx/tree/master) and contain the latest features and bugfixes. You'll need to [decide which is appropriate for your purposes](https://docs.nginx.com/nginx/admin-guide/installing-nginx/installing-nginx-open-source/#choosing-between-a-stable-or-a-mainline-version).
## Linux binary installation process
The NGINX binary installation process takes advantage of package managers native to specific Linux distributions. For this reason, first-time installations involve adding the official NGINX package repository to your system's package manager. Follow [these steps](https://nginx.org/en/linux_packages.html) to download, verify, and install NGINX binaries using the package manager appropriate for your Linux distribution.
### Upgrades
Future upgrades to the latest version can be managed using the same package manager without the need to manually download and verify binaries.
## FreeBSD installation process
For more information on installing NGINX on FreeBSD system, visit https://nginx.org/en/docs/install.html
## Windows executables
Windows executables for mainline and stable releases can be found on the main [NGINX download page](https://nginx.org/en/download.html). Note that the current implementation of NGINX for Windows is at the Proof-of-Concept stage and should only be used for development and testing purposes. For additional information, please see [nginx for Windows](https://nginx.org/en/docs/windows.html).
## Dynamic modules
NGINX version 1.9.11 added support for [Dynamic Modules](https://nginx.org/en/docs/ngx_core_module.html#load_module). Unlike Static modules, dynamically built modules can be downloaded, installed, and configured after the core NGINX binaries have been built. [Official dynamic module binaries](https://nginx.org/en/linux_packages.html#dynmodules) are available from the same package repository as the core NGINX binaries described in previous steps.
> [!TIP]
> [NGINX JavaScript (njs)](https://github.com/nginx/njs), is a popular NGINX dynamic module that enables the extension of core NGINX functionality using familiar JavaScript syntax.
> [!IMPORTANT]
> If desired, dynamic modules can also be built statically into NGINX at compile time.
# Getting started with NGINX
For a gentle introduction to NGINX basics, please see our [Beginners Guide](https://nginx.org/en/docs/beginners_guide.html).
## Installing SSL certificates and enabling TLS encryption
See [Configuring HTTPS servers](https://nginx.org/en/docs/http/configuring_https_servers.html) for a quick guide on how to enable secure traffic to your NGINX installation.
## Load Balancing
For a quick start guide on configuring NGINX as a Load Balancer, please see [Using nginx as HTTP load balancer](https://nginx.org/en/docs/http/load_balancing.html).
## Rate limiting
See our [Rate Limiting with NGINX](https://blog.nginx.org/blog/rate-limiting-nginx) blog post for an overview of core concepts for provisioning NGINX as an API Gateway.
## Content caching
See [A Guide to Caching with NGINX and NGINX Plus](https://blog.nginx.org/blog/nginx-caching-guide) blog post for an overview of how to use NGINX as a content cache (e.g. edge server of a content delivery network).
# Building from source
The following steps can be used to build NGINX from source code available in this repository.
## Installing dependencies
Most Linux distributions will require several dependencies to be installed in order to build NGINX. The following instructions are specific to the `apt` package manager, widely available on most Ubuntu/Debian distributions and their derivatives.
> [!TIP]
> It is always a good idea to update your package repository lists prior to installing new packages.
> ```bash
> sudo apt update
> ```
### Installing compiler and make utility
Use the following command to install the GNU C compiler and Make utility.
```bash
sudo apt install gcc make
```
### Installing dependency libraries
```bash
sudo apt install libpcre3-dev zlib1g-dev
```
> [!WARNING]
> This is the minimal set of dependency libraries needed to build NGINX with rewriting and gzip capabilities. Other dependencies may be required if you choose to build NGINX with additional modules. Monitor the output of the `configure` command discussed in the following sections for information on which modules may be missing. For example, if you plan to use SSL certificates to encrypt traffic with TLS, you'll need to install the OpenSSL library. To do so, issue the following command.
>```bash
>sudo apt install libssl-dev
## Cloning the NGINX GitHub repository
Using your preferred method, clone the NGINX repository into your development directory. See [Cloning a GitHub Repository](https://docs.github.com/en/repositories/creating-and-managing-repositories/cloning-a-repository) for additional help.
```bash
git clone https://github.com/nginx/nginx.git
```
## Configuring the build
Prior to building NGINX, you must run the `configure` script with [appropriate flags](https://nginx.org/en/docs/configure.html). This will generate a Makefile in your NGINX source root directory that can then be used to compile NGINX with [options specified during configuration](https://nginx.org/en/docs/configure.html).
From the NGINX source code repository's root directory:
```bash
auto/configure
```
> [!IMPORTANT]
> Configuring the build without any flags will compile NGINX with the default set of options. Please refer to https://nginx.org/en/docs/configure.html for a full list of available build configuration options.
## Compiling
The `configure` script will generate a `Makefile` in the NGINX source root directory upon successful execution. To compile NGINX into a binary, issue the following command from that same directory:
```bash
make
```
## Location of binary and installation
After successful compilation, a binary will be generated at `<NGINX_SRC_ROOT_DIR>/objs/nginx`. To install this binary, issue the following command from the source root directory:
```bash
sudo make install
```
> [!IMPORTANT]
> The binary will be installed into the `/usr/local/nginx/` directory.
## Running and testing the installed binary
To run the installed binary, issue the following command:
```bash
sudo /usr/local/nginx/sbin/nginx
```
You may test NGINX operation using `curl`.
```bash
curl localhost
```
The output of which should start with:
```html
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
```
# Asking questions and reporting issues
We encourage you to engage with us.
- [NGINX GitHub Discussions](https://github.com/nginx/nginx/discussions), is the go-to place to start asking questions and sharing your thoughts.
- Our [GitHub Issues](https://github.com/nginx/nginx/issues) page offers space to submit and discuss specific issues, report bugs, and suggest enhancements.
# Contributing code
Please see the [Contributing](CONTRIBUTING.md) guide for information on how to contribute code.
# Additional help and resources
- See the [NGINX Community Blog](https://blog.nginx.org/) for more tips, tricks and HOW-TOs related to NGINX and related projects.
- Access [nginx.org](https://nginx.org/), your go-to source for all documentation, information and software related to the NGINX suite of projects.
# Changelog
See our [changelog](https://nginx.org/en/CHANGES) to keep track of updates.
# License
[2-clause BSD-like license](LICENSE)
---
Additional documentation available at: https://nginx.org/en/docs
+2 -1
View File
@@ -1311,10 +1311,11 @@ fi
if [ $USE_OPENSSL = YES ]; then if [ $USE_OPENSSL = YES ]; then
ngx_module_type=CORE ngx_module_type=CORE
ngx_module_name=ngx_openssl_module ngx_module_name="ngx_openssl_module ngx_openssl_cache_module"
ngx_module_incs= ngx_module_incs=
ngx_module_deps=src/event/ngx_event_openssl.h ngx_module_deps=src/event/ngx_event_openssl.h
ngx_module_srcs="src/event/ngx_event_openssl.c ngx_module_srcs="src/event/ngx_event_openssl.c
src/event/ngx_event_openssl_cache.c
src/event/ngx_event_openssl_stapling.c" src/event/ngx_event_openssl_stapling.c"
ngx_module_libs= ngx_module_libs=
ngx_module_link=YES ngx_module_link=YES
+1 -1
View File
@@ -92,7 +92,7 @@ zip: export
sed -i '' -e "s/$$/`printf '\r'`/" $(TEMP)/$(NGINX)/conf/* sed -i '' -e "s/$$/`printf '\r'`/" $(TEMP)/$(NGINX)/conf/*
mv $(TEMP)/$(NGINX)/LICENSE $(TEMP)/$(NGINX)/docs.new mv $(TEMP)/$(NGINX)/LICENSE $(TEMP)/$(NGINX)/docs.new
mv $(TEMP)/$(NGINX)/README $(TEMP)/$(NGINX)/docs.new mv $(TEMP)/$(NGINX)/README.md $(TEMP)/$(NGINX)/docs.new
mv $(TEMP)/$(NGINX)/docs/html $(TEMP)/$(NGINX) mv $(TEMP)/$(NGINX)/docs/html $(TEMP)/$(NGINX)
rm -r $(TEMP)/$(NGINX)/docs rm -r $(TEMP)/$(NGINX)/docs
+262 -385
View File
@@ -18,15 +18,12 @@ typedef struct {
} ngx_openssl_conf_t; } ngx_openssl_conf_t;
static X509 *ngx_ssl_load_certificate(ngx_pool_t *pool, char **err, static ngx_inline ngx_int_t ngx_ssl_cert_already_in_hash(void);
ngx_str_t *cert, STACK_OF(X509) **chain);
static EVP_PKEY *ngx_ssl_load_certificate_key(ngx_pool_t *pool, char **err,
ngx_str_t *key, ngx_array_t *passwords);
static int ngx_ssl_password_callback(char *buf, int size, int rwflag,
void *userdata);
static int ngx_ssl_verify_callback(int ok, X509_STORE_CTX *x509_store); static int ngx_ssl_verify_callback(int ok, X509_STORE_CTX *x509_store);
static void ngx_ssl_info_callback(const ngx_ssl_conn_t *ssl_conn, int where, static void ngx_ssl_info_callback(const ngx_ssl_conn_t *ssl_conn, int where,
int ret); int ret);
static int ngx_ssl_cmp_x509_name(const X509_NAME *const *a,
const X509_NAME *const *b);
static void ngx_ssl_passwords_cleanup(void *data); static void ngx_ssl_passwords_cleanup(void *data);
static int ngx_ssl_new_client_session(ngx_ssl_conn_t *ssl_conn, static int ngx_ssl_new_client_session(ngx_ssl_conn_t *ssl_conn,
ngx_ssl_session_t *sess); ngx_ssl_session_t *sess);
@@ -131,10 +128,8 @@ int ngx_ssl_server_conf_index;
int ngx_ssl_session_cache_index; int ngx_ssl_session_cache_index;
int ngx_ssl_ticket_keys_index; int ngx_ssl_ticket_keys_index;
int ngx_ssl_ocsp_index; int ngx_ssl_ocsp_index;
int ngx_ssl_certificate_index; int ngx_ssl_index;
int ngx_ssl_next_certificate_index;
int ngx_ssl_certificate_name_index; int ngx_ssl_certificate_name_index;
int ngx_ssl_stapling_index;
ngx_int_t ngx_int_t
@@ -258,21 +253,14 @@ ngx_ssl_init(ngx_log_t *log)
return NGX_ERROR; return NGX_ERROR;
} }
ngx_ssl_certificate_index = SSL_CTX_get_ex_new_index(0, NULL, NULL, NULL, ngx_ssl_index = SSL_CTX_get_ex_new_index(0, NULL, NULL, NULL, NULL);
NULL);
if (ngx_ssl_certificate_index == -1) { if (ngx_ssl_index == -1) {
ngx_ssl_error(NGX_LOG_ALERT, log, 0, ngx_ssl_error(NGX_LOG_ALERT, log, 0,
"SSL_CTX_get_ex_new_index() failed"); "SSL_CTX_get_ex_new_index() failed");
return NGX_ERROR; return NGX_ERROR;
} }
ngx_ssl_next_certificate_index = X509_get_ex_new_index(0, NULL, NULL, NULL,
NULL);
if (ngx_ssl_next_certificate_index == -1) {
ngx_ssl_error(NGX_LOG_ALERT, log, 0, "X509_get_ex_new_index() failed");
return NGX_ERROR;
}
ngx_ssl_certificate_name_index = X509_get_ex_new_index(0, NULL, NULL, NULL, ngx_ssl_certificate_name_index = X509_get_ex_new_index(0, NULL, NULL, NULL,
NULL); NULL);
@@ -281,13 +269,6 @@ ngx_ssl_init(ngx_log_t *log)
return NGX_ERROR; return NGX_ERROR;
} }
ngx_ssl_stapling_index = X509_get_ex_new_index(0, NULL, NULL, NULL, NULL);
if (ngx_ssl_stapling_index == -1) {
ngx_ssl_error(NGX_LOG_ALERT, log, 0, "X509_get_ex_new_index() failed");
return NGX_ERROR;
}
return NGX_OK; return NGX_OK;
} }
@@ -308,12 +289,15 @@ ngx_ssl_create(ngx_ssl_t *ssl, ngx_uint_t protocols, void *data)
return NGX_ERROR; return NGX_ERROR;
} }
if (SSL_CTX_set_ex_data(ssl->ctx, ngx_ssl_certificate_index, NULL) == 0) { if (SSL_CTX_set_ex_data(ssl->ctx, ngx_ssl_index, ssl) == 0) {
ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0, ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0,
"SSL_CTX_set_ex_data() failed"); "SSL_CTX_set_ex_data() failed");
return NGX_ERROR; return NGX_ERROR;
} }
ngx_rbtree_init(&ssl->staple_rbtree, &ssl->staple_sentinel,
ngx_rbtree_insert_value);
ssl->buffer_size = NGX_SSL_BUFSIZE; ssl->buffer_size = NGX_SSL_BUFSIZE;
/* client side options */ /* client side options */
@@ -458,12 +442,12 @@ ngx_ssl_certificate(ngx_conf_t *cf, ngx_ssl_t *ssl, ngx_str_t *cert,
ngx_str_t *key, ngx_array_t *passwords) ngx_str_t *key, ngx_array_t *passwords)
{ {
char *err; char *err;
X509 *x509; X509 *x509, **elm;
EVP_PKEY *pkey; EVP_PKEY *pkey;
STACK_OF(X509) *chain; STACK_OF(X509) *chain;
x509 = ngx_ssl_load_certificate(cf->pool, &err, cert, &chain); chain = ngx_ssl_cache_fetch(cf, NGX_SSL_CACHE_CERT, &err, cert, NULL);
if (x509 == NULL) { if (chain == NULL) {
if (err != NULL) { if (err != NULL) {
ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0, ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0,
"cannot load certificate \"%s\": %s", "cannot load certificate \"%s\": %s",
@@ -473,6 +457,8 @@ ngx_ssl_certificate(ngx_conf_t *cf, ngx_ssl_t *ssl, ngx_str_t *cert,
return NGX_ERROR; return NGX_ERROR;
} }
x509 = sk_X509_shift(chain);
if (SSL_CTX_use_certificate(ssl->ctx, x509) == 0) { if (SSL_CTX_use_certificate(ssl->ctx, x509) == 0) {
ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0, ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0,
"SSL_CTX_use_certificate(\"%s\") failed", cert->data); "SSL_CTX_use_certificate(\"%s\") failed", cert->data);
@@ -490,29 +476,29 @@ ngx_ssl_certificate(ngx_conf_t *cf, ngx_ssl_t *ssl, ngx_str_t *cert,
return NGX_ERROR; return NGX_ERROR;
} }
if (X509_set_ex_data(x509, ngx_ssl_next_certificate_index, if (ssl->certs.elts == NULL) {
SSL_CTX_get_ex_data(ssl->ctx, ngx_ssl_certificate_index)) if (ngx_array_init(&ssl->certs, cf->pool, 1, sizeof(X509 *))
== 0) != NGX_OK)
{ {
ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0, "X509_set_ex_data() failed"); X509_free(x509);
sk_X509_pop_free(chain, X509_free);
return NGX_ERROR;
}
}
elm = ngx_array_push(&ssl->certs);
if (elm == NULL) {
X509_free(x509); X509_free(x509);
sk_X509_pop_free(chain, X509_free); sk_X509_pop_free(chain, X509_free);
return NGX_ERROR; return NGX_ERROR;
} }
if (SSL_CTX_set_ex_data(ssl->ctx, ngx_ssl_certificate_index, x509) == 0) { *elm = x509;
ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0,
"SSL_CTX_set_ex_data() failed");
X509_free(x509);
sk_X509_pop_free(chain, X509_free);
return NGX_ERROR;
}
/* /*
* Note that x509 is not freed here, but will be instead freed in * Note that x509 is not freed here, but will be instead freed in
* ngx_ssl_cleanup_ctx(). This is because we need to preserve all * ngx_ssl_cleanup_ctx(). This is because we need to preserve all
* certificates to be able to iterate all of them through exdata * certificates to be able to iterate all of them through ssl->certs,
* (ngx_ssl_certificate_index, ngx_ssl_next_certificate_index),
* while OpenSSL can free a certificate if it is replaced with another * while OpenSSL can free a certificate if it is replaced with another
* certificate of the same type. * certificate of the same type.
*/ */
@@ -550,7 +536,7 @@ ngx_ssl_certificate(ngx_conf_t *cf, ngx_ssl_t *ssl, ngx_str_t *cert,
} }
#endif #endif
pkey = ngx_ssl_load_certificate_key(cf->pool, &err, key, passwords); pkey = ngx_ssl_cache_fetch(cf, NGX_SSL_CACHE_PKEY, &err, key, passwords);
if (pkey == NULL) { if (pkey == NULL) {
if (err != NULL) { if (err != NULL) {
ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0, ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0,
@@ -583,8 +569,9 @@ ngx_ssl_connection_certificate(ngx_connection_t *c, ngx_pool_t *pool,
EVP_PKEY *pkey; EVP_PKEY *pkey;
STACK_OF(X509) *chain; STACK_OF(X509) *chain;
x509 = ngx_ssl_load_certificate(pool, &err, cert, &chain); chain = ngx_ssl_cache_connection_fetch(pool, NGX_SSL_CACHE_CERT, &err,
if (x509 == NULL) { cert, NULL);
if (chain == NULL) {
if (err != NULL) { if (err != NULL) {
ngx_ssl_error(NGX_LOG_ERR, c->log, 0, ngx_ssl_error(NGX_LOG_ERR, c->log, 0,
"cannot load certificate \"%s\": %s", "cannot load certificate \"%s\": %s",
@@ -594,6 +581,8 @@ ngx_ssl_connection_certificate(ngx_connection_t *c, ngx_pool_t *pool,
return NGX_ERROR; return NGX_ERROR;
} }
x509 = sk_X509_shift(chain);
if (SSL_use_certificate(c->ssl->connection, x509) == 0) { if (SSL_use_certificate(c->ssl->connection, x509) == 0) {
ngx_ssl_error(NGX_LOG_ERR, c->log, 0, ngx_ssl_error(NGX_LOG_ERR, c->log, 0,
"SSL_use_certificate(\"%s\") failed", cert->data); "SSL_use_certificate(\"%s\") failed", cert->data);
@@ -621,7 +610,8 @@ ngx_ssl_connection_certificate(ngx_connection_t *c, ngx_pool_t *pool,
#endif #endif
pkey = ngx_ssl_load_certificate_key(pool, &err, key, passwords); pkey = ngx_ssl_cache_connection_fetch(pool, NGX_SSL_CACHE_PKEY, &err,
key, passwords);
if (pkey == NULL) { if (pkey == NULL) {
if (err != NULL) { if (err != NULL) {
ngx_ssl_error(NGX_LOG_ERR, c->log, 0, ngx_ssl_error(NGX_LOG_ERR, c->log, 0,
@@ -645,241 +635,6 @@ ngx_ssl_connection_certificate(ngx_connection_t *c, ngx_pool_t *pool,
} }
static X509 *
ngx_ssl_load_certificate(ngx_pool_t *pool, char **err, ngx_str_t *cert,
STACK_OF(X509) **chain)
{
BIO *bio;
X509 *x509, *temp;
u_long n;
if (ngx_strncmp(cert->data, "data:", sizeof("data:") - 1) == 0) {
bio = BIO_new_mem_buf(cert->data + sizeof("data:") - 1,
cert->len - (sizeof("data:") - 1));
if (bio == NULL) {
*err = "BIO_new_mem_buf() failed";
return NULL;
}
} else {
if (ngx_get_full_name(pool, (ngx_str_t *) &ngx_cycle->conf_prefix, cert)
!= NGX_OK)
{
*err = NULL;
return NULL;
}
bio = BIO_new_file((char *) cert->data, "r");
if (bio == NULL) {
*err = "BIO_new_file() failed";
return NULL;
}
}
/* certificate itself */
x509 = PEM_read_bio_X509_AUX(bio, NULL, NULL, NULL);
if (x509 == NULL) {
*err = "PEM_read_bio_X509_AUX() failed";
BIO_free(bio);
return NULL;
}
/* rest of the chain */
*chain = sk_X509_new_null();
if (*chain == NULL) {
*err = "sk_X509_new_null() failed";
BIO_free(bio);
X509_free(x509);
return NULL;
}
for ( ;; ) {
temp = PEM_read_bio_X509(bio, NULL, NULL, NULL);
if (temp == NULL) {
n = ERR_peek_last_error();
if (ERR_GET_LIB(n) == ERR_LIB_PEM
&& ERR_GET_REASON(n) == PEM_R_NO_START_LINE)
{
/* end of file */
ERR_clear_error();
break;
}
/* some real error */
*err = "PEM_read_bio_X509() failed";
BIO_free(bio);
X509_free(x509);
sk_X509_pop_free(*chain, X509_free);
return NULL;
}
if (sk_X509_push(*chain, temp) == 0) {
*err = "sk_X509_push() failed";
BIO_free(bio);
X509_free(x509);
sk_X509_pop_free(*chain, X509_free);
return NULL;
}
}
BIO_free(bio);
return x509;
}
static EVP_PKEY *
ngx_ssl_load_certificate_key(ngx_pool_t *pool, char **err,
ngx_str_t *key, ngx_array_t *passwords)
{
BIO *bio;
EVP_PKEY *pkey;
ngx_str_t *pwd;
ngx_uint_t tries;
pem_password_cb *cb;
if (ngx_strncmp(key->data, "engine:", sizeof("engine:") - 1) == 0) {
#ifndef OPENSSL_NO_ENGINE
u_char *p, *last;
ENGINE *engine;
p = key->data + sizeof("engine:") - 1;
last = (u_char *) ngx_strchr(p, ':');
if (last == NULL) {
*err = "invalid syntax";
return NULL;
}
*last = '\0';
engine = ENGINE_by_id((char *) p);
*last++ = ':';
if (engine == NULL) {
*err = "ENGINE_by_id() failed";
return NULL;
}
pkey = ENGINE_load_private_key(engine, (char *) last, 0, 0);
if (pkey == NULL) {
*err = "ENGINE_load_private_key() failed";
ENGINE_free(engine);
return NULL;
}
ENGINE_free(engine);
return pkey;
#else
*err = "loading \"engine:...\" certificate keys is not supported";
return NULL;
#endif
}
if (ngx_strncmp(key->data, "data:", sizeof("data:") - 1) == 0) {
bio = BIO_new_mem_buf(key->data + sizeof("data:") - 1,
key->len - (sizeof("data:") - 1));
if (bio == NULL) {
*err = "BIO_new_mem_buf() failed";
return NULL;
}
} else {
if (ngx_get_full_name(pool, (ngx_str_t *) &ngx_cycle->conf_prefix, key)
!= NGX_OK)
{
*err = NULL;
return NULL;
}
bio = BIO_new_file((char *) key->data, "r");
if (bio == NULL) {
*err = "BIO_new_file() failed";
return NULL;
}
}
if (passwords) {
tries = passwords->nelts;
pwd = passwords->elts;
cb = ngx_ssl_password_callback;
} else {
tries = 1;
pwd = NULL;
cb = NULL;
}
for ( ;; ) {
pkey = PEM_read_bio_PrivateKey(bio, NULL, cb, pwd);
if (pkey != NULL) {
break;
}
if (tries-- > 1) {
ERR_clear_error();
(void) BIO_reset(bio);
pwd++;
continue;
}
*err = "PEM_read_bio_PrivateKey() failed";
BIO_free(bio);
return NULL;
}
BIO_free(bio);
return pkey;
}
static int
ngx_ssl_password_callback(char *buf, int size, int rwflag, void *userdata)
{
ngx_str_t *pwd = userdata;
if (rwflag) {
ngx_log_error(NGX_LOG_ALERT, ngx_cycle->log, 0,
"ngx_ssl_password_callback() is called for encryption");
return 0;
}
if (pwd == NULL) {
return 0;
}
if (pwd->len > (size_t) size) {
ngx_log_error(NGX_LOG_ERR, ngx_cycle->log, 0,
"password is truncated to %d bytes", size);
} else {
size = pwd->len;
}
ngx_memcpy(buf, pwd->data, size);
return size;
}
ngx_int_t ngx_int_t
ngx_ssl_ciphers(ngx_conf_t *cf, ngx_ssl_t *ssl, ngx_str_t *ciphers, ngx_ssl_ciphers(ngx_conf_t *cf, ngx_ssl_t *ssl, ngx_str_t *ciphers,
ngx_uint_t prefer_server_ciphers) ngx_uint_t prefer_server_ciphers)
@@ -903,6 +658,12 @@ ngx_int_t
ngx_ssl_client_certificate(ngx_conf_t *cf, ngx_ssl_t *ssl, ngx_str_t *cert, ngx_ssl_client_certificate(ngx_conf_t *cf, ngx_ssl_t *ssl, ngx_str_t *cert,
ngx_int_t depth) ngx_int_t depth)
{ {
int n, i;
char *err;
X509 *x509;
X509_NAME *name;
X509_STORE *store;
STACK_OF(X509) *chain;
STACK_OF(X509_NAME) *list; STACK_OF(X509_NAME) *list;
SSL_CTX_set_verify(ssl->ctx, SSL_VERIFY_PEER, ngx_ssl_verify_callback); SSL_CTX_set_verify(ssl->ctx, SSL_VERIFY_PEER, ngx_ssl_verify_callback);
@@ -913,88 +674,8 @@ ngx_ssl_client_certificate(ngx_conf_t *cf, ngx_ssl_t *ssl, ngx_str_t *cert,
return NGX_OK; return NGX_OK;
} }
if (ngx_conf_full_name(cf->cycle, cert, 1) != NGX_OK) { list = sk_X509_NAME_new(ngx_ssl_cmp_x509_name);
return NGX_ERROR;
}
if (SSL_CTX_load_verify_locations(ssl->ctx, (char *) cert->data, NULL)
== 0)
{
ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0,
"SSL_CTX_load_verify_locations(\"%s\") failed",
cert->data);
return NGX_ERROR;
}
/*
* SSL_CTX_load_verify_locations() may leave errors in the error queue
* while returning success
*/
ERR_clear_error();
list = SSL_load_client_CA_file((char *) cert->data);
if (list == NULL) { if (list == NULL) {
ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0,
"SSL_load_client_CA_file(\"%s\") failed", cert->data);
return NGX_ERROR;
}
SSL_CTX_set_client_CA_list(ssl->ctx, list);
return NGX_OK;
}
ngx_int_t
ngx_ssl_trusted_certificate(ngx_conf_t *cf, ngx_ssl_t *ssl, ngx_str_t *cert,
ngx_int_t depth)
{
SSL_CTX_set_verify(ssl->ctx, SSL_CTX_get_verify_mode(ssl->ctx),
ngx_ssl_verify_callback);
SSL_CTX_set_verify_depth(ssl->ctx, depth);
if (cert->len == 0) {
return NGX_OK;
}
if (ngx_conf_full_name(cf->cycle, cert, 1) != NGX_OK) {
return NGX_ERROR;
}
if (SSL_CTX_load_verify_locations(ssl->ctx, (char *) cert->data, NULL)
== 0)
{
ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0,
"SSL_CTX_load_verify_locations(\"%s\") failed",
cert->data);
return NGX_ERROR;
}
/*
* SSL_CTX_load_verify_locations() may leave errors in the error queue
* while returning success
*/
ERR_clear_error();
return NGX_OK;
}
ngx_int_t
ngx_ssl_crl(ngx_conf_t *cf, ngx_ssl_t *ssl, ngx_str_t *crl)
{
X509_STORE *store;
X509_LOOKUP *lookup;
if (crl->len == 0) {
return NGX_OK;
}
if (ngx_conf_full_name(cf->cycle, crl, 1) != NGX_OK) {
return NGX_ERROR; return NGX_ERROR;
} }
@@ -1006,22 +687,190 @@ ngx_ssl_crl(ngx_conf_t *cf, ngx_ssl_t *ssl, ngx_str_t *crl)
return NGX_ERROR; return NGX_ERROR;
} }
lookup = X509_STORE_add_lookup(store, X509_LOOKUP_file()); chain = ngx_ssl_cache_fetch(cf, NGX_SSL_CACHE_CA, &err, cert, NULL);
if (chain == NULL) {
if (err != NULL) {
ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0,
"cannot load certificate \"%s\": %s",
cert->data, err);
}
if (lookup == NULL) { sk_X509_NAME_pop_free(list, X509_NAME_free);
ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0,
"X509_STORE_add_lookup() failed");
return NGX_ERROR; return NGX_ERROR;
} }
if (X509_LOOKUP_load_file(lookup, (char *) crl->data, X509_FILETYPE_PEM) n = sk_X509_num(chain);
== 0)
{ for (i = 0; i < n; i++) {
x509 = sk_X509_value(chain, i);
if (X509_STORE_add_cert(store, x509) != 1) {
if (ngx_ssl_cert_already_in_hash()) {
continue;
}
ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0,
"X509_STORE_add_cert(\"%s\") failed", cert->data);
sk_X509_NAME_pop_free(list, X509_NAME_free);
sk_X509_pop_free(chain, X509_free);
return NGX_ERROR;
}
name = X509_get_subject_name(x509);
if (name == NULL) {
ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0,
"X509_get_subject_name(\"%s\") failed", cert->data);
sk_X509_NAME_pop_free(list, X509_NAME_free);
sk_X509_pop_free(chain, X509_free);
return NGX_ERROR;
}
name = X509_NAME_dup(name);
if (name == NULL) {
sk_X509_NAME_pop_free(list, X509_NAME_free);
sk_X509_pop_free(chain, X509_free);
return NGX_ERROR;
}
#ifdef OPENSSL_IS_BORINGSSL
if (sk_X509_NAME_find(list, NULL, name) > 0) {
#else
if (sk_X509_NAME_find(list, name) >= 0) {
#endif
X509_NAME_free(name);
continue;
}
if (sk_X509_NAME_push(list, name) == 0) {
sk_X509_NAME_pop_free(list, X509_NAME_free);
sk_X509_pop_free(chain, X509_free);
X509_NAME_free(name);
return NGX_ERROR;
}
}
sk_X509_pop_free(chain, X509_free);
SSL_CTX_set_client_CA_list(ssl->ctx, list);
return NGX_OK;
}
ngx_int_t
ngx_ssl_trusted_certificate(ngx_conf_t *cf, ngx_ssl_t *ssl, ngx_str_t *cert,
ngx_int_t depth)
{
int i, n;
char *err;
X509 *x509;
X509_STORE *store;
STACK_OF(X509) *chain;
SSL_CTX_set_verify(ssl->ctx, SSL_CTX_get_verify_mode(ssl->ctx),
ngx_ssl_verify_callback);
SSL_CTX_set_verify_depth(ssl->ctx, depth);
if (cert->len == 0) {
return NGX_OK;
}
store = SSL_CTX_get_cert_store(ssl->ctx);
if (store == NULL) {
ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0, ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0,
"X509_LOOKUP_load_file(\"%s\") failed", crl->data); "SSL_CTX_get_cert_store() failed");
return NGX_ERROR; return NGX_ERROR;
} }
chain = ngx_ssl_cache_fetch(cf, NGX_SSL_CACHE_CA, &err, cert, NULL);
if (chain == NULL) {
if (err != NULL) {
ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0,
"cannot load certificate \"%s\": %s",
cert->data, err);
}
return NGX_ERROR;
}
n = sk_X509_num(chain);
for (i = 0; i < n; i++) {
x509 = sk_X509_value(chain, i);
if (X509_STORE_add_cert(store, x509) != 1) {
if (ngx_ssl_cert_already_in_hash()) {
continue;
}
ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0,
"X509_STORE_add_cert(\"%s\") failed", cert->data);
sk_X509_pop_free(chain, X509_free);
return NGX_ERROR;
}
}
sk_X509_pop_free(chain, X509_free);
return NGX_OK;
}
ngx_int_t
ngx_ssl_crl(ngx_conf_t *cf, ngx_ssl_t *ssl, ngx_str_t *crl)
{
int n, i;
char *err;
X509_CRL *x509;
X509_STORE *store;
STACK_OF(X509_CRL) *chain;
if (crl->len == 0) {
return NGX_OK;
}
store = SSL_CTX_get_cert_store(ssl->ctx);
if (store == NULL) {
ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0,
"SSL_CTX_get_cert_store() failed");
return NGX_ERROR;
}
chain = ngx_ssl_cache_fetch(cf, NGX_SSL_CACHE_CRL, &err, crl, NULL);
if (chain == NULL) {
if (err != NULL) {
ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0,
"cannot load CRL \"%s\": %s", crl->data, err);
}
return NGX_ERROR;
}
n = sk_X509_CRL_num(chain);
for (i = 0; i < n; i++) {
x509 = sk_X509_CRL_value(chain, i);
if (X509_STORE_add_crl(store, x509) != 1) {
if (ngx_ssl_cert_already_in_hash()) {
continue;
}
ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0,
"X509_STORE_add_crl(\"%s\") failed", crl->data);
sk_X509_CRL_pop_free(chain, X509_CRL_free);
return NGX_ERROR;
}
}
sk_X509_CRL_pop_free(chain, X509_CRL_free);
X509_STORE_set_flags(store, X509_STORE_set_flags(store,
X509_V_FLAG_CRL_CHECK|X509_V_FLAG_CRL_CHECK_ALL); X509_V_FLAG_CRL_CHECK|X509_V_FLAG_CRL_CHECK_ALL);
@@ -1029,6 +878,32 @@ ngx_ssl_crl(ngx_conf_t *cf, ngx_ssl_t *ssl, ngx_str_t *crl)
} }
static ngx_inline ngx_int_t
ngx_ssl_cert_already_in_hash(void)
{
#if !(OPENSSL_VERSION_NUMBER >= 0x1010009fL \
|| LIBRESSL_VERSION_NUMBER >= 0x3050000fL)
u_long error;
/*
* OpenSSL prior to 1.1.0i doesn't ignore duplicate certificate entries,
* see https://github.com/openssl/openssl/commit/c0452248
*/
error = ERR_peek_last_error();
if (ERR_GET_LIB(error) == ERR_LIB_X509
&& ERR_GET_REASON(error) == X509_R_CERT_ALREADY_IN_HASH_TABLE)
{
ERR_clear_error();
return 1;
}
#endif
return 0;
}
static int static int
ngx_ssl_verify_callback(int ok, X509_STORE_CTX *x509_store) ngx_ssl_verify_callback(int ok, X509_STORE_CTX *x509_store)
{ {
@@ -1195,6 +1070,13 @@ ngx_ssl_info_callback(const ngx_ssl_conn_t *ssl_conn, int where, int ret)
} }
static int
ngx_ssl_cmp_x509_name(const X509_NAME *const *a, const X509_NAME *const *b)
{
return (X509_NAME_cmp(*a, *b));
}
ngx_array_t * ngx_array_t *
ngx_ssl_read_password_file(ngx_conf_t *cf, ngx_str_t *file) ngx_ssl_read_password_file(ngx_conf_t *cf, ngx_str_t *file)
{ {
@@ -3859,10 +3741,9 @@ ngx_ssl_session_id_context(ngx_ssl_t *ssl, ngx_str_t *sess_ctx,
goto failed; goto failed;
} }
for (cert = SSL_CTX_get_ex_data(ssl->ctx, ngx_ssl_certificate_index); for (k = 0; k < ssl->certs.nelts; k++) {
cert; cert = ((X509 **) ssl->certs.elts)[k];
cert = X509_get_ex_data(cert, ngx_ssl_next_certificate_index))
{
if (X509_digest(cert, EVP_sha1(), buf, &len) == 0) { if (X509_digest(cert, EVP_sha1(), buf, &len) == 0) {
ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0, ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0,
"X509_digest() failed"); "X509_digest() failed");
@@ -3876,9 +3757,7 @@ ngx_ssl_session_id_context(ngx_ssl_t *ssl, ngx_str_t *sess_ctx,
} }
} }
if (SSL_CTX_get_ex_data(ssl->ctx, ngx_ssl_certificate_index) == NULL if (ssl->certs.nelts == 0 && certificates != NULL) {
&& certificates != NULL)
{
/* /*
* If certificates are loaded dynamically, we use certificate * If certificates are loaded dynamically, we use certificate
* names as specified in the configuration (with variables). * names as specified in the configuration (with variables).
@@ -4890,14 +4769,12 @@ ngx_ssl_cleanup_ctx(void *data)
{ {
ngx_ssl_t *ssl = data; ngx_ssl_t *ssl = data;
X509 *cert, *next; X509 *cert;
ngx_uint_t i;
cert = SSL_CTX_get_ex_data(ssl->ctx, ngx_ssl_certificate_index); for (i = 0; i < ssl->certs.nelts; i++) {
cert = ((X509 **) ssl->certs.elts)[i];
while (cert) {
next = X509_get_ex_data(cert, ngx_ssl_next_certificate_index);
X509_free(cert); X509_free(cert);
cert = next;
} }
SSL_CTX_free(ssl->ctx); SSL_CTX_free(ssl->ctx);
+18 -3
View File
@@ -98,6 +98,12 @@ struct ngx_ssl_s {
SSL_CTX *ctx; SSL_CTX *ctx;
ngx_log_t *log; ngx_log_t *log;
size_t buffer_size; size_t buffer_size;
ngx_array_t certs;
ngx_rbtree_t staple_rbtree;
ngx_rbtree_node_t staple_sentinel;
ngx_ssl_dyn_rec_t dyn_rec; ngx_ssl_dyn_rec_t dyn_rec;
}; };
@@ -201,6 +207,12 @@ typedef struct {
#define NGX_SSL_BUFSIZE 16384 #define NGX_SSL_BUFSIZE 16384
#define NGX_SSL_CACHE_CERT 0
#define NGX_SSL_CACHE_PKEY 1
#define NGX_SSL_CACHE_CRL 2
#define NGX_SSL_CACHE_CA 3
ngx_int_t ngx_ssl_init(ngx_log_t *log); ngx_int_t ngx_ssl_init(ngx_log_t *log);
ngx_int_t ngx_ssl_create(ngx_ssl_t *ssl, ngx_uint_t protocols, void *data); ngx_int_t ngx_ssl_create(ngx_ssl_t *ssl, ngx_uint_t protocols, void *data);
@@ -232,6 +244,11 @@ ngx_int_t ngx_ssl_ocsp_get_status(ngx_connection_t *c, const char **s);
void ngx_ssl_ocsp_cleanup(ngx_connection_t *c); void ngx_ssl_ocsp_cleanup(ngx_connection_t *c);
ngx_int_t ngx_ssl_ocsp_cache_init(ngx_shm_zone_t *shm_zone, void *data); ngx_int_t ngx_ssl_ocsp_cache_init(ngx_shm_zone_t *shm_zone, void *data);
void *ngx_ssl_cache_fetch(ngx_conf_t *cf, ngx_uint_t index, char **err,
ngx_str_t *path, void *data);
void *ngx_ssl_cache_connection_fetch(ngx_pool_t *pool, ngx_uint_t index,
char **err, ngx_str_t *path, void *data);
ngx_array_t *ngx_ssl_read_password_file(ngx_conf_t *cf, ngx_str_t *file); ngx_array_t *ngx_ssl_read_password_file(ngx_conf_t *cf, ngx_str_t *file);
ngx_array_t *ngx_ssl_preserve_passwords(ngx_conf_t *cf, ngx_array_t *ngx_ssl_preserve_passwords(ngx_conf_t *cf,
ngx_array_t *passwords); ngx_array_t *passwords);
@@ -343,10 +360,8 @@ extern int ngx_ssl_server_conf_index;
extern int ngx_ssl_session_cache_index; extern int ngx_ssl_session_cache_index;
extern int ngx_ssl_ticket_keys_index; extern int ngx_ssl_ticket_keys_index;
extern int ngx_ssl_ocsp_index; extern int ngx_ssl_ocsp_index;
extern int ngx_ssl_certificate_index; extern int ngx_ssl_index;
extern int ngx_ssl_next_certificate_index;
extern int ngx_ssl_certificate_name_index; extern int ngx_ssl_certificate_name_index;
extern int ngx_ssl_stapling_index;
#endif /* _NGX_EVENT_OPENSSL_H_INCLUDED_ */ #endif /* _NGX_EVENT_OPENSSL_H_INCLUDED_ */
+806
View File
@@ -0,0 +1,806 @@
/*
* Copyright (C) Nginx, Inc.
*/
#include <ngx_config.h>
#include <ngx_core.h>
#include <ngx_event.h>
#define NGX_SSL_CACHE_PATH 0
#define NGX_SSL_CACHE_DATA 1
#define NGX_SSL_CACHE_ENGINE 2
typedef struct {
unsigned type:2;
unsigned len:30;
u_char *data;
} ngx_ssl_cache_key_t;
typedef void *(*ngx_ssl_cache_create_pt)(ngx_ssl_cache_key_t *id, char **err,
void *data);
typedef void (*ngx_ssl_cache_free_pt)(void *data);
typedef void *(*ngx_ssl_cache_ref_pt)(char **err, void *data);
typedef struct {
ngx_ssl_cache_create_pt create;
ngx_ssl_cache_free_pt free;
ngx_ssl_cache_ref_pt ref;
} ngx_ssl_cache_type_t;
typedef struct {
ngx_rbtree_node_t node;
ngx_ssl_cache_key_t id;
ngx_ssl_cache_type_t *type;
void *value;
} ngx_ssl_cache_node_t;
typedef struct {
ngx_rbtree_t rbtree;
ngx_rbtree_node_t sentinel;
} ngx_ssl_cache_t;
static ngx_int_t ngx_ssl_cache_init_key(ngx_pool_t *pool, ngx_uint_t index,
ngx_str_t *path, ngx_ssl_cache_key_t *id);
static ngx_ssl_cache_node_t *ngx_ssl_cache_lookup(ngx_ssl_cache_t *cache,
ngx_ssl_cache_type_t *type, ngx_ssl_cache_key_t *id, uint32_t hash);
static void *ngx_ssl_cache_cert_create(ngx_ssl_cache_key_t *id, char **err,
void *data);
static void ngx_ssl_cache_cert_free(void *data);
static void *ngx_ssl_cache_cert_ref(char **err, void *data);
static void *ngx_ssl_cache_pkey_create(ngx_ssl_cache_key_t *id, char **err,
void *data);
static int ngx_ssl_cache_pkey_password_callback(char *buf, int size, int rwflag,
void *userdata);
static void ngx_ssl_cache_pkey_free(void *data);
static void *ngx_ssl_cache_pkey_ref(char **err, void *data);
static void *ngx_ssl_cache_crl_create(ngx_ssl_cache_key_t *id, char **err,
void *data);
static void ngx_ssl_cache_crl_free(void *data);
static void *ngx_ssl_cache_crl_ref(char **err, void *data);
static void *ngx_ssl_cache_ca_create(ngx_ssl_cache_key_t *id, char **err,
void *data);
static BIO *ngx_ssl_cache_create_bio(ngx_ssl_cache_key_t *id, char **err);
static void *ngx_openssl_cache_create_conf(ngx_cycle_t *cycle);
static void ngx_ssl_cache_cleanup(void *data);
static void ngx_ssl_cache_node_insert(ngx_rbtree_node_t *temp,
ngx_rbtree_node_t *node, ngx_rbtree_node_t *sentinel);
static ngx_core_module_t ngx_openssl_cache_module_ctx = {
ngx_string("openssl_cache"),
ngx_openssl_cache_create_conf,
NULL
};
ngx_module_t ngx_openssl_cache_module = {
NGX_MODULE_V1,
&ngx_openssl_cache_module_ctx, /* module context */
NULL, /* module directives */
NGX_CORE_MODULE, /* module type */
NULL, /* init master */
NULL, /* init module */
NULL, /* init process */
NULL, /* init thread */
NULL, /* exit thread */
NULL, /* exit process */
NULL, /* exit master */
NGX_MODULE_V1_PADDING
};
static ngx_ssl_cache_type_t ngx_ssl_cache_types[] = {
/* NGX_SSL_CACHE_CERT */
{ ngx_ssl_cache_cert_create,
ngx_ssl_cache_cert_free,
ngx_ssl_cache_cert_ref },
/* NGX_SSL_CACHE_PKEY */
{ ngx_ssl_cache_pkey_create,
ngx_ssl_cache_pkey_free,
ngx_ssl_cache_pkey_ref },
/* NGX_SSL_CACHE_CRL */
{ ngx_ssl_cache_crl_create,
ngx_ssl_cache_crl_free,
ngx_ssl_cache_crl_ref },
/* NGX_SSL_CACHE_CA */
{ ngx_ssl_cache_ca_create,
ngx_ssl_cache_cert_free,
ngx_ssl_cache_cert_ref }
};
void *
ngx_ssl_cache_fetch(ngx_conf_t *cf, ngx_uint_t index, char **err,
ngx_str_t *path, void *data)
{
uint32_t hash;
ngx_ssl_cache_t *cache;
ngx_ssl_cache_key_t id;
ngx_ssl_cache_type_t *type;
ngx_ssl_cache_node_t *cn;
if (ngx_ssl_cache_init_key(cf->pool, index, path, &id) != NGX_OK) {
return NULL;
}
cache = (ngx_ssl_cache_t *) ngx_get_conf(cf->cycle->conf_ctx,
ngx_openssl_cache_module);
type = &ngx_ssl_cache_types[index];
hash = ngx_murmur_hash2(id.data, id.len);
cn = ngx_ssl_cache_lookup(cache, type, &id, hash);
if (cn != NULL) {
return type->ref(err, cn->value);
}
cn = ngx_palloc(cf->pool, sizeof(ngx_ssl_cache_node_t) + id.len + 1);
if (cn == NULL) {
return NULL;
}
cn->node.key = hash;
cn->id.data = (u_char *)(cn + 1);
cn->id.len = id.len;
cn->id.type = id.type;
cn->type = type;
ngx_cpystrn(cn->id.data, id.data, id.len + 1);
cn->value = type->create(&id, err, data);
if (cn->value == NULL) {
return NULL;
}
ngx_rbtree_insert(&cache->rbtree, &cn->node);
return type->ref(err, cn->value);
}
void *
ngx_ssl_cache_connection_fetch(ngx_pool_t *pool, ngx_uint_t index, char **err,
ngx_str_t *path, void *data)
{
ngx_ssl_cache_key_t id;
if (ngx_ssl_cache_init_key(pool, index, path, &id) != NGX_OK) {
return NULL;
}
return ngx_ssl_cache_types[index].create(&id, err, data);
}
static ngx_int_t
ngx_ssl_cache_init_key(ngx_pool_t *pool, ngx_uint_t index, ngx_str_t *path,
ngx_ssl_cache_key_t *id)
{
if (index <= NGX_SSL_CACHE_PKEY
&& ngx_strncmp(path->data, "data:", sizeof("data:") - 1) == 0)
{
id->type = NGX_SSL_CACHE_DATA;
} else if (index == NGX_SSL_CACHE_PKEY
&& ngx_strncmp(path->data, "engine:", sizeof("engine:") - 1) == 0)
{
id->type = NGX_SSL_CACHE_ENGINE;
} else {
if (ngx_get_full_name(pool, (ngx_str_t *) &ngx_cycle->conf_prefix, path)
!= NGX_OK)
{
return NGX_ERROR;
}
id->type = NGX_SSL_CACHE_PATH;
}
id->len = path->len;
id->data = path->data;
return NGX_OK;
}
static ngx_ssl_cache_node_t *
ngx_ssl_cache_lookup(ngx_ssl_cache_t *cache, ngx_ssl_cache_type_t *type,
ngx_ssl_cache_key_t *id, uint32_t hash)
{
ngx_int_t rc;
ngx_rbtree_node_t *node, *sentinel;
ngx_ssl_cache_node_t *cn;
node = cache->rbtree.root;
sentinel = cache->rbtree.sentinel;
while (node != sentinel) {
if (hash < node->key) {
node = node->left;
continue;
}
if (hash > node->key) {
node = node->right;
continue;
}
/* hash == node->key */
cn = (ngx_ssl_cache_node_t *) node;
if (type < cn->type) {
node = node->left;
continue;
}
if (type > cn->type) {
node = node->right;
continue;
}
/* type == cn->type */
rc = ngx_memn2cmp(id->data, cn->id.data, id->len, cn->id.len);
if (rc == 0) {
return cn;
}
node = (rc < 0) ? node->left : node->right;
}
return NULL;
}
static void *
ngx_ssl_cache_cert_create(ngx_ssl_cache_key_t *id, char **err, void *data)
{
BIO *bio;
X509 *x509;
u_long n;
STACK_OF(X509) *chain;
chain = sk_X509_new_null();
if (chain == NULL) {
*err = "sk_X509_new_null() failed";
return NULL;
}
bio = ngx_ssl_cache_create_bio(id, err);
if (bio == NULL) {
sk_X509_pop_free(chain, X509_free);
return NULL;
}
/* certificate itself */
x509 = PEM_read_bio_X509_AUX(bio, NULL, NULL, NULL);
if (x509 == NULL) {
*err = "PEM_read_bio_X509_AUX() failed";
BIO_free(bio);
sk_X509_pop_free(chain, X509_free);
return NULL;
}
if (sk_X509_push(chain, x509) == 0) {
*err = "sk_X509_push() failed";
BIO_free(bio);
X509_free(x509);
sk_X509_pop_free(chain, X509_free);
return NULL;
}
/* rest of the chain */
for ( ;; ) {
x509 = PEM_read_bio_X509(bio, NULL, NULL, NULL);
if (x509 == NULL) {
n = ERR_peek_last_error();
if (ERR_GET_LIB(n) == ERR_LIB_PEM
&& ERR_GET_REASON(n) == PEM_R_NO_START_LINE)
{
/* end of file */
ERR_clear_error();
break;
}
/* some real error */
*err = "PEM_read_bio_X509() failed";
BIO_free(bio);
sk_X509_pop_free(chain, X509_free);
return NULL;
}
if (sk_X509_push(chain, x509) == 0) {
*err = "sk_X509_push() failed";
BIO_free(bio);
X509_free(x509);
sk_X509_pop_free(chain, X509_free);
return NULL;
}
}
BIO_free(bio);
return chain;
}
static void
ngx_ssl_cache_cert_free(void *data)
{
sk_X509_pop_free(data, X509_free);
}
static void *
ngx_ssl_cache_cert_ref(char **err, void *data)
{
int n, i;
X509 *x509;
STACK_OF(X509) *chain;
chain = sk_X509_dup(data);
if (chain == NULL) {
*err = "sk_X509_dup() failed";
return NULL;
}
n = sk_X509_num(chain);
for (i = 0; i < n; i++) {
x509 = sk_X509_value(chain, i);
#if (OPENSSL_VERSION_NUMBER >= 0x10100000L)
X509_up_ref(x509);
#else
CRYPTO_add(&x509->references, 1, CRYPTO_LOCK_X509);
#endif
}
return chain;
}
static void *
ngx_ssl_cache_pkey_create(ngx_ssl_cache_key_t *id, char **err, void *data)
{
ngx_array_t *passwords = data;
BIO *bio;
EVP_PKEY *pkey;
ngx_str_t *pwd;
ngx_uint_t tries;
pem_password_cb *cb;
if (id->type == NGX_SSL_CACHE_ENGINE) {
#ifndef OPENSSL_NO_ENGINE
u_char *p, *last;
ENGINE *engine;
p = id->data + sizeof("engine:") - 1;
last = (u_char *) ngx_strchr(p, ':');
if (last == NULL) {
*err = "invalid syntax";
return NULL;
}
*last = '\0';
engine = ENGINE_by_id((char *) p);
*last++ = ':';
if (engine == NULL) {
*err = "ENGINE_by_id() failed";
return NULL;
}
pkey = ENGINE_load_private_key(engine, (char *) last, 0, 0);
if (pkey == NULL) {
*err = "ENGINE_load_private_key() failed";
ENGINE_free(engine);
return NULL;
}
ENGINE_free(engine);
return pkey;
#else
*err = "loading \"engine:...\" certificate keys is not supported";
return NULL;
#endif
}
bio = ngx_ssl_cache_create_bio(id, err);
if (bio == NULL) {
return NULL;
}
if (passwords) {
tries = passwords->nelts;
pwd = passwords->elts;
cb = ngx_ssl_cache_pkey_password_callback;
} else {
tries = 1;
pwd = NULL;
cb = NULL;
}
for ( ;; ) {
pkey = PEM_read_bio_PrivateKey(bio, NULL, cb, pwd);
if (pkey != NULL) {
break;
}
if (tries-- > 1) {
ERR_clear_error();
(void) BIO_reset(bio);
pwd++;
continue;
}
*err = "PEM_read_bio_PrivateKey() failed";
BIO_free(bio);
return NULL;
}
BIO_free(bio);
return pkey;
}
static int
ngx_ssl_cache_pkey_password_callback(char *buf, int size, int rwflag,
void *userdata)
{
ngx_str_t *pwd = userdata;
if (rwflag) {
ngx_log_error(NGX_LOG_ALERT, ngx_cycle->log, 0,
"ngx_ssl_cache_pkey_password_callback() is called "
"for encryption");
return 0;
}
if (pwd == NULL) {
return 0;
}
if (pwd->len > (size_t) size) {
ngx_log_error(NGX_LOG_ERR, ngx_cycle->log, 0,
"password is truncated to %d bytes", size);
} else {
size = pwd->len;
}
ngx_memcpy(buf, pwd->data, size);
return size;
}
static void
ngx_ssl_cache_pkey_free(void *data)
{
EVP_PKEY_free(data);
}
static void *
ngx_ssl_cache_pkey_ref(char **err, void *data)
{
EVP_PKEY *pkey = data;
#if (OPENSSL_VERSION_NUMBER >= 0x10100000L)
EVP_PKEY_up_ref(pkey);
#else
CRYPTO_add(&pkey->references, 1, CRYPTO_LOCK_EVP_PKEY);
#endif
return data;
}
static void *
ngx_ssl_cache_crl_create(ngx_ssl_cache_key_t *id, char **err, void *data)
{
BIO *bio;
u_long n;
X509_CRL *x509;
STACK_OF(X509_CRL) *chain;
chain = sk_X509_CRL_new_null();
if (chain == NULL) {
*err = "sk_X509_CRL_new_null() failed";
return NULL;
}
bio = ngx_ssl_cache_create_bio(id, err);
if (bio == NULL) {
sk_X509_CRL_pop_free(chain, X509_CRL_free);
return NULL;
}
for ( ;; ) {
x509 = PEM_read_bio_X509_CRL(bio, NULL, NULL, NULL);
if (x509 == NULL) {
n = ERR_peek_last_error();
if (ERR_GET_LIB(n) == ERR_LIB_PEM
&& ERR_GET_REASON(n) == PEM_R_NO_START_LINE
&& sk_X509_CRL_num(chain) > 0)
{
/* end of file */
ERR_clear_error();
break;
}
/* some real error */
*err = "PEM_read_bio_X509_CRL() failed";
BIO_free(bio);
sk_X509_CRL_pop_free(chain, X509_CRL_free);
return NULL;
}
if (sk_X509_CRL_push(chain, x509) == 0) {
*err = "sk_X509_CRL_push() failed";
BIO_free(bio);
X509_CRL_free(x509);
sk_X509_CRL_pop_free(chain, X509_CRL_free);
return NULL;
}
}
BIO_free(bio);
return chain;
}
static void
ngx_ssl_cache_crl_free(void *data)
{
sk_X509_CRL_pop_free(data, X509_CRL_free);
}
static void *
ngx_ssl_cache_crl_ref(char **err, void *data)
{
int n, i;
X509_CRL *x509;
STACK_OF(X509_CRL) *chain;
chain = sk_X509_CRL_dup(data);
if (chain == NULL) {
*err = "sk_X509_CRL_dup() failed";
return NULL;
}
n = sk_X509_CRL_num(chain);
for (i = 0; i < n; i++) {
x509 = sk_X509_CRL_value(chain, i);
#if (OPENSSL_VERSION_NUMBER >= 0x10100000L)
X509_CRL_up_ref(x509);
#else
CRYPTO_add(&x509->references, 1, CRYPTO_LOCK_X509_CRL);
#endif
}
return chain;
}
static void *
ngx_ssl_cache_ca_create(ngx_ssl_cache_key_t *id, char **err, void *data)
{
BIO *bio;
X509 *x509;
u_long n;
STACK_OF(X509) *chain;
chain = sk_X509_new_null();
if (chain == NULL) {
*err = "sk_X509_new_null() failed";
return NULL;
}
bio = ngx_ssl_cache_create_bio(id, err);
if (bio == NULL) {
sk_X509_pop_free(chain, X509_free);
return NULL;
}
for ( ;; ) {
x509 = PEM_read_bio_X509_AUX(bio, NULL, NULL, NULL);
if (x509 == NULL) {
n = ERR_peek_last_error();
if (ERR_GET_LIB(n) == ERR_LIB_PEM
&& ERR_GET_REASON(n) == PEM_R_NO_START_LINE
&& sk_X509_num(chain) > 0)
{
/* end of file */
ERR_clear_error();
break;
}
/* some real error */
*err = "PEM_read_bio_X509_AUX() failed";
BIO_free(bio);
sk_X509_pop_free(chain, X509_free);
return NULL;
}
if (sk_X509_push(chain, x509) == 0) {
*err = "sk_X509_push() failed";
BIO_free(bio);
X509_free(x509);
sk_X509_pop_free(chain, X509_free);
return NULL;
}
}
BIO_free(bio);
return chain;
}
static BIO *
ngx_ssl_cache_create_bio(ngx_ssl_cache_key_t *id, char **err)
{
BIO *bio;
if (id->type == NGX_SSL_CACHE_DATA) {
bio = BIO_new_mem_buf(id->data + sizeof("data:") - 1,
id->len - (sizeof("data:") - 1));
if (bio == NULL) {
*err = "BIO_new_mem_buf() failed";
}
return bio;
}
bio = BIO_new_file((char *) id->data, "r");
if (bio == NULL) {
*err = "BIO_new_file() failed";
}
return bio;
}
static void *
ngx_openssl_cache_create_conf(ngx_cycle_t *cycle)
{
ngx_ssl_cache_t *cache;
ngx_pool_cleanup_t *cln;
cache = ngx_pcalloc(cycle->pool, sizeof(ngx_ssl_cache_t));
if (cache == NULL) {
return NULL;
}
cln = ngx_pool_cleanup_add(cycle->pool, 0);
if (cln == NULL) {
return NULL;
}
cln->handler = ngx_ssl_cache_cleanup;
cln->data = cache;
ngx_rbtree_init(&cache->rbtree, &cache->sentinel,
ngx_ssl_cache_node_insert);
return cache;
}
static void
ngx_ssl_cache_cleanup(void *data)
{
ngx_ssl_cache_t *cache = data;
ngx_rbtree_t *tree;
ngx_rbtree_node_t *node;
ngx_ssl_cache_node_t *cn;
tree = &cache->rbtree;
if (tree->root == tree->sentinel) {
return;
}
for (node = ngx_rbtree_min(tree->root, tree->sentinel);
node;
node = ngx_rbtree_next(tree, node))
{
cn = ngx_rbtree_data(node, ngx_ssl_cache_node_t, node);
cn->type->free(cn->value);
}
}
static void
ngx_ssl_cache_node_insert(ngx_rbtree_node_t *temp,
ngx_rbtree_node_t *node, ngx_rbtree_node_t *sentinel)
{
ngx_rbtree_node_t **p;
ngx_ssl_cache_node_t *n, *t;
for ( ;; ) {
n = ngx_rbtree_data(node, ngx_ssl_cache_node_t, node);
t = ngx_rbtree_data(temp, ngx_ssl_cache_node_t, node);
if (node->key != temp->key) {
p = (node->key < temp->key) ? &temp->left : &temp->right;
} else if (n->type != t->type) {
p = (n->type < t->type) ? &temp->left : &temp->right;
} else {
p = (ngx_memn2cmp(n->id.data, t->id.data, n->id.len, t->id.len)
< 0) ? &temp->left : &temp->right;
}
if (*p == sentinel) {
break;
}
temp = *p;
}
*p = node;
node->parent = temp;
node->left = sentinel;
node->right = sentinel;
ngx_rbt_red(node);
}
+56 -19
View File
@@ -15,6 +15,8 @@
typedef struct { typedef struct {
ngx_rbtree_node_t node;
ngx_str_t staple; ngx_str_t staple;
ngx_msec_t timeout; ngx_msec_t timeout;
@@ -154,6 +156,7 @@ static ngx_int_t ngx_ssl_stapling_responder(ngx_conf_t *cf, ngx_ssl_t *ssl,
static int ngx_ssl_certificate_status_callback(ngx_ssl_conn_t *ssl_conn, static int ngx_ssl_certificate_status_callback(ngx_ssl_conn_t *ssl_conn,
void *data); void *data);
static ngx_ssl_stapling_t *ngx_ssl_stapling_lookup(ngx_ssl_t *ssl, X509 *cert);
static void ngx_ssl_stapling_update(ngx_ssl_stapling_t *staple); static void ngx_ssl_stapling_update(ngx_ssl_stapling_t *staple);
static void ngx_ssl_stapling_ocsp_handler(ngx_ssl_ocsp_ctx_t *ctx); static void ngx_ssl_stapling_ocsp_handler(ngx_ssl_ocsp_ctx_t *ctx);
@@ -195,12 +198,12 @@ ngx_int_t
ngx_ssl_stapling(ngx_conf_t *cf, ngx_ssl_t *ssl, ngx_str_t *file, ngx_ssl_stapling(ngx_conf_t *cf, ngx_ssl_t *ssl, ngx_str_t *file,
ngx_str_t *responder, ngx_uint_t verify) ngx_str_t *responder, ngx_uint_t verify)
{ {
X509 *cert; X509 *cert;
ngx_uint_t k;
for (k = 0; k < ssl->certs.nelts; k++) {
cert = ((X509 **) ssl->certs.elts)[k];
for (cert = SSL_CTX_get_ex_data(ssl->ctx, ngx_ssl_certificate_index);
cert;
cert = X509_get_ex_data(cert, ngx_ssl_next_certificate_index))
{
if (ngx_ssl_stapling_certificate(cf, ssl, cert, file, responder, verify) if (ngx_ssl_stapling_certificate(cf, ssl, cert, file, responder, verify)
!= NGX_OK) != NGX_OK)
{ {
@@ -235,10 +238,9 @@ ngx_ssl_stapling_certificate(ngx_conf_t *cf, ngx_ssl_t *ssl, X509 *cert,
cln->handler = ngx_ssl_stapling_cleanup; cln->handler = ngx_ssl_stapling_cleanup;
cln->data = staple; cln->data = staple;
if (X509_set_ex_data(cert, ngx_ssl_stapling_index, staple) == 0) { staple->node.key = (ngx_rbtree_key_t) cert;
ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0, "X509_set_ex_data() failed");
return NGX_ERROR; ngx_rbtree_insert(&ssl->staple_rbtree, &staple->node);
}
#ifdef SSL_CTRL_SELECT_CURRENT_CERT #ifdef SSL_CTRL_SELECT_CURRENT_CERT
/* OpenSSL 1.0.2+ */ /* OpenSSL 1.0.2+ */
@@ -545,14 +547,21 @@ ngx_int_t
ngx_ssl_stapling_resolver(ngx_conf_t *cf, ngx_ssl_t *ssl, ngx_ssl_stapling_resolver(ngx_conf_t *cf, ngx_ssl_t *ssl,
ngx_resolver_t *resolver, ngx_msec_t resolver_timeout) ngx_resolver_t *resolver, ngx_msec_t resolver_timeout)
{ {
X509 *cert; ngx_rbtree_t *tree;
ngx_rbtree_node_t *node;
ngx_ssl_stapling_t *staple; ngx_ssl_stapling_t *staple;
for (cert = SSL_CTX_get_ex_data(ssl->ctx, ngx_ssl_certificate_index); tree = &ssl->staple_rbtree;
cert;
cert = X509_get_ex_data(cert, ngx_ssl_next_certificate_index)) if (tree->root == tree->sentinel) {
return NGX_OK;
}
for (node = ngx_rbtree_min(tree->root, tree->sentinel);
node;
node = ngx_rbtree_next(tree, node))
{ {
staple = X509_get_ex_data(cert, ngx_ssl_stapling_index); staple = ngx_rbtree_data(node, ngx_ssl_stapling_t, node);
staple->resolver = resolver; staple->resolver = resolver;
staple->resolver_timeout = resolver_timeout; staple->resolver_timeout = resolver_timeout;
} }
@@ -567,6 +576,8 @@ ngx_ssl_certificate_status_callback(ngx_ssl_conn_t *ssl_conn, void *data)
int rc; int rc;
X509 *cert; X509 *cert;
u_char *p; u_char *p;
SSL_CTX *ssl_ctx;
ngx_ssl_t *ssl;
ngx_connection_t *c; ngx_connection_t *c;
ngx_ssl_stapling_t *staple; ngx_ssl_stapling_t *staple;
@@ -583,7 +594,10 @@ ngx_ssl_certificate_status_callback(ngx_ssl_conn_t *ssl_conn, void *data)
return rc; return rc;
} }
staple = X509_get_ex_data(cert, ngx_ssl_stapling_index); ssl_ctx = SSL_get_SSL_CTX(ssl_conn);
ssl = SSL_CTX_get_ex_data(ssl_ctx, ngx_ssl_index);
staple = ngx_ssl_stapling_lookup(ssl, cert);
if (staple == NULL) { if (staple == NULL) {
return rc; return rc;
@@ -613,6 +627,30 @@ ngx_ssl_certificate_status_callback(ngx_ssl_conn_t *ssl_conn, void *data)
} }
static ngx_ssl_stapling_t *
ngx_ssl_stapling_lookup(ngx_ssl_t *ssl, X509 *cert)
{
ngx_rbtree_key_t key;
ngx_rbtree_node_t *node, *sentinel;
node = ssl->staple_rbtree.root;
sentinel = ssl->staple_rbtree.sentinel;
key = (ngx_rbtree_key_t) cert;
while (node != sentinel) {
if (key != node->key) {
node = (key < node->key) ? node->left : node->right;
continue;
}
return ngx_rbtree_data(node, ngx_ssl_stapling_t, node);
}
return NULL;
}
static void static void
ngx_ssl_stapling_update(ngx_ssl_stapling_t *staple) ngx_ssl_stapling_update(ngx_ssl_stapling_t *staple)
{ {
@@ -2717,12 +2755,11 @@ ngx_ssl_stapling(ngx_conf_t *cf, ngx_ssl_t *ssl, ngx_str_t *file,
ngx_str_t *responder, ngx_uint_t verify) ngx_str_t *responder, ngx_uint_t verify)
{ {
X509 *cert; X509 *cert;
ngx_uint_t k;
for (cert = SSL_CTX_get_ex_data(ssl->ctx, ngx_ssl_certificate_index); for (k = 0; k < ssl->certs.nelts; k++) {
cert;
cert = X509_get_ex_data(cert, ngx_ssl_next_certificate_index))
{
if (file->len) { if (file->len) {
cert = ((X509 **) ssl->certs.elts)[k];
if (ngx_ssl_stapling_file(cf, ssl, cert, file, responder, verify) if (ngx_ssl_stapling_file(cf, ssl, cert, file, responder, verify)
!= NGX_OK) != NGX_OK)
{ {
+1 -1
View File
@@ -25,6 +25,6 @@ clean:
@rm -f $(RESULT) *.o @rm -f $(RESULT) *.o
debug: $(PROGNAME).o debug: $(PROGNAME).o
llvm-objdump -S -no-show-raw-insn $< llvm-objdump -S --no-show-raw-insn $<
.DELETE_ON_ERROR: .DELETE_ON_ERROR: