Latest update - 7466

This commit is contained in:
2019-02-26 16:40:49 +09:00
parent efe1334ec8
commit f6264bdb9e
9 changed files with 822 additions and 180 deletions
+401 -149
View File
@@ -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) {
+8 -1
View File
@@ -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);
+118 -5
View File
@@ -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)
{
+3
View File
@@ -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;
+4
View File
@@ -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
View File
@@ -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";
+1 -1
View File
@@ -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)
{
+177 -5
View File
@@ -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)
{
+3
View File
@@ -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;