Latest update - 7466
This commit is contained in:
+401
-149
@@ -18,6 +18,10 @@ typedef struct {
|
||||
} ngx_openssl_conf_t;
|
||||
|
||||
|
||||
static X509 *ngx_ssl_load_certificate(ngx_pool_t *pool, char **err,
|
||||
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);
|
||||
@@ -50,7 +54,7 @@ static void ngx_ssl_connection_error(ngx_connection_t *c, int sslerr,
|
||||
static void ngx_ssl_clear_error(ngx_log_t *log);
|
||||
|
||||
static ngx_int_t ngx_ssl_session_id_context(ngx_ssl_t *ssl,
|
||||
ngx_str_t *sess_ctx);
|
||||
ngx_str_t *sess_ctx, ngx_array_t *certificates);
|
||||
static int ngx_ssl_new_session(ngx_ssl_conn_t *ssl_conn,
|
||||
ngx_ssl_session_t *sess);
|
||||
static ngx_ssl_session_t *ngx_ssl_get_cached_session(ngx_ssl_conn_t *ssl_conn,
|
||||
@@ -415,16 +419,209 @@ ngx_int_t
|
||||
ngx_ssl_certificate(ngx_conf_t *cf, ngx_ssl_t *ssl, ngx_str_t *cert,
|
||||
ngx_str_t *key, ngx_array_t *passwords)
|
||||
{
|
||||
BIO *bio;
|
||||
X509 *x509;
|
||||
u_long n;
|
||||
ngx_str_t *pwd;
|
||||
ngx_uint_t tries;
|
||||
char *err;
|
||||
X509 *x509;
|
||||
EVP_PKEY *pkey;
|
||||
STACK_OF(X509) *chain;
|
||||
|
||||
x509 = ngx_ssl_load_certificate(cf->pool, &err, cert, &chain);
|
||||
if (x509 == NULL) {
|
||||
if (err != NULL) {
|
||||
ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0,
|
||||
"cannot load certificate \"%s\": %s",
|
||||
cert->data, err);
|
||||
}
|
||||
|
||||
if (ngx_conf_full_name(cf->cycle, cert, 1) != NGX_OK) {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
if (SSL_CTX_use_certificate(ssl->ctx, x509) == 0) {
|
||||
ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0,
|
||||
"SSL_CTX_use_certificate(\"%s\") failed", cert->data);
|
||||
X509_free(x509);
|
||||
sk_X509_pop_free(chain, X509_free);
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
if (X509_set_ex_data(x509, ngx_ssl_certificate_name_index, cert->data)
|
||||
== 0)
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
if (X509_set_ex_data(x509, ngx_ssl_next_certificate_index,
|
||||
SSL_CTX_get_ex_data(ssl->ctx, ngx_ssl_certificate_index))
|
||||
== 0)
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
if (SSL_CTX_set_ex_data(ssl->ctx, ngx_ssl_certificate_index, x509) == 0) {
|
||||
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
|
||||
* ngx_ssl_cleanup_ctx(). This is because we need to preserve all
|
||||
* certificates to be able to iterate all of them through exdata
|
||||
* (ngx_ssl_certificate_index, ngx_ssl_next_certificate_index),
|
||||
* while OpenSSL can free a certificate if it is replaced with another
|
||||
* certificate of the same type.
|
||||
*/
|
||||
|
||||
#ifdef SSL_CTX_set0_chain
|
||||
|
||||
if (SSL_CTX_set0_chain(ssl->ctx, chain) == 0) {
|
||||
ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0,
|
||||
"SSL_CTX_set0_chain(\"%s\") failed", cert->data);
|
||||
sk_X509_pop_free(chain, X509_free);
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
#else
|
||||
{
|
||||
int n;
|
||||
|
||||
/* SSL_CTX_set0_chain() is only available in OpenSSL 1.0.2+ */
|
||||
|
||||
n = sk_X509_num(chain);
|
||||
|
||||
while (n--) {
|
||||
x509 = sk_X509_shift(chain);
|
||||
|
||||
if (SSL_CTX_add_extra_chain_cert(ssl->ctx, x509) == 0) {
|
||||
ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0,
|
||||
"SSL_CTX_add_extra_chain_cert(\"%s\") failed",
|
||||
cert->data);
|
||||
sk_X509_pop_free(chain, X509_free);
|
||||
return NGX_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
sk_X509_free(chain);
|
||||
}
|
||||
#endif
|
||||
|
||||
pkey = ngx_ssl_load_certificate_key(cf->pool, &err, key, passwords);
|
||||
if (pkey == NULL) {
|
||||
if (err != NULL) {
|
||||
ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0,
|
||||
"cannot load certificate key \"%s\": %s",
|
||||
key->data, err);
|
||||
}
|
||||
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
if (SSL_CTX_use_PrivateKey(ssl->ctx, pkey) == 0) {
|
||||
ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0,
|
||||
"SSL_CTX_use_PrivateKey(\"%s\") failed", key->data);
|
||||
EVP_PKEY_free(pkey);
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
EVP_PKEY_free(pkey);
|
||||
|
||||
return NGX_OK;
|
||||
}
|
||||
|
||||
|
||||
ngx_int_t
|
||||
ngx_ssl_connection_certificate(ngx_connection_t *c, ngx_pool_t *pool,
|
||||
ngx_str_t *cert, ngx_str_t *key, ngx_array_t *passwords)
|
||||
{
|
||||
char *err;
|
||||
X509 *x509;
|
||||
EVP_PKEY *pkey;
|
||||
STACK_OF(X509) *chain;
|
||||
|
||||
x509 = ngx_ssl_load_certificate(pool, &err, cert, &chain);
|
||||
if (x509 == NULL) {
|
||||
if (err != NULL) {
|
||||
ngx_ssl_error(NGX_LOG_ERR, c->log, 0,
|
||||
"cannot load certificate \"%s\": %s",
|
||||
cert->data, err);
|
||||
}
|
||||
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
if (SSL_use_certificate(c->ssl->connection, x509) == 0) {
|
||||
ngx_ssl_error(NGX_LOG_ERR, c->log, 0,
|
||||
"SSL_use_certificate(\"%s\") failed", cert->data);
|
||||
X509_free(x509);
|
||||
sk_X509_pop_free(chain, X509_free);
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
X509_free(x509);
|
||||
|
||||
#ifdef SSL_set0_chain
|
||||
|
||||
/*
|
||||
* SSL_set0_chain() is only available in OpenSSL 1.0.2+,
|
||||
* but this function is only called via certificate callback,
|
||||
* which is only available in OpenSSL 1.0.2+ as well
|
||||
*/
|
||||
|
||||
if (SSL_set0_chain(c->ssl->connection, chain) == 0) {
|
||||
ngx_ssl_error(NGX_LOG_ERR, c->log, 0,
|
||||
"SSL_set0_chain(\"%s\") failed", cert->data);
|
||||
sk_X509_pop_free(chain, X509_free);
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
pkey = ngx_ssl_load_certificate_key(pool, &err, key, passwords);
|
||||
if (pkey == NULL) {
|
||||
if (err != NULL) {
|
||||
ngx_ssl_error(NGX_LOG_ERR, c->log, 0,
|
||||
"cannot load certificate key \"%s\": %s",
|
||||
key->data, err);
|
||||
}
|
||||
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
if (SSL_use_PrivateKey(c->ssl->connection, pkey) == 0) {
|
||||
ngx_ssl_error(NGX_LOG_ERR, c->log, 0,
|
||||
"SSL_use_PrivateKey(\"%s\") failed", key->data);
|
||||
EVP_PKEY_free(pkey);
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
EVP_PKEY_free(pkey);
|
||||
|
||||
return NGX_OK;
|
||||
}
|
||||
|
||||
|
||||
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_get_full_name(pool, (ngx_str_t *) &ngx_cycle->conf_prefix, cert)
|
||||
!= NGX_OK)
|
||||
{
|
||||
*err = NULL;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* we can't use SSL_CTX_use_certificate_chain_file() as it doesn't
|
||||
* allow to access certificate later from SSL_CTX, so we reimplement
|
||||
@@ -433,62 +630,33 @@ ngx_ssl_certificate(ngx_conf_t *cf, ngx_ssl_t *ssl, ngx_str_t *cert,
|
||||
|
||||
bio = BIO_new_file((char *) cert->data, "r");
|
||||
if (bio == NULL) {
|
||||
ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0,
|
||||
"BIO_new_file(\"%s\") failed", cert->data);
|
||||
return NGX_ERROR;
|
||||
*err = "BIO_new_file() failed";
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* certificate itself */
|
||||
|
||||
x509 = PEM_read_bio_X509_AUX(bio, NULL, NULL, NULL);
|
||||
if (x509 == NULL) {
|
||||
ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0,
|
||||
"PEM_read_bio_X509_AUX(\"%s\") failed", cert->data);
|
||||
*err = "PEM_read_bio_X509_AUX() failed";
|
||||
BIO_free(bio);
|
||||
return NGX_ERROR;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (SSL_CTX_use_certificate(ssl->ctx, x509) == 0) {
|
||||
ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0,
|
||||
"SSL_CTX_use_certificate(\"%s\") failed", cert->data);
|
||||
/* rest of the chain */
|
||||
|
||||
*chain = sk_X509_new_null();
|
||||
if (*chain == NULL) {
|
||||
*err = "sk_X509_new_null() failed";
|
||||
BIO_free(bio);
|
||||
X509_free(x509);
|
||||
BIO_free(bio);
|
||||
return NGX_ERROR;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (X509_set_ex_data(x509, ngx_ssl_certificate_name_index, cert->data)
|
||||
== 0)
|
||||
{
|
||||
ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0, "X509_set_ex_data() failed");
|
||||
X509_free(x509);
|
||||
BIO_free(bio);
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
if (X509_set_ex_data(x509, ngx_ssl_next_certificate_index,
|
||||
SSL_CTX_get_ex_data(ssl->ctx, ngx_ssl_certificate_index))
|
||||
== 0)
|
||||
{
|
||||
ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0, "X509_set_ex_data() failed");
|
||||
X509_free(x509);
|
||||
BIO_free(bio);
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
if (SSL_CTX_set_ex_data(ssl->ctx, ngx_ssl_certificate_index, x509)
|
||||
== 0)
|
||||
{
|
||||
ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0,
|
||||
"SSL_CTX_set_ex_data() failed");
|
||||
X509_free(x509);
|
||||
BIO_free(bio);
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
/* read rest of the chain */
|
||||
|
||||
for ( ;; ) {
|
||||
|
||||
x509 = PEM_read_bio_X509(bio, NULL, NULL, NULL);
|
||||
if (x509 == NULL) {
|
||||
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
|
||||
@@ -501,43 +669,38 @@ ngx_ssl_certificate(ngx_conf_t *cf, ngx_ssl_t *ssl, ngx_str_t *cert,
|
||||
|
||||
/* some real error */
|
||||
|
||||
ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0,
|
||||
"PEM_read_bio_X509(\"%s\") failed", cert->data);
|
||||
*err = "PEM_read_bio_X509() failed";
|
||||
BIO_free(bio);
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
#ifdef SSL_CTRL_CHAIN_CERT
|
||||
|
||||
/*
|
||||
* SSL_CTX_add0_chain_cert() is needed to add chain to
|
||||
* a particular certificate when multiple certificates are used;
|
||||
* only available in OpenSSL 1.0.2+
|
||||
*/
|
||||
|
||||
if (SSL_CTX_add0_chain_cert(ssl->ctx, x509) == 0) {
|
||||
ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0,
|
||||
"SSL_CTX_add0_chain_cert(\"%s\") failed",
|
||||
cert->data);
|
||||
X509_free(x509);
|
||||
BIO_free(bio);
|
||||
return NGX_ERROR;
|
||||
sk_X509_pop_free(*chain, X509_free);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#else
|
||||
if (SSL_CTX_add_extra_chain_cert(ssl->ctx, x509) == 0) {
|
||||
ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0,
|
||||
"SSL_CTX_add_extra_chain_cert(\"%s\") failed",
|
||||
cert->data);
|
||||
X509_free(x509);
|
||||
if (sk_X509_push(*chain, temp) == 0) {
|
||||
*err = "sk_X509_push() failed";
|
||||
BIO_free(bio);
|
||||
return NGX_ERROR;
|
||||
X509_free(x509);
|
||||
sk_X509_pop_free(*chain, X509_free);
|
||||
return NULL;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
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
|
||||
@@ -550,9 +713,8 @@ ngx_ssl_certificate(ngx_conf_t *cf, ngx_ssl_t *ssl, ngx_str_t *cert,
|
||||
last = (u_char *) ngx_strchr(p, ':');
|
||||
|
||||
if (last == NULL) {
|
||||
ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
|
||||
"invalid syntax in \"%V\"", key);
|
||||
return NGX_ERROR;
|
||||
*err = "invalid syntax";
|
||||
return NULL;
|
||||
}
|
||||
|
||||
*last = '\0';
|
||||
@@ -560,9 +722,8 @@ ngx_ssl_certificate(ngx_conf_t *cf, ngx_ssl_t *ssl, ngx_str_t *cert,
|
||||
engine = ENGINE_by_id((char *) p);
|
||||
|
||||
if (engine == NULL) {
|
||||
ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0,
|
||||
"ENGINE_by_id(\"%s\") failed", p);
|
||||
return NGX_ERROR;
|
||||
*err = "ENGINE_by_id() failed";
|
||||
return NULL;
|
||||
}
|
||||
|
||||
*last++ = ':';
|
||||
@@ -570,76 +731,69 @@ ngx_ssl_certificate(ngx_conf_t *cf, ngx_ssl_t *ssl, ngx_str_t *cert,
|
||||
pkey = ENGINE_load_private_key(engine, (char *) last, 0, 0);
|
||||
|
||||
if (pkey == NULL) {
|
||||
ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0,
|
||||
"ENGINE_load_private_key(\"%s\") failed", last);
|
||||
*err = "ENGINE_load_private_key() failed";
|
||||
ENGINE_free(engine);
|
||||
return NGX_ERROR;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ENGINE_free(engine);
|
||||
|
||||
if (SSL_CTX_use_PrivateKey(ssl->ctx, pkey) == 0) {
|
||||
ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0,
|
||||
"SSL_CTX_use_PrivateKey(\"%s\") failed", last);
|
||||
EVP_PKEY_free(pkey);
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
EVP_PKEY_free(pkey);
|
||||
|
||||
return NGX_OK;
|
||||
return pkey;
|
||||
|
||||
#else
|
||||
|
||||
ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
|
||||
"loading \"engine:...\" certificate keys "
|
||||
"is not supported");
|
||||
return NGX_ERROR;
|
||||
*err = "loading \"engine:...\" certificate keys is not supported";
|
||||
return NULL;
|
||||
|
||||
#endif
|
||||
}
|
||||
|
||||
if (ngx_conf_full_name(cf->cycle, key, 1) != NGX_OK) {
|
||||
return NGX_ERROR;
|
||||
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;
|
||||
|
||||
SSL_CTX_set_default_passwd_cb(ssl->ctx, ngx_ssl_password_callback);
|
||||
SSL_CTX_set_default_passwd_cb_userdata(ssl->ctx, pwd);
|
||||
cb = ngx_ssl_password_callback;
|
||||
|
||||
} else {
|
||||
tries = 1;
|
||||
#if (NGX_SUPPRESS_WARN)
|
||||
pwd = NULL;
|
||||
#endif
|
||||
cb = NULL;
|
||||
}
|
||||
|
||||
for ( ;; ) {
|
||||
|
||||
if (SSL_CTX_use_PrivateKey_file(ssl->ctx, (char *) key->data,
|
||||
SSL_FILETYPE_PEM)
|
||||
!= 0)
|
||||
{
|
||||
pkey = PEM_read_bio_PrivateKey(bio, NULL, cb, pwd);
|
||||
if (pkey != NULL) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (--tries) {
|
||||
if (tries-- > 1) {
|
||||
ERR_clear_error();
|
||||
SSL_CTX_set_default_passwd_cb_userdata(ssl->ctx, ++pwd);
|
||||
(void) BIO_reset(bio);
|
||||
pwd++;
|
||||
continue;
|
||||
}
|
||||
|
||||
ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0,
|
||||
"SSL_CTX_use_PrivateKey_file(\"%s\") failed", key->data);
|
||||
return NGX_ERROR;
|
||||
*err = "PEM_read_bio_PrivateKey() failed";
|
||||
BIO_free(bio);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
SSL_CTX_set_default_passwd_cb(ssl->ctx, NULL);
|
||||
BIO_free(bio);
|
||||
|
||||
return NGX_OK;
|
||||
return pkey;
|
||||
}
|
||||
|
||||
|
||||
@@ -654,6 +808,10 @@ ngx_ssl_password_callback(char *buf, int size, int rwflag, void *userdata)
|
||||
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);
|
||||
@@ -1069,6 +1227,69 @@ cleanup:
|
||||
}
|
||||
|
||||
|
||||
ngx_array_t *
|
||||
ngx_ssl_preserve_passwords(ngx_conf_t *cf, ngx_array_t *passwords)
|
||||
{
|
||||
ngx_str_t *opwd, *pwd;
|
||||
ngx_uint_t i;
|
||||
ngx_array_t *pwds;
|
||||
ngx_pool_cleanup_t *cln;
|
||||
static ngx_array_t empty_passwords;
|
||||
|
||||
if (passwords == NULL) {
|
||||
|
||||
/*
|
||||
* If there are no passwords, an empty array is used
|
||||
* to make sure OpenSSL's default password callback
|
||||
* won't block on reading from stdin.
|
||||
*/
|
||||
|
||||
return &empty_passwords;
|
||||
}
|
||||
|
||||
/*
|
||||
* Passwords are normally allocated from the temporary pool
|
||||
* and cleared after parsing configuration. To be used at
|
||||
* runtime they have to be copied to the configuration pool.
|
||||
*/
|
||||
|
||||
pwds = ngx_array_create(cf->pool, passwords->nelts, sizeof(ngx_str_t));
|
||||
if (pwds == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
cln = ngx_pool_cleanup_add(cf->pool, 0);
|
||||
if (cln == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
cln->handler = ngx_ssl_passwords_cleanup;
|
||||
cln->data = pwds;
|
||||
|
||||
opwd = passwords->elts;
|
||||
|
||||
for (i = 0; i < passwords->nelts; i++) {
|
||||
|
||||
pwd = ngx_array_push(pwds);
|
||||
if (pwd == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
pwd->len = opwd[i].len;
|
||||
pwd->data = ngx_pnalloc(cf->pool, pwd->len);
|
||||
|
||||
if (pwd->data == NULL) {
|
||||
pwds->nelts--;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ngx_memcpy(pwd->data, opwd[i].data, opwd[i].len);
|
||||
}
|
||||
|
||||
return pwds;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
ngx_ssl_passwords_cleanup(void *data)
|
||||
{
|
||||
@@ -2732,6 +2953,9 @@ ngx_ssl_connection_error(ngx_connection_t *c, int sslerr, ngx_err_t err,
|
||||
#ifdef SSL_R_INAPPROPRIATE_FALLBACK
|
||||
|| n == SSL_R_INAPPROPRIATE_FALLBACK /* 373 */
|
||||
#endif
|
||||
#ifdef SSL_R_CERT_CB_ERROR
|
||||
|| n == SSL_R_CERT_CB_ERROR /* 377 */
|
||||
#endif
|
||||
#ifdef SSL_R_VERSION_TOO_LOW
|
||||
|| n == SSL_R_VERSION_TOO_LOW /* 396 */
|
||||
#endif
|
||||
@@ -2811,53 +3035,60 @@ ngx_ssl_error(ngx_uint_t level, ngx_log_t *log, ngx_err_t err, char *fmt, ...)
|
||||
p = ngx_vslprintf(errstr, last - 1, fmt, args);
|
||||
va_end(args);
|
||||
|
||||
p = ngx_cpystrn(p, (u_char *) " (SSL:", last - p);
|
||||
if (ERR_peek_error()) {
|
||||
p = ngx_cpystrn(p, (u_char *) " (SSL:", last - p);
|
||||
|
||||
for ( ;; ) {
|
||||
for ( ;; ) {
|
||||
|
||||
n = ERR_peek_error_line_data(NULL, NULL, &data, &flags);
|
||||
n = ERR_peek_error_line_data(NULL, NULL, &data, &flags);
|
||||
|
||||
if (n == 0) {
|
||||
break;
|
||||
if (n == 0) {
|
||||
break;
|
||||
}
|
||||
|
||||
/* ERR_error_string_n() requires at least one byte */
|
||||
|
||||
if (p >= last - 1) {
|
||||
goto next;
|
||||
}
|
||||
|
||||
*p++ = ' ';
|
||||
|
||||
ERR_error_string_n(n, (char *) p, last - p);
|
||||
|
||||
while (p < last && *p) {
|
||||
p++;
|
||||
}
|
||||
|
||||
if (p < last && *data && (flags & ERR_TXT_STRING)) {
|
||||
*p++ = ':';
|
||||
p = ngx_cpystrn(p, (u_char *) data, last - p);
|
||||
}
|
||||
|
||||
next:
|
||||
|
||||
(void) ERR_get_error();
|
||||
}
|
||||
|
||||
/* ERR_error_string_n() requires at least one byte */
|
||||
|
||||
if (p >= last - 1) {
|
||||
goto next;
|
||||
if (p < last) {
|
||||
*p++ = ')';
|
||||
}
|
||||
|
||||
*p++ = ' ';
|
||||
|
||||
ERR_error_string_n(n, (char *) p, last - p);
|
||||
|
||||
while (p < last && *p) {
|
||||
p++;
|
||||
}
|
||||
|
||||
if (p < last && *data && (flags & ERR_TXT_STRING)) {
|
||||
*p++ = ':';
|
||||
p = ngx_cpystrn(p, (u_char *) data, last - p);
|
||||
}
|
||||
|
||||
next:
|
||||
|
||||
(void) ERR_get_error();
|
||||
}
|
||||
|
||||
ngx_log_error(level, log, err, "%*s)", p - errstr, errstr);
|
||||
ngx_log_error(level, log, err, "%*s", p - errstr, errstr);
|
||||
}
|
||||
|
||||
|
||||
ngx_int_t
|
||||
ngx_ssl_session_cache(ngx_ssl_t *ssl, ngx_str_t *sess_ctx,
|
||||
ssize_t builtin_session_cache, ngx_shm_zone_t *shm_zone, time_t timeout)
|
||||
ngx_array_t *certificates, ssize_t builtin_session_cache,
|
||||
ngx_shm_zone_t *shm_zone, time_t timeout)
|
||||
{
|
||||
long cache_mode;
|
||||
|
||||
SSL_CTX_set_timeout(ssl->ctx, (long) timeout);
|
||||
|
||||
if (ngx_ssl_session_id_context(ssl, sess_ctx) != NGX_OK) {
|
||||
if (ngx_ssl_session_id_context(ssl, sess_ctx, certificates) != NGX_OK) {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
@@ -2923,11 +3154,14 @@ ngx_ssl_session_cache(ngx_ssl_t *ssl, ngx_str_t *sess_ctx,
|
||||
|
||||
|
||||
static ngx_int_t
|
||||
ngx_ssl_session_id_context(ngx_ssl_t *ssl, ngx_str_t *sess_ctx)
|
||||
ngx_ssl_session_id_context(ngx_ssl_t *ssl, ngx_str_t *sess_ctx,
|
||||
ngx_array_t *certificates)
|
||||
{
|
||||
int n, i;
|
||||
X509 *cert;
|
||||
X509_NAME *name;
|
||||
ngx_str_t *certs;
|
||||
ngx_uint_t k;
|
||||
EVP_MD_CTX *md;
|
||||
unsigned int len;
|
||||
STACK_OF(X509_NAME) *list;
|
||||
@@ -2972,6 +3206,24 @@ 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 certificates are loaded dynamically, we use certificate
|
||||
* names as specified in the configuration (with variables).
|
||||
*/
|
||||
|
||||
certs = certificates->elts;
|
||||
for (k = 0; k < certificates->nelts; k++) {
|
||||
|
||||
if (EVP_DigestUpdate(md, certs[k].data, certs[k].len) == 0) {
|
||||
ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0,
|
||||
"EVP_DigestUpdate() failed");
|
||||
goto failed;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
list = SSL_CTX_get_client_CA_list(ssl->ctx);
|
||||
|
||||
if (list != NULL) {
|
||||
|
||||
@@ -174,10 +174,14 @@ typedef struct {
|
||||
|
||||
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_certificates(ngx_conf_t *cf, ngx_ssl_t *ssl,
|
||||
ngx_array_t *certs, ngx_array_t *keys, ngx_array_t *passwords);
|
||||
ngx_int_t ngx_ssl_certificate(ngx_conf_t *cf, ngx_ssl_t *ssl,
|
||||
ngx_str_t *cert, ngx_str_t *key, ngx_array_t *passwords);
|
||||
ngx_int_t ngx_ssl_connection_certificate(ngx_connection_t *c, ngx_pool_t *pool,
|
||||
ngx_str_t *cert, ngx_str_t *key, ngx_array_t *passwords);
|
||||
|
||||
ngx_int_t ngx_ssl_ciphers(ngx_conf_t *cf, ngx_ssl_t *ssl, ngx_str_t *ciphers,
|
||||
ngx_uint_t prefer_server_ciphers);
|
||||
ngx_int_t ngx_ssl_client_certificate(ngx_conf_t *cf, ngx_ssl_t *ssl,
|
||||
@@ -192,6 +196,8 @@ ngx_int_t ngx_ssl_stapling_resolver(ngx_conf_t *cf, ngx_ssl_t *ssl,
|
||||
RSA *ngx_ssl_rsa512_key_callback(ngx_ssl_conn_t *ssl_conn, int is_export,
|
||||
int key_length);
|
||||
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 *passwords);
|
||||
ngx_int_t ngx_ssl_dhparam(ngx_conf_t *cf, ngx_ssl_t *ssl, ngx_str_t *file);
|
||||
ngx_int_t ngx_ssl_ecdh_curve(ngx_conf_t *cf, ngx_ssl_t *ssl, ngx_str_t *name);
|
||||
ngx_int_t ngx_ssl_early_data(ngx_conf_t *cf, ngx_ssl_t *ssl,
|
||||
@@ -199,7 +205,8 @@ ngx_int_t ngx_ssl_early_data(ngx_conf_t *cf, ngx_ssl_t *ssl,
|
||||
ngx_int_t ngx_ssl_client_session_cache(ngx_conf_t *cf, ngx_ssl_t *ssl,
|
||||
ngx_uint_t enable);
|
||||
ngx_int_t ngx_ssl_session_cache(ngx_ssl_t *ssl, ngx_str_t *sess_ctx,
|
||||
ssize_t builtin_session_cache, ngx_shm_zone_t *shm_zone, time_t timeout);
|
||||
ngx_array_t *certificates, ssize_t builtin_session_cache,
|
||||
ngx_shm_zone_t *shm_zone, time_t timeout);
|
||||
ngx_int_t ngx_ssl_session_ticket_keys(ngx_conf_t *cf, ngx_ssl_t *ssl,
|
||||
ngx_array_t *paths);
|
||||
ngx_int_t ngx_ssl_session_cache_init(ngx_shm_zone_t *shm_zone, void *data);
|
||||
|
||||
@@ -41,6 +41,9 @@ static void *ngx_http_ssl_create_srv_conf(ngx_conf_t *cf);
|
||||
static char *ngx_http_ssl_merge_srv_conf(ngx_conf_t *cf,
|
||||
void *parent, void *child);
|
||||
|
||||
static ngx_int_t ngx_http_ssl_compile_certificates(ngx_conf_t *cf,
|
||||
ngx_http_ssl_srv_conf_t *conf);
|
||||
|
||||
static char *ngx_http_ssl_enable(ngx_conf_t *cf, ngx_command_t *cmd,
|
||||
void *conf);
|
||||
static char *ngx_http_ssl_password_file(ngx_conf_t *cf, ngx_command_t *cmd,
|
||||
@@ -585,6 +588,7 @@ ngx_http_ssl_create_srv_conf(ngx_conf_t *cf)
|
||||
* set by ngx_pcalloc():
|
||||
*
|
||||
* sscf->protocols = 0;
|
||||
* sscf->certificate_values = NULL;
|
||||
* sscf->dhparam = { 0, NULL };
|
||||
* sscf->ecdh_curve = { 0, NULL };
|
||||
* sscf->client_certificate = { 0, NULL };
|
||||
@@ -781,13 +785,38 @@ ngx_http_ssl_merge_srv_conf(ngx_conf_t *cf, void *parent, void *child)
|
||||
cln->handler = ngx_ssl_cleanup_ctx;
|
||||
cln->data = &conf->ssl;
|
||||
|
||||
if (ngx_ssl_certificates(cf, &conf->ssl, conf->certificates,
|
||||
conf->certificate_keys, conf->passwords)
|
||||
!= NGX_OK)
|
||||
{
|
||||
if (ngx_http_ssl_compile_certificates(cf, conf) != NGX_OK) {
|
||||
return NGX_CONF_ERROR;
|
||||
}
|
||||
|
||||
if (conf->certificate_values) {
|
||||
|
||||
#ifdef SSL_R_CERT_CB_ERROR
|
||||
|
||||
/* install callback to lookup certificates */
|
||||
|
||||
SSL_CTX_set_cert_cb(conf->ssl.ctx, ngx_http_ssl_certificate, conf);
|
||||
|
||||
#else
|
||||
ngx_log_error(NGX_LOG_EMERG, cf->log, 0,
|
||||
"variables in "
|
||||
"\"ssl_certificate\" and \"ssl_certificate_key\" "
|
||||
"directives are not supported on this platform");
|
||||
return NGX_CONF_ERROR;
|
||||
#endif
|
||||
|
||||
} else {
|
||||
|
||||
/* configure certificates */
|
||||
|
||||
if (ngx_ssl_certificates(cf, &conf->ssl, conf->certificates,
|
||||
conf->certificate_keys, conf->passwords)
|
||||
!= NGX_OK)
|
||||
{
|
||||
return NGX_CONF_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
if (ngx_ssl_ciphers(cf, &conf->ssl, &conf->ciphers,
|
||||
conf->prefer_server_ciphers)
|
||||
!= NGX_OK)
|
||||
@@ -842,7 +871,7 @@ ngx_http_ssl_merge_srv_conf(ngx_conf_t *cf, void *parent, void *child)
|
||||
}
|
||||
|
||||
if (ngx_ssl_session_cache(&conf->ssl, &ngx_http_ssl_sess_id_ctx,
|
||||
conf->builtin_session_cache,
|
||||
conf->certificates, conf->builtin_session_cache,
|
||||
conf->shm_zone, conf->session_timeout)
|
||||
!= NGX_OK)
|
||||
{
|
||||
@@ -907,6 +936,90 @@ ngx_http_ssl_merge_srv_conf(ngx_conf_t *cf, void *parent, void *child)
|
||||
}
|
||||
|
||||
|
||||
static ngx_int_t
|
||||
ngx_http_ssl_compile_certificates(ngx_conf_t *cf,
|
||||
ngx_http_ssl_srv_conf_t *conf)
|
||||
{
|
||||
ngx_str_t *cert, *key;
|
||||
ngx_uint_t i, nelts;
|
||||
ngx_http_complex_value_t *cv;
|
||||
ngx_http_compile_complex_value_t ccv;
|
||||
|
||||
cert = conf->certificates->elts;
|
||||
key = conf->certificate_keys->elts;
|
||||
nelts = conf->certificates->nelts;
|
||||
|
||||
for (i = 0; i < nelts; i++) {
|
||||
|
||||
if (ngx_http_script_variables_count(&cert[i])) {
|
||||
goto found;
|
||||
}
|
||||
|
||||
if (ngx_http_script_variables_count(&key[i])) {
|
||||
goto found;
|
||||
}
|
||||
}
|
||||
|
||||
return NGX_OK;
|
||||
|
||||
found:
|
||||
|
||||
conf->certificate_values = ngx_array_create(cf->pool, nelts,
|
||||
sizeof(ngx_http_complex_value_t));
|
||||
if (conf->certificate_values == NULL) {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
conf->certificate_key_values = ngx_array_create(cf->pool, nelts,
|
||||
sizeof(ngx_http_complex_value_t));
|
||||
if (conf->certificate_key_values == NULL) {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
for (i = 0; i < nelts; i++) {
|
||||
|
||||
cv = ngx_array_push(conf->certificate_values);
|
||||
if (cv == NULL) {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
ngx_memzero(&ccv, sizeof(ngx_http_compile_complex_value_t));
|
||||
|
||||
ccv.cf = cf;
|
||||
ccv.value = &cert[i];
|
||||
ccv.complex_value = cv;
|
||||
ccv.zero = 1;
|
||||
|
||||
if (ngx_http_compile_complex_value(&ccv) != NGX_OK) {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
cv = ngx_array_push(conf->certificate_key_values);
|
||||
if (cv == NULL) {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
ngx_memzero(&ccv, sizeof(ngx_http_compile_complex_value_t));
|
||||
|
||||
ccv.cf = cf;
|
||||
ccv.value = &key[i];
|
||||
ccv.complex_value = cv;
|
||||
ccv.zero = 1;
|
||||
|
||||
if (ngx_http_compile_complex_value(&ccv) != NGX_OK) {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
conf->passwords = ngx_ssl_preserve_passwords(cf, conf->passwords);
|
||||
if (conf->passwords == NULL) {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
return NGX_OK;
|
||||
}
|
||||
|
||||
|
||||
static char *
|
||||
ngx_http_ssl_enable(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
|
||||
{
|
||||
|
||||
@@ -36,6 +36,9 @@ typedef struct {
|
||||
ngx_array_t *certificates;
|
||||
ngx_array_t *certificate_keys;
|
||||
|
||||
ngx_array_t *certificate_values;
|
||||
ngx_array_t *certificate_key_values;
|
||||
|
||||
ngx_str_t dhparam;
|
||||
ngx_str_t ecdh_curve;
|
||||
ngx_str_t client_certificate;
|
||||
|
||||
@@ -88,6 +88,10 @@ void ngx_http_close_connection(ngx_connection_t *c);
|
||||
#if (NGX_HTTP_SSL && defined SSL_CTRL_SET_TLSEXT_HOSTNAME)
|
||||
int ngx_http_ssl_servername(ngx_ssl_conn_t *ssl_conn, int *ad, void *arg);
|
||||
#endif
|
||||
#if (NGX_HTTP_SSL && defined SSL_R_CERT_CB_ERROR)
|
||||
int ngx_http_ssl_certificate(ngx_ssl_conn_t *ssl_conn, void *arg);
|
||||
#endif
|
||||
|
||||
|
||||
ngx_int_t ngx_http_parse_request_line(ngx_http_request_t *r, ngx_buf_t *b);
|
||||
ngx_int_t ngx_http_parse_uri(ngx_http_request_t *r);
|
||||
|
||||
+107
-19
@@ -11,6 +11,7 @@
|
||||
|
||||
|
||||
static void ngx_http_wait_request_handler(ngx_event_t *ev);
|
||||
static ngx_http_request_t *ngx_http_alloc_request(ngx_connection_t *c);
|
||||
static void ngx_http_process_request_line(ngx_event_t *rev);
|
||||
static void ngx_http_process_request_headers(ngx_event_t *rev);
|
||||
static ssize_t ngx_http_read_request_header(ngx_http_request_t *r);
|
||||
@@ -502,18 +503,46 @@ ngx_http_wait_request_handler(ngx_event_t *rev)
|
||||
|
||||
ngx_http_request_t *
|
||||
ngx_http_create_request(ngx_connection_t *c)
|
||||
{
|
||||
ngx_http_request_t *r;
|
||||
ngx_http_log_ctx_t *ctx;
|
||||
ngx_http_core_loc_conf_t *clcf;
|
||||
|
||||
r = ngx_http_alloc_request(c);
|
||||
if (r == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
c->requests++;
|
||||
|
||||
clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);
|
||||
|
||||
ngx_set_connection_log(c, clcf->error_log);
|
||||
|
||||
ctx = c->log->data;
|
||||
ctx->request = r;
|
||||
ctx->current_request = r;
|
||||
|
||||
#if (NGX_STAT_STUB)
|
||||
(void) ngx_atomic_fetch_add(ngx_stat_reading, 1);
|
||||
r->stat_reading = 1;
|
||||
(void) ngx_atomic_fetch_add(ngx_stat_requests, 1);
|
||||
#endif
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
|
||||
static ngx_http_request_t *
|
||||
ngx_http_alloc_request(ngx_connection_t *c)
|
||||
{
|
||||
ngx_pool_t *pool;
|
||||
ngx_time_t *tp;
|
||||
ngx_http_request_t *r;
|
||||
ngx_http_log_ctx_t *ctx;
|
||||
ngx_http_connection_t *hc;
|
||||
ngx_http_core_srv_conf_t *cscf;
|
||||
ngx_http_core_loc_conf_t *clcf;
|
||||
ngx_http_core_main_conf_t *cmcf;
|
||||
|
||||
c->requests++;
|
||||
|
||||
hc = c->data;
|
||||
|
||||
cscf = ngx_http_get_module_srv_conf(hc->conf_ctx, ngx_http_core_module);
|
||||
@@ -541,10 +570,6 @@ ngx_http_create_request(ngx_connection_t *c)
|
||||
|
||||
r->read_event_handler = ngx_http_block_reading;
|
||||
|
||||
clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);
|
||||
|
||||
ngx_set_connection_log(r->connection, clcf->error_log);
|
||||
|
||||
r->header_in = hc->busy ? hc->busy->buf : c->buffer;
|
||||
|
||||
if (ngx_list_init(&r->headers_out.headers, r->pool, 20,
|
||||
@@ -604,17 +629,8 @@ ngx_http_create_request(ngx_connection_t *c)
|
||||
|
||||
r->http_state = NGX_HTTP_READING_REQUEST_STATE;
|
||||
|
||||
ctx = c->log->data;
|
||||
ctx->request = r;
|
||||
ctx->current_request = r;
|
||||
r->log_handler = ngx_http_log_error_handler;
|
||||
|
||||
#if (NGX_STAT_STUB)
|
||||
(void) ngx_atomic_fetch_add(ngx_stat_reading, 1);
|
||||
r->stat_reading = 1;
|
||||
(void) ngx_atomic_fetch_add(ngx_stat_requests, 1);
|
||||
#endif
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
@@ -833,6 +849,7 @@ ngx_http_ssl_handshake_handler(ngx_connection_t *c)
|
||||
ngx_http_close_connection(c);
|
||||
}
|
||||
|
||||
|
||||
#ifdef SSL_CTRL_SET_TLSEXT_HOSTNAME
|
||||
|
||||
int
|
||||
@@ -930,6 +947,75 @@ ngx_http_ssl_servername(ngx_ssl_conn_t *ssl_conn, int *ad, void *arg)
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef SSL_R_CERT_CB_ERROR
|
||||
|
||||
int
|
||||
ngx_http_ssl_certificate(ngx_ssl_conn_t *ssl_conn, void *arg)
|
||||
{
|
||||
ngx_str_t cert, key;
|
||||
ngx_uint_t i, nelts;
|
||||
ngx_connection_t *c;
|
||||
ngx_http_request_t *r;
|
||||
ngx_http_ssl_srv_conf_t *sscf;
|
||||
ngx_http_complex_value_t *certs, *keys;
|
||||
|
||||
c = ngx_ssl_get_connection(ssl_conn);
|
||||
|
||||
if (c->ssl->handshaked) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
r = ngx_http_alloc_request(c);
|
||||
if (r == NULL) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
r->logged = 1;
|
||||
|
||||
sscf = arg;
|
||||
|
||||
nelts = sscf->certificate_values->nelts;
|
||||
certs = sscf->certificate_values->elts;
|
||||
keys = sscf->certificate_key_values->elts;
|
||||
|
||||
for (i = 0; i < nelts; i++) {
|
||||
|
||||
if (ngx_http_complex_value(r, &certs[i], &cert) != NGX_OK) {
|
||||
goto failed;
|
||||
}
|
||||
|
||||
ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->log, 0,
|
||||
"ssl cert: \"%s\"", cert.data);
|
||||
|
||||
if (ngx_http_complex_value(r, &keys[i], &key) != NGX_OK) {
|
||||
goto failed;
|
||||
}
|
||||
|
||||
ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->log, 0,
|
||||
"ssl key: \"%s\"", key.data);
|
||||
|
||||
if (ngx_ssl_connection_certificate(c, r->pool, &cert, &key,
|
||||
sscf->passwords)
|
||||
!= NGX_OK)
|
||||
{
|
||||
goto failed;
|
||||
}
|
||||
}
|
||||
|
||||
ngx_http_free_request(r, 0);
|
||||
c->destroyed = 0;
|
||||
return 1;
|
||||
|
||||
failed:
|
||||
|
||||
ngx_http_free_request(r, 0);
|
||||
c->destroyed = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
@@ -3523,9 +3609,11 @@ ngx_http_free_request(ngx_http_request_t *r, ngx_int_t rc)
|
||||
r->headers_out.status = rc;
|
||||
}
|
||||
|
||||
log->action = "logging request";
|
||||
if (!r->logged) {
|
||||
log->action = "logging request";
|
||||
|
||||
ngx_http_log_request(r);
|
||||
ngx_http_log_request(r);
|
||||
}
|
||||
|
||||
log->action = "closing request";
|
||||
|
||||
|
||||
@@ -435,7 +435,7 @@ ngx_mail_ssl_merge_conf(ngx_conf_t *cf, void *parent, void *child)
|
||||
}
|
||||
|
||||
if (ngx_ssl_session_cache(&conf->ssl, &ngx_mail_ssl_sess_id_ctx,
|
||||
conf->builtin_session_cache,
|
||||
conf->certificates, conf->builtin_session_cache,
|
||||
conf->shm_zone, conf->session_timeout)
|
||||
!= NGX_OK)
|
||||
{
|
||||
|
||||
@@ -22,6 +22,9 @@ static ngx_int_t ngx_stream_ssl_handler(ngx_stream_session_t *s);
|
||||
static ngx_int_t ngx_stream_ssl_init_connection(ngx_ssl_t *ssl,
|
||||
ngx_connection_t *c);
|
||||
static void ngx_stream_ssl_handshake_handler(ngx_connection_t *c);
|
||||
#ifdef SSL_R_CERT_CB_ERROR
|
||||
static int ngx_stream_ssl_certificate(ngx_ssl_conn_t *ssl_conn, void *arg);
|
||||
#endif
|
||||
static ngx_int_t ngx_stream_ssl_static_variable(ngx_stream_session_t *s,
|
||||
ngx_stream_variable_value_t *v, uintptr_t data);
|
||||
static ngx_int_t ngx_stream_ssl_variable(ngx_stream_session_t *s,
|
||||
@@ -32,6 +35,9 @@ static void *ngx_stream_ssl_create_conf(ngx_conf_t *cf);
|
||||
static char *ngx_stream_ssl_merge_conf(ngx_conf_t *cf, void *parent,
|
||||
void *child);
|
||||
|
||||
static ngx_int_t ngx_stream_ssl_compile_certificates(ngx_conf_t *cf,
|
||||
ngx_stream_ssl_conf_t *conf);
|
||||
|
||||
static char *ngx_stream_ssl_password_file(ngx_conf_t *cf, ngx_command_t *cmd,
|
||||
void *conf);
|
||||
static char *ngx_stream_ssl_session_cache(ngx_conf_t *cf, ngx_command_t *cmd,
|
||||
@@ -408,6 +414,62 @@ ngx_stream_ssl_handshake_handler(ngx_connection_t *c)
|
||||
}
|
||||
|
||||
|
||||
#ifdef SSL_R_CERT_CB_ERROR
|
||||
|
||||
int
|
||||
ngx_stream_ssl_certificate(ngx_ssl_conn_t *ssl_conn, void *arg)
|
||||
{
|
||||
ngx_str_t cert, key;
|
||||
ngx_uint_t i, nelts;
|
||||
ngx_connection_t *c;
|
||||
ngx_stream_session_t *s;
|
||||
ngx_stream_ssl_conf_t *sslcf;
|
||||
ngx_stream_complex_value_t *certs, *keys;
|
||||
|
||||
c = ngx_ssl_get_connection(ssl_conn);
|
||||
|
||||
if (c->ssl->handshaked) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
s = c->data;
|
||||
|
||||
sslcf = arg;
|
||||
|
||||
nelts = sslcf->certificate_values->nelts;
|
||||
certs = sslcf->certificate_values->elts;
|
||||
keys = sslcf->certificate_key_values->elts;
|
||||
|
||||
for (i = 0; i < nelts; i++) {
|
||||
|
||||
if (ngx_stream_complex_value(s, &certs[i], &cert) != NGX_OK) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
ngx_log_debug1(NGX_LOG_DEBUG_STREAM, c->log, 0,
|
||||
"ssl cert: \"%s\"", cert.data);
|
||||
|
||||
if (ngx_stream_complex_value(s, &keys[i], &key) != NGX_OK) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
ngx_log_debug1(NGX_LOG_DEBUG_STREAM, c->log, 0,
|
||||
"ssl key: \"%s\"", key.data);
|
||||
|
||||
if (ngx_ssl_connection_certificate(c, c->pool, &cert, &key,
|
||||
sslcf->passwords)
|
||||
!= NGX_OK)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
static ngx_int_t
|
||||
ngx_stream_ssl_static_variable(ngx_stream_session_t *s,
|
||||
ngx_stream_variable_value_t *v, uintptr_t data)
|
||||
@@ -505,6 +567,7 @@ ngx_stream_ssl_create_conf(ngx_conf_t *cf)
|
||||
*
|
||||
* scf->listen = 0;
|
||||
* scf->protocols = 0;
|
||||
* scf->certificate_values = NULL;
|
||||
* scf->dhparam = { 0, NULL };
|
||||
* scf->ecdh_curve = { 0, NULL };
|
||||
* scf->client_certificate = { 0, NULL };
|
||||
@@ -619,13 +682,38 @@ ngx_stream_ssl_merge_conf(ngx_conf_t *cf, void *parent, void *child)
|
||||
cln->handler = ngx_ssl_cleanup_ctx;
|
||||
cln->data = &conf->ssl;
|
||||
|
||||
if (ngx_ssl_certificates(cf, &conf->ssl, conf->certificates,
|
||||
conf->certificate_keys, conf->passwords)
|
||||
!= NGX_OK)
|
||||
{
|
||||
if (ngx_stream_ssl_compile_certificates(cf, conf) != NGX_OK) {
|
||||
return NGX_CONF_ERROR;
|
||||
}
|
||||
|
||||
if (conf->certificate_values) {
|
||||
|
||||
#ifdef SSL_R_CERT_CB_ERROR
|
||||
|
||||
/* install callback to lookup certificates */
|
||||
|
||||
SSL_CTX_set_cert_cb(conf->ssl.ctx, ngx_stream_ssl_certificate, conf);
|
||||
|
||||
#else
|
||||
ngx_log_error(NGX_LOG_EMERG, cf->log, 0,
|
||||
"variables in "
|
||||
"\"ssl_certificate\" and \"ssl_certificate_key\" "
|
||||
"directives are not supported on this platform");
|
||||
return NGX_CONF_ERROR;
|
||||
#endif
|
||||
|
||||
} else {
|
||||
|
||||
/* configure certificates */
|
||||
|
||||
if (ngx_ssl_certificates(cf, &conf->ssl, conf->certificates,
|
||||
conf->certificate_keys, conf->passwords)
|
||||
!= NGX_OK)
|
||||
{
|
||||
return NGX_CONF_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
if (ngx_ssl_ciphers(cf, &conf->ssl, &conf->ciphers,
|
||||
conf->prefer_server_ciphers)
|
||||
!= NGX_OK)
|
||||
@@ -678,7 +766,7 @@ ngx_stream_ssl_merge_conf(ngx_conf_t *cf, void *parent, void *child)
|
||||
}
|
||||
|
||||
if (ngx_ssl_session_cache(&conf->ssl, &ngx_stream_ssl_sess_id_ctx,
|
||||
conf->builtin_session_cache,
|
||||
conf->certificates, conf->builtin_session_cache,
|
||||
conf->shm_zone, conf->session_timeout)
|
||||
!= NGX_OK)
|
||||
{
|
||||
@@ -707,6 +795,90 @@ ngx_stream_ssl_merge_conf(ngx_conf_t *cf, void *parent, void *child)
|
||||
}
|
||||
|
||||
|
||||
static ngx_int_t
|
||||
ngx_stream_ssl_compile_certificates(ngx_conf_t *cf,
|
||||
ngx_stream_ssl_conf_t *conf)
|
||||
{
|
||||
ngx_str_t *cert, *key;
|
||||
ngx_uint_t i, nelts;
|
||||
ngx_stream_complex_value_t *cv;
|
||||
ngx_stream_compile_complex_value_t ccv;
|
||||
|
||||
cert = conf->certificates->elts;
|
||||
key = conf->certificate_keys->elts;
|
||||
nelts = conf->certificates->nelts;
|
||||
|
||||
for (i = 0; i < nelts; i++) {
|
||||
|
||||
if (ngx_stream_script_variables_count(&cert[i])) {
|
||||
goto found;
|
||||
}
|
||||
|
||||
if (ngx_stream_script_variables_count(&key[i])) {
|
||||
goto found;
|
||||
}
|
||||
}
|
||||
|
||||
return NGX_OK;
|
||||
|
||||
found:
|
||||
|
||||
conf->certificate_values = ngx_array_create(cf->pool, nelts,
|
||||
sizeof(ngx_stream_complex_value_t));
|
||||
if (conf->certificate_values == NULL) {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
conf->certificate_key_values = ngx_array_create(cf->pool, nelts,
|
||||
sizeof(ngx_stream_complex_value_t));
|
||||
if (conf->certificate_key_values == NULL) {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
for (i = 0; i < nelts; i++) {
|
||||
|
||||
cv = ngx_array_push(conf->certificate_values);
|
||||
if (cv == NULL) {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
ngx_memzero(&ccv, sizeof(ngx_stream_compile_complex_value_t));
|
||||
|
||||
ccv.cf = cf;
|
||||
ccv.value = &cert[i];
|
||||
ccv.complex_value = cv;
|
||||
ccv.zero = 1;
|
||||
|
||||
if (ngx_stream_compile_complex_value(&ccv) != NGX_OK) {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
cv = ngx_array_push(conf->certificate_key_values);
|
||||
if (cv == NULL) {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
ngx_memzero(&ccv, sizeof(ngx_stream_compile_complex_value_t));
|
||||
|
||||
ccv.cf = cf;
|
||||
ccv.value = &key[i];
|
||||
ccv.complex_value = cv;
|
||||
ccv.zero = 1;
|
||||
|
||||
if (ngx_stream_compile_complex_value(&ccv) != NGX_OK) {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
conf->passwords = ngx_ssl_preserve_passwords(cf, conf->passwords);
|
||||
if (conf->passwords == NULL) {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
return NGX_OK;
|
||||
}
|
||||
|
||||
|
||||
static char *
|
||||
ngx_stream_ssl_password_file(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
|
||||
{
|
||||
|
||||
@@ -34,6 +34,9 @@ typedef struct {
|
||||
ngx_array_t *certificates;
|
||||
ngx_array_t *certificate_keys;
|
||||
|
||||
ngx_array_t *certificate_values;
|
||||
ngx_array_t *certificate_key_values;
|
||||
|
||||
ngx_str_t dhparam;
|
||||
ngx_str_t ecdh_curve;
|
||||
ngx_str_t client_certificate;
|
||||
|
||||
Reference in New Issue
Block a user