Removed memory allocations from encryption code.

+ ngx_quic_encrypt():
     - no longer accepts pool as argument
     - pkt is 1st arg
     - payload is passed as pkt->payload
     - performs encryption to the specified static buffer

 + ngx_quic_create_long/short_packet() functions:
    - single buffer for everything, allocated by caller
    - buffer layout is: [ ad | payload | TAG ]
      the result is in the beginning of buffer with proper length
    - nonce is calculated on stack
    - log is passed explicitly, pkt is 1st arg
    - no more allocations inside

 + ngx_quic_create_long_header():
    - args changed: no need to pass str_t

 + added ngx_quic_create_short_header()
This commit is contained in:
Vladimir Homutov 2020-03-26 12:11:50 +03:00
parent bcd54c2643
commit 715d8a250b
5 changed files with 101 additions and 118 deletions

View File

@ -1365,8 +1365,9 @@ static ngx_int_t
ngx_quic_send_packet(ngx_connection_t *c, ngx_quic_connection_t *qc, ngx_quic_send_packet(ngx_connection_t *c, ngx_quic_connection_t *qc,
enum ssl_encryption_level_t level, ngx_str_t *payload) enum ssl_encryption_level_t level, ngx_str_t *payload)
{ {
ngx_str_t res; ngx_str_t res;
ngx_quic_header_t pkt; ngx_quic_header_t pkt;
static u_char buf[65535];
static ngx_str_t initial_token = ngx_null_string; static ngx_str_t initial_token = ngx_null_string;
@ -1377,6 +1378,7 @@ ngx_quic_send_packet(ngx_connection_t *c, ngx_quic_connection_t *qc,
pkt.level = level; pkt.level = level;
pkt.dcid = qc->dcid; pkt.dcid = qc->dcid;
pkt.scid = qc->scid; pkt.scid = qc->scid;
pkt.payload = *payload;
if (level == ssl_encryption_initial) { if (level == ssl_encryption_initial) {
pkt.number = &qc->initial_pn; pkt.number = &qc->initial_pn;
@ -1394,9 +1396,12 @@ ngx_quic_send_packet(ngx_connection_t *c, ngx_quic_connection_t *qc,
pkt.secret = &qc->secrets.server.ad; pkt.secret = &qc->secrets.server.ad;
} }
if (ngx_quic_encrypt(c->pool, c->ssl->connection, &pkt, payload, &res) // TODO: ensure header size + payload.len + crypto tail fits into packet
!= NGX_OK) // (i.e. limit payload while pushing frames to < 65k)
{
res.data = buf;
if (ngx_quic_encrypt(&pkt, c->ssl->connection, &res) != NGX_OK) {
return NGX_ERROR; return NGX_ERROR;
} }

View File

@ -43,21 +43,19 @@ static ngx_int_t ngx_quic_ciphers(ngx_ssl_conn_t *ssl_conn,
static ngx_int_t ngx_quic_tls_open(ngx_pool_t *pool, const ngx_quic_cipher_t *cipher, static ngx_int_t ngx_quic_tls_open(ngx_pool_t *pool, const ngx_quic_cipher_t *cipher,
ngx_quic_secret_t *s, ngx_str_t *out, u_char *nonce, ngx_str_t *in, ngx_quic_secret_t *s, ngx_str_t *out, u_char *nonce, ngx_str_t *in,
ngx_str_t *ad); ngx_str_t *ad);
static ngx_int_t ngx_quic_tls_seal(ngx_pool_t *pool, static ngx_int_t ngx_quic_tls_seal(const ngx_quic_cipher_t *cipher,
const ngx_quic_cipher_t *cipher, ngx_quic_secret_t *s, ngx_str_t *out, ngx_quic_secret_t *s, ngx_str_t *out, u_char *nonce, ngx_str_t *in,
u_char *nonce, ngx_str_t *in, ngx_str_t *ad); ngx_str_t *ad, ngx_log_t *log);
static ngx_int_t ngx_quic_tls_hp(ngx_log_t *log, const EVP_CIPHER *cipher, static ngx_int_t ngx_quic_tls_hp(ngx_log_t *log, const EVP_CIPHER *cipher,
ngx_quic_secret_t *s, u_char *out, u_char *in); ngx_quic_secret_t *s, u_char *out, u_char *in);
static ngx_int_t ngx_quic_hkdf_expand(ngx_pool_t *pool, const EVP_MD *digest, static ngx_int_t ngx_quic_hkdf_expand(ngx_pool_t *pool, const EVP_MD *digest,
ngx_str_t *out, ngx_str_t *label, const uint8_t *prk, size_t prk_len); ngx_str_t *out, ngx_str_t *label, const uint8_t *prk, size_t prk_len);
static ngx_int_t ngx_quic_create_long_packet(ngx_pool_t *pool, static ssize_t ngx_quic_create_long_packet(ngx_quic_header_t *pkt,
ngx_ssl_conn_t *ssl_conn, ngx_quic_header_t *pkt, ngx_str_t *in, ngx_ssl_conn_t *ssl_conn, ngx_str_t *res);
ngx_str_t *res);
static ngx_int_t ngx_quic_create_short_packet(ngx_pool_t *pool, static ssize_t ngx_quic_create_short_packet(ngx_quic_header_t *pkt,
ngx_ssl_conn_t *ssl_conn, ngx_quic_header_t *pkt, ngx_str_t *in, ngx_ssl_conn_t *ssl_conn, ngx_str_t *res);
ngx_str_t *res);
static ngx_int_t static ngx_int_t
@ -467,19 +465,9 @@ ngx_quic_tls_open(ngx_pool_t *pool, const ngx_quic_cipher_t *cipher,
static ngx_int_t static ngx_int_t
ngx_quic_tls_seal(ngx_pool_t *pool, const ngx_quic_cipher_t *cipher, ngx_quic_tls_seal(const ngx_quic_cipher_t *cipher, ngx_quic_secret_t *s,
ngx_quic_secret_t *s, ngx_str_t *out, u_char *nonce, ngx_str_t *in, ngx_str_t *out, u_char *nonce, ngx_str_t *in, ngx_str_t *ad, ngx_log_t *log)
ngx_str_t *ad)
{ {
ngx_log_t *log;
log = pool->log; // TODO: pass log ?
out->len = in->len + EVP_GCM_TLS_TAG_LEN;
out->data = ngx_pnalloc(pool, out->len);
if (out->data == NULL) {
return NGX_ERROR;
}
#ifdef OPENSSL_IS_BORINGSSL #ifdef OPENSSL_IS_BORINGSSL
EVP_AEAD_CTX *ctx; EVP_AEAD_CTX *ctx;
@ -682,161 +670,128 @@ ngx_quic_set_encryption_secret(ngx_pool_t *pool, ngx_ssl_conn_t *ssl_conn,
} }
static ngx_int_t static ssize_t
ngx_quic_create_long_packet(ngx_pool_t *pool, ngx_ssl_conn_t *ssl_conn, ngx_quic_create_long_packet(ngx_quic_header_t *pkt, ngx_ssl_conn_t *ssl_conn,
ngx_quic_header_t *pkt, ngx_str_t *payload, ngx_str_t *res) ngx_str_t *res)
{ {
u_char *p, *pnp, *nonce, *sample, *packet; u_char *pnp, *sample;
uint64_t pn; uint64_t pn;
ngx_log_t *log;
ngx_str_t ad, out; ngx_str_t ad, out;
ngx_quic_ciphers_t ciphers; ngx_quic_ciphers_t ciphers;
u_char mask[16]; u_char nonce[12], mask[16];
log = pool->log; out.len = pkt->payload.len + EVP_GCM_TLS_TAG_LEN;
out.len = payload->len + EVP_GCM_TLS_TAG_LEN; ad.data = res->data;
ad.len = ngx_quic_create_long_header(pkt, ad.data, out.len, &pnp);
ad.data = ngx_alloc(NGX_QUIC_MAX_LONG_HEADER, log); out.data = res->data + ad.len;
if (ad.data == 0) {
return NGX_ERROR;
}
ad.len = ngx_quic_create_long_header(pkt, &ad, out.len, &pnp); ngx_quic_hexdump0(pkt->log, "ad", ad.data, ad.len);
ngx_quic_hexdump0(log, "ad", ad.data, ad.len);
if (ngx_quic_ciphers(ssl_conn, &ciphers, pkt->level) == NGX_ERROR) { if (ngx_quic_ciphers(ssl_conn, &ciphers, pkt->level) == NGX_ERROR) {
return NGX_ERROR; return NGX_ERROR;
} }
nonce = ngx_pstrdup(pool, &pkt->secret->iv); ngx_memcpy(nonce, pkt->secret->iv.data, pkt->secret->iv.len);
pn = *pkt->number; pn = *pkt->number;
nonce[11] ^= pn; nonce[11] ^= pn;
ngx_quic_hexdump0(log, "server_iv", pkt->secret->iv.data, 12); ngx_quic_hexdump0(pkt->log, "server_iv", pkt->secret->iv.data, 12);
ngx_quic_hexdump0(log, "nonce", nonce, 12); ngx_quic_hexdump0(pkt->log, "nonce", nonce, 12);
if (ngx_quic_tls_seal(pool, ciphers.c, pkt->secret, &out, if (ngx_quic_tls_seal(ciphers.c, pkt->secret, &out,
nonce, payload, &ad) nonce, &pkt->payload, &ad, pkt->log)
!= NGX_OK) != NGX_OK)
{ {
return NGX_ERROR; return NGX_ERROR;
} }
sample = &out.data[3]; // pnl=0 sample = &out.data[3]; // pnl=0
if (ngx_quic_tls_hp(log, ciphers.hp, pkt->secret, mask, sample) != NGX_OK) { if (ngx_quic_tls_hp(pkt->log, ciphers.hp, pkt->secret, mask, sample)
!= NGX_OK)
{
return NGX_ERROR; return NGX_ERROR;
} }
ngx_quic_hexdump0(log, "sample", sample, 16); ngx_quic_hexdump0(pkt->log, "sample", sample, 16);
ngx_quic_hexdump0(log, "mask", mask, 16); ngx_quic_hexdump0(pkt->log, "mask", mask, 16);
ngx_quic_hexdump0(log, "hp_key", pkt->secret->hp.data, 16); ngx_quic_hexdump0(pkt->log, "hp_key", pkt->secret->hp.data, 16);
// header protection, pnl = 0 // header protection, pnl = 0
ad.data[0] ^= mask[0] & 0x0f; ad.data[0] ^= mask[0] & 0x0f;
*pnp ^= mask[1]; *pnp ^= mask[1];
packet = ngx_alloc(ad.len + out.len, log); res->len = ad.len + out.len;
if (packet == 0) {
return NGX_ERROR;
}
p = ngx_cpymem(packet, ad.data, ad.len);
p = ngx_cpymem(p, out.data, out.len);
res->data = packet;
res->len = p - packet;
return NGX_OK; return NGX_OK;
} }
static ngx_int_t static ssize_t
ngx_quic_create_short_packet(ngx_pool_t *pool, ngx_ssl_conn_t *ssl_conn, ngx_quic_create_short_packet(ngx_quic_header_t *pkt, ngx_ssl_conn_t *ssl_conn,
ngx_quic_header_t *pkt, ngx_str_t *payload, ngx_str_t *res) ngx_str_t *res)
{ {
u_char *p, *pnp, *nonce, *sample, *packet; u_char *pnp, *sample;
ngx_log_t *log;
ngx_str_t ad, out; ngx_str_t ad, out;
ngx_quic_ciphers_t ciphers; ngx_quic_ciphers_t ciphers;
u_char mask[16]; u_char nonce[12], mask[16];
log = pool->log; out.len = pkt->payload.len + EVP_GCM_TLS_TAG_LEN;
out.len = payload->len + EVP_GCM_TLS_TAG_LEN; ad.data = res->data;
ad.len = ngx_quic_create_short_header(pkt, ad.data, out.len, &pnp);
ad.data = ngx_alloc(NGX_QUIC_MAX_SHORT_HEADER, log); ngx_quic_hexdump0(pkt->log, "ad", ad.data, ad.len);
if (ad.data == 0) {
return NGX_ERROR;
}
p = ad.data;
*p++ = 0x40;
p = ngx_cpymem(p, pkt->scid.data, pkt->scid.len);
pnp = p;
*p++ = (*pkt->number);
ad.len = p - ad.data;
ngx_quic_hexdump0(log, "ad", ad.data, ad.len);
if (ngx_quic_ciphers(ssl_conn, &ciphers, pkt->level) == NGX_ERROR) { if (ngx_quic_ciphers(ssl_conn, &ciphers, pkt->level) == NGX_ERROR) {
return NGX_ERROR; return NGX_ERROR;
} }
nonce = ngx_pstrdup(pool, &pkt->secret->iv); ngx_memcpy(nonce, pkt->secret->iv.data, pkt->secret->iv.len);
if (pkt->level == ssl_encryption_handshake if (pkt->level == ssl_encryption_handshake
|| pkt->level == ssl_encryption_application) || pkt->level == ssl_encryption_application)
{ {
nonce[11] ^= *pkt->number; nonce[11] ^= *pkt->number;
} }
ngx_quic_hexdump0(log, "server_iv", pkt->secret->iv.data, 12); ngx_quic_hexdump0(pkt->log, "server_iv", pkt->secret->iv.data, 12);
ngx_quic_hexdump0(log, "nonce", nonce, 12); ngx_quic_hexdump0(pkt->log, "nonce", nonce, 12);
if (ngx_quic_tls_seal(pool, ciphers.c, pkt->secret, &out, out.data = res->data + ad.len;
nonce, payload, &ad)
if (ngx_quic_tls_seal(ciphers.c, pkt->secret, &out, nonce, &pkt->payload,
&ad, pkt->log)
!= NGX_OK) != NGX_OK)
{ {
return NGX_ERROR; return NGX_ERROR;
} }
ngx_quic_hexdump0(log, "out", out.data, out.len); ngx_quic_hexdump0(pkt->log, "out", out.data, out.len);
sample = &out.data[3]; // pnl=0 sample = &out.data[3]; // pnl=0
if (ngx_quic_tls_hp(log, ciphers.hp, pkt->secret, mask, sample) != NGX_OK) { if (ngx_quic_tls_hp(pkt->log, ciphers.hp, pkt->secret, mask, sample)
!= NGX_OK)
{
return NGX_ERROR; return NGX_ERROR;
} }
ngx_quic_hexdump0(log, "sample", sample, 16); ngx_quic_hexdump0(pkt->log, "sample", sample, 16);
ngx_quic_hexdump0(log, "mask", mask, 16); ngx_quic_hexdump0(pkt->log, "mask", mask, 16);
ngx_quic_hexdump0(log, "hp_key", pkt->secret->hp.data, 16); ngx_quic_hexdump0(pkt->log, "hp_key", pkt->secret->hp.data, 16);
// header protection, pnl = 0 // header protection, pnl = 0
ad.data[0] ^= mask[0] & 0x1f; ad.data[0] ^= mask[0] & 0x1f;
*pnp ^= mask[1]; *pnp ^= mask[1];
packet = ngx_alloc(ad.len + out.len, log); res->len = ad.len + out.len;
if (packet == 0) {
return NGX_ERROR;
}
p = ngx_cpymem(packet, ad.data, ad.len); ngx_quic_hexdump0(pkt->log, "packet", res->data, res->len);
p = ngx_cpymem(p, out.data, out.len);
ngx_quic_hexdump0(log, "packet", packet, p - packet);
res->data = packet;
res->len = p - packet;
return NGX_OK; return NGX_OK;
} }
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)
{ {
@ -855,15 +810,15 @@ ngx_quic_parse_pn(u_char **pos, ngx_int_t len, u_char *mask)
} }
ngx_int_t ssize_t
ngx_quic_encrypt(ngx_pool_t *pool, ngx_ssl_conn_t *ssl_conn, ngx_quic_encrypt(ngx_quic_header_t *pkt, ngx_ssl_conn_t *ssl_conn,
ngx_quic_header_t *pkt, ngx_str_t *payload, ngx_str_t *res) ngx_str_t *res)
{ {
if (pkt->level == ssl_encryption_application) { if (pkt->level == ssl_encryption_application) {
return ngx_quic_create_short_packet(pool, ssl_conn, pkt, payload, res); return ngx_quic_create_short_packet(pkt, ssl_conn, res);
} }
return ngx_quic_create_long_packet(pool, ssl_conn, pkt, payload, res); return ngx_quic_create_long_packet(pkt, ssl_conn, res);
} }

View File

@ -36,8 +36,8 @@ int ngx_quic_set_encryption_secret(ngx_pool_t *pool, ngx_ssl_conn_t *ssl_conn,
enum ssl_encryption_level_t level, const uint8_t *secret, size_t secret_len, enum ssl_encryption_level_t level, const uint8_t *secret, size_t secret_len,
ngx_quic_peer_secrets_t *qsec); ngx_quic_peer_secrets_t *qsec);
ngx_int_t ngx_quic_encrypt(ngx_pool_t *pool, ngx_ssl_conn_t *ssl_conn, ssize_t ngx_quic_encrypt(ngx_quic_header_t *pkt, ngx_ssl_conn_t *ssl_conn,
ngx_quic_header_t *pkt, ngx_str_t *payload, ngx_str_t *res); ngx_str_t *res);
ngx_int_t ngx_quic_decrypt(ngx_pool_t *pool, ngx_ssl_conn_t *ssl_conn, ngx_int_t ngx_quic_decrypt(ngx_pool_t *pool, ngx_ssl_conn_t *ssl_conn,
ngx_quic_header_t *pkt); ngx_quic_header_t *pkt);

View File

@ -341,12 +341,12 @@ ngx_quic_parse_long_header(ngx_quic_header_t *pkt)
size_t size_t
ngx_quic_create_long_header(ngx_quic_header_t *pkt, ngx_str_t *out, ngx_quic_create_long_header(ngx_quic_header_t *pkt, u_char *out,
size_t pkt_len, u_char **pnp) size_t pkt_len, u_char **pnp)
{ {
u_char *p, *start; u_char *p, *start;
p = start = out->data; p = start = out;
*p++ = pkt->flags; *p++ = pkt->flags;
@ -372,6 +372,26 @@ ngx_quic_create_long_header(ngx_quic_header_t *pkt, ngx_str_t *out,
} }
size_t
ngx_quic_create_short_header(ngx_quic_header_t *pkt, u_char *out,
size_t pkt_len, u_char **pnp)
{
u_char *p, *start;
p = start = out;
*p++ = 0x40;
p = ngx_cpymem(p, pkt->scid.data, pkt->scid.len);
*pnp = p;
*p++ = (*pkt->number);
return p - start;
}
ngx_int_t ngx_int_t
ngx_quic_parse_short_header(ngx_quic_header_t *pkt, ngx_str_t *dcid) ngx_quic_parse_short_header(ngx_quic_header_t *pkt, ngx_str_t *dcid)
{ {

View File

@ -255,11 +255,14 @@ typedef struct {
u_char *ngx_quic_error_text(uint64_t error_code); u_char *ngx_quic_error_text(uint64_t error_code);
ngx_int_t ngx_quic_parse_long_header(ngx_quic_header_t *pkt); ngx_int_t ngx_quic_parse_long_header(ngx_quic_header_t *pkt);
size_t ngx_quic_create_long_header(ngx_quic_header_t *pkt, ngx_str_t *out, size_t ngx_quic_create_long_header(ngx_quic_header_t *pkt, u_char *out,
size_t pkt_len, u_char **pnp); size_t pkt_len, u_char **pnp);
ngx_int_t ngx_quic_parse_short_header(ngx_quic_header_t *pkt, ngx_int_t ngx_quic_parse_short_header(ngx_quic_header_t *pkt,
ngx_str_t *dcid); ngx_str_t *dcid);
size_t ngx_quic_create_short_header(ngx_quic_header_t *pkt, u_char *out,
size_t pkt_len, u_char **pnp);
ngx_int_t ngx_quic_parse_initial_header(ngx_quic_header_t *pkt); ngx_int_t ngx_quic_parse_initial_header(ngx_quic_header_t *pkt);
ngx_int_t ngx_quic_parse_handshake_header(ngx_quic_header_t *pkt); ngx_int_t ngx_quic_parse_handshake_header(ngx_quic_header_t *pkt);