Address validation using NEW_TOKEN frame.

This commit is contained in:
Sergey Kandaurov 2020-05-14 15:47:24 +03:00
parent ad2289e70e
commit 9b1800d09a
3 changed files with 86 additions and 1 deletions

View File

@ -187,6 +187,7 @@ static ngx_int_t ngx_quic_payload_handler(ngx_connection_t *c,
static ngx_int_t ngx_quic_send_ack(ngx_connection_t *c, ngx_quic_header_t *pkt);
static ngx_int_t ngx_quic_send_cc(ngx_connection_t *c,
enum ssl_encryption_level_t level, ngx_uint_t err);
static ngx_int_t ngx_quic_send_new_token(ngx_connection_t *c);
static ngx_int_t ngx_quic_handle_ack_frame(ngx_connection_t *c,
ngx_quic_header_t *pkt, ngx_quic_ack_frame_t *f);
@ -544,6 +545,7 @@ static ngx_int_t
ngx_quic_new_connection(ngx_connection_t *c, ngx_ssl_t *ssl, ngx_quic_tp_t *tp,
ngx_quic_header_t *pkt, ngx_connection_handler_pt handler)
{
ngx_int_t rc;
ngx_uint_t i;
ngx_quic_tp_t *ctp;
ngx_quic_secrets_t *keys;
@ -642,7 +644,22 @@ ngx_quic_new_connection(ngx_connection_t *c, ngx_ssl_t *ssl, ngx_quic_tp_t *tp,
return NGX_ERROR;
}
if (tp->retry) {
if (pkt->token.len) {
rc = ngx_quic_validate_token(c, pkt);
if (rc == NGX_ERROR) {
ngx_log_error(NGX_LOG_INFO, c->log, 0, "quic invalid token");
return NGX_ERROR;
}
if (rc == NGX_DECLINED) {
ngx_log_error(NGX_LOG_INFO, c->log, 0, "quic expired token");
return ngx_quic_retry(c);
}
/* NGX_OK */
} else if (tp->retry) {
return ngx_quic_retry(c);
}
@ -1950,6 +1967,35 @@ ngx_quic_send_cc(ngx_connection_t *c, enum ssl_encryption_level_t level,
}
static ngx_int_t
ngx_quic_send_new_token(ngx_connection_t *c)
{
ngx_str_t token;
ngx_quic_frame_t *frame;
if (!c->quic->tp.retry) {
return NGX_OK;
}
if (ngx_quic_new_token(c, &token) != NGX_OK) {
return NGX_ERROR;
}
frame = ngx_quic_alloc_frame(c, 0);
if (frame == NULL) {
return NGX_ERROR;
}
frame->level = ssl_encryption_application;
frame->type = NGX_QUIC_FT_NEW_TOKEN;
frame->u.token.length = token.len;
frame->u.token.data = token.data;
ngx_sprintf(frame->info, "NEW_TOKEN");
ngx_quic_queue_frame(c->quic, frame);
return NGX_OK;
}
static ngx_int_t
ngx_quic_handle_ack_frame(ngx_connection_t *c, ngx_quic_header_t *pkt,
ngx_quic_ack_frame_t *ack)
@ -2405,6 +2451,10 @@ ngx_quic_crypto_input(ngx_connection_t *c, ngx_quic_frame_t *frame, void *data)
ngx_sprintf(frame->info, "HANDSHAKE DONE on handshake completed");
ngx_quic_queue_frame(c->quic, frame);
if (ngx_quic_send_new_token(c) != NGX_OK) {
return NGX_ERROR;
}
/*
* Generating next keys before a key update is received.
* See quic-tls 9.4 Header Protection Timing Side-Channels.

View File

@ -72,6 +72,8 @@ static size_t ngx_quic_create_ack(u_char *p, ngx_quic_ack_frame_t *ack);
static size_t ngx_quic_create_crypto(u_char *p,
ngx_quic_crypto_frame_t *crypto);
static size_t ngx_quic_create_hs_done(u_char *p);
static size_t ngx_quic_create_new_token(u_char *p,
ngx_quic_new_token_frame_t *token);
static size_t ngx_quic_create_stream(u_char *p, ngx_quic_stream_frame_t *sf);
static size_t ngx_quic_create_max_streams(u_char *p,
ngx_quic_max_streams_frame_t *ms);
@ -1128,6 +1130,9 @@ ngx_quic_create_frame(u_char *p, ngx_quic_frame_t *f)
case NGX_QUIC_FT_HANDSHAKE_DONE:
return ngx_quic_create_hs_done(p);
case NGX_QUIC_FT_NEW_TOKEN:
return ngx_quic_create_new_token(p, &f->u.token);
case NGX_QUIC_FT_STREAM0:
case NGX_QUIC_FT_STREAM1:
case NGX_QUIC_FT_STREAM2:
@ -1231,6 +1236,30 @@ ngx_quic_create_hs_done(u_char *p)
}
static size_t
ngx_quic_create_new_token(u_char *p, ngx_quic_new_token_frame_t *token)
{
size_t len;
u_char *start;
if (p == NULL) {
len = ngx_quic_varint_len(NGX_QUIC_FT_NEW_TOKEN);
len += ngx_quic_varint_len(token->length);
len += token->length;
return len;
}
start = p;
ngx_quic_build_int(&p, NGX_QUIC_FT_NEW_TOKEN);
ngx_quic_build_int(&p, token->length);
p = ngx_cpymem(p, token->data, token->length);
return p - start;
}
static size_t
ngx_quic_create_stream(u_char *p, ngx_quic_stream_frame_t *sf)
{

View File

@ -132,6 +132,11 @@ typedef struct {
} ngx_quic_new_conn_id_frame_t;
typedef struct {
uint64_t length;
u_char *data;
} ngx_quic_new_token_frame_t;
/*
* common layout for CRYPTO and STREAM frames;
* conceptually, CRYPTO frame is also a stream
@ -242,6 +247,7 @@ struct ngx_quic_frame_s {
ngx_quic_crypto_frame_t crypto;
ngx_quic_ordered_frame_t ord;
ngx_quic_new_conn_id_frame_t ncid;
ngx_quic_new_token_frame_t token;
ngx_quic_stream_frame_t stream;
ngx_quic_max_data_frame_t max_data;
ngx_quic_close_frame_t close;