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 <el...@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 < albertcasadem...@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 <kypri...@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