mirror of https://github.com/nginx/nginx
Add basic ECH shared-mode via OpenSSL.
This commit is contained in:
parent
bcb41c9193
commit
ab4f5b2d32
|
|
@ -1653,6 +1653,102 @@ ngx_ssl_dhparam(ngx_conf_t *cf, ngx_ssl_t *ssl, ngx_str_t *file)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
ngx_int_t
|
||||||
|
ngx_ssl_ech_files(ngx_conf_t *cf, ngx_ssl_t *ssl, ngx_array_t *filenames)
|
||||||
|
{
|
||||||
|
#ifdef SSL_OP_ECH_GREASE
|
||||||
|
int numkeys;
|
||||||
|
BIO *in;
|
||||||
|
ngx_int_t rc;
|
||||||
|
ngx_str_t *filename;
|
||||||
|
ngx_uint_t i;
|
||||||
|
OSSL_ECHSTORE *es;
|
||||||
|
|
||||||
|
if (filenames == NULL) {
|
||||||
|
return NGX_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
es = OSSL_ECHSTORE_new(NULL, NULL);
|
||||||
|
if (es == NULL) {
|
||||||
|
ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0, "OSSL_ECHSTORE_new() failed");
|
||||||
|
return NGX_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
rc = NGX_ERROR;
|
||||||
|
filename = filenames->elts;
|
||||||
|
|
||||||
|
for (i = 0; i < filenames->nelts; i++) {
|
||||||
|
|
||||||
|
if (ngx_conf_full_name(cf->cycle, &filename[i], 1) != NGX_OK) {
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
|
||||||
|
in = BIO_new_file((char *) filename[i].data, "r");
|
||||||
|
if (in == NULL) {
|
||||||
|
ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0,
|
||||||
|
"BIO_new_file(\"%s\") failed", filename[i].data);
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* We only set the ECHConfigList from the first file read to use
|
||||||
|
* in ECH retry-configs.
|
||||||
|
*
|
||||||
|
* That allows many sensible key rotation schemes so that the
|
||||||
|
* values sent in ECH retry-configs are smaller and current.
|
||||||
|
* For example, if the first file name has the current ECH
|
||||||
|
* private key, and a second one has the previously used key
|
||||||
|
* that some clients may still use due to DNS caching.
|
||||||
|
*/
|
||||||
|
|
||||||
|
if (OSSL_ECHSTORE_read_pem(es, in, i ? OSSL_ECH_NO_RETRY
|
||||||
|
: OSSL_ECH_FOR_RETRY)
|
||||||
|
!= 1)
|
||||||
|
{
|
||||||
|
ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0,
|
||||||
|
"OSSL_ECHSTORE_read_pem(%s) failed",
|
||||||
|
filename[i].data);
|
||||||
|
BIO_free(in);
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
|
||||||
|
BIO_free(in);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* load the ECH store after checking there's at least one ECH
|
||||||
|
* private key in there (the PEM file spec allows zero or one
|
||||||
|
* private key per file)
|
||||||
|
*/
|
||||||
|
|
||||||
|
if (OSSL_ECHSTORE_num_keys(es, &numkeys) != 1) {
|
||||||
|
ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0,
|
||||||
|
"OSSL_ECHSTORE_num_keys(%s) failed");
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (numkeys > 0 && SSL_CTX_set1_echstore(ssl->ctx, es) != 1) {
|
||||||
|
ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0,
|
||||||
|
"SSL_CTX_set1_echstore() failed");
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
|
||||||
|
rc = NGX_OK;
|
||||||
|
|
||||||
|
cleanup:
|
||||||
|
|
||||||
|
OSSL_ECHSTORE_free(es);
|
||||||
|
return rc;
|
||||||
|
|
||||||
|
#else
|
||||||
|
ngx_log_error(NGX_LOG_WARN, ssl->log, 0,
|
||||||
|
"\"ssl_ech_file\" is not supported on this platform, "
|
||||||
|
"ignored");
|
||||||
|
return NGX_OK;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
ngx_int_t
|
ngx_int_t
|
||||||
ngx_ssl_ecdh_curve(ngx_conf_t *cf, ngx_ssl_t *ssl, ngx_str_t *name)
|
ngx_ssl_ecdh_curve(ngx_conf_t *cf, ngx_ssl_t *ssl, ngx_str_t *name)
|
||||||
{
|
{
|
||||||
|
|
@ -5708,6 +5804,81 @@ ngx_ssl_get_alpn_protocol(ngx_connection_t *c, ngx_pool_t *pool, ngx_str_t *s)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
ngx_int_t
|
||||||
|
ngx_ssl_get_ech_status(ngx_connection_t *c, ngx_pool_t *pool, ngx_str_t *s)
|
||||||
|
{
|
||||||
|
#ifdef SSL_OP_ECH_GREASE
|
||||||
|
int echrv;
|
||||||
|
char *inner_sni, *outer_sni;
|
||||||
|
|
||||||
|
inner_sni = NULL;
|
||||||
|
outer_sni = NULL;
|
||||||
|
|
||||||
|
echrv = SSL_ech_get1_status(c->ssl->connection, &inner_sni, &outer_sni);
|
||||||
|
|
||||||
|
switch (echrv) {
|
||||||
|
case SSL_ECH_STATUS_NOT_TRIED:
|
||||||
|
ngx_str_set(s, "NOT_TRIED");
|
||||||
|
break;
|
||||||
|
case SSL_ECH_STATUS_SUCCESS:
|
||||||
|
ngx_str_set(s, "SUCCESS");
|
||||||
|
break;
|
||||||
|
case SSL_ECH_STATUS_GREASE:
|
||||||
|
ngx_str_set(s, "GREASE");
|
||||||
|
break;
|
||||||
|
case SSL_ECH_STATUS_BACKEND:
|
||||||
|
ngx_str_set(s, "BACKEND");
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
ngx_str_set(s, "FAILED");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
OPENSSL_free(inner_sni);
|
||||||
|
OPENSSL_free(outer_sni);
|
||||||
|
#else
|
||||||
|
s->len = 0;
|
||||||
|
#endif
|
||||||
|
return NGX_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
ngx_int_t
|
||||||
|
ngx_ssl_get_ech_outer_server_name(ngx_connection_t *c, ngx_pool_t *pool,
|
||||||
|
ngx_str_t *s)
|
||||||
|
{
|
||||||
|
#if defined(SSL_OP_ECH_GREASE)
|
||||||
|
int echrv;
|
||||||
|
char *inner_sni, *outer_sni;
|
||||||
|
|
||||||
|
inner_sni = NULL;
|
||||||
|
outer_sni = NULL;
|
||||||
|
|
||||||
|
echrv = SSL_ech_get1_status(c->ssl->connection, &inner_sni, &outer_sni);
|
||||||
|
|
||||||
|
if (echrv == SSL_ECH_STATUS_SUCCESS && outer_sni) {
|
||||||
|
s->len = ngx_strlen(outer_sni);
|
||||||
|
|
||||||
|
s->data = ngx_pnalloc(pool, s->len);
|
||||||
|
if (s->data == NULL) {
|
||||||
|
return NGX_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
ngx_memcpy(s->data, outer_sni, s->len);
|
||||||
|
|
||||||
|
} else {
|
||||||
|
s->len = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
OPENSSL_free(inner_sni);
|
||||||
|
OPENSSL_free(outer_sni);
|
||||||
|
#else
|
||||||
|
s->len = 0;
|
||||||
|
#endif
|
||||||
|
return NGX_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
ngx_int_t
|
ngx_int_t
|
||||||
ngx_ssl_get_raw_certificate(ngx_connection_t *c, ngx_pool_t *pool, ngx_str_t *s)
|
ngx_ssl_get_raw_certificate(ngx_connection_t *c, ngx_pool_t *pool, ngx_str_t *s)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -271,6 +271,8 @@ ngx_array_t *ngx_ssl_read_password_file(ngx_conf_t *cf, ngx_str_t *file);
|
||||||
ngx_array_t *ngx_ssl_preserve_passwords(ngx_conf_t *cf,
|
ngx_array_t *ngx_ssl_preserve_passwords(ngx_conf_t *cf,
|
||||||
ngx_array_t *passwords);
|
ngx_array_t *passwords);
|
||||||
ngx_int_t ngx_ssl_dhparam(ngx_conf_t *cf, ngx_ssl_t *ssl, ngx_str_t *file);
|
ngx_int_t ngx_ssl_dhparam(ngx_conf_t *cf, ngx_ssl_t *ssl, ngx_str_t *file);
|
||||||
|
ngx_int_t ngx_ssl_ech_files(ngx_conf_t *cf, ngx_ssl_t *ssl,
|
||||||
|
ngx_array_t *filename);
|
||||||
ngx_int_t ngx_ssl_ecdh_curve(ngx_conf_t *cf, ngx_ssl_t *ssl, ngx_str_t *name);
|
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,
|
ngx_int_t ngx_ssl_early_data(ngx_conf_t *cf, ngx_ssl_t *ssl,
|
||||||
ngx_uint_t enable);
|
ngx_uint_t enable);
|
||||||
|
|
@ -338,6 +340,10 @@ ngx_int_t ngx_ssl_get_early_data(ngx_connection_t *c, ngx_pool_t *pool,
|
||||||
ngx_str_t *s);
|
ngx_str_t *s);
|
||||||
ngx_int_t ngx_ssl_get_server_name(ngx_connection_t *c, ngx_pool_t *pool,
|
ngx_int_t ngx_ssl_get_server_name(ngx_connection_t *c, ngx_pool_t *pool,
|
||||||
ngx_str_t *s);
|
ngx_str_t *s);
|
||||||
|
ngx_int_t ngx_ssl_get_ech_status(ngx_connection_t *c, ngx_pool_t *pool,
|
||||||
|
ngx_str_t *s);
|
||||||
|
ngx_int_t ngx_ssl_get_ech_outer_server_name(ngx_connection_t *c,
|
||||||
|
ngx_pool_t *pool, ngx_str_t *s);
|
||||||
ngx_int_t ngx_ssl_get_alpn_protocol(ngx_connection_t *c, ngx_pool_t *pool,
|
ngx_int_t ngx_ssl_get_alpn_protocol(ngx_connection_t *c, ngx_pool_t *pool,
|
||||||
ngx_str_t *s);
|
ngx_str_t *s);
|
||||||
ngx_int_t ngx_ssl_get_raw_certificate(ngx_connection_t *c, ngx_pool_t *pool,
|
ngx_int_t ngx_ssl_get_raw_certificate(ngx_connection_t *c, ngx_pool_t *pool,
|
||||||
|
|
|
||||||
|
|
@ -117,6 +117,13 @@ static ngx_command_t ngx_http_ssl_commands[] = {
|
||||||
0,
|
0,
|
||||||
NULL },
|
NULL },
|
||||||
|
|
||||||
|
{ ngx_string("ssl_ech_file"),
|
||||||
|
NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_CONF_TAKE1,
|
||||||
|
ngx_conf_set_str_array_slot,
|
||||||
|
NGX_HTTP_SRV_CONF_OFFSET,
|
||||||
|
offsetof(ngx_http_ssl_srv_conf_t, ech_files),
|
||||||
|
NULL },
|
||||||
|
|
||||||
{ ngx_string("ssl_password_file"),
|
{ ngx_string("ssl_password_file"),
|
||||||
NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_CONF_TAKE1,
|
NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_CONF_TAKE1,
|
||||||
ngx_http_ssl_password_file,
|
ngx_http_ssl_password_file,
|
||||||
|
|
@ -377,6 +384,13 @@ static ngx_http_variable_t ngx_http_ssl_vars[] = {
|
||||||
{ ngx_string("ssl_alpn_protocol"), NULL, ngx_http_ssl_variable,
|
{ ngx_string("ssl_alpn_protocol"), NULL, ngx_http_ssl_variable,
|
||||||
(uintptr_t) ngx_ssl_get_alpn_protocol, NGX_HTTP_VAR_CHANGEABLE, 0 },
|
(uintptr_t) ngx_ssl_get_alpn_protocol, NGX_HTTP_VAR_CHANGEABLE, 0 },
|
||||||
|
|
||||||
|
{ ngx_string("ssl_ech_status"), NULL, ngx_http_ssl_variable,
|
||||||
|
(uintptr_t) ngx_ssl_get_ech_status, NGX_HTTP_VAR_CHANGEABLE, 0 },
|
||||||
|
|
||||||
|
{ ngx_string("ssl_ech_outer_server_name"), NULL, ngx_http_ssl_variable,
|
||||||
|
(uintptr_t) ngx_ssl_get_ech_outer_server_name,
|
||||||
|
NGX_HTTP_VAR_CHANGEABLE, 0 },
|
||||||
|
|
||||||
{ ngx_string("ssl_client_cert"), NULL, ngx_http_ssl_variable,
|
{ ngx_string("ssl_client_cert"), NULL, ngx_http_ssl_variable,
|
||||||
(uintptr_t) ngx_ssl_get_certificate, NGX_HTTP_VAR_CHANGEABLE, 0 },
|
(uintptr_t) ngx_ssl_get_certificate, NGX_HTTP_VAR_CHANGEABLE, 0 },
|
||||||
|
|
||||||
|
|
@ -643,6 +657,7 @@ ngx_http_ssl_create_srv_conf(ngx_conf_t *cf)
|
||||||
sscf->certificates = NGX_CONF_UNSET_PTR;
|
sscf->certificates = NGX_CONF_UNSET_PTR;
|
||||||
sscf->certificate_keys = NGX_CONF_UNSET_PTR;
|
sscf->certificate_keys = NGX_CONF_UNSET_PTR;
|
||||||
sscf->certificate_cache = NGX_CONF_UNSET_PTR;
|
sscf->certificate_cache = NGX_CONF_UNSET_PTR;
|
||||||
|
sscf->ech_files = NGX_CONF_UNSET_PTR;
|
||||||
sscf->passwords = NGX_CONF_UNSET_PTR;
|
sscf->passwords = NGX_CONF_UNSET_PTR;
|
||||||
sscf->conf_commands = NGX_CONF_UNSET_PTR;
|
sscf->conf_commands = NGX_CONF_UNSET_PTR;
|
||||||
sscf->builtin_session_cache = NGX_CONF_UNSET;
|
sscf->builtin_session_cache = NGX_CONF_UNSET;
|
||||||
|
|
@ -694,6 +709,8 @@ ngx_http_ssl_merge_srv_conf(ngx_conf_t *cf, void *parent, void *child)
|
||||||
ngx_conf_merge_ptr_value(conf->certificate_cache, prev->certificate_cache,
|
ngx_conf_merge_ptr_value(conf->certificate_cache, prev->certificate_cache,
|
||||||
NULL);
|
NULL);
|
||||||
|
|
||||||
|
ngx_conf_merge_ptr_value(conf->ech_files, prev->ech_files, NULL);
|
||||||
|
|
||||||
ngx_conf_merge_ptr_value(conf->passwords, prev->passwords, NULL);
|
ngx_conf_merge_ptr_value(conf->passwords, prev->passwords, NULL);
|
||||||
|
|
||||||
ngx_conf_merge_str_value(conf->dhparam, prev->dhparam, "");
|
ngx_conf_merge_str_value(conf->dhparam, prev->dhparam, "");
|
||||||
|
|
@ -880,6 +897,10 @@ ngx_http_ssl_merge_srv_conf(ngx_conf_t *cf, void *parent, void *child)
|
||||||
return NGX_CONF_ERROR;
|
return NGX_CONF_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (ngx_ssl_ech_files(cf, &conf->ssl, conf->ech_files) != NGX_OK) {
|
||||||
|
return NGX_CONF_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
if (ngx_ssl_ecdh_curve(cf, &conf->ssl, &conf->ecdh_curve) != NGX_OK) {
|
if (ngx_ssl_ecdh_curve(cf, &conf->ssl, &conf->ecdh_curve) != NGX_OK) {
|
||||||
return NGX_CONF_ERROR;
|
return NGX_CONF_ERROR;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -49,6 +49,7 @@ typedef struct {
|
||||||
|
|
||||||
ngx_str_t ciphers;
|
ngx_str_t ciphers;
|
||||||
|
|
||||||
|
ngx_array_t *ech_files;
|
||||||
ngx_array_t *passwords;
|
ngx_array_t *passwords;
|
||||||
ngx_array_t *conf_commands;
|
ngx_array_t *conf_commands;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -126,6 +126,13 @@ static ngx_command_t ngx_stream_ssl_commands[] = {
|
||||||
0,
|
0,
|
||||||
NULL },
|
NULL },
|
||||||
|
|
||||||
|
{ ngx_string("ssl_ech_file"),
|
||||||
|
NGX_STREAM_MAIN_CONF|NGX_STREAM_SRV_CONF|NGX_CONF_TAKE1,
|
||||||
|
ngx_conf_set_str_array_slot,
|
||||||
|
NGX_STREAM_SRV_CONF_OFFSET,
|
||||||
|
offsetof(ngx_stream_ssl_srv_conf_t, ech_files),
|
||||||
|
NULL },
|
||||||
|
|
||||||
{ ngx_string("ssl_password_file"),
|
{ ngx_string("ssl_password_file"),
|
||||||
NGX_STREAM_MAIN_CONF|NGX_STREAM_SRV_CONF|NGX_CONF_TAKE1,
|
NGX_STREAM_MAIN_CONF|NGX_STREAM_SRV_CONF|NGX_CONF_TAKE1,
|
||||||
ngx_stream_ssl_password_file,
|
ngx_stream_ssl_password_file,
|
||||||
|
|
@ -372,6 +379,13 @@ static ngx_stream_variable_t ngx_stream_ssl_vars[] = {
|
||||||
{ ngx_string("ssl_alpn_protocol"), NULL, ngx_stream_ssl_variable,
|
{ ngx_string("ssl_alpn_protocol"), NULL, ngx_stream_ssl_variable,
|
||||||
(uintptr_t) ngx_ssl_get_alpn_protocol, NGX_STREAM_VAR_CHANGEABLE, 0 },
|
(uintptr_t) ngx_ssl_get_alpn_protocol, NGX_STREAM_VAR_CHANGEABLE, 0 },
|
||||||
|
|
||||||
|
{ ngx_string("ssl_ech_status"), NULL, ngx_stream_ssl_variable,
|
||||||
|
(uintptr_t) ngx_ssl_get_ech_status, NGX_STREAM_VAR_CHANGEABLE, 0 },
|
||||||
|
|
||||||
|
{ ngx_string("ssl_ech_outer_server_name"), NULL, ngx_stream_ssl_variable,
|
||||||
|
(uintptr_t) ngx_ssl_get_ech_outer_server_name,
|
||||||
|
NGX_STREAM_VAR_CHANGEABLE, 0 },
|
||||||
|
|
||||||
{ ngx_string("ssl_client_cert"), NULL, ngx_stream_ssl_variable,
|
{ ngx_string("ssl_client_cert"), NULL, ngx_stream_ssl_variable,
|
||||||
(uintptr_t) ngx_ssl_get_certificate, NGX_STREAM_VAR_CHANGEABLE, 0 },
|
(uintptr_t) ngx_ssl_get_certificate, NGX_STREAM_VAR_CHANGEABLE, 0 },
|
||||||
|
|
||||||
|
|
@ -888,6 +902,7 @@ ngx_stream_ssl_create_srv_conf(ngx_conf_t *cf)
|
||||||
sscf->certificates = NGX_CONF_UNSET_PTR;
|
sscf->certificates = NGX_CONF_UNSET_PTR;
|
||||||
sscf->certificate_keys = NGX_CONF_UNSET_PTR;
|
sscf->certificate_keys = NGX_CONF_UNSET_PTR;
|
||||||
sscf->certificate_cache = NGX_CONF_UNSET_PTR;
|
sscf->certificate_cache = NGX_CONF_UNSET_PTR;
|
||||||
|
sscf->ech_files = NGX_CONF_UNSET_PTR;
|
||||||
sscf->passwords = NGX_CONF_UNSET_PTR;
|
sscf->passwords = NGX_CONF_UNSET_PTR;
|
||||||
sscf->conf_commands = NGX_CONF_UNSET_PTR;
|
sscf->conf_commands = NGX_CONF_UNSET_PTR;
|
||||||
sscf->prefer_server_ciphers = NGX_CONF_UNSET;
|
sscf->prefer_server_ciphers = NGX_CONF_UNSET;
|
||||||
|
|
@ -943,6 +958,8 @@ ngx_stream_ssl_merge_srv_conf(ngx_conf_t *cf, void *parent, void *child)
|
||||||
ngx_conf_merge_ptr_value(conf->certificate_cache, prev->certificate_cache,
|
ngx_conf_merge_ptr_value(conf->certificate_cache, prev->certificate_cache,
|
||||||
NULL);
|
NULL);
|
||||||
|
|
||||||
|
ngx_conf_merge_ptr_value(conf->ech_files, prev->ech_files, NULL);
|
||||||
|
|
||||||
ngx_conf_merge_ptr_value(conf->passwords, prev->passwords, NULL);
|
ngx_conf_merge_ptr_value(conf->passwords, prev->passwords, NULL);
|
||||||
|
|
||||||
ngx_conf_merge_str_value(conf->dhparam, prev->dhparam, "");
|
ngx_conf_merge_str_value(conf->dhparam, prev->dhparam, "");
|
||||||
|
|
@ -1124,6 +1141,10 @@ ngx_stream_ssl_merge_srv_conf(ngx_conf_t *cf, void *parent, void *child)
|
||||||
return NGX_CONF_ERROR;
|
return NGX_CONF_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (ngx_ssl_ech_files(cf, &conf->ssl, conf->ech_files) != NGX_OK) {
|
||||||
|
return NGX_CONF_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
if (ngx_ssl_ecdh_curve(cf, &conf->ssl, &conf->ecdh_curve) != NGX_OK) {
|
if (ngx_ssl_ecdh_curve(cf, &conf->ssl, &conf->ecdh_curve) != NGX_OK) {
|
||||||
return NGX_CONF_ERROR;
|
return NGX_CONF_ERROR;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -49,6 +49,7 @@ typedef struct {
|
||||||
|
|
||||||
ngx_str_t ciphers;
|
ngx_str_t ciphers;
|
||||||
|
|
||||||
|
ngx_array_t *ech_files;
|
||||||
ngx_array_t *passwords;
|
ngx_array_t *passwords;
|
||||||
ngx_array_t *conf_commands;
|
ngx_array_t *conf_commands;
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue