Parsing of truncated packet numbers.

For sample decoding algorithm, see quic-transport-27#appendix-A.
This commit is contained in:
Sergey Kandaurov 2020-04-16 12:46:48 +03:00
parent 29b6ad00a2
commit df01c0c13c
3 changed files with 63 additions and 18 deletions

View File

@ -65,8 +65,9 @@ typedef struct {
ngx_quic_secret_t client_secret; ngx_quic_secret_t client_secret;
ngx_quic_secret_t server_secret; ngx_quic_secret_t server_secret;
uint64_t pnum; uint64_t pnum; /* packet number to send */
uint64_t largest_ack; /* number received from peer */ uint64_t largest_ack; /* number received from peer */
uint64_t largest_pn; /* number received from peer */
ngx_queue_t frames; ngx_queue_t frames;
ngx_queue_t sent; ngx_queue_t sent;
@ -473,6 +474,7 @@ ngx_quic_new_connection(ngx_connection_t *c, ngx_ssl_t *ssl, ngx_quic_tp_t *tp,
ngx_uint_t i; ngx_uint_t i;
ngx_quic_tp_t *ctp; ngx_quic_tp_t *ctp;
ngx_quic_secrets_t *keys; ngx_quic_secrets_t *keys;
ngx_quic_send_ctx_t *ctx;
ngx_quic_connection_t *qc; ngx_quic_connection_t *qc;
static u_char buf[NGX_QUIC_DEFAULT_MAX_PACKET_SIZE]; static u_char buf[NGX_QUIC_DEFAULT_MAX_PACKET_SIZE];
@ -510,6 +512,7 @@ ngx_quic_new_connection(ngx_connection_t *c, ngx_ssl_t *ssl, ngx_quic_tp_t *tp,
for (i = 0; i < NGX_QUIC_SEND_CTX_LAST; i++) { for (i = 0; i < NGX_QUIC_SEND_CTX_LAST; i++) {
ngx_queue_init(&qc->send_ctx[i].frames); ngx_queue_init(&qc->send_ctx[i].frames);
ngx_queue_init(&qc->send_ctx[i].sent); ngx_queue_init(&qc->send_ctx[i].sent);
qc->send_ctx[i].largest_pn = (uint64_t) -1;
} }
for (i = 0; i < NGX_QUIC_ENCRYPTION_LAST; i++) { for (i = 0; i < NGX_QUIC_ENCRYPTION_LAST; i++) {
@ -574,7 +577,9 @@ ngx_quic_new_connection(ngx_connection_t *c, ngx_ssl_t *ssl, ngx_quic_tp_t *tp,
pkt->level = ssl_encryption_initial; pkt->level = ssl_encryption_initial;
pkt->plaintext = buf; pkt->plaintext = buf;
if (ngx_quic_decrypt(pkt, NULL) != NGX_OK) { ctx = ngx_quic_get_send_ctx(qc, pkt->level);
if (ngx_quic_decrypt(pkt, NULL, &ctx->largest_pn) != NGX_OK) {
return NGX_ERROR; return NGX_ERROR;
} }
@ -907,9 +912,10 @@ ngx_quic_input(ngx_connection_t *c, ngx_buf_t *b)
static ngx_int_t static ngx_int_t
ngx_quic_initial_input(ngx_connection_t *c, ngx_quic_header_t *pkt) ngx_quic_initial_input(ngx_connection_t *c, ngx_quic_header_t *pkt)
{ {
ngx_ssl_conn_t *ssl_conn; ngx_ssl_conn_t *ssl_conn;
ngx_quic_secrets_t *keys; ngx_quic_secrets_t *keys;
static u_char buf[NGX_QUIC_DEFAULT_MAX_PACKET_SIZE]; ngx_quic_send_ctx_t *ctx;
static u_char buf[NGX_QUIC_DEFAULT_MAX_PACKET_SIZE];
c->log->action = "processing initial quic packet"; c->log->action = "processing initial quic packet";
@ -929,7 +935,9 @@ ngx_quic_initial_input(ngx_connection_t *c, ngx_quic_header_t *pkt)
pkt->level = ssl_encryption_initial; pkt->level = ssl_encryption_initial;
pkt->plaintext = buf; pkt->plaintext = buf;
if (ngx_quic_decrypt(pkt, ssl_conn) != NGX_OK) { ctx = ngx_quic_get_send_ctx(c->quic, pkt->level);
if (ngx_quic_decrypt(pkt, ssl_conn, &ctx->largest_pn) != NGX_OK) {
return NGX_ERROR; return NGX_ERROR;
} }
@ -941,6 +949,7 @@ static ngx_int_t
ngx_quic_handshake_input(ngx_connection_t *c, ngx_quic_header_t *pkt) ngx_quic_handshake_input(ngx_connection_t *c, ngx_quic_header_t *pkt)
{ {
ngx_quic_secrets_t *keys; ngx_quic_secrets_t *keys;
ngx_quic_send_ctx_t *ctx;
ngx_quic_connection_t *qc; ngx_quic_connection_t *qc;
static u_char buf[NGX_QUIC_DEFAULT_MAX_PACKET_SIZE]; static u_char buf[NGX_QUIC_DEFAULT_MAX_PACKET_SIZE];
@ -995,7 +1004,9 @@ ngx_quic_handshake_input(ngx_connection_t *c, ngx_quic_header_t *pkt)
pkt->level = ssl_encryption_handshake; pkt->level = ssl_encryption_handshake;
pkt->plaintext = buf; pkt->plaintext = buf;
if (ngx_quic_decrypt(pkt, c->ssl->connection) != NGX_OK) { ctx = ngx_quic_get_send_ctx(qc, pkt->level);
if (ngx_quic_decrypt(pkt, c->ssl->connection, &ctx->largest_pn) != NGX_OK) {
return NGX_ERROR; return NGX_ERROR;
} }
@ -1007,6 +1018,7 @@ static ngx_int_t
ngx_quic_early_input(ngx_connection_t *c, ngx_quic_header_t *pkt) ngx_quic_early_input(ngx_connection_t *c, ngx_quic_header_t *pkt)
{ {
ngx_quic_secrets_t *keys; ngx_quic_secrets_t *keys;
ngx_quic_send_ctx_t *ctx;
ngx_quic_connection_t *qc; ngx_quic_connection_t *qc;
static u_char buf[NGX_QUIC_DEFAULT_MAX_PACKET_SIZE]; static u_char buf[NGX_QUIC_DEFAULT_MAX_PACKET_SIZE];
@ -1060,7 +1072,9 @@ ngx_quic_early_input(ngx_connection_t *c, ngx_quic_header_t *pkt)
pkt->level = ssl_encryption_early_data; pkt->level = ssl_encryption_early_data;
pkt->plaintext = buf; pkt->plaintext = buf;
if (ngx_quic_decrypt(pkt, c->ssl->connection) != NGX_OK) { ctx = ngx_quic_get_send_ctx(qc, pkt->level);
if (ngx_quic_decrypt(pkt, c->ssl->connection, &ctx->largest_pn) != NGX_OK) {
return NGX_ERROR; return NGX_ERROR;
} }
@ -1073,6 +1087,7 @@ ngx_quic_app_input(ngx_connection_t *c, ngx_quic_header_t *pkt)
{ {
ngx_int_t rc; ngx_int_t rc;
ngx_quic_secrets_t *keys, *next, tmp; ngx_quic_secrets_t *keys, *next, tmp;
ngx_quic_send_ctx_t *ctx;
ngx_quic_connection_t *qc; ngx_quic_connection_t *qc;
static u_char buf[NGX_QUIC_DEFAULT_MAX_PACKET_SIZE]; static u_char buf[NGX_QUIC_DEFAULT_MAX_PACKET_SIZE];
@ -1099,7 +1114,9 @@ ngx_quic_app_input(ngx_connection_t *c, ngx_quic_header_t *pkt)
pkt->level = ssl_encryption_application; pkt->level = ssl_encryption_application;
pkt->plaintext = buf; pkt->plaintext = buf;
if (ngx_quic_decrypt(pkt, c->ssl->connection) != NGX_OK) { ctx = ngx_quic_get_send_ctx(qc, pkt->level);
if (ngx_quic_decrypt(pkt, c->ssl->connection, &ctx->largest_pn) != NGX_OK) {
return NGX_ERROR; return NGX_ERROR;
} }

View File

@ -36,7 +36,8 @@ static ngx_int_t ngx_hkdf_extract(u_char *out_key, size_t *out_len,
const EVP_MD *digest, const u_char *secret, size_t secret_len, const EVP_MD *digest, const u_char *secret, size_t secret_len,
const u_char *salt, size_t salt_len); const u_char *salt, size_t salt_len);
static uint64_t ngx_quic_parse_pn(u_char **pos, ngx_int_t len, u_char *mask); static uint64_t ngx_quic_parse_pn(u_char **pos, ngx_int_t len, u_char *mask,
uint64_t *largest_pn);
static void ngx_quic_compute_nonce(u_char *nonce, size_t len, uint64_t pn); static void ngx_quic_compute_nonce(u_char *nonce, size_t len, uint64_t pn);
static ngx_int_t ngx_quic_ciphers(ngx_ssl_conn_t *ssl_conn, static ngx_int_t ngx_quic_ciphers(ngx_ssl_conn_t *ssl_conn,
ngx_quic_ciphers_t *ciphers, enum ssl_encryption_level_t level); ngx_quic_ciphers_t *ciphers, enum ssl_encryption_level_t level);
@ -870,20 +871,45 @@ ngx_quic_create_short_packet(ngx_quic_header_t *pkt, ngx_ssl_conn_t *ssl_conn,
static uint64_t static uint64_t
ngx_quic_parse_pn(u_char **pos, ngx_int_t len, u_char *mask) ngx_quic_parse_pn(u_char **pos, ngx_int_t len, u_char *mask,
uint64_t *largest_pn)
{ {
u_char *p; u_char *p;
uint64_t value; uint64_t truncated_pn, expected_pn, candidate_pn;
uint64_t pn_nbits, pn_win, pn_hwin, pn_mask;
pn_nbits = ngx_min(len * 8, 62);
p = *pos; p = *pos;
value = *p++ ^ *mask++; truncated_pn = *p++ ^ *mask++;
while (--len) { while (--len) {
value = (value << 8) + (*p++ ^ *mask++); truncated_pn = (truncated_pn << 8) + (*p++ ^ *mask++);
} }
*pos = p; *pos = p;
return value;
expected_pn = *largest_pn + 1;
pn_win = 1 << pn_nbits;
pn_hwin = pn_win / 2;
pn_mask = pn_win - 1;
candidate_pn = (expected_pn & ~pn_mask) | truncated_pn;
if ((int64_t) candidate_pn <= (int64_t) (expected_pn - pn_hwin)
&& candidate_pn < (1ULL << 62) - pn_win)
{
candidate_pn += pn_win;
} else if (candidate_pn > expected_pn + pn_hwin
&& candidate_pn >= pn_win)
{
candidate_pn -= pn_win;
}
*largest_pn = ngx_max((int64_t) *largest_pn, (int64_t) candidate_pn);
return candidate_pn;
} }
@ -910,7 +936,8 @@ ngx_quic_encrypt(ngx_quic_header_t *pkt, ngx_ssl_conn_t *ssl_conn,
ngx_int_t ngx_int_t
ngx_quic_decrypt(ngx_quic_header_t *pkt, ngx_ssl_conn_t *ssl_conn) ngx_quic_decrypt(ngx_quic_header_t *pkt, ngx_ssl_conn_t *ssl_conn,
uint64_t *largest_pn)
{ {
u_char clearflags, *p, *sample; u_char clearflags, *p, *sample;
uint64_t pn; uint64_t pn;
@ -960,7 +987,7 @@ ngx_quic_decrypt(ngx_quic_header_t *pkt, ngx_ssl_conn_t *ssl_conn)
} }
pnl = (clearflags & 0x03) + 1; pnl = (clearflags & 0x03) + 1;
pn = ngx_quic_parse_pn(&p, pnl, &mask[1]); pn = ngx_quic_parse_pn(&p, pnl, &mask[1], largest_pn);
pkt->pn = pn; pkt->pn = pn;

View File

@ -39,7 +39,8 @@ ngx_int_t ngx_quic_key_update(ngx_connection_t *c,
ssize_t ngx_quic_encrypt(ngx_quic_header_t *pkt, ngx_ssl_conn_t *ssl_conn, ssize_t ngx_quic_encrypt(ngx_quic_header_t *pkt, ngx_ssl_conn_t *ssl_conn,
ngx_str_t *res); ngx_str_t *res);
ngx_int_t ngx_quic_decrypt(ngx_quic_header_t *pkt, ngx_ssl_conn_t *ssl_conn); ngx_int_t ngx_quic_decrypt(ngx_quic_header_t *pkt, ngx_ssl_conn_t *ssl_conn,
uint64_t *largest_pn);
#endif /* _NGX_EVENT_QUIC_PROTECTION_H_INCLUDED_ */ #endif /* _NGX_EVENT_QUIC_PROTECTION_H_INCLUDED_ */