From e92cb24f40b865e3cc5b9f0993e328e4f0642e0f Mon Sep 17 00:00:00 2001 From: Sergey Kandaurov Date: Fri, 28 Feb 2020 13:09:51 +0300 Subject: HTTP UDP layer, QUIC support autotest. --- src/http/ngx_http_request.c | 10 ++++++++++ 1 file changed, 10 insertions(+) (limited to 'src/http/ngx_http_request.c') diff --git a/src/http/ngx_http_request.c b/src/http/ngx_http_request.c index bb69e71d0..f137590fd 100644 --- a/src/http/ngx_http_request.c +++ b/src/http/ngx_http_request.c @@ -324,6 +324,10 @@ ngx_http_init_connection(ngx_connection_t *c) rev->handler = ngx_http_wait_request_handler; c->write->handler = ngx_http_empty_handler; + if (c->shared) { + rev->ready = 1; + } + #if (NGX_HTTP_V2) if (hc->addr_conf->http2) { rev->handler = ngx_http_v2_init; @@ -386,6 +390,10 @@ ngx_http_wait_request_handler(ngx_event_t *rev) ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0, "http wait request handler"); + if (c->shared) { + goto request; + } + if (rev->timedout) { ngx_log_error(NGX_LOG_INFO, c->log, NGX_ETIMEDOUT, "client timed out"); ngx_http_close_connection(c); @@ -486,6 +494,8 @@ ngx_http_wait_request_handler(ngx_event_t *rev) } } +request: + c->log->action = "reading client request line"; ngx_reusable_connection(c, 0); -- cgit v1.2.3 From 26ac1c73f0fe90c77cbad84a6b4ef5712e35ba52 Mon Sep 17 00:00:00 2001 From: Sergey Kandaurov Date: Fri, 28 Feb 2020 13:09:51 +0300 Subject: Initial QUIC support in http. --- src/http/ngx_http_request.c | 495 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 495 insertions(+) (limited to 'src/http/ngx_http_request.c') diff --git a/src/http/ngx_http_request.c b/src/http/ngx_http_request.c index f137590fd..54a0da497 100644 --- a/src/http/ngx_http_request.c +++ b/src/http/ngx_http_request.c @@ -62,6 +62,8 @@ static u_char *ngx_http_log_error_handler(ngx_http_request_t *r, #if (NGX_HTTP_SSL) static void ngx_http_ssl_handshake(ngx_event_t *rev); static void ngx_http_ssl_handshake_handler(ngx_connection_t *c); + +static void ngx_http_quic_handshake(ngx_event_t *rev); #endif @@ -328,6 +330,14 @@ ngx_http_init_connection(ngx_connection_t *c) rev->ready = 1; } +#if (NGX_HTTP_SSL) + if (hc->addr_conf->http3) { + hc->quic = 1; + c->log->action = "QUIC handshaking"; + rev->handler = ngx_http_quic_handshake; + } +#endif + #if (NGX_HTTP_V2) if (hc->addr_conf->http2) { rev->handler = ngx_http_v2_init; @@ -647,6 +657,491 @@ ngx_http_alloc_request(ngx_connection_t *c) #if (NGX_HTTP_SSL) +static uint64_t +ngx_quic_parse_int(u_char **pos) +{ + u_char *p; + uint64_t value; + ngx_uint_t len; + + p = *pos; + len = 1 << ((*p & 0xc0) >> 6); + value = *p++ & 0x3f; + + while (--len) { + value = (value << 8) + *p++; + } + + *pos = p; + return value; +} + + +static uint64_t +ngx_quic_parse_pn(u_char **pos, ngx_int_t len, u_char *mask) +{ + u_char *p; + uint64_t value; + + p = *pos; + value = *p++ ^ *mask++; + + while (--len) { + value = (value << 8) + (*p++ ^ *mask++); + } + + *pos = p; + return value; +} + + +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; + + qc = ngx_pcalloc(c->pool, sizeof(ngx_quic_connection_t)); + if (qc == NULL) { + ngx_http_close_connection(c); + return; + } + + c->quic = qc; + + printf("buffer %p %p:%p:%p:%p \n", b, b->start, b->pos, b->last, b->end); + + 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_http_v2_parse_uint32(b->pos); + b->pos += 4; + + ngx_log_debug2(NGX_LOG_DEBUG_HTTP, rev->log, 0, + "quic flags:%xi version:%xD", flags, version); + + if (version != 0xff000017) { + ngx_log_error(NGX_LOG_INFO, rev->log, 0, "unsupported quic version"); + ngx_http_close_connection(c); + return; + } + + 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; + + uint64_t plen = ngx_quic_parse_int(&b->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.3: + * AES-Based header protection samples 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]; + const EVP_MD *digest; + 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"; + + digest = EVP_sha256(); + HKDF_extract(is, &is_len, digest, qc->dcid.data, qc->dcid.len, salt, + sizeof(salt)); + +#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 + + size_t hkdfl_len; + uint8_t hkdfl[20]; + uint8_t *p; + + /* draft-ietf-quic-tls-23#section-5.2 */ + + qc->client_in.len = SHA256_DIGEST_LENGTH; + qc->client_in.data = ngx_pnalloc(c->pool, qc->client_in.len); + if (qc->client_in.data == NULL) { + ngx_http_close_connection(c); + return; + } + + hkdfl_len = 2 + 1 + sizeof("tls13 client in") - 1 + 1; + hkdfl[0] = 0; + hkdfl[1] = qc->client_in.len; + hkdfl[2] = sizeof("tls13 client in") - 1; + p = ngx_cpymem(&hkdfl[3], "tls13 client in", + sizeof("tls13 client in") - 1); + *p = '\0'; + + if (HKDF_expand(qc->client_in.data, qc->client_in.len, + digest, is, is_len, hkdfl, hkdfl_len) + == 0) + { + ngx_ssl_error(NGX_LOG_INFO, rev->log, 0, + "HKDF_expand(client_in) failed"); + ngx_http_close_connection(c); + return; + } + + ngx_log_debug3(NGX_LOG_DEBUG_HTTP, rev->log, 0, + "quic EVP key:%d tag:%d nonce:%d", + EVP_AEAD_key_length(EVP_aead_aes_128_gcm()), + EVP_AEAD_max_tag_len(EVP_aead_aes_128_gcm()), + EVP_AEAD_nonce_length(EVP_aead_aes_128_gcm())); + + /* AEAD_AES_128_GCM prior to handshake, quic-tls-23#section-5.3 */ + + qc->client_in_key.len = EVP_AEAD_key_length(EVP_aead_aes_128_gcm()); + qc->client_in_key.data = ngx_pnalloc(c->pool, qc->client_in_key.len); + if (qc->client_in_key.data == NULL) { + ngx_http_close_connection(c); + return; + } + + hkdfl_len = 2 + 1 + sizeof("tls13 quic key") - 1 + 1; + hkdfl[1] = qc->client_in_key.len; + hkdfl[2] = sizeof("tls13 quic key") - 1; + p = ngx_cpymem(&hkdfl[3], "tls13 quic key", + sizeof("tls13 quic key") - 1); + *p = '\0'; + + if (HKDF_expand(qc->client_in_key.data, qc->client_in_key.len, + digest, qc->client_in.data, qc->client_in.len, + hkdfl, hkdfl_len) + == 0) + { + ngx_ssl_error(NGX_LOG_INFO, rev->log, 0, + "HKDF_expand(client_in_key) failed"); + ngx_http_close_connection(c); + return; + } + + qc->client_in_iv.len = EVP_AEAD_nonce_length(EVP_aead_aes_128_gcm()); + qc->client_in_iv.data = ngx_pnalloc(c->pool, qc->client_in_iv.len); + if (qc->client_in_iv.data == NULL) { + ngx_http_close_connection(c); + return; + } + + hkdfl_len = 2 + 1 + sizeof("tls13 quic iv") - 1 + 1; + hkdfl[1] = qc->client_in_iv.len; + hkdfl[2] = sizeof("tls13 quic iv") - 1; + p = ngx_cpymem(&hkdfl[3], "tls13 quic iv", sizeof("tls13 quic iv") - 1); + *p = '\0'; + + if (HKDF_expand(qc->client_in_iv.data, qc->client_in_iv.len, digest, + qc->client_in.data, qc->client_in.len, hkdfl, hkdfl_len) + == 0) + { + ngx_ssl_error(NGX_LOG_INFO, rev->log, 0, + "HKDF_expand(client_in_iv) failed"); + ngx_http_close_connection(c); + return; + } + + /* AEAD_AES_128_GCM prior to handshake, quic-tls-23#section-5.4.1 */ + + qc->client_in_hp.len = EVP_AEAD_key_length(EVP_aead_aes_128_gcm()); + qc->client_in_hp.data = ngx_pnalloc(c->pool, qc->client_in_hp.len); + if (qc->client_in_hp.data == NULL) { + ngx_http_close_connection(c); + return; + } + + hkdfl_len = 2 + 1 + sizeof("tls13 quic hp") - 1 + 1; + hkdfl[1] = qc->client_in_hp.len; + hkdfl[2] = sizeof("tls13 quic hp") - 1; + p = ngx_cpymem(&hkdfl[3], "tls13 quic hp", sizeof("tls13 quic hp") - 1); + *p = '\0'; + + if (HKDF_expand(qc->client_in_hp.data, qc->client_in_hp.len, digest, + qc->client_in.data, qc->client_in.len, hkdfl, hkdfl_len) + == 0) + { + ngx_ssl_error(NGX_LOG_INFO, rev->log, 0, + "HKDF_expand(client_in_hp) failed"); + ngx_http_close_connection(c); + return; + } + +#if (NGX_DEBUG) + if (c->log->log_level & NGX_LOG_DEBUG_EVENT) { + m = ngx_hex_dump(buf, qc->client_in.data, qc->client_in.len) - buf; + ngx_log_debug3(NGX_LOG_DEBUG_HTTP, rev->log, 0, + "quic client initial secret: %*s, len: %uz", + m, buf, qc->client_in.len); + + m = ngx_hex_dump(buf, qc->client_in_key.data, qc->client_in_key.len) + - buf; + ngx_log_debug3(NGX_LOG_DEBUG_HTTP, rev->log, 0, + "quic key: %*s, len: %uz", + m, buf, qc->client_in_key.len); + + m = ngx_hex_dump(buf, qc->client_in_iv.data, qc->client_in_iv.len) + - buf; + ngx_log_debug3(NGX_LOG_DEBUG_HTTP, rev->log, 0, + "quic iv: %*s, len: %uz", m, buf, qc->client_in_iv.len); + + m = ngx_hex_dump(buf, qc->client_in_hp.data, qc->client_in_hp.len) + - buf; + ngx_log_debug3(NGX_LOG_DEBUG_HTTP, rev->log, 0, + "quic hp: %*s, len: %uz", m, buf, qc->client_in_hp.len); + } +#endif + +// header protection + + EVP_CIPHER_CTX *ctx = EVP_CIPHER_CTX_new(); + uint8_t mask[16]; + int outlen; + + if (EVP_EncryptInit_ex(ctx, EVP_aes_128_ecb(), NULL, + qc->client_in_hp.data, NULL) + != 1) + { + EVP_CIPHER_CTX_free(ctx); + ngx_ssl_error(NGX_LOG_INFO, rev->log, 0, + "EVP_EncryptInit_ex() failed"); + ngx_http_close_connection(c); + return; + } + + if (!EVP_EncryptUpdate(ctx, mask, &outlen, sample, 16)) { + EVP_CIPHER_CTX_free(ctx); + ngx_ssl_error(NGX_LOG_INFO, rev->log, 0, + "EVP_EncryptUpdate() failed"); + ngx_http_close_connection(c); + return; + } + + EVP_CIPHER_CTX_free(ctx); + + 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 ciphertext; + ciphertext.data = b->pos; + ciphertext.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 + + EVP_AEAD_CTX *aead = EVP_AEAD_CTX_new(EVP_aead_aes_128_gcm(), + qc->client_in_key.data, + qc->client_in_key.len, + EVP_AEAD_DEFAULT_TAG_LENGTH); + uint8_t cleartext[1600]; + size_t cleartext_len = sizeof(cleartext); + + if (EVP_AEAD_CTX_open(aead, cleartext, &cleartext_len, sizeof(cleartext), + nonce, qc->client_in_iv.len, ciphertext.data, + ciphertext.len, ad.data, ad.len) + != 1) + { + EVP_AEAD_CTX_free(aead); + ngx_ssl_error(NGX_LOG_INFO, rev->log, 0, + "EVP_AEAD_CTX_open() failed"); + ngx_http_close_connection(c); + return; + } + + EVP_AEAD_CTX_free(aead); + +#if (NGX_DEBUG) + if (c->log->log_level & NGX_LOG_DEBUG_EVENT) { + m = ngx_hex_dump(buf, cleartext, ngx_min(cleartext_len, 256)) - buf; + ngx_log_debug4(NGX_LOG_DEBUG_HTTP, rev->log, 0, + "quic packet: %*s%s, len: %uz", + m, buf, m < 512 ? "" : "...", cleartext_len); + } +#endif + + 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; + } + + 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), + &cleartext[4], cleartext_len - 4)) + { + 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)); + + ngx_http_close_connection(c); + return; +} + + static void ngx_http_ssl_handshake(ngx_event_t *rev) { -- cgit v1.2.3 From f03fe916636c25bfe6ac9a63b48f28f4bfaa72b2 Mon Sep 17 00:00:00 2001 From: Sergey Kandaurov Date: Fri, 28 Feb 2020 13:09:51 +0300 Subject: Server Initial Keys. --- src/http/ngx_http_request.c | 141 ++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 137 insertions(+), 4 deletions(-) (limited to 'src/http/ngx_http_request.c') diff --git a/src/http/ngx_http_request.c b/src/http/ngx_http_request.c index 54a0da497..bc4f2a13b 100644 --- a/src/http/ngx_http_request.c +++ b/src/http/ngx_http_request.c @@ -898,7 +898,7 @@ ngx_http_quic_handshake(ngx_event_t *rev) "HKDF_expand(client_in_key) failed"); ngx_http_close_connection(c); return; - } + } qc->client_in_iv.len = EVP_AEAD_nonce_length(EVP_aead_aes_128_gcm()); qc->client_in_iv.data = ngx_pnalloc(c->pool, qc->client_in_iv.len); @@ -958,18 +958,151 @@ ngx_http_quic_handshake(ngx_event_t *rev) m = ngx_hex_dump(buf, qc->client_in_key.data, qc->client_in_key.len) - buf; ngx_log_debug3(NGX_LOG_DEBUG_HTTP, rev->log, 0, - "quic key: %*s, len: %uz", + "quic client key: %*s, len: %uz", m, buf, qc->client_in_key.len); m = ngx_hex_dump(buf, qc->client_in_iv.data, qc->client_in_iv.len) - buf; ngx_log_debug3(NGX_LOG_DEBUG_HTTP, rev->log, 0, - "quic iv: %*s, len: %uz", m, buf, qc->client_in_iv.len); + "quic client iv: %*s, len: %uz", + m, buf, qc->client_in_iv.len); m = ngx_hex_dump(buf, qc->client_in_hp.data, qc->client_in_hp.len) - buf; ngx_log_debug3(NGX_LOG_DEBUG_HTTP, rev->log, 0, - "quic hp: %*s, len: %uz", m, buf, qc->client_in_hp.len); + "quic client hp: %*s, len: %uz", + m, buf, qc->client_in_hp.len); + } +#endif + +// server initial + + /* draft-ietf-quic-tls-23#section-5.2 */ + + qc->server_in.len = SHA256_DIGEST_LENGTH; + qc->server_in.data = ngx_pnalloc(c->pool, qc->server_in.len); + if (qc->server_in.data == NULL) { + ngx_http_close_connection(c); + return; + } + + hkdfl_len = 2 + 1 + sizeof("tls13 server in") - 1 + 1; + hkdfl[0] = 0; + hkdfl[1] = qc->server_in.len; + hkdfl[2] = sizeof("tls13 server in") - 1; + p = ngx_cpymem(&hkdfl[3], "tls13 server in", + sizeof("tls13 server in") - 1); + *p = '\0'; + + if (HKDF_expand(qc->server_in.data, qc->server_in.len, + digest, is, is_len, hkdfl, hkdfl_len) + == 0) + { + ngx_ssl_error(NGX_LOG_INFO, rev->log, 0, + "HKDF_expand(server_in) failed"); + ngx_http_close_connection(c); + return; + } + + /* AEAD_AES_128_GCM prior to handshake, quic-tls-23#section-5.3 */ + + qc->server_in_key.len = EVP_AEAD_key_length(EVP_aead_aes_128_gcm()); + qc->server_in_key.data = ngx_pnalloc(c->pool, qc->server_in_key.len); + if (qc->server_in_key.data == NULL) { + ngx_http_close_connection(c); + return; + } + + hkdfl_len = 2 + 1 + sizeof("tls13 quic key") - 1 + 1; + hkdfl[1] = qc->server_in_key.len; + hkdfl[2] = sizeof("tls13 quic key") - 1; + p = ngx_cpymem(&hkdfl[3], "tls13 quic key", + sizeof("tls13 quic key") - 1); + *p = '\0'; + + if (HKDF_expand(qc->server_in_key.data, qc->server_in_key.len, + digest, qc->server_in.data, qc->server_in.len, + hkdfl, hkdfl_len) + == 0) + { + ngx_ssl_error(NGX_LOG_INFO, rev->log, 0, + "HKDF_expand(server_in_key) failed"); + ngx_http_close_connection(c); + return; + } + + qc->server_in_iv.len = EVP_AEAD_nonce_length(EVP_aead_aes_128_gcm()); + qc->server_in_iv.data = ngx_pnalloc(c->pool, qc->server_in_iv.len); + if (qc->server_in_iv.data == NULL) { + ngx_http_close_connection(c); + return; + } + + hkdfl_len = 2 + 1 + sizeof("tls13 quic iv") - 1 + 1; + hkdfl[1] = qc->server_in_iv.len; + hkdfl[2] = sizeof("tls13 quic iv") - 1; + p = ngx_cpymem(&hkdfl[3], "tls13 quic iv", sizeof("tls13 quic iv") - 1); + *p = '\0'; + + if (HKDF_expand(qc->server_in_iv.data, qc->server_in_iv.len, digest, + qc->server_in.data, qc->server_in.len, hkdfl, hkdfl_len) + == 0) + { + ngx_ssl_error(NGX_LOG_INFO, rev->log, 0, + "HKDF_expand(server_in_iv) failed"); + ngx_http_close_connection(c); + return; + } + + /* AEAD_AES_128_GCM prior to handshake, quic-tls-23#section-5.4.1 */ + + qc->server_in_hp.len = EVP_AEAD_key_length(EVP_aead_aes_128_gcm()); + qc->server_in_hp.data = ngx_pnalloc(c->pool, qc->server_in_hp.len); + if (qc->server_in_hp.data == NULL) { + ngx_http_close_connection(c); + return; + } + + hkdfl_len = 2 + 1 + sizeof("tls13 quic hp") - 1 + 1; + hkdfl[1] = qc->server_in_hp.len; + hkdfl[2] = sizeof("tls13 quic hp") - 1; + p = ngx_cpymem(&hkdfl[3], "tls13 quic hp", sizeof("tls13 quic hp") - 1); + *p = '\0'; + + if (HKDF_expand(qc->server_in_hp.data, qc->server_in_hp.len, digest, + qc->server_in.data, qc->server_in.len, hkdfl, hkdfl_len) + == 0) + { + ngx_ssl_error(NGX_LOG_INFO, rev->log, 0, + "HKDF_expand(server_in_hp) failed"); + ngx_http_close_connection(c); + return; + } + +#if (NGX_DEBUG) + if (c->log->log_level & NGX_LOG_DEBUG_EVENT) { + m = ngx_hex_dump(buf, qc->server_in.data, qc->server_in.len) - buf; + ngx_log_debug3(NGX_LOG_DEBUG_HTTP, rev->log, 0, + "quic server initial secret: %*s, len: %uz", + m, buf, qc->server_in.len); + + m = ngx_hex_dump(buf, qc->server_in_key.data, qc->server_in_key.len) + - buf; + ngx_log_debug3(NGX_LOG_DEBUG_HTTP, rev->log, 0, + "quic server key: %*s, len: %uz", + m, buf, qc->server_in_key.len); + + m = ngx_hex_dump(buf, qc->server_in_iv.data, qc->server_in_iv.len) + - buf; + ngx_log_debug3(NGX_LOG_DEBUG_HTTP, rev->log, 0, + "quic server iv: %*s, len: %uz", + m, buf, qc->server_in_iv.len); + + m = ngx_hex_dump(buf, qc->server_in_hp.data, qc->server_in_hp.len) + - buf; + ngx_log_debug3(NGX_LOG_DEBUG_HTTP, rev->log, 0, + "quic server hp: %*s, len: %uz", + m, buf, qc->server_in_hp.len); } #endif -- cgit v1.2.3 From b77c2d00b57233a87350dedbe44897fcb0b7adf1 Mon Sep 17 00:00:00 2001 From: Sergey Kandaurov Date: Fri, 28 Feb 2020 13:09:51 +0300 Subject: QUIC set_encryption_secrets callback. --- src/http/ngx_http_request.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src/http/ngx_http_request.c') diff --git a/src/http/ngx_http_request.c b/src/http/ngx_http_request.c index bc4f2a13b..85b6835ee 100644 --- a/src/http/ngx_http_request.c +++ b/src/http/ngx_http_request.c @@ -783,8 +783,8 @@ ngx_http_quic_handshake(ngx_event_t *rev) uint64_t plen = ngx_quic_parse_int(&b->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.3: - * AES-Based header protection samples 16 bytes + * 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; -- cgit v1.2.3 From 812a0b69a072119de75d57ebdb222f540952c423 Mon Sep 17 00:00:00 2001 From: Sergey Kandaurov Date: Fri, 28 Feb 2020 13:09:51 +0300 Subject: QUIC add_handshake_data callback, varint routines. --- src/http/ngx_http_request.c | 40 +--------------------------------------- 1 file changed, 1 insertion(+), 39 deletions(-) (limited to 'src/http/ngx_http_request.c') diff --git a/src/http/ngx_http_request.c b/src/http/ngx_http_request.c index 85b6835ee..d128190c5 100644 --- a/src/http/ngx_http_request.c +++ b/src/http/ngx_http_request.c @@ -657,44 +657,6 @@ ngx_http_alloc_request(ngx_connection_t *c) #if (NGX_HTTP_SSL) -static uint64_t -ngx_quic_parse_int(u_char **pos) -{ - u_char *p; - uint64_t value; - ngx_uint_t len; - - p = *pos; - len = 1 << ((*p & 0xc0) >> 6); - value = *p++ & 0x3f; - - while (--len) { - value = (value << 8) + *p++; - } - - *pos = p; - return value; -} - - -static uint64_t -ngx_quic_parse_pn(u_char **pos, ngx_int_t len, u_char *mask) -{ - u_char *p; - uint64_t value; - - p = *pos; - value = *p++ ^ *mask++; - - while (--len) { - value = (value << 8) + (*p++ ^ *mask++); - } - - *pos = p; - return value; -} - - static void ngx_http_quic_handshake(ngx_event_t *rev) { @@ -1210,7 +1172,7 @@ ngx_http_quic_handshake(ngx_event_t *rev) if (c->log->log_level & NGX_LOG_DEBUG_EVENT) { m = ngx_hex_dump(buf, cleartext, ngx_min(cleartext_len, 256)) - buf; ngx_log_debug4(NGX_LOG_DEBUG_HTTP, rev->log, 0, - "quic packet: %*s%s, len: %uz", + "quic packet payload: %*s%s, len: %uz", m, buf, m < 512 ? "" : "...", cleartext_len); } #endif -- cgit v1.2.3 From ac640641a6ee09affe12a77cd7a944c1ac3148f0 Mon Sep 17 00:00:00 2001 From: Sergey Kandaurov Date: Fri, 28 Feb 2020 13:09:51 +0300 Subject: OpenSSL compatibility. --- src/http/ngx_http_request.c | 251 +++++++++++++++++++++++++++++++++++--------- 1 file changed, 199 insertions(+), 52 deletions(-) (limited to 'src/http/ngx_http_request.c') diff --git a/src/http/ngx_http_request.c b/src/http/ngx_http_request.c index d128190c5..17ad78986 100644 --- a/src/http/ngx_http_request.c +++ b/src/http/ngx_http_request.c @@ -775,16 +775,35 @@ ngx_http_quic_handshake(ngx_event_t *rev) // initial secret - size_t is_len; - uint8_t is[SHA256_DIGEST_LENGTH]; - const EVP_MD *digest; + size_t is_len; + uint8_t is[SHA256_DIGEST_LENGTH]; + const EVP_MD *digest; +#ifdef OPENSSL_IS_BORINGSSL + const EVP_AEAD *cipher; +#else + const EVP_CIPHER *cipher; +#endif 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"; digest = EVP_sha256(); - HKDF_extract(is, &is_len, digest, qc->dcid.data, qc->dcid.len, salt, - sizeof(salt)); + + /* AEAD_AES_128_GCM prior to handshake, quic-tls-23#section-5.3 */ + +#ifdef OPENSSL_IS_BORINGSSL + cipher = EVP_aead_aes_128_gcm(); +#else + cipher = EVP_aes_128_gcm(); +#endif + + 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; + } #if (NGX_DEBUG) if (c->log->log_level & NGX_LOG_DEBUG_EVENT) { @@ -812,6 +831,7 @@ ngx_http_quic_handshake(ngx_event_t *rev) } hkdfl_len = 2 + 1 + sizeof("tls13 client in") - 1 + 1; + bzero(hkdfl, sizeof(hkdfl)); hkdfl[0] = 0; hkdfl[1] = qc->client_in.len; hkdfl[2] = sizeof("tls13 client in") - 1; @@ -819,25 +839,39 @@ ngx_http_quic_handshake(ngx_event_t *rev) sizeof("tls13 client in") - 1); *p = '\0'; - if (HKDF_expand(qc->client_in.data, qc->client_in.len, - digest, is, is_len, hkdfl, hkdfl_len) - == 0) +#if 0 + ngx_memcpy(hkdfl, "\x00\x20\x0f\x74\x6c\x73\x31\x33\x20\x63\x6c\x69\x65\x6e\x74\x20\x69\x6e\x00\x00", 20); + + m = ngx_hex_dump(buf, hkdfl, sizeof(hkdfl)) - buf; + ngx_log_debug3(NGX_LOG_DEBUG_HTTP, rev->log, 0, + "quic initial secret hkdf: %*s, len: %uz", + m, buf, sizeof(hkdfl)); +#endif + + if (ngx_hkdf_expand(qc->client_in.data, qc->client_in.len, + digest, is, is_len, hkdfl, hkdfl_len) + != NGX_OK) { ngx_ssl_error(NGX_LOG_INFO, rev->log, 0, - "HKDF_expand(client_in) failed"); + "ngx_hkdf_expand(client_in) failed"); ngx_http_close_connection(c); return; } +#ifdef OPENSSL_IS_BORINGSSL ngx_log_debug3(NGX_LOG_DEBUG_HTTP, rev->log, 0, "quic EVP key:%d tag:%d nonce:%d", - EVP_AEAD_key_length(EVP_aead_aes_128_gcm()), - EVP_AEAD_max_tag_len(EVP_aead_aes_128_gcm()), - EVP_AEAD_nonce_length(EVP_aead_aes_128_gcm())); + EVP_AEAD_key_length(cipher), + EVP_AEAD_max_tag_len(cipher), + EVP_AEAD_nonce_length(cipher)); +#endif - /* AEAD_AES_128_GCM prior to handshake, quic-tls-23#section-5.3 */ - qc->client_in_key.len = EVP_AEAD_key_length(EVP_aead_aes_128_gcm()); +#ifdef OPENSSL_IS_BORINGSSL + qc->client_in_key.len = EVP_AEAD_key_length(cipher); +#else + qc->client_in_key.len = EVP_CIPHER_key_length(cipher); +#endif qc->client_in_key.data = ngx_pnalloc(c->pool, qc->client_in_key.len); if (qc->client_in_key.data == NULL) { ngx_http_close_connection(c); @@ -851,18 +885,22 @@ ngx_http_quic_handshake(ngx_event_t *rev) sizeof("tls13 quic key") - 1); *p = '\0'; - if (HKDF_expand(qc->client_in_key.data, qc->client_in_key.len, - digest, qc->client_in.data, qc->client_in.len, - hkdfl, hkdfl_len) - == 0) + if (ngx_hkdf_expand(qc->client_in_key.data, qc->client_in_key.len, + digest, qc->client_in.data, qc->client_in.len, + hkdfl, hkdfl_len) + != NGX_OK) { ngx_ssl_error(NGX_LOG_INFO, rev->log, 0, - "HKDF_expand(client_in_key) failed"); + "ngx_hkdf_expand(client_in_key) failed"); ngx_http_close_connection(c); return; } - qc->client_in_iv.len = EVP_AEAD_nonce_length(EVP_aead_aes_128_gcm()); +#ifdef OPENSSL_IS_BORINGSSL + qc->client_in_iv.len = EVP_AEAD_nonce_length(cipher); +#else + qc->client_in_iv.len = EVP_CIPHER_iv_length(cipher); +#endif qc->client_in_iv.data = ngx_pnalloc(c->pool, qc->client_in_iv.len); if (qc->client_in_iv.data == NULL) { ngx_http_close_connection(c); @@ -875,19 +913,24 @@ ngx_http_quic_handshake(ngx_event_t *rev) p = ngx_cpymem(&hkdfl[3], "tls13 quic iv", sizeof("tls13 quic iv") - 1); *p = '\0'; - if (HKDF_expand(qc->client_in_iv.data, qc->client_in_iv.len, digest, - qc->client_in.data, qc->client_in.len, hkdfl, hkdfl_len) - == 0) + if (ngx_hkdf_expand(qc->client_in_iv.data, qc->client_in_iv.len, + digest, qc->client_in.data, qc->client_in.len, + hkdfl, hkdfl_len) + != NGX_OK) { ngx_ssl_error(NGX_LOG_INFO, rev->log, 0, - "HKDF_expand(client_in_iv) failed"); + "ngx_hkdf_expand(client_in_iv) failed"); ngx_http_close_connection(c); return; } /* AEAD_AES_128_GCM prior to handshake, quic-tls-23#section-5.4.1 */ - qc->client_in_hp.len = EVP_AEAD_key_length(EVP_aead_aes_128_gcm()); +#ifdef OPENSSL_IS_BORINGSSL + qc->client_in_hp.len = EVP_AEAD_key_length(cipher); +#else + qc->client_in_hp.len = EVP_CIPHER_key_length(cipher); +#endif qc->client_in_hp.data = ngx_pnalloc(c->pool, qc->client_in_hp.len); if (qc->client_in_hp.data == NULL) { ngx_http_close_connection(c); @@ -900,12 +943,13 @@ ngx_http_quic_handshake(ngx_event_t *rev) p = ngx_cpymem(&hkdfl[3], "tls13 quic hp", sizeof("tls13 quic hp") - 1); *p = '\0'; - if (HKDF_expand(qc->client_in_hp.data, qc->client_in_hp.len, digest, - qc->client_in.data, qc->client_in.len, hkdfl, hkdfl_len) - == 0) + if (ngx_hkdf_expand(qc->client_in_hp.data, qc->client_in_hp.len, + digest, qc->client_in.data, qc->client_in.len, + hkdfl, hkdfl_len) + != NGX_OK) { ngx_ssl_error(NGX_LOG_INFO, rev->log, 0, - "HKDF_expand(client_in_hp) failed"); + "ngx_hkdf_expand(client_in_hp) failed"); ngx_http_close_connection(c); return; } @@ -956,19 +1000,23 @@ ngx_http_quic_handshake(ngx_event_t *rev) sizeof("tls13 server in") - 1); *p = '\0'; - if (HKDF_expand(qc->server_in.data, qc->server_in.len, - digest, is, is_len, hkdfl, hkdfl_len) - == 0) + if (ngx_hkdf_expand(qc->server_in.data, qc->server_in.len, + digest, is, is_len, hkdfl, hkdfl_len) + != NGX_OK) { ngx_ssl_error(NGX_LOG_INFO, rev->log, 0, - "HKDF_expand(server_in) failed"); + "ngx_hkdf_expand(server_in) failed"); ngx_http_close_connection(c); return; } /* AEAD_AES_128_GCM prior to handshake, quic-tls-23#section-5.3 */ - qc->server_in_key.len = EVP_AEAD_key_length(EVP_aead_aes_128_gcm()); +#ifdef OPENSSL_IS_BORINGSSL + qc->server_in_key.len = EVP_AEAD_key_length(cipher); +#else + qc->server_in_key.len = EVP_CIPHER_key_length(cipher); +#endif qc->server_in_key.data = ngx_pnalloc(c->pool, qc->server_in_key.len); if (qc->server_in_key.data == NULL) { ngx_http_close_connection(c); @@ -982,18 +1030,22 @@ ngx_http_quic_handshake(ngx_event_t *rev) sizeof("tls13 quic key") - 1); *p = '\0'; - if (HKDF_expand(qc->server_in_key.data, qc->server_in_key.len, - digest, qc->server_in.data, qc->server_in.len, - hkdfl, hkdfl_len) - == 0) + if (ngx_hkdf_expand(qc->server_in_key.data, qc->server_in_key.len, + digest, qc->server_in.data, qc->server_in.len, + hkdfl, hkdfl_len) + != NGX_OK) { ngx_ssl_error(NGX_LOG_INFO, rev->log, 0, - "HKDF_expand(server_in_key) failed"); + "ngx_hkdf_expand(server_in_key) failed"); ngx_http_close_connection(c); return; } - qc->server_in_iv.len = EVP_AEAD_nonce_length(EVP_aead_aes_128_gcm()); +#ifdef OPENSSL_IS_BORINGSSL + qc->server_in_iv.len = EVP_AEAD_nonce_length(cipher); +#else + qc->server_in_iv.len = EVP_CIPHER_iv_length(cipher); +#endif qc->server_in_iv.data = ngx_pnalloc(c->pool, qc->server_in_iv.len); if (qc->server_in_iv.data == NULL) { ngx_http_close_connection(c); @@ -1006,19 +1058,24 @@ ngx_http_quic_handshake(ngx_event_t *rev) p = ngx_cpymem(&hkdfl[3], "tls13 quic iv", sizeof("tls13 quic iv") - 1); *p = '\0'; - if (HKDF_expand(qc->server_in_iv.data, qc->server_in_iv.len, digest, - qc->server_in.data, qc->server_in.len, hkdfl, hkdfl_len) - == 0) + if (ngx_hkdf_expand(qc->server_in_iv.data, qc->server_in_iv.len, + digest, qc->server_in.data, qc->server_in.len, + hkdfl, hkdfl_len) + != NGX_OK) { ngx_ssl_error(NGX_LOG_INFO, rev->log, 0, - "HKDF_expand(server_in_iv) failed"); + "ngx_hkdf_expand(server_in_iv) failed"); ngx_http_close_connection(c); return; } /* AEAD_AES_128_GCM prior to handshake, quic-tls-23#section-5.4.1 */ - qc->server_in_hp.len = EVP_AEAD_key_length(EVP_aead_aes_128_gcm()); +#ifdef OPENSSL_IS_BORINGSSL + qc->server_in_hp.len = EVP_AEAD_key_length(cipher); +#else + qc->server_in_hp.len = EVP_CIPHER_key_length(cipher); +#endif qc->server_in_hp.data = ngx_pnalloc(c->pool, qc->server_in_hp.len); if (qc->server_in_hp.data == NULL) { ngx_http_close_connection(c); @@ -1031,12 +1088,13 @@ ngx_http_quic_handshake(ngx_event_t *rev) p = ngx_cpymem(&hkdfl[3], "tls13 quic hp", sizeof("tls13 quic hp") - 1); *p = '\0'; - if (HKDF_expand(qc->server_in_hp.data, qc->server_in_hp.len, digest, - qc->server_in.data, qc->server_in.len, hkdfl, hkdfl_len) - == 0) + if (ngx_hkdf_expand(qc->server_in_hp.data, qc->server_in_hp.len, + digest, qc->server_in.data, qc->server_in.len, + hkdfl, hkdfl_len) + != NGX_OK) { ngx_ssl_error(NGX_LOG_INFO, rev->log, 0, - "HKDF_expand(server_in_hp) failed"); + "ngx_hkdf_expand(server_in_hp) failed"); ngx_http_close_connection(c); return; } @@ -1147,12 +1205,20 @@ ngx_http_quic_handshake(ngx_event_t *rev) } #endif - EVP_AEAD_CTX *aead = EVP_AEAD_CTX_new(EVP_aead_aes_128_gcm(), + uint8_t cleartext[1600]; + size_t cleartext_len; + +#ifdef OPENSSL_IS_BORINGSSL + EVP_AEAD_CTX *aead = EVP_AEAD_CTX_new(cipher, qc->client_in_key.data, qc->client_in_key.len, EVP_AEAD_DEFAULT_TAG_LENGTH); - uint8_t cleartext[1600]; - size_t cleartext_len = sizeof(cleartext); + if (aead == NULL) { + ngx_ssl_error(NGX_LOG_INFO, rev->log, 0, + "EVP_AEAD_CTX_new() failed"); + ngx_http_close_connection(c); + return; + } if (EVP_AEAD_CTX_open(aead, cleartext, &cleartext_len, sizeof(cleartext), nonce, qc->client_in_iv.len, ciphertext.data, @@ -1167,6 +1233,87 @@ ngx_http_quic_handshake(ngx_event_t *rev) } EVP_AEAD_CTX_free(aead); +#else + int len; + u_char *tag; + EVP_CIPHER_CTX *aead; + + aead = EVP_CIPHER_CTX_new(); + if (aead == NULL) { + ngx_ssl_error(NGX_LOG_INFO, rev->log, 0, "EVP_CIPHER_CTX_new() failed"); + ngx_http_close_connection(c); + return; + } + + if (EVP_DecryptInit_ex(aead, cipher, NULL, NULL, NULL) != 1) { + EVP_CIPHER_CTX_free(aead); + ngx_ssl_error(NGX_LOG_INFO, rev->log, 0, "EVP_DecryptInit_ex() failed"); + ngx_http_close_connection(c); + return; + } + + if (EVP_CIPHER_CTX_ctrl(aead, EVP_CTRL_GCM_SET_IVLEN, qc->client_in_iv.len, + NULL) + == 0) + { + EVP_CIPHER_CTX_free(aead); + ngx_ssl_error(NGX_LOG_INFO, rev->log, 0, + "EVP_CIPHER_CTX_ctrl(EVP_CTRL_GCM_SET_IVLEN) failed"); + ngx_http_close_connection(c); + return; + } + + if (EVP_DecryptInit_ex(aead, NULL, NULL, qc->client_in_key.data, nonce) + != 1) + { + EVP_CIPHER_CTX_free(aead); + ngx_ssl_error(NGX_LOG_INFO, rev->log, 0, "EVP_DecryptInit_ex() failed"); + ngx_http_close_connection(c); + return; + } + + if (EVP_DecryptUpdate(aead, NULL, &len, ad.data, ad.len) != 1) { + EVP_CIPHER_CTX_free(aead); + ngx_ssl_error(NGX_LOG_INFO, rev->log, 0, "EVP_DecryptUpdate() failed"); + ngx_http_close_connection(c); + return; + } + + if (EVP_DecryptUpdate(aead, cleartext, &len, ciphertext.data, + ciphertext.len - EVP_GCM_TLS_TAG_LEN) + != 1) + { + EVP_CIPHER_CTX_free(aead); + ngx_ssl_error(NGX_LOG_INFO, rev->log, 0, "EVP_DecryptUpdate() failed"); + ngx_http_close_connection(c); + return; + } + + cleartext_len = len; + tag = ciphertext.data + ciphertext.len - EVP_GCM_TLS_TAG_LEN; + + if (EVP_CIPHER_CTX_ctrl(aead, EVP_CTRL_GCM_SET_TAG, EVP_GCM_TLS_TAG_LEN, + tag) + == 0) + { + EVP_CIPHER_CTX_free(aead); + ngx_ssl_error(NGX_LOG_INFO, rev->log, 0, + "EVP_CIPHER_CTX_ctrl(EVP_CTRL_GCM_SET_TAG) failed"); + ngx_http_close_connection(c); + return; + } + + if (EVP_DecryptFinal_ex(aead, cleartext + len, &len) <= 0) { + EVP_CIPHER_CTX_free(aead); + ngx_ssl_error(NGX_LOG_INFO, rev->log, 0, "EVP_DecryptFinal_ex failed"); + ngx_http_close_connection(c); + return; + } + + cleartext_len += len; + + EVP_CIPHER_CTX_free(aead); +#endif #if (NGX_DEBUG) if (c->log->log_level & NGX_LOG_DEBUG_EVENT) { -- cgit v1.2.3 From 0ddf4a2e67beb96a8de26e3a00082ebc98987902 Mon Sep 17 00:00:00 2001 From: Sergey Kandaurov Date: Fri, 28 Feb 2020 13:09:52 +0300 Subject: PN-aware AEAD nonce, feeding proper CRYPTO length. --- src/http/ngx_http_request.c | 22 +++++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) (limited to 'src/http/ngx_http_request.c') diff --git a/src/http/ngx_http_request.c b/src/http/ngx_http_request.c index 17ad78986..fd30bf3d9 100644 --- a/src/http/ngx_http_request.c +++ b/src/http/ngx_http_request.c @@ -1324,6 +1324,26 @@ ngx_http_quic_handshake(ngx_event_t *rev) } #endif + if (cleartext[0] != 0x06) { + ngx_log_error(NGX_LOG_INFO, rev->log, 0, + "unexpected frame in initial packet"); + ngx_http_close_connection(c); + return; + } + + if (cleartext[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 = &cleartext[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, cleartext, 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) @@ -1351,7 +1371,7 @@ ngx_http_quic_handshake(ngx_event_t *rev) if (!SSL_provide_quic_data(c->ssl->connection, SSL_quic_read_level(c->ssl->connection), - &cleartext[4], cleartext_len - 4)) + crypto, crypto_len)) { ngx_ssl_error(NGX_LOG_INFO, rev->log, 0, "SSL_provide_quic_data() failed"); -- cgit v1.2.3 From 56a80c228a7f4211e507ce48edf023f907821f1e Mon Sep 17 00:00:00 2001 From: Sergey Kandaurov Date: Fri, 28 Feb 2020 13:09:52 +0300 Subject: Fixed indentation. --- src/http/ngx_http_request.c | 395 ++++++++++++++++++++++---------------------- 1 file changed, 196 insertions(+), 199 deletions(-) (limited to 'src/http/ngx_http_request.c') diff --git a/src/http/ngx_http_request.c b/src/http/ngx_http_request.c index fd30bf3d9..389d7488f 100644 --- a/src/http/ngx_http_request.c +++ b/src/http/ngx_http_request.c @@ -817,46 +817,46 @@ ngx_http_quic_handshake(ngx_event_t *rev) } #endif - size_t hkdfl_len; - uint8_t hkdfl[20]; - uint8_t *p; + size_t hkdfl_len; + uint8_t hkdfl[20]; + uint8_t *p; - /* draft-ietf-quic-tls-23#section-5.2 */ + /* draft-ietf-quic-tls-23#section-5.2 */ - qc->client_in.len = SHA256_DIGEST_LENGTH; - qc->client_in.data = ngx_pnalloc(c->pool, qc->client_in.len); - if (qc->client_in.data == NULL) { - ngx_http_close_connection(c); - return; - } + qc->client_in.len = SHA256_DIGEST_LENGTH; + qc->client_in.data = ngx_pnalloc(c->pool, qc->client_in.len); + if (qc->client_in.data == NULL) { + ngx_http_close_connection(c); + return; + } - hkdfl_len = 2 + 1 + sizeof("tls13 client in") - 1 + 1; - bzero(hkdfl, sizeof(hkdfl)); - hkdfl[0] = 0; - hkdfl[1] = qc->client_in.len; - hkdfl[2] = sizeof("tls13 client in") - 1; - p = ngx_cpymem(&hkdfl[3], "tls13 client in", - sizeof("tls13 client in") - 1); - *p = '\0'; + hkdfl_len = 2 + 1 + sizeof("tls13 client in") - 1 + 1; + bzero(hkdfl, sizeof(hkdfl)); + hkdfl[0] = 0; + hkdfl[1] = qc->client_in.len; + hkdfl[2] = sizeof("tls13 client in") - 1; + p = ngx_cpymem(&hkdfl[3], "tls13 client in", sizeof("tls13 client in") - 1); + *p = '\0'; #if 0 - ngx_memcpy(hkdfl, "\x00\x20\x0f\x74\x6c\x73\x31\x33\x20\x63\x6c\x69\x65\x6e\x74\x20\x69\x6e\x00\x00", 20); + ngx_memcpy(hkdfl, "\x00\x20\x0f\x74\x6c\x73\x31\x33\x20\x63" + "\x6c\x69\x65\x6e\x74\x20\x69\x6e\x00\x00", 20); - m = ngx_hex_dump(buf, hkdfl, sizeof(hkdfl)) - buf; - ngx_log_debug3(NGX_LOG_DEBUG_HTTP, rev->log, 0, - "quic initial secret hkdf: %*s, len: %uz", - m, buf, sizeof(hkdfl)); + m = ngx_hex_dump(buf, hkdfl, sizeof(hkdfl)) - buf; + ngx_log_debug3(NGX_LOG_DEBUG_HTTP, rev->log, 0, + "quic initial secret hkdf: %*s, len: %uz", + m, buf, sizeof(hkdfl)); #endif - if (ngx_hkdf_expand(qc->client_in.data, qc->client_in.len, - digest, is, is_len, hkdfl, hkdfl_len) - != NGX_OK) - { - ngx_ssl_error(NGX_LOG_INFO, rev->log, 0, - "ngx_hkdf_expand(client_in) failed"); - ngx_http_close_connection(c); - return; - } + if (ngx_hkdf_expand(qc->client_in.data, qc->client_in.len, + digest, is, is_len, hkdfl, hkdfl_len) + != NGX_OK) + { + ngx_ssl_error(NGX_LOG_INFO, rev->log, 0, + "ngx_hkdf_expand(client_in) failed"); + ngx_http_close_connection(c); + return; + } #ifdef OPENSSL_IS_BORINGSSL ngx_log_debug3(NGX_LOG_DEBUG_HTTP, rev->log, 0, @@ -868,91 +868,90 @@ ngx_http_quic_handshake(ngx_event_t *rev) #ifdef OPENSSL_IS_BORINGSSL - qc->client_in_key.len = EVP_AEAD_key_length(cipher); + qc->client_in_key.len = EVP_AEAD_key_length(cipher); #else - qc->client_in_key.len = EVP_CIPHER_key_length(cipher); + qc->client_in_key.len = EVP_CIPHER_key_length(cipher); #endif - qc->client_in_key.data = ngx_pnalloc(c->pool, qc->client_in_key.len); - if (qc->client_in_key.data == NULL) { - ngx_http_close_connection(c); - return; - } + qc->client_in_key.data = ngx_pnalloc(c->pool, qc->client_in_key.len); + if (qc->client_in_key.data == NULL) { + ngx_http_close_connection(c); + return; + } - hkdfl_len = 2 + 1 + sizeof("tls13 quic key") - 1 + 1; - hkdfl[1] = qc->client_in_key.len; - hkdfl[2] = sizeof("tls13 quic key") - 1; - p = ngx_cpymem(&hkdfl[3], "tls13 quic key", - sizeof("tls13 quic key") - 1); - *p = '\0'; + hkdfl_len = 2 + 1 + sizeof("tls13 quic key") - 1 + 1; + hkdfl[1] = qc->client_in_key.len; + hkdfl[2] = sizeof("tls13 quic key") - 1; + p = ngx_cpymem(&hkdfl[3], "tls13 quic key", sizeof("tls13 quic key") - 1); + *p = '\0'; - if (ngx_hkdf_expand(qc->client_in_key.data, qc->client_in_key.len, - digest, qc->client_in.data, qc->client_in.len, - hkdfl, hkdfl_len) - != NGX_OK) - { - ngx_ssl_error(NGX_LOG_INFO, rev->log, 0, - "ngx_hkdf_expand(client_in_key) failed"); - ngx_http_close_connection(c); - return; - } + if (ngx_hkdf_expand(qc->client_in_key.data, qc->client_in_key.len, + digest, qc->client_in.data, qc->client_in.len, + hkdfl, hkdfl_len) + != NGX_OK) + { + ngx_ssl_error(NGX_LOG_INFO, rev->log, 0, + "ngx_hkdf_expand(client_in_key) failed"); + ngx_http_close_connection(c); + return; + } #ifdef OPENSSL_IS_BORINGSSL - qc->client_in_iv.len = EVP_AEAD_nonce_length(cipher); + qc->client_in_iv.len = EVP_AEAD_nonce_length(cipher); #else - qc->client_in_iv.len = EVP_CIPHER_iv_length(cipher); + qc->client_in_iv.len = EVP_CIPHER_iv_length(cipher); #endif - qc->client_in_iv.data = ngx_pnalloc(c->pool, qc->client_in_iv.len); - if (qc->client_in_iv.data == NULL) { - ngx_http_close_connection(c); - return; - } + qc->client_in_iv.data = ngx_pnalloc(c->pool, qc->client_in_iv.len); + if (qc->client_in_iv.data == NULL) { + ngx_http_close_connection(c); + return; + } - hkdfl_len = 2 + 1 + sizeof("tls13 quic iv") - 1 + 1; - hkdfl[1] = qc->client_in_iv.len; - hkdfl[2] = sizeof("tls13 quic iv") - 1; - p = ngx_cpymem(&hkdfl[3], "tls13 quic iv", sizeof("tls13 quic iv") - 1); - *p = '\0'; + hkdfl_len = 2 + 1 + sizeof("tls13 quic iv") - 1 + 1; + hkdfl[1] = qc->client_in_iv.len; + hkdfl[2] = sizeof("tls13 quic iv") - 1; + p = ngx_cpymem(&hkdfl[3], "tls13 quic iv", sizeof("tls13 quic iv") - 1); + *p = '\0'; - if (ngx_hkdf_expand(qc->client_in_iv.data, qc->client_in_iv.len, - digest, qc->client_in.data, qc->client_in.len, - hkdfl, hkdfl_len) - != NGX_OK) - { - ngx_ssl_error(NGX_LOG_INFO, rev->log, 0, - "ngx_hkdf_expand(client_in_iv) failed"); - ngx_http_close_connection(c); - return; - } + if (ngx_hkdf_expand(qc->client_in_iv.data, qc->client_in_iv.len, + digest, qc->client_in.data, qc->client_in.len, + hkdfl, hkdfl_len) + != NGX_OK) + { + ngx_ssl_error(NGX_LOG_INFO, rev->log, 0, + "ngx_hkdf_expand(client_in_iv) failed"); + ngx_http_close_connection(c); + return; + } - /* AEAD_AES_128_GCM prior to handshake, quic-tls-23#section-5.4.1 */ + /* AEAD_AES_128_GCM prior to handshake, quic-tls-23#section-5.4.1 */ #ifdef OPENSSL_IS_BORINGSSL - qc->client_in_hp.len = EVP_AEAD_key_length(cipher); + qc->client_in_hp.len = EVP_AEAD_key_length(cipher); #else - qc->client_in_hp.len = EVP_CIPHER_key_length(cipher); + qc->client_in_hp.len = EVP_CIPHER_key_length(cipher); #endif - qc->client_in_hp.data = ngx_pnalloc(c->pool, qc->client_in_hp.len); - if (qc->client_in_hp.data == NULL) { - ngx_http_close_connection(c); - return; - } + qc->client_in_hp.data = ngx_pnalloc(c->pool, qc->client_in_hp.len); + if (qc->client_in_hp.data == NULL) { + ngx_http_close_connection(c); + return; + } - hkdfl_len = 2 + 1 + sizeof("tls13 quic hp") - 1 + 1; - hkdfl[1] = qc->client_in_hp.len; - hkdfl[2] = sizeof("tls13 quic hp") - 1; - p = ngx_cpymem(&hkdfl[3], "tls13 quic hp", sizeof("tls13 quic hp") - 1); - *p = '\0'; + hkdfl_len = 2 + 1 + sizeof("tls13 quic hp") - 1 + 1; + hkdfl[1] = qc->client_in_hp.len; + hkdfl[2] = sizeof("tls13 quic hp") - 1; + p = ngx_cpymem(&hkdfl[3], "tls13 quic hp", sizeof("tls13 quic hp") - 1); + *p = '\0'; - if (ngx_hkdf_expand(qc->client_in_hp.data, qc->client_in_hp.len, - digest, qc->client_in.data, qc->client_in.len, - hkdfl, hkdfl_len) - != NGX_OK) - { - ngx_ssl_error(NGX_LOG_INFO, rev->log, 0, - "ngx_hkdf_expand(client_in_hp) failed"); - ngx_http_close_connection(c); - return; - } + if (ngx_hkdf_expand(qc->client_in_hp.data, qc->client_in_hp.len, + digest, qc->client_in.data, qc->client_in.len, + hkdfl, hkdfl_len) + != NGX_OK) + { + ngx_ssl_error(NGX_LOG_INFO, rev->log, 0, + "ngx_hkdf_expand(client_in_hp) failed"); + ngx_http_close_connection(c); + return; + } #if (NGX_DEBUG) if (c->log->log_level & NGX_LOG_DEBUG_EVENT) { @@ -983,121 +982,119 @@ ngx_http_quic_handshake(ngx_event_t *rev) // server initial - /* draft-ietf-quic-tls-23#section-5.2 */ + /* draft-ietf-quic-tls-23#section-5.2 */ - qc->server_in.len = SHA256_DIGEST_LENGTH; - qc->server_in.data = ngx_pnalloc(c->pool, qc->server_in.len); - if (qc->server_in.data == NULL) { - ngx_http_close_connection(c); - return; - } + qc->server_in.len = SHA256_DIGEST_LENGTH; + qc->server_in.data = ngx_pnalloc(c->pool, qc->server_in.len); + if (qc->server_in.data == NULL) { + ngx_http_close_connection(c); + return; + } - hkdfl_len = 2 + 1 + sizeof("tls13 server in") - 1 + 1; - hkdfl[0] = 0; - hkdfl[1] = qc->server_in.len; - hkdfl[2] = sizeof("tls13 server in") - 1; - p = ngx_cpymem(&hkdfl[3], "tls13 server in", - sizeof("tls13 server in") - 1); - *p = '\0'; + hkdfl_len = 2 + 1 + sizeof("tls13 server in") - 1 + 1; + hkdfl[0] = 0; + hkdfl[1] = qc->server_in.len; + hkdfl[2] = sizeof("tls13 server in") - 1; + p = ngx_cpymem(&hkdfl[3], "tls13 server in", sizeof("tls13 server in") - 1); + *p = '\0'; - if (ngx_hkdf_expand(qc->server_in.data, qc->server_in.len, - digest, is, is_len, hkdfl, hkdfl_len) - != NGX_OK) - { - ngx_ssl_error(NGX_LOG_INFO, rev->log, 0, - "ngx_hkdf_expand(server_in) failed"); - ngx_http_close_connection(c); - return; - } + if (ngx_hkdf_expand(qc->server_in.data, qc->server_in.len, + digest, is, is_len, hkdfl, hkdfl_len) + != NGX_OK) + { + ngx_ssl_error(NGX_LOG_INFO, rev->log, 0, + "ngx_hkdf_expand(server_in) failed"); + ngx_http_close_connection(c); + return; + } - /* AEAD_AES_128_GCM prior to handshake, quic-tls-23#section-5.3 */ + /* AEAD_AES_128_GCM prior to handshake, quic-tls-23#section-5.3 */ #ifdef OPENSSL_IS_BORINGSSL - qc->server_in_key.len = EVP_AEAD_key_length(cipher); + qc->server_in_key.len = EVP_AEAD_key_length(cipher); #else - qc->server_in_key.len = EVP_CIPHER_key_length(cipher); + qc->server_in_key.len = EVP_CIPHER_key_length(cipher); #endif - qc->server_in_key.data = ngx_pnalloc(c->pool, qc->server_in_key.len); - if (qc->server_in_key.data == NULL) { - ngx_http_close_connection(c); - return; - } + qc->server_in_key.data = ngx_pnalloc(c->pool, qc->server_in_key.len); + if (qc->server_in_key.data == NULL) { + ngx_http_close_connection(c); + return; + } - hkdfl_len = 2 + 1 + sizeof("tls13 quic key") - 1 + 1; - hkdfl[1] = qc->server_in_key.len; - hkdfl[2] = sizeof("tls13 quic key") - 1; - p = ngx_cpymem(&hkdfl[3], "tls13 quic key", - sizeof("tls13 quic key") - 1); - *p = '\0'; + hkdfl_len = 2 + 1 + sizeof("tls13 quic key") - 1 + 1; + hkdfl[1] = qc->server_in_key.len; + hkdfl[2] = sizeof("tls13 quic key") - 1; + p = ngx_cpymem(&hkdfl[3], "tls13 quic key", sizeof("tls13 quic key") - 1); + *p = '\0'; - if (ngx_hkdf_expand(qc->server_in_key.data, qc->server_in_key.len, - digest, qc->server_in.data, qc->server_in.len, - hkdfl, hkdfl_len) - != NGX_OK) - { - ngx_ssl_error(NGX_LOG_INFO, rev->log, 0, - "ngx_hkdf_expand(server_in_key) failed"); - ngx_http_close_connection(c); - return; - } + if (ngx_hkdf_expand(qc->server_in_key.data, qc->server_in_key.len, + digest, qc->server_in.data, qc->server_in.len, + hkdfl, hkdfl_len) + != NGX_OK) + { + ngx_ssl_error(NGX_LOG_INFO, rev->log, 0, + "ngx_hkdf_expand(server_in_key) failed"); + ngx_http_close_connection(c); + return; + } #ifdef OPENSSL_IS_BORINGSSL - qc->server_in_iv.len = EVP_AEAD_nonce_length(cipher); + qc->server_in_iv.len = EVP_AEAD_nonce_length(cipher); #else - qc->server_in_iv.len = EVP_CIPHER_iv_length(cipher); + qc->server_in_iv.len = EVP_CIPHER_iv_length(cipher); #endif - qc->server_in_iv.data = ngx_pnalloc(c->pool, qc->server_in_iv.len); - if (qc->server_in_iv.data == NULL) { - ngx_http_close_connection(c); - return; - } + qc->server_in_iv.data = ngx_pnalloc(c->pool, qc->server_in_iv.len); + if (qc->server_in_iv.data == NULL) { + ngx_http_close_connection(c); + return; + } - hkdfl_len = 2 + 1 + sizeof("tls13 quic iv") - 1 + 1; - hkdfl[1] = qc->server_in_iv.len; - hkdfl[2] = sizeof("tls13 quic iv") - 1; - p = ngx_cpymem(&hkdfl[3], "tls13 quic iv", sizeof("tls13 quic iv") - 1); - *p = '\0'; + hkdfl_len = 2 + 1 + sizeof("tls13 quic iv") - 1 + 1; + hkdfl[1] = qc->server_in_iv.len; + hkdfl[2] = sizeof("tls13 quic iv") - 1; + p = ngx_cpymem(&hkdfl[3], "tls13 quic iv", sizeof("tls13 quic iv") - 1); + *p = '\0'; - if (ngx_hkdf_expand(qc->server_in_iv.data, qc->server_in_iv.len, - digest, qc->server_in.data, qc->server_in.len, - hkdfl, hkdfl_len) - != NGX_OK) - { - ngx_ssl_error(NGX_LOG_INFO, rev->log, 0, - "ngx_hkdf_expand(server_in_iv) failed"); - ngx_http_close_connection(c); - return; - } + if (ngx_hkdf_expand(qc->server_in_iv.data, qc->server_in_iv.len, + digest, qc->server_in.data, qc->server_in.len, + hkdfl, hkdfl_len) + != NGX_OK) + { + ngx_ssl_error(NGX_LOG_INFO, rev->log, 0, + "ngx_hkdf_expand(server_in_iv) failed"); + ngx_http_close_connection(c); + return; + } - /* AEAD_AES_128_GCM prior to handshake, quic-tls-23#section-5.4.1 */ + /* AEAD_AES_128_GCM prior to handshake, quic-tls-23#section-5.4.1 */ #ifdef OPENSSL_IS_BORINGSSL - qc->server_in_hp.len = EVP_AEAD_key_length(cipher); + qc->server_in_hp.len = EVP_AEAD_key_length(cipher); #else - qc->server_in_hp.len = EVP_CIPHER_key_length(cipher); + qc->server_in_hp.len = EVP_CIPHER_key_length(cipher); #endif - qc->server_in_hp.data = ngx_pnalloc(c->pool, qc->server_in_hp.len); - if (qc->server_in_hp.data == NULL) { - ngx_http_close_connection(c); - return; - } + qc->server_in_hp.data = ngx_pnalloc(c->pool, qc->server_in_hp.len); + if (qc->server_in_hp.data == NULL) { + ngx_http_close_connection(c); + return; + } - hkdfl_len = 2 + 1 + sizeof("tls13 quic hp") - 1 + 1; - hkdfl[1] = qc->server_in_hp.len; - hkdfl[2] = sizeof("tls13 quic hp") - 1; - p = ngx_cpymem(&hkdfl[3], "tls13 quic hp", sizeof("tls13 quic hp") - 1); - *p = '\0'; + hkdfl_len = 2 + 1 + sizeof("tls13 quic hp") - 1 + 1; + hkdfl[1] = qc->server_in_hp.len; + hkdfl[2] = sizeof("tls13 quic hp") - 1; + p = ngx_cpymem(&hkdfl[3], "tls13 quic hp", sizeof("tls13 quic hp") - 1); + *p = '\0'; - if (ngx_hkdf_expand(qc->server_in_hp.data, qc->server_in_hp.len, - digest, qc->server_in.data, qc->server_in.len, - hkdfl, hkdfl_len) - != NGX_OK) - { - ngx_ssl_error(NGX_LOG_INFO, rev->log, 0, - "ngx_hkdf_expand(server_in_hp) failed"); - ngx_http_close_connection(c); - return; - } + if (ngx_hkdf_expand(qc->server_in_hp.data, qc->server_in_hp.len, + digest, qc->server_in.data, qc->server_in.len, + hkdfl, hkdfl_len) + != NGX_OK) + { + ngx_ssl_error(NGX_LOG_INFO, rev->log, 0, + "ngx_hkdf_expand(server_in_hp) failed"); + ngx_http_close_connection(c); + return; + } #if (NGX_DEBUG) if (c->log->log_level & NGX_LOG_DEBUG_EVENT) { @@ -1214,8 +1211,7 @@ ngx_http_quic_handshake(ngx_event_t *rev) qc->client_in_key.len, EVP_AEAD_DEFAULT_TAG_LENGTH); if (aead == NULL) { - ngx_ssl_error(NGX_LOG_INFO, rev->log, 0, - "EVP_AEAD_CTX_new() failed"); + ngx_ssl_error(NGX_LOG_INFO, rev->log, 0, "EVP_AEAD_CTX_new() failed"); ngx_http_close_connection(c); return; } @@ -1342,7 +1338,8 @@ ngx_http_quic_handshake(ngx_event_t *rev) 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, cleartext, crypto); + "quic initial packet CRYPTO length: %uL pp:%p:%p", + crypto_len, cleartext, crypto); sscf = ngx_http_get_module_srv_conf(hc->conf_ctx, ngx_http_ssl_module); @@ -1373,10 +1370,10 @@ ngx_http_quic_handshake(ngx_event_t *rev) 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; + 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); -- cgit v1.2.3 From aba1768d94a834dac08c8252576ca5279d4108ef Mon Sep 17 00:00:00 2001 From: Sergey Kandaurov Date: Fri, 28 Feb 2020 13:09:52 +0300 Subject: QUIC handshake handler, draft 24 bump. --- src/http/ngx_http_request.c | 356 +++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 353 insertions(+), 3 deletions(-) (limited to 'src/http/ngx_http_request.c') diff --git a/src/http/ngx_http_request.c b/src/http/ngx_http_request.c index 389d7488f..b8bca5547 100644 --- a/src/http/ngx_http_request.c +++ b/src/http/ngx_http_request.c @@ -64,6 +64,7 @@ static void ngx_http_ssl_handshake(ngx_event_t *rev); static void ngx_http_ssl_handshake_handler(ngx_connection_t *c); static void ngx_http_quic_handshake(ngx_event_t *rev); +static void ngx_http_quic_handshake_handler(ngx_event_t *rev); #endif @@ -706,7 +707,7 @@ ngx_http_quic_handshake(ngx_event_t *rev) ngx_log_debug2(NGX_LOG_DEBUG_HTTP, rev->log, 0, "quic flags:%xi version:%xD", flags, version); - if (version != 0xff000017) { + if (version != 0xff000018) { ngx_log_error(NGX_LOG_INFO, rev->log, 0, "unsupported quic version"); ngx_http_close_connection(c); return; @@ -742,7 +743,14 @@ ngx_http_quic_handshake(ngx_event_t *rev) ngx_memcpy(qc->token.data, b->pos, qc->token.len); b->pos += qc->token.len; - uint64_t plen = ngx_quic_parse_int(&b->pos); + 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]: @@ -1396,11 +1404,353 @@ ngx_http_quic_handshake(ngx_event_t *rev) (int) SSL_quic_read_level(c->ssl->connection), (int) SSL_quic_write_level(c->ssl->connection)); - ngx_http_close_connection(c); + if (!rev->timer_set) { + ngx_add_timer(rev, c->listening->post_accept_timeout); + } + + rev->handler = ngx_http_quic_handshake_handler; return; } +static void +ngx_http_quic_handshake_handler(ngx_event_t *rev) +{ + size_t m; + ssize_t n; + ngx_connection_t *c; + ngx_quic_connection_t *qc; + u_char buf[4096], b[512], *p; + + c = rev->data; + qc = c->quic; + p = b; + + ngx_log_debug0(NGX_LOG_DEBUG_HTTP, rev->log, 0, "quic handshake handler"); + + if (rev->timedout) { + ngx_log_error(NGX_LOG_INFO, c->log, NGX_ETIMEDOUT, "client timed out"); + ngx_http_close_connection(c); + return; + } + + if (c->close) { + ngx_http_close_connection(c); + return; + } + + n = c->recv(c, b, sizeof(b)); + + if (n == NGX_AGAIN) { + return; + } + + if (n == NGX_ERROR) { + c->read->eof = 1; + ngx_http_close_connection(c); + 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); + + /* XXX bug-for-bug compat - assuming initial ack in handshake pkt */ + + if ((p[0] & 0xf0) != 0xe0) { + ngx_log_error(NGX_LOG_INFO, rev->log, 0, "invalid packet type"); + ngx_http_close_connection(c); + return; + } + + ngx_int_t flags = *p++; + uint32_t version = ngx_http_v2_parse_uint32(p); + p += 4; + + ngx_log_debug2(NGX_LOG_DEBUG_HTTP, rev->log, 0, + "quic flags:%xi version:%xD", flags, version); + + if (version != 0xff000018) { + 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 + + EVP_CIPHER_CTX *ctx = EVP_CIPHER_CTX_new(); + uint8_t mask[16]; + int outlen; + + if (EVP_EncryptInit_ex(ctx, EVP_aes_128_ecb(), NULL, + qc->client_hs_hp.data, NULL) + != 1) + { + EVP_CIPHER_CTX_free(ctx); + ngx_ssl_error(NGX_LOG_INFO, rev->log, 0, + "EVP_EncryptInit_ex() failed"); + ngx_http_close_connection(c); + return; + } + + if (!EVP_EncryptUpdate(ctx, mask, &outlen, sample, 16)) { + EVP_CIPHER_CTX_free(ctx); + ngx_ssl_error(NGX_LOG_INFO, rev->log, 0, + "EVP_EncryptUpdate() failed"); + ngx_http_close_connection(c); + return; + } + + EVP_CIPHER_CTX_free(ctx); + + 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 ciphertext; + ciphertext.data = p; + ciphertext.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 + +#ifdef OPENSSL_IS_BORINGSSL + const EVP_AEAD *cipher; +#else + const EVP_CIPHER *cipher; +#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) + { +#ifdef OPENSSL_IS_BORINGSSL + cipher = EVP_aead_aes_128_gcm(); +#else + cipher = EVP_aes_128_gcm(); +#endif + + } else if (ngx_strcasecmp(name, (u_char *) "TLS_AES_256_GCM_SHA384") == 0) { +#ifdef OPENSSL_IS_BORINGSSL + cipher = EVP_aead_aes_256_gcm(); +#else + cipher = EVP_aes_256_gcm(); +#endif + + } else { + ngx_ssl_error(NGX_LOG_INFO, rev->log, 0, "unexpected cipher"); + ngx_http_close_connection(c); + return; + } + + + uint8_t cleartext[1600]; + size_t cleartext_len; + +#ifdef OPENSSL_IS_BORINGSSL + EVP_AEAD_CTX *aead = EVP_AEAD_CTX_new(cipher, + qc->client_hs_key.data, + qc->client_hs_key.len, + EVP_AEAD_DEFAULT_TAG_LENGTH); + if (aead == NULL) { + ngx_ssl_error(NGX_LOG_INFO, rev->log, 0, "EVP_AEAD_CTX_new() failed"); + ngx_http_close_connection(c); + return; + } + + if (EVP_AEAD_CTX_open(aead, cleartext, &cleartext_len, sizeof(cleartext), + nonce, qc->client_hs_iv.len, ciphertext.data, + ciphertext.len, ad.data, ad.len) + != 1) + { + EVP_AEAD_CTX_free(aead); + ngx_ssl_error(NGX_LOG_INFO, rev->log, 0, + "EVP_AEAD_CTX_open() failed"); + ngx_http_close_connection(c); + return; + } + + EVP_AEAD_CTX_free(aead); +#else + int len; + u_char *tag; + EVP_CIPHER_CTX *aead; + + aead = EVP_CIPHER_CTX_new(); + if (aead == NULL) { + ngx_ssl_error(NGX_LOG_INFO, rev->log, 0, "EVP_CIPHER_CTX_new() failed"); + ngx_http_close_connection(c); + return; + } + + if (EVP_DecryptInit_ex(aead, cipher, NULL, NULL, NULL) != 1) { + EVP_CIPHER_CTX_free(aead); + ngx_ssl_error(NGX_LOG_INFO, rev->log, 0, "EVP_DecryptInit_ex() failed"); + ngx_http_close_connection(c); + return; + } + + if (EVP_CIPHER_CTX_ctrl(aead, EVP_CTRL_GCM_SET_IVLEN, qc->client_hs_iv.len, + NULL) + == 0) + { + EVP_CIPHER_CTX_free(aead); + ngx_ssl_error(NGX_LOG_INFO, rev->log, 0, + "EVP_CIPHER_CTX_ctrl(EVP_CTRL_GCM_SET_IVLEN) failed"); + ngx_http_close_connection(c); + return; + } + + if (EVP_DecryptInit_ex(aead, NULL, NULL, qc->client_hs_key.data, nonce) + != 1) + { + EVP_CIPHER_CTX_free(aead); + ngx_ssl_error(NGX_LOG_INFO, rev->log, 0, "EVP_DecryptInit_ex() failed"); + ngx_http_close_connection(c); + return; + } + + if (EVP_DecryptUpdate(aead, NULL, &len, ad.data, ad.len) != 1) { + EVP_CIPHER_CTX_free(aead); + ngx_ssl_error(NGX_LOG_INFO, rev->log, 0, "EVP_DecryptUpdate() failed"); + ngx_http_close_connection(c); + return; + } + + if (EVP_DecryptUpdate(aead, cleartext, &len, ciphertext.data, + ciphertext.len - EVP_GCM_TLS_TAG_LEN) + != 1) + { + EVP_CIPHER_CTX_free(aead); + ngx_ssl_error(NGX_LOG_INFO, rev->log, 0, "EVP_DecryptUpdate() failed"); + ngx_http_close_connection(c); + return; + } + + cleartext_len = len; + tag = ciphertext.data + ciphertext.len - EVP_GCM_TLS_TAG_LEN; + + if (EVP_CIPHER_CTX_ctrl(aead, EVP_CTRL_GCM_SET_TAG, EVP_GCM_TLS_TAG_LEN, + tag) + == 0) + { + EVP_CIPHER_CTX_free(aead); + ngx_ssl_error(NGX_LOG_INFO, rev->log, 0, + "EVP_CIPHER_CTX_ctrl(EVP_CTRL_GCM_SET_TAG) failed"); + ngx_http_close_connection(c); + return; + } + + if (EVP_DecryptFinal_ex(aead, cleartext + len, &len) <= 0) { + EVP_CIPHER_CTX_free(aead); + ngx_ssl_error(NGX_LOG_INFO, rev->log, 0, "EVP_DecryptFinal_ex failed"); + ngx_http_close_connection(c); + return; + } + + cleartext_len += len; + + EVP_CIPHER_CTX_free(aead); +#endif + +#if (NGX_DEBUG) + if (c->log->log_level & NGX_LOG_DEBUG_EVENT) { + m = ngx_hex_dump(buf, cleartext, ngx_min(cleartext_len, 256)) - buf; + ngx_log_debug4(NGX_LOG_DEBUG_HTTP, rev->log, 0, + "quic packet payload: %*s%s, len: %uz", + m, buf, m < 512 ? "" : "...", cleartext_len); + } +#endif + + ngx_http_close_connection(c); +} + + static void ngx_http_ssl_handshake(ngx_event_t *rev) { -- cgit v1.2.3 From 27e5e87784f1464e9c40f31e8c119918073fb90b Mon Sep 17 00:00:00 2001 From: Sergey Kandaurov Date: Fri, 28 Feb 2020 13:09:52 +0300 Subject: Introduced ngx_quic_secret_t. --- src/http/ngx_http_request.c | 176 ++++++++++++++++++++++---------------------- 1 file changed, 88 insertions(+), 88 deletions(-) (limited to 'src/http/ngx_http_request.c') diff --git a/src/http/ngx_http_request.c b/src/http/ngx_http_request.c index b8bca5547..7f62643c1 100644 --- a/src/http/ngx_http_request.c +++ b/src/http/ngx_http_request.c @@ -831,9 +831,9 @@ ngx_http_quic_handshake(ngx_event_t *rev) /* draft-ietf-quic-tls-23#section-5.2 */ - qc->client_in.len = SHA256_DIGEST_LENGTH; - qc->client_in.data = ngx_pnalloc(c->pool, qc->client_in.len); - if (qc->client_in.data == NULL) { + qc->client_in.secret.len = SHA256_DIGEST_LENGTH; + qc->client_in.secret.data = ngx_pnalloc(c->pool, qc->client_in.secret.len); + if (qc->client_in.secret.data == NULL) { ngx_http_close_connection(c); return; } @@ -841,7 +841,7 @@ ngx_http_quic_handshake(ngx_event_t *rev) hkdfl_len = 2 + 1 + sizeof("tls13 client in") - 1 + 1; bzero(hkdfl, sizeof(hkdfl)); hkdfl[0] = 0; - hkdfl[1] = qc->client_in.len; + hkdfl[1] = qc->client_in.secret.len; hkdfl[2] = sizeof("tls13 client in") - 1; p = ngx_cpymem(&hkdfl[3], "tls13 client in", sizeof("tls13 client in") - 1); *p = '\0'; @@ -856,7 +856,7 @@ ngx_http_quic_handshake(ngx_event_t *rev) m, buf, sizeof(hkdfl)); #endif - if (ngx_hkdf_expand(qc->client_in.data, qc->client_in.len, + if (ngx_hkdf_expand(qc->client_in.secret.data, qc->client_in.secret.len, digest, is, is_len, hkdfl, hkdfl_len) != NGX_OK) { @@ -876,57 +876,57 @@ ngx_http_quic_handshake(ngx_event_t *rev) #ifdef OPENSSL_IS_BORINGSSL - qc->client_in_key.len = EVP_AEAD_key_length(cipher); + qc->client_in.key.len = EVP_AEAD_key_length(cipher); #else - qc->client_in_key.len = EVP_CIPHER_key_length(cipher); + qc->client_in.key.len = EVP_CIPHER_key_length(cipher); #endif - qc->client_in_key.data = ngx_pnalloc(c->pool, qc->client_in_key.len); - if (qc->client_in_key.data == NULL) { + qc->client_in.key.data = ngx_pnalloc(c->pool, qc->client_in.key.len); + if (qc->client_in.key.data == NULL) { ngx_http_close_connection(c); return; } hkdfl_len = 2 + 1 + sizeof("tls13 quic key") - 1 + 1; - hkdfl[1] = qc->client_in_key.len; + hkdfl[1] = qc->client_in.key.len; hkdfl[2] = sizeof("tls13 quic key") - 1; p = ngx_cpymem(&hkdfl[3], "tls13 quic key", sizeof("tls13 quic key") - 1); *p = '\0'; - if (ngx_hkdf_expand(qc->client_in_key.data, qc->client_in_key.len, - digest, qc->client_in.data, qc->client_in.len, + if (ngx_hkdf_expand(qc->client_in.key.data, qc->client_in.key.len, + digest, qc->client_in.secret.data, qc->client_in.secret.len, hkdfl, hkdfl_len) != NGX_OK) { ngx_ssl_error(NGX_LOG_INFO, rev->log, 0, - "ngx_hkdf_expand(client_in_key) failed"); + "ngx_hkdf_expand(client_in.key) failed"); ngx_http_close_connection(c); return; } #ifdef OPENSSL_IS_BORINGSSL - qc->client_in_iv.len = EVP_AEAD_nonce_length(cipher); + qc->client_in.iv.len = EVP_AEAD_nonce_length(cipher); #else - qc->client_in_iv.len = EVP_CIPHER_iv_length(cipher); + qc->client_in.iv.len = EVP_CIPHER_iv_length(cipher); #endif - qc->client_in_iv.data = ngx_pnalloc(c->pool, qc->client_in_iv.len); - if (qc->client_in_iv.data == NULL) { + qc->client_in.iv.data = ngx_pnalloc(c->pool, qc->client_in.iv.len); + if (qc->client_in.iv.data == NULL) { ngx_http_close_connection(c); return; } hkdfl_len = 2 + 1 + sizeof("tls13 quic iv") - 1 + 1; - hkdfl[1] = qc->client_in_iv.len; + hkdfl[1] = qc->client_in.iv.len; hkdfl[2] = sizeof("tls13 quic iv") - 1; p = ngx_cpymem(&hkdfl[3], "tls13 quic iv", sizeof("tls13 quic iv") - 1); *p = '\0'; - if (ngx_hkdf_expand(qc->client_in_iv.data, qc->client_in_iv.len, - digest, qc->client_in.data, qc->client_in.len, + if (ngx_hkdf_expand(qc->client_in.iv.data, qc->client_in.iv.len, + digest, qc->client_in.secret.data, qc->client_in.secret.len, hkdfl, hkdfl_len) != NGX_OK) { ngx_ssl_error(NGX_LOG_INFO, rev->log, 0, - "ngx_hkdf_expand(client_in_iv) failed"); + "ngx_hkdf_expand(client_in.iv) failed"); ngx_http_close_connection(c); return; } @@ -934,57 +934,57 @@ ngx_http_quic_handshake(ngx_event_t *rev) /* AEAD_AES_128_GCM prior to handshake, quic-tls-23#section-5.4.1 */ #ifdef OPENSSL_IS_BORINGSSL - qc->client_in_hp.len = EVP_AEAD_key_length(cipher); + qc->client_in.hp.len = EVP_AEAD_key_length(cipher); #else - qc->client_in_hp.len = EVP_CIPHER_key_length(cipher); + qc->client_in.hp.len = EVP_CIPHER_key_length(cipher); #endif - qc->client_in_hp.data = ngx_pnalloc(c->pool, qc->client_in_hp.len); - if (qc->client_in_hp.data == NULL) { + qc->client_in.hp.data = ngx_pnalloc(c->pool, qc->client_in.hp.len); + if (qc->client_in.hp.data == NULL) { ngx_http_close_connection(c); return; } hkdfl_len = 2 + 1 + sizeof("tls13 quic hp") - 1 + 1; - hkdfl[1] = qc->client_in_hp.len; + hkdfl[1] = qc->client_in.hp.len; hkdfl[2] = sizeof("tls13 quic hp") - 1; p = ngx_cpymem(&hkdfl[3], "tls13 quic hp", sizeof("tls13 quic hp") - 1); *p = '\0'; - if (ngx_hkdf_expand(qc->client_in_hp.data, qc->client_in_hp.len, - digest, qc->client_in.data, qc->client_in.len, + if (ngx_hkdf_expand(qc->client_in.hp.data, qc->client_in.hp.len, + digest, qc->client_in.secret.data, qc->client_in.secret.len, hkdfl, hkdfl_len) != NGX_OK) { ngx_ssl_error(NGX_LOG_INFO, rev->log, 0, - "ngx_hkdf_expand(client_in_hp) failed"); + "ngx_hkdf_expand(client_in.hp) failed"); ngx_http_close_connection(c); return; } #if (NGX_DEBUG) if (c->log->log_level & NGX_LOG_DEBUG_EVENT) { - m = ngx_hex_dump(buf, qc->client_in.data, qc->client_in.len) - buf; + m = ngx_hex_dump(buf, qc->client_in.secret.data, qc->client_in.secret.len) - buf; ngx_log_debug3(NGX_LOG_DEBUG_HTTP, rev->log, 0, "quic client initial secret: %*s, len: %uz", - m, buf, qc->client_in.len); + m, buf, qc->client_in.secret.len); - m = ngx_hex_dump(buf, qc->client_in_key.data, qc->client_in_key.len) + m = ngx_hex_dump(buf, qc->client_in.key.data, qc->client_in.key.len) - buf; ngx_log_debug3(NGX_LOG_DEBUG_HTTP, rev->log, 0, "quic client key: %*s, len: %uz", - m, buf, qc->client_in_key.len); + m, buf, qc->client_in.key.len); - m = ngx_hex_dump(buf, qc->client_in_iv.data, qc->client_in_iv.len) + m = ngx_hex_dump(buf, qc->client_in.iv.data, qc->client_in.iv.len) - buf; ngx_log_debug3(NGX_LOG_DEBUG_HTTP, rev->log, 0, "quic client iv: %*s, len: %uz", - m, buf, qc->client_in_iv.len); + m, buf, qc->client_in.iv.len); - m = ngx_hex_dump(buf, qc->client_in_hp.data, qc->client_in_hp.len) + m = ngx_hex_dump(buf, qc->client_in.hp.data, qc->client_in.hp.len) - buf; ngx_log_debug3(NGX_LOG_DEBUG_HTTP, rev->log, 0, "quic client hp: %*s, len: %uz", - m, buf, qc->client_in_hp.len); + m, buf, qc->client_in.hp.len); } #endif @@ -992,21 +992,21 @@ ngx_http_quic_handshake(ngx_event_t *rev) /* draft-ietf-quic-tls-23#section-5.2 */ - qc->server_in.len = SHA256_DIGEST_LENGTH; - qc->server_in.data = ngx_pnalloc(c->pool, qc->server_in.len); - if (qc->server_in.data == NULL) { + qc->server_in.secret.len = SHA256_DIGEST_LENGTH; + qc->server_in.secret.data = ngx_pnalloc(c->pool, qc->server_in.secret.len); + if (qc->server_in.secret.data == NULL) { ngx_http_close_connection(c); return; } hkdfl_len = 2 + 1 + sizeof("tls13 server in") - 1 + 1; hkdfl[0] = 0; - hkdfl[1] = qc->server_in.len; + hkdfl[1] = qc->server_in.secret.len; hkdfl[2] = sizeof("tls13 server in") - 1; p = ngx_cpymem(&hkdfl[3], "tls13 server in", sizeof("tls13 server in") - 1); *p = '\0'; - if (ngx_hkdf_expand(qc->server_in.data, qc->server_in.len, + if (ngx_hkdf_expand(qc->server_in.secret.data, qc->server_in.secret.len, digest, is, is_len, hkdfl, hkdfl_len) != NGX_OK) { @@ -1019,57 +1019,57 @@ ngx_http_quic_handshake(ngx_event_t *rev) /* AEAD_AES_128_GCM prior to handshake, quic-tls-23#section-5.3 */ #ifdef OPENSSL_IS_BORINGSSL - qc->server_in_key.len = EVP_AEAD_key_length(cipher); + qc->server_in.key.len = EVP_AEAD_key_length(cipher); #else - qc->server_in_key.len = EVP_CIPHER_key_length(cipher); + qc->server_in.key.len = EVP_CIPHER_key_length(cipher); #endif - qc->server_in_key.data = ngx_pnalloc(c->pool, qc->server_in_key.len); - if (qc->server_in_key.data == NULL) { + qc->server_in.key.data = ngx_pnalloc(c->pool, qc->server_in.key.len); + if (qc->server_in.key.data == NULL) { ngx_http_close_connection(c); return; } hkdfl_len = 2 + 1 + sizeof("tls13 quic key") - 1 + 1; - hkdfl[1] = qc->server_in_key.len; + hkdfl[1] = qc->server_in.key.len; hkdfl[2] = sizeof("tls13 quic key") - 1; p = ngx_cpymem(&hkdfl[3], "tls13 quic key", sizeof("tls13 quic key") - 1); *p = '\0'; - if (ngx_hkdf_expand(qc->server_in_key.data, qc->server_in_key.len, - digest, qc->server_in.data, qc->server_in.len, + if (ngx_hkdf_expand(qc->server_in.key.data, qc->server_in.key.len, + digest, qc->server_in.secret.data, qc->server_in.secret.len, hkdfl, hkdfl_len) != NGX_OK) { ngx_ssl_error(NGX_LOG_INFO, rev->log, 0, - "ngx_hkdf_expand(server_in_key) failed"); + "ngx_hkdf_expand(server_in.key) failed"); ngx_http_close_connection(c); return; } #ifdef OPENSSL_IS_BORINGSSL - qc->server_in_iv.len = EVP_AEAD_nonce_length(cipher); + qc->server_in.iv.len = EVP_AEAD_nonce_length(cipher); #else - qc->server_in_iv.len = EVP_CIPHER_iv_length(cipher); + qc->server_in.iv.len = EVP_CIPHER_iv_length(cipher); #endif - qc->server_in_iv.data = ngx_pnalloc(c->pool, qc->server_in_iv.len); - if (qc->server_in_iv.data == NULL) { + qc->server_in.iv.data = ngx_pnalloc(c->pool, qc->server_in.iv.len); + if (qc->server_in.iv.data == NULL) { ngx_http_close_connection(c); return; } hkdfl_len = 2 + 1 + sizeof("tls13 quic iv") - 1 + 1; - hkdfl[1] = qc->server_in_iv.len; + hkdfl[1] = qc->server_in.iv.len; hkdfl[2] = sizeof("tls13 quic iv") - 1; p = ngx_cpymem(&hkdfl[3], "tls13 quic iv", sizeof("tls13 quic iv") - 1); *p = '\0'; - if (ngx_hkdf_expand(qc->server_in_iv.data, qc->server_in_iv.len, - digest, qc->server_in.data, qc->server_in.len, + if (ngx_hkdf_expand(qc->server_in.iv.data, qc->server_in.iv.len, + digest, qc->server_in.secret.data, qc->server_in.secret.len, hkdfl, hkdfl_len) != NGX_OK) { ngx_ssl_error(NGX_LOG_INFO, rev->log, 0, - "ngx_hkdf_expand(server_in_iv) failed"); + "ngx_hkdf_expand(server_in.iv) failed"); ngx_http_close_connection(c); return; } @@ -1077,57 +1077,57 @@ ngx_http_quic_handshake(ngx_event_t *rev) /* AEAD_AES_128_GCM prior to handshake, quic-tls-23#section-5.4.1 */ #ifdef OPENSSL_IS_BORINGSSL - qc->server_in_hp.len = EVP_AEAD_key_length(cipher); + qc->server_in.hp.len = EVP_AEAD_key_length(cipher); #else - qc->server_in_hp.len = EVP_CIPHER_key_length(cipher); + qc->server_in.hp.len = EVP_CIPHER_key_length(cipher); #endif - qc->server_in_hp.data = ngx_pnalloc(c->pool, qc->server_in_hp.len); - if (qc->server_in_hp.data == NULL) { + qc->server_in.hp.data = ngx_pnalloc(c->pool, qc->server_in.hp.len); + if (qc->server_in.hp.data == NULL) { ngx_http_close_connection(c); return; } hkdfl_len = 2 + 1 + sizeof("tls13 quic hp") - 1 + 1; - hkdfl[1] = qc->server_in_hp.len; + hkdfl[1] = qc->server_in.hp.len; hkdfl[2] = sizeof("tls13 quic hp") - 1; p = ngx_cpymem(&hkdfl[3], "tls13 quic hp", sizeof("tls13 quic hp") - 1); *p = '\0'; - if (ngx_hkdf_expand(qc->server_in_hp.data, qc->server_in_hp.len, - digest, qc->server_in.data, qc->server_in.len, + if (ngx_hkdf_expand(qc->server_in.hp.data, qc->server_in.hp.len, + digest, qc->server_in.secret.data, qc->server_in.secret.len, hkdfl, hkdfl_len) != NGX_OK) { ngx_ssl_error(NGX_LOG_INFO, rev->log, 0, - "ngx_hkdf_expand(server_in_hp) failed"); + "ngx_hkdf_expand(server_in.hp) failed"); ngx_http_close_connection(c); return; } #if (NGX_DEBUG) if (c->log->log_level & NGX_LOG_DEBUG_EVENT) { - m = ngx_hex_dump(buf, qc->server_in.data, qc->server_in.len) - buf; + m = ngx_hex_dump(buf, qc->server_in.secret.data, qc->server_in.secret.len) - buf; ngx_log_debug3(NGX_LOG_DEBUG_HTTP, rev->log, 0, "quic server initial secret: %*s, len: %uz", - m, buf, qc->server_in.len); + m, buf, qc->server_in.secret.len); - m = ngx_hex_dump(buf, qc->server_in_key.data, qc->server_in_key.len) + m = ngx_hex_dump(buf, qc->server_in.key.data, qc->server_in.key.len) - buf; ngx_log_debug3(NGX_LOG_DEBUG_HTTP, rev->log, 0, "quic server key: %*s, len: %uz", - m, buf, qc->server_in_key.len); + m, buf, qc->server_in.key.len); - m = ngx_hex_dump(buf, qc->server_in_iv.data, qc->server_in_iv.len) + m = ngx_hex_dump(buf, qc->server_in.iv.data, qc->server_in.iv.len) - buf; ngx_log_debug3(NGX_LOG_DEBUG_HTTP, rev->log, 0, "quic server iv: %*s, len: %uz", - m, buf, qc->server_in_iv.len); + m, buf, qc->server_in.iv.len); - m = ngx_hex_dump(buf, qc->server_in_hp.data, qc->server_in_hp.len) + m = ngx_hex_dump(buf, qc->server_in.hp.data, qc->server_in.hp.len) - buf; ngx_log_debug3(NGX_LOG_DEBUG_HTTP, rev->log, 0, "quic server hp: %*s, len: %uz", - m, buf, qc->server_in_hp.len); + m, buf, qc->server_in.hp.len); } #endif @@ -1138,7 +1138,7 @@ ngx_http_quic_handshake(ngx_event_t *rev) int outlen; if (EVP_EncryptInit_ex(ctx, EVP_aes_128_ecb(), NULL, - qc->client_in_hp.data, NULL) + qc->client_in.hp.data, NULL) != 1) { EVP_CIPHER_CTX_free(ctx); @@ -1195,7 +1195,7 @@ ngx_http_quic_handshake(ngx_event_t *rev) ad.data[0] = clearflags; ad.data[ad.len - pnl] = (u_char)pn; - uint8_t *nonce = ngx_pstrdup(c->pool, &qc->client_in_iv); + uint8_t *nonce = ngx_pstrdup(c->pool, &qc->client_in.iv); nonce[11] ^= pn; #if (NGX_DEBUG) @@ -1215,8 +1215,8 @@ ngx_http_quic_handshake(ngx_event_t *rev) #ifdef OPENSSL_IS_BORINGSSL EVP_AEAD_CTX *aead = EVP_AEAD_CTX_new(cipher, - qc->client_in_key.data, - qc->client_in_key.len, + qc->client_in.key.data, + qc->client_in.key.len, EVP_AEAD_DEFAULT_TAG_LENGTH); if (aead == NULL) { ngx_ssl_error(NGX_LOG_INFO, rev->log, 0, "EVP_AEAD_CTX_new() failed"); @@ -1225,7 +1225,7 @@ ngx_http_quic_handshake(ngx_event_t *rev) } if (EVP_AEAD_CTX_open(aead, cleartext, &cleartext_len, sizeof(cleartext), - nonce, qc->client_in_iv.len, ciphertext.data, + nonce, qc->client_in.iv.len, ciphertext.data, ciphertext.len, ad.data, ad.len) != 1) { @@ -1256,7 +1256,7 @@ ngx_http_quic_handshake(ngx_event_t *rev) return; } - if (EVP_CIPHER_CTX_ctrl(aead, EVP_CTRL_GCM_SET_IVLEN, qc->client_in_iv.len, + if (EVP_CIPHER_CTX_ctrl(aead, EVP_CTRL_GCM_SET_IVLEN, qc->client_in.iv.len, NULL) == 0) { @@ -1267,7 +1267,7 @@ ngx_http_quic_handshake(ngx_event_t *rev) return; } - if (EVP_DecryptInit_ex(aead, NULL, NULL, qc->client_in_key.data, nonce) + if (EVP_DecryptInit_ex(aead, NULL, NULL, qc->client_in.key.data, nonce) != 1) { EVP_CIPHER_CTX_free(aead); @@ -1527,7 +1527,7 @@ ngx_http_quic_handshake_handler(ngx_event_t *rev) int outlen; if (EVP_EncryptInit_ex(ctx, EVP_aes_128_ecb(), NULL, - qc->client_hs_hp.data, NULL) + qc->client_hs.hp.data, NULL) != 1) { EVP_CIPHER_CTX_free(ctx); @@ -1581,7 +1581,7 @@ ngx_http_quic_handshake_handler(ngx_event_t *rev) ad.data[0] = clearflags; ad.data[ad.len - pnl] = (u_char)pn; - uint8_t *nonce = ngx_pstrdup(c->pool, &qc->client_hs_iv); + uint8_t *nonce = ngx_pstrdup(c->pool, &qc->client_hs.iv); nonce[11] ^= pn; #if (NGX_DEBUG) @@ -1634,8 +1634,8 @@ ngx_http_quic_handshake_handler(ngx_event_t *rev) #ifdef OPENSSL_IS_BORINGSSL EVP_AEAD_CTX *aead = EVP_AEAD_CTX_new(cipher, - qc->client_hs_key.data, - qc->client_hs_key.len, + qc->client_hs.key.data, + qc->client_hs.key.len, EVP_AEAD_DEFAULT_TAG_LENGTH); if (aead == NULL) { ngx_ssl_error(NGX_LOG_INFO, rev->log, 0, "EVP_AEAD_CTX_new() failed"); @@ -1644,7 +1644,7 @@ ngx_http_quic_handshake_handler(ngx_event_t *rev) } if (EVP_AEAD_CTX_open(aead, cleartext, &cleartext_len, sizeof(cleartext), - nonce, qc->client_hs_iv.len, ciphertext.data, + nonce, qc->client_hs.iv.len, ciphertext.data, ciphertext.len, ad.data, ad.len) != 1) { @@ -1675,7 +1675,7 @@ ngx_http_quic_handshake_handler(ngx_event_t *rev) return; } - if (EVP_CIPHER_CTX_ctrl(aead, EVP_CTRL_GCM_SET_IVLEN, qc->client_hs_iv.len, + if (EVP_CIPHER_CTX_ctrl(aead, EVP_CTRL_GCM_SET_IVLEN, qc->client_hs.iv.len, NULL) == 0) { @@ -1686,7 +1686,7 @@ ngx_http_quic_handshake_handler(ngx_event_t *rev) return; } - if (EVP_DecryptInit_ex(aead, NULL, NULL, qc->client_hs_key.data, nonce) + if (EVP_DecryptInit_ex(aead, NULL, NULL, qc->client_hs.key.data, nonce) != 1) { EVP_CIPHER_CTX_free(aead); -- cgit v1.2.3 From 8c90e6f440f432908ad70002bb6acb1f9aec1758 Mon Sep 17 00:00:00 2001 From: Sergey Kandaurov Date: Fri, 28 Feb 2020 13:09:52 +0300 Subject: Transport parameters stub, to complete handshake. --- src/http/ngx_http_request.c | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) (limited to 'src/http/ngx_http_request.c') diff --git a/src/http/ngx_http_request.c b/src/http/ngx_http_request.c index 7f62643c1..318933a40 100644 --- a/src/http/ngx_http_request.c +++ b/src/http/ngx_http_request.c @@ -1358,6 +1358,17 @@ ngx_http_quic_handshake(ngx_event_t *rev) 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"); + 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); @@ -1747,7 +1758,6 @@ ngx_http_quic_handshake_handler(ngx_event_t *rev) } #endif - ngx_http_close_connection(c); } -- cgit v1.2.3 From 56eead6176d2d63392fc82668b2233dfadbae33e Mon Sep 17 00:00:00 2001 From: Sergey Kandaurov Date: Fri, 28 Feb 2020 13:09:52 +0300 Subject: AEAD routines, introduced ngx_quic_tls_open()/ngx_quic_tls_seal(). --- src/http/ngx_http_request.c | 270 +++++--------------------------------------- 1 file changed, 27 insertions(+), 243 deletions(-) (limited to 'src/http/ngx_http_request.c') diff --git a/src/http/ngx_http_request.c b/src/http/ngx_http_request.c index 318933a40..c9bddc6dd 100644 --- a/src/http/ngx_http_request.c +++ b/src/http/ngx_http_request.c @@ -783,27 +783,18 @@ ngx_http_quic_handshake(ngx_event_t *rev) // initial secret - size_t is_len; - uint8_t is[SHA256_DIGEST_LENGTH]; - const EVP_MD *digest; -#ifdef OPENSSL_IS_BORINGSSL - const EVP_AEAD *cipher; -#else - const EVP_CIPHER *cipher; -#endif + size_t is_len; + uint8_t is[SHA256_DIGEST_LENGTH]; + const EVP_MD *digest; + const ngx_aead_cipher_t *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"; - digest = EVP_sha256(); - /* AEAD_AES_128_GCM prior to handshake, quic-tls-23#section-5.3 */ -#ifdef OPENSSL_IS_BORINGSSL - cipher = EVP_aead_aes_128_gcm(); -#else - cipher = EVP_aes_128_gcm(); -#endif + cipher = NGX_QUIC_INITIAL_CIPHER; + digest = EVP_sha256(); if (ngx_hkdf_extract(is, &is_len, digest, qc->dcid.data, qc->dcid.len, salt, sizeof(salt)) @@ -1179,9 +1170,9 @@ ngx_http_quic_handshake(ngx_event_t *rev) // packet protection - ngx_str_t ciphertext; - ciphertext.data = b->pos; - ciphertext.len = plen - pnl; + ngx_str_t in; + in.data = b->pos; + in.len = plen - pnl; ngx_str_t ad; ad.len = b->pos - b->start; @@ -1210,144 +1201,44 @@ ngx_http_quic_handshake(ngx_event_t *rev) } #endif - uint8_t cleartext[1600]; - size_t cleartext_len; - -#ifdef OPENSSL_IS_BORINGSSL - EVP_AEAD_CTX *aead = EVP_AEAD_CTX_new(cipher, - qc->client_in.key.data, - qc->client_in.key.len, - EVP_AEAD_DEFAULT_TAG_LENGTH); - if (aead == NULL) { - ngx_ssl_error(NGX_LOG_INFO, rev->log, 0, "EVP_AEAD_CTX_new() failed"); - ngx_http_close_connection(c); - return; - } - - if (EVP_AEAD_CTX_open(aead, cleartext, &cleartext_len, sizeof(cleartext), - nonce, qc->client_in.iv.len, ciphertext.data, - ciphertext.len, ad.data, ad.len) - != 1) - { - EVP_AEAD_CTX_free(aead); - ngx_ssl_error(NGX_LOG_INFO, rev->log, 0, - "EVP_AEAD_CTX_open() failed"); - ngx_http_close_connection(c); - return; - } - - EVP_AEAD_CTX_free(aead); -#else - int len; - u_char *tag; - EVP_CIPHER_CTX *aead; - - aead = EVP_CIPHER_CTX_new(); - if (aead == NULL) { - ngx_ssl_error(NGX_LOG_INFO, rev->log, 0, "EVP_CIPHER_CTX_new() failed"); - ngx_http_close_connection(c); - return; - } - - if (EVP_DecryptInit_ex(aead, cipher, NULL, NULL, NULL) != 1) { - EVP_CIPHER_CTX_free(aead); - ngx_ssl_error(NGX_LOG_INFO, rev->log, 0, "EVP_DecryptInit_ex() failed"); - ngx_http_close_connection(c); - return; - } + ngx_str_t out; - if (EVP_CIPHER_CTX_ctrl(aead, EVP_CTRL_GCM_SET_IVLEN, qc->client_in.iv.len, - NULL) - == 0) - { - EVP_CIPHER_CTX_free(aead); - ngx_ssl_error(NGX_LOG_INFO, rev->log, 0, - "EVP_CIPHER_CTX_ctrl(EVP_CTRL_GCM_SET_IVLEN) failed"); - ngx_http_close_connection(c); - return; - } - - if (EVP_DecryptInit_ex(aead, NULL, NULL, qc->client_in.key.data, nonce) - != 1) - { - EVP_CIPHER_CTX_free(aead); - ngx_ssl_error(NGX_LOG_INFO, rev->log, 0, "EVP_DecryptInit_ex() failed"); - ngx_http_close_connection(c); - return; - } - - if (EVP_DecryptUpdate(aead, NULL, &len, ad.data, ad.len) != 1) { - EVP_CIPHER_CTX_free(aead); - ngx_ssl_error(NGX_LOG_INFO, rev->log, 0, "EVP_DecryptUpdate() failed"); - ngx_http_close_connection(c); - return; - } - - if (EVP_DecryptUpdate(aead, cleartext, &len, ciphertext.data, - ciphertext.len - EVP_GCM_TLS_TAG_LEN) - != 1) - { - EVP_CIPHER_CTX_free(aead); - ngx_ssl_error(NGX_LOG_INFO, rev->log, 0, "EVP_DecryptUpdate() failed"); - ngx_http_close_connection(c); - return; - } - - cleartext_len = len; - tag = ciphertext.data + ciphertext.len - EVP_GCM_TLS_TAG_LEN; - - if (EVP_CIPHER_CTX_ctrl(aead, EVP_CTRL_GCM_SET_TAG, EVP_GCM_TLS_TAG_LEN, - tag) - == 0) + if (ngx_quic_tls_open(c, cipher, &qc->client_in, &out, nonce, &in, &ad) + != NGX_OK) { - EVP_CIPHER_CTX_free(aead); - ngx_ssl_error(NGX_LOG_INFO, rev->log, 0, - "EVP_CIPHER_CTX_ctrl(EVP_CTRL_GCM_SET_TAG) failed"); ngx_http_close_connection(c); return; } - if (EVP_DecryptFinal_ex(aead, cleartext + len, &len) <= 0) { - EVP_CIPHER_CTX_free(aead); - ngx_ssl_error(NGX_LOG_INFO, rev->log, 0, "EVP_DecryptFinal_ex failed"); - ngx_http_close_connection(c); - return; - } - - cleartext_len += len; - - EVP_CIPHER_CTX_free(aead); -#endif - #if (NGX_DEBUG) if (c->log->log_level & NGX_LOG_DEBUG_EVENT) { - m = ngx_hex_dump(buf, cleartext, ngx_min(cleartext_len, 256)) - buf; + 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 ? "" : "...", cleartext_len); + m, buf, m < 512 ? "" : "...", out.len); } #endif - if (cleartext[0] != 0x06) { + 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 (cleartext[1] != 0x00) { + 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 = &cleartext[2]; + 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, cleartext, crypto); + crypto_len, out.data, crypto); sscf = ngx_http_get_module_srv_conf(hc->conf_ctx, ngx_http_ssl_module); @@ -1466,8 +1357,6 @@ ngx_http_quic_handshake_handler(ngx_event_t *rev) ngx_log_debug3(NGX_LOG_DEBUG_HTTP, rev->log, 0, "quic handshake handler: %*s, len: %uz", m, buf, n); - /* XXX bug-for-bug compat - assuming initial ack in handshake pkt */ - if ((p[0] & 0xf0) != 0xe0) { ngx_log_error(NGX_LOG_INFO, rev->log, 0, "invalid packet type"); ngx_http_close_connection(c); @@ -1576,9 +1465,9 @@ ngx_http_quic_handshake_handler(ngx_event_t *rev) // packet protection - ngx_str_t ciphertext; - ciphertext.data = p; - ciphertext.len = plen - pnl; + ngx_str_t in; + in.data = p; + in.len = plen - pnl; ngx_str_t ad; ad.len = p - b; @@ -1607,11 +1496,7 @@ ngx_http_quic_handshake_handler(ngx_event_t *rev) } #endif -#ifdef OPENSSL_IS_BORINGSSL - const EVP_AEAD *cipher; -#else - const EVP_CIPHER *cipher; -#endif + const ngx_aead_cipher_t *cipher; u_char *name = (u_char *) SSL_get_cipher(c->ssl->connection); ngx_log_debug1(NGX_LOG_DEBUG_HTTP, rev->log, 0, @@ -1639,122 +1524,21 @@ ngx_http_quic_handshake_handler(ngx_event_t *rev) return; } + ngx_str_t out; - uint8_t cleartext[1600]; - size_t cleartext_len; - -#ifdef OPENSSL_IS_BORINGSSL - EVP_AEAD_CTX *aead = EVP_AEAD_CTX_new(cipher, - qc->client_hs.key.data, - qc->client_hs.key.len, - EVP_AEAD_DEFAULT_TAG_LENGTH); - if (aead == NULL) { - ngx_ssl_error(NGX_LOG_INFO, rev->log, 0, "EVP_AEAD_CTX_new() failed"); - ngx_http_close_connection(c); - return; - } - - if (EVP_AEAD_CTX_open(aead, cleartext, &cleartext_len, sizeof(cleartext), - nonce, qc->client_hs.iv.len, ciphertext.data, - ciphertext.len, ad.data, ad.len) - != 1) - { - EVP_AEAD_CTX_free(aead); - ngx_ssl_error(NGX_LOG_INFO, rev->log, 0, - "EVP_AEAD_CTX_open() failed"); - ngx_http_close_connection(c); - return; - } - - EVP_AEAD_CTX_free(aead); -#else - int len; - u_char *tag; - EVP_CIPHER_CTX *aead; - - aead = EVP_CIPHER_CTX_new(); - if (aead == NULL) { - ngx_ssl_error(NGX_LOG_INFO, rev->log, 0, "EVP_CIPHER_CTX_new() failed"); - ngx_http_close_connection(c); - return; - } - - if (EVP_DecryptInit_ex(aead, cipher, NULL, NULL, NULL) != 1) { - EVP_CIPHER_CTX_free(aead); - ngx_ssl_error(NGX_LOG_INFO, rev->log, 0, "EVP_DecryptInit_ex() failed"); - ngx_http_close_connection(c); - return; - } - - if (EVP_CIPHER_CTX_ctrl(aead, EVP_CTRL_GCM_SET_IVLEN, qc->client_hs.iv.len, - NULL) - == 0) - { - EVP_CIPHER_CTX_free(aead); - ngx_ssl_error(NGX_LOG_INFO, rev->log, 0, - "EVP_CIPHER_CTX_ctrl(EVP_CTRL_GCM_SET_IVLEN) failed"); - ngx_http_close_connection(c); - return; - } - - if (EVP_DecryptInit_ex(aead, NULL, NULL, qc->client_hs.key.data, nonce) - != 1) - { - EVP_CIPHER_CTX_free(aead); - ngx_ssl_error(NGX_LOG_INFO, rev->log, 0, "EVP_DecryptInit_ex() failed"); - ngx_http_close_connection(c); - return; - } - - if (EVP_DecryptUpdate(aead, NULL, &len, ad.data, ad.len) != 1) { - EVP_CIPHER_CTX_free(aead); - ngx_ssl_error(NGX_LOG_INFO, rev->log, 0, "EVP_DecryptUpdate() failed"); - ngx_http_close_connection(c); - return; - } - - if (EVP_DecryptUpdate(aead, cleartext, &len, ciphertext.data, - ciphertext.len - EVP_GCM_TLS_TAG_LEN) - != 1) - { - EVP_CIPHER_CTX_free(aead); - ngx_ssl_error(NGX_LOG_INFO, rev->log, 0, "EVP_DecryptUpdate() failed"); - ngx_http_close_connection(c); - return; - } - - cleartext_len = len; - tag = ciphertext.data + ciphertext.len - EVP_GCM_TLS_TAG_LEN; - - if (EVP_CIPHER_CTX_ctrl(aead, EVP_CTRL_GCM_SET_TAG, EVP_GCM_TLS_TAG_LEN, - tag) - == 0) + if (ngx_quic_tls_open(c, cipher, &qc->client_hs, &out, nonce, &in, &ad) + != NGX_OK) { - EVP_CIPHER_CTX_free(aead); - ngx_ssl_error(NGX_LOG_INFO, rev->log, 0, - "EVP_CIPHER_CTX_ctrl(EVP_CTRL_GCM_SET_TAG) failed"); ngx_http_close_connection(c); return; } - if (EVP_DecryptFinal_ex(aead, cleartext + len, &len) <= 0) { - EVP_CIPHER_CTX_free(aead); - ngx_ssl_error(NGX_LOG_INFO, rev->log, 0, "EVP_DecryptFinal_ex failed"); - ngx_http_close_connection(c); - return; - } - - cleartext_len += len; - - EVP_CIPHER_CTX_free(aead); -#endif - #if (NGX_DEBUG) if (c->log->log_level & NGX_LOG_DEBUG_EVENT) { - m = ngx_hex_dump(buf, cleartext, ngx_min(cleartext_len, 256)) - buf; + 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 ? "" : "...", cleartext_len); + m, buf, m < 512 ? "" : "...", out.len); } #endif -- cgit v1.2.3 From a3620d469f2378420b52199b5da4fff9fa0b8995 Mon Sep 17 00:00:00 2001 From: Sergey Kandaurov Date: Fri, 28 Feb 2020 13:09:52 +0300 Subject: QUIC header protection routines, introduced ngx_quic_tls_hp(). --- src/http/ngx_http_request.c | 42 ++++-------------------------------------- 1 file changed, 4 insertions(+), 38 deletions(-) (limited to 'src/http/ngx_http_request.c') diff --git a/src/http/ngx_http_request.c b/src/http/ngx_http_request.c index c9bddc6dd..8fbc20424 100644 --- a/src/http/ngx_http_request.c +++ b/src/http/ngx_http_request.c @@ -1124,31 +1124,14 @@ ngx_http_quic_handshake(ngx_event_t *rev) // header protection - EVP_CIPHER_CTX *ctx = EVP_CIPHER_CTX_new(); uint8_t mask[16]; - int outlen; - - if (EVP_EncryptInit_ex(ctx, EVP_aes_128_ecb(), NULL, - qc->client_in.hp.data, NULL) - != 1) + if (ngx_quic_tls_hp(c, EVP_aes_128_ecb(), &qc->client_in, mask, sample) + != NGX_OK) { - EVP_CIPHER_CTX_free(ctx); - ngx_ssl_error(NGX_LOG_INFO, rev->log, 0, - "EVP_EncryptInit_ex() failed"); ngx_http_close_connection(c); return; } - if (!EVP_EncryptUpdate(ctx, mask, &outlen, sample, 16)) { - EVP_CIPHER_CTX_free(ctx); - ngx_ssl_error(NGX_LOG_INFO, rev->log, 0, - "EVP_EncryptUpdate() failed"); - ngx_http_close_connection(c); - return; - } - - EVP_CIPHER_CTX_free(ctx); - 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]); @@ -1422,31 +1405,14 @@ ngx_http_quic_handshake_handler(ngx_event_t *rev) // header protection - EVP_CIPHER_CTX *ctx = EVP_CIPHER_CTX_new(); uint8_t mask[16]; - int outlen; - - if (EVP_EncryptInit_ex(ctx, EVP_aes_128_ecb(), NULL, - qc->client_hs.hp.data, NULL) - != 1) + if (ngx_quic_tls_hp(c, EVP_aes_128_ecb(), &qc->client_hs, mask, sample) + != NGX_OK) { - EVP_CIPHER_CTX_free(ctx); - ngx_ssl_error(NGX_LOG_INFO, rev->log, 0, - "EVP_EncryptInit_ex() failed"); ngx_http_close_connection(c); return; } - if (!EVP_EncryptUpdate(ctx, mask, &outlen, sample, 16)) { - EVP_CIPHER_CTX_free(ctx); - ngx_ssl_error(NGX_LOG_INFO, rev->log, 0, - "EVP_EncryptUpdate() failed"); - ngx_http_close_connection(c); - return; - } - - EVP_CIPHER_CTX_free(ctx); - 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]); -- cgit v1.2.3 From eb464a7feba7f3297e8127d5e707f36bec6b87a5 Mon Sep 17 00:00:00 2001 From: Vladimir Homutov Date: Wed, 26 Feb 2020 16:56:47 +0300 Subject: Generic function for HKDF expansion. --- src/http/ngx_http_request.c | 351 +++++++++----------------------------------- 1 file changed, 69 insertions(+), 282 deletions(-) (limited to 'src/http/ngx_http_request.c') diff --git a/src/http/ngx_http_request.c b/src/http/ngx_http_request.c index 8fbc20424..7aa5a6408 100644 --- a/src/http/ngx_http_request.c +++ b/src/http/ngx_http_request.c @@ -785,6 +785,7 @@ ngx_http_quic_handshake(ngx_event_t *rev) size_t is_len; uint8_t is[SHA256_DIGEST_LENGTH]; + ngx_uint_t i; const EVP_MD *digest; const ngx_aead_cipher_t *cipher; static const uint8_t salt[20] = @@ -804,6 +805,11 @@ ngx_http_quic_handshake(ngx_event_t *rev) 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; @@ -816,311 +822,92 @@ ngx_http_quic_handshake(ngx_event_t *rev) } #endif - size_t hkdfl_len; - uint8_t hkdfl[20]; - uint8_t *p; - /* draft-ietf-quic-tls-23#section-5.2 */ - qc->client_in.secret.len = SHA256_DIGEST_LENGTH; - qc->client_in.secret.data = ngx_pnalloc(c->pool, qc->client_in.secret.len); - if (qc->client_in.secret.data == NULL) { - ngx_http_close_connection(c); - return; - } - - hkdfl_len = 2 + 1 + sizeof("tls13 client in") - 1 + 1; - bzero(hkdfl, sizeof(hkdfl)); - hkdfl[0] = 0; - hkdfl[1] = qc->client_in.secret.len; - hkdfl[2] = sizeof("tls13 client in") - 1; - p = ngx_cpymem(&hkdfl[3], "tls13 client in", sizeof("tls13 client in") - 1); - *p = '\0'; - -#if 0 - ngx_memcpy(hkdfl, "\x00\x20\x0f\x74\x6c\x73\x31\x33\x20\x63" - "\x6c\x69\x65\x6e\x74\x20\x69\x6e\x00\x00", 20); - - m = ngx_hex_dump(buf, hkdfl, sizeof(hkdfl)) - buf; - ngx_log_debug3(NGX_LOG_DEBUG_HTTP, rev->log, 0, - "quic initial secret hkdf: %*s, len: %uz", - m, buf, sizeof(hkdfl)); -#endif - - if (ngx_hkdf_expand(qc->client_in.secret.data, qc->client_in.secret.len, - digest, is, is_len, hkdfl, hkdfl_len) - != NGX_OK) - { - ngx_ssl_error(NGX_LOG_INFO, rev->log, 0, - "ngx_hkdf_expand(client_in) failed"); - ngx_http_close_connection(c); - return; - } - -#ifdef OPENSSL_IS_BORINGSSL - ngx_log_debug3(NGX_LOG_DEBUG_HTTP, rev->log, 0, - "quic EVP key:%d tag:%d nonce:%d", - EVP_AEAD_key_length(cipher), - EVP_AEAD_max_tag_len(cipher), - EVP_AEAD_nonce_length(cipher)); -#endif - + qc->server_in.secret.len = SHA256_DIGEST_LENGTH; #ifdef OPENSSL_IS_BORINGSSL qc->client_in.key.len = EVP_AEAD_key_length(cipher); -#else - qc->client_in.key.len = EVP_CIPHER_key_length(cipher); -#endif - qc->client_in.key.data = ngx_pnalloc(c->pool, qc->client_in.key.len); - if (qc->client_in.key.data == NULL) { - ngx_http_close_connection(c); - return; - } - - hkdfl_len = 2 + 1 + sizeof("tls13 quic key") - 1 + 1; - hkdfl[1] = qc->client_in.key.len; - hkdfl[2] = sizeof("tls13 quic key") - 1; - p = ngx_cpymem(&hkdfl[3], "tls13 quic key", sizeof("tls13 quic key") - 1); - *p = '\0'; - - if (ngx_hkdf_expand(qc->client_in.key.data, qc->client_in.key.len, - digest, qc->client_in.secret.data, qc->client_in.secret.len, - hkdfl, hkdfl_len) - != NGX_OK) - { - ngx_ssl_error(NGX_LOG_INFO, rev->log, 0, - "ngx_hkdf_expand(client_in.key) failed"); - ngx_http_close_connection(c); - return; - } - -#ifdef OPENSSL_IS_BORINGSSL - qc->client_in.iv.len = EVP_AEAD_nonce_length(cipher); -#else - qc->client_in.iv.len = EVP_CIPHER_iv_length(cipher); -#endif - qc->client_in.iv.data = ngx_pnalloc(c->pool, qc->client_in.iv.len); - if (qc->client_in.iv.data == NULL) { - ngx_http_close_connection(c); - return; - } - - hkdfl_len = 2 + 1 + sizeof("tls13 quic iv") - 1 + 1; - hkdfl[1] = qc->client_in.iv.len; - hkdfl[2] = sizeof("tls13 quic iv") - 1; - p = ngx_cpymem(&hkdfl[3], "tls13 quic iv", sizeof("tls13 quic iv") - 1); - *p = '\0'; - - if (ngx_hkdf_expand(qc->client_in.iv.data, qc->client_in.iv.len, - digest, qc->client_in.secret.data, qc->client_in.secret.len, - hkdfl, hkdfl_len) - != NGX_OK) - { - ngx_ssl_error(NGX_LOG_INFO, rev->log, 0, - "ngx_hkdf_expand(client_in.iv) failed"); - ngx_http_close_connection(c); - return; - } - - /* AEAD_AES_128_GCM prior to handshake, quic-tls-23#section-5.4.1 */ + qc->server_in.key.len = EVP_AEAD_key_length(cipher); -#ifdef OPENSSL_IS_BORINGSSL qc->client_in.hp.len = EVP_AEAD_key_length(cipher); -#else - qc->client_in.hp.len = EVP_CIPHER_key_length(cipher); -#endif - qc->client_in.hp.data = ngx_pnalloc(c->pool, qc->client_in.hp.len); - if (qc->client_in.hp.data == NULL) { - ngx_http_close_connection(c); - return; - } - - hkdfl_len = 2 + 1 + sizeof("tls13 quic hp") - 1 + 1; - hkdfl[1] = qc->client_in.hp.len; - hkdfl[2] = sizeof("tls13 quic hp") - 1; - p = ngx_cpymem(&hkdfl[3], "tls13 quic hp", sizeof("tls13 quic hp") - 1); - *p = '\0'; - - if (ngx_hkdf_expand(qc->client_in.hp.data, qc->client_in.hp.len, - digest, qc->client_in.secret.data, qc->client_in.secret.len, - hkdfl, hkdfl_len) - != NGX_OK) - { - ngx_ssl_error(NGX_LOG_INFO, rev->log, 0, - "ngx_hkdf_expand(client_in.hp) failed"); - ngx_http_close_connection(c); - return; - } - -#if (NGX_DEBUG) - if (c->log->log_level & NGX_LOG_DEBUG_EVENT) { - m = ngx_hex_dump(buf, qc->client_in.secret.data, qc->client_in.secret.len) - buf; - ngx_log_debug3(NGX_LOG_DEBUG_HTTP, rev->log, 0, - "quic client initial secret: %*s, len: %uz", - m, buf, qc->client_in.secret.len); - - m = ngx_hex_dump(buf, qc->client_in.key.data, qc->client_in.key.len) - - buf; - ngx_log_debug3(NGX_LOG_DEBUG_HTTP, rev->log, 0, - "quic client key: %*s, len: %uz", - m, buf, qc->client_in.key.len); - - m = ngx_hex_dump(buf, qc->client_in.iv.data, qc->client_in.iv.len) - - buf; - ngx_log_debug3(NGX_LOG_DEBUG_HTTP, rev->log, 0, - "quic client iv: %*s, len: %uz", - m, buf, qc->client_in.iv.len); - - m = ngx_hex_dump(buf, qc->client_in.hp.data, qc->client_in.hp.len) - - buf; - ngx_log_debug3(NGX_LOG_DEBUG_HTTP, rev->log, 0, - "quic client hp: %*s, len: %uz", - m, buf, qc->client_in.hp.len); - } -#endif - -// server initial - - /* draft-ietf-quic-tls-23#section-5.2 */ - - qc->server_in.secret.len = SHA256_DIGEST_LENGTH; - qc->server_in.secret.data = ngx_pnalloc(c->pool, qc->server_in.secret.len); - if (qc->server_in.secret.data == NULL) { - ngx_http_close_connection(c); - return; - } - - hkdfl_len = 2 + 1 + sizeof("tls13 server in") - 1 + 1; - hkdfl[0] = 0; - hkdfl[1] = qc->server_in.secret.len; - hkdfl[2] = sizeof("tls13 server in") - 1; - p = ngx_cpymem(&hkdfl[3], "tls13 server in", sizeof("tls13 server in") - 1); - *p = '\0'; - - if (ngx_hkdf_expand(qc->server_in.secret.data, qc->server_in.secret.len, - digest, is, is_len, hkdfl, hkdfl_len) - != NGX_OK) - { - ngx_ssl_error(NGX_LOG_INFO, rev->log, 0, - "ngx_hkdf_expand(server_in) failed"); - ngx_http_close_connection(c); - return; - } - - /* AEAD_AES_128_GCM prior to handshake, quic-tls-23#section-5.3 */ + qc->server_in.hp.len = EVP_AEAD_key_length(cipher); -#ifdef OPENSSL_IS_BORINGSSL - qc->server_in.key.len = EVP_AEAD_key_length(cipher); + qc->client_in.iv.len = EVP_AEAD_nonce_length(cipher); + qc->server_in.iv.len = EVP_AEAD_nonce_length(cipher); #else + qc->client_in.key.len = EVP_CIPHER_key_length(cipher); qc->server_in.key.len = EVP_CIPHER_key_length(cipher); -#endif - qc->server_in.key.data = ngx_pnalloc(c->pool, qc->server_in.key.len); - if (qc->server_in.key.data == NULL) { - ngx_http_close_connection(c); - return; - } - - hkdfl_len = 2 + 1 + sizeof("tls13 quic key") - 1 + 1; - hkdfl[1] = qc->server_in.key.len; - hkdfl[2] = sizeof("tls13 quic key") - 1; - p = ngx_cpymem(&hkdfl[3], "tls13 quic key", sizeof("tls13 quic key") - 1); - *p = '\0'; - if (ngx_hkdf_expand(qc->server_in.key.data, qc->server_in.key.len, - digest, qc->server_in.secret.data, qc->server_in.secret.len, - hkdfl, hkdfl_len) - != NGX_OK) - { - ngx_ssl_error(NGX_LOG_INFO, rev->log, 0, - "ngx_hkdf_expand(server_in.key) failed"); - ngx_http_close_connection(c); - return; - } + qc->client_in.hp.len = EVP_CIPHER_key_length(cipher); + qc->server_in.hp.len = EVP_CIPHER_key_length(cipher); -#ifdef OPENSSL_IS_BORINGSSL - qc->server_in.iv.len = EVP_AEAD_nonce_length(cipher); -#else + qc->client_in.iv.len = EVP_CIPHER_iv_length(cipher); qc->server_in.iv.len = EVP_CIPHER_iv_length(cipher); #endif - qc->server_in.iv.data = ngx_pnalloc(c->pool, qc->server_in.iv.len); - if (qc->server_in.iv.data == NULL) { - ngx_http_close_connection(c); - return; - } - - hkdfl_len = 2 + 1 + sizeof("tls13 quic iv") - 1 + 1; - hkdfl[1] = qc->server_in.iv.len; - hkdfl[2] = sizeof("tls13 quic iv") - 1; - p = ngx_cpymem(&hkdfl[3], "tls13 quic iv", sizeof("tls13 quic iv") - 1); - *p = '\0'; - - if (ngx_hkdf_expand(qc->server_in.iv.data, qc->server_in.iv.len, - digest, qc->server_in.secret.data, qc->server_in.secret.len, - hkdfl, hkdfl_len) - != NGX_OK) - { - ngx_ssl_error(NGX_LOG_INFO, rev->log, 0, - "ngx_hkdf_expand(server_in.iv) failed"); - ngx_http_close_connection(c); - return; - } - - /* AEAD_AES_128_GCM prior to handshake, quic-tls-23#section-5.4.1 */ #ifdef OPENSSL_IS_BORINGSSL - qc->server_in.hp.len = EVP_AEAD_key_length(cipher); -#else - qc->server_in.hp.len = EVP_CIPHER_key_length(cipher); + ngx_log_debug3(NGX_LOG_DEBUG_HTTP, rev->log, 0, + "quic EVP key:%d tag:%d nonce:%d", + EVP_AEAD_key_length(cipher), + EVP_AEAD_max_tag_len(cipher), + EVP_AEAD_nonce_length(cipher)); #endif - qc->server_in.hp.data = ngx_pnalloc(c->pool, qc->server_in.hp.len); - if (qc->server_in.hp.data == NULL) { - ngx_http_close_connection(c); - return; - } - - hkdfl_len = 2 + 1 + sizeof("tls13 quic hp") - 1 + 1; - hkdfl[1] = qc->server_in.hp.len; - hkdfl[2] = sizeof("tls13 quic hp") - 1; - p = ngx_cpymem(&hkdfl[3], "tls13 quic hp", sizeof("tls13 quic hp") - 1); - *p = '\0'; - if (ngx_hkdf_expand(qc->server_in.hp.data, qc->server_in.hp.len, - digest, qc->server_in.secret.data, qc->server_in.secret.len, - hkdfl, hkdfl_len) - != NGX_OK) - { - ngx_ssl_error(NGX_LOG_INFO, rev->log, 0, - "ngx_hkdf_expand(server_in.hp) failed"); - ngx_http_close_connection(c); - return; - } + struct { + ngx_str_t id; + ngx_str_t *in; + ngx_str_t *prk; + } seq[] = { -#if (NGX_DEBUG) - if (c->log->log_level & NGX_LOG_DEBUG_EVENT) { - m = ngx_hex_dump(buf, qc->server_in.secret.data, qc->server_in.secret.len) - buf; - ngx_log_debug3(NGX_LOG_DEBUG_HTTP, rev->log, 0, - "quic server initial secret: %*s, len: %uz", - m, buf, qc->server_in.secret.len); + /* 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 + }, - m = ngx_hex_dump(buf, qc->server_in.key.data, qc->server_in.key.len) - - buf; - ngx_log_debug3(NGX_LOG_DEBUG_HTTP, rev->log, 0, - "quic server key: %*s, len: %uz", - m, buf, qc->server_in.key.len); + }; - m = ngx_hex_dump(buf, qc->server_in.iv.data, qc->server_in.iv.len) - - buf; - ngx_log_debug3(NGX_LOG_DEBUG_HTTP, rev->log, 0, - "quic server iv: %*s, len: %uz", - m, buf, qc->server_in.iv.len); + for (i = 0; i < (sizeof(seq) / sizeof(seq[0])); i++) { - m = ngx_hex_dump(buf, qc->server_in.hp.data, qc->server_in.hp.len) - - buf; - ngx_log_debug3(NGX_LOG_DEBUG_HTTP, rev->log, 0, - "quic server hp: %*s, len: %uz", - m, buf, qc->server_in.hp.len); + if (ngx_quic_hkdf_expand(c, digest, seq[i].in, seq[i].prk, &seq[i].id, 0) + != NGX_OK) + { + ngx_http_close_connection(c); + return; + } } -#endif // header protection -- cgit v1.2.3 From ef8b06b186a2f7ac25b8ee49a325c935c3e5bb9f Mon Sep 17 00:00:00 2001 From: Sergey Kandaurov Date: Fri, 28 Feb 2020 13:09:52 +0300 Subject: Cleanup. --- src/http/ngx_http_request.c | 67 +++++++++++++-------------------------------- 1 file changed, 19 insertions(+), 48 deletions(-) (limited to 'src/http/ngx_http_request.c') diff --git a/src/http/ngx_http_request.c b/src/http/ngx_http_request.c index 7aa5a6408..bc2797b21 100644 --- a/src/http/ngx_http_request.c +++ b/src/http/ngx_http_request.c @@ -678,16 +678,6 @@ ngx_http_quic_handshake(ngx_event_t *rev) hc = c->data; b = c->buffer; - qc = ngx_pcalloc(c->pool, sizeof(ngx_quic_connection_t)); - if (qc == NULL) { - ngx_http_close_connection(c); - return; - } - - c->quic = qc; - - printf("buffer %p %p:%p:%p:%p \n", b, b->start, b->pos, b->last, b->end); - if ((b->pos[0] & 0xf0) != 0xc0) { ngx_log_error(NGX_LOG_INFO, rev->log, 0, "invalid initial packet"); ngx_http_close_connection(c); @@ -713,6 +703,14 @@ ngx_http_quic_handshake(ngx_event_t *rev) 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) { @@ -787,14 +785,14 @@ ngx_http_quic_handshake(ngx_event_t *rev) uint8_t is[SHA256_DIGEST_LENGTH]; ngx_uint_t i; const EVP_MD *digest; - const ngx_aead_cipher_t *cipher; + 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 = NGX_QUIC_INITIAL_CIPHER; + cipher = EVP_aes_128_gcm(); digest = EVP_sha256(); if (ngx_hkdf_extract(is, &is_len, digest, qc->dcid.data, qc->dcid.len, @@ -826,16 +824,6 @@ ngx_http_quic_handshake(ngx_event_t *rev) qc->client_in.secret.len = SHA256_DIGEST_LENGTH; qc->server_in.secret.len = SHA256_DIGEST_LENGTH; -#ifdef OPENSSL_IS_BORINGSSL - qc->client_in.key.len = EVP_AEAD_key_length(cipher); - qc->server_in.key.len = EVP_AEAD_key_length(cipher); - - qc->client_in.hp.len = EVP_AEAD_key_length(cipher); - qc->server_in.hp.len = EVP_AEAD_key_length(cipher); - - qc->client_in.iv.len = EVP_AEAD_nonce_length(cipher); - qc->server_in.iv.len = EVP_AEAD_nonce_length(cipher); -#else qc->client_in.key.len = EVP_CIPHER_key_length(cipher); qc->server_in.key.len = EVP_CIPHER_key_length(cipher); @@ -844,19 +832,10 @@ ngx_http_quic_handshake(ngx_event_t *rev) qc->client_in.iv.len = EVP_CIPHER_iv_length(cipher); qc->server_in.iv.len = EVP_CIPHER_iv_length(cipher); -#endif - -#ifdef OPENSSL_IS_BORINGSSL - ngx_log_debug3(NGX_LOG_DEBUG_HTTP, rev->log, 0, - "quic EVP key:%d tag:%d nonce:%d", - EVP_AEAD_key_length(cipher), - EVP_AEAD_max_tag_len(cipher), - EVP_AEAD_nonce_length(cipher)); -#endif struct { - ngx_str_t id; - ngx_str_t *in; + ngx_str_t label; + ngx_str_t *key; ngx_str_t *prk; } seq[] = { @@ -894,14 +873,15 @@ ngx_http_quic_handshake(ngx_event_t *rev) /* 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 + &qc->server_in.secret, }, }; for (i = 0; i < (sizeof(seq) / sizeof(seq[0])); i++) { - if (ngx_quic_hkdf_expand(c, digest, seq[i].in, seq[i].prk, &seq[i].id, 0) + 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); @@ -973,7 +953,8 @@ ngx_http_quic_handshake(ngx_event_t *rev) ngx_str_t out; - if (ngx_quic_tls_open(c, cipher, &qc->client_in, &out, nonce, &in, &ad) + if (ngx_quic_tls_open(c, EVP_aes_128_gcm(), &qc->client_in, &out, nonce, + &in, &ad) != NGX_OK) { ngx_http_close_connection(c); @@ -1090,7 +1071,9 @@ 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; @@ -1249,8 +1232,6 @@ ngx_http_quic_handshake_handler(ngx_event_t *rev) } #endif - const ngx_aead_cipher_t *cipher; - 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); @@ -1258,18 +1239,10 @@ ngx_http_quic_handshake_handler(ngx_event_t *rev) if (ngx_strcasecmp(name, (u_char *) "TLS_AES_128_GCM_SHA256") == 0 || ngx_strcasecmp(name, (u_char *) "(NONE)") == 0) { -#ifdef OPENSSL_IS_BORINGSSL - cipher = EVP_aead_aes_128_gcm(); -#else cipher = EVP_aes_128_gcm(); -#endif } else if (ngx_strcasecmp(name, (u_char *) "TLS_AES_256_GCM_SHA384") == 0) { -#ifdef OPENSSL_IS_BORINGSSL - cipher = EVP_aead_aes_256_gcm(); -#else cipher = EVP_aes_256_gcm(); -#endif } else { ngx_ssl_error(NGX_LOG_INFO, rev->log, 0, "unexpected cipher"); @@ -1277,8 +1250,6 @@ ngx_http_quic_handshake_handler(ngx_event_t *rev) return; } - ngx_str_t out; - if (ngx_quic_tls_open(c, cipher, &qc->client_hs, &out, nonce, &in, &ad) != NGX_OK) { -- cgit v1.2.3 From 899372129879b5874ffddca4247fca12d3b7c257 Mon Sep 17 00:00:00 2001 From: Sergey Kandaurov Date: Fri, 28 Feb 2020 13:09:52 +0300 Subject: Introduced quic_version macro, uint16/uint32 routines ported. --- src/http/ngx_http_request.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'src/http/ngx_http_request.c') diff --git a/src/http/ngx_http_request.c b/src/http/ngx_http_request.c index bc2797b21..d40f50496 100644 --- a/src/http/ngx_http_request.c +++ b/src/http/ngx_http_request.c @@ -691,13 +691,13 @@ ngx_http_quic_handshake(ngx_event_t *rev) } ngx_int_t flags = *b->pos++; - uint32_t version = ngx_http_v2_parse_uint32(b->pos); - b->pos += 4; + 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 != 0xff000018) { + if (version != quic_version) { ngx_log_error(NGX_LOG_INFO, rev->log, 0, "unsupported quic version"); ngx_http_close_connection(c); return; @@ -1117,13 +1117,13 @@ ngx_http_quic_handshake_handler(ngx_event_t *rev) } ngx_int_t flags = *p++; - uint32_t version = ngx_http_v2_parse_uint32(p); - p += 4; + 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 != 0xff000018) { + if (version != quic_version) { ngx_log_error(NGX_LOG_INFO, rev->log, 0, "unsupported quic version"); ngx_http_close_connection(c); return; -- cgit v1.2.3 From b20ed8f7f1acc2a1ef38714ddd75c7ba7add5f1d Mon Sep 17 00:00:00 2001 From: Vladimir Homutov Date: Fri, 28 Feb 2020 16:23:25 +0300 Subject: 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. --- src/http/ngx_http_request.c | 555 +------------------------------------------- 1 file changed, 10 insertions(+), 545 deletions(-) (limited to 'src/http/ngx_http_request.c') 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 - } -- cgit v1.2.3 From 4f4f56f013eb0dbe5eb66bb2f22584aec26b13e6 Mon Sep 17 00:00:00 2001 From: Vladimir Homutov Date: Thu, 12 Mar 2020 16:54:43 +0300 Subject: HTTP/QUIC interface reworked. - events handling moved into src/event/ngx_event_quic.c - http invokes once ngx_quic_run() and passes stream callback (diff to original http_request.c is now minimal) - streams are stored in rbtree using ID as a key - when a new stream is registered, appropriate callback is called - ngx_quic_stream_t type represents STREAM and stored in c->qs --- src/http/ngx_http_request.c | 105 ++++++++------------------------------------ 1 file changed, 18 insertions(+), 87 deletions(-) (limited to 'src/http/ngx_http_request.c') diff --git a/src/http/ngx_http_request.c b/src/http/ngx_http_request.c index 6d89fef24..7a2c78046 100644 --- a/src/http/ngx_http_request.c +++ b/src/http/ngx_http_request.c @@ -62,11 +62,9 @@ static u_char *ngx_http_log_error_handler(ngx_http_request_t *r, #if (NGX_HTTP_SSL) static void ngx_http_ssl_handshake(ngx_event_t *rev); static void ngx_http_ssl_handshake_handler(ngx_connection_t *c); - -static void ngx_http_quic_handshake(ngx_event_t *rev); -static void ngx_http_quic_handshake_handler(ngx_event_t *rev); #endif +static void ngx_http_quic_stream_handler(ngx_connection_t *c); static char *ngx_http_client_errors[] = { @@ -333,9 +331,15 @@ ngx_http_init_connection(ngx_connection_t *c) #if (NGX_HTTP_SSL) if (hc->addr_conf->http3) { + ngx_http_ssl_srv_conf_t *sscf; + hc->quic = 1; - c->log->action = "QUIC handshaking"; - rev->handler = ngx_http_quic_handshake; + + sscf = ngx_http_get_module_srv_conf(hc->conf_ctx, ngx_http_ssl_module); + + ngx_quic_run(c, &sscf->ssl, c->listening->post_accept_timeout, + ngx_http_quic_stream_handler); + return; } #endif @@ -386,6 +390,15 @@ ngx_http_init_connection(ngx_connection_t *c) } +static void +ngx_http_quic_stream_handler(ngx_connection_t *c) +{ + ngx_quic_stream_t *qs = c->qs; + + printf("quic stream: 0x%lx\n", qs->id); +} + + static void ngx_http_wait_request_handler(ngx_event_t *rev) { @@ -401,10 +414,6 @@ ngx_http_wait_request_handler(ngx_event_t *rev) ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0, "http wait request handler"); - if (c->shared) { - goto request; - } - if (rev->timedout) { ngx_log_error(NGX_LOG_INFO, c->log, NGX_ETIMEDOUT, "client timed out"); ngx_http_close_connection(c); @@ -505,8 +514,6 @@ ngx_http_wait_request_handler(ngx_event_t *rev) } } -request: - c->log->action = "reading client request line"; ngx_reusable_connection(c, 0); @@ -658,82 +665,6 @@ ngx_http_alloc_request(ngx_connection_t *c) #if (NGX_HTTP_SSL) -static void -ngx_http_quic_handshake(ngx_event_t *rev) -{ - ngx_connection_t *c; - ngx_http_connection_t *hc; - 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; - - sscf = ngx_http_get_module_srv_conf(hc->conf_ctx, ngx_http_ssl_module); - - if (ngx_quic_input(c, &sscf->ssl, c->buffer) != NGX_OK) { - ngx_http_close_connection(c); - return; - } - - if (!rev->timer_set) { - ngx_add_timer(rev, c->listening->post_accept_timeout); - } - - rev->handler = ngx_http_quic_handshake_handler; - return; -} - - -static void -ngx_http_quic_handshake_handler(ngx_event_t *rev) -{ - ssize_t n; - ngx_connection_t *c; - u_char buf[512]; - ngx_buf_t b; - - b.start = buf; - b.end = buf + 512; - b.pos = b.last = b.start; - - c = rev->data; - - ngx_log_debug0(NGX_LOG_DEBUG_HTTP, rev->log, 0, "quic handshake handler"); - - if (rev->timedout) { - ngx_log_error(NGX_LOG_INFO, c->log, NGX_ETIMEDOUT, "client timed out"); - ngx_http_close_connection(c); - return; - } - - if (c->close) { - ngx_http_close_connection(c); - return; - } - - n = c->recv(c, b.start, b.end - b.start); - - if (n == NGX_AGAIN) { - return; - } - - if (n == NGX_ERROR) { - c->read->eof = 1; - ngx_http_close_connection(c); - return; - } - - b.last += n; - - if (ngx_quic_input(c, NULL, &b) != NGX_OK) { - ngx_http_close_connection(c); - return; - } -} - - static void ngx_http_ssl_handshake(ngx_event_t *rev) { -- cgit v1.2.3 From 5bc8cd4044fe49d672607c365929459969a338fc Mon Sep 17 00:00:00 2001 From: Sergey Kandaurov Date: Thu, 12 Mar 2020 18:08:26 +0300 Subject: Fix build. --- src/http/ngx_http_request.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'src/http/ngx_http_request.c') diff --git a/src/http/ngx_http_request.c b/src/http/ngx_http_request.c index 7a2c78046..f463e674e 100644 --- a/src/http/ngx_http_request.c +++ b/src/http/ngx_http_request.c @@ -395,7 +395,8 @@ ngx_http_quic_stream_handler(ngx_connection_t *c) { ngx_quic_stream_t *qs = c->qs; - printf("quic stream: 0x%lx\n", qs->id); + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->log, 0, + "quic stream: 0x%uXL", qs->id); } -- cgit v1.2.3 From 05d1464c68a269e2f6ed08b5559edb90dfd3ab1f Mon Sep 17 00:00:00 2001 From: Vladimir Homutov Date: Fri, 13 Mar 2020 14:39:23 +0300 Subject: Stream "connection" read/write methods. --- src/http/ngx_http_request.c | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) (limited to 'src/http/ngx_http_request.c') diff --git a/src/http/ngx_http_request.c b/src/http/ngx_http_request.c index f463e674e..55af26bf8 100644 --- a/src/http/ngx_http_request.c +++ b/src/http/ngx_http_request.c @@ -395,8 +395,39 @@ ngx_http_quic_stream_handler(ngx_connection_t *c) { ngx_quic_stream_t *qs = c->qs; + // STUB for stream read/write + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->log, 0, "quic stream: 0x%uXL", qs->id); + ssize_t n; + ngx_buf_t b; + + u_char buf[512]; + + b.start = buf; + b.end = buf + 512; + b.pos = b.last = b.start; + + n = c->recv(c, b.pos, b.end - b.start); + if (n < 0) { + ngx_log_error(NGX_LOG_INFO, c->log, 0, "stream read failed"); + return; + } + + ngx_log_debug2(NGX_LOG_DEBUG_HTTP, c->log, 0, + "quic stream: 0x%uXL %ui bytes read", qs->id, n); + + b.last += n; + + n = c->send(c, b.start, n); + + if (n < 0) { + ngx_log_error(NGX_LOG_INFO, c->log, 0, "stream write failed"); + return; + } + + ngx_log_debug2(NGX_LOG_DEBUG_HTTP, c->log, 0, + "quic stream: 0x%uXL %ui bytes written", qs->id, n); } -- cgit v1.2.3 From 7739b6073b11086d9a3dc4b9744418070e182c33 Mon Sep 17 00:00:00 2001 From: Roman Arutyunyan Date: Fri, 13 Mar 2020 19:36:33 +0300 Subject: HTTP/3. --- src/http/ngx_http_request.c | 178 +++++++++++++++++++++++++++++++------------- 1 file changed, 126 insertions(+), 52 deletions(-) (limited to 'src/http/ngx_http_request.c') diff --git a/src/http/ngx_http_request.c b/src/http/ngx_http_request.c index 55af26bf8..ef305faf4 100644 --- a/src/http/ngx_http_request.c +++ b/src/http/ngx_http_request.c @@ -64,7 +64,9 @@ static void ngx_http_ssl_handshake(ngx_event_t *rev); static void ngx_http_ssl_handshake_handler(ngx_connection_t *c); #endif +#if (NGX_HTTP_V3) static void ngx_http_quic_stream_handler(ngx_connection_t *c); +#endif static char *ngx_http_client_errors[] = { @@ -219,7 +221,15 @@ ngx_http_init_connection(ngx_connection_t *c) ngx_http_in6_addr_t *addr6; #endif - hc = ngx_pcalloc(c->pool, sizeof(ngx_http_connection_t)); +#if (NGX_HTTP_V3) + if (c->type == SOCK_DGRAM) { + hc = ngx_pcalloc(c->pool, sizeof(ngx_http_v3_connection_t)); + hc->quic = 1; + + } else +#endif + hc = ngx_pcalloc(c->pool, sizeof(ngx_http_connection_t)); + if (hc == NULL) { ngx_http_close_connection(c); return; @@ -329,11 +339,9 @@ ngx_http_init_connection(ngx_connection_t *c) rev->ready = 1; } -#if (NGX_HTTP_SSL) - if (hc->addr_conf->http3) { - ngx_http_ssl_srv_conf_t *sscf; - - hc->quic = 1; +#if (NGX_HTTP_V3) + if (hc->quic) { + ngx_http_ssl_srv_conf_t *sscf; sscf = ngx_http_get_module_srv_conf(hc->conf_ctx, ngx_http_ssl_module); @@ -390,46 +398,63 @@ ngx_http_init_connection(ngx_connection_t *c) } +#if (NGX_HTTP_V3) + static void ngx_http_quic_stream_handler(ngx_connection_t *c) { - ngx_quic_stream_t *qs = c->qs; + ngx_event_t *rev; + ngx_connection_t *pc; + ngx_http_log_ctx_t *ctx; + ngx_http_connection_t *hc; + ngx_http_v3_connection_t *h3c; - // STUB for stream read/write + pc = c->qs->parent; + h3c = pc->data; - ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->log, 0, - "quic stream: 0x%uXL", qs->id); - ssize_t n; - ngx_buf_t b; + if (c->qs->unidirectional) { + ngx_http_v3_handle_client_uni_stream(c); + return; + } - u_char buf[512]; + hc = ngx_pcalloc(c->pool, sizeof(ngx_http_connection_t)); + if (hc == NULL) { + ngx_http_close_connection(c); + return; + } - b.start = buf; - b.end = buf + 512; - b.pos = b.last = b.start; + ngx_memcpy(hc, h3c, sizeof(ngx_http_connection_t)); + c->data = hc; - n = c->recv(c, b.pos, b.end - b.start); - if (n < 0) { - ngx_log_error(NGX_LOG_INFO, c->log, 0, "stream read failed"); + ctx = ngx_palloc(c->pool, sizeof(ngx_http_log_ctx_t)); + if (ctx == NULL) { + ngx_http_close_connection(c); return; } - ngx_log_debug2(NGX_LOG_DEBUG_HTTP, c->log, 0, - "quic stream: 0x%uXL %ui bytes read", qs->id, n); + ctx->connection = c; + ctx->request = NULL; + ctx->current_request = NULL; - b.last += n; + c->log->connection = c->number; + c->log->handler = ngx_http_log_error; + c->log->data = ctx; + c->log->action = "waiting for request"; - n = c->send(c, b.start, n); + c->log_error = NGX_ERROR_INFO; - if (n < 0) { - ngx_log_error(NGX_LOG_INFO, c->log, 0, "stream write failed"); - return; - } + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->log, 0, + "http3 new stream id:0x%uXL", c->qs->id); - ngx_log_debug2(NGX_LOG_DEBUG_HTTP, c->log, 0, - "quic stream: 0x%uXL %ui bytes written", qs->id, n); + rev = c->read; + rev->handler = ngx_http_wait_request_handler; + c->write->handler = ngx_http_empty_handler; + + rev->handler(rev); } +#endif + static void ngx_http_wait_request_handler(ngx_event_t *rev) @@ -679,6 +704,13 @@ ngx_http_alloc_request(ngx_connection_t *c) r->method = NGX_HTTP_UNKNOWN; r->http_version = NGX_HTTP_VERSION_10; +#if (NGX_HTTP_V3) + if (hc->quic) { + r->http_version = NGX_HTTP_VERSION_30; + r->filter_need_in_memory = 1; + } +#endif + r->headers_in.content_length_n = -1; r->headers_in.keep_alive_n = -1; r->headers_out.content_length_n = -1; @@ -1128,7 +1160,16 @@ ngx_http_process_request_line(ngx_event_t *rev) } } - rc = ngx_http_parse_request_line(r, r->header_in); + switch (r->http_version) { +#if (NGX_HTTP_V3) + case NGX_HTTP_VERSION_30: + rc = ngx_http_v3_parse_header(r, r->header_in, 1); + break; +#endif + + default: /* HTTP/1.x */ + rc = ngx_http_parse_request_line(r, r->header_in); + } if (rc == NGX_OK) { @@ -1141,8 +1182,8 @@ ngx_http_process_request_line(ngx_event_t *rev) ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->log, 0, "http request line: \"%V\"", &r->request_line); - r->method_name.len = r->method_end - r->request_start + 1; - r->method_name.data = r->request_line.data; + r->method_name.len = r->method_end - r->method_start; + r->method_name.data = r->method_start; if (r->http_protocol.data) { r->http_protocol.len = r->request_end - r->http_protocol.data; @@ -1213,6 +1254,15 @@ ngx_http_process_request_line(ngx_event_t *rev) break; } + if (rc == NGX_DONE) { + if (ngx_handle_read_event(rev, 0) != NGX_OK) { + ngx_http_close_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR); + return; + } + + break; + } + if (rc != NGX_AGAIN) { /* there was error while a request line parsing */ @@ -1403,7 +1453,7 @@ ngx_http_process_request_headers(ngx_event_t *rev) cmcf = ngx_http_get_module_main_conf(r, ngx_http_core_module); - rc = NGX_AGAIN; + rc = NGX_OK; for ( ;; ) { @@ -1457,11 +1507,21 @@ ngx_http_process_request_headers(ngx_event_t *rev) /* the host header could change the server configuration context */ cscf = ngx_http_get_module_srv_conf(r, ngx_http_core_module); - rc = ngx_http_parse_header_line(r, r->header_in, - cscf->underscores_in_headers); + switch (r->http_version) { +#if (NGX_HTTP_V3) + case NGX_HTTP_VERSION_30: + rc = ngx_http_v3_parse_header(r, r->header_in, 0); + break; +#endif + + default: /* HTTP/1.x */ + rc = ngx_http_parse_header_line(r, r->header_in, + cscf->underscores_in_headers); + } if (rc == NGX_OK) { + /* XXX */ r->request_length += r->header_in->pos - r->header_name_start; if (r->invalid_header && cscf->ignore_invalid_headers) { @@ -1487,11 +1547,11 @@ ngx_http_process_request_headers(ngx_event_t *rev) h->key.len = r->header_name_end - r->header_name_start; h->key.data = r->header_name_start; - h->key.data[h->key.len] = '\0'; + //h->key.data[h->key.len] = '\0'; h->value.len = r->header_end - r->header_start; h->value.data = r->header_start; - h->value.data[h->value.len] = '\0'; + //h->value.data[h->value.len] = '\0'; h->lowcase_key = ngx_pnalloc(r->pool, h->key.len); if (h->lowcase_key == NULL) { @@ -1642,7 +1702,7 @@ ngx_http_alloc_large_header_buffer(ngx_http_request_t *r, return NGX_OK; } - old = request_line ? r->request_start : r->header_name_start; + old = request_line ? r->request_start : r->header_name_start; /* XXX */ cscf = ngx_http_get_module_srv_conf(r, ngx_http_core_module); @@ -1721,45 +1781,59 @@ ngx_http_alloc_large_header_buffer(ngx_http_request_t *r, r->request_end = new + (r->request_end - old); } - r->method_end = new + (r->method_end - old); + if (r->method_start >= old && r->method_start < r->header_in->pos) { + r->method_start = new + (r->method_start - old); + r->method_end = new + (r->method_end - old); + } - r->uri_start = new + (r->uri_start - old); - r->uri_end = new + (r->uri_end - old); + if (r->uri_start >= old && r->uri_start < r->header_in->pos) { + r->uri_start = new + (r->uri_start - old); + r->uri_end = new + (r->uri_end - old); + } - if (r->schema_start) { + if (r->schema_start >= old && r->schema_start < r->header_in->pos) { r->schema_start = new + (r->schema_start - old); r->schema_end = new + (r->schema_end - old); } - if (r->host_start) { + if (r->host_start >= old && r->host_start < r->header_in->pos) { r->host_start = new + (r->host_start - old); if (r->host_end) { r->host_end = new + (r->host_end - old); } } - if (r->port_start) { + if (r->port_start >= old && r->port_start < r->header_in->pos) { r->port_start = new + (r->port_start - old); r->port_end = new + (r->port_end - old); } - if (r->uri_ext) { + if (r->uri_ext >= old && r->uri_ext < r->header_in->pos) { r->uri_ext = new + (r->uri_ext - old); } - if (r->args_start) { + if (r->args_start >= old && r->args_start < r->header_in->pos) { r->args_start = new + (r->args_start - old); } - if (r->http_protocol.data) { + if (r->http_protocol.data >= old + && r->http_protocol.data < r->header_in->pos) + { r->http_protocol.data = new + (r->http_protocol.data - old); } } else { - r->header_name_start = new; - r->header_name_end = new + (r->header_name_end - old); - r->header_start = new + (r->header_start - old); - r->header_end = new + (r->header_end - old); + if (r->header_name_start >= old + && r->header_name_start < r->header_in->pos) + { + r->header_name_start = new; + r->header_name_end = new + (r->header_name_end - old); + } + + if (r->header_start >= old && r->header_start < r->header_in->pos) { + r->header_start = new + (r->header_start - old); + r->header_end = new + (r->header_end - old); + } } r->header_in = b; @@ -1984,7 +2058,7 @@ ngx_http_process_request_header(ngx_http_request_t *r) return NGX_ERROR; } - if (r->headers_in.host == NULL && r->http_version > NGX_HTTP_VERSION_10) { + if (r->headers_in.host == NULL && r->http_version == NGX_HTTP_VERSION_11) { ngx_log_error(NGX_LOG_INFO, r->connection->log, 0, "client sent HTTP/1.1 request without \"Host\" header"); ngx_http_finalize_request(r, NGX_HTTP_BAD_REQUEST); -- cgit v1.2.3 From 5399670fcc51b440f00a9a584654f7bcc52d3f88 Mon Sep 17 00:00:00 2001 From: Roman Arutyunyan Date: Sat, 14 Mar 2020 13:18:55 +0300 Subject: Temporary fix for header null-termination in HTTP/3. --- src/http/ngx_http_request.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src/http/ngx_http_request.c') diff --git a/src/http/ngx_http_request.c b/src/http/ngx_http_request.c index ef305faf4..85b090d5f 100644 --- a/src/http/ngx_http_request.c +++ b/src/http/ngx_http_request.c @@ -1547,11 +1547,11 @@ ngx_http_process_request_headers(ngx_event_t *rev) h->key.len = r->header_name_end - r->header_name_start; h->key.data = r->header_name_start; - //h->key.data[h->key.len] = '\0'; + h->key.data[h->key.len] = '\0'; h->value.len = r->header_end - r->header_start; h->value.data = r->header_start; - //h->value.data[h->value.len] = '\0'; + h->value.data[h->value.len] = '\0'; h->lowcase_key = ngx_pnalloc(r->pool, h->key.len); if (h->lowcase_key == NULL) { -- cgit v1.2.3 From 01dc7445f0fc392edd4f4e23f4fa1af69af68e41 Mon Sep 17 00:00:00 2001 From: Roman Arutyunyan Date: Wed, 18 Mar 2020 13:46:35 +0300 Subject: Refactored HTTP/3 parser. --- src/http/ngx_http_request.c | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) (limited to 'src/http/ngx_http_request.c') diff --git a/src/http/ngx_http_request.c b/src/http/ngx_http_request.c index 85b090d5f..166d8ffba 100644 --- a/src/http/ngx_http_request.c +++ b/src/http/ngx_http_request.c @@ -1163,7 +1163,7 @@ ngx_http_process_request_line(ngx_event_t *rev) switch (r->http_version) { #if (NGX_HTTP_V3) case NGX_HTTP_VERSION_30: - rc = ngx_http_v3_parse_header(r, r->header_in, 1); + rc = ngx_http_v3_parse_header(r, r->header_in); break; #endif @@ -1510,7 +1510,7 @@ ngx_http_process_request_headers(ngx_event_t *rev) switch (r->http_version) { #if (NGX_HTTP_V3) case NGX_HTTP_VERSION_30: - rc = ngx_http_v3_parse_header(r, r->header_in, 0); + rc = ngx_http_v3_parse_header(r, r->header_in); break; #endif @@ -1547,11 +1547,17 @@ ngx_http_process_request_headers(ngx_event_t *rev) h->key.len = r->header_name_end - r->header_name_start; h->key.data = r->header_name_start; - h->key.data[h->key.len] = '\0'; + + if (h->key.data[h->key.len]) { + h->key.data[h->key.len] = '\0'; + } h->value.len = r->header_end - r->header_start; h->value.data = r->header_start; - h->value.data[h->value.len] = '\0'; + + if (h->value.data[h->value.len]) { + h->value.data[h->value.len] = '\0'; + } h->lowcase_key = ngx_pnalloc(r->pool, h->key.len); if (h->lowcase_key == NULL) { -- cgit v1.2.3 From e63accd7bd222aebd7cf4f90aeb8cca617d01b94 Mon Sep 17 00:00:00 2001 From: Roman Arutyunyan Date: Wed, 18 Mar 2020 20:22:16 +0300 Subject: HTTP/3 $request_line variable. --- src/http/ngx_http_request.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src/http/ngx_http_request.c') diff --git a/src/http/ngx_http_request.c b/src/http/ngx_http_request.c index 166d8ffba..687de931c 100644 --- a/src/http/ngx_http_request.c +++ b/src/http/ngx_http_request.c @@ -1177,7 +1177,7 @@ ngx_http_process_request_line(ngx_event_t *rev) r->request_line.len = r->request_end - r->request_start; r->request_line.data = r->request_start; - r->request_length = r->header_in->pos - r->request_start; + r->request_length = r->header_in->pos - r->request_start; /* XXX */ ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->log, 0, "http request line: \"%V\"", &r->request_line); @@ -1593,7 +1593,7 @@ ngx_http_process_request_headers(ngx_event_t *rev) ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "http header done"); - r->request_length += r->header_in->pos - r->header_name_start; + r->request_length += r->header_in->pos - r->header_name_start; /* XXX */ r->http_state = NGX_HTTP_PROCESS_REQUEST_STATE; -- cgit v1.2.3 From 30de0ca52dc7d460a184781e82288b0e2723ebce Mon Sep 17 00:00:00 2001 From: Vladimir Homutov Date: Fri, 20 Mar 2020 13:47:44 +0300 Subject: Configurable transport parameters. - integer parameters can be configured using the following directives: quic_max_idle_timeout quic_max_ack_delay quic_max_packet_size quic_initial_max_data quic_initial_max_stream_data_bidi_local quic_initial_max_stream_data_bidi_remote quic_initial_max_stream_data_uni quic_initial_max_streams_bidi quic_initial_max_streams_uni quic_ack_delay_exponent quic_active_migration quic_active_connection_id_limit - only following parameters are actually sent: active_connection_id_limit initial_max_streams_uni initial_max_streams_bidi initial_max_stream_data_bidi_local initial_max_stream_data_bidi_remote initial_max_stream_data_uni (other parameters are to be added into ngx_quic_create_transport_params() function as needed, should be easy now) - draft 24 and draft 27 are now supported (at compile-time using quic_version macro) --- src/http/ngx_http_request.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'src/http/ngx_http_request.c') diff --git a/src/http/ngx_http_request.c b/src/http/ngx_http_request.c index 687de931c..6c9fdc543 100644 --- a/src/http/ngx_http_request.c +++ b/src/http/ngx_http_request.c @@ -341,11 +341,14 @@ ngx_http_init_connection(ngx_connection_t *c) #if (NGX_HTTP_V3) if (hc->quic) { + ngx_http_v3_srv_conf_t *v3cf; ngx_http_ssl_srv_conf_t *sscf; + v3cf = ngx_http_get_module_srv_conf(hc->conf_ctx, ngx_http_v3_module); sscf = ngx_http_get_module_srv_conf(hc->conf_ctx, ngx_http_ssl_module); - ngx_quic_run(c, &sscf->ssl, c->listening->post_accept_timeout, + ngx_quic_run(c, &sscf->ssl, &v3cf->quic, + c->listening->post_accept_timeout, ngx_http_quic_stream_handler); return; } -- cgit v1.2.3 From 5ac5e51fdfe68e8b11f8c7abd2ce361062f68e54 Mon Sep 17 00:00:00 2001 From: Roman Arutyunyan Date: Mon, 23 Mar 2020 21:20:20 +0300 Subject: Respect QUIC max_idle_timeout. --- src/http/ngx_http_request.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'src/http/ngx_http_request.c') diff --git a/src/http/ngx_http_request.c b/src/http/ngx_http_request.c index 6c9fdc543..acd708cf6 100644 --- a/src/http/ngx_http_request.c +++ b/src/http/ngx_http_request.c @@ -347,9 +347,7 @@ ngx_http_init_connection(ngx_connection_t *c) v3cf = ngx_http_get_module_srv_conf(hc->conf_ctx, ngx_http_v3_module); sscf = ngx_http_get_module_srv_conf(hc->conf_ctx, ngx_http_ssl_module); - ngx_quic_run(c, &sscf->ssl, &v3cf->quic, - c->listening->post_accept_timeout, - ngx_http_quic_stream_handler); + ngx_quic_run(c, &sscf->ssl, &v3cf->quic, ngx_http_quic_stream_handler); return; } #endif -- cgit v1.2.3 From f20af3dabca75b1f57f5c72a0e45e7251762b43c Mon Sep 17 00:00:00 2001 From: Sergey Kandaurov Date: Mon, 23 Mar 2020 20:48:34 +0300 Subject: Fixed client certificate verification. For ngx_http_process_request() part to work, this required to set both r->http_connection->ssl and c->ssl on a QUIC stream. To avoid damaging global SSL object, ngx_ssl_shutdown() is managed to ignore QUIC streams. --- src/http/ngx_http_request.c | 1 + 1 file changed, 1 insertion(+) (limited to 'src/http/ngx_http_request.c') diff --git a/src/http/ngx_http_request.c b/src/http/ngx_http_request.c index acd708cf6..890e5374b 100644 --- a/src/http/ngx_http_request.c +++ b/src/http/ngx_http_request.c @@ -225,6 +225,7 @@ ngx_http_init_connection(ngx_connection_t *c) if (c->type == SOCK_DGRAM) { hc = ngx_pcalloc(c->pool, sizeof(ngx_http_v3_connection_t)); hc->quic = 1; + hc->ssl = 1; } else #endif -- cgit v1.2.3 From d8d42e29e7ff43025ba0f56262993cd37c4a5b10 Mon Sep 17 00:00:00 2001 From: Sergey Kandaurov Date: Tue, 24 Mar 2020 19:17:57 +0300 Subject: QUIC streams don't need filter_need_in_memory after 7f0981be07c4. Now they inherit c->ssl always enabled from the main connection, which makes r->main_filter_need_in_memory set for them. --- src/http/ngx_http_request.c | 1 - 1 file changed, 1 deletion(-) (limited to 'src/http/ngx_http_request.c') diff --git a/src/http/ngx_http_request.c b/src/http/ngx_http_request.c index 890e5374b..c5165f2dc 100644 --- a/src/http/ngx_http_request.c +++ b/src/http/ngx_http_request.c @@ -709,7 +709,6 @@ ngx_http_alloc_request(ngx_connection_t *c) #if (NGX_HTTP_V3) if (hc->quic) { r->http_version = NGX_HTTP_VERSION_30; - r->filter_need_in_memory = 1; } #endif -- cgit v1.2.3 From f75e4e3fef6e270555afefbb15b4741c694596f3 Mon Sep 17 00:00:00 2001 From: Roman Arutyunyan Date: Tue, 24 Mar 2020 16:38:03 +0300 Subject: Removed ngx_quic_stream_node_t. Now ngx_quic_stream_t is directly inserted into the tree. --- src/http/ngx_http_request.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/http/ngx_http_request.c') diff --git a/src/http/ngx_http_request.c b/src/http/ngx_http_request.c index c5165f2dc..6f168c8bd 100644 --- a/src/http/ngx_http_request.c +++ b/src/http/ngx_http_request.c @@ -414,7 +414,7 @@ ngx_http_quic_stream_handler(ngx_connection_t *c) pc = c->qs->parent; h3c = pc->data; - if (c->qs->unidirectional) { + if (c->qs->id & NGX_QUIC_STREAM_UNIDIRECTIONAL) { ngx_http_v3_handle_client_uni_stream(c); return; } -- cgit v1.2.3 From fa1e1beadca8b1ea900ec654919aea58762ab746 Mon Sep 17 00:00:00 2001 From: Roman Arutyunyan Date: Fri, 27 Mar 2020 19:41:06 +0300 Subject: Parsing HTTP/3 request body. --- src/http/ngx_http_request.c | 1 + 1 file changed, 1 insertion(+) (limited to 'src/http/ngx_http_request.c') diff --git a/src/http/ngx_http_request.c b/src/http/ngx_http_request.c index 6f168c8bd..4368e79c0 100644 --- a/src/http/ngx_http_request.c +++ b/src/http/ngx_http_request.c @@ -709,6 +709,7 @@ ngx_http_alloc_request(ngx_connection_t *c) #if (NGX_HTTP_V3) if (hc->quic) { r->http_version = NGX_HTTP_VERSION_30; + r->headers_in.chunked = 1; } #endif -- cgit v1.2.3 From 9c375910161cdcac5bb616f6afb8de030849f2ca Mon Sep 17 00:00:00 2001 From: Roman Arutyunyan Date: Thu, 23 Apr 2020 18:05:05 +0300 Subject: Assign connection number to every QUIC stream log. --- src/http/ngx_http_request.c | 1 - 1 file changed, 1 deletion(-) (limited to 'src/http/ngx_http_request.c') diff --git a/src/http/ngx_http_request.c b/src/http/ngx_http_request.c index 082938e00..b0cc9a543 100644 --- a/src/http/ngx_http_request.c +++ b/src/http/ngx_http_request.c @@ -438,7 +438,6 @@ ngx_http_quic_stream_handler(ngx_connection_t *c) ctx->request = NULL; ctx->current_request = NULL; - c->log->connection = c->number; c->log->handler = ngx_http_log_error; c->log->data = ctx; c->log->action = "waiting for request"; -- cgit v1.2.3 From 6abb50658fcdf6ab92a4bc9042cd7dd9bb413850 Mon Sep 17 00:00:00 2001 From: Roman Arutyunyan Date: Tue, 19 May 2020 15:29:10 +0300 Subject: HTTP/3: split header parser in two functions. The first one parses pseudo-headers and is analagous to the request line parser in HTTP/1. The second one parses regular headers and is analogous to the header parser in HTTP/1. Additionally, error handling of client passing malformed uri is now fixed. --- src/http/ngx_http_request.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/http/ngx_http_request.c') diff --git a/src/http/ngx_http_request.c b/src/http/ngx_http_request.c index b0cc9a543..e77c4bc35 100644 --- a/src/http/ngx_http_request.c +++ b/src/http/ngx_http_request.c @@ -1164,7 +1164,7 @@ ngx_http_process_request_line(ngx_event_t *rev) switch (r->http_version) { #if (NGX_HTTP_V3) case NGX_HTTP_VERSION_30: - rc = ngx_http_v3_parse_header(r, r->header_in); + rc = ngx_http_v3_parse_request(r, r->header_in); break; #endif -- cgit v1.2.3 From d25937c2b596013874fcb049f10b28270ee49e29 Mon Sep 17 00:00:00 2001 From: Roman Arutyunyan Date: Tue, 19 May 2020 15:34:00 +0300 Subject: HTTP/3: restricted symbols in header names. As per HTTP/3 draft 27, a request or response containing uppercase header field names MUST be treated as malformed. Also, existing rules applied when parsing HTTP/1 header names are also applied to HTTP/3 header names: - null character is not allowed - underscore character may or may not be treated as invalid depending on the value of "underscores_in_headers" - all non-alphanumeric characters with the exception of '-' are treated as invalid Also, the r->locase_header field is now filled while parsing an HTTP/3 header. Error logging for invalid headers is fixed as well. --- src/http/ngx_http_request.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) (limited to 'src/http/ngx_http_request.c') diff --git a/src/http/ngx_http_request.c b/src/http/ngx_http_request.c index e77c4bc35..e3d217f79 100644 --- a/src/http/ngx_http_request.c +++ b/src/http/ngx_http_request.c @@ -1511,7 +1511,8 @@ ngx_http_process_request_headers(ngx_event_t *rev) switch (r->http_version) { #if (NGX_HTTP_V3) case NGX_HTTP_VERSION_30: - rc = ngx_http_v3_parse_header(r, r->header_in); + rc = ngx_http_v3_parse_header(r, r->header_in, + cscf->underscores_in_headers); break; #endif @@ -1530,9 +1531,10 @@ ngx_http_process_request_headers(ngx_event_t *rev) /* there was error while a header line parsing */ ngx_log_error(NGX_LOG_INFO, c->log, 0, - "client sent invalid header line: \"%*s\"", - r->header_end - r->header_name_start, - r->header_name_start); + "client sent invalid header line: \"%*s: %*s\"", + r->header_name_end - r->header_name_start, + r->header_name_start, + r->header_end - r->header_start, r->header_start); continue; } -- cgit v1.2.3 From d6b6b6dfc57c916dc7990504fffe71248421456d Mon Sep 17 00:00:00 2001 From: Roman Arutyunyan Date: Tue, 19 May 2020 15:47:37 +0300 Subject: Fixed $request_length for HTTP/3. New field r->parse_start is introduced to substitute r->request_start and r->header_name_start for request length accounting. These fields only work for this purpose in HTTP/1 because HTTP/1 request line and header line start with these values. Also, error logging is now fixed to output the right part of the request. --- src/http/ngx_http_request.c | 27 ++++++++++++++------------- 1 file changed, 14 insertions(+), 13 deletions(-) (limited to 'src/http/ngx_http_request.c') diff --git a/src/http/ngx_http_request.c b/src/http/ngx_http_request.c index e3d217f79..baef5f444 100644 --- a/src/http/ngx_http_request.c +++ b/src/http/ngx_http_request.c @@ -1178,7 +1178,7 @@ ngx_http_process_request_line(ngx_event_t *rev) r->request_line.len = r->request_end - r->request_start; r->request_line.data = r->request_start; - r->request_length = r->header_in->pos - r->request_start; /* XXX */ + r->request_length = r->header_in->pos - r->parse_start; ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->log, 0, "http request line: \"%V\"", &r->request_line); @@ -1293,8 +1293,8 @@ ngx_http_process_request_line(ngx_event_t *rev) } if (rv == NGX_DECLINED) { - r->request_line.len = r->header_in->end - r->request_start; - r->request_line.data = r->request_start; + r->request_line.len = r->header_in->end - r->parse_start; + r->request_line.data = r->parse_start; ngx_log_error(NGX_LOG_INFO, c->log, 0, "client sent too long URI"); @@ -1470,7 +1470,7 @@ ngx_http_process_request_headers(ngx_event_t *rev) } if (rv == NGX_DECLINED) { - p = r->header_name_start; + p = r->parse_start; r->lingering_close = 1; @@ -1490,7 +1490,7 @@ ngx_http_process_request_headers(ngx_event_t *rev) ngx_log_error(NGX_LOG_INFO, c->log, 0, "client sent too long header line: \"%*s...\"", - len, r->header_name_start); + len, r->parse_start); ngx_http_finalize_request(r, NGX_HTTP_REQUEST_HEADER_TOO_LARGE); @@ -1523,8 +1523,7 @@ ngx_http_process_request_headers(ngx_event_t *rev) if (rc == NGX_OK) { - /* XXX */ - r->request_length += r->header_in->pos - r->header_name_start; + r->request_length += r->header_in->pos - r->parse_start; if (r->invalid_header && cscf->ignore_invalid_headers) { @@ -1596,7 +1595,7 @@ ngx_http_process_request_headers(ngx_event_t *rev) ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "http header done"); - r->request_length += r->header_in->pos - r->header_name_start; /* XXX */ + r->request_length += r->header_in->pos - r->parse_start; r->http_state = NGX_HTTP_PROCESS_REQUEST_STATE; @@ -1711,7 +1710,7 @@ ngx_http_alloc_large_header_buffer(ngx_http_request_t *r, return NGX_OK; } - old = request_line ? r->request_start : r->header_name_start; /* XXX */ + old = r->parse_start; cscf = ngx_http_get_module_srv_conf(r, ngx_http_core_module); @@ -1783,6 +1782,8 @@ ngx_http_alloc_large_header_buffer(ngx_http_request_t *r, b->pos = new + (r->header_in->pos - old); b->last = new + (r->header_in->pos - old); + r->parse_start = new; + if (request_line) { r->request_start = new; @@ -3892,15 +3893,15 @@ ngx_http_log_error_handler(ngx_http_request_t *r, ngx_http_request_t *sr, len -= p - buf; buf = p; - if (r->request_line.data == NULL && r->request_start) { - for (p = r->request_start; p < r->header_in->last; p++) { + if (r->request_line.data == NULL && r->parse_start) { + for (p = r->parse_start; p < r->header_in->last; p++) { if (*p == CR || *p == LF) { break; } } - r->request_line.len = p - r->request_start; - r->request_line.data = r->request_start; + r->request_line.len = p - r->parse_start; + r->request_line.data = r->parse_start; } if (r->request_line.len) { -- cgit v1.2.3 From 94764fda6efa48fc18b2fc0a2cd82d451e947094 Mon Sep 17 00:00:00 2001 From: Roman Arutyunyan Date: Tue, 19 May 2020 16:20:33 +0300 Subject: Fixed client buffer reallocation for HTTP/3. Preserving pointers within the client buffer is not needed for HTTP/3 because all data is either allocated from pool or static. Unlike with HTTP/1, data typically cannot be referenced directly within the client buffer. Trying to preserve NULLs or external pointers lead to broken pointers. Also, reverted changes in ngx_http_alloc_large_header_buffer() not relevant for HTTP/3 to minimize diff to mainstream. --- src/http/ngx_http_request.c | 48 ++++++++++++++++++--------------------------- 1 file changed, 19 insertions(+), 29 deletions(-) (limited to 'src/http/ngx_http_request.c') diff --git a/src/http/ngx_http_request.c b/src/http/ngx_http_request.c index baef5f444..1b3573598 100644 --- a/src/http/ngx_http_request.c +++ b/src/http/ngx_http_request.c @@ -1784,6 +1784,12 @@ ngx_http_alloc_large_header_buffer(ngx_http_request_t *r, r->parse_start = new; + r->header_in = b; + + if (r->http_version > NGX_HTTP_VERSION_11) { + return NGX_OK; + } + if (request_line) { r->request_start = new; @@ -1791,63 +1797,47 @@ ngx_http_alloc_large_header_buffer(ngx_http_request_t *r, r->request_end = new + (r->request_end - old); } - if (r->method_start >= old && r->method_start < r->header_in->pos) { - r->method_start = new + (r->method_start - old); - r->method_end = new + (r->method_end - old); - } + r->method_end = new + (r->method_end - old); - if (r->uri_start >= old && r->uri_start < r->header_in->pos) { - r->uri_start = new + (r->uri_start - old); - r->uri_end = new + (r->uri_end - old); - } + r->uri_start = new + (r->uri_start - old); + r->uri_end = new + (r->uri_end - old); - if (r->schema_start >= old && r->schema_start < r->header_in->pos) { + if (r->schema_start) { r->schema_start = new + (r->schema_start - old); r->schema_end = new + (r->schema_end - old); } - if (r->host_start >= old && r->host_start < r->header_in->pos) { + if (r->host_start) { r->host_start = new + (r->host_start - old); if (r->host_end) { r->host_end = new + (r->host_end - old); } } - if (r->port_start >= old && r->port_start < r->header_in->pos) { + if (r->port_start) { r->port_start = new + (r->port_start - old); r->port_end = new + (r->port_end - old); } - if (r->uri_ext >= old && r->uri_ext < r->header_in->pos) { + if (r->uri_ext) { r->uri_ext = new + (r->uri_ext - old); } - if (r->args_start >= old && r->args_start < r->header_in->pos) { + if (r->args_start) { r->args_start = new + (r->args_start - old); } - if (r->http_protocol.data >= old - && r->http_protocol.data < r->header_in->pos) - { + if (r->http_protocol.data) { r->http_protocol.data = new + (r->http_protocol.data - old); } } else { - if (r->header_name_start >= old - && r->header_name_start < r->header_in->pos) - { - r->header_name_start = new; - r->header_name_end = new + (r->header_name_end - old); - } - - if (r->header_start >= old && r->header_start < r->header_in->pos) { - r->header_start = new + (r->header_start - old); - r->header_end = new + (r->header_end - old); - } + r->header_name_start = new; + r->header_name_end = new + (r->header_name_end - old); + r->header_start = new + (r->header_start - old); + r->header_end = new + (r->header_end - old); } - r->header_in = b; - return NGX_OK; } -- cgit v1.2.3 From 22297afd7924d00440105bc440aa4f67fde380fe Mon Sep 17 00:00:00 2001 From: Roman Arutyunyan Date: Fri, 29 May 2020 12:42:23 +0300 Subject: Require ":authority" or "Host" in HTTP/3 and HTTP/2 requests. Also, if both are present, require that they have the same value. These requirements are specified in HTTP/3 draft 28. Current implementation of HTTP/2 treats ":authority" and "Host" interchangeably. New checks only make sure at least one of these values is present in the request. A similar check existed earlier and was limited only to HTTP/1.1 in 38c0898b6df7. --- src/http/ngx_http_request.c | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) (limited to 'src/http/ngx_http_request.c') diff --git a/src/http/ngx_http_request.c b/src/http/ngx_http_request.c index 3e6fce676..23b28c243 100644 --- a/src/http/ngx_http_request.c +++ b/src/http/ngx_http_request.c @@ -2065,6 +2065,31 @@ ngx_http_process_request_header(ngx_http_request_t *r) return NGX_ERROR; } + if (r->http_version >= NGX_HTTP_VERSION_20) { + if (r->headers_in.server.len == 0) { + ngx_log_error(NGX_LOG_INFO, r->connection->log, 0, + "client sent HTTP request without " + "\":authority\" or \"Host\" header"); + ngx_http_finalize_request(r, NGX_HTTP_BAD_REQUEST); + return NGX_ERROR; + } + + if (r->headers_in.host) { + if (r->headers_in.host->value.len != r->headers_in.server.len + || ngx_memcmp(r->headers_in.host->value.data, + r->headers_in.server.data, + r->headers_in.server.len) + != 0) + { + ngx_log_error(NGX_LOG_INFO, r->connection->log, 0, + "client sent HTTP request with different " + "values of \":authority\" and \"Host\" headers"); + ngx_http_finalize_request(r, NGX_HTTP_BAD_REQUEST); + return NGX_ERROR; + } + } + } + if (r->headers_in.content_length) { r->headers_in.content_length_n = ngx_atoof(r->headers_in.content_length->value.data, -- cgit v1.2.3 From c0003539ac767ec9d16e54d26b5296a6669d0089 Mon Sep 17 00:00:00 2001 From: Roman Arutyunyan Date: Tue, 2 Jun 2020 15:59:14 +0300 Subject: Decoupled validation of Host and :authority for HTTP/2 and HTTP/3. Previously an error was triggered for HTTP/2 when host with port was passed by client. --- src/http/ngx_http_request.c | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) (limited to 'src/http/ngx_http_request.c') diff --git a/src/http/ngx_http_request.c b/src/http/ngx_http_request.c index 23b28c243..ac5937347 100644 --- a/src/http/ngx_http_request.c +++ b/src/http/ngx_http_request.c @@ -2065,10 +2065,18 @@ ngx_http_process_request_header(ngx_http_request_t *r) return NGX_ERROR; } - if (r->http_version >= NGX_HTTP_VERSION_20) { + if (r->headers_in.host == NULL && r->http_version == NGX_HTTP_VERSION_20) { + ngx_log_error(NGX_LOG_INFO, r->connection->log, 0, + "client sent HTTP/2 request without " + "\":authority\" or \"Host\" header"); + ngx_http_finalize_request(r, NGX_HTTP_BAD_REQUEST); + return NGX_ERROR; + } + + if (r->http_version == NGX_HTTP_VERSION_30) { if (r->headers_in.server.len == 0) { ngx_log_error(NGX_LOG_INFO, r->connection->log, 0, - "client sent HTTP request without " + "client sent HTTP/3 request without " "\":authority\" or \"Host\" header"); ngx_http_finalize_request(r, NGX_HTTP_BAD_REQUEST); return NGX_ERROR; @@ -2082,7 +2090,7 @@ ngx_http_process_request_header(ngx_http_request_t *r) != 0) { ngx_log_error(NGX_LOG_INFO, r->connection->log, 0, - "client sent HTTP request with different " + "client sent HTTP/3 request with different " "values of \":authority\" and \"Host\" headers"); ngx_http_finalize_request(r, NGX_HTTP_BAD_REQUEST); return NGX_ERROR; -- cgit v1.2.3 From a687d08062d8cb029ab82249aa55833cf44be3ce Mon Sep 17 00:00:00 2001 From: Roman Arutyunyan Date: Thu, 2 Jul 2020 15:34:05 +0300 Subject: HTTP/3: refactored dynamic table implementation. Previously dynamic table was not functional because of zero limit on its size set by default. Now the following changes enable it: - new directives to set SETTINGS_QPACK_MAX_TABLE_CAPACITY and SETTINGS_QPACK_BLOCKED_STREAMS - send settings with SETTINGS_QPACK_MAX_TABLE_CAPACITY and SETTINGS_QPACK_BLOCKED_STREAMS to the client - send Insert Count Increment to the client - send Header Acknowledgement to the client - evict old dynamic table entries on overflow - decode Required Insert Count from client - block stream if Required Insert Count is not reached --- src/http/ngx_http_request.c | 21 +++++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) (limited to 'src/http/ngx_http_request.c') diff --git a/src/http/ngx_http_request.c b/src/http/ngx_http_request.c index ac5937347..89e554bf2 100644 --- a/src/http/ngx_http_request.c +++ b/src/http/ngx_http_request.c @@ -223,7 +223,17 @@ ngx_http_init_connection(ngx_connection_t *c) #if (NGX_HTTP_V3) if (c->type == SOCK_DGRAM) { - hc = ngx_pcalloc(c->pool, sizeof(ngx_http_v3_connection_t)); + ngx_http_v3_connection_t *h3c; + + h3c = ngx_pcalloc(c->pool, sizeof(ngx_http_v3_connection_t)); + if (h3c == NULL) { + ngx_http_close_connection(c); + return; + } + + ngx_queue_init(&h3c->blocked); + + hc = &h3c->hc; hc->quic = 1; hc->ssl = 1; @@ -414,6 +424,13 @@ ngx_http_quic_stream_handler(ngx_connection_t *c) pc = c->qs->parent; h3c = pc->data; + if (!h3c->settings_sent) { + h3c->settings_sent = 1; + + /* TODO close QUIC connection on error */ + (void) ngx_http_v3_send_settings(c); + } + if (c->qs->id & NGX_QUIC_STREAM_UNIDIRECTIONAL) { ngx_http_v3_handle_client_uni_stream(c); return; @@ -1255,7 +1272,7 @@ ngx_http_process_request_line(ngx_event_t *rev) break; } - if (rc == NGX_DONE) { + if (rc == NGX_BUSY) { if (ngx_handle_read_event(rev, 0) != NGX_OK) { ngx_http_close_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR); return; -- cgit v1.2.3 From 707117276ed252e39c75769a140cbac6e18eb74a Mon Sep 17 00:00:00 2001 From: Roman Arutyunyan Date: Thu, 2 Jul 2020 16:47:51 +0300 Subject: HTTP/3: close QUIC connection with HTTP/QPACK errors when needed. Previously errors led only to closing streams. To simplify closing QUIC connection from a QUIC stream context, new macro ngx_http_v3_finalize_connection() is introduced. It calls ngx_quic_finalize_connection() for the parent connection. --- src/http/ngx_http_request.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) (limited to 'src/http/ngx_http_request.c') diff --git a/src/http/ngx_http_request.c b/src/http/ngx_http_request.c index 89e554bf2..c953386d4 100644 --- a/src/http/ngx_http_request.c +++ b/src/http/ngx_http_request.c @@ -416,19 +416,21 @@ static void ngx_http_quic_stream_handler(ngx_connection_t *c) { ngx_event_t *rev; - ngx_connection_t *pc; ngx_http_log_ctx_t *ctx; ngx_http_connection_t *hc; ngx_http_v3_connection_t *h3c; - pc = c->qs->parent; - h3c = pc->data; + h3c = c->qs->parent->data; if (!h3c->settings_sent) { h3c->settings_sent = 1; - /* TODO close QUIC connection on error */ - (void) ngx_http_v3_send_settings(c); + if (ngx_http_v3_send_settings(c) != NGX_OK) { + ngx_http_v3_finalize_connection(c, NGX_HTTP_V3_ERR_INTERNAL_ERROR, + "could not send settings"); + ngx_http_close_connection(c); + return; + } } if (c->qs->id & NGX_QUIC_STREAM_UNIDIRECTIONAL) { -- cgit v1.2.3 From d839fee75f5247c160c0b7b927dc45a3122cb6a2 Mon Sep 17 00:00:00 2001 From: Roman Arutyunyan Date: Tue, 30 Jun 2020 15:32:09 +0300 Subject: HTTP/3: set r->headers_in.chunked flag after parsing headers. Previously it was set when creating the request object. The side-effect was trying to discard the request body in case of header parse error. --- src/http/ngx_http_request.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) (limited to 'src/http/ngx_http_request.c') diff --git a/src/http/ngx_http_request.c b/src/http/ngx_http_request.c index c953386d4..8933bb3c3 100644 --- a/src/http/ngx_http_request.c +++ b/src/http/ngx_http_request.c @@ -727,7 +727,6 @@ ngx_http_alloc_request(ngx_connection_t *c) #if (NGX_HTTP_V3) if (hc->quic) { r->http_version = NGX_HTTP_VERSION_30; - r->headers_in.chunked = 1; } #endif @@ -2155,6 +2154,12 @@ ngx_http_process_request_header(ngx_http_request_t *r) } } +#if (NGX_HTTP_V3) + if (r->http_version == NGX_HTTP_VERSION_30) { + r->headers_in.chunked = 1; + } +#endif + if (r->headers_in.connection_type == NGX_HTTP_CONNECTION_KEEP_ALIVE) { if (r->headers_in.keep_alive) { r->headers_in.keep_alive_n = -- cgit v1.2.3 From b813b9ec358862a2a94868bc057420d6eca5c05d Mon Sep 17 00:00:00 2001 From: Roman Arutyunyan Date: Tue, 21 Jul 2020 23:09:22 +0300 Subject: QUIC: added "quic" listen parameter. The parameter allows processing HTTP/0.9-2 over QUIC. Also, introduced ngx_http_quic_module and moved QUIC settings there --- src/http/ngx_http_request.c | 149 +++++++++++++------------------------------- 1 file changed, 42 insertions(+), 107 deletions(-) (limited to 'src/http/ngx_http_request.c') diff --git a/src/http/ngx_http_request.c b/src/http/ngx_http_request.c index 8933bb3c3..bfa8e11c5 100644 --- a/src/http/ngx_http_request.c +++ b/src/http/ngx_http_request.c @@ -64,9 +64,6 @@ static void ngx_http_ssl_handshake(ngx_event_t *rev); static void ngx_http_ssl_handshake_handler(ngx_connection_t *c); #endif -#if (NGX_HTTP_V3) -static void ngx_http_quic_stream_handler(ngx_connection_t *c); -#endif static char *ngx_http_client_errors[] = { @@ -221,26 +218,7 @@ ngx_http_init_connection(ngx_connection_t *c) ngx_http_in6_addr_t *addr6; #endif -#if (NGX_HTTP_V3) - if (c->type == SOCK_DGRAM) { - ngx_http_v3_connection_t *h3c; - - h3c = ngx_pcalloc(c->pool, sizeof(ngx_http_v3_connection_t)); - if (h3c == NULL) { - ngx_http_close_connection(c); - return; - } - - ngx_queue_init(&h3c->blocked); - - hc = &h3c->hc; - hc->quic = 1; - hc->ssl = 1; - - } else -#endif - hc = ngx_pcalloc(c->pool, sizeof(ngx_http_connection_t)); - + hc = ngx_pcalloc(c->pool, sizeof(ngx_http_connection_t)); if (hc == NULL) { ngx_http_close_connection(c); return; @@ -325,6 +303,46 @@ ngx_http_init_connection(ngx_connection_t *c) /* the default server configuration for the address:port */ hc->conf_ctx = hc->addr_conf->default_server->ctx; +#if (NGX_HTTP_QUIC) + + if (hc->addr_conf->quic) { + ngx_quic_conf_t *qcf; + ngx_http_ssl_srv_conf_t *sscf; + +#if (NGX_HTTP_V3) + + if (hc->addr_conf->http3) { + ngx_int_t rc; + + rc = ngx_http_v3_init_connection(c); + + if (rc == NGX_ERROR) { + ngx_http_close_connection(c); + return; + } + + if (rc == NGX_DONE) { + return; + } + } + +#endif + + if (c->qs == NULL) { + c->log->connection = c->number; + + qcf = ngx_http_get_module_srv_conf(hc->conf_ctx, + ngx_http_quic_module); + sscf = ngx_http_get_module_srv_conf(hc->conf_ctx, + ngx_http_ssl_module); + + ngx_quic_run(c, &sscf->ssl, qcf, ngx_http_init_connection); + return; + } + } + +#endif + ctx = ngx_palloc(c->pool, sizeof(ngx_http_log_ctx_t)); if (ctx == NULL) { ngx_http_close_connection(c); @@ -346,23 +364,6 @@ ngx_http_init_connection(ngx_connection_t *c) rev->handler = ngx_http_wait_request_handler; c->write->handler = ngx_http_empty_handler; - if (c->shared) { - rev->ready = 1; - } - -#if (NGX_HTTP_V3) - if (hc->quic) { - ngx_http_v3_srv_conf_t *v3cf; - ngx_http_ssl_srv_conf_t *sscf; - - v3cf = ngx_http_get_module_srv_conf(hc->conf_ctx, ngx_http_v3_module); - sscf = ngx_http_get_module_srv_conf(hc->conf_ctx, ngx_http_ssl_module); - - ngx_quic_run(c, &sscf->ssl, &v3cf->quic, ngx_http_quic_stream_handler); - return; - } -#endif - #if (NGX_HTTP_V2) if (hc->addr_conf->http2) { rev->handler = ngx_http_v2_init; @@ -410,72 +411,6 @@ ngx_http_init_connection(ngx_connection_t *c) } -#if (NGX_HTTP_V3) - -static void -ngx_http_quic_stream_handler(ngx_connection_t *c) -{ - ngx_event_t *rev; - ngx_http_log_ctx_t *ctx; - ngx_http_connection_t *hc; - ngx_http_v3_connection_t *h3c; - - h3c = c->qs->parent->data; - - if (!h3c->settings_sent) { - h3c->settings_sent = 1; - - if (ngx_http_v3_send_settings(c) != NGX_OK) { - ngx_http_v3_finalize_connection(c, NGX_HTTP_V3_ERR_INTERNAL_ERROR, - "could not send settings"); - ngx_http_close_connection(c); - return; - } - } - - if (c->qs->id & NGX_QUIC_STREAM_UNIDIRECTIONAL) { - ngx_http_v3_handle_client_uni_stream(c); - return; - } - - hc = ngx_pcalloc(c->pool, sizeof(ngx_http_connection_t)); - if (hc == NULL) { - ngx_http_close_connection(c); - return; - } - - ngx_memcpy(hc, h3c, sizeof(ngx_http_connection_t)); - c->data = hc; - - ctx = ngx_palloc(c->pool, sizeof(ngx_http_log_ctx_t)); - if (ctx == NULL) { - ngx_http_close_connection(c); - return; - } - - ctx->connection = c; - ctx->request = NULL; - ctx->current_request = NULL; - - c->log->handler = ngx_http_log_error; - c->log->data = ctx; - c->log->action = "waiting for request"; - - c->log_error = NGX_ERROR_INFO; - - ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->log, 0, - "http3 new stream id:0x%uXL", c->qs->id); - - rev = c->read; - rev->handler = ngx_http_wait_request_handler; - c->write->handler = ngx_http_empty_handler; - - rev->handler(rev); -} - -#endif - - static void ngx_http_wait_request_handler(ngx_event_t *rev) { @@ -725,7 +660,7 @@ ngx_http_alloc_request(ngx_connection_t *c) r->http_version = NGX_HTTP_VERSION_10; #if (NGX_HTTP_V3) - if (hc->quic) { + if (hc->addr_conf->http3) { r->http_version = NGX_HTTP_VERSION_30; } #endif -- cgit v1.2.3 From 3073ad1381c4d8f8aae4501d66497164167b2081 Mon Sep 17 00:00:00 2001 From: Roman Arutyunyan Date: Tue, 21 Jul 2020 23:08:23 +0300 Subject: QUIC: eliminated connection handler argument in ngx_quic_run(). Now c->listening->handler() is called instead. --- src/http/ngx_http_request.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/http/ngx_http_request.c') diff --git a/src/http/ngx_http_request.c b/src/http/ngx_http_request.c index bfa8e11c5..9b6d461e0 100644 --- a/src/http/ngx_http_request.c +++ b/src/http/ngx_http_request.c @@ -336,7 +336,7 @@ ngx_http_init_connection(ngx_connection_t *c) sscf = ngx_http_get_module_srv_conf(hc->conf_ctx, ngx_http_ssl_module); - ngx_quic_run(c, &sscf->ssl, qcf, ngx_http_init_connection); + ngx_quic_run(c, &sscf->ssl, qcf); return; } } -- cgit v1.2.3 From cdc0d61ea0c55f89c9fbc35b4c785c1f5d7f895e Mon Sep 17 00:00:00 2001 From: Roman Arutyunyan Date: Wed, 22 Jul 2020 11:03:42 +0300 Subject: HTTP/3: do not call shutdown() for QUIC streams. Previously, this triggered an alert "shutdown() failed" in error log. --- src/http/ngx_http_request.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) (limited to 'src/http/ngx_http_request.c') diff --git a/src/http/ngx_http_request.c b/src/http/ngx_http_request.c index 9b6d461e0..285879f2f 100644 --- a/src/http/ngx_http_request.c +++ b/src/http/ngx_http_request.c @@ -3504,11 +3504,13 @@ ngx_http_set_lingering_close(ngx_http_request_t *r) } } - if (ngx_shutdown_socket(c->fd, NGX_WRITE_SHUTDOWN) == -1) { - ngx_connection_error(c, ngx_socket_errno, - ngx_shutdown_socket_n " failed"); - ngx_http_close_request(r, 0); - return; + if (c->fd != NGX_INVALID_FILE) { + if (ngx_shutdown_socket(c->fd, NGX_WRITE_SHUTDOWN) == -1) { + ngx_connection_error(c, ngx_socket_errno, + ngx_shutdown_socket_n " failed"); + ngx_http_close_request(r, 0); + return; + } } if (rev->ready) { -- cgit v1.2.3 From 5e036a6bef567bbe4e87ce7958ab76663ed3242e Mon Sep 17 00:00:00 2001 From: Roman Arutyunyan Date: Tue, 14 Jul 2020 16:52:44 +0300 Subject: HTTP/3: support $server_protocol variable. Now it holds "HTTP/3.0". Previously it was empty. --- src/http/ngx_http_request.c | 4 ---- 1 file changed, 4 deletions(-) (limited to 'src/http/ngx_http_request.c') diff --git a/src/http/ngx_http_request.c b/src/http/ngx_http_request.c index 285879f2f..82deef674 100644 --- a/src/http/ngx_http_request.c +++ b/src/http/ngx_http_request.c @@ -1139,10 +1139,6 @@ ngx_http_process_request_line(ngx_event_t *rev) r->method_name.len = r->method_end - r->method_start; r->method_name.data = r->method_start; - if (r->http_protocol.data) { - r->http_protocol.len = r->request_end - r->http_protocol.data; - } - if (ngx_http_process_request_uri(r) != NGX_OK) { break; } -- cgit v1.2.3 From 6d064c94e0600f7ff15e2815784f9f89cc4858b4 Mon Sep 17 00:00:00 2001 From: Roman Arutyunyan Date: Thu, 23 Jul 2020 13:41:24 +0300 Subject: HTTP/3: server pushes. New directives are added: - http3_max_concurrent_pushes - http3_push - http3_push_preload --- src/http/ngx_http_request.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'src/http/ngx_http_request.c') diff --git a/src/http/ngx_http_request.c b/src/http/ngx_http_request.c index 82deef674..54e5e2866 100644 --- a/src/http/ngx_http_request.c +++ b/src/http/ngx_http_request.c @@ -55,7 +55,6 @@ static ngx_int_t ngx_http_post_action(ngx_http_request_t *r); static void ngx_http_close_request(ngx_http_request_t *r, ngx_int_t error); static void ngx_http_log_request(ngx_http_request_t *r); -static u_char *ngx_http_log_error(ngx_log_t *log, u_char *buf, size_t len); static u_char *ngx_http_log_error_handler(ngx_http_request_t *r, ngx_http_request_t *sr, u_char *buf, size_t len); @@ -3838,7 +3837,7 @@ ngx_http_close_connection(ngx_connection_t *c) } -static u_char * +u_char * ngx_http_log_error(ngx_log_t *log, u_char *buf, size_t len) { u_char *p; -- cgit v1.2.3 From 68c5d80ee5381db9ea20e2ef247153e300fe837c Mon Sep 17 00:00:00 2001 From: Roman Arutyunyan Date: Tue, 11 Aug 2020 10:41:39 +0300 Subject: QUIC: fixed ngx_http_test_reading() for QUIC streams. Previously this function generated an error trying to figure out if client shut down the write end of the connection. The reason for this error was that a QUIC stream has no socket descriptor. However checking for eof is not the right thing to do for an HTTP/3 QUIC stream since HTTP/3 clients are expected to shut down the write end of the stream after sending the request. Now the function handles QUIC streams separately. It checks if c->read->error is set. The error flags for c->read and c->write are now set for all streams when closing the QUIC connection instead of setting the pending_eof flag. --- src/http/ngx_http_request.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) (limited to 'src/http/ngx_http_request.c') diff --git a/src/http/ngx_http_request.c b/src/http/ngx_http_request.c index 54e5e2866..30a22fa22 100644 --- a/src/http/ngx_http_request.c +++ b/src/http/ngx_http_request.c @@ -3022,6 +3022,19 @@ ngx_http_test_reading(ngx_http_request_t *r) #endif +#if (NGX_HTTP_QUIC) + + if (c->qs) { + if (c->read->error) { + err = 0; + goto closed; + } + + return; + } + +#endif + #if (NGX_HAVE_KQUEUE) if (ngx_event_flags & NGX_USE_KQUEUE_EVENT) { -- cgit v1.2.3 From 693e55a4b232afc6f7b4ba8e25f07decd86baa21 Mon Sep 17 00:00:00 2001 From: Roman Arutyunyan Date: Tue, 25 Aug 2020 12:45:21 +0300 Subject: HTTP/3: drop the unwanted remainder of the request. As per HTTP/3 draft 29, section 4.1: When the server does not need to receive the remainder of the request, it MAY abort reading the request stream, send a complete response, and cleanly close the sending part of the stream. --- src/http/ngx_http_request.c | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'src/http/ngx_http_request.c') diff --git a/src/http/ngx_http_request.c b/src/http/ngx_http_request.c index 7dbbcceb2..e322fae4b 100644 --- a/src/http/ngx_http_request.c +++ b/src/http/ngx_http_request.c @@ -2819,6 +2819,13 @@ ngx_http_finalize_connection(ngx_http_request_t *r) } #endif +#if (NGX_HTTP_QUIC) + if (r->connection->qs) { + ngx_http_close_request(r, 0); + return; + } +#endif + clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); if (r->main->count != 1) { -- cgit v1.2.3 From 0824d61fc9d28898e7d771825eca2880bc08df8b Mon Sep 17 00:00:00 2001 From: Sergey Kandaurov Date: Wed, 23 Sep 2020 13:13:04 +0100 Subject: QUIC: unbreak client certificate verification after 0d2b2664b41c. Initially, client certificate verification didn't work due to the missing hc->ssl on a QUIC stream, which is started to be set in 7738:7f0981be07c4. Then it was lost in 7999:0d2b2664b41c introducing "quic" listen parameter. This change re-adds hc->ssl back for all QUIC connections, similar to SSL. --- src/http/ngx_http_request.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'src/http/ngx_http_request.c') diff --git a/src/http/ngx_http_request.c b/src/http/ngx_http_request.c index e322fae4b..f1c6fa45c 100644 --- a/src/http/ngx_http_request.c +++ b/src/http/ngx_http_request.c @@ -308,6 +308,8 @@ ngx_http_init_connection(ngx_connection_t *c) ngx_quic_conf_t *qcf; ngx_http_ssl_srv_conf_t *sscf; + hc->ssl = 1; + #if (NGX_HTTP_V3) if (hc->addr_conf->http3) { -- cgit v1.2.3 From 1f90fccd972d3395239a7f6dea733dfe3627abc5 Mon Sep 17 00:00:00 2001 From: Roman Arutyunyan Date: Tue, 29 Sep 2020 22:09:09 +0100 Subject: QUIC: switch stream context to a server selected by SNI. Previously the default server configuration context was used until the :authority or host header was parsed. This led to using the configuration parameters like client_header_buffer_size or request_pool_size from the default server rather than from the server selected by SNI. Also, the switch to the right server log is implemented. This issue manifested itself as QUIC stream being logged to the default server log until :authority or host is parsed. --- src/http/ngx_http_request.c | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) (limited to 'src/http/ngx_http_request.c') diff --git a/src/http/ngx_http_request.c b/src/http/ngx_http_request.c index f1c6fa45c..2a8a22564 100644 --- a/src/http/ngx_http_request.c +++ b/src/http/ngx_http_request.c @@ -305,8 +305,10 @@ ngx_http_init_connection(ngx_connection_t *c) #if (NGX_HTTP_QUIC) if (hc->addr_conf->quic) { - ngx_quic_conf_t *qcf; - ngx_http_ssl_srv_conf_t *sscf; + ngx_quic_conf_t *qcf; + ngx_http_connection_t *phc; + ngx_http_ssl_srv_conf_t *sscf; + ngx_http_core_loc_conf_t *clcf; hc->ssl = 1; @@ -340,6 +342,17 @@ ngx_http_init_connection(ngx_connection_t *c) ngx_quic_run(c, &sscf->ssl, qcf); return; } + + phc = c->qs->parent->data; + + if (phc->ssl_servername) { + hc->ssl_servername = phc->ssl_servername; + hc->conf_ctx = phc->conf_ctx; + + clcf = ngx_http_get_module_loc_conf(hc->conf_ctx, + ngx_http_core_module); + ngx_set_connection_log(c, clcf->error_log); + } } #endif -- cgit v1.2.3 From 0f843cfb74dd4dab7bff4d9a0f7e73b8b8cb61f0 Mon Sep 17 00:00:00 2001 From: Vladimir Homutov Date: Thu, 1 Oct 2020 10:04:35 +0300 Subject: QUIC: moved ssl configuration pointer to quic configuration. The ssl configuration is obtained at config time and saved for future use. --- src/http/ngx_http_request.c | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) (limited to 'src/http/ngx_http_request.c') diff --git a/src/http/ngx_http_request.c b/src/http/ngx_http_request.c index 2a8a22564..b3e27c62e 100644 --- a/src/http/ngx_http_request.c +++ b/src/http/ngx_http_request.c @@ -307,7 +307,6 @@ ngx_http_init_connection(ngx_connection_t *c) if (hc->addr_conf->quic) { ngx_quic_conf_t *qcf; ngx_http_connection_t *phc; - ngx_http_ssl_srv_conf_t *sscf; ngx_http_core_loc_conf_t *clcf; hc->ssl = 1; @@ -336,10 +335,7 @@ ngx_http_init_connection(ngx_connection_t *c) qcf = ngx_http_get_module_srv_conf(hc->conf_ctx, ngx_http_quic_module); - sscf = ngx_http_get_module_srv_conf(hc->conf_ctx, - ngx_http_ssl_module); - - ngx_quic_run(c, &sscf->ssl, qcf); + ngx_quic_run(c, qcf); return; } -- cgit v1.2.3 From 2fd31c8959fbae8f069d09b61f339358214e75d1 Mon Sep 17 00:00:00 2001 From: Roman Arutyunyan Date: Tue, 10 Nov 2020 19:40:00 +0000 Subject: QUIC: renamed c->qs to c->quic. --- src/http/ngx_http_request.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'src/http/ngx_http_request.c') diff --git a/src/http/ngx_http_request.c b/src/http/ngx_http_request.c index f33555687..8df43891a 100644 --- a/src/http/ngx_http_request.c +++ b/src/http/ngx_http_request.c @@ -330,7 +330,7 @@ ngx_http_init_connection(ngx_connection_t *c) #endif - if (c->qs == NULL) { + if (c->quic == NULL) { c->log->connection = c->number; qcf = ngx_http_get_module_srv_conf(hc->conf_ctx, @@ -339,7 +339,7 @@ ngx_http_init_connection(ngx_connection_t *c) return; } - phc = c->qs->parent->data; + phc = c->quic->parent->data; if (phc->ssl_servername) { hc->ssl_servername = phc->ssl_servername; @@ -2847,7 +2847,7 @@ ngx_http_finalize_connection(ngx_http_request_t *r) #endif #if (NGX_HTTP_QUIC) - if (r->connection->qs) { + if (r->connection->quic) { ngx_http_close_request(r, 0); return; } @@ -3064,7 +3064,7 @@ ngx_http_test_reading(ngx_http_request_t *r) #if (NGX_HTTP_QUIC) - if (c->qs) { + if (c->quic) { if (c->read->error) { err = 0; goto closed; -- cgit v1.2.3 From 7cfc5eb11fbfe3beb9d793dbacae70fb658d46c2 Mon Sep 17 00:00:00 2001 From: Roman Arutyunyan Date: Wed, 25 Nov 2020 17:57:43 +0000 Subject: HTTP/3: eliminated r->method_start. The field was introduced to ease parsing HTTP/3 requests. The change reduces diff to the default branch. --- src/http/ngx_http_request.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) (limited to 'src/http/ngx_http_request.c') diff --git a/src/http/ngx_http_request.c b/src/http/ngx_http_request.c index 3b9e59005..a60c5758f 100644 --- a/src/http/ngx_http_request.c +++ b/src/http/ngx_http_request.c @@ -1162,8 +1162,12 @@ ngx_http_process_request_line(ngx_event_t *rev) ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->log, 0, "http request line: \"%V\"", &r->request_line); - r->method_name.len = r->method_end - r->method_start; - r->method_name.data = r->method_start; + r->method_name.len = r->method_end - r->request_start + 1; + r->method_name.data = r->request_line.data; + + if (r->http_protocol.data) { + r->http_protocol.len = r->request_end - r->http_protocol.data; + } if (ngx_http_process_request_uri(r) != NGX_OK) { break; -- cgit v1.2.3 From 9e489d208fff35c490b43980a064c38cc8dc4f2c Mon Sep 17 00:00:00 2001 From: Roman Arutyunyan Date: Fri, 22 Jan 2021 16:34:06 +0300 Subject: HTTP/3: refactored request parser. The change reduces diff to the default branch for src/http/ngx_http_request.c and src/http/ngx_http_parse.c. --- src/http/ngx_http_request.c | 197 ++++++++------------------------------------ 1 file changed, 35 insertions(+), 162 deletions(-) (limited to 'src/http/ngx_http_request.c') diff --git a/src/http/ngx_http_request.c b/src/http/ngx_http_request.c index 0ce4dacec..abcc1bba8 100644 --- a/src/http/ngx_http_request.c +++ b/src/http/ngx_http_request.c @@ -31,10 +31,6 @@ static ngx_int_t ngx_http_process_connection(ngx_http_request_t *r, static ngx_int_t ngx_http_process_user_agent(ngx_http_request_t *r, ngx_table_elt_t *h, ngx_uint_t offset); -static ngx_int_t ngx_http_validate_host(ngx_str_t *host, ngx_pool_t *pool, - ngx_uint_t alloc); -static ngx_int_t ngx_http_set_virtual_server(ngx_http_request_t *r, - ngx_str_t *host); static ngx_int_t ngx_http_find_virtual_server(ngx_connection_t *c, ngx_http_virtual_names_t *virtual_names, ngx_str_t *host, ngx_http_request_t *r, ngx_http_core_srv_conf_t **cscfp); @@ -52,7 +48,6 @@ static void ngx_http_keepalive_handler(ngx_event_t *ev); static void ngx_http_set_lingering_close(ngx_connection_t *c); static void ngx_http_lingering_close_handler(ngx_event_t *ev); static ngx_int_t ngx_http_post_action(ngx_http_request_t *r); -static void ngx_http_close_request(ngx_http_request_t *r, ngx_int_t error); static void ngx_http_log_request(ngx_http_request_t *r); static u_char *ngx_http_log_error_handler(ngx_http_request_t *r, @@ -303,54 +298,11 @@ ngx_http_init_connection(ngx_connection_t *c) hc->conf_ctx = hc->addr_conf->default_server->ctx; #if (NGX_HTTP_QUIC) - if (hc->addr_conf->quic) { - ngx_quic_conf_t *qcf; - ngx_http_connection_t *phc; - ngx_http_core_loc_conf_t *clcf; - - hc->ssl = 1; - -#if (NGX_HTTP_V3) - - if (hc->addr_conf->http3) { - ngx_int_t rc; - - rc = ngx_http_v3_init_connection(c); - - if (rc == NGX_ERROR) { - ngx_http_close_connection(c); - return; - } - - if (rc == NGX_DONE) { - return; - } - } - -#endif - - if (c->quic == NULL) { - c->log->connection = c->number; - - qcf = ngx_http_get_module_srv_conf(hc->conf_ctx, - ngx_http_quic_module); - ngx_quic_run(c, qcf); + if (ngx_http_quic_init(c) == NGX_DONE) { return; } - - phc = c->quic->parent->data; - - if (phc->ssl_servername) { - hc->ssl_servername = phc->ssl_servername; - hc->conf_ctx = phc->conf_ctx; - - clcf = ngx_http_get_module_loc_conf(hc->conf_ctx, - ngx_http_core_module); - ngx_set_connection_log(c, clcf->error_log); - } } - #endif ctx = ngx_palloc(c->pool, sizeof(ngx_http_log_ctx_t)); @@ -380,6 +332,13 @@ ngx_http_init_connection(ngx_connection_t *c) } #endif +#if (NGX_HTTP_V3) + if (hc->addr_conf->http3) { + ngx_http_v3_init(c); + return; + } +#endif + #if (NGX_HTTP_SSL) { ngx_http_ssl_srv_conf_t *sscf; @@ -669,12 +628,6 @@ ngx_http_alloc_request(ngx_connection_t *c) r->method = NGX_HTTP_UNKNOWN; r->http_version = NGX_HTTP_VERSION_10; -#if (NGX_HTTP_V3) - if (hc->addr_conf->http3) { - r->http_version = NGX_HTTP_VERSION_30; - } -#endif - r->headers_in.content_length_n = -1; r->headers_in.keep_alive_n = -1; r->headers_out.content_length_n = -1; @@ -1140,16 +1093,7 @@ ngx_http_process_request_line(ngx_event_t *rev) } } - switch (r->http_version) { -#if (NGX_HTTP_V3) - case NGX_HTTP_VERSION_30: - rc = ngx_http_v3_parse_request(r, r->header_in); - break; -#endif - - default: /* HTTP/1.x */ - rc = ngx_http_parse_request_line(r, r->header_in); - } + rc = ngx_http_parse_request_line(r, r->header_in); if (rc == NGX_OK) { @@ -1157,7 +1101,7 @@ ngx_http_process_request_line(ngx_event_t *rev) r->request_line.len = r->request_end - r->request_start; r->request_line.data = r->request_start; - r->request_length = r->header_in->pos - r->parse_start; + r->request_length = r->header_in->pos - r->request_start; ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->log, 0, "http request line: \"%V\"", &r->request_line); @@ -1234,15 +1178,6 @@ ngx_http_process_request_line(ngx_event_t *rev) break; } - if (rc == NGX_BUSY) { - if (ngx_handle_read_event(rev, 0) != NGX_OK) { - ngx_http_close_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR); - return; - } - - break; - } - if (rc != NGX_AGAIN) { /* there was error while a request line parsing */ @@ -1272,8 +1207,8 @@ ngx_http_process_request_line(ngx_event_t *rev) } if (rv == NGX_DECLINED) { - r->request_line.len = r->header_in->end - r->parse_start; - r->request_line.data = r->parse_start; + r->request_line.len = r->header_in->end - r->request_start; + r->request_line.data = r->request_start; ngx_log_error(NGX_LOG_INFO, c->log, 0, "client sent too long URI"); @@ -1437,7 +1372,7 @@ ngx_http_process_request_headers(ngx_event_t *rev) cmcf = ngx_http_get_module_main_conf(r, ngx_http_core_module); - rc = NGX_OK; + rc = NGX_AGAIN; for ( ;; ) { @@ -1453,7 +1388,7 @@ ngx_http_process_request_headers(ngx_event_t *rev) } if (rv == NGX_DECLINED) { - p = r->parse_start; + p = r->header_name_start; r->lingering_close = 1; @@ -1473,7 +1408,7 @@ ngx_http_process_request_headers(ngx_event_t *rev) ngx_log_error(NGX_LOG_INFO, c->log, 0, "client sent too long header line: \"%*s...\"", - len, r->parse_start); + len, r->header_name_start); ngx_http_finalize_request(r, NGX_HTTP_REQUEST_HEADER_TOO_LARGE); @@ -1491,32 +1426,21 @@ ngx_http_process_request_headers(ngx_event_t *rev) /* the host header could change the server configuration context */ cscf = ngx_http_get_module_srv_conf(r, ngx_http_core_module); - switch (r->http_version) { -#if (NGX_HTTP_V3) - case NGX_HTTP_VERSION_30: - rc = ngx_http_v3_parse_header(r, r->header_in, - cscf->underscores_in_headers); - break; -#endif - - default: /* HTTP/1.x */ - rc = ngx_http_parse_header_line(r, r->header_in, - cscf->underscores_in_headers); - } + rc = ngx_http_parse_header_line(r, r->header_in, + cscf->underscores_in_headers); if (rc == NGX_OK) { - r->request_length += r->header_in->pos - r->parse_start; + r->request_length += r->header_in->pos - r->header_name_start; if (r->invalid_header && cscf->ignore_invalid_headers) { /* there was error while a header line parsing */ ngx_log_error(NGX_LOG_INFO, c->log, 0, - "client sent invalid header line: \"%*s: %*s\"", - r->header_name_end - r->header_name_start, - r->header_name_start, - r->header_end - r->header_start, r->header_start); + "client sent invalid header line: \"%*s\"", + r->header_end - r->header_name_start, + r->header_name_start); continue; } @@ -1532,17 +1456,11 @@ ngx_http_process_request_headers(ngx_event_t *rev) h->key.len = r->header_name_end - r->header_name_start; h->key.data = r->header_name_start; - - if (h->key.data[h->key.len]) { - h->key.data[h->key.len] = '\0'; - } + h->key.data[h->key.len] = '\0'; h->value.len = r->header_end - r->header_start; h->value.data = r->header_start; - - if (h->value.data[h->value.len]) { - h->value.data[h->value.len] = '\0'; - } + h->value.data[h->value.len] = '\0'; h->lowcase_key = ngx_pnalloc(r->pool, h->key.len); if (h->lowcase_key == NULL) { @@ -1578,7 +1496,7 @@ ngx_http_process_request_headers(ngx_event_t *rev) ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "http header done"); - r->request_length += r->header_in->pos - r->parse_start; + r->request_length += r->header_in->pos - r->header_name_start; r->http_state = NGX_HTTP_PROCESS_REQUEST_STATE; @@ -1693,7 +1611,7 @@ ngx_http_alloc_large_header_buffer(ngx_http_request_t *r, return NGX_OK; } - old = r->parse_start; + old = request_line ? r->request_start : r->header_name_start; cscf = ngx_http_get_module_srv_conf(r, ngx_http_core_module); @@ -1771,14 +1689,6 @@ ngx_http_alloc_large_header_buffer(ngx_http_request_t *r, b->pos = new + (r->header_in->pos - old); b->last = new + (r->header_in->pos - old); - r->parse_start = new; - - r->header_in = b; - - if (r->http_version > NGX_HTTP_VERSION_11) { - return NGX_OK; - } - if (request_line) { r->request_start = new; @@ -1827,6 +1737,8 @@ ngx_http_alloc_large_header_buffer(ngx_http_request_t *r, r->header_end = new + (r->header_end - old); } + r->header_in = b; + return NGX_OK; } @@ -2047,46 +1959,13 @@ ngx_http_process_request_header(ngx_http_request_t *r) return NGX_ERROR; } - if (r->headers_in.host == NULL && r->http_version == NGX_HTTP_VERSION_11) { + if (r->headers_in.host == NULL && r->http_version > NGX_HTTP_VERSION_10) { ngx_log_error(NGX_LOG_INFO, r->connection->log, 0, "client sent HTTP/1.1 request without \"Host\" header"); ngx_http_finalize_request(r, NGX_HTTP_BAD_REQUEST); return NGX_ERROR; } - if (r->headers_in.host == NULL && r->http_version == NGX_HTTP_VERSION_20) { - ngx_log_error(NGX_LOG_INFO, r->connection->log, 0, - "client sent HTTP/2 request without " - "\":authority\" or \"Host\" header"); - ngx_http_finalize_request(r, NGX_HTTP_BAD_REQUEST); - return NGX_ERROR; - } - - if (r->http_version == NGX_HTTP_VERSION_30) { - if (r->headers_in.server.len == 0) { - ngx_log_error(NGX_LOG_INFO, r->connection->log, 0, - "client sent HTTP/3 request without " - "\":authority\" or \"Host\" header"); - ngx_http_finalize_request(r, NGX_HTTP_BAD_REQUEST); - return NGX_ERROR; - } - - if (r->headers_in.host) { - if (r->headers_in.host->value.len != r->headers_in.server.len - || ngx_memcmp(r->headers_in.host->value.data, - r->headers_in.server.data, - r->headers_in.server.len) - != 0) - { - ngx_log_error(NGX_LOG_INFO, r->connection->log, 0, - "client sent HTTP/3 request with different " - "values of \":authority\" and \"Host\" headers"); - ngx_http_finalize_request(r, NGX_HTTP_BAD_REQUEST); - return NGX_ERROR; - } - } - } - if (r->headers_in.content_length) { r->headers_in.content_length_n = ngx_atoof(r->headers_in.content_length->value.data, @@ -2125,12 +2004,6 @@ ngx_http_process_request_header(ngx_http_request_t *r) } } -#if (NGX_HTTP_V3) - if (r->http_version == NGX_HTTP_VERSION_30) { - r->headers_in.chunked = 1; - } -#endif - if (r->headers_in.connection_type == NGX_HTTP_CONNECTION_KEEP_ALIVE) { if (r->headers_in.keep_alive) { r->headers_in.keep_alive_n = @@ -2235,7 +2108,7 @@ ngx_http_process_request(ngx_http_request_t *r) } -static ngx_int_t +ngx_int_t ngx_http_validate_host(ngx_str_t *host, ngx_pool_t *pool, ngx_uint_t alloc) { u_char *h, ch; @@ -2326,7 +2199,7 @@ ngx_http_validate_host(ngx_str_t *host, ngx_pool_t *pool, ngx_uint_t alloc) } -static ngx_int_t +ngx_int_t ngx_http_set_virtual_server(ngx_http_request_t *r, ngx_str_t *host) { ngx_int_t rc; @@ -3744,7 +3617,7 @@ ngx_http_post_action(ngx_http_request_t *r) } -static void +void ngx_http_close_request(ngx_http_request_t *r, ngx_int_t rc) { ngx_connection_t *c; @@ -3965,15 +3838,15 @@ ngx_http_log_error_handler(ngx_http_request_t *r, ngx_http_request_t *sr, len -= p - buf; buf = p; - if (r->request_line.data == NULL && r->parse_start) { - for (p = r->parse_start; p < r->header_in->last; p++) { + if (r->request_line.data == NULL && r->request_start) { + for (p = r->request_start; p < r->header_in->last; p++) { if (*p == CR || *p == LF) { break; } } - r->request_line.len = p - r->parse_start; - r->request_line.data = r->parse_start; + r->request_line.len = p - r->request_start; + r->request_line.data = r->request_start; } if (r->request_line.len) { -- cgit v1.2.3 From 52d0bf620a964bbb51bd7ff87e778ba72164b802 Mon Sep 17 00:00:00 2001 From: Roman Arutyunyan Date: Mon, 21 Dec 2020 17:35:13 +0000 Subject: HTTP/3: removed HTTP/3-specific code. The ngx_http_set_lingering_close() function is not called for HTTP/3. The change reduces diff to the default branch. --- src/http/ngx_http_request.c | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) (limited to 'src/http/ngx_http_request.c') diff --git a/src/http/ngx_http_request.c b/src/http/ngx_http_request.c index abcc1bba8..b747b0206 100644 --- a/src/http/ngx_http_request.c +++ b/src/http/ngx_http_request.c @@ -3451,13 +3451,11 @@ ngx_http_set_lingering_close(ngx_connection_t *c) } } - if (c->fd != NGX_INVALID_FILE) { - if (ngx_shutdown_socket(c->fd, NGX_WRITE_SHUTDOWN) == -1) { - ngx_connection_error(c, ngx_socket_errno, - ngx_shutdown_socket_n " failed"); - ngx_http_close_request(r, 0); - return; - } + if (ngx_shutdown_socket(c->fd, NGX_WRITE_SHUTDOWN) == -1) { + ngx_connection_error(c, ngx_socket_errno, + ngx_shutdown_socket_n " failed"); + ngx_http_close_request(r, 0); + return; } ngx_add_timer(rev, clcf->lingering_timeout); -- cgit v1.2.3 From 0f3eb180d2af781c98b84c1e5e2b4fe4c0c3be54 Mon Sep 17 00:00:00 2001 From: Roman Arutyunyan Date: Fri, 17 Sep 2021 16:32:23 +0300 Subject: HTTP/3: make ngx_http_log_error() static again. This function was only referenced from ngx_http_v3_create_push_request() to initialize push connection log. Now the log handler is copied from the parent request connection. The change reduces diff to the default branch. --- src/http/ngx_http_request.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'src/http/ngx_http_request.c') diff --git a/src/http/ngx_http_request.c b/src/http/ngx_http_request.c index 30200075e..2b838cfc3 100644 --- a/src/http/ngx_http_request.c +++ b/src/http/ngx_http_request.c @@ -50,6 +50,7 @@ static void ngx_http_lingering_close_handler(ngx_event_t *ev); static ngx_int_t ngx_http_post_action(ngx_http_request_t *r); static void ngx_http_log_request(ngx_http_request_t *r); +static u_char *ngx_http_log_error(ngx_log_t *log, u_char *buf, size_t len); static u_char *ngx_http_log_error_handler(ngx_http_request_t *r, ngx_http_request_t *sr, u_char *buf, size_t len); @@ -3829,7 +3830,7 @@ ngx_http_close_connection(ngx_connection_t *c) } -u_char * +static u_char * ngx_http_log_error(ngx_log_t *log, u_char *buf, size_t len) { u_char *p; -- cgit v1.2.3 From dab6035d68f3dd3f212393635c193c7aefea0d65 Mon Sep 17 00:00:00 2001 From: Sergey Kandaurov Date: Wed, 29 Sep 2021 15:01:59 +0300 Subject: HTTP/3: fixed segfault when using SSL certificates with variables. A QUIC connection doesn't have c->log->data and friends initialized to sensible values. Yet, a request can be created in the certificate callback with such an assumption, which leads to a segmentation fault due to null pointer dereference in ngx_http_free_request(). The fix is to adjust initializing the QUIC part of a connection such that it has all of that in place. Further, this appends logging error context for unsuccessful QUIC handshakes: - cannot load certificate .. while handling frames - SSL_do_handshake() failed .. while sending frames --- src/http/ngx_http_request.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) (limited to 'src/http/ngx_http_request.c') diff --git a/src/http/ngx_http_request.c b/src/http/ngx_http_request.c index 2b838cfc3..6496a5400 100644 --- a/src/http/ngx_http_request.c +++ b/src/http/ngx_http_request.c @@ -299,14 +299,6 @@ ngx_http_init_connection(ngx_connection_t *c) /* the default server configuration for the address:port */ hc->conf_ctx = hc->addr_conf->default_server->ctx; -#if (NGX_HTTP_QUIC) - if (hc->addr_conf->quic) { - if (ngx_http_quic_init(c) == NGX_DONE) { - return; - } - } -#endif - ctx = ngx_palloc(c->pool, sizeof(ngx_http_log_ctx_t)); if (ctx == NULL) { ngx_http_close_connection(c); @@ -324,6 +316,14 @@ ngx_http_init_connection(ngx_connection_t *c) c->log_error = NGX_ERROR_INFO; +#if (NGX_HTTP_QUIC) + if (hc->addr_conf->quic) { + if (ngx_http_quic_init(c) == NGX_DONE) { + return; + } + } +#endif + rev = c->read; rev->handler = ngx_http_wait_request_handler; c->write->handler = ngx_http_empty_handler; -- cgit v1.2.3 From 38d56f4ccd94ffba49e84ace82125249af7ef20a Mon Sep 17 00:00:00 2001 From: Roman Arutyunyan Date: Mon, 27 Sep 2021 17:08:48 +0300 Subject: HTTP/3: reset streams with incomplete responses or timeouts. This prevents client from closing the QUIC connection due to response parse error. --- src/http/ngx_http_request.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) (limited to 'src/http/ngx_http_request.c') diff --git a/src/http/ngx_http_request.c b/src/http/ngx_http_request.c index 6496a5400..e37ef8024 100644 --- a/src/http/ngx_http_request.c +++ b/src/http/ngx_http_request.c @@ -3746,6 +3746,12 @@ ngx_http_free_request(ngx_http_request_t *r, ngx_int_t rc) if (r->connection->timedout) { clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); +#if (NGX_HTTP_V3) + if (r->connection->quic) { + (void) ngx_quic_reset_stream(r->connection, + NGX_HTTP_V3_ERR_GENERAL_PROTOCOL_ERROR); + } else +#endif if (clcf->reset_timedout_connection) { linger.l_onoff = 1; linger.l_linger = 0; @@ -3757,6 +3763,14 @@ ngx_http_free_request(ngx_http_request_t *r, ngx_int_t rc) "setsockopt(SO_LINGER) failed"); } } + + } else if (!r->response_sent) { +#if (NGX_HTTP_V3) + if (r->connection->quic) { + (void) ngx_quic_reset_stream(r->connection, + NGX_HTTP_V3_ERR_INTERNAL_ERROR); + } +#endif } /* the various request strings were allocated from r->pool */ -- cgit v1.2.3 From a6fb8fe85077bd10e11231c70ece803284890520 Mon Sep 17 00:00:00 2001 From: Roman Arutyunyan Date: Mon, 18 Oct 2021 15:47:06 +0300 Subject: HTTP/3: allowed QUIC stream connection reuse. A QUIC stream connection is treated as reusable until first bytes of request arrive, which is also when the request object is now allocated. A connection closed as a result of draining, is reset with the error code H3_REQUEST_REJECTED. Such behavior is allowed by quic-http-34: Once a request stream has been opened, the request MAY be cancelled by either endpoint. Clients cancel requests if the response is no longer of interest; servers cancel requests if they are unable to or choose not to respond. When the server cancels a request without performing any application processing, the request is considered "rejected." The server SHOULD abort its response stream with the error code H3_REQUEST_REJECTED. The client can treat requests rejected by the server as though they had never been sent at all, thereby allowing them to be retried later. --- src/http/ngx_http_request.c | 27 ++++++++++++--------------- 1 file changed, 12 insertions(+), 15 deletions(-) (limited to 'src/http/ngx_http_request.c') diff --git a/src/http/ngx_http_request.c b/src/http/ngx_http_request.c index 88516cb4d..7125e7dd1 100644 --- a/src/http/ngx_http_request.c +++ b/src/http/ngx_http_request.c @@ -3731,15 +3731,14 @@ ngx_http_free_request(ngx_http_request_t *r, ngx_int_t rc) log->action = "closing request"; - if (r->connection->timedout) { + if (r->connection->timedout +#if (NGX_HTTP_QUIC) + && r->connection->quic == NULL +#endif + ) + { clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); -#if (NGX_HTTP_V3) - if (r->connection->quic) { - (void) ngx_quic_reset_stream(r->connection, - NGX_HTTP_V3_ERR_GENERAL_PROTOCOL_ERROR); - } else -#endif if (clcf->reset_timedout_connection) { linger.l_onoff = 1; linger.l_linger = 0; @@ -3751,14 +3750,6 @@ ngx_http_free_request(ngx_http_request_t *r, ngx_int_t rc) "setsockopt(SO_LINGER) failed"); } } - - } else if (!r->response_sent) { -#if (NGX_HTTP_V3) - if (r->connection->quic) { - (void) ngx_quic_reset_stream(r->connection, - NGX_HTTP_V3_ERR_INTERNAL_ERROR); - } -#endif } /* the various request strings were allocated from r->pool */ @@ -3818,6 +3809,12 @@ ngx_http_close_connection(ngx_connection_t *c) #endif +#if (NGX_HTTP_V3) + if (ngx_http_v3_connection(c)) { + ngx_http_v3_reset_connection(c); + } +#endif + #if (NGX_STAT_STUB) (void) ngx_atomic_fetch_add(ngx_stat_active, -1); #endif -- cgit v1.2.3 From 731915a0c5e90b79d3cca1a4b0a3c33e1f77631c Mon Sep 17 00:00:00 2001 From: Roman Arutyunyan Date: Mon, 6 Dec 2021 13:02:36 +0300 Subject: HTTP/3: merged ngx_http_quic_module into ngx_http_v3_module. --- src/http/ngx_http_request.c | 18 +++++------------- 1 file changed, 5 insertions(+), 13 deletions(-) (limited to 'src/http/ngx_http_request.c') diff --git a/src/http/ngx_http_request.c b/src/http/ngx_http_request.c index 7125e7dd1..0acedb6e9 100644 --- a/src/http/ngx_http_request.c +++ b/src/http/ngx_http_request.c @@ -316,14 +316,6 @@ ngx_http_init_connection(ngx_connection_t *c) c->log_error = NGX_ERROR_INFO; -#if (NGX_HTTP_QUIC) - if (hc->addr_conf->quic) { - if (ngx_http_quic_init(c) == NGX_DONE) { - return; - } - } -#endif - rev = c->read; rev->handler = ngx_http_wait_request_handler; c->write->handler = ngx_http_empty_handler; @@ -335,7 +327,7 @@ ngx_http_init_connection(ngx_connection_t *c) #endif #if (NGX_HTTP_V3) - if (hc->addr_conf->http3) { + if (hc->addr_conf->quic) { ngx_http_v3_init(c); return; } @@ -2746,7 +2738,7 @@ ngx_http_finalize_connection(ngx_http_request_t *r) } #endif -#if (NGX_HTTP_QUIC) +#if (NGX_HTTP_V3) if (r->connection->quic) { ngx_http_close_request(r, 0); return; @@ -2967,7 +2959,7 @@ ngx_http_test_reading(ngx_http_request_t *r) #endif -#if (NGX_HTTP_QUIC) +#if (NGX_HTTP_V3) if (c->quic) { if (c->read->error) { @@ -3732,7 +3724,7 @@ ngx_http_free_request(ngx_http_request_t *r, ngx_int_t rc) log->action = "closing request"; if (r->connection->timedout -#if (NGX_HTTP_QUIC) +#if (NGX_HTTP_V3) && r->connection->quic == NULL #endif ) @@ -3810,7 +3802,7 @@ ngx_http_close_connection(ngx_connection_t *c) #endif #if (NGX_HTTP_V3) - if (ngx_http_v3_connection(c)) { + if (c->quic) { ngx_http_v3_reset_connection(c); } #endif -- cgit v1.2.3 From d84c1f7885cc898f626057c314cdae4047c5d513 Mon Sep 17 00:00:00 2001 From: Roman Arutyunyan Date: Sat, 4 Dec 2021 10:52:55 +0300 Subject: HTTP/3: http3_hq directive and NGX_HTTP_V3_HQ macro. Listen quic parameter is no longer supported. --- src/http/ngx_http_request.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/http/ngx_http_request.c') diff --git a/src/http/ngx_http_request.c b/src/http/ngx_http_request.c index 0acedb6e9..e8907c100 100644 --- a/src/http/ngx_http_request.c +++ b/src/http/ngx_http_request.c @@ -327,7 +327,7 @@ ngx_http_init_connection(ngx_connection_t *c) #endif #if (NGX_HTTP_V3) - if (hc->addr_conf->quic) { + if (hc->addr_conf->http3) { ngx_http_v3_init(c); return; } -- cgit v1.2.3 From a42a62fc583ad311d06a90e3bcd12d63df0701a4 Mon Sep 17 00:00:00 2001 From: Sergey Kandaurov Date: Tue, 7 Dec 2021 15:49:51 +0300 Subject: QUIC: clear SSL_OP_ENABLE_MIDDLEBOX_COMPAT on SSL context switch. The SSL_OP_ENABLE_MIDDLEBOX_COMPAT option is provided by QuicTLS and enabled by default in the newly created SSL contexts. SSL_set_quic_method() is used to clear it, which is required for SSL handshake to work on QUIC connections. Switching context in the ngx_http_ssl_servername() SNI callback overrides SSL options from the new SSL context. This results in the option set again. Fix is to explicitly clear it when switching to another SSL context. Initially reported here (in Russian): http://mailman.nginx.org/pipermail/nginx-ru/2021-November/063989.html --- src/http/ngx_http_request.c | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'src/http/ngx_http_request.c') diff --git a/src/http/ngx_http_request.c b/src/http/ngx_http_request.c index e8907c100..32a26379c 100644 --- a/src/http/ngx_http_request.c +++ b/src/http/ngx_http_request.c @@ -953,6 +953,14 @@ ngx_http_ssl_servername(ngx_ssl_conn_t *ssl_conn, int *ad, void *arg) #ifdef SSL_OP_NO_RENEGOTIATION SSL_set_options(ssl_conn, SSL_OP_NO_RENEGOTIATION); +#endif + +#ifdef SSL_OP_ENABLE_MIDDLEBOX_COMPAT +#if (NGX_HTTP_QUIC) + if (c->listening->quic) { + SSL_clear_options(ssl_conn, SSL_OP_ENABLE_MIDDLEBOX_COMPAT); + } +#endif #endif } -- cgit v1.2.3 From 702a0986f393390d25368180e619e40160fe92da Mon Sep 17 00:00:00 2001 From: Sergey Kandaurov Date: Thu, 9 Dec 2021 11:15:25 +0300 Subject: QUIC: fixed e06283038ec8 mis-merge. The NGX_HTTP_QUIC macro was removed in 33226ac61076. --- src/http/ngx_http_request.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/http/ngx_http_request.c') diff --git a/src/http/ngx_http_request.c b/src/http/ngx_http_request.c index 32a26379c..12a8cd144 100644 --- a/src/http/ngx_http_request.c +++ b/src/http/ngx_http_request.c @@ -956,7 +956,7 @@ ngx_http_ssl_servername(ngx_ssl_conn_t *ssl_conn, int *ad, void *arg) #endif #ifdef SSL_OP_ENABLE_MIDDLEBOX_COMPAT -#if (NGX_HTTP_QUIC) +#if (NGX_HTTP_V3) if (c->listening->quic) { SSL_clear_options(ssl_conn, SSL_OP_ENABLE_MIDDLEBOX_COMPAT); } -- cgit v1.2.3 From 5ab94d4219fb2119770d024731a53dba6871b25c Mon Sep 17 00:00:00 2001 From: Roman Arutyunyan Date: Wed, 12 Jan 2022 11:57:06 +0300 Subject: HTTP/3: simplified code. --- src/http/ngx_http_request.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/http/ngx_http_request.c') diff --git a/src/http/ngx_http_request.c b/src/http/ngx_http_request.c index 12a8cd144..fd3e880f8 100644 --- a/src/http/ngx_http_request.c +++ b/src/http/ngx_http_request.c @@ -2970,7 +2970,7 @@ ngx_http_test_reading(ngx_http_request_t *r) #if (NGX_HTTP_V3) if (c->quic) { - if (c->read->error) { + if (rev->error) { err = 0; goto closed; } -- cgit v1.2.3 From 38cfe35779e4a8a6288d61bdf4a2e892dc0ce046 Mon Sep 17 00:00:00 2001 From: Roman Arutyunyan Date: Wed, 12 Jan 2022 11:57:46 +0300 Subject: HTTP/3: set c->error on read error in ngx_http_test_reading(). Similar to other error/eof cases. --- src/http/ngx_http_request.c | 1 + 1 file changed, 1 insertion(+) (limited to 'src/http/ngx_http_request.c') diff --git a/src/http/ngx_http_request.c b/src/http/ngx_http_request.c index fd3e880f8..bc6c077db 100644 --- a/src/http/ngx_http_request.c +++ b/src/http/ngx_http_request.c @@ -2971,6 +2971,7 @@ ngx_http_test_reading(ngx_http_request_t *r) if (c->quic) { if (rev->error) { + c->error = 1; err = 0; goto closed; } -- cgit v1.2.3 From 8a1deaca78d65f4db82f856e22dcf879d1cec479 Mon Sep 17 00:00:00 2001 From: Roman Arutyunyan Date: Mon, 22 Aug 2022 14:09:03 +0400 Subject: HTTP/3: renamed functions. ngx_http_v3_init() is renamed ngx_http_v3_init_stream(). ngx_http_v3_reset_connection() is renamed to ngx_http_v3_reset_stream(). --- src/http/ngx_http_request.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src/http/ngx_http_request.c') diff --git a/src/http/ngx_http_request.c b/src/http/ngx_http_request.c index 86da94262..8cc3cff24 100644 --- a/src/http/ngx_http_request.c +++ b/src/http/ngx_http_request.c @@ -326,7 +326,7 @@ ngx_http_init_connection(ngx_connection_t *c) #if (NGX_HTTP_V3) if (hc->addr_conf->http3) { - ngx_http_v3_init(c); + ngx_http_v3_init_stream(c); return; } #endif @@ -3786,7 +3786,7 @@ ngx_http_close_connection(ngx_connection_t *c) #if (NGX_HTTP_V3) if (c->quic) { - ngx_http_v3_reset_connection(c); + ngx_http_v3_reset_stream(c); } #endif -- cgit v1.2.3 From 815ef96124176baef4e940c4beaec158305b368a Mon Sep 17 00:00:00 2001 From: Roman Arutyunyan Date: Mon, 27 Feb 2023 14:00:56 +0400 Subject: HTTP/3: "quic" parameter of "listen" directive. Now "listen" directve has a new "quic" parameter which enables QUIC protocol for the address. Further, to enable HTTP/3, a new directive "http3" is introduced. The hq-interop protocol is enabled by "http3_hq" as before. Now application protocol is chosen by ALPN. Previously used "http3" parameter of "listen" is deprecated. --- src/http/ngx_http_request.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/http/ngx_http_request.c') diff --git a/src/http/ngx_http_request.c b/src/http/ngx_http_request.c index 8cc3cff24..6cfae3435 100644 --- a/src/http/ngx_http_request.c +++ b/src/http/ngx_http_request.c @@ -325,7 +325,7 @@ ngx_http_init_connection(ngx_connection_t *c) #endif #if (NGX_HTTP_V3) - if (hc->addr_conf->http3) { + if (hc->addr_conf->quic) { ngx_http_v3_init_stream(c); return; } -- cgit v1.2.3