Mercurial > hg > nginx
diff src/http/ngx_http_request.c @ 8182:b28ea685a56e quic
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.
author | Vladimir Homutov <vl@nginx.com> |
---|---|
date | Fri, 28 Feb 2020 16:23:25 +0300 |
parents | 3cb4f16426a5 |
children | 4ae9ac69ab93 |
line wrap: on
line diff
--- 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 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) - { + + 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; } - 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"); - 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_even 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_even 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); - - 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_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) - { + b.last += n; + + if (ngx_quic_input(c, NULL, &b) != 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 - }