Welcome! Log In Create A New Profile

Advanced

Re: [PATCH] Multiple certificate support with OpenSSL >= 1.0.2

kyprizel
March 17, 2015 02:40PM
Sure it should be tested (there are can be some memory leaks).
Need to know if it's idologically acceptable.

Nginx with dual cert support can be tested at https://ctftime.org.

Patch in body inline:
# HG changeset patch
# User Eldar Zaitov <eldar@kyprizel.net>
# Date 1426616118 -10800
# Node ID 83b0f57fbcb514ffd74bb89070580473bacd286e
# Parent e370c5fdf4c8edc2e8d33d7170c1b1cc74a2ecb6
Multiple SSL certificate support with OpenSSL >= 1.0.2

diff -r e370c5fdf4c8 -r 83b0f57fbcb5 src/event/ngx_event_openssl.c
--- a/src/event/ngx_event_openssl.c Tue Mar 17 00:26:27 2015 +0300
+++ b/src/event/ngx_event_openssl.c Tue Mar 17 21:15:18 2015 +0300
@@ -286,198 +286,282 @@


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_ssl_certificates(ngx_conf_t *cf, ngx_ssl_t *ssl, ngx_array_t *certs,
+ ngx_array_t *keys, ngx_array_t *passwords)
{
- BIO *bio;
- X509 *x509;
- u_long n;
- ngx_str_t *pwd;
- ngx_uint_t tries;
-
- if (ngx_conf_full_name(cf->cycle, cert, 1) != NGX_OK) {
+ ngx_str_t *pwd;
+ ngx_uint_t tries;
+ ngx_str_t *cert;
+ ngx_str_t *key;
+ ngx_uint_t i, j;
+ u_long n;
+ BIO *bio;
+ EVP_PKEY *pkey;
+ X509 *x509;
+ X509 *x509_ca;
+ STACK_OF(X509) *chain;
+ ngx_array_t *certificates;
+ ngx_ssl_certificate_t *cert_info;
+
+ bio = NULL;
+ pkey = NULL;
+ x509 = NULL;
+ x509_ca = NULL;
+
+ cert = certs->elts;
+ key = keys->elts;
+
+ certificates = ngx_array_create(cf->pool, certs->nelts,
+ sizeof(ngx_ssl_certificate_t));
+ if (certificates == NULL) {
return NGX_ERROR;
}

- /*
- * 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
- * it here
- */
-
- 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;
- }
-
- 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);
- BIO_free(bio);
- 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);
- 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;
- }
-
- X509_free(x509);
-
- /* read rest of the chain */
-
- for ( ;; ) {
-
- x509 = PEM_read_bio_X509(bio, NULL, NULL, NULL);
+ for (i = 0; i < certs->nelts; i++) {
+
+ /* load server certificate */
+
+ if (ngx_conf_full_name(cf->cycle, &cert[i], 1) != NGX_OK) {
+ goto failed;
+ }
+
+ /*
+ * 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
+ * it here
+ */
+
+ bio = BIO_new_file((char *) cert[i].data, "r");
+ if (bio == NULL) {
+ ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0,
+ "BIO_new_file(\"%V\") failed", &cert[i]);
+ goto failed;
+ }
+
+ 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(\"%V\") failed",
&cert[i]);
+ goto failed;
+ }
+
+ if (SSL_CTX_use_certificate(ssl->ctx, x509) == 0) {
+ ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0,
+ "SSL_CTX_use_certificate(\"%V\") failed",
&cert[i]);
+ goto failed;
+ }
+
+
+ /* read rest of the chain */
+
+ for (j = 0; ; j++) {
+
+ x509_ca = PEM_read_bio_X509(bio, NULL, NULL, 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();
+ if (x509_ca == NULL) {
+
+ 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 */
+
+ ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0,
+ "PEM_read_bio_X509(\"%V\") failed",
&cert[i]);
+ goto failed;
+ }
+
+#ifdef SSL_CTX_add0_chain_cert
+ /* OpenSSL >=1.0.2 allows multiple server certificates in a
single
+ * SSL_CTX to each have a different chain
+ */
+ if (SSL_CTX_add0_chain_cert(ssl->ctx, x509_ca) == 0) {
+
+ ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0,
+ "SSL_CTX_add0_chain_cert(\"%V\") failed",
+ &cert[i]);
+ goto failed;
+ }
+#else
+ if (i == 0) {
+ if (SSL_CTX_add_extra_chain_cert(ssl->ctx, x509_ca) == 0) {
+
+ ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0,
+ "SSL_CTX_add_extra_chain_cert() failed");
+ goto failed;
+ }
break;
}
-
- /* some real error */
+#endif
+
+ }
+
+ BIO_free(bio);
+ bio = NULL;
+
+
+ /* load private key */
+
+ if (ngx_strncmp(key[i].data, "engine:", sizeof("engine:") - 1) ==
0) {
+#ifndef OPENSSL_NO_ENGINE
+
+ u_char *p, *last;
+ ENGINE *engine;
+
+ p = key[i].data + sizeof("engine:") - 1;
+ last = (u_char *) ngx_strchr(p, ':');
+
+ if (last == NULL) {
+ ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
+ "invalid syntax in \"%V\"", &(key[i]));
+ goto failed;
+ }
+
+
+ *last = '\0';
+
+ engine = ENGINE_by_id((char *) p);
+
+ if (engine == NULL) {
+ ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0,
+ "ENGINE_by_id(\"%s\") failed", p);
+ goto failed;
+ }
+
+ *last++ = ':';
+
+ 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);
+ ENGINE_free(engine);
+ goto failed;
+ }
+
+ 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);
+ goto failed;
+ }
+
+ EVP_PKEY_free(pkey);
+ pkey = NULL;
+
+ continue;
+#else
+
+ ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
+ "loading \"engine:...\" certificate keys "
+ "is not supported");
+ goto failed;
+
+#endif
+ }
+
+ if (ngx_conf_full_name(cf->cycle, &key[i], 1) != NGX_OK) {
+ goto failed;
+ }
+
+ 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);
+ } else {
+ tries = 1;
+#if (NGX_SUPPRESS_WARN)
+ pwd = NULL;
+#endif
+ }
+
+
+ for ( ;; ) {
+ if (SSL_CTX_use_PrivateKey_file(ssl->ctx, (char *) key[i].data,
+ SSL_FILETYPE_PEM)
+ != 0)
+ {
+ break;
+ }
+
+ if (--tries) {
+ ERR_clear_error();
+ SSL_CTX_set_default_passwd_cb_userdata(ssl->ctx, ++pwd);
+ continue;
+ }

ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0,
- "PEM_read_bio_X509(\"%s\") failed", cert->data);
- BIO_free(bio);
- return NGX_ERROR;
+ "SSL_CTX_use_PrivateKey_file(\"%s\") failed",
+ key[i].data);
+ goto failed;
}

- if (SSL_CTX_add_extra_chain_cert(ssl->ctx, x509) == 0) {
+ if (SSL_CTX_check_private_key(ssl->ctx) < 1) {
ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0,
- "SSL_CTX_add_extra_chain_cert(\"%s\") failed",
- cert->data);
- X509_free(x509);
- BIO_free(bio);
- return NGX_ERROR;
+ "PrivateKey \"%V\" does not match \"%V\" failed",
+ &key[i], &cert[i]);
+ goto failed;
}
- }
-
- BIO_free(bio);
-
- if (ngx_strncmp(key->data, "engine:", sizeof("engine:") - 1) == 0) {
-
-#ifndef OPENSSL_NO_ENGINE
-
- u_char *p, *last;
- ENGINE *engine;
- EVP_PKEY *pkey;
-
- p = key->data + sizeof("engine:") - 1;
- 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;
+
+ SSL_CTX_set_default_passwd_cb(ssl->ctx, NULL);
+
+
+#ifdef SSL_CTX_get0_chain_certs
+ SSL_CTX_get0_chain_certs(ssl->ctx, &chain);
+#else
+#if OPENSSL_VERSION_NUMBER >= 0x10001000L
+ SSL_CTX_get_extra_chain_certs(ssl->ctx, &chain);
+#else
+ chain = ssl->ctx->extra_certs;
+#endif
+#endif
+
+ cert_info = ngx_array_push(certificates);
+ if (cert_info == NULL) {
+ goto failed;
}

- *last = '\0';
-
- 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;
- }
-
- *last++ = ':';
-
- 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);
- ENGINE_free(engine);
- return NGX_ERROR;
- }
-
- 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;
- }
-
+ cert_info->issuer = NULL;
+ cert_info->cert = x509;
+ CRYPTO_add(&x509->references, 1, CRYPTO_LOCK_X509);
+
+ cert_info->chain = chain;
+
+
+ }
+
+ /* store cert info for future use in stapling and sessions */
+
+ if (SSL_CTX_set_ex_data(ssl->ctx, ngx_ssl_certificate_index,
certificates)
+ == 0)
+ {
+ ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0,
+ "SSL_CTX_set_ex_data() failed");
+ goto failed;
+ }
+
+ return NGX_OK;
+
+failed:
+
+ if (bio)
+ BIO_free(bio);
+ if (pkey)
EVP_PKEY_free(pkey);
-
- return NGX_OK;
-
-#else
-
- ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
- "loading \"engine:...\" certificate keys "
- "is not supported");
- return NGX_ERROR;
-
-#endif
- }
-
- if (ngx_conf_full_name(cf->cycle, key, 1) != NGX_OK) {
- return NGX_ERROR;
- }
-
- 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);
-
- } else {
- tries = 1;
-#if (NGX_SUPPRESS_WARN)
- pwd = NULL;
-#endif
- }
-
- for ( ;; ) {
-
- if (SSL_CTX_use_PrivateKey_file(ssl->ctx, (char *) key->data,
- SSL_FILETYPE_PEM)
- != 0)
- {
- break;
- }
-
- if (--tries) {
- ERR_clear_error();
- SSL_CTX_set_default_passwd_cb_userdata(ssl->ctx, ++pwd);
- continue;
- }
-
- ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0,
- "SSL_CTX_use_PrivateKey_file(\"%s\") failed",
key->data);
- return NGX_ERROR;
- }
-
- SSL_CTX_set_default_passwd_cb(ssl->ctx, NULL);
-
- return NGX_OK;
+ if (x509)
+ X509_free(x509);
+ if (x509_ca)
+ X509_free(x509_ca);
+
+ return NGX_ERROR;
}


