mirror of https://github.com/nginx/nginx.git
fixup! fixup! OpenSSL ECH integration
This commit is contained in:
parent
ea757e4229
commit
170eb2806e
34
ECH-build.md
34
ECH-build.md
|
@ -21,6 +21,8 @@ here. (For more on ECH "split-mode" see the
|
|||
|
||||
## Build
|
||||
|
||||
### OpenSSL
|
||||
|
||||
> [!NOTE]
|
||||
> ECH is not yet a part of an OpenSSL release, our current goal is that ECH be
|
||||
> part of an OpenSSL 4.0 release in spring 2026.
|
||||
|
@ -125,6 +127,10 @@ files. The `ssl_echkeydir` directive should be in the "http" section of an
|
|||
NGINX configuration as shown in the example below. All ECH PEM files in that
|
||||
directory that are successfully decoded will be loaded.
|
||||
|
||||
The NGINX instance also needs to include a virtual server that matches the
|
||||
ECH `public_name` so that the ECH fallback can work. The first virtual
|
||||
server in the example below does this.
|
||||
|
||||
```
|
||||
http {
|
||||
log_format withech '$remote_addr - $remote_user [$time_local] '
|
||||
|
@ -167,31 +173,41 @@ normal `combined` log format:
|
|||
```
|
||||
log_format withech '$remote_addr - $remote_user [$time_local] '
|
||||
'"$request" $status $body_bytes_sent '
|
||||
'"$http_referer" "$http_user_agent" "$ech_status"';
|
||||
'"$http_referer" "$http_user_agent"
|
||||
"ECH: $ssl_ech_status/$ssl_server_name/$ssl_ech_outer_sni"';
|
||||
access_log /var/log/nginx/access.log withech;
|
||||
```
|
||||
|
||||
That results in log lines like the following:
|
||||
|
||||
```
|
||||
127.0.0.1 - - [26/Feb/2025:13:35:52 +0000] "GET / HTTP/1.1" 200 494 "-" "curl/8.12.0-DEV" "ECH: SSL_ECH_STATUS_GREASE/foo.example.com/"
|
||||
127.0.0.1 - - [26/Feb/2025:13:39:39 +0000] "GET / HTTP/1.1" 200 494 "-" "curl/8.12.0-DEV" "ECH: SSL_ECH_STATUS_NOT_TRIED/foo.example.com/"
|
||||
127.0.0.1 - - [26/Feb/2025:14:08:21 +0000] "GET / HTTP/1.1" 200 494 "-" "curl/8.12.0-DEV" "ECH: SSL_ECH_STATUS_SUCCESS/example.com/foo.example.com"
|
||||
127.0.0.1 - - [26/Feb/2025:14:09:58 +0000] "GET / HTTP/1.1" 200 494 "-" "curl/8.12.0-DEV" "ECH: SSL_ECH_STATUS_NOT_TRIED/foo.example.com/"
|
||||
127.0.0.1 - - [26/Feb/2025:14:11:47 +0000] "GET / HTTP/1.1" 400 255 "-" "curl/8.12.0-DEV" "ECH: no TLS connection"
|
||||
127.0.0.1 - - [12/Oct/2025:18:54:07 +0100] "GET /index.html HTTP/1.1" 200 494 "-" "-"
|
||||
"ECH: GREASED/foo.example.com/-"
|
||||
127.0.0.1 - - [12/Oct/2025:18:54:15 +0100] "GET /index.html HTTP/1.1" 200 486 "-" "-"
|
||||
"ECH: GREASED/example.com/-"
|
||||
127.0.0.1 - - [12/Oct/2025:18:54:23 +0100] "GET /index.html HTTP/1.1" 200 494 "-" "-"
|
||||
"ECH: SUCCESS/foo.example.com/example.com"
|
||||
127.0.0.1 - - [12/Oct/2025:18:54:31 +0100] "GET /index.html HTTP/1.1" 200 494 "-" "-"
|
||||
"ECH: SUCCESS/foo.example.com/example.com"
|
||||
```
|
||||
|
||||
When ECH has succeeded, then the outer SNI and inner SNI are included in that
|
||||
order. If a client GREASEd or didn't try ECH at all, and no outer SNI was
|
||||
provided, the HTTP host header will be shown instead. Connections that did not
|
||||
use TLS show that. The TLS version is not specifically shown, so TLSv1.2
|
||||
connections will show up as `SSL_ECH_STATUS_NOT_TRIED`.
|
||||
connections will show up as `NOT_TRIED`.
|
||||
|
||||
At start-up, and on configuration re-load, NGINX will log (to `error.log` at
|
||||
the "notice" log level) the names of ECH PEM files successfully loaded and the
|
||||
total number of ECH keys loaded, for each `server` stanza in the configuration.
|
||||
Errors in loading keys are also logged and may result in the server not
|
||||
starting.
|
||||
starting. Example log lines would be:
|
||||
|
||||
```
|
||||
2025/10/12 18:54:07 [notice] 768265#0: ngx_ssl_load_echkeys, worked for: /etc/nginx/echkeydir/echconfig.pem.ech
|
||||
2025/10/12 18:54:07 [notice] 768265#0: ngx_ssl_load_echkeys, worked for: /etc/nginx/echkeydir/d13.pem.ech
|
||||
2025/10/12 18:54:07 [notice] 768265#0: ngx_ssl_load_echkeys, total keys loaded: 2
|
||||
```
|
||||
|
||||
## CGI variables
|
||||
|
||||
|
@ -208,7 +224,7 @@ NGINX config:
|
|||
|
||||
```
|
||||
fastcgi_param SSL_ECH_STATUS $ssl_ech_status;
|
||||
fastcgi_param SSL_ECH_INNER_SNI $ssl_ech_inner_sni;
|
||||
fastcgi_param SSL_ECH_INNER_SNI $ssl_server_name;
|
||||
fastcgi_param SSL_ECH_OUTER_SNI $ssl_ech_outer_sni;
|
||||
```
|
||||
|
||||
|
|
|
@ -14,6 +14,12 @@
|
|||
#endif
|
||||
|
||||
|
||||
/* check defines from <openssl/ssl.h> for ECH support */
|
||||
#if !defined(SSL_OP_ECH_GREASE) && !defined(SSL_R_ECH_REJECTED)
|
||||
#define OPENSSL_NO_ECH
|
||||
#endif
|
||||
|
||||
|
||||
#define NGX_SSL_PASSWORD_BUFFER_SIZE 4096
|
||||
|
||||
|
||||
|
@ -1575,33 +1581,38 @@ ngx_ssl_passwords_cleanup(void *data)
|
|||
#ifndef OPENSSL_NO_ECH
|
||||
|
||||
#ifndef PATH_MAX
|
||||
#define PATH_MAC 1024
|
||||
#define PATH_MAX 1024
|
||||
#endif
|
||||
|
||||
/* load key files called <name>.ech we find in the ssl_echkeydir directory */
|
||||
static int
|
||||
ngx_load_echkeys(ngx_ssl_t *ssl, ngx_str_t *dirname)
|
||||
static ngx_int_t
|
||||
ngx_ssl_load_echkeys(ngx_ssl_t *ssl, ngx_str_t *dirname)
|
||||
{
|
||||
/* 1024 private key files (maxkeyfiles) is plenty */
|
||||
int somekeyworked = 0, numkeys = 0, maxkeyfiles = 1024;
|
||||
char *den = NULL, *last4 = NULL, privname[PATH_MAX];
|
||||
size_t elen = dirname->len, nlen = 0;
|
||||
int somekeyworked, numkeys, maxkeyfiles;
|
||||
char *den, *last4, privname[PATH_MAX];
|
||||
size_t elen, nlen;
|
||||
ngx_dir_t thedir;
|
||||
ngx_int_t nrv = ngx_open_dir(dirname, &thedir);
|
||||
ngx_int_t nrv;
|
||||
struct stat thestat;
|
||||
OSSL_ECHSTORE *const es = OSSL_ECHSTORE_new(NULL, NULL);
|
||||
OSSL_ECHSTORE *es;
|
||||
|
||||
es = OSSL_ECHSTORE_new(NULL, NULL);
|
||||
if (es == NULL) {
|
||||
ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0,
|
||||
"ngx_load_echkeys, error allocating store" , __LINE__);
|
||||
"ngx_ssl_load_echkeys, error allocating store" );
|
||||
return NGX_ERROR;
|
||||
}
|
||||
nrv = ngx_open_dir(dirname, &thedir);
|
||||
if (nrv != NGX_OK) {
|
||||
ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0,
|
||||
"ngx_load_echkeys, error opening %s at %d",
|
||||
dirname->data, __LINE__);
|
||||
"ngx_ssl_load_echkeys, error opening %s", dirname->data);
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
somekeyworked = 0;
|
||||
numkeys = 0;
|
||||
maxkeyfiles = 1024; /* 1024 private key files (maxkeyfiles) is plenty */
|
||||
elen = dirname->len;
|
||||
for ( ;; ) {
|
||||
nrv = ngx_read_dir(&thedir);
|
||||
if (nrv != NGX_OK) {
|
||||
|
@ -1616,7 +1627,7 @@ ngx_load_echkeys(ngx_ssl_t *ssl, ngx_str_t *dirname)
|
|||
}
|
||||
if ((elen + 1 + nlen + 1) >= PATH_MAX) {
|
||||
ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0,
|
||||
"ngx_load_echkeys, name too long: %s with %s",
|
||||
"ngx_ssl_load_echkeys, name too long: %s with %s",
|
||||
dirname->data, den);
|
||||
continue;
|
||||
}
|
||||
|
@ -1624,9 +1635,9 @@ ngx_load_echkeys(ngx_ssl_t *ssl, ngx_str_t *dirname)
|
|||
if (!--maxkeyfiles) {
|
||||
/* so we don't loop forever, ever */
|
||||
ngx_ssl_error(NGX_LOG_ALERT, ssl->log, 0,
|
||||
"ngx_load_echkeys, too many files to check!");
|
||||
"ngx_ssl_load_echkeys, too many files to check!");
|
||||
ngx_ssl_error(NGX_LOG_ALERT, ssl->log, 0,
|
||||
"ngx_load_echkeys, hardcoded maxkeyfiles = 1024");
|
||||
"ngx_ssl_load_echkeys, hardcoded maxkeyfiles = 1024");
|
||||
return NGX_ERROR;
|
||||
}
|
||||
if (stat(privname, &thestat) == 0) {
|
||||
|
@ -1636,13 +1647,13 @@ ngx_load_echkeys(ngx_ssl_t *ssl, ngx_str_t *dirname)
|
|||
if (in != NULL
|
||||
&& 1 == OSSL_ECHSTORE_read_pem(es, in, is_retry_config)) {
|
||||
ngx_ssl_error(NGX_LOG_NOTICE, ssl->log, 0,
|
||||
"ngx_load_echkeys, worked for: %s",
|
||||
"ngx_ssl_load_echkeys, worked for: %s",
|
||||
privname);
|
||||
somekeyworked = 1;
|
||||
}
|
||||
else {
|
||||
ngx_ssl_error(NGX_LOG_ALERT, ssl->log, 0,
|
||||
"ngx_load_echkeys, failed for: %s",
|
||||
"ngx_ssl_load_echkeys, failed for: %s",
|
||||
privname);
|
||||
}
|
||||
BIO_free_all(in);
|
||||
|
@ -1653,51 +1664,54 @@ ngx_load_echkeys(ngx_ssl_t *ssl, ngx_str_t *dirname)
|
|||
|
||||
if (somekeyworked == 0) {
|
||||
ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0,
|
||||
"ngx_load_echkeys loaded no keys but ECH configured");
|
||||
"ngx_ssl_load_echkeys loaded no keys but ECH configured");
|
||||
return NGX_ERROR;
|
||||
}
|
||||
if (OSSL_ECHSTORE_num_keys(es, &numkeys) != 1) {
|
||||
ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0,
|
||||
"ngx_load_echkeys OSSL_ECHSTORE_num_keys failed");
|
||||
"ngx_ssl_load_echkeys OSSL_ECHSTORE_num_keys failed");
|
||||
return NGX_ERROR;
|
||||
}
|
||||
ngx_ssl_error(NGX_LOG_NOTICE, ssl->log, 0,
|
||||
"ngx_load_echkeys, total keys loaded: %d", numkeys);
|
||||
"ngx_ssl_load_echkeys, total keys loaded: %d", numkeys);
|
||||
if (1 != SSL_CTX_set1_echstore(ssl->ctx, es)) {
|
||||
OSSL_ECHSTORE_free(es);
|
||||
ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0,
|
||||
"ngx_load_echkeys: SSL_CTX_set1_echstore failed");
|
||||
"ngx_ssl_load_echkeys: SSL_CTX_set1_echstore failed");
|
||||
return NGX_ERROR;
|
||||
}
|
||||
OSSL_ECHSTORE_free(es);
|
||||
|
||||
return NGX_OK;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
ngx_int_t
|
||||
ngx_ssl_echkeydir(ngx_conf_t *cf, ngx_ssl_t *ssl, ngx_str_t *dir)
|
||||
{
|
||||
int rv = 0;
|
||||
|
||||
#ifndef OPENSSL_NO_ECH
|
||||
if (!dir) {
|
||||
return NGX_OK;
|
||||
}
|
||||
if (dir->len == 0) {
|
||||
return NGX_OK;
|
||||
}
|
||||
if (cf != NULL && ngx_conf_full_name(cf->cycle, dir, 1) != NGX_OK) {
|
||||
ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0, "ECH error at %d", __LINE__);
|
||||
if (ngx_conf_full_name(cf->cycle, dir, 1) != NGX_OK) {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
rv = ngx_load_echkeys(ssl, dir);
|
||||
if (rv != NGX_OK) {
|
||||
ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0, "ECH error at %d", __LINE__);
|
||||
return rv;
|
||||
|
||||
if (ngx_ssl_load_echkeys(ssl, dir) != NGX_OK) {
|
||||
ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0,
|
||||
"ngx_ssl_load_echkeys error for %s", dir->data);
|
||||
return NGX_ERROR;
|
||||
}
|
||||
return NGX_OK;
|
||||
}
|
||||
#else
|
||||
ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0,
|
||||
"ECH configured but not supported");
|
||||
return NGX_ERROR;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
ngx_int_t
|
||||
|
@ -5464,87 +5478,70 @@ ngx_ssl_get_cipher_name(ngx_connection_t *c, ngx_pool_t *pool, ngx_str_t *s)
|
|||
}
|
||||
|
||||
|
||||
#ifndef OPENSSL_NO_ECH
|
||||
ngx_int_t
|
||||
ngx_ssl_get_ech_status(ngx_connection_t *c, ngx_pool_t *pool, ngx_str_t *s)
|
||||
{
|
||||
int echrv = SSL_ECH_STATUS_NOT_TRIED;
|
||||
char *inner_sni = NULL, *outer_sni = NULL, buf[PATH_MAX];
|
||||
#ifndef OPENSSL_NO_ECH
|
||||
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:
|
||||
snprintf(buf,PATH_MAX, "NOT_TRIED");
|
||||
ngx_str_set(s, "NOT_TRIED");
|
||||
break;
|
||||
case SSL_ECH_STATUS_FAILED:
|
||||
snprintf(buf, PATH_MAX, "TRIED_BUT_FAILED");
|
||||
ngx_str_set(s, "FAILED");
|
||||
break;
|
||||
case SSL_ECH_STATUS_BAD_NAME:
|
||||
snprintf(buf, PATH_MAX, "WORKED_BAD_NAME");
|
||||
ngx_str_set(s, "WORKED_BAD_NAME");
|
||||
break;
|
||||
case SSL_ECH_STATUS_SUCCESS:
|
||||
snprintf(buf, PATH_MAX, "SUCCESS");
|
||||
ngx_str_set(s, "SUCCESS");
|
||||
break;
|
||||
case SSL_ECH_STATUS_GREASE:
|
||||
snprintf(buf, PATH_MAX, "GREASED");
|
||||
ngx_str_set(s, "GREASED");
|
||||
break;
|
||||
case SSL_ECH_STATUS_BACKEND:
|
||||
snprintf(buf, PATH_MAX, "INNER");
|
||||
ngx_str_set(s, "INNER");
|
||||
break;
|
||||
default:
|
||||
snprintf(buf, PATH_MAX, "ERROR");
|
||||
ngx_str_set(s, "STATUS_ERROR");
|
||||
break;
|
||||
}
|
||||
OPENSSL_free(inner_sni);
|
||||
OPENSSL_free(outer_sni);
|
||||
s->len = ngx_strlen(buf);
|
||||
s->data = ngx_pnalloc(pool, s->len);
|
||||
ngx_memcpy(s->data, buf, s->len);
|
||||
return NGX_OK;
|
||||
}
|
||||
|
||||
ngx_int_t
|
||||
ngx_ssl_get_ech_inner_sni(ngx_connection_t *c, ngx_pool_t *pool, ngx_str_t *s)
|
||||
{
|
||||
int echrv = SSL_ECH_STATUS_NOT_TRIED;
|
||||
char *inner_sni, *outer_sni;
|
||||
|
||||
echrv = SSL_ech_get1_status(c->ssl->connection, &inner_sni, &outer_sni);
|
||||
if (echrv == SSL_ECH_STATUS_SUCCESS && inner_sni) {
|
||||
s->len = strlen(inner_sni);
|
||||
s->data = ngx_pnalloc(pool, s->len);
|
||||
ngx_memcpy(s->data, inner_sni, s->len);
|
||||
} else {
|
||||
s->len = ngx_strlen("NONE");
|
||||
s->data = ngx_pnalloc(pool, s->len);
|
||||
ngx_memcpy(s->data, "NONE", s->len);
|
||||
}
|
||||
OPENSSL_free(inner_sni);
|
||||
OPENSSL_free(outer_sni);
|
||||
#endif
|
||||
return NGX_OK;
|
||||
}
|
||||
|
||||
ngx_int_t
|
||||
ngx_ssl_get_ech_outer_sni(ngx_connection_t *c, ngx_pool_t *pool, ngx_str_t *s)
|
||||
{
|
||||
int echrv = SSL_ECH_STATUS_NOT_TRIED;
|
||||
#ifndef OPENSSL_NO_ECH
|
||||
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 = strlen(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 = ngx_strlen("NONE");
|
||||
s->data = ngx_pnalloc(pool, s->len);
|
||||
ngx_memcpy(s->data, "NONE", s->len);
|
||||
ngx_str_set(s, "");
|
||||
}
|
||||
OPENSSL_free(inner_sni);
|
||||
OPENSSL_free(outer_sni);
|
||||
#endif
|
||||
return NGX_OK;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
ngx_int_t
|
||||
|
|
|
@ -34,14 +34,6 @@
|
|||
#include <openssl/x509.h>
|
||||
#include <openssl/x509v3.h>
|
||||
|
||||
/* check defines from <openssl/ssl.h> for ECH support */
|
||||
#if !defined(SSL_OP_ECH_GREASE)
|
||||
#define OPENSSL_NO_ECH
|
||||
#endif
|
||||
#ifndef OPENSSL_NO_ECH
|
||||
#include <openssl/ech.h>
|
||||
#endif
|
||||
|
||||
#define NGX_SSL_NAME "OpenSSL"
|
||||
|
||||
|
||||
|
@ -305,9 +297,7 @@ enum ssl_select_cert_result_t ngx_ssl_select_certificate(
|
|||
|
||||
ngx_int_t ngx_ssl_create_connection(ngx_ssl_t *ssl, ngx_connection_t *c,
|
||||
ngx_uint_t flags);
|
||||
#ifndef OPENSSL_NO_ECH
|
||||
ngx_int_t ngx_ssl_echkeydir(ngx_conf_t *cf, ngx_ssl_t *ssl, ngx_str_t *dir);
|
||||
#endif
|
||||
|
||||
void ngx_ssl_remove_cached_session(SSL_CTX *ssl, ngx_ssl_session_t *sess);
|
||||
ngx_int_t ngx_ssl_set_session(ngx_connection_t *c, ngx_ssl_session_t *session);
|
||||
|
@ -337,14 +327,10 @@ ngx_int_t ngx_ssl_get_ciphers(ngx_connection_t *c, ngx_pool_t *pool,
|
|||
ngx_str_t *s);
|
||||
ngx_int_t ngx_ssl_get_curve(ngx_connection_t *c, ngx_pool_t *pool,
|
||||
ngx_str_t *s);
|
||||
#ifndef OPENSSL_NO_ECH
|
||||
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_inner_sni(ngx_connection_t *c, ngx_pool_t *pool,
|
||||
ngx_str_t *s);
|
||||
ngx_int_t ngx_ssl_get_ech_outer_sni(ngx_connection_t *c, ngx_pool_t *pool,
|
||||
ngx_str_t *s);
|
||||
#endif
|
||||
ngx_int_t ngx_ssl_get_curves(ngx_connection_t *c, ngx_pool_t *pool,
|
||||
ngx_str_t *s);
|
||||
ngx_int_t ngx_ssl_get_session_id(ngx_connection_t *c, ngx_pool_t *pool,
|
||||
|
|
|
@ -129,10 +129,6 @@ static u_char *ngx_http_log_body_bytes_sent(ngx_http_request_t *r,
|
|||
u_char *buf, ngx_http_log_op_t *op);
|
||||
static u_char *ngx_http_log_request_length(ngx_http_request_t *r, u_char *buf,
|
||||
ngx_http_log_op_t *op);
|
||||
#ifndef OPENSSL_NO_ECH
|
||||
static u_char *ngx_http_log_ech_status(ngx_http_request_t *r, u_char *buf,
|
||||
ngx_http_log_op_t *op);
|
||||
#endif
|
||||
|
||||
static ngx_int_t ngx_http_log_variable_compile(ngx_conf_t *cf,
|
||||
ngx_http_log_op_t *op, ngx_str_t *value, ngx_uint_t escape);
|
||||
|
@ -234,10 +230,6 @@ static ngx_str_t ngx_http_combined_fmt =
|
|||
"\"$http_referer\" \"$http_user_agent\"");
|
||||
|
||||
|
||||
#ifndef OPENSSL_NO_ECH
|
||||
#define NGX_ECH_STATUS_LEN 140
|
||||
#endif
|
||||
|
||||
static ngx_http_log_var_t ngx_http_log_vars[] = {
|
||||
{ ngx_string("pipe"), 1, ngx_http_log_pipe },
|
||||
{ ngx_string("time_local"), sizeof("28/Sep/1970:12:00:00 +0600") - 1,
|
||||
|
@ -253,11 +245,6 @@ static ngx_http_log_var_t ngx_http_log_vars[] = {
|
|||
ngx_http_log_body_bytes_sent },
|
||||
{ ngx_string("request_length"), NGX_SIZE_T_LEN,
|
||||
ngx_http_log_request_length },
|
||||
#ifndef OPENSSL_NO_ECH
|
||||
{ ngx_string("ech_status"), NGX_ECH_STATUS_LEN,
|
||||
ngx_http_log_ech_status },
|
||||
#endif
|
||||
|
||||
{ ngx_null_string, 0, NULL }
|
||||
};
|
||||
|
||||
|
@ -923,76 +910,6 @@ ngx_http_log_request_length(ngx_http_request_t *r, u_char *buf,
|
|||
return ngx_sprintf(buf, "%O", r->request_length);
|
||||
}
|
||||
|
||||
#ifndef OPENSSL_NO_ECH
|
||||
static u_char *
|
||||
ngx_http_log_ech_status(ngx_http_request_t *r, u_char *buf,
|
||||
ngx_http_log_op_t *op)
|
||||
{
|
||||
int echstat = SSL_ECH_STATUS_NOT_TRIED;
|
||||
SSL *ssl = NULL;
|
||||
char *sni_ech = NULL, *sni_clr = NULL, *hostheader = NULL;
|
||||
u_char *sprv = NULL;
|
||||
const char *str;
|
||||
|
||||
/*
|
||||
* this is a bit oddly structured but is based on what was done for
|
||||
* lighttpd (by it's upstream maintainer) and what we did for haproxy
|
||||
* and re-use makes us all happy
|
||||
*/
|
||||
if (!r || !r->connection || !r->connection->ssl
|
||||
|| !r->connection->ssl->connection)
|
||||
return ngx_sprintf(buf, "ECH: no TLS connection");
|
||||
ssl = r->connection->ssl->connection;
|
||||
if (r->headers_in.server.len > 0)
|
||||
hostheader = (char *)r->headers_in.server.data;
|
||||
#define s(x) #x
|
||||
switch ((echstat = SSL_ech_get1_status(ssl, &sni_ech, &sni_clr))) {
|
||||
case SSL_ECH_STATUS_SUCCESS:
|
||||
str = s(SSL_ECH_STATUS_SUCCESS);
|
||||
break;
|
||||
case SSL_ECH_STATUS_NOT_TRIED:
|
||||
str = s(SSL_ECH_STATUS_NOT_TRIED);
|
||||
break;
|
||||
case SSL_ECH_STATUS_FAILED:
|
||||
str = s(SSL_ECH_STATUS_FAILED);
|
||||
break;
|
||||
case SSL_ECH_STATUS_BAD_NAME:
|
||||
str = s(SSL_ECH_STATUS_BAD_NAME);
|
||||
break;
|
||||
case SSL_ECH_STATUS_BAD_CALL:
|
||||
str = s(SSL_ECH_STATUS_BAD_CALL);
|
||||
break;
|
||||
case SSL_ECH_STATUS_GREASE:
|
||||
str = s(SSL_ECH_STATUS_GREASE);
|
||||
break;
|
||||
case SSL_ECH_STATUS_BACKEND:
|
||||
str = s(SSL_ECH_STATUS_BACKEND);
|
||||
break;
|
||||
default:
|
||||
str = "ECH status unknown";
|
||||
break;
|
||||
}
|
||||
#undef s
|
||||
/*
|
||||
* We output ECH status, then either the outer SNI or the host header (if
|
||||
* outer SNI is NULL) and the inner SNI if non-NULL.
|
||||
*/
|
||||
if (echstat != SSL_ECH_STATUS_SUCCESS) {
|
||||
OPENSSL_free(sni_clr);
|
||||
sni_clr = (char *)SSL_get_servername(ssl, TLSEXT_NAMETYPE_host_name);
|
||||
}
|
||||
if (sni_clr != NULL)
|
||||
hostheader = sni_clr;
|
||||
sprv = ngx_sprintf(buf, "ECH: %s/%s/%s", str,
|
||||
(hostheader == NULL ? "" : hostheader),
|
||||
(sni_ech == NULL ? "" : sni_ech));
|
||||
OPENSSL_free(sni_ech);
|
||||
if (echstat == SSL_ECH_STATUS_SUCCESS)
|
||||
OPENSSL_free(sni_clr);
|
||||
return sprv;
|
||||
}
|
||||
#endif
|
||||
|
||||
static ngx_int_t
|
||||
ngx_http_log_variable_compile(ngx_conf_t *cf, ngx_http_log_op_t *op,
|
||||
ngx_str_t *value, ngx_uint_t escape)
|
||||
|
|
|
@ -215,14 +215,12 @@ static ngx_command_t ngx_http_ssl_commands[] = {
|
|||
offsetof(ngx_http_ssl_srv_conf_t, session_tickets),
|
||||
NULL },
|
||||
|
||||
#ifndef OPENSSL_NO_ECH
|
||||
{ ngx_string("ssl_echkeydir"),
|
||||
NGX_HTTP_MAIN_CONF|NGX_CONF_TAKE1,
|
||||
ngx_conf_set_str_slot,
|
||||
NGX_HTTP_SRV_CONF_OFFSET,
|
||||
offsetof(ngx_http_ssl_srv_conf_t, echkeydir),
|
||||
NULL },
|
||||
#endif
|
||||
|
||||
{ ngx_string("ssl_session_ticket_key"),
|
||||
NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_CONF_TAKE1,
|
||||
|
@ -363,14 +361,12 @@ static ngx_http_variable_t ngx_http_ssl_vars[] = {
|
|||
|
||||
{ ngx_string("ssl_curve"), NULL, ngx_http_ssl_variable,
|
||||
(uintptr_t) ngx_ssl_get_curve, NGX_HTTP_VAR_CHANGEABLE, 0 },
|
||||
#ifndef OPENSSL_NO_ECH
|
||||
|
||||
{ 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_inner_sni"), NULL, ngx_http_ssl_variable,
|
||||
(uintptr_t) ngx_ssl_get_ech_inner_sni, NGX_HTTP_VAR_CHANGEABLE, 0 },
|
||||
|
||||
{ ngx_string("ssl_ech_outer_sni"), NULL, ngx_http_ssl_variable,
|
||||
(uintptr_t) ngx_ssl_get_ech_outer_sni, NGX_HTTP_VAR_CHANGEABLE, 0 },
|
||||
#endif
|
||||
|
||||
{ ngx_string("ssl_curves"), NULL, ngx_http_ssl_variable,
|
||||
(uintptr_t) ngx_ssl_get_curves, NGX_HTTP_VAR_CHANGEABLE, 0 },
|
||||
|
@ -642,9 +638,7 @@ ngx_http_ssl_create_srv_conf(ngx_conf_t *cf)
|
|||
* sscf->ocsp_responder = { 0, NULL };
|
||||
* sscf->stapling_file = { 0, NULL };
|
||||
* sscf->stapling_responder = { 0, NULL };
|
||||
* #ifndef OPENSSL_NO_ECH
|
||||
* sscf->echkeydir = { 0, NULL} ;
|
||||
* #endif
|
||||
*/
|
||||
|
||||
sscf->prefer_server_ciphers = NGX_CONF_UNSET;
|
||||
|
@ -711,9 +705,8 @@ ngx_http_ssl_merge_srv_conf(ngx_conf_t *cf, void *parent, void *child)
|
|||
ngx_conf_merge_ptr_value(conf->passwords, prev->passwords, NULL);
|
||||
|
||||
ngx_conf_merge_str_value(conf->dhparam, prev->dhparam, "");
|
||||
#ifndef OPENSSL_NO_ECH
|
||||
|
||||
ngx_conf_merge_str_value(conf->echkeydir, prev->echkeydir, "");
|
||||
#endif
|
||||
|
||||
ngx_conf_merge_str_value(conf->client_certificate, prev->client_certificate,
|
||||
"");
|
||||
|
@ -895,11 +888,9 @@ ngx_http_ssl_merge_srv_conf(ngx_conf_t *cf, void *parent, void *child)
|
|||
return NGX_CONF_ERROR;
|
||||
}
|
||||
|
||||
#ifndef OPENSSL_NO_ECH
|
||||
if (ngx_ssl_echkeydir(cf, &conf->ssl, &conf->echkeydir) != NGX_OK) {
|
||||
return NGX_CONF_ERROR;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (ngx_ssl_ecdh_curve(cf, &conf->ssl, &conf->ecdh_curve) != NGX_OK) {
|
||||
return NGX_CONF_ERROR;
|
||||
|
|
|
@ -42,9 +42,7 @@ typedef struct {
|
|||
ngx_ssl_cache_t *certificate_cache;
|
||||
|
||||
ngx_str_t dhparam;
|
||||
#ifndef OPENSSL_NO_ECH
|
||||
ngx_str_t echkeydir;
|
||||
#endif
|
||||
ngx_str_t ecdh_curve;
|
||||
ngx_str_t client_certificate;
|
||||
ngx_str_t trusted_certificate;
|
||||
|
|
Loading…
Reference in New Issue