# HG changeset patch # User Vladimir Homutov # Date 1585213910 -10800 # Node ID f85749b60e58cf1b88566df6c70abf61321bbdd2 # Parent 2935a11c55b6be38ef65619dc18dc4d5cfdc76ab 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() diff -r 2935a11c55b6 -r f85749b60e58 src/event/ngx_event_quic.c --- a/src/event/ngx_event_quic.c Wed Mar 25 14:05:40 2020 +0300 +++ b/src/event/ngx_event_quic.c Thu Mar 26 12:11:50 2020 +0300 @@ -1365,8 +1365,9 @@ ngx_quic_send_packet(ngx_connection_t *c, ngx_quic_connection_t *qc, enum ssl_encryption_level_t level, ngx_str_t *payload) { - ngx_str_t res; - ngx_quic_header_t pkt; + ngx_str_t res; + ngx_quic_header_t pkt; + static u_char buf[65535]; static ngx_str_t initial_token = ngx_null_string; @@ -1377,6 +1378,7 @@ pkt.level = level; pkt.dcid = qc->dcid; pkt.scid = qc->scid; + pkt.payload = *payload; if (level == ssl_encryption_initial) { pkt.number = &qc->initial_pn; @@ -1394,9 +1396,12 @@ pkt.secret = &qc->secrets.server.ad; } - if (ngx_quic_encrypt(c->pool, c->ssl->connection, &pkt, payload, &res) - != NGX_OK) - { + // TODO: ensure header size + payload.len + crypto tail fits into packet + // (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; } diff -r 2935a11c55b6 -r f85749b60e58 src/event/ngx_event_quic_protection.c --- a/src/event/ngx_event_quic_protection.c Wed Mar 25 14:05:40 2020 +0300 +++ b/src/event/ngx_event_quic_protection.c Thu Mar 26 12:11:50 2020 +0300 @@ -43,21 +43,19 @@ 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_str_t *ad); -static ngx_int_t ngx_quic_tls_seal(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_str_t *ad); +static ngx_int_t ngx_quic_tls_seal(const ngx_quic_cipher_t *cipher, + ngx_quic_secret_t *s, ngx_str_t *out, u_char *nonce, ngx_str_t *in, + ngx_str_t *ad, ngx_log_t *log); 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); 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); -static ngx_int_t ngx_quic_create_long_packet(ngx_pool_t *pool, - ngx_ssl_conn_t *ssl_conn, ngx_quic_header_t *pkt, ngx_str_t *in, - ngx_str_t *res); +static ssize_t ngx_quic_create_long_packet(ngx_quic_header_t *pkt, + ngx_ssl_conn_t *ssl_conn, ngx_str_t *res); -static ngx_int_t ngx_quic_create_short_packet(ngx_pool_t *pool, - ngx_ssl_conn_t *ssl_conn, ngx_quic_header_t *pkt, ngx_str_t *in, - ngx_str_t *res); +static ssize_t ngx_quic_create_short_packet(ngx_quic_header_t *pkt, + ngx_ssl_conn_t *ssl_conn, ngx_str_t *res); static ngx_int_t @@ -467,19 +465,9 @@ static ngx_int_t -ngx_quic_tls_seal(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_str_t *ad) +ngx_quic_tls_seal(const ngx_quic_cipher_t *cipher, ngx_quic_secret_t *s, + ngx_str_t *out, u_char *nonce, ngx_str_t *in, ngx_str_t *ad, ngx_log_t *log) { - 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 EVP_AEAD_CTX *ctx; @@ -682,161 +670,128 @@ } -static ngx_int_t -ngx_quic_create_long_packet(ngx_pool_t *pool, ngx_ssl_conn_t *ssl_conn, - ngx_quic_header_t *pkt, ngx_str_t *payload, ngx_str_t *res) +static ssize_t +ngx_quic_create_long_packet(ngx_quic_header_t *pkt, ngx_ssl_conn_t *ssl_conn, + ngx_str_t *res) { - u_char *p, *pnp, *nonce, *sample, *packet; + u_char *pnp, *sample; uint64_t pn; - ngx_log_t *log; ngx_str_t ad, out; ngx_quic_ciphers_t ciphers; - u_char mask[16]; + u_char nonce[12], mask[16]; - log = pool->log; - - out.len = payload->len + EVP_GCM_TLS_TAG_LEN; + out.len = pkt->payload.len + EVP_GCM_TLS_TAG_LEN; - ad.data = ngx_alloc(NGX_QUIC_MAX_LONG_HEADER, log); - if (ad.data == 0) { - return NGX_ERROR; - } + ad.data = res->data; + ad.len = ngx_quic_create_long_header(pkt, ad.data, out.len, &pnp); - ad.len = ngx_quic_create_long_header(pkt, &ad, out.len, &pnp); + out.data = res->data + ad.len; - ngx_quic_hexdump0(log, "ad", ad.data, ad.len); + ngx_quic_hexdump0(pkt->log, "ad", ad.data, ad.len); if (ngx_quic_ciphers(ssl_conn, &ciphers, pkt->level) == 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; nonce[11] ^= pn; - ngx_quic_hexdump0(log, "server_iv", pkt->secret->iv.data, 12); - ngx_quic_hexdump0(log, "nonce", nonce, 12); + ngx_quic_hexdump0(pkt->log, "server_iv", pkt->secret->iv.data, 12); + ngx_quic_hexdump0(pkt->log, "nonce", nonce, 12); - if (ngx_quic_tls_seal(pool, ciphers.c, pkt->secret, &out, - nonce, payload, &ad) + if (ngx_quic_tls_seal(ciphers.c, pkt->secret, &out, + nonce, &pkt->payload, &ad, pkt->log) != NGX_OK) { return NGX_ERROR; } 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; } - ngx_quic_hexdump0(log, "sample", sample, 16); - ngx_quic_hexdump0(log, "mask", mask, 16); - ngx_quic_hexdump0(log, "hp_key", pkt->secret->hp.data, 16); + ngx_quic_hexdump0(pkt->log, "sample", sample, 16); + ngx_quic_hexdump0(pkt->log, "mask", mask, 16); + ngx_quic_hexdump0(pkt->log, "hp_key", pkt->secret->hp.data, 16); // header protection, pnl = 0 ad.data[0] ^= mask[0] & 0x0f; *pnp ^= mask[1]; - packet = ngx_alloc(ad.len + out.len, log); - 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; + res->len = ad.len + out.len; return NGX_OK; } -static ngx_int_t -ngx_quic_create_short_packet(ngx_pool_t *pool, ngx_ssl_conn_t *ssl_conn, - ngx_quic_header_t *pkt, ngx_str_t *payload, ngx_str_t *res) +static ssize_t +ngx_quic_create_short_packet(ngx_quic_header_t *pkt, ngx_ssl_conn_t *ssl_conn, + ngx_str_t *res) { - u_char *p, *pnp, *nonce, *sample, *packet; - ngx_log_t *log; + u_char *pnp, *sample; ngx_str_t ad, out; ngx_quic_ciphers_t ciphers; - u_char mask[16]; - - log = pool->log; + u_char nonce[12], mask[16]; - out.len = payload->len + EVP_GCM_TLS_TAG_LEN; - - ad.data = ngx_alloc(NGX_QUIC_MAX_SHORT_HEADER, log); - if (ad.data == 0) { - return NGX_ERROR; - } + out.len = pkt->payload.len + EVP_GCM_TLS_TAG_LEN; - p = ad.data; - - *p++ = 0x40; - - p = ngx_cpymem(p, pkt->scid.data, pkt->scid.len); + ad.data = res->data; + ad.len = ngx_quic_create_short_header(pkt, ad.data, out.len, &pnp); - pnp = p; - - *p++ = (*pkt->number); - - ad.len = p - ad.data; - - ngx_quic_hexdump0(log, "ad", ad.data, ad.len); + ngx_quic_hexdump0(pkt->log, "ad", ad.data, ad.len); if (ngx_quic_ciphers(ssl_conn, &ciphers, pkt->level) == 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 || pkt->level == ssl_encryption_application) { nonce[11] ^= *pkt->number; } - ngx_quic_hexdump0(log, "server_iv", pkt->secret->iv.data, 12); - ngx_quic_hexdump0(log, "nonce", nonce, 12); + ngx_quic_hexdump0(pkt->log, "server_iv", pkt->secret->iv.data, 12); + ngx_quic_hexdump0(pkt->log, "nonce", nonce, 12); - if (ngx_quic_tls_seal(pool, ciphers.c, pkt->secret, &out, - nonce, payload, &ad) + out.data = res->data + ad.len; + + if (ngx_quic_tls_seal(ciphers.c, pkt->secret, &out, nonce, &pkt->payload, + &ad, pkt->log) != NGX_OK) { 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 - 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; } - ngx_quic_hexdump0(log, "sample", sample, 16); - ngx_quic_hexdump0(log, "mask", mask, 16); - ngx_quic_hexdump0(log, "hp_key", pkt->secret->hp.data, 16); + ngx_quic_hexdump0(pkt->log, "sample", sample, 16); + ngx_quic_hexdump0(pkt->log, "mask", mask, 16); + ngx_quic_hexdump0(pkt->log, "hp_key", pkt->secret->hp.data, 16); // header protection, pnl = 0 ad.data[0] ^= mask[0] & 0x1f; *pnp ^= mask[1]; - packet = ngx_alloc(ad.len + out.len, log); - if (packet == 0) { - return NGX_ERROR; - } + res->len = ad.len + out.len; - p = ngx_cpymem(packet, ad.data, ad.len); - p = ngx_cpymem(p, out.data, out.len); - - ngx_quic_hexdump0(log, "packet", packet, p - packet); - - res->data = packet; - res->len = p - packet; + ngx_quic_hexdump0(pkt->log, "packet", res->data, res->len); return NGX_OK; } + static uint64_t ngx_quic_parse_pn(u_char **pos, ngx_int_t len, u_char *mask) { @@ -855,15 +810,15 @@ } -ngx_int_t -ngx_quic_encrypt(ngx_pool_t *pool, ngx_ssl_conn_t *ssl_conn, - ngx_quic_header_t *pkt, ngx_str_t *payload, ngx_str_t *res) +ssize_t +ngx_quic_encrypt(ngx_quic_header_t *pkt, ngx_ssl_conn_t *ssl_conn, + ngx_str_t *res) { 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); } diff -r 2935a11c55b6 -r f85749b60e58 src/event/ngx_event_quic_protection.h --- a/src/event/ngx_event_quic_protection.h Wed Mar 25 14:05:40 2020 +0300 +++ b/src/event/ngx_event_quic_protection.h Thu Mar 26 12:11:50 2020 +0300 @@ -36,8 +36,8 @@ enum ssl_encryption_level_t level, const uint8_t *secret, size_t secret_len, ngx_quic_peer_secrets_t *qsec); -ngx_int_t ngx_quic_encrypt(ngx_pool_t *pool, ngx_ssl_conn_t *ssl_conn, - ngx_quic_header_t *pkt, ngx_str_t *payload, ngx_str_t *res); +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_pool_t *pool, ngx_ssl_conn_t *ssl_conn, ngx_quic_header_t *pkt); diff -r 2935a11c55b6 -r f85749b60e58 src/event/ngx_event_quic_transport.c --- a/src/event/ngx_event_quic_transport.c Wed Mar 25 14:05:40 2020 +0300 +++ b/src/event/ngx_event_quic_transport.c Thu Mar 26 12:11:50 2020 +0300 @@ -341,12 +341,12 @@ 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) { - u_char *p, *start; + u_char *p, *start; - p = start = out->data; + p = start = out; *p++ = pkt->flags; @@ -372,6 +372,26 @@ } +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_quic_parse_short_header(ngx_quic_header_t *pkt, ngx_str_t *dcid) { diff -r 2935a11c55b6 -r f85749b60e58 src/event/ngx_event_quic_transport.h --- a/src/event/ngx_event_quic_transport.h Wed Mar 25 14:05:40 2020 +0300 +++ b/src/event/ngx_event_quic_transport.h Thu Mar 26 12:11:50 2020 +0300 @@ -255,11 +255,14 @@ u_char *ngx_quic_error_text(uint64_t error_code); 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); ngx_int_t ngx_quic_parse_short_header(ngx_quic_header_t *pkt, 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_handshake_header(ngx_quic_header_t *pkt);