Mercurial > hg > nginx
comparison src/stream/ngx_stream_quic_module.c @ 8694:cef042935003 quic
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.
author | Vladimir Homutov <vl@nginx.com> |
---|---|
date | Mon, 08 Feb 2021 16:49:33 +0300 |
parents | dffb66fb783b |
children | b4e6b7049984 |
comparison
equal
deleted
inserted
replaced
8693:3956bbf91002 | 8694:cef042935003 |
---|---|
6 | 6 |
7 | 7 |
8 #include <ngx_config.h> | 8 #include <ngx_config.h> |
9 #include <ngx_core.h> | 9 #include <ngx_core.h> |
10 #include <ngx_stream.h> | 10 #include <ngx_stream.h> |
11 | |
12 #include <ngx_event_quic_protection.h> | |
11 | 13 |
12 | 14 |
13 static ngx_int_t ngx_stream_variable_quic(ngx_stream_session_t *s, | 15 static ngx_int_t ngx_stream_variable_quic(ngx_stream_session_t *s, |
14 ngx_stream_variable_value_t *v, uintptr_t data); | 16 ngx_stream_variable_value_t *v, uintptr_t data); |
15 static ngx_int_t ngx_stream_quic_add_variables(ngx_conf_t *cf); | 17 static ngx_int_t ngx_stream_quic_add_variables(ngx_conf_t *cf); |
18 void *child); | 20 void *child); |
19 static char *ngx_stream_quic_max_ack_delay(ngx_conf_t *cf, void *post, | 21 static char *ngx_stream_quic_max_ack_delay(ngx_conf_t *cf, void *post, |
20 void *data); | 22 void *data); |
21 static char *ngx_stream_quic_max_udp_payload_size(ngx_conf_t *cf, void *post, | 23 static char *ngx_stream_quic_max_udp_payload_size(ngx_conf_t *cf, void *post, |
22 void *data); | 24 void *data); |
25 static char *ngx_stream_quic_host_key(ngx_conf_t *cf, ngx_command_t *cmd, | |
26 void *conf); | |
23 | 27 |
24 | 28 |
25 static ngx_conf_post_t ngx_stream_quic_max_ack_delay_post = | 29 static ngx_conf_post_t ngx_stream_quic_max_ack_delay_post = |
26 { ngx_stream_quic_max_ack_delay }; | 30 { ngx_stream_quic_max_ack_delay }; |
27 static ngx_conf_post_t ngx_stream_quic_max_udp_payload_size_post = | 31 static ngx_conf_post_t ngx_stream_quic_max_udp_payload_size_post = |
124 ngx_conf_set_flag_slot, | 128 ngx_conf_set_flag_slot, |
125 NGX_STREAM_SRV_CONF_OFFSET, | 129 NGX_STREAM_SRV_CONF_OFFSET, |
126 offsetof(ngx_quic_conf_t, retry), | 130 offsetof(ngx_quic_conf_t, retry), |
127 NULL }, | 131 NULL }, |
128 | 132 |
129 { ngx_string("quic_stateless_reset_token_key"), | 133 { ngx_string("quic_host_key"), |
130 NGX_STREAM_MAIN_CONF|NGX_STREAM_SRV_CONF|NGX_CONF_FLAG, | 134 NGX_STREAM_MAIN_CONF|NGX_STREAM_SRV_CONF|NGX_CONF_FLAG, |
131 ngx_conf_set_str_slot, | 135 ngx_stream_quic_host_key, |
132 NGX_STREAM_SRV_CONF_OFFSET, | 136 NGX_STREAM_SRV_CONF_OFFSET, |
133 offsetof(ngx_quic_conf_t, sr_token_key), | 137 0, |
134 NULL }, | 138 NULL }, |
135 | 139 |
136 ngx_null_command | 140 ngx_null_command |
137 }; | 141 }; |
138 | 142 |
170 { ngx_string("quic"), NULL, ngx_stream_variable_quic, 0, 0, 0 }, | 174 { ngx_string("quic"), NULL, ngx_stream_variable_quic, 0, 0, 0 }, |
171 | 175 |
172 ngx_stream_null_variable | 176 ngx_stream_null_variable |
173 }; | 177 }; |
174 | 178 |
179 static ngx_str_t ngx_stream_quic_salt = ngx_string("ngx_quic"); | |
180 | |
175 | 181 |
176 static ngx_int_t | 182 static ngx_int_t |
177 ngx_stream_variable_quic(ngx_stream_session_t *s, | 183 ngx_stream_variable_quic(ngx_stream_session_t *s, |
178 ngx_stream_variable_value_t *v, uintptr_t data) | 184 ngx_stream_variable_value_t *v, uintptr_t data) |
179 { | 185 { |
227 * | 233 * |
228 * conf->tp.original_dcid = { 0, NULL }; | 234 * conf->tp.original_dcid = { 0, NULL }; |
229 * conf->tp.initial_scid = { 0, NULL }; | 235 * conf->tp.initial_scid = { 0, NULL }; |
230 * conf->tp.retry_scid = { 0, NULL }; | 236 * conf->tp.retry_scid = { 0, NULL }; |
231 * conf->tp.preferred_address = NULL | 237 * conf->tp.preferred_address = NULL |
232 * conf->sr_token_key = { 0, NULL } | 238 * conf->host_key = { 0, NULL } |
233 * conf->require_alpn = 0; | 239 * conf->require_alpn = 0; |
234 */ | 240 */ |
235 | 241 |
236 conf->tp.max_idle_timeout = NGX_CONF_UNSET_MSEC; | 242 conf->tp.max_idle_timeout = NGX_CONF_UNSET_MSEC; |
237 conf->tp.max_ack_delay = NGX_CONF_UNSET_MSEC; | 243 conf->tp.max_ack_delay = NGX_CONF_UNSET_MSEC; |
303 ngx_conf_merge_uint_value(conf->tp.active_connection_id_limit, | 309 ngx_conf_merge_uint_value(conf->tp.active_connection_id_limit, |
304 prev->tp.active_connection_id_limit, 2); | 310 prev->tp.active_connection_id_limit, 2); |
305 | 311 |
306 ngx_conf_merge_value(conf->retry, prev->retry, 0); | 312 ngx_conf_merge_value(conf->retry, prev->retry, 0); |
307 | 313 |
308 if (RAND_bytes(conf->token_key, sizeof(conf->token_key)) <= 0) { | 314 ngx_conf_merge_str_value(conf->host_key, prev->host_key, ""); |
309 return NGX_CONF_ERROR; | 315 |
310 } | 316 if (conf->host_key.len == 0) { |
311 | 317 |
312 ngx_conf_merge_str_value(conf->sr_token_key, prev->sr_token_key, ""); | 318 conf->host_key.len = NGX_QUIC_DEFAULT_HOST_KEY_LEN; |
313 | 319 conf->host_key.data = ngx_palloc(cf->pool, conf->host_key.len); |
314 if (conf->sr_token_key.len == 0) { | 320 if (conf->host_key.data == NULL) { |
315 conf->sr_token_key.len = NGX_QUIC_DEFAULT_SRT_KEY_LEN; | |
316 | |
317 conf->sr_token_key.data = ngx_pnalloc(cf->pool, conf->sr_token_key.len); | |
318 if (conf->sr_token_key.data == NULL) { | |
319 return NGX_CONF_ERROR; | 321 return NGX_CONF_ERROR; |
320 } | 322 } |
321 | 323 |
322 if (RAND_bytes(conf->sr_token_key.data, conf->sr_token_key.len) <= 0) { | 324 if (RAND_bytes(conf->host_key.data, NGX_QUIC_DEFAULT_HOST_KEY_LEN) |
325 <= 0) | |
326 { | |
323 return NGX_CONF_ERROR; | 327 return NGX_CONF_ERROR; |
324 } | 328 } |
329 } | |
330 | |
331 if (ngx_quic_derive_key(cf->log, "av_token_key", | |
332 &conf->host_key, &ngx_stream_quic_salt, | |
333 conf->av_token_key, NGX_QUIC_AV_KEY_LEN) | |
334 != NGX_OK) | |
335 { | |
336 return NGX_CONF_ERROR; | |
337 } | |
338 | |
339 if (ngx_quic_derive_key(cf->log, "sr_token_key", | |
340 &conf->host_key, &ngx_stream_quic_salt, | |
341 conf->sr_token_key, NGX_QUIC_SR_KEY_LEN) | |
342 != NGX_OK) | |
343 { | |
344 return NGX_CONF_ERROR; | |
325 } | 345 } |
326 | 346 |
327 scf = ngx_stream_conf_get_module_srv_conf(cf, ngx_stream_ssl_module); | 347 scf = ngx_stream_conf_get_module_srv_conf(cf, ngx_stream_ssl_module); |
328 conf->ssl = &scf->ssl; | 348 conf->ssl = &scf->ssl; |
329 | 349 |
364 return NGX_CONF_ERROR; | 384 return NGX_CONF_ERROR; |
365 } | 385 } |
366 | 386 |
367 return NGX_CONF_OK; | 387 return NGX_CONF_OK; |
368 } | 388 } |
389 | |
390 | |
391 static char * | |
392 ngx_stream_quic_host_key(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) | |
393 { | |
394 ngx_quic_conf_t *qcf = conf; | |
395 | |
396 u_char *buf; | |
397 size_t size; | |
398 ssize_t n; | |
399 ngx_str_t *value; | |
400 ngx_file_t file; | |
401 ngx_file_info_t fi; | |
402 | |
403 if (qcf->host_key.len) { | |
404 return "is duplicate"; | |
405 } | |
406 | |
407 buf = NULL; | |
408 #if (NGX_SUPPRESS_WARN) | |
409 size = 0; | |
410 #endif | |
411 | |
412 value = cf->args->elts; | |
413 | |
414 if (ngx_conf_full_name(cf->cycle, &value[1], 1) != NGX_OK) { | |
415 return NGX_CONF_ERROR; | |
416 } | |
417 | |
418 ngx_memzero(&file, sizeof(ngx_file_t)); | |
419 file.name = value[1]; | |
420 file.log = cf->log; | |
421 | |
422 file.fd = ngx_open_file(file.name.data, NGX_FILE_RDONLY, NGX_FILE_OPEN, 0); | |
423 | |
424 if (file.fd == NGX_INVALID_FILE) { | |
425 ngx_conf_log_error(NGX_LOG_EMERG, cf, ngx_errno, | |
426 ngx_open_file_n " \"%V\" failed", &file.name); | |
427 return NGX_CONF_ERROR; | |
428 } | |
429 | |
430 if (ngx_fd_info(file.fd, &fi) == NGX_FILE_ERROR) { | |
431 ngx_conf_log_error(NGX_LOG_CRIT, cf, ngx_errno, | |
432 ngx_fd_info_n " \"%V\" failed", &file.name); | |
433 goto failed; | |
434 } | |
435 | |
436 size = ngx_file_size(&fi); | |
437 | |
438 if (size == 0) { | |
439 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, | |
440 "\"%V\" zero key size", &file.name); | |
441 goto failed; | |
442 } | |
443 | |
444 buf = ngx_pnalloc(cf->pool, size); | |
445 if (buf == NULL) { | |
446 goto failed; | |
447 } | |
448 | |
449 n = ngx_read_file(&file, buf, size, 0); | |
450 | |
451 if (n == NGX_ERROR) { | |
452 ngx_conf_log_error(NGX_LOG_CRIT, cf, ngx_errno, | |
453 ngx_read_file_n " \"%V\" failed", &file.name); | |
454 goto failed; | |
455 } | |
456 | |
457 if ((size_t) n != size) { | |
458 ngx_conf_log_error(NGX_LOG_CRIT, cf, 0, | |
459 ngx_read_file_n " \"%V\" returned only " | |
460 "%z bytes instead of %uz", &file.name, n, size); | |
461 goto failed; | |
462 } | |
463 | |
464 qcf->host_key.data = buf; | |
465 qcf->host_key.len = n; | |
466 | |
467 if (ngx_close_file(file.fd) == NGX_FILE_ERROR) { | |
468 ngx_log_error(NGX_LOG_ALERT, cf->log, ngx_errno, | |
469 ngx_close_file_n " \"%V\" failed", &file.name); | |
470 } | |
471 | |
472 return NGX_CONF_OK; | |
473 | |
474 failed: | |
475 | |
476 if (ngx_close_file(file.fd) == NGX_FILE_ERROR) { | |
477 ngx_log_error(NGX_LOG_ALERT, cf->log, ngx_errno, | |
478 ngx_close_file_n " \"%V\" failed", &file.name); | |
479 } | |
480 | |
481 if (buf) { | |
482 ngx_explicit_memzero(buf, size); | |
483 } | |
484 | |
485 return NGX_CONF_ERROR; | |
486 } |