diff options
author | Vladimir Homutov <vl@nginx.com> | 2021-02-08 16:49:33 +0300 |
---|---|---|
committer | Vladimir Homutov <vl@nginx.com> | 2021-02-08 16:49:33 +0300 |
commit | eab61bfc22b583031b5a6f42f9c277223ce18672 (patch) | |
tree | 665e150d9665600dd5b8280c7ec24501ba40bb4f /src/stream/ngx_stream_quic_module.c | |
parent | 040a23bfc316403fa374e55ce52de70ace3cff38 (diff) | |
download | nginx-eab61bfc22b583031b5a6f42f9c277223ce18672.tar.gz nginx-eab61bfc22b583031b5a6f42f9c277223ce18672.zip |
QUIC: the "quic_host_key" directive.
The token generation in QUIC is reworked. Single host key is used to generate
all required keys of needed sizes using HKDF.
The "quic_stateless_reset_token_key" directive is removed. Instead, the
"quic_host_key" directive is used, which reads key from file, or sets it
to random bytes if not specified.
Diffstat (limited to 'src/stream/ngx_stream_quic_module.c')
-rw-r--r-- | src/stream/ngx_stream_quic_module.c | 146 |
1 files changed, 132 insertions, 14 deletions
diff --git a/src/stream/ngx_stream_quic_module.c b/src/stream/ngx_stream_quic_module.c index e6466bba4..6a67680b2 100644 --- a/src/stream/ngx_stream_quic_module.c +++ b/src/stream/ngx_stream_quic_module.c @@ -9,6 +9,8 @@ #include <ngx_core.h> #include <ngx_stream.h> +#include <ngx_event_quic_protection.h> + static ngx_int_t ngx_stream_variable_quic(ngx_stream_session_t *s, ngx_stream_variable_value_t *v, uintptr_t data); @@ -20,6 +22,8 @@ static char *ngx_stream_quic_max_ack_delay(ngx_conf_t *cf, void *post, void *data); static char *ngx_stream_quic_max_udp_payload_size(ngx_conf_t *cf, void *post, void *data); +static char *ngx_stream_quic_host_key(ngx_conf_t *cf, ngx_command_t *cmd, + void *conf); static ngx_conf_post_t ngx_stream_quic_max_ack_delay_post = @@ -126,11 +130,11 @@ static ngx_command_t ngx_stream_quic_commands[] = { offsetof(ngx_quic_conf_t, retry), NULL }, - { ngx_string("quic_stateless_reset_token_key"), + { ngx_string("quic_host_key"), NGX_STREAM_MAIN_CONF|NGX_STREAM_SRV_CONF|NGX_CONF_FLAG, - ngx_conf_set_str_slot, + ngx_stream_quic_host_key, NGX_STREAM_SRV_CONF_OFFSET, - offsetof(ngx_quic_conf_t, sr_token_key), + 0, NULL }, ngx_null_command @@ -172,6 +176,8 @@ static ngx_stream_variable_t ngx_stream_quic_vars[] = { ngx_stream_null_variable }; +static ngx_str_t ngx_stream_quic_salt = ngx_string("ngx_quic"); + static ngx_int_t ngx_stream_variable_quic(ngx_stream_session_t *s, @@ -229,7 +235,7 @@ ngx_stream_quic_create_srv_conf(ngx_conf_t *cf) * conf->tp.initial_scid = { 0, NULL }; * conf->tp.retry_scid = { 0, NULL }; * conf->tp.preferred_address = NULL - * conf->sr_token_key = { 0, NULL } + * conf->host_key = { 0, NULL } * conf->require_alpn = 0; */ @@ -305,25 +311,39 @@ ngx_stream_quic_merge_srv_conf(ngx_conf_t *cf, void *parent, void *child) ngx_conf_merge_value(conf->retry, prev->retry, 0); - if (RAND_bytes(conf->token_key, sizeof(conf->token_key)) <= 0) { - return NGX_CONF_ERROR; - } + ngx_conf_merge_str_value(conf->host_key, prev->host_key, ""); - ngx_conf_merge_str_value(conf->sr_token_key, prev->sr_token_key, ""); + if (conf->host_key.len == 0) { - if (conf->sr_token_key.len == 0) { - conf->sr_token_key.len = NGX_QUIC_DEFAULT_SRT_KEY_LEN; - - conf->sr_token_key.data = ngx_pnalloc(cf->pool, conf->sr_token_key.len); - if (conf->sr_token_key.data == NULL) { + conf->host_key.len = NGX_QUIC_DEFAULT_HOST_KEY_LEN; + conf->host_key.data = ngx_palloc(cf->pool, conf->host_key.len); + if (conf->host_key.data == NULL) { return NGX_CONF_ERROR; } - if (RAND_bytes(conf->sr_token_key.data, conf->sr_token_key.len) <= 0) { + if (RAND_bytes(conf->host_key.data, NGX_QUIC_DEFAULT_HOST_KEY_LEN) + <= 0) + { return NGX_CONF_ERROR; } } + if (ngx_quic_derive_key(cf->log, "av_token_key", + &conf->host_key, &ngx_stream_quic_salt, + conf->av_token_key, NGX_QUIC_AV_KEY_LEN) + != NGX_OK) + { + return NGX_CONF_ERROR; + } + + if (ngx_quic_derive_key(cf->log, "sr_token_key", + &conf->host_key, &ngx_stream_quic_salt, + conf->sr_token_key, NGX_QUIC_SR_KEY_LEN) + != NGX_OK) + { + return NGX_CONF_ERROR; + } + scf = ngx_stream_conf_get_module_srv_conf(cf, ngx_stream_ssl_module); conf->ssl = &scf->ssl; @@ -366,3 +386,101 @@ ngx_stream_quic_max_udp_payload_size(ngx_conf_t *cf, void *post, void *data) return NGX_CONF_OK; } + + +static char * +ngx_stream_quic_host_key(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) +{ + ngx_quic_conf_t *qcf = conf; + + u_char *buf; + size_t size; + ssize_t n; + ngx_str_t *value; + ngx_file_t file; + ngx_file_info_t fi; + + if (qcf->host_key.len) { + return "is duplicate"; + } + + buf = NULL; +#if (NGX_SUPPRESS_WARN) + size = 0; +#endif + + value = cf->args->elts; + + if (ngx_conf_full_name(cf->cycle, &value[1], 1) != NGX_OK) { + return NGX_CONF_ERROR; + } + + ngx_memzero(&file, sizeof(ngx_file_t)); + file.name = value[1]; + file.log = cf->log; + + file.fd = ngx_open_file(file.name.data, NGX_FILE_RDONLY, NGX_FILE_OPEN, 0); + + if (file.fd == NGX_INVALID_FILE) { + ngx_conf_log_error(NGX_LOG_EMERG, cf, ngx_errno, + ngx_open_file_n " \"%V\" failed", &file.name); + return NGX_CONF_ERROR; + } + + if (ngx_fd_info(file.fd, &fi) == NGX_FILE_ERROR) { + ngx_conf_log_error(NGX_LOG_CRIT, cf, ngx_errno, + ngx_fd_info_n " \"%V\" failed", &file.name); + goto failed; + } + + size = ngx_file_size(&fi); + + if (size == 0) { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "\"%V\" zero key size", &file.name); + goto failed; + } + + buf = ngx_pnalloc(cf->pool, size); + if (buf == NULL) { + goto failed; + } + + n = ngx_read_file(&file, buf, size, 0); + + if (n == NGX_ERROR) { + ngx_conf_log_error(NGX_LOG_CRIT, cf, ngx_errno, + ngx_read_file_n " \"%V\" failed", &file.name); + goto failed; + } + + if ((size_t) n != size) { + ngx_conf_log_error(NGX_LOG_CRIT, cf, 0, + ngx_read_file_n " \"%V\" returned only " + "%z bytes instead of %uz", &file.name, n, size); + goto failed; + } + + qcf->host_key.data = buf; + qcf->host_key.len = n; + + if (ngx_close_file(file.fd) == NGX_FILE_ERROR) { + ngx_log_error(NGX_LOG_ALERT, cf->log, ngx_errno, + ngx_close_file_n " \"%V\" failed", &file.name); + } + + return NGX_CONF_OK; + +failed: + + if (ngx_close_file(file.fd) == NGX_FILE_ERROR) { + ngx_log_error(NGX_LOG_ALERT, cf->log, ngx_errno, + ngx_close_file_n " \"%V\" failed", &file.name); + } + + if (buf) { + ngx_explicit_memzero(buf, size); + } + + return NGX_CONF_ERROR; +} |