# HG changeset patch # User Sergey Kandaurov # Date 1587030408 -10800 # Node ID aba84d9ab256829c3825ab7756567e9d32173ea8 # Parent 0f9e9786b90d5c446175eae4b1621817d552182e Parsing of truncated packet numbers. For sample decoding algorithm, see quic-transport-27#appendix-A. diff --git a/src/event/ngx_event_quic.c b/src/event/ngx_event_quic.c --- a/src/event/ngx_event_quic.c +++ b/src/event/ngx_event_quic.c @@ -65,8 +65,9 @@ typedef struct { ngx_quic_secret_t client_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_pn; /* number received from peer */ ngx_queue_t frames; ngx_queue_t sent; @@ -473,6 +474,7 @@ ngx_quic_new_connection(ngx_connection_t ngx_uint_t i; ngx_quic_tp_t *ctp; ngx_quic_secrets_t *keys; + ngx_quic_send_ctx_t *ctx; ngx_quic_connection_t *qc; static u_char buf[NGX_QUIC_DEFAULT_MAX_PACKET_SIZE]; @@ -510,6 +512,7 @@ ngx_quic_new_connection(ngx_connection_t 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].sent); + qc->send_ctx[i].largest_pn = (uint64_t) -1; } for (i = 0; i < NGX_QUIC_ENCRYPTION_LAST; i++) { @@ -574,7 +577,9 @@ ngx_quic_new_connection(ngx_connection_t pkt->level = ssl_encryption_initial; 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; } @@ -907,9 +912,10 @@ ngx_quic_input(ngx_connection_t *c, ngx_ static ngx_int_t ngx_quic_initial_input(ngx_connection_t *c, ngx_quic_header_t *pkt) { - ngx_ssl_conn_t *ssl_conn; - ngx_quic_secrets_t *keys; - static u_char buf[NGX_QUIC_DEFAULT_MAX_PACKET_SIZE]; + ngx_ssl_conn_t *ssl_conn; + ngx_quic_secrets_t *keys; + ngx_quic_send_ctx_t *ctx; + static u_char buf[NGX_QUIC_DEFAULT_MAX_PACKET_SIZE]; c->log->action = "processing initial quic packet"; @@ -929,7 +935,9 @@ ngx_quic_initial_input(ngx_connection_t pkt->level = ssl_encryption_initial; 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; } @@ -941,6 +949,7 @@ static ngx_int_t ngx_quic_handshake_input(ngx_connection_t *c, ngx_quic_header_t *pkt) { ngx_quic_secrets_t *keys; + ngx_quic_send_ctx_t *ctx; ngx_quic_connection_t *qc; static u_char buf[NGX_QUIC_DEFAULT_MAX_PACKET_SIZE]; @@ -995,7 +1004,9 @@ ngx_quic_handshake_input(ngx_connection_ pkt->level = ssl_encryption_handshake; 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; } @@ -1007,6 +1018,7 @@ static ngx_int_t ngx_quic_early_input(ngx_connection_t *c, ngx_quic_header_t *pkt) { ngx_quic_secrets_t *keys; + ngx_quic_send_ctx_t *ctx; ngx_quic_connection_t *qc; static u_char buf[NGX_QUIC_DEFAULT_MAX_PACKET_SIZE]; @@ -1060,7 +1072,9 @@ ngx_quic_early_input(ngx_connection_t *c pkt->level = ssl_encryption_early_data; 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; } @@ -1073,6 +1087,7 @@ ngx_quic_app_input(ngx_connection_t *c, { ngx_int_t rc; ngx_quic_secrets_t *keys, *next, tmp; + ngx_quic_send_ctx_t *ctx; ngx_quic_connection_t *qc; static u_char buf[NGX_QUIC_DEFAULT_MAX_PACKET_SIZE]; @@ -1099,7 +1114,9 @@ ngx_quic_app_input(ngx_connection_t *c, pkt->level = ssl_encryption_application; 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; } diff --git a/src/event/ngx_event_quic_protection.c b/src/event/ngx_event_quic_protection.c --- a/src/event/ngx_event_quic_protection.c +++ b/src/event/ngx_event_quic_protection.c @@ -36,7 +36,8 @@ static ngx_int_t ngx_hkdf_extract(u_char const EVP_MD *digest, const u_char *secret, size_t secret_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 ngx_int_t ngx_quic_ciphers(ngx_ssl_conn_t *ssl_conn, ngx_quic_ciphers_t *ciphers, enum ssl_encryption_level_t level); @@ -870,20 +871,45 @@ ngx_quic_create_short_packet(ngx_quic_he 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; - 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; - value = *p++ ^ *mask++; + truncated_pn = *p++ ^ *mask++; while (--len) { - value = (value << 8) + (*p++ ^ *mask++); + truncated_pn = (truncated_pn << 8) + (*p++ ^ *mask++); } *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_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; uint64_t pn; @@ -960,7 +987,7 @@ ngx_quic_decrypt(ngx_quic_header_t *pkt, } 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; diff --git a/src/event/ngx_event_quic_protection.h b/src/event/ngx_event_quic_protection.h --- a/src/event/ngx_event_quic_protection.h +++ b/src/event/ngx_event_quic_protection.h @@ -39,7 +39,8 @@ ngx_int_t ngx_quic_key_update(ngx_connec ssize_t ngx_quic_encrypt(ngx_quic_header_t *pkt, ngx_ssl_conn_t *ssl_conn, 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_ */