aboutsummaryrefslogtreecommitdiff
path: root/src/http/ngx_http_request.c
diff options
context:
space:
mode:
authorVladimir Homutov <vl@nginx.com>2020-02-28 16:23:25 +0300
committerVladimir Homutov <vl@nginx.com>2020-02-28 16:23:25 +0300
commitb20ed8f7f1acc2a1ef38714ddd75c7ba7add5f1d (patch)
tree00d7ae6c61654441a9a896c6c5af8c77358ee7db /src/http/ngx_http_request.c
parent899372129879b5874ffddca4247fca12d3b7c257 (diff)
downloadnginx-b20ed8f7f1acc2a1ef38714ddd75c7ba7add5f1d.tar.gz
nginx-b20ed8f7f1acc2a1ef38714ddd75c7ba7add5f1d.zip
Moved all QUIC code into ngx_event_quic.c
Introduced ngx_quic_input() and ngx_quic_output() as interface between nginx and protocol. They are the only functions that are exported. While there, added copyrights.
Diffstat (limited to 'src/http/ngx_http_request.c')
-rw-r--r--src/http/ngx_http_request.c555
1 files changed, 10 insertions, 545 deletions
diff --git a/src/http/ngx_http_request.c b/src/http/ngx_http_request.c
index d40f50496..6d89fef24 100644
--- a/src/http/ngx_http_request.c
+++ b/src/http/ngx_http_request.c
@@ -661,402 +661,22 @@ ngx_http_alloc_request(ngx_connection_t *c)
static void
ngx_http_quic_handshake(ngx_event_t *rev)
{
- int n, sslerr;
-#if (NGX_DEBUG)
- u_char buf[512];
- size_t m;
-#endif
- ngx_buf_t *b;
ngx_connection_t *c;
ngx_http_connection_t *hc;
- ngx_quic_connection_t *qc;
ngx_http_ssl_srv_conf_t *sscf;
ngx_log_debug0(NGX_LOG_DEBUG_HTTP, rev->log, 0, "quic handshake");
c = rev->data;
hc = c->data;
- b = c->buffer;
-
- if ((b->pos[0] & 0xf0) != 0xc0) {
- ngx_log_error(NGX_LOG_INFO, rev->log, 0, "invalid initial packet");
- ngx_http_close_connection(c);
- return;
- }
-
- if (ngx_buf_size(b) < 1200) {
- ngx_log_error(NGX_LOG_INFO, rev->log, 0, "too small UDP datagram");
- ngx_http_close_connection(c);
- return;
- }
-
- ngx_int_t flags = *b->pos++;
- uint32_t version = ngx_quic_parse_uint32(b->pos);
- b->pos += sizeof(uint32_t);
-
- ngx_log_debug2(NGX_LOG_DEBUG_HTTP, rev->log, 0,
- "quic flags:%xi version:%xD", flags, version);
-
- if (version != quic_version) {
- ngx_log_error(NGX_LOG_INFO, rev->log, 0, "unsupported quic version");
- ngx_http_close_connection(c);
- return;
- }
-
- qc = ngx_pcalloc(c->pool, sizeof(ngx_quic_connection_t));
- if (qc == NULL) {
- ngx_http_close_connection(c);
- return;
- }
-
- c->quic = qc;
-
- qc->dcid.len = *b->pos++;
- qc->dcid.data = ngx_pnalloc(c->pool, qc->dcid.len);
- if (qc->dcid.data == NULL) {
- ngx_http_close_connection(c);
- return;
- }
-
- ngx_memcpy(qc->dcid.data, b->pos, qc->dcid.len);
- b->pos += qc->dcid.len;
-
- qc->scid.len = *b->pos++;
- qc->scid.data = ngx_pnalloc(c->pool, qc->scid.len);
- if (qc->scid.data == NULL) {
- ngx_http_close_connection(c);
- return;
- }
-
- ngx_memcpy(qc->scid.data, b->pos, qc->scid.len);
- b->pos += qc->scid.len;
-
- qc->token.len = ngx_quic_parse_int(&b->pos);
- qc->token.data = ngx_pnalloc(c->pool, qc->token.len);
- if (qc->token.data == NULL) {
- ngx_http_close_connection(c);
- return;
- }
-
- ngx_memcpy(qc->token.data, b->pos, qc->token.len);
- b->pos += qc->token.len;
-
- ngx_int_t plen = ngx_quic_parse_int(&b->pos);
-
- if (plen > b->last - b->pos) {
- ngx_log_error(NGX_LOG_INFO, rev->log, 0, "truncated initial packet");
- ngx_http_close_connection(c);
- return;
- }
-
- /* 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;
-
-#if (NGX_DEBUG)
- if (c->log->log_level & NGX_LOG_DEBUG_EVENT) {
- m = ngx_hex_dump(buf, qc->dcid.data, qc->dcid.len) - buf;
- ngx_log_debug3(NGX_LOG_DEBUG_HTTP, rev->log, 0,
- "quic DCID: %*s, len: %uz", m, buf, qc->dcid.len);
-
- m = ngx_hex_dump(buf, qc->scid.data, qc->scid.len) - buf;
- ngx_log_debug3(NGX_LOG_DEBUG_HTTP, rev->log, 0,
- "quic SCID: %*s, len: %uz", m, buf, qc->scid.len);
-
- m = ngx_hex_dump(buf, qc->token.data, qc->token.len) - buf;
- ngx_log_debug3(NGX_LOG_DEBUG_HTTP, rev->log, 0,
- "quic token: %*s, len: %uz", m, buf, qc->token.len);
-
- ngx_log_debug1(NGX_LOG_DEBUG_HTTP, rev->log, 0,
- "quic packet length: %d", plen);
-
- m = ngx_hex_dump(buf, sample, 16) - buf;
- ngx_log_debug2(NGX_LOG_DEBUG_HTTP, rev->log, 0,
- "quic sample: %*s", m, buf);
- }
-#endif
-
-// initial secret
-
- size_t is_len;
- uint8_t is[SHA256_DIGEST_LENGTH];
- ngx_uint_t i;
- const EVP_MD *digest;
- const EVP_CIPHER *cipher;
- static const uint8_t salt[20] =
- "\xc3\xee\xf7\x12\xc7\x2e\xbb\x5a\x11\xa7"
- "\xd2\x43\x2b\xb4\x63\x65\xbe\xf9\xf5\x02";
-
- /* AEAD_AES_128_GCM prior to handshake, quic-tls-23#section-5.3 */
-
- cipher = EVP_aes_128_gcm();
- digest = EVP_sha256();
-
- if (ngx_hkdf_extract(is, &is_len, digest, qc->dcid.data, qc->dcid.len,
- salt, sizeof(salt))
- != NGX_OK)
- {
- ngx_http_close_connection(c);
- return;
- }
-
- ngx_str_t iss = {
- .data = is,
- .len = is_len
- };
-
-#if (NGX_DEBUG)
- if (c->log->log_level & NGX_LOG_DEBUG_EVENT) {
- m = ngx_hex_dump(buf, (uint8_t *) salt, sizeof(salt)) - buf;
- ngx_log_debug3(NGX_LOG_DEBUG_HTTP, rev->log, 0,
- "quic salt: %*s, len: %uz", m, buf, sizeof(salt));
-
- m = ngx_hex_dump(buf, is, is_len) - buf;
- ngx_log_debug3(NGX_LOG_DEBUG_HTTP, rev->log, 0,
- "quic initial secret: %*s, len: %uz", m, buf, is_len);
- }
-#endif
-
- /* draft-ietf-quic-tls-23#section-5.2 */
- qc->client_in.secret.len = SHA256_DIGEST_LENGTH;
- qc->server_in.secret.len = SHA256_DIGEST_LENGTH;
-
- qc->client_in.key.len = EVP_CIPHER_key_length(cipher);
- qc->server_in.key.len = EVP_CIPHER_key_length(cipher);
-
- qc->client_in.hp.len = EVP_CIPHER_key_length(cipher);
- qc->server_in.hp.len = EVP_CIPHER_key_length(cipher);
-
- qc->client_in.iv.len = EVP_CIPHER_iv_length(cipher);
- qc->server_in.iv.len = EVP_CIPHER_iv_length(cipher);
-
- struct {
- ngx_str_t label;
- ngx_str_t *key;
- ngx_str_t *prk;
- } seq[] = {
-
- /* draft-ietf-quic-tls-23#section-5.2 */
- { ngx_string("tls13 client in"), &qc->client_in.secret, &iss },
- {
- ngx_string("tls13 quic key"),
- &qc->client_in.key,
- &qc->client_in.secret,
- },
- {
- ngx_string("tls13 quic iv"),
- &qc->client_in.iv,
- &qc->client_in.secret,
- },
- {
- /* AEAD_AES_128_GCM prior to handshake, quic-tls-23#section-5.4.1 */
- ngx_string("tls13 quic hp"),
- &qc->client_in.hp,
- &qc->client_in.secret,
- },
- { ngx_string("tls13 server in"), &qc->server_in.secret, &iss },
- {
- /* AEAD_AES_128_GCM prior to handshake, quic-tls-23#section-5.3 */
- ngx_string("tls13 quic key"),
- &qc->server_in.key,
- &qc->server_in.secret,
- },
- {
- ngx_string("tls13 quic iv"),
- &qc->server_in.iv,
- &qc->server_in.secret,
- },
- {
- /* AEAD_AES_128_GCM prior to handshake, quic-tls-23#section-5.4.1 */
- ngx_string("tls13 quic hp"),
- &qc->server_in.hp,
- &qc->server_in.secret,
- },
-
- };
-
- for (i = 0; i < (sizeof(seq) / sizeof(seq[0])); i++) {
-
- if (ngx_quic_hkdf_expand(c, digest, seq[i].key, &seq[i].label,
- seq[i].prk->data, seq[i].prk->len)
- != NGX_OK)
- {
- ngx_http_close_connection(c);
- return;
- }
- }
-
-// header protection
-
- uint8_t mask[16];
- if (ngx_quic_tls_hp(c, EVP_aes_128_ecb(), &qc->client_in, mask, sample)
- != NGX_OK)
- {
- ngx_http_close_connection(c);
- return;
- }
-
- 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]);
-
-#if (NGX_DEBUG)
- if (c->log->log_level & NGX_LOG_DEBUG_EVENT) {
- m = ngx_hex_dump(buf, sample, 16) - buf;
- ngx_log_debug2(NGX_LOG_DEBUG_HTTP, rev->log, 0,
- "quic sample: %*s", m, buf);
-
- m = ngx_hex_dump(buf, mask, 5) - buf;
- ngx_log_debug2(NGX_LOG_DEBUG_HTTP, rev->log, 0,
- "quic mask: %*s", m, buf);
-
- ngx_log_debug2(NGX_LOG_DEBUG_HTTP, rev->log, 0,
- "quic packet number: %uL, len: %xi", pn, pnl);
- }
-#endif
-
-// packet protection
-
- ngx_str_t in;
- in.data = b->pos;
- in.len = plen - pnl;
-
- ngx_str_t ad;
- ad.len = b->pos - b->start;
- ad.data = ngx_pnalloc(c->pool, ad.len);
- if (ad.data == NULL) {
- ngx_http_close_connection(c);
- return;
- }
-
- ngx_memcpy(ad.data, b->start, ad.len);
- ad.data[0] = clearflags;
- ad.data[ad.len - pnl] = (u_char)pn;
-
- uint8_t *nonce = ngx_pstrdup(c->pool, &qc->client_in.iv);
- nonce[11] ^= pn;
-
-#if (NGX_DEBUG)
- if (c->log->log_level & NGX_LOG_DEBUG_EVENT) {
- m = ngx_hex_dump(buf, nonce, 12) - buf;
- ngx_log_debug3(NGX_LOG_DEBUG_HTTP, rev->log, 0,
- "quic nonce: %*s, len: %uz", m, buf, 12);
-
- m = ngx_hex_dump(buf, ad.data, ad.len) - buf;
- ngx_log_debug3(NGX_LOG_DEBUG_HTTP, rev->log, 0,
- "quic ad: %*s, len: %uz", m, buf, ad.len);
- }
-#endif
-
- ngx_str_t out;
-
- if (ngx_quic_tls_open(c, EVP_aes_128_gcm(), &qc->client_in, &out, nonce,
- &in, &ad)
- != NGX_OK)
- {
- ngx_http_close_connection(c);
- return;
- }
-
-#if (NGX_DEBUG)
- if (c->log->log_level & NGX_LOG_DEBUG_EVENT) {
- m = ngx_hex_dump(buf, out.data, ngx_min(out.len, 256)) - buf;
- ngx_log_debug4(NGX_LOG_DEBUG_HTTP, rev->log, 0,
- "quic packet payload: %*s%s, len: %uz",
- m, buf, m < 512 ? "" : "...", out.len);
- }
-#endif
-
- if (out.data[0] != 0x06) {
- ngx_log_error(NGX_LOG_INFO, rev->log, 0,
- "unexpected frame in initial packet");
- ngx_http_close_connection(c);
- return;
- }
-
- if (out.data[1] != 0x00) {
- ngx_log_error(NGX_LOG_INFO, rev->log, 0,
- "unexpected CRYPTO offset in initial packet");
- ngx_http_close_connection(c);
- return;
- }
-
- uint8_t *crypto = &out.data[2];
- uint64_t crypto_len = ngx_quic_parse_int(&crypto);
-
- ngx_log_debug3(NGX_LOG_DEBUG_HTTP, rev->log, 0,
- "quic initial packet CRYPTO length: %uL pp:%p:%p",
- crypto_len, out.data, crypto);
sscf = ngx_http_get_module_srv_conf(hc->conf_ctx, ngx_http_ssl_module);
- if (ngx_ssl_create_connection(&sscf->ssl, c, NGX_SSL_BUFFER)
- != NGX_OK)
- {
- ngx_http_close_connection(c);
- return;
- }
-
- static const uint8_t params[12] = "\x00\x0a\x00\x3a\x00\x01\x00\x00\x09\x00\x01\x03";
-
- if (SSL_set_quic_transport_params(c->ssl->connection, params,
- sizeof(params)) == 0)
- {
- ngx_log_error(NGX_LOG_INFO, rev->log, 0,
- "SSL_set_quic_transport_params() failed");
+ if (ngx_quic_input(c, &sscf->ssl, c->buffer) != NGX_OK) {
ngx_http_close_connection(c);
return;
}
- n = SSL_do_handshake(c->ssl->connection);
-
- ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0, "SSL_do_handshake: %d", n);
-
- if (n == -1) {
- sslerr = SSL_get_error(c->ssl->connection, n);
-
- ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0, "SSL_get_error: %d",
- sslerr);
- }
-
- ngx_log_debug2(NGX_LOG_DEBUG_EVENT, c->log, 0,
- "SSL_quic_read_level: %d, SSL_quic_write_level: %d",
- (int) SSL_quic_read_level(c->ssl->connection),
- (int) SSL_quic_write_level(c->ssl->connection));
-
- if (!SSL_provide_quic_data(c->ssl->connection,
- SSL_quic_read_level(c->ssl->connection),
- crypto, crypto_len))
- {
- ngx_ssl_error(NGX_LOG_INFO, rev->log, 0,
- "SSL_provide_quic_data() failed");
- ngx_http_close_connection(c);
- return;
- }
-
- n = SSL_do_handshake(c->ssl->connection);
-
- ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0, "SSL_do_handshake: %d", n);
-
- if (n == -1) {
- sslerr = SSL_get_error(c->ssl->connection, n);
-
- ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0, "SSL_get_error: %d",
- sslerr);
-
- if (sslerr == SSL_ERROR_SSL) {
- ngx_ssl_error(NGX_LOG_ERR, c->log, 0, "SSL_do_handshake() failed");
- }
- }
-
- ngx_log_debug2(NGX_LOG_DEBUG_EVENT, c->log, 0,
- "SSL_quic_read_level: %d, SSL_quic_write_level: %d",
- (int) SSL_quic_read_level(c->ssl->connection),
- (int) SSL_quic_write_level(c->ssl->connection));
-
if (!rev->timer_set) {
ngx_add_timer(rev, c->listening->post_accept_timeout);
}
@@ -1069,17 +689,16 @@ ngx_http_quic_handshake(ngx_event_t *rev)
static void
ngx_http_quic_handshake_handler(ngx_event_t *rev)
{
- size_t m;
ssize_t n;
- ngx_str_t out;
ngx_connection_t *c;
- const EVP_CIPHER *cipher;
- ngx_quic_connection_t *qc;
- u_char buf[4096], b[512], *p;
+ u_char buf[512];
+ ngx_buf_t b;
+
+ b.start = buf;
+ b.end = buf + 512;
+ b.pos = b.last = b.start;
c = rev->data;
- qc = c->quic;
- p = b;
ngx_log_debug0(NGX_LOG_DEBUG_HTTP, rev->log, 0, "quic handshake handler");
@@ -1094,7 +713,7 @@ ngx_http_quic_handshake_handler(ngx_event_t *rev)
return;
}
- n = c->recv(c, b, sizeof(b));
+ n = c->recv(c, b.start, b.end - b.start);
if (n == NGX_AGAIN) {
return;
@@ -1106,166 +725,12 @@ ngx_http_quic_handshake_handler(ngx_event_t *rev)
return;
}
- m = ngx_hex_dump(buf, b, n) - buf;
- ngx_log_debug3(NGX_LOG_DEBUG_HTTP, rev->log, 0,
- "quic handshake handler: %*s, len: %uz", m, buf, n);
+ b.last += n;
- if ((p[0] & 0xf0) != 0xe0) {
- ngx_log_error(NGX_LOG_INFO, rev->log, 0, "invalid packet type");
+ if (ngx_quic_input(c, NULL, &b) != NGX_OK) {
ngx_http_close_connection(c);
return;
}
-
- ngx_int_t flags = *p++;
- uint32_t version = ngx_quic_parse_uint32(p);
- p += sizeof(uint32_t);
-
- ngx_log_debug2(NGX_LOG_DEBUG_HTTP, rev->log, 0,
- "quic flags:%xi version:%xD", flags, version);
-
- if (version != quic_version) {
- ngx_log_error(NGX_LOG_INFO, rev->log, 0, "unsupported quic version");
- ngx_http_close_connection(c);
- return;
- }
-
- if (*p++ != qc->dcid.len) {
- ngx_log_error(NGX_LOG_INFO, rev->log, 0, "unexpected quic dcidl");
- ngx_http_close_connection(c);
- return;
- }
-
- if (ngx_memcmp(p, qc->dcid.data, qc->dcid.len) != 0) {
- ngx_log_error(NGX_LOG_INFO, rev->log, 0, "unexpected quic dcid");
- ngx_http_close_connection(c);
- return;
- }
-
- p += qc->dcid.len;
-
- if (*p++ != qc->scid.len) {
- ngx_log_error(NGX_LOG_INFO, rev->log, 0, "unexpected quic scidl");
- ngx_http_close_connection(c);
- return;
- }
-
- if (ngx_memcmp(p, qc->scid.data, qc->scid.len) != 0) {
- ngx_log_error(NGX_LOG_INFO, rev->log, 0, "unexpected quic scid");
- ngx_http_close_connection(c);
- return;
- }
-
- p += qc->scid.len;
-
- ngx_int_t plen = ngx_quic_parse_int(&p);
-
- ngx_log_debug1(NGX_LOG_DEBUG_HTTP, rev->log, 0,
- "quic packet length: %d", plen);
-
- if (plen > b + n - p) {
- ngx_log_error(NGX_LOG_INFO, rev->log, 0, "truncated handshake packet");
- ngx_http_close_connection(c);
- return;
- }
-
- u_char *sample = p + 4;
-
- m = ngx_hex_dump(buf, sample, 16) - buf;
- ngx_log_debug2(NGX_LOG_DEBUG_HTTP, rev->log, 0, "quic sample: %*s", m, buf);
-
-// header protection
-
- uint8_t mask[16];
- if (ngx_quic_tls_hp(c, EVP_aes_128_ecb(), &qc->client_hs, mask, sample)
- != NGX_OK)
- {
- ngx_http_close_connection(c);
- return;
- }
-
- 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]);
-
-#if (NGX_DEBUG)
- if (c->log->log_level & NGX_LOG_DEBUG_EVENT) {
- m = ngx_hex_dump(buf, mask, 5) - buf;
- ngx_log_debug2(NGX_LOG_DEBUG_HTTP, rev->log, 0,
- "quic mask: %*s", m, buf);
- ngx_log_debug1(NGX_LOG_DEBUG_HTTP, rev->log, 0,
- "quic clear flags: %xi", clearflags);
- ngx_log_debug2(NGX_LOG_DEBUG_HTTP, rev->log, 0,
- "quic packet number: %uL, len: %xi", pn, pnl);
- }
-#endif
-
-// 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) {
- ngx_http_close_connection(c);
- return;
- }
-
- 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;
-
-#if (NGX_DEBUG)
- if (c->log->log_level & NGX_LOG_DEBUG_EVENT) {
- m = ngx_hex_dump(buf, nonce, 12) - buf;
- ngx_log_debug3(NGX_LOG_DEBUG_HTTP, rev->log, 0,
- "quic nonce: %*s, len: %uz", m, buf, 12);
-
- m = ngx_hex_dump(buf, ad.data, ad.len) - buf;
- ngx_log_debug3(NGX_LOG_DEBUG_HTTP, rev->log, 0,
- "quic ad: %*s, len: %uz", m, buf, ad.len);
- }
-#endif
-
- u_char *name = (u_char *) SSL_get_cipher(c->ssl->connection);
- ngx_log_debug1(NGX_LOG_DEBUG_HTTP, rev->log, 0,
- "quic ssl cipher: %s", name);
-
- if (ngx_strcasecmp(name, (u_char *) "TLS_AES_128_GCM_SHA256") == 0
- || ngx_strcasecmp(name, (u_char *) "(NONE)") == 0)
- {
- cipher = EVP_aes_128_gcm();
-
- } else if (ngx_strcasecmp(name, (u_char *) "TLS_AES_256_GCM_SHA384") == 0) {
- cipher = EVP_aes_256_gcm();
-
- } else {
- ngx_ssl_error(NGX_LOG_INFO, rev->log, 0, "unexpected cipher");
- ngx_http_close_connection(c);
- return;
- }
-
- if (ngx_quic_tls_open(c, cipher, &qc->client_hs, &out, nonce, &in, &ad)
- != NGX_OK)
- {
- ngx_http_close_connection(c);
- return;
- }
-
-#if (NGX_DEBUG)
- if (c->log->log_level & NGX_LOG_DEBUG_EVENT) {
- m = ngx_hex_dump(buf, out.data, ngx_min(out.len, 256)) - buf;
- ngx_log_debug4(NGX_LOG_DEBUG_HTTP, rev->log, 0,
- "quic packet payload: %*s%s, len: %uz",
- m, buf, m < 512 ? "" : "...", out.len);
- }
-#endif
-
}