@@ -2111,13 +2195,14 @@
static ngx_int_t
ngx_ssl_session_id_context(ngx_ssl_t *ssl, ngx_str_t *sess_ctx)
{
- int n, i;
- X509 *cert;
- X509_NAME *name;
- EVP_MD_CTX md;
- unsigned int len;
- STACK_OF(X509_NAME) *list;
- u_char buf[EVP_MAX_MD_SIZE];
+ int n, i;
+ X509_NAME *name;
+ EVP_MD_CTX md;
+ unsigned int len;
+ STACK_OF(X509_NAME) *list;
+ u_char buf[EVP_MAX_MD_SIZE];
+ ngx_array_t *certs;
+ ngx_ssl_certificate_t *cert_info;

/*
* Session ID context is set based on the string provided,
@@ -2138,9 +2223,14 @@
goto failed;
}

- cert = SSL_CTX_get_ex_data(ssl->ctx, ngx_ssl_certificate_index);
-
- if (X509_digest(cert, EVP_sha1(), buf, &len) == 0) {
+ certs = SSL_CTX_get_ex_data(ssl->ctx, ngx_ssl_certificate_index);
+ if (!certs || certs->nelts == 0) {
+ goto failed;
+ }
+
+ cert_info = certs->elts;
+
+ if (X509_digest((&cert_info[0])->cert, EVP_sha1(), buf, &len) == 0) {
ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0,
"X509_digest() failed");
goto failed;
diff -r e370c5fdf4c8 -r 83b0f57fbcb5 src/event/ngx_event_openssl.h
--- a/src/event/ngx_event_openssl.h Tue Mar 17 00:26:27 2015 +0300
+++ b/src/event/ngx_event_openssl.h Tue Mar 17 21:15:18 2015 +0300
@@ -45,6 +45,13 @@


typedef struct {
+ X509 *cert;
+ X509 *issuer;
+ STACK_OF(X509) *chain;
+} ngx_ssl_certificate_t;
+
+
+typedef struct {
ngx_ssl_conn_t *connection;

ngx_int_t last;
@@ -122,15 +129,15 @@

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_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_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_client_certificate(ngx_conf_t *cf, ngx_ssl_t *ssl,
ngx_str_t *cert, ngx_int_t depth);
ngx_int_t ngx_ssl_trusted_certificate(ngx_conf_t *cf, ngx_ssl_t *ssl,
ngx_str_t *cert, ngx_int_t depth);
ngx_int_t ngx_ssl_crl(ngx_conf_t *cf, ngx_ssl_t *ssl, ngx_str_t *crl);
ngx_int_t ngx_ssl_stapling(ngx_conf_t *cf, ngx_ssl_t *ssl,
- ngx_str_t *file, ngx_str_t *responder, ngx_uint_t verify);
+ ngx_array_t *files, ngx_array_t *responders, ngx_uint_t verify);
ngx_int_t ngx_ssl_stapling_resolver(ngx_conf_t *cf, ngx_ssl_t *ssl,
ngx_resolver_t *resolver, ngx_msec_t resolver_timeout);
RSA *ngx_ssl_rsa512_key_callback(ngx_ssl_conn_t *ssl_conn, int is_export,
diff -r e370c5fdf4c8 -r 83b0f57fbcb5 src/event/ngx_event_openssl_stapling.c
--- a/src/event/ngx_event_openssl_stapling.c Tue Mar 17 00:26:27 2015
+0300
+++ b/src/event/ngx_event_openssl_stapling.c Tue Mar 17 21:15:18 2015
+0300
@@ -28,8 +28,7 @@

SSL_CTX *ssl_ctx;

- X509 *cert;
- X509 *issuer;
+ ngx_ssl_certificate_t *cert_info;

time_t valid;

@@ -83,10 +82,11 @@


static ngx_int_t ngx_ssl_stapling_file(ngx_conf_t *cf, ngx_ssl_t *ssl,
- ngx_str_t *file);
-static ngx_int_t ngx_ssl_stapling_issuer(ngx_conf_t *cf, ngx_ssl_t *ssl);
+ ngx_ssl_stapling_t *staple, ngx_str_t *file);
+static ngx_int_t ngx_ssl_stapling_issuer(ngx_conf_t *cf, ngx_ssl_t *ssl,
+ ngx_ssl_stapling_t *staple);
static ngx_int_t ngx_ssl_stapling_responder(ngx_conf_t *cf, ngx_ssl_t *ssl,
- ngx_str_t *responder);
+ ngx_ssl_stapling_t *staple, ngx_str_t *responder);

static int ngx_ssl_certificate_status_callback(ngx_ssl_conn_t *ssl_conn,
void *data);
@@ -115,15 +115,29 @@


ngx_int_t
-ngx_ssl_stapling(ngx_conf_t *cf, ngx_ssl_t *ssl, ngx_str_t *file,
- ngx_str_t *responder, ngx_uint_t verify)
+ngx_ssl_stapling(ngx_conf_t *cf, ngx_ssl_t *ssl, ngx_array_t *files,
+ ngx_array_t *responders, ngx_uint_t verify)
{
- ngx_int_t rc;
- ngx_pool_cleanup_t *cln;
- ngx_ssl_stapling_t *staple;
+ ngx_uint_t i;
+ ngx_array_t *staples;
+ ngx_array_t *certificates;
+ ngx_pool_cleanup_t *cln;
+ ngx_str_t *responder, *file;
+ ngx_str_t empty_responder = ngx_null_string;
+ ngx_ssl_stapling_t *staple;
+ ngx_ssl_certificate_t *cert_info;

- staple = ngx_pcalloc(cf->pool, sizeof(ngx_ssl_stapling_t));
- if (staple == NULL) {
+ responder = NULL;
+ file = NULL;
+
+ certificates = SSL_CTX_get_ex_data(ssl->ctx,
ngx_ssl_certificate_index);
+ if (certificates == NULL || (certificates->nelts == 0)) {
+ return NGX_ERROR;
+ }
+
+ staples = ngx_array_create(cf->pool, certificates->nelts,
+ sizeof(ngx_ssl_stapling_t));
+ if (staples == NULL) {
return NGX_ERROR;
}

@@ -133,9 +147,66 @@
}

cln->handler = ngx_ssl_stapling_cleanup;
- cln->data = staple;
+ cln->data = staples;

- if (SSL_CTX_set_ex_data(ssl->ctx, ngx_ssl_stapling_index, staple)
+
+ cert_info = certificates->elts;
+ staple = staples->elts;
+
+ if (responders)
+ responder = responders->elts;
+
+ if (files)
+ file = files->elts;
+
+ for (i = 0; i < certificates->nelts; i++) {
+
+ staple = ngx_array_push(staples);
+ staple->timeout = 60000;
+ staple->ssl_ctx = ssl->ctx;
+ CRYPTO_add(&ssl->ctx->references, 1, CRYPTO_LOCK_X509);
+
+ staple->cert_info = &cert_info[i];
+ if (ngx_ssl_stapling_issuer(cf, ssl, staple) == NGX_ERROR) {
+ return NGX_ERROR;
+ }
+ staple->verify = verify;
+
+ if (responder && responders->nelts > i) {
+
+ if (ngx_ssl_stapling_responder(cf, ssl, staple, &responder[i])
+ != NGX_OK)
+ {
+ return NGX_ERROR;
+ }
+
+ } else {
+
+ if (ngx_ssl_stapling_responder(cf, ssl, staple,
&empty_responder)
+ == NGX_ERROR)
+ {
+ return NGX_ERROR;
+ }
+ empty_responder.len = 0;
+ empty_responder.data = NULL;
+
+ }
+
+ if (!file || files->nelts <= i)
+ continue;
+
+ if (file[i].len) {
+
+ /* use OCSP response from the file */
+
+ if (ngx_ssl_stapling_file(cf, ssl, staple, &file[i]) !=
NGX_OK) {
+ return NGX_ERROR;
+ }
+ }
+ }
+
+
+ if (SSL_CTX_set_ex_data(ssl->ctx, ngx_ssl_stapling_index, staples)
== 0)
{
ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0,
@@ -143,59 +214,21 @@
return NGX_ERROR;
}

- staple->ssl_ctx = ssl->ctx;
- staple->timeout = 60000;
- staple->verify = verify;
-
- if (file->len) {
- /* use OCSP response from the file */
-
- if (ngx_ssl_stapling_file(cf, ssl, file) != NGX_OK) {
- return NGX_ERROR;
- }
-
- goto done;
- }
-
- rc = ngx_ssl_stapling_issuer(cf, ssl);
-
- if (rc == NGX_DECLINED) {
- return NGX_OK;
- }
-
- if (rc != NGX_OK) {
- return NGX_ERROR;
- }
-
- rc = ngx_ssl_stapling_responder(cf, ssl, responder);
-
- if (rc == NGX_DECLINED) {
- return NGX_OK;
- }
-
- if (rc != NGX_OK) {
- return NGX_ERROR;
- }
-
-done:
-
SSL_CTX_set_tlsext_status_cb(ssl->ctx,
ngx_ssl_certificate_status_callback);
- SSL_CTX_set_tlsext_status_arg(ssl->ctx, staple);
+ SSL_CTX_set_tlsext_status_arg(ssl->ctx, staples);

return NGX_OK;
}


