mirror of
https://github.com/nginx/nginx.git
synced 2024-12-13 11:09:06 +08:00
Added functions to decrypt long packets.
This commit is contained in:
parent
12fc8a8bac
commit
32b2728ebb
@ -185,9 +185,22 @@ typedef struct {
|
||||
ngx_uint_t type;
|
||||
ngx_uint_t *number;
|
||||
ngx_uint_t flags;
|
||||
ngx_uint_t version;
|
||||
ngx_str_t *token;
|
||||
uint32_t version;
|
||||
ngx_str_t token;
|
||||
ngx_quic_level_t level;
|
||||
|
||||
/* filled in by parser */
|
||||
ngx_str_t buf; /* quic packet from wire */
|
||||
u_char *pos; /* current parser position */
|
||||
|
||||
/* cleartext fields */
|
||||
ngx_str_t dcid;
|
||||
ngx_str_t scid;
|
||||
|
||||
uint64_t pn;
|
||||
|
||||
ngx_str_t payload; /* decrypted payload */
|
||||
|
||||
} ngx_quic_header_t;
|
||||
|
||||
|
||||
@ -210,6 +223,15 @@ static int ngx_quic_flush_flight(ngx_ssl_conn_t *ssl_conn);
|
||||
static int ngx_quic_send_alert(ngx_ssl_conn_t *ssl_conn,
|
||||
enum ssl_encryption_level_t level, uint8_t alert);
|
||||
|
||||
static ngx_int_t ngx_quic_process_long_header(ngx_connection_t *c,
|
||||
ngx_quic_header_t *pkt);
|
||||
static ngx_int_t ngx_quic_process_initial_header(ngx_connection_t *c,
|
||||
ngx_quic_header_t *pkt);
|
||||
static ngx_int_t ngx_quic_process_handshake_header(ngx_connection_t *c,
|
||||
ngx_quic_header_t *pkt);
|
||||
static ngx_int_t ngx_quic_initial_secret(ngx_connection_t *c);
|
||||
static ngx_int_t ngx_quic_decrypt(ngx_connection_t *c, ngx_quic_header_t *pkt);
|
||||
|
||||
static uint64_t ngx_quic_parse_pn(u_char **pos, ngx_int_t len, u_char *mask);
|
||||
static uint64_t ngx_quic_parse_int(u_char **pos);
|
||||
static void ngx_quic_build_int(u_char **pos, uint64_t value);
|
||||
@ -287,7 +309,7 @@ ngx_quic_send_packet(ngx_connection_t *c, ngx_quic_connection_t *qc,
|
||||
pkt.number = &qc->initial_pn;
|
||||
pkt.flags = NGX_QUIC_PKT_INITIAL;
|
||||
pkt.secret = &qc->server_in;
|
||||
pkt.token = &initial_token;
|
||||
pkt.token = initial_token;
|
||||
|
||||
if (ngx_quic_create_long_packet(c, c->ssl->connection,
|
||||
&pkt, payload, &res)
|
||||
@ -599,8 +621,8 @@ ngx_quic_create_long_packet(ngx_connection_t *c, ngx_ssl_conn_t *ssl_conn,
|
||||
*p++ = qc->dcid.len;
|
||||
p = ngx_cpymem(p, qc->dcid.data, qc->dcid.len);
|
||||
|
||||
if (pkt->token) { // if pkt->flags & initial ?
|
||||
ngx_quic_build_int(&p, pkt->token->len);
|
||||
if (pkt->level == ssl_encryption_initial) {
|
||||
ngx_quic_build_int(&p, pkt->token.len);
|
||||
}
|
||||
|
||||
ngx_quic_build_int(&p, out.len + 1); // length (inc. pnl)
|
||||
@ -865,90 +887,114 @@ ngx_quic_send_alert(ngx_ssl_conn_t *ssl_conn, enum ssl_encryption_level_t level,
|
||||
|
||||
|
||||
static ngx_int_t
|
||||
ngx_quic_new_connection(ngx_connection_t *c, ngx_ssl_t *ssl, ngx_buf_t *b)
|
||||
ngx_quic_process_long_header(ngx_connection_t *c, ngx_quic_header_t *pkt)
|
||||
{
|
||||
int n, sslerr;
|
||||
ngx_quic_connection_t *qc;
|
||||
u_char *p;
|
||||
|
||||
if ((b->pos[0] & 0xf0) != NGX_QUIC_PKT_INITIAL) {
|
||||
ngx_log_error(NGX_LOG_INFO, c->log, 0, "invalid initial packet");
|
||||
p = pkt->buf.data;
|
||||
|
||||
ngx_quic_hexdump0(c->log, "input", pkt->buf.data, pkt->buf.len);
|
||||
|
||||
if (!(p[0] & NGX_QUIC_PKT_LONG)) {
|
||||
ngx_log_error(NGX_LOG_INFO, c->log, 0, "not a long packet");
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
if (ngx_buf_size(b) < 1200) {
|
||||
ngx_log_error(NGX_LOG_INFO, c->log, 0, "too small UDP datagram");
|
||||
return NGX_ERROR;
|
||||
}
|
||||
pkt->flags = *p++;
|
||||
|
||||
ngx_int_t flags = *b->pos++;
|
||||
uint32_t version = ngx_quic_parse_uint32(b->pos);
|
||||
b->pos += sizeof(uint32_t);
|
||||
pkt->version = ngx_quic_parse_uint32(p);
|
||||
p += sizeof(uint32_t);
|
||||
|
||||
ngx_log_debug2(NGX_LOG_DEBUG_EVENT, c->log, 0,
|
||||
"quic flags:%xi version:%xD", flags, version);
|
||||
"quic flags:%xi version:%xD", pkt->flags, pkt->version);
|
||||
|
||||
if (version != quic_version) {
|
||||
if (pkt->version != quic_version) {
|
||||
ngx_log_error(NGX_LOG_INFO, c->log, 0, "unsupported quic version");
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
qc = ngx_pcalloc(c->pool, sizeof(ngx_quic_connection_t));
|
||||
if (qc == NULL) {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
pkt->dcid.len = *p++;
|
||||
pkt->dcid.data = p;
|
||||
p += pkt->dcid.len;
|
||||
|
||||
c->quic = qc;
|
||||
pkt->scid.len = *p++;
|
||||
pkt->scid.data = p;
|
||||
p += pkt->scid.len;
|
||||
|
||||
qc->dcid.len = *b->pos++;
|
||||
qc->dcid.data = ngx_pnalloc(c->pool, qc->dcid.len);
|
||||
if (qc->dcid.data == NULL) {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
pkt->pos = p;
|
||||
|
||||
ngx_memcpy(qc->dcid.data, b->pos, qc->dcid.len);
|
||||
b->pos += qc->dcid.len;
|
||||
return NGX_OK;
|
||||
}
|
||||
|
||||
qc->scid.len = *b->pos++;
|
||||
qc->scid.data = ngx_pnalloc(c->pool, qc->scid.len);
|
||||
if (qc->scid.data == NULL) {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
ngx_memcpy(qc->scid.data, b->pos, qc->scid.len);
|
||||
b->pos += qc->scid.len;
|
||||
static ngx_int_t
|
||||
ngx_quic_process_initial_header(ngx_connection_t *c, ngx_quic_header_t *pkt)
|
||||
{
|
||||
u_char *p;
|
||||
ngx_int_t plen;
|
||||
|
||||
qc->token.len = ngx_quic_parse_int(&b->pos);
|
||||
qc->token.data = ngx_pnalloc(c->pool, qc->token.len);
|
||||
if (qc->token.data == NULL) {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
p = pkt->pos;
|
||||
|
||||
ngx_memcpy(qc->token.data, b->pos, qc->token.len);
|
||||
b->pos += qc->token.len;
|
||||
pkt->token.len = ngx_quic_parse_int(&p);
|
||||
pkt->token.data = p;
|
||||
|
||||
ngx_int_t plen = ngx_quic_parse_int(&b->pos);
|
||||
p += pkt->token.len;
|
||||
|
||||
if (plen > b->last - b->pos) {
|
||||
plen = ngx_quic_parse_int(&p);
|
||||
|
||||
ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0,
|
||||
"quic packet length: %d", plen);
|
||||
|
||||
if (plen > pkt->buf.data + pkt->buf.len - p) {
|
||||
ngx_log_error(NGX_LOG_INFO, c->log, 0, "truncated initial packet");
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
/* draft-ietf-quic-tls-23#section-5.4.2:
|
||||
* the Packet Number field is assumed to be 4 bytes long
|
||||
* draft-ietf-quic-tls-23#section-5.4.[34]:
|
||||
* AES-Based and ChaCha20-Based header protections sample 16 bytes
|
||||
*/
|
||||
u_char *sample = b->pos + 4;
|
||||
pkt->pos = p;
|
||||
pkt->buf.len = plen;
|
||||
|
||||
ngx_quic_hexdump0(c->log, "DCID", pkt->dcid.data, pkt->dcid.len);
|
||||
ngx_quic_hexdump0(c->log, "SCID", pkt->scid.data, pkt->scid.len);
|
||||
ngx_quic_hexdump0(c->log, "token", pkt->token.data, pkt->token.len);
|
||||
|
||||
ngx_quic_hexdump0(c->log, "DCID", qc->dcid.data, qc->dcid.len);
|
||||
ngx_quic_hexdump0(c->log, "SCID", qc->scid.data, qc->scid.len);
|
||||
ngx_quic_hexdump0(c->log, "token", qc->token.data, qc->token.len);
|
||||
ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0,
|
||||
"quic packet length: %d", plen);
|
||||
ngx_quic_hexdump0(c->log, "sample", sample, 16);
|
||||
|
||||
return NGX_OK;
|
||||
}
|
||||
|
||||
static ngx_int_t
|
||||
ngx_quic_process_handshake_header(ngx_connection_t *c, ngx_quic_header_t *pkt)
|
||||
{
|
||||
u_char *p;
|
||||
ngx_int_t plen;
|
||||
|
||||
p = pkt->pos;
|
||||
|
||||
plen = ngx_quic_parse_int(&p);
|
||||
|
||||
ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0,
|
||||
"quic packet length: %d", plen);
|
||||
|
||||
if (plen > pkt->buf.data + pkt->buf.len - p) {
|
||||
ngx_log_error(NGX_LOG_INFO, c->log, 0, "truncated handshake packet");
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
pkt->pos = p;
|
||||
pkt->buf.len = plen;
|
||||
|
||||
ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0,
|
||||
"quic packet length: %d", plen);
|
||||
|
||||
return NGX_OK;
|
||||
}
|
||||
|
||||
|
||||
// initial secret
|
||||
static ngx_int_t
|
||||
ngx_quic_initial_secret(ngx_connection_t *c)
|
||||
{
|
||||
ngx_quic_connection_t *qc = c->quic;
|
||||
|
||||
size_t is_len;
|
||||
uint8_t is[SHA256_DIGEST_LENGTH];
|
||||
@ -1047,57 +1093,176 @@ ngx_quic_new_connection(ngx_connection_t *c, ngx_ssl_t *ssl, ngx_buf_t *b)
|
||||
}
|
||||
}
|
||||
|
||||
// header protection
|
||||
return NGX_OK;
|
||||
}
|
||||
|
||||
uint8_t mask[16];
|
||||
if (ngx_quic_tls_hp(c, EVP_aes_128_ecb(), &qc->client_in, mask, sample)
|
||||
|
||||
static ngx_int_t
|
||||
ngx_quic_decrypt(ngx_connection_t *c, ngx_quic_header_t *pkt)
|
||||
{
|
||||
u_char clearflags, *p, *sample;
|
||||
uint8_t *nonce;
|
||||
uint64_t pn;
|
||||
ngx_int_t pnl, rc;
|
||||
ngx_str_t in, ad;
|
||||
|
||||
const EVP_CIPHER *cipher;
|
||||
|
||||
uint8_t mask[16];
|
||||
|
||||
p = pkt->pos;
|
||||
|
||||
/* draft-ietf-quic-tls-23#section-5.4.2:
|
||||
* the Packet Number field is assumed to be 4 bytes long
|
||||
* draft-ietf-quic-tls-23#section-5.4.[34]:
|
||||
* AES-Based and ChaCha20-Based header protections sample 16 bytes
|
||||
*/
|
||||
|
||||
sample = p + 4;
|
||||
|
||||
ngx_quic_hexdump0(c->log, "sample", sample, 16);
|
||||
|
||||
/* header protection */
|
||||
|
||||
if (ngx_quic_tls_hp(c, EVP_aes_128_ecb(), pkt->secret, mask, sample)
|
||||
!= NGX_OK)
|
||||
{
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
u_char clearflags = flags ^ (mask[0] & 0x0f);
|
||||
ngx_int_t pnl = (clearflags & 0x03) + 1;
|
||||
uint64_t pn = ngx_quic_parse_pn(&b->pos, pnl, &mask[1]);
|
||||
clearflags = pkt->flags ^ (mask[0] & 0x0f);
|
||||
pnl = (clearflags & 0x03) + 1;
|
||||
pn = ngx_quic_parse_pn(&p, pnl, &mask[1]);
|
||||
|
||||
pkt->pn = pn;
|
||||
|
||||
ngx_quic_hexdump0(c->log, "sample", sample, 16);
|
||||
ngx_quic_hexdump0(c->log, "mask", mask, 5);
|
||||
ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0,
|
||||
"quic clear flags: %xi", clearflags);
|
||||
ngx_log_debug2(NGX_LOG_DEBUG_EVENT, c->log, 0,
|
||||
"quic packet number: %uL, len: %xi", pn, pnl);
|
||||
|
||||
// packet protection
|
||||
/* packet protection */
|
||||
|
||||
ngx_str_t in;
|
||||
in.data = b->pos;
|
||||
in.len = plen - pnl;
|
||||
in.data = p;
|
||||
in.len = pkt->buf.len - pnl;
|
||||
|
||||
ngx_str_t ad;
|
||||
ad.len = b->pos - b->start;
|
||||
ad.len = p - pkt->buf.data;;
|
||||
ad.data = ngx_pnalloc(c->pool, ad.len);
|
||||
if (ad.data == NULL) {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
ngx_memcpy(ad.data, b->start, ad.len);
|
||||
ngx_memcpy(ad.data, pkt->buf.data, ad.len);
|
||||
ad.data[0] = clearflags;
|
||||
ad.data[ad.len - pnl] = (u_char)pn;
|
||||
ad.data[ad.len - pnl] = (u_char) pn;
|
||||
|
||||
uint8_t *nonce = ngx_pstrdup(c->pool, &qc->client_in.iv);
|
||||
nonce = ngx_pstrdup(c->pool, &pkt->secret->iv);
|
||||
nonce[11] ^= pn;
|
||||
|
||||
ngx_quic_hexdump0(c->log, "nonce", nonce, 12);
|
||||
ngx_quic_hexdump0(c->log, "ad", ad.data, ad.len);
|
||||
|
||||
ngx_str_t out;
|
||||
if (c->ssl) {
|
||||
switch (SSL_CIPHER_get_id(SSL_get_current_cipher(c->ssl->connection)) & 0xffff) {
|
||||
|
||||
if (ngx_quic_tls_open(c, EVP_aes_128_gcm(), &qc->client_in, &out, nonce,
|
||||
&in, &ad)
|
||||
!= NGX_OK)
|
||||
{
|
||||
case NGX_AES_128_GCM_SHA256:
|
||||
cipher = EVP_aes_128_gcm();
|
||||
break;
|
||||
case NGX_AES_256_GCM_SHA384:
|
||||
cipher = EVP_aes_256_gcm();
|
||||
break;
|
||||
default:
|
||||
ngx_ssl_error(NGX_LOG_INFO, c->log, 0, "unexpected cipher");
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
} else {
|
||||
/* initial packets */
|
||||
cipher = EVP_aes_128_gcm();
|
||||
}
|
||||
|
||||
rc = ngx_quic_tls_open(c, cipher, pkt->secret, &pkt->payload,
|
||||
nonce, &in, &ad);
|
||||
|
||||
ngx_quic_hexdump0(c->log, "packet payload",
|
||||
pkt->payload.data, pkt->payload.len);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
static ngx_int_t
|
||||
ngx_quic_new_connection(ngx_connection_t *c, ngx_ssl_t *ssl, ngx_buf_t *b)
|
||||
{
|
||||
int n, sslerr;
|
||||
ngx_str_t out;
|
||||
ngx_quic_connection_t *qc;
|
||||
|
||||
ngx_quic_header_t pkt = { 0 };
|
||||
|
||||
pkt.buf.data = b->start;
|
||||
pkt.buf.len = b->last - b->pos;
|
||||
|
||||
if (ngx_buf_size(b) < 1200) {
|
||||
ngx_log_error(NGX_LOG_INFO, c->log, 0, "too small UDP datagram");
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
ngx_quic_hexdump0(c->log, "packet payload", out.data, out.len);
|
||||
if (ngx_quic_process_long_header(c, &pkt) != NGX_OK) {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
if ((pkt.flags & 0xf0) != NGX_QUIC_PKT_INITIAL) {
|
||||
ngx_log_error(NGX_LOG_INFO, c->log, 0,
|
||||
"invalid initial packet: 0x%x", pkt.flags);
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
if (ngx_quic_process_initial_header(c, &pkt) != NGX_OK) {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
qc = ngx_pcalloc(c->pool, sizeof(ngx_quic_connection_t));
|
||||
if (qc == NULL) {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
c->quic = qc;
|
||||
|
||||
qc->dcid.len = pkt.dcid.len;
|
||||
qc->dcid.data = ngx_pnalloc(c->pool, pkt.dcid.len);
|
||||
if (qc->dcid.data == NULL) {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
ngx_memcpy(qc->dcid.data, pkt.dcid.data, qc->dcid.len);
|
||||
|
||||
qc->scid.len = pkt.scid.len;
|
||||
qc->scid.data = ngx_pnalloc(c->pool, qc->scid.len);
|
||||
if (qc->scid.data == NULL) {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
ngx_memcpy(qc->scid.data, pkt.scid.data, qc->scid.len);
|
||||
|
||||
qc->token.len = pkt.token.len;
|
||||
qc->token.data = ngx_pnalloc(c->pool, qc->token.len);
|
||||
if (qc->token.data == NULL) {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
ngx_memcpy(qc->token.data, pkt.token.data, qc->token.len);
|
||||
|
||||
|
||||
if (ngx_quic_initial_secret(c) != NGX_OK) {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
pkt.secret = &qc->client_in;
|
||||
|
||||
if (ngx_quic_decrypt(c, &pkt) != NGX_OK) {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
out = pkt.payload;
|
||||
|
||||
if (out.data[0] != 0x06) {
|
||||
ngx_log_error(NGX_LOG_INFO, c->log, 0,
|
||||
@ -1183,144 +1348,64 @@ ngx_quic_new_connection(ngx_connection_t *c, ngx_ssl_t *ssl, ngx_buf_t *b)
|
||||
|
||||
|
||||
static ngx_int_t
|
||||
ngx_quic_handshake_input(ngx_connection_t *c, ngx_buf_t *bb)
|
||||
ngx_quic_handshake_input(ngx_connection_t *c, ngx_buf_t *b)
|
||||
{
|
||||
int sslerr;
|
||||
u_char *p, *b;
|
||||
ssize_t n;
|
||||
ngx_str_t out;
|
||||
ngx_ssl_conn_t *ssl_conn;
|
||||
const EVP_CIPHER *cipher;
|
||||
ngx_quic_connection_t *qc;
|
||||
|
||||
ngx_quic_header_t pkt = { 0 };
|
||||
|
||||
qc = c->quic;
|
||||
ssl_conn = c->ssl->connection;
|
||||
|
||||
n = bb->last - bb->pos;
|
||||
p = bb->pos;
|
||||
b = bb->start;
|
||||
pkt.buf.data = b->start;
|
||||
pkt.buf.len = b->last - b->pos;
|
||||
|
||||
ngx_quic_hexdump0(c->log, "input", p, n);
|
||||
|
||||
if ((p[0] & 0xf0) != NGX_QUIC_PKT_HANDSHAKE) {
|
||||
ngx_log_error(NGX_LOG_INFO, c->log, 0, "invalid packet type");
|
||||
/* extract cleartext data into pkt */
|
||||
if (ngx_quic_process_long_header(c, &pkt) != NGX_OK) {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
ngx_int_t flags = *p++;
|
||||
uint32_t version = ngx_quic_parse_uint32(p);
|
||||
p += sizeof(uint32_t);
|
||||
|
||||
ngx_log_debug2(NGX_LOG_DEBUG_EVENT, c->log, 0,
|
||||
"quic flags:%xi version:%xD", flags, version);
|
||||
|
||||
if (version != quic_version) {
|
||||
ngx_log_error(NGX_LOG_INFO, c->log, 0, "unsupported quic version");
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
if (*p++ != qc->dcid.len) {
|
||||
if (pkt.dcid.len != qc->dcid.len) {
|
||||
ngx_log_error(NGX_LOG_INFO, c->log, 0, "unexpected quic dcidl");
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
if (ngx_memcmp(p, qc->dcid.data, qc->dcid.len) != 0) {
|
||||
if (ngx_memcmp(pkt.dcid.data, qc->dcid.data, qc->dcid.len) != 0) {
|
||||
ngx_log_error(NGX_LOG_INFO, c->log, 0, "unexpected quic dcid");
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
p += qc->dcid.len;
|
||||
|
||||
if (*p++ != qc->scid.len) {
|
||||
if (pkt.scid.len != qc->scid.len) {
|
||||
ngx_log_error(NGX_LOG_INFO, c->log, 0, "unexpected quic scidl");
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
if (ngx_memcmp(p, qc->scid.data, qc->scid.len) != 0) {
|
||||
if (ngx_memcmp(pkt.scid.data, qc->scid.data, qc->scid.len) != 0) {
|
||||
ngx_log_error(NGX_LOG_INFO, c->log, 0, "unexpected quic scid");
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
p += qc->scid.len;
|
||||
|
||||
ngx_int_t plen = ngx_quic_parse_int(&p);
|
||||
|
||||
ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0,
|
||||
"quic packet length: %d", plen);
|
||||
|
||||
if (plen > b + n - p) {
|
||||
ngx_log_error(NGX_LOG_INFO, c->log, 0, "truncated handshake packet");
|
||||
if ((pkt.flags & 0xf0) != NGX_QUIC_PKT_HANDSHAKE) {
|
||||
ngx_log_error(NGX_LOG_INFO, c->log, 0,
|
||||
"invalid packet type: 0x%x", pkt.flags);
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
u_char *sample = p + 4;
|
||||
|
||||
ngx_quic_hexdump0(c->log, "sample", sample, 16);
|
||||
|
||||
// header protection
|
||||
|
||||
uint8_t mask[16];
|
||||
if (ngx_quic_tls_hp(c, EVP_aes_128_ecb(), &qc->client_hs, mask, sample)
|
||||
!= NGX_OK)
|
||||
{
|
||||
if (ngx_quic_process_handshake_header(c, &pkt) != NGX_OK) {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
u_char clearflags = flags ^ (mask[0] & 0x0f);
|
||||
ngx_int_t pnl = (clearflags & 0x03) + 1;
|
||||
uint64_t pn = ngx_quic_parse_pn(&p, pnl, &mask[1]);
|
||||
pkt.secret = &qc->client_hs;
|
||||
|
||||
ngx_quic_hexdump0(c->log, "mask", mask, 5);
|
||||
ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0,
|
||||
"quic clear flags: %xi", clearflags);
|
||||
ngx_log_debug2(NGX_LOG_DEBUG_EVENT, c->log, 0,
|
||||
"quic packet number: %uL, len: %xi", pn, pnl);
|
||||
|
||||
// packet protection
|
||||
|
||||
ngx_str_t in;
|
||||
in.data = p;
|
||||
in.len = plen - pnl;
|
||||
|
||||
ngx_str_t ad;
|
||||
ad.len = p - b;
|
||||
ad.data = ngx_pnalloc(c->pool, ad.len);
|
||||
if (ad.data == NULL) {
|
||||
if (ngx_quic_decrypt(c, &pkt) != NGX_OK) {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
ngx_memcpy(ad.data, b, ad.len);
|
||||
ad.data[0] = clearflags;
|
||||
ad.data[ad.len - pnl] = (u_char)pn;
|
||||
|
||||
uint8_t *nonce = ngx_pstrdup(c->pool, &qc->client_hs.iv);
|
||||
nonce[11] ^= pn;
|
||||
|
||||
ngx_quic_hexdump0(c->log, "nonce", nonce, 12);
|
||||
ngx_quic_hexdump0(c->log, "ad", ad.data, ad.len);
|
||||
|
||||
switch (SSL_CIPHER_get_id(SSL_get_current_cipher(ssl_conn)) & 0xffff) {
|
||||
|
||||
case NGX_AES_128_GCM_SHA256:
|
||||
cipher = EVP_aes_128_gcm();
|
||||
break;
|
||||
|
||||
case NGX_AES_256_GCM_SHA384:
|
||||
cipher = EVP_aes_256_gcm();
|
||||
break;
|
||||
|
||||
default:
|
||||
ngx_ssl_error(NGX_LOG_INFO, c->log, 0, "unexpected cipher");
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
if (ngx_quic_tls_open(c, cipher, &qc->client_hs, &out, nonce, &in, &ad)
|
||||
!= NGX_OK)
|
||||
{
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
ngx_quic_hexdump0(c->log, "packet payload", out.data, out.len);
|
||||
out = pkt.payload;
|
||||
|
||||
if (out.data[0] != 0x06) {
|
||||
ngx_log_error(NGX_LOG_INFO, c->log, 0,
|
||||
@ -1388,9 +1473,9 @@ ngx_quic_handshake_input(ngx_connection_t *c, ngx_buf_t *bb)
|
||||
|
||||
frame->level = ssl_encryption_handshake;
|
||||
frame->type = NGX_QUIC_FT_ACK;
|
||||
frame->u.ack.pn = pn;
|
||||
frame->u.ack.pn = pkt.pn;
|
||||
|
||||
ngx_sprintf(frame->info, "ACK for PN=%d at handshake level, in respond to client finished", pn);
|
||||
ngx_sprintf(frame->info, "ACK for PN=%d at handshake level, in respond to client finished", pkt.pn);
|
||||
ngx_quic_queue_frame(qc, frame);
|
||||
|
||||
if (ngx_quic_output(c) != NGX_OK) {
|
||||
|
Loading…
Reference in New Issue
Block a user