# HG changeset patch # User Sergey Kandaurov # Date 1582884591 -10800 # Node ID 53a5cdbe500cdc95afb286f11c170f2692311788 # Parent bd006bd520a9a5d443eb0a6f32da45233763bb84 QUIC add_handshake_data callback, varint routines. diff --git a/auto/modules b/auto/modules --- a/auto/modules +++ b/auto/modules @@ -1245,7 +1245,8 @@ if [ $USE_OPENSSL = YES ]; then ngx_module_deps="src/event/ngx_event_openssl.h \ src/event/ngx_event_quic.h" ngx_module_srcs="src/event/ngx_event_openssl.c - src/event/ngx_event_openssl_stapling.c" + src/event/ngx_event_openssl_stapling.c + src/event/ngx_event_quic.c" ngx_module_libs= ngx_module_link=YES ngx_module_order= diff --git a/src/event/ngx_event_openssl.c b/src/event/ngx_event_openssl.c --- a/src/event/ngx_event_openssl.c +++ b/src/event/ngx_event_openssl.c @@ -362,22 +362,159 @@ static int quic_add_handshake_data(ngx_ssl_conn_t *ssl_conn, enum ssl_encryption_level_t level, const uint8_t *data, size_t len) { - u_char buf[512]; - ngx_int_t m; - ngx_connection_t *c; + u_char buf[512], *p, *cipher, *clear, *ad; + size_t ad_len, clear_len; + ngx_int_t m; + ngx_str_t *server_key, *server_iv, *server_hp; + ngx_connection_t *c; + ngx_quic_connection_t *qc; c = ngx_ssl_get_connection((ngx_ssl_conn_t *) ssl_conn); + qc = c->quic; + + switch (level) { + + case ssl_encryption_initial: + server_key = &qc->server_in_key; + server_iv = &qc->server_in_iv; + server_hp = &qc->server_in_hp; + break; + + case ssl_encryption_handshake: + server_key = &qc->server_hs_key; + server_iv = &qc->server_hs_iv; + server_hp = &qc->server_hs_hp; + break; + + default: + return 0; + } m = ngx_hex_dump(buf, (u_char *) data, ngx_min(len, 256)) - buf; ngx_log_debug5(NGX_LOG_DEBUG_EVENT, c->log, 0, "quic_add_handshake_data: %*s%s, len: %uz, level:%d", m, buf, len < 512 ? "" : "...", len, (int) level); - if (!(SSL_provide_quic_data(ssl_conn, level, data, len))) { - ERR_print_errors_fp(stderr); + clear = ngx_alloc(4 + len + 5 /*minimal ACK*/, c->log); + if (clear == 0) { + return 0; + } + + p = clear; + ngx_quic_build_int(&p, 6); // crypto frame + ngx_quic_build_int(&p, 0); + ngx_quic_build_int(&p, len); + p = ngx_cpymem(p, data, len); + + ngx_quic_build_int(&p, 2); // ack frame + ngx_quic_build_int(&p, 0); + ngx_quic_build_int(&p, 0); + ngx_quic_build_int(&p, 0); + ngx_quic_build_int(&p, 0); + + clear_len = p - clear; + size_t cipher_len = clear_len + 16 /*expansion*/; + + ad = ngx_alloc(346 /*max header*/, c->log); + if (ad == 0) { + return 0; + } + + p = ad; + if (level == ssl_encryption_initial) { + *p++ = 0xc0; // initial, packet number len + } else if (level == ssl_encryption_handshake) { + *p++ = 0xe0; // handshake, packet number len + } + *p++ = 0xff; + *p++ = 0x00; + *p++ = 0x00; + *p++ = 0x17; + *p++ = qc->scid.len; + p = ngx_cpymem(p, qc->scid.data, qc->scid.len); + *p++ = qc->dcid.len; + p = ngx_cpymem(p, qc->dcid.data, qc->dcid.len); + ngx_quic_build_int(&p, 0); // token length + ngx_quic_build_int(&p, cipher_len); // length + u_char *pnp = p; + *p++ = 0; // packet number 0 + + ad_len = p - ad; + + m = ngx_hex_dump(buf, (u_char *) ad, ad_len) - buf; + ngx_log_debug3(NGX_LOG_DEBUG_EVENT, c->log, 0, + "quic_add_handshake_data ad: %*s, len: %uz", + m, buf, ad_len); + + EVP_AEAD_CTX *aead = EVP_AEAD_CTX_new(EVP_aead_aes_128_gcm(), + server_key->data, + server_key->len, + EVP_AEAD_DEFAULT_TAG_LENGTH); + + cipher = ngx_alloc(cipher_len, c->log); + if (cipher == 0) { return 0; } + size_t out_len; + + if (EVP_AEAD_CTX_seal(aead, cipher, &out_len, cipher_len, + server_iv->data, server_iv->len, + clear, clear_len, ad, ad_len) + != 1) + { + EVP_AEAD_CTX_free(aead); + ngx_ssl_error(NGX_LOG_INFO, c->log, 0, + "EVP_AEAD_CTX_seal() failed"); + return 0; + } + + EVP_AEAD_CTX_free(aead); + + EVP_CIPHER_CTX *ctx = EVP_CIPHER_CTX_new(); + u_char *sample = cipher + 3; // pnl=0 + uint8_t mask[16]; + int outlen; + + if (EVP_EncryptInit_ex(ctx, EVP_aes_128_ecb(), NULL, server_hp->data, NULL) + != 1) + { + EVP_CIPHER_CTX_free(ctx); + ngx_ssl_error(NGX_LOG_INFO, c->log, 0, + "EVP_EncryptInit_ex() failed"); + return 0; + } + + if (!EVP_EncryptUpdate(ctx, mask, &outlen, sample, 16)) { + EVP_CIPHER_CTX_free(ctx); + ngx_ssl_error(NGX_LOG_INFO, c->log, 0, + "EVP_EncryptUpdate() failed"); + return 0; + } + + EVP_CIPHER_CTX_free(ctx); + + // header protection, pnl = 0 + ad[0] ^= mask[0] & 0x0f; + *pnp ^= mask[1]; + +printf("cipher_len %ld out_len %ld ad_len %ld\n", cipher_len, out_len, ad_len); + + u_char *packet = ngx_alloc(ad_len + out_len, c->log); + if (packet == 0) { + return 0; + } + + p = ngx_cpymem(packet, ad, ad_len); + p = ngx_cpymem(p, cipher, out_len); + + m = ngx_hex_dump(buf, (u_char *) packet, p - packet) - buf; + ngx_log_debug3(NGX_LOG_DEBUG_EVENT, c->log, 0, + "quic_add_handshake_data packet: %*s, len: %uz", + m, buf, p - packet); + + c->send(c, packet, p - packet); + return 1; } diff --git a/src/event/ngx_event_quic.h b/src/event/ngx_event_quic.h --- a/src/event/ngx_event_quic.h +++ b/src/event/ngx_event_quic.h @@ -8,6 +8,9 @@ #define _NGX_EVENT_QUIC_H_INCLUDED_ +#include + + struct ngx_quic_connection_s { ngx_str_t scid; ngx_str_t dcid; @@ -45,4 +48,9 @@ struct ngx_quic_connection_s { }; +uint64_t ngx_quic_parse_pn(u_char **pos, ngx_int_t len, u_char *mask); +uint64_t ngx_quic_parse_int(u_char **pos); +void ngx_quic_build_int(u_char **pos, uint64_t value); + + #endif /* _NGX_EVENT_QUIC_H_INCLUDED_ */ diff --git a/src/http/ngx_http_request.c b/src/http/ngx_http_request.c --- 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 #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