static ngx_int_t
-ngx_ssl_stapling_file(ngx_conf_t *cf, ngx_ssl_t *ssl, ngx_str_t *file)
+ngx_ssl_stapling_file(ngx_conf_t *cf, ngx_ssl_t *ssl,
+ ngx_ssl_stapling_t *staple, ngx_str_t *file)
{
BIO *bio;
int len;
u_char *p, *buf;
OCSP_RESPONSE *response;
- ngx_ssl_stapling_t *staple;
-
- staple = SSL_CTX_get_ex_data(ssl->ctx, ngx_ssl_stapling_index);

if (ngx_conf_full_name(cf->cycle, file, 1) != NGX_OK) {
return NGX_ERROR;
@@ -255,23 +288,32 @@


static ngx_int_t
-ngx_ssl_stapling_issuer(ngx_conf_t *cf, ngx_ssl_t *ssl)
+ngx_ssl_stapling_issuer(ngx_conf_t *cf, ngx_ssl_t *ssl,
+ ngx_ssl_stapling_t *staple)
{
- int i, n, rc;
- X509 *cert, *issuer;
- X509_STORE *store;
- X509_STORE_CTX *store_ctx;
- STACK_OF(X509) *chain;
- ngx_ssl_stapling_t *staple;
+ int i, n, rc;
+ X509 *issuer;
+ X509_STORE *store;
+ X509_STORE_CTX *store_ctx;
+ ngx_ssl_certificate_t *cert_info = staple->cert_info;
+ X509 *cert;
+ STACK_OF(X509) *chain;

- staple = SSL_CTX_get_ex_data(ssl->ctx, ngx_ssl_stapling_index);
- cert = SSL_CTX_get_ex_data(ssl->ctx, ngx_ssl_certificate_index);

-#if OPENSSL_VERSION_NUMBER >= 0x10001000L
- SSL_CTX_get_extra_chain_certs(ssl->ctx, &chain);
-#else
- chain = ssl->ctx->extra_certs;
-#endif
+ if (!cert_info || !cert_info->cert) {
+ ngx_log_error(NGX_LOG_WARN, ssl->log, 0,
+ "\"ssl_stapling\" ignored, no certificate info
found");
+ return NGX_ERROR;
+ }
+
+ if (!cert_info->chain) {
+ ngx_log_error(NGX_LOG_WARN, ssl->log, 0,
+ "\"ssl_stapling\" ignored, no certificate chain
found");
+ return NGX_ERROR;
+ }
+
+ cert = cert_info->cert;
+ chain = cert_info->chain;

n = sk_X509_num(chain);

@@ -286,8 +328,7 @@
ngx_log_debug1(NGX_LOG_DEBUG_EVENT, ssl->log, 0,
"SSL get issuer: found %p in extra certs",
issuer);

- staple->cert = cert;
- staple->issuer = issuer;
+ cert_info->issuer = issuer;

return NGX_OK;
}
@@ -334,28 +375,25 @@
ngx_log_debug1(NGX_LOG_DEBUG_EVENT, ssl->log, 0,
"SSL get issuer: found %p in cert store", issuer);

- staple->cert = cert;
- staple->issuer = issuer;
+ cert_info->issuer = issuer;

return NGX_OK;
}


static ngx_int_t
-ngx_ssl_stapling_responder(ngx_conf_t *cf, ngx_ssl_t *ssl, ngx_str_t
*responder)
+ngx_ssl_stapling_responder(ngx_conf_t *cf, ngx_ssl_t *ssl,
+ ngx_ssl_stapling_t *staple, ngx_str_t
*responder)
{
ngx_url_t u;
char *s;
- ngx_ssl_stapling_t *staple;
STACK_OF(OPENSSL_STRING) *aia;

- staple = SSL_CTX_get_ex_data(ssl->ctx, ngx_ssl_stapling_index);
-
if (responder->len == 0) {

/* extract OCSP responder URL from certificate */

- aia = X509_get1_ocsp(staple->cert);
+ aia = X509_get1_ocsp(staple->cert_info->cert);
if (aia == NULL) {
ngx_log_error(NGX_LOG_WARN, ssl->log, 0,
"\"ssl_stapling\" ignored, "
@@ -434,12 +472,21 @@
ngx_ssl_stapling_resolver(ngx_conf_t *cf, ngx_ssl_t *ssl,
ngx_resolver_t *resolver, ngx_msec_t resolver_timeout)
{
+
+ ngx_uint_t i;
+ ngx_array_t *staples;
ngx_ssl_stapling_t *staple;

- staple = SSL_CTX_get_ex_data(ssl->ctx, ngx_ssl_stapling_index);
+ staples = SSL_CTX_get_ex_data(ssl->ctx, ngx_ssl_stapling_index);
+ if (staples == NULL) {
+ return NGX_ERROR;
+ }

- staple->resolver = resolver;
- staple->resolver_timeout = resolver_timeout;
+ staple = staples->elts;
+ for (i = 0; i < staples->nelts; i++) {
+ staple[i].resolver = resolver;
+ staple[i].resolver_timeout = resolver_timeout;
+ }

return NGX_OK;
}
@@ -448,19 +495,46 @@
static int
ngx_ssl_certificate_status_callback(ngx_ssl_conn_t *ssl_conn, void *data)
{
- int rc;
- u_char *p;
- ngx_connection_t *c;
- ngx_ssl_stapling_t *staple;
+ int rc;
+ ngx_uint_t i;
+ u_char *p;
+ ngx_connection_t *c;
+ X509 *cert;
+ ngx_array_t *staples = data;
+ ngx_ssl_stapling_t *staple, *staples_elm;
+ ngx_ssl_certificate_t *cert_info;
+
+ staple = NULL;

c = ngx_ssl_get_connection(ssl_conn);

ngx_log_debug0(NGX_LOG_DEBUG_EVENT, c->log, 0,
"SSL certificate status callback");

- staple = data;
+
+ cert = SSL_get_certificate(ssl_conn);
+
rc = SSL_TLSEXT_ERR_NOACK;

+ /* find a staple for current certificate */
+
+ staples_elm = staples->elts;
+ for (i = 0; i < staples->nelts; i++) {
+
+ cert_info = staples_elm[i].cert_info;
+ if (!cert_info)
+ continue;
+
+ if (cert == cert_info->cert) {
+ staple = &staples_elm[i];
+ break;
+ }
+ }
+
+ if (staple == NULL) {
+ return rc;
+ }
+
if (staple->staple.len) {
/* we have to copy ocsp response as OpenSSL will free it by itself
*/

@@ -486,7 +560,8 @@
static void
ngx_ssl_stapling_update(ngx_ssl_stapling_t *staple)
{
- ngx_ssl_ocsp_ctx_t *ctx;
+ ngx_ssl_ocsp_ctx_t *ctx;
+ ngx_ssl_certificate_t *cert_info;

if (staple->host.len == 0
|| staple->loading || staple->valid >= ngx_time())
@@ -494,6 +569,11 @@
return;
}

+ cert_info = staple->cert_info;
+ if (!cert_info) {
+ return;
+ }
+
staple->loading = 1;

ctx = ngx_ssl_ocsp_start();
@@ -501,8 +581,8 @@
return;
}

- ctx->cert = staple->cert;
- ctx->issuer = staple->issuer;
+ ctx->cert = cert_info->cert;
+ ctx->issuer = cert_info->issuer;

ctx->addrs = staple->addrs;
ctx->host = staple->host;
@@ -528,17 +608,17 @@
#if OPENSSL_VERSION_NUMBER >= 0x0090707fL
const
#endif
- u_char *p;
- int n;
- size_t len;
- ngx_str_t response;
- X509_STORE *store;
- STACK_OF(X509) *chain;
- OCSP_CERTID *id;
- OCSP_RESPONSE *ocsp;
- OCSP_BASICRESP *basic;
- ngx_ssl_stapling_t *staple;
- ASN1_GENERALIZEDTIME *thisupdate, *nextupdate;
+ u_char *p;
+ int n;
+ size_t len;
+ ngx_str_t response;
+ X509_STORE *store;
+ OCSP_CERTID *id;
+ OCSP_RESPONSE *ocsp;
+ OCSP_BASICRESP *basic;
+ ngx_ssl_stapling_t *staple;
+ ASN1_GENERALIZEDTIME *thisupdate, *nextupdate;
+ ngx_ssl_certificate_t *cert_info;

staple = ctx->data;
ocsp = NULL;
@@ -584,22 +664,28 @@
goto error;
}

-#if OPENSSL_VERSION_NUMBER >= 0x10001000L
- SSL_CTX_get_extra_chain_certs(staple->ssl_ctx, &chain);
-#else
- chain = staple->ssl_ctx->extra_certs;
+ cert_info = staple->cert_info;
+ if (!cert_info) {
+ ngx_ssl_error(NGX_LOG_ERR, ctx->log, 0,
+ "No certificate information found");
+ goto error;
+ }
+
+ if (OCSP_basic_verify(basic, cert_info->chain, store, (staple->verify)
+ ?
OCSP_TRUSTOTHER
+ : OCSP_NOVERIFY
+#if OPENSSL_VERSION_NUMBER < 0x10000000L
+ /* ECDSA/SHA-2 signature verification not supported */
+ | OCSP_NOSIGS
#endif
-
- if (OCSP_basic_verify(basic, chain, store,
- staple->verify ? OCSP_TRUSTOTHER : OCSP_NOVERIFY)
- != 1)
+ ) != 1)
{
ngx_ssl_error(NGX_LOG_ERR, ctx->log, 0,
"OCSP_basic_verify() failed");
goto error;
}

- id = OCSP_cert_to_id(NULL, ctx->cert, ctx->issuer);
+ id = OCSP_cert_to_id(NULL, cert_info->cert, ctx->issuer);
if (id == NULL) {
ngx_ssl_error(NGX_LOG_CRIT, ctx->log, 0,
"OCSP_cert_to_id() failed");
@@ -685,14 +771,28 @@
static void
ngx_ssl_stapling_cleanup(void *data)
{
- ngx_ssl_stapling_t *staple = data;
+ ngx_uint_t i;
+ ngx_ssl_stapling_t *staple;
+ ngx_ssl_certificate_t *cert_info;
+ ngx_array_t *staples = data;

- if (staple->issuer) {
- X509_free(staple->issuer);
- }
+ staple = staples->elts;
+ for (i = 0; i < staples->nelts; i++) {
+ if (staple[i].staple.data) {
+ ngx_free(staple[i].staple.data);
+ }

- if (staple->staple.data) {
- ngx_free(staple->staple.data);
+ cert_info = staple[i].cert_info;
+ if (!cert_info)
+ continue;
+
+ if (cert_info->issuer) {
+ X509_free(cert_info->issuer);
+ }
+
+ if (cert_info->chain) {
+ sk_X509_free(cert_info->chain);
+ }
}
}

@@ -1742,8 +1842,8 @@


ngx_int_t
-ngx_ssl_stapling(ngx_conf_t *cf, ngx_ssl_t *ssl, ngx_str_t *file,
- ngx_str_t *responder, ngx_uint_t verify)
+ngx_ssl_stapling(ngx_conf_t *cf, ngx_ssl_t *ssl, ngx_array_t *files,
+ ngx_array_t *responders, ngx_uint_t verify)
{
ngx_log_error(NGX_LOG_WARN, ssl->log, 0,
"\"ssl_stapling\" ignored, not supported");
diff -r e370c5fdf4c8 -r 83b0f57fbcb5
src/http/modules/ngx_http_proxy_module.c
--- a/src/http/modules/ngx_http_proxy_module.c Tue Mar 17 00:26:27 2015
+0300
+++ b/src/http/modules/ngx_http_proxy_module.c Tue Mar 17 21:15:18 2015
+0300
@@ -97,8 +97,8 @@
ngx_uint_t ssl_verify_depth;
ngx_str_t ssl_trusted_certificate;
ngx_str_t ssl_crl;
- ngx_str_t ssl_certificate;
- ngx_str_t ssl_certificate_key;
+ ngx_array_t *ssl_certificates;
+ ngx_array_t *ssl_certificate_keys;
ngx_array_t *ssl_passwords;
#endif
} ngx_http_proxy_loc_conf_t;
@@ -657,16 +657,16 @@

{ ngx_string("proxy_ssl_certificate"),

NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
- ngx_conf_set_str_slot,
+ ngx_conf_set_str_array_slot,
NGX_HTTP_LOC_CONF_OFFSET,
- offsetof(ngx_http_proxy_loc_conf_t, ssl_certificate),
+ offsetof(ngx_http_proxy_loc_conf_t, ssl_certificates),
NULL },

{ ngx_string("proxy_ssl_certificate_key"),

NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
- ngx_conf_set_str_slot,
+ ngx_conf_set_str_array_slot,
NGX_HTTP_LOC_CONF_OFFSET,
- offsetof(ngx_http_proxy_loc_conf_t, ssl_certificate_key),
+ offsetof(ngx_http_proxy_loc_conf_t, ssl_certificate_keys),
NULL },

{ ngx_string("proxy_ssl_password_file"),
@@ -2625,6 +2625,8 @@
conf->upstream.ssl_verify = NGX_CONF_UNSET;
conf->ssl_verify_depth = NGX_CONF_UNSET_UINT;
conf->ssl_passwords = NGX_CONF_UNSET_PTR;
+ conf->ssl_certificates = NGX_CONF_UNSET_PTR;
+ conf->ssl_certificate_keys = NGX_CONF_UNSET_PTR;
#endif

/* "proxy_cyclic_temp_file" is disabled */
@@ -2953,10 +2955,11 @@
prev->ssl_trusted_certificate, "");
ngx_conf_merge_str_value(conf->ssl_crl, prev->ssl_crl, "");

- ngx_conf_merge_str_value(conf->ssl_certificate,
- prev->ssl_certificate, "");
- ngx_conf_merge_str_value(conf->ssl_certificate_key,
- prev->ssl_certificate_key, "");
+ ngx_conf_merge_ptr_value(conf->ssl_certificates,
+ prev->ssl_certificates, NULL);
+ ngx_conf_merge_ptr_value(conf->ssl_certificate_keys,
+ prev->ssl_certificate_keys, NULL);
+
ngx_conf_merge_ptr_value(conf->ssl_passwords, prev->ssl_passwords,
NULL);

if (conf->ssl && ngx_http_proxy_set_ssl(cf, conf) != NGX_OK) {
@@ -4043,6 +4046,7 @@
ngx_http_proxy_set_ssl(ngx_conf_t *cf, ngx_http_proxy_loc_conf_t *plcf)
{
ngx_pool_cleanup_t *cln;
+ ngx_str_t *oddkey;

plcf->upstream.ssl = ngx_pcalloc(cf->pool, sizeof(ngx_ssl_t));
if (plcf->upstream.ssl == NULL) {
@@ -4065,18 +4069,43 @@
cln->handler = ngx_ssl_cleanup_ctx;
cln->data = plcf->upstream.ssl;

- if (plcf->ssl_certificate.len) {
-
- if (plcf->ssl_certificate_key.len == 0) {
+ if (plcf->ssl_certificates && (plcf->ssl_certificates->nelts > 0)) {
+
+ if ((!plcf->ssl_certificate_keys)
+ || (plcf->ssl_certificate_keys->nelts
+ < plcf->ssl_certificates->nelts))
+ {
+
+ oddkey = plcf->ssl_certificates->elts;
+
ngx_log_error(NGX_LOG_EMERG, cf->log, 0,
- "no \"proxy_ssl_certificate_key\" is defined "
- "for certificate \"%V\"",
&plcf->ssl_certificate);
+ "no \"proxy_ssl_certificate_key\" is defined for
"
+ "ssl certificate \"%V\"",
+ oddkey[(plcf->ssl_certificate_keys)
+ ? plcf->ssl_certificate_keys->nelts
+ : 0]);
+
return NGX_ERROR;
}

- if (ngx_ssl_certificate(cf, plcf->upstream.ssl,
&plcf->ssl_certificate,
- &plcf->ssl_certificate_key,
plcf->ssl_passwords)
- != NGX_OK)
+#ifndef SSL_CTX_add0_chain_cert
+ if (plcf->ssl_certificates->nelts > 1) {
+ /*
+ * no multiple certificates support for OpenSSL < 1.0.2,
+ * so we need to alarm user
+ */
+ ngx_log_error(NGX_LOG_EMERG, cf->log, 0,
+ "Multiple certificate configured "
+ "in \"proxy_ssl_certificate\", "
+ "but OpenSSL version < 1.0.2 used");
+ return NGX_ERROR;
+ }
+#endif
+
+ if (ngx_ssl_certificates(cf, plcf->upstream.ssl,
plcf->ssl_certificates,
+ plcf->ssl_certificate_keys,
+ plcf->ssl_passwords)
+ != NGX_OK)
{
return NGX_ERROR;
}
diff -r e370c5fdf4c8 -r 83b0f57fbcb5 src/http/modules/ngx_http_ssl_module.c
--- a/src/http/modules/ngx_http_ssl_module.c Tue Mar 17 00:26:27 2015
+0300
+++ b/src/http/modules/ngx_http_ssl_module.c Tue Mar 17 21:15:18 2015
+0300
@@ -81,16 +81,16 @@

{ ngx_string("ssl_certificate"),
NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_CONF_TAKE1,
- ngx_conf_set_str_slot,
+ ngx_conf_set_str_array_slot,
NGX_HTTP_SRV_CONF_OFFSET,
- offsetof(ngx_http_ssl_srv_conf_t, certificate),
+ offsetof(ngx_http_ssl_srv_conf_t, certificates),
NULL },

{ ngx_string("ssl_certificate_key"),
NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_CONF_TAKE1,
- ngx_conf_set_str_slot,
+ ngx_conf_set_str_array_slot,
NGX_HTTP_SRV_CONF_OFFSET,
- offsetof(ngx_http_ssl_srv_conf_t, certificate_key),
+ offsetof(ngx_http_ssl_srv_conf_t, certificate_keys),
NULL },

{ ngx_string("ssl_password_file"),
@@ -214,16 +214,16 @@

{ ngx_string("ssl_stapling_file"),
NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_CONF_TAKE1,
- ngx_conf_set_str_slot,
+ ngx_conf_set_str_array_slot,
NGX_HTTP_SRV_CONF_OFFSET,
- offsetof(ngx_http_ssl_srv_conf_t, stapling_file),
+ offsetof(ngx_http_ssl_srv_conf_t, stapling_files),
NULL },

{ ngx_string("ssl_stapling_responder"),
NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_CONF_TAKE1,
- ngx_conf_set_str_slot,
+ ngx_conf_set_str_array_slot,
NGX_HTTP_SRV_CONF_OFFSET,
- offsetof(ngx_http_ssl_srv_conf_t, stapling_responder),
+ offsetof(ngx_http_ssl_srv_conf_t, stapling_responders),
NULL },

{ ngx_string("ssl_stapling_verify"),
@@ -505,8 +505,6 @@
* set by ngx_pcalloc():
*
* sscf->protocols = 0;
- * sscf->certificate = { 0, NULL };
- * sscf->certificate_key = { 0, NULL };
* sscf->dhparam = { 0, NULL };
* sscf->ecdh_curve = { 0, NULL };
* sscf->client_certificate = { 0, NULL };
@@ -514,12 +512,12 @@
* sscf->crl = { 0, NULL };
* sscf->ciphers = { 0, NULL };
* sscf->shm_zone = NULL;
- * sscf->stapling_file = { 0, NULL };
- * sscf->stapling_responder = { 0, NULL };
*/

sscf->enable = NGX_CONF_UNSET;
sscf->prefer_server_ciphers = NGX_CONF_UNSET;
+ sscf->certificates = NGX_CONF_UNSET_PTR;
+ sscf->certificate_keys = NGX_CONF_UNSET_PTR;
sscf->buffer_size = NGX_CONF_UNSET_SIZE;
sscf->verify = NGX_CONF_UNSET_UINT;
sscf->verify_depth = NGX_CONF_UNSET_UINT;
@@ -530,6 +528,8 @@
sscf->session_ticket_keys = NGX_CONF_UNSET_PTR;
sscf->stapling = NGX_CONF_UNSET;
sscf->stapling_verify = NGX_CONF_UNSET;
+ sscf->stapling_files = NGX_CONF_UNSET_PTR;
+ sscf->stapling_responders = NGX_CONF_UNSET_PTR;

return sscf;
}
@@ -570,8 +570,10 @@
ngx_conf_merge_uint_value(conf->verify, prev->verify, 0);
ngx_conf_merge_uint_value(conf->verify_depth, prev->verify_depth, 1);

- ngx_conf_merge_str_value(conf->certificate, prev->certificate, "");
- ngx_conf_merge_str_value(conf->certificate_key, prev->certificate_key,
"");
+ ngx_conf_merge_ptr_value(conf->certificates, prev->certificates,
+ NULL);
+ ngx_conf_merge_ptr_value(conf->certificate_keys,
prev->certificate_keys,
+ NULL);

ngx_conf_merge_ptr_value(conf->passwords, prev->passwords, NULL);

@@ -590,15 +592,18 @@

ngx_conf_merge_value(conf->stapling, prev->stapling, 0);
ngx_conf_merge_value(conf->stapling_verify, prev->stapling_verify, 0);
- ngx_conf_merge_str_value(conf->stapling_file, prev->stapling_file, "");
- ngx_conf_merge_str_value(conf->stapling_responder,
- prev->stapling_responder, "");
+ ngx_conf_merge_ptr_value(conf->stapling_files, prev->stapling_files,
+ NULL);
+ ngx_conf_merge_ptr_value(conf->stapling_responders,
+ prev->stapling_responders, NULL);

conf->ssl.log = cf->log;

if (conf->enable) {

- if (conf->certificate.len == 0) {
+ if ((!conf->certificates)
+ || (conf->certificates->nelts == 0)) {
+
ngx_log_error(NGX_LOG_EMERG, cf->log, 0,
"no \"ssl_certificate\" is defined for "
"the \"ssl\" directive in %s:%ui",
@@ -606,7 +611,9 @@
return NGX_CONF_ERROR;
}

- if (conf->certificate_key.len == 0) {
+ if ((!conf->certificate_keys)
+ || (conf->certificate_keys->nelts == 0)) {
+
ngx_log_error(NGX_LOG_EMERG, cf->log, 0,
"no \"ssl_certificate_key\" is defined for "
"the \"ssl\" directive in %s:%ui",
@@ -616,18 +623,39 @@

} else {

- if (conf->certificate.len == 0) {
+ if ((!conf->certificates)
+ || (conf->certificates->nelts == 0)) {
+
return NGX_CONF_OK;
}

- if (conf->certificate_key.len == 0) {
+ if ((!conf->certificate_keys)
+ || (conf->certificate_keys->nelts < conf->certificates->nelts))
+ {
+
ngx_log_error(NGX_LOG_EMERG, cf->log, 0,
- "no \"ssl_certificate_key\" is defined "
- "for certificate \"%V\"", &conf->certificate);
+ "no \"ssl_certificate_key\" is defined for "
+ "ssl_certificate \"%V\"",
+ &conf->certificates[(conf->certificate_keys)
+ ?
conf->certificate_keys->nelts
+ : 0]);
return NGX_CONF_ERROR;
}
}

+#ifndef SSL_CTX_add0_chain_cert
+ if (conf->certificates->nelts > 1) {
+ /*
+ * no multiple certificates support for OpenSSL < 1.0.2,
+ * so we need to alarm user
+ */
+ ngx_log_error(NGX_LOG_EMERG, cf->log, 0,
+ "Multiple certificate configured in "
+ "\"ssl_certificate\", but OpenSSL < 1.0.2
used");
+ return NGX_CONF_ERROR;
+ }
+#endif
+
if (ngx_ssl_create(&conf->ssl, conf->protocols, conf) != NGX_OK) {
return NGX_CONF_ERROR;
}
@@ -663,8 +691,8 @@
cln->handler = ngx_ssl_cleanup_ctx;
cln->data = &conf->ssl;

- if (ngx_ssl_certificate(cf, &conf->ssl, &conf->certificate,
- &conf->certificate_key, conf->passwords)
+ if (ngx_ssl_certificates(cf, &conf->ssl, conf->certificates,
+ conf->certificate_keys, conf->passwords)
!= NGX_OK)
{
return NGX_CONF_ERROR;
@@ -760,8 +788,8 @@

if (conf->stapling) {

- if (ngx_ssl_stapling(cf, &conf->ssl, &conf->stapling_file,
- &conf->stapling_responder,
conf->stapling_verify)
+ if (ngx_ssl_stapling(cf, &conf->ssl, conf->stapling_files,
+ conf->stapling_responders,
conf->stapling_verify)
!= NGX_OK)
{
return NGX_CONF_ERROR;
diff -r e370c5fdf4c8 -r 83b0f57fbcb5
src/http/modules/ngx_http_uwsgi_module.c
--- a/src/http/modules/ngx_http_uwsgi_module.c Tue Mar 17 00:26:27 2015
+0300
+++ b/src/http/modules/ngx_http_uwsgi_module.c Tue Mar 17 21:15:18 2015
+0300
@@ -54,8 +54,8 @@
ngx_uint_t ssl_verify_depth;
ngx_str_t ssl_trusted_certificate;
ngx_str_t ssl_crl;
- ngx_str_t ssl_certificate;
- ngx_str_t ssl_certificate_key;
+ ngx_array_t *ssl_certificates;
+ ngx_array_t *ssl_certificate_keys;
ngx_array_t *ssl_passwords;
#endif
} ngx_http_uwsgi_loc_conf_t;
@@ -510,16 +510,16 @@

{ ngx_string("uwsgi_ssl_certificate"),

NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
- ngx_conf_set_str_slot,
+ ngx_conf_set_str_array_slot,
NGX_HTTP_LOC_CONF_OFFSET,
- offsetof(ngx_http_uwsgi_loc_conf_t, ssl_certificate),
+ offsetof(ngx_http_uwsgi_loc_conf_t, ssl_certificates),
NULL },

{ ngx_string("uwsgi_ssl_certificate_key"),

NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
- ngx_conf_set_str_slot,
+ ngx_conf_set_str_array_slot,
NGX_HTTP_LOC_CONF_OFFSET,
- offsetof(ngx_http_uwsgi_loc_conf_t, ssl_certificate_key),
+ offsetof(ngx_http_uwsgi_loc_conf_t, ssl_certificate_keys),
NULL },

{ ngx_string("uwsgi_ssl_password_file"),
@@ -1412,6 +1412,8 @@
conf->upstream.ssl_verify = NGX_CONF_UNSET;
conf->ssl_verify_depth = NGX_CONF_UNSET_UINT;
conf->ssl_passwords = NGX_CONF_UNSET_PTR;
+ conf->ssl_certificates = NGX_CONF_UNSET_PTR;
+ conf->ssl_certificate_keys = NGX_CONF_UNSET_PTR;
#endif

/* "uwsgi_cyclic_temp_file" is disabled */
@@ -1723,11 +1725,10 @@
ngx_conf_merge_str_value(conf->ssl_trusted_certificate,
prev->ssl_trusted_certificate, "");
ngx_conf_merge_str_value(conf->ssl_crl, prev->ssl_crl, "");
-
- ngx_conf_merge_str_value(conf->ssl_certificate,
- prev->ssl_certificate, "");
- ngx_conf_merge_str_value(conf->ssl_certificate_key,
- prev->ssl_certificate_key, "");
+ ngx_conf_merge_ptr_value(conf->ssl_certificates,
+ prev->ssl_certificates, NULL);
+ ngx_conf_merge_ptr_value(conf->ssl_certificate_keys,
+ prev->ssl_certificate_keys, NULL);
ngx_conf_merge_ptr_value(conf->ssl_passwords, prev->ssl_passwords,
NULL);

if (conf->ssl && ngx_http_uwsgi_set_ssl(cf, conf) != NGX_OK) {
@@ -2264,6 +2265,7 @@
ngx_http_uwsgi_set_ssl(ngx_conf_t *cf, ngx_http_uwsgi_loc_conf_t *uwcf)
{
ngx_pool_cleanup_t *cln;
+ ngx_str_t *oddkey;

uwcf->upstream.ssl = ngx_pcalloc(cf->pool, sizeof(ngx_ssl_t));
if (uwcf->upstream.ssl == NULL) {
@@ -2286,17 +2288,42 @@
cln->handler = ngx_ssl_cleanup_ctx;
cln->data = uwcf->upstream.ssl;

- if (uwcf->ssl_certificate.len) {
-
- if (uwcf->ssl_certificate_key.len == 0) {
+ if (uwcf->ssl_certificates && (uwcf->ssl_certificates->nelts > 0)) {
+
+ if ((!uwcf->ssl_certificate_keys)
+ || (uwcf->ssl_certificate_keys->nelts
+ < uwcf->ssl_certificates->nelts))
+ {
+
+ oddkey = &uwcf->ssl_certificates->elts;
+
ngx_log_error(NGX_LOG_EMERG, cf->log, 0,
- "no \"uwsgi_ssl_certificate_key\" is defined "
- "for certificate \"%V\"",
&uwcf->ssl_certificate);
+ "no \"uwsgi_ssl_certificate_key\" is defined for
"
+ "ssl certificate \"%V\"",
+ oddkey[(uwcf->ssl_certificate_keys)
+ ? uwcf->ssl_certificate_keys->nelts
+ : 0]);
+
return NGX_ERROR;
}

- if (ngx_ssl_certificate(cf, uwcf->upstream.ssl,
&uwcf->ssl_certificate,
- &uwcf->ssl_certificate_key,
uwcf->ssl_passwords)
+#ifndef SSL_CTX_add0_chain_cert
+ if (uwcf->ssl_certificates->nelts > 1) {
+ /*
+ * no multiple certificates support for OpenSSL < 1.0.2,
+ * so we need to alarm user
+ */
+ ngx_log_error(NGX_LOG_EMERG, cf->log, 0,
+ "Multiple certificate configured "
+ "in "\"uwsgi_ssl_certificate\", but "
+ "OpenSSL < 1.0.2 used");
+ return NGX_ERROR;
+ }
+#endif
+
+ if (ngx_ssl_certificates(cf, uwcf->upstream.ssl,
uwcf->ssl_certificates,
+ uwcf->ssl_certificate_keys,
+ uwcf->ssl_passwords)
!= NGX_OK)
{
return NGX_ERROR;


On Tue, Mar 17, 2015 at 9:27 PM, Albert Casademont Filella <
albertcasademont@gmail.com> wrote:

> This would be a very nice addition indeed, thanks!! I guess it needs quite
> a lot of testing though, ECC certs are still not really common these days.
>
> BTW and before some of the core devs says it patches should be sent in the
> email body, not as an attachment. It is much more convenient for reviewing
> it ;)
>
> On Tue, Mar 17, 2015 at 7:22 PM, kyprizel <kyprizel@gmail.com> wrote:
>
>> Hi,
>> Sorry for spamming - previous message was sent to wrong mailing list and
>> possibly included broken patch.
>>
>> This patch is mostly finishing of Rob Stradlings patch discussed in thread
>> http://mailman.nginx.org/pipermail/nginx-devel/2013-November/004475.html
>>
>> Multi certificate support works only for OpenSSL >= 1.0.2.
>> Only certificates with different crypto algorithms (ECC/RSA/DSA) can be
>> used b/c of OpenSSL limitations, otherwise (RSA+SHA-256 / RSA-SHA-1 for
>> example) only last specified in the config will be used.
>> Can you please review it.
>>
>> Thank you.
>>
>>
>> _______________________________________________
>> nginx-devel mailing list
>> nginx-devel@nginx.org
>> http://mailman.nginx.org/mailman/listinfo/nginx-devel
>>
>
>
> _______________________________________________
> nginx-devel mailing list
> nginx-devel@nginx.org
> http://mailman.nginx.org/mailman/listinfo/nginx-devel
>
_______________________________________________
nginx-devel mailing list
nginx-devel@nginx.org
http://mailman.nginx.org/mailman/listinfo/nginx-devel
Subject Author Views Posted

[PATCH] Multiple certificate support with OpenSSL >= 1.0.2 Attachments

kyprizel 1260 March 17, 2015 02:24PM

Re: [PATCH] Multiple certificate support with OpenSSL >= 1.0.2

Albert Casademont Filella 433 March 17, 2015 02:28PM

Re: [PATCH] Multiple certificate support with OpenSSL >= 1.0.2

kyprizel 1097 March 17, 2015 02:40PM

Re: [PATCH] Multiple certificate support with OpenSSL >= 1.0.2

Maxim Dounin 318 March 17, 2015 03:22PM

Re: [PATCH] Multiple certificate support with OpenSSL >= 1.0.2

Albert Casademont 318 March 24, 2015 12:34PM

Re: [PATCH] Multiple certificate support with OpenSSL >= 1.0.2

kyprizel 319 March 24, 2015 05:22PM

Re: [PATCH] Multiple certificate support with OpenSSL >= 1.0.2

Filipe Da Silva 396 March 25, 2015 05:10AM



Sorry, you do not have permission to post/reply in this forum.

Online Users

Guests: 173
Record Number of Users: 8 on April 13, 2023
Record Number of Guests: 421 on December 02, 2018
Powered by nginx      Powered by FreeBSD      PHP Powered      Powered by MariaDB      ipv6 ready