mirror of
https://github.com/nginx/nginx.git
synced 2024-12-04 22:09:01 +08:00
QUIC: refactored key handling.
All key handling functionality is moved into ngx_quic_protection.c. Public structures from ngx_quic_protection.h are now private and new methods are available to manipulate keys. A negotiated cipher is cached in QUIC connection from the set secret callback to avoid calling SSL_get_current_cipher() on each encrypt/decrypt operation. This also reduces the number of unwanted c->ssl->connection occurrences.
This commit is contained in:
parent
8ed020db75
commit
0aef8438f4
@ -94,9 +94,6 @@ typedef struct {
|
||||
* are also Initial packets.
|
||||
*/
|
||||
typedef struct {
|
||||
ngx_quic_secret_t client_secret;
|
||||
ngx_quic_secret_t server_secret;
|
||||
|
||||
enum ssl_encryption_level_t level;
|
||||
|
||||
uint64_t pnum; /* to be sent */
|
||||
@ -134,10 +131,11 @@ struct ngx_quic_connection_s {
|
||||
ngx_quic_tp_t ctp;
|
||||
|
||||
ngx_quic_send_ctx_t send_ctx[NGX_QUIC_SEND_CTX_LAST];
|
||||
ngx_quic_secrets_t keys[NGX_QUIC_ENCRYPTION_LAST];
|
||||
ngx_quic_secrets_t next_key;
|
||||
|
||||
ngx_quic_frames_stream_t crypto[NGX_QUIC_ENCRYPTION_LAST];
|
||||
|
||||
ngx_quic_keys_t *keys;
|
||||
|
||||
ngx_quic_conf_t *conf;
|
||||
|
||||
ngx_event_t push;
|
||||
@ -643,8 +641,7 @@ ngx_quic_set_read_secret(ngx_ssl_conn_t *ssl_conn,
|
||||
enum ssl_encryption_level_t level, const SSL_CIPHER *cipher,
|
||||
const uint8_t *rsecret, size_t secret_len)
|
||||
{
|
||||
ngx_connection_t *c;
|
||||
ngx_quic_secrets_t *keys;
|
||||
ngx_connection_t *c;
|
||||
|
||||
c = ngx_ssl_get_connection((ngx_ssl_conn_t *) ssl_conn);
|
||||
|
||||
@ -654,11 +651,8 @@ ngx_quic_set_read_secret(ngx_ssl_conn_t *ssl_conn,
|
||||
ngx_quic_hexdump(c->log, "quic read secret", rsecret, secret_len);
|
||||
#endif
|
||||
|
||||
keys = &c->quic->keys[level];
|
||||
|
||||
return ngx_quic_set_encryption_secret(c->pool, ssl_conn, level,
|
||||
rsecret, secret_len,
|
||||
&keys->client);
|
||||
return ngx_quic_keys_set_encryption_secret(c->pool, 0, c->quic->keys, level,
|
||||
cipher, rsecret, secret_len);
|
||||
}
|
||||
|
||||
|
||||
@ -667,8 +661,7 @@ ngx_quic_set_write_secret(ngx_ssl_conn_t *ssl_conn,
|
||||
enum ssl_encryption_level_t level, const SSL_CIPHER *cipher,
|
||||
const uint8_t *wsecret, size_t secret_len)
|
||||
{
|
||||
ngx_connection_t *c;
|
||||
ngx_quic_secrets_t *keys;
|
||||
ngx_connection_t *c;
|
||||
|
||||
c = ngx_ssl_get_connection((ngx_ssl_conn_t *) ssl_conn);
|
||||
|
||||
@ -678,11 +671,8 @@ ngx_quic_set_write_secret(ngx_ssl_conn_t *ssl_conn,
|
||||
ngx_quic_hexdump(c->log, "quic write secret", wsecret, secret_len);
|
||||
#endif
|
||||
|
||||
keys = &c->quic->keys[level];
|
||||
|
||||
return ngx_quic_set_encryption_secret(c->pool, ssl_conn, level,
|
||||
wsecret, secret_len,
|
||||
&keys->server);
|
||||
return ngx_quic_keys_set_encryption_secret(c->pool, 1, c->quic->keys, level,
|
||||
cipher, wsecret, secret_len);
|
||||
}
|
||||
|
||||
#else
|
||||
@ -692,25 +682,24 @@ ngx_quic_set_encryption_secrets(ngx_ssl_conn_t *ssl_conn,
|
||||
enum ssl_encryption_level_t level, const uint8_t *rsecret,
|
||||
const uint8_t *wsecret, size_t secret_len)
|
||||
{
|
||||
ngx_int_t rc;
|
||||
ngx_connection_t *c;
|
||||
ngx_quic_secrets_t *keys;
|
||||
ngx_connection_t *c;
|
||||
const SSL_CIPHER *cipher;
|
||||
|
||||
c = ngx_ssl_get_connection((ngx_ssl_conn_t *) ssl_conn);
|
||||
|
||||
ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0,
|
||||
"quic ngx_quic_set_encryption_secrets() level:%d", level);
|
||||
#ifdef NGX_QUIC_DEBUG_CRYPTO
|
||||
ngx_quic_hexdump(c->log, "quic read", rsecret, secret_len);
|
||||
ngx_quic_hexdump(c->log, "quic read secret", rsecret, secret_len);
|
||||
#endif
|
||||
|
||||
keys = &c->quic->keys[level];
|
||||
cipher = SSL_get_current_cipher(ssl_conn);
|
||||
|
||||
rc = ngx_quic_set_encryption_secret(c->pool, ssl_conn, level,
|
||||
rsecret, secret_len,
|
||||
&keys->client);
|
||||
if (rc != 1) {
|
||||
return rc;
|
||||
if (ngx_quic_keys_set_encryption_secret(c->pool, 0, c->quic->keys, level,
|
||||
cipher, rsecret, secret_len)
|
||||
!= 1)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (level == ssl_encryption_early_data) {
|
||||
@ -718,12 +707,11 @@ ngx_quic_set_encryption_secrets(ngx_ssl_conn_t *ssl_conn,
|
||||
}
|
||||
|
||||
#ifdef NGX_QUIC_DEBUG_CRYPTO
|
||||
ngx_quic_hexdump(c->log, "quic write", wsecret, secret_len);
|
||||
ngx_quic_hexdump(c->log, "quic write secret", wsecret, secret_len);
|
||||
#endif
|
||||
|
||||
return ngx_quic_set_encryption_secret(c->pool, ssl_conn, level,
|
||||
wsecret, secret_len,
|
||||
&keys->server);
|
||||
return ngx_quic_keys_set_encryption_secret(c->pool, 1, c->quic->keys, level,
|
||||
cipher, wsecret, secret_len);
|
||||
}
|
||||
|
||||
#endif
|
||||
@ -965,6 +953,11 @@ ngx_quic_new_connection(ngx_connection_t *c, ngx_quic_conf_t *conf,
|
||||
return NULL;
|
||||
}
|
||||
|
||||
qc->keys = ngx_quic_keys_new(c->pool);
|
||||
if (qc->keys == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ngx_rbtree_init(&qc->streams.tree, &qc->streams.sentinel,
|
||||
ngx_quic_rbtree_insert_stream);
|
||||
|
||||
@ -1239,7 +1232,7 @@ ngx_quic_send_retry(ngx_connection_t *c)
|
||||
|
||||
res.data = buf;
|
||||
|
||||
if (ngx_quic_encrypt(&pkt, NULL, &res) != NGX_OK) {
|
||||
if (ngx_quic_encrypt(&pkt, &res) != NGX_OK) {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
@ -1990,8 +1983,6 @@ ngx_quic_process_packet(ngx_connection_t *c, ngx_quic_conf_t *conf,
|
||||
ngx_quic_header_t *pkt)
|
||||
{
|
||||
ngx_int_t rc;
|
||||
ngx_ssl_conn_t *ssl_conn;
|
||||
ngx_quic_secrets_t *keys, *next, tmp;
|
||||
ngx_quic_send_ctx_t *ctx;
|
||||
ngx_quic_connection_t *qc;
|
||||
|
||||
@ -2135,26 +2126,19 @@ ngx_quic_process_packet(ngx_connection_t *c, ngx_quic_conf_t *conf,
|
||||
|
||||
c->log->action = "decrypting packet";
|
||||
|
||||
keys = &qc->keys[pkt->level];
|
||||
|
||||
if (keys->client.key.len == 0) {
|
||||
if (!ngx_quic_keys_available(qc->keys, pkt->level)) {
|
||||
ngx_log_error(NGX_LOG_INFO, c->log, 0,
|
||||
"quic no level %d keys yet, ignoring packet", pkt->level);
|
||||
return NGX_DECLINED;
|
||||
}
|
||||
|
||||
next = &qc->next_key;
|
||||
|
||||
pkt->secret = &keys->client;
|
||||
pkt->next = &next->client;
|
||||
pkt->keys = qc->keys;
|
||||
pkt->key_phase = qc->key_phase;
|
||||
pkt->plaintext = buf;
|
||||
|
||||
ctx = ngx_quic_get_send_ctx(qc, pkt->level);
|
||||
|
||||
ssl_conn = c->ssl ? c->ssl->connection : NULL;
|
||||
|
||||
rc = ngx_quic_decrypt(pkt, ssl_conn, &ctx->largest_pn);
|
||||
rc = ngx_quic_decrypt(pkt, &ctx->largest_pn);
|
||||
if (rc != NGX_OK) {
|
||||
qc->error = pkt->error;
|
||||
qc->error_reason = "failed to decrypt packet";
|
||||
@ -2190,44 +2174,32 @@ ngx_quic_process_packet(ngx_connection_t *c, ngx_quic_conf_t *conf,
|
||||
return ngx_quic_payload_handler(c, pkt);
|
||||
}
|
||||
|
||||
/* switch keys on Key Phase change */
|
||||
|
||||
if (pkt->key_update) {
|
||||
qc->key_phase ^= 1;
|
||||
|
||||
tmp = *keys;
|
||||
*keys = *next;
|
||||
*next = tmp;
|
||||
if (!pkt->key_update) {
|
||||
return ngx_quic_payload_handler(c, pkt);
|
||||
}
|
||||
|
||||
/* switch keys and generate next on Key Phase change */
|
||||
|
||||
qc->key_phase ^= 1;
|
||||
ngx_quic_keys_switch(c, qc->keys);
|
||||
|
||||
rc = ngx_quic_payload_handler(c, pkt);
|
||||
if (rc != NGX_OK) {
|
||||
return rc;
|
||||
}
|
||||
|
||||
/* generate next keys */
|
||||
|
||||
if (pkt->key_update) {
|
||||
if (ngx_quic_key_update(c, keys, next) != NGX_OK) {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
return NGX_OK;
|
||||
return ngx_quic_keys_update(c, qc->keys);
|
||||
}
|
||||
|
||||
|
||||
static ngx_int_t
|
||||
ngx_quic_init_secrets(ngx_connection_t *c)
|
||||
{
|
||||
ngx_quic_secrets_t *keys;
|
||||
ngx_quic_connection_t *qc;
|
||||
|
||||
qc =c->quic;
|
||||
keys = &qc->keys[ssl_encryption_initial];
|
||||
qc = c->quic;
|
||||
|
||||
if (ngx_quic_set_initial_secret(c->pool, &keys->client, &keys->server,
|
||||
&qc->odcid)
|
||||
if (ngx_quic_keys_set_initial_secret(c->pool, qc->keys, &qc->odcid)
|
||||
!= NGX_OK)
|
||||
{
|
||||
return NGX_ERROR;
|
||||
@ -2249,11 +2221,12 @@ ngx_quic_discard_ctx(ngx_connection_t *c, enum ssl_encryption_level_t level)
|
||||
|
||||
qc = c->quic;
|
||||
|
||||
if (qc->keys[level].client.key.len == 0) {
|
||||
if (!ngx_quic_keys_available(qc->keys, level)) {
|
||||
return;
|
||||
}
|
||||
|
||||
qc->keys[level].client.key.len = 0;
|
||||
ngx_quic_keys_discard(qc->keys, level);
|
||||
|
||||
qc->pto_count = 0;
|
||||
|
||||
ctx = ngx_quic_get_send_ctx(qc, level);
|
||||
@ -3634,10 +3607,7 @@ ngx_quic_crypto_input(ngx_connection_t *c, ngx_quic_frame_t *frame, void *data)
|
||||
* See quic-tls 9.4 Header Protection Timing Side-Channels.
|
||||
*/
|
||||
|
||||
if (ngx_quic_key_update(c, &c->quic->keys[ssl_encryption_application],
|
||||
&c->quic->next_key)
|
||||
!= NGX_OK)
|
||||
{
|
||||
if (ngx_quic_keys_update(c, c->quic->keys) != NGX_OK) {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
@ -4503,10 +4473,8 @@ ngx_quic_send_frames(ngx_connection_t *c, ngx_quic_send_ctx_t *ctx,
|
||||
ngx_str_t out, res;
|
||||
ngx_msec_t now;
|
||||
ngx_queue_t *q;
|
||||
ngx_ssl_conn_t *ssl_conn;
|
||||
ngx_quic_frame_t *f, *start;
|
||||
ngx_quic_header_t pkt;
|
||||
ngx_quic_secrets_t *keys;
|
||||
ngx_quic_connection_t *qc;
|
||||
static u_char src[NGX_QUIC_MAX_UDP_PAYLOAD_SIZE];
|
||||
static u_char dst[NGX_QUIC_MAX_UDP_PAYLOAD_SIZE];
|
||||
@ -4514,8 +4482,6 @@ ngx_quic_send_frames(ngx_connection_t *c, ngx_quic_send_ctx_t *ctx,
|
||||
ngx_log_debug0(NGX_LOG_DEBUG_EVENT, c->log, 0,
|
||||
"quic ngx_quic_send_frames");
|
||||
|
||||
ssl_conn = c->ssl ? c->ssl->connection : NULL;
|
||||
|
||||
q = ngx_queue_head(frames);
|
||||
start = ngx_queue_data(q, ngx_quic_frame_t, queue);
|
||||
|
||||
@ -4554,9 +4520,7 @@ ngx_quic_send_frames(ngx_connection_t *c, ngx_quic_send_ctx_t *ctx,
|
||||
|
||||
qc = c->quic;
|
||||
|
||||
keys = &c->quic->keys[start->level];
|
||||
|
||||
pkt.secret = &keys->server;
|
||||
pkt.keys = qc->keys;
|
||||
|
||||
pkt.flags = NGX_QUIC_PKT_FIXED_BIT;
|
||||
|
||||
@ -4603,7 +4567,7 @@ ngx_quic_send_frames(ngx_connection_t *c, ngx_quic_send_ctx_t *ctx,
|
||||
ngx_quic_level_name(start->level), out.len, pkt.need_ack,
|
||||
pkt.number, pkt.num_len, pkt.trunc);
|
||||
|
||||
if (ngx_quic_encrypt(&pkt, ssl_conn, &res) != NGX_OK) {
|
||||
if (ngx_quic_encrypt(&pkt, &res) != NGX_OK) {
|
||||
ngx_quic_free_frames(c, frames);
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
@ -116,6 +116,9 @@ struct ngx_quic_stream_s {
|
||||
};
|
||||
|
||||
|
||||
typedef struct ngx_quic_keys_s ngx_quic_keys_t;
|
||||
|
||||
|
||||
void ngx_quic_run(ngx_connection_t *c, ngx_quic_conf_t *conf);
|
||||
ngx_connection_t *ngx_quic_open_stream(ngx_connection_t *c, ngx_uint_t bidi);
|
||||
void ngx_quic_finalize_connection(ngx_connection_t *c, ngx_uint_t err,
|
||||
|
@ -24,6 +24,7 @@
|
||||
#define ngx_quic_cipher_t EVP_CIPHER
|
||||
#endif
|
||||
|
||||
|
||||
typedef struct {
|
||||
const ngx_quic_cipher_t *c;
|
||||
const EVP_CIPHER *hp;
|
||||
@ -31,6 +32,27 @@ typedef struct {
|
||||
} ngx_quic_ciphers_t;
|
||||
|
||||
|
||||
typedef struct ngx_quic_secret_s {
|
||||
ngx_str_t secret;
|
||||
ngx_str_t key;
|
||||
ngx_str_t iv;
|
||||
ngx_str_t hp;
|
||||
} ngx_quic_secret_t;
|
||||
|
||||
|
||||
typedef struct {
|
||||
ngx_quic_secret_t client;
|
||||
ngx_quic_secret_t server;
|
||||
} ngx_quic_secrets_t;
|
||||
|
||||
|
||||
struct ngx_quic_keys_s {
|
||||
ngx_quic_secrets_t secrets[NGX_QUIC_ENCRYPTION_LAST];
|
||||
ngx_quic_secrets_t next_key;
|
||||
ngx_uint_t cipher;
|
||||
};
|
||||
|
||||
|
||||
static ngx_int_t ngx_hkdf_expand(u_char *out_key, size_t out_len,
|
||||
const EVP_MD *digest, const u_char *prk, size_t prk_len,
|
||||
const u_char *info, size_t info_len);
|
||||
@ -41,7 +63,7 @@ static ngx_int_t ngx_hkdf_extract(u_char *out_key, size_t *out_len,
|
||||
static uint64_t ngx_quic_parse_pn(u_char **pos, ngx_int_t len, u_char *mask,
|
||||
uint64_t *largest_pn);
|
||||
static void ngx_quic_compute_nonce(u_char *nonce, size_t len, uint64_t pn);
|
||||
static ngx_int_t ngx_quic_ciphers(ngx_ssl_conn_t *ssl_conn,
|
||||
static ngx_int_t ngx_quic_ciphers(ngx_uint_t id,
|
||||
ngx_quic_ciphers_t *ciphers, enum ssl_encryption_level_t level);
|
||||
|
||||
static ngx_int_t ngx_quic_tls_open(const ngx_quic_cipher_t *cipher,
|
||||
@ -56,30 +78,21 @@ static ngx_int_t ngx_quic_hkdf_expand(ngx_pool_t *pool, const EVP_MD *digest,
|
||||
ngx_str_t *out, ngx_str_t *label, const uint8_t *prk, size_t prk_len);
|
||||
|
||||
static ngx_int_t ngx_quic_create_long_packet(ngx_quic_header_t *pkt,
|
||||
ngx_ssl_conn_t *ssl_conn, ngx_str_t *res);
|
||||
ngx_str_t *res);
|
||||
static ngx_int_t ngx_quic_create_short_packet(ngx_quic_header_t *pkt,
|
||||
ngx_ssl_conn_t *ssl_conn, ngx_str_t *res);
|
||||
ngx_str_t *res);
|
||||
static ngx_int_t ngx_quic_create_retry_packet(ngx_quic_header_t *pkt,
|
||||
ngx_str_t *res);
|
||||
|
||||
|
||||
static ngx_int_t
|
||||
ngx_quic_ciphers(ngx_ssl_conn_t *ssl_conn, ngx_quic_ciphers_t *ciphers,
|
||||
ngx_quic_ciphers(ngx_uint_t id, ngx_quic_ciphers_t *ciphers,
|
||||
enum ssl_encryption_level_t level)
|
||||
{
|
||||
ngx_int_t id, len;
|
||||
const SSL_CIPHER *cipher;
|
||||
ngx_int_t len;
|
||||
|
||||
if (level == ssl_encryption_initial) {
|
||||
id = NGX_AES_128_GCM_SHA256;
|
||||
|
||||
} else {
|
||||
cipher = SSL_get_current_cipher(ssl_conn);
|
||||
if (cipher == NULL) {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
id = SSL_CIPHER_get_id(cipher) & 0xffff;
|
||||
}
|
||||
|
||||
switch (id) {
|
||||
@ -130,14 +143,15 @@ ngx_quic_ciphers(ngx_ssl_conn_t *ssl_conn, ngx_quic_ciphers_t *ciphers,
|
||||
|
||||
|
||||
ngx_int_t
|
||||
ngx_quic_set_initial_secret(ngx_pool_t *pool, ngx_quic_secret_t *client,
|
||||
ngx_quic_secret_t *server, ngx_str_t *secret)
|
||||
ngx_quic_keys_set_initial_secret(ngx_pool_t *pool, ngx_quic_keys_t *keys,
|
||||
ngx_str_t *secret)
|
||||
{
|
||||
size_t is_len;
|
||||
uint8_t is[SHA256_DIGEST_LENGTH];
|
||||
ngx_uint_t i;
|
||||
const EVP_MD *digest;
|
||||
const EVP_CIPHER *cipher;
|
||||
size_t is_len;
|
||||
uint8_t is[SHA256_DIGEST_LENGTH];
|
||||
ngx_uint_t i;
|
||||
const EVP_MD *digest;
|
||||
const EVP_CIPHER *cipher;
|
||||
ngx_quic_secret_t *client, *server;
|
||||
|
||||
static const uint8_t salt[20] =
|
||||
#if (NGX_QUIC_DRAFT_VERSION >= 29)
|
||||
@ -148,6 +162,9 @@ ngx_quic_set_initial_secret(ngx_pool_t *pool, ngx_quic_secret_t *client,
|
||||
"\xd2\x43\x2b\xb4\x63\x65\xbe\xf9\xf5\x02";
|
||||
#endif
|
||||
|
||||
client = &keys->secrets[ssl_encryption_initial].client;
|
||||
server = &keys->secrets[ssl_encryption_initial].server;
|
||||
|
||||
/* AEAD_AES_128_GCM prior to handshake, quic-tls-23#section-5.3 */
|
||||
|
||||
cipher = EVP_aes_128_gcm();
|
||||
@ -626,16 +643,25 @@ failed:
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
ngx_quic_set_encryption_secret(ngx_pool_t *pool, ngx_ssl_conn_t *ssl_conn,
|
||||
enum ssl_encryption_level_t level, const uint8_t *secret,
|
||||
size_t secret_len, ngx_quic_secret_t *peer_secret)
|
||||
int ngx_quic_keys_set_encryption_secret(ngx_pool_t *pool, ngx_uint_t is_write,
|
||||
ngx_quic_keys_t *keys, enum ssl_encryption_level_t level,
|
||||
const SSL_CIPHER *cipher, const uint8_t *secret, size_t secret_len)
|
||||
{
|
||||
ngx_int_t key_len;
|
||||
ngx_uint_t i;
|
||||
ngx_quic_ciphers_t ciphers;
|
||||
ngx_int_t key_len;
|
||||
ngx_uint_t i;
|
||||
ngx_quic_secret_t *peer_secret;
|
||||
ngx_quic_ciphers_t ciphers;
|
||||
|
||||
key_len = ngx_quic_ciphers(ssl_conn, &ciphers, level);
|
||||
peer_secret = is_write ? &keys->secrets[level].server
|
||||
: &keys->secrets[level].client;
|
||||
|
||||
/*
|
||||
* SSL_CIPHER_get_protocol_id() is not universally available,
|
||||
* casting to uint16_t works for both OpenSSL and BoringSSL
|
||||
*/
|
||||
keys->cipher = (uint16_t) SSL_CIPHER_get_id(cipher);
|
||||
|
||||
key_len = ngx_quic_ciphers(keys->cipher, &ciphers, level);
|
||||
|
||||
if (key_len == NGX_ERROR) {
|
||||
ngx_ssl_error(NGX_LOG_INFO, pool->log, 0, "unexpected cipher");
|
||||
@ -682,17 +708,56 @@ ngx_quic_set_encryption_secret(ngx_pool_t *pool, ngx_ssl_conn_t *ssl_conn,
|
||||
}
|
||||
|
||||
|
||||
ngx_int_t
|
||||
ngx_quic_key_update(ngx_connection_t *c, ngx_quic_secrets_t *current,
|
||||
ngx_quic_secrets_t *next)
|
||||
ngx_quic_keys_t *
|
||||
ngx_quic_keys_new(ngx_pool_t *pool)
|
||||
{
|
||||
ngx_uint_t i;
|
||||
ngx_quic_ciphers_t ciphers;
|
||||
return ngx_pcalloc(pool, sizeof(ngx_quic_keys_t));
|
||||
}
|
||||
|
||||
|
||||
ngx_uint_t
|
||||
ngx_quic_keys_available(ngx_quic_keys_t *keys,
|
||||
enum ssl_encryption_level_t level)
|
||||
{
|
||||
return keys->secrets[level].client.key.len != 0;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
ngx_quic_keys_discard(ngx_quic_keys_t *keys,
|
||||
enum ssl_encryption_level_t level)
|
||||
{
|
||||
keys->secrets[level].client.key.len = 0;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
ngx_quic_keys_switch(ngx_connection_t *c, ngx_quic_keys_t *keys)
|
||||
{
|
||||
ngx_quic_secrets_t *current, *next, tmp;
|
||||
|
||||
current = &keys->secrets[ssl_encryption_application];
|
||||
next = &keys->next_key;
|
||||
|
||||
tmp = *current;
|
||||
*current = *next;
|
||||
*next = tmp;
|
||||
}
|
||||
|
||||
|
||||
ngx_int_t
|
||||
ngx_quic_keys_update(ngx_connection_t *c, ngx_quic_keys_t *keys)
|
||||
{
|
||||
ngx_uint_t i;
|
||||
ngx_quic_ciphers_t ciphers;
|
||||
ngx_quic_secrets_t *current, *next;
|
||||
|
||||
current = &keys->secrets[ssl_encryption_application];
|
||||
next = &keys->next_key;
|
||||
|
||||
ngx_log_debug0(NGX_LOG_DEBUG_EVENT, c->log, 0, "quic key update");
|
||||
|
||||
if (ngx_quic_ciphers(c->ssl->connection, &ciphers,
|
||||
ssl_encryption_application)
|
||||
if (ngx_quic_ciphers(keys->cipher, &ciphers, ssl_encryption_application)
|
||||
== NGX_ERROR)
|
||||
{
|
||||
return NGX_ERROR;
|
||||
@ -760,12 +825,12 @@ ngx_quic_key_update(ngx_connection_t *c, ngx_quic_secrets_t *current,
|
||||
|
||||
|
||||
static ngx_int_t
|
||||
ngx_quic_create_long_packet(ngx_quic_header_t *pkt, ngx_ssl_conn_t *ssl_conn,
|
||||
ngx_str_t *res)
|
||||
ngx_quic_create_long_packet(ngx_quic_header_t *pkt, ngx_str_t *res)
|
||||
{
|
||||
u_char *pnp, *sample;
|
||||
ngx_str_t ad, out;
|
||||
ngx_uint_t i;
|
||||
ngx_quic_secret_t *secret;
|
||||
ngx_quic_ciphers_t ciphers;
|
||||
u_char nonce[12], mask[16];
|
||||
|
||||
@ -780,14 +845,17 @@ ngx_quic_create_long_packet(ngx_quic_header_t *pkt, ngx_ssl_conn_t *ssl_conn,
|
||||
ngx_quic_hexdump(pkt->log, "quic ad", ad.data, ad.len);
|
||||
#endif
|
||||
|
||||
if (ngx_quic_ciphers(ssl_conn, &ciphers, pkt->level) == NGX_ERROR) {
|
||||
if (ngx_quic_ciphers(pkt->keys->cipher, &ciphers, pkt->level) == NGX_ERROR)
|
||||
{
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
ngx_memcpy(nonce, pkt->secret->iv.data, pkt->secret->iv.len);
|
||||
secret = &pkt->keys->secrets[pkt->level].server;
|
||||
|
||||
ngx_memcpy(nonce, secret->iv.data, secret->iv.len);
|
||||
ngx_quic_compute_nonce(nonce, sizeof(nonce), pkt->number);
|
||||
|
||||
if (ngx_quic_tls_seal(ciphers.c, pkt->secret, &out,
|
||||
if (ngx_quic_tls_seal(ciphers.c, secret, &out,
|
||||
nonce, &pkt->payload, &ad, pkt->log)
|
||||
!= NGX_OK)
|
||||
{
|
||||
@ -795,7 +863,7 @@ ngx_quic_create_long_packet(ngx_quic_header_t *pkt, ngx_ssl_conn_t *ssl_conn,
|
||||
}
|
||||
|
||||
sample = &out.data[4 - pkt->num_len];
|
||||
if (ngx_quic_tls_hp(pkt->log, ciphers.hp, pkt->secret, mask, sample)
|
||||
if (ngx_quic_tls_hp(pkt->log, ciphers.hp, secret, mask, sample)
|
||||
!= NGX_OK)
|
||||
{
|
||||
return NGX_ERROR;
|
||||
@ -815,12 +883,12 @@ ngx_quic_create_long_packet(ngx_quic_header_t *pkt, ngx_ssl_conn_t *ssl_conn,
|
||||
|
||||
|
||||
static ngx_int_t
|
||||
ngx_quic_create_short_packet(ngx_quic_header_t *pkt, ngx_ssl_conn_t *ssl_conn,
|
||||
ngx_str_t *res)
|
||||
ngx_quic_create_short_packet(ngx_quic_header_t *pkt, ngx_str_t *res)
|
||||
{
|
||||
u_char *pnp, *sample;
|
||||
ngx_str_t ad, out;
|
||||
ngx_uint_t i;
|
||||
ngx_quic_secret_t *secret;
|
||||
ngx_quic_ciphers_t ciphers;
|
||||
u_char nonce[12], mask[16];
|
||||
|
||||
@ -835,14 +903,17 @@ ngx_quic_create_short_packet(ngx_quic_header_t *pkt, ngx_ssl_conn_t *ssl_conn,
|
||||
ngx_quic_hexdump(pkt->log, "quic ad", ad.data, ad.len);
|
||||
#endif
|
||||
|
||||
if (ngx_quic_ciphers(ssl_conn, &ciphers, pkt->level) == NGX_ERROR) {
|
||||
if (ngx_quic_ciphers(pkt->keys->cipher, &ciphers, pkt->level) == NGX_ERROR)
|
||||
{
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
ngx_memcpy(nonce, pkt->secret->iv.data, pkt->secret->iv.len);
|
||||
secret = &pkt->keys->secrets[pkt->level].server;
|
||||
|
||||
ngx_memcpy(nonce, secret->iv.data, secret->iv.len);
|
||||
ngx_quic_compute_nonce(nonce, sizeof(nonce), pkt->number);
|
||||
|
||||
if (ngx_quic_tls_seal(ciphers.c, pkt->secret, &out,
|
||||
if (ngx_quic_tls_seal(ciphers.c, secret, &out,
|
||||
nonce, &pkt->payload, &ad, pkt->log)
|
||||
!= NGX_OK)
|
||||
{
|
||||
@ -850,7 +921,7 @@ ngx_quic_create_short_packet(ngx_quic_header_t *pkt, ngx_ssl_conn_t *ssl_conn,
|
||||
}
|
||||
|
||||
sample = &out.data[4 - pkt->num_len];
|
||||
if (ngx_quic_tls_hp(pkt->log, ciphers.hp, pkt->secret, mask, sample)
|
||||
if (ngx_quic_tls_hp(pkt->log, ciphers.hp, secret, mask, sample)
|
||||
!= NGX_OK)
|
||||
{
|
||||
return NGX_ERROR;
|
||||
@ -902,7 +973,7 @@ ngx_quic_create_retry_packet(ngx_quic_header_t *pkt, ngx_str_t *res)
|
||||
ngx_quic_hexdump(pkt->log, "quic retry itag", ad.data, ad.len);
|
||||
#endif
|
||||
|
||||
if (ngx_quic_ciphers(NULL, &ciphers, pkt->level) == NGX_ERROR) {
|
||||
if (ngx_quic_ciphers(0, &ciphers, pkt->level) == NGX_ERROR) {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
@ -1033,24 +1104,22 @@ ngx_quic_compute_nonce(u_char *nonce, size_t len, uint64_t pn)
|
||||
|
||||
|
||||
ngx_int_t
|
||||
ngx_quic_encrypt(ngx_quic_header_t *pkt, ngx_ssl_conn_t *ssl_conn,
|
||||
ngx_str_t *res)
|
||||
ngx_quic_encrypt(ngx_quic_header_t *pkt, ngx_str_t *res)
|
||||
{
|
||||
if (ngx_quic_short_pkt(pkt->flags)) {
|
||||
return ngx_quic_create_short_packet(pkt, ssl_conn, res);
|
||||
return ngx_quic_create_short_packet(pkt, res);
|
||||
}
|
||||
|
||||
if (ngx_quic_pkt_retry(pkt->flags)) {
|
||||
return ngx_quic_create_retry_packet(pkt, res);
|
||||
}
|
||||
|
||||
return ngx_quic_create_long_packet(pkt, ssl_conn, res);
|
||||
return ngx_quic_create_long_packet(pkt, res);
|
||||
}
|
||||
|
||||
|
||||
ngx_int_t
|
||||
ngx_quic_decrypt(ngx_quic_header_t *pkt, ngx_ssl_conn_t *ssl_conn,
|
||||
uint64_t *largest_pn)
|
||||
ngx_quic_decrypt(ngx_quic_header_t *pkt, uint64_t *largest_pn)
|
||||
{
|
||||
u_char clearflags, *p, *sample;
|
||||
size_t len;
|
||||
@ -1062,11 +1131,12 @@ ngx_quic_decrypt(ngx_quic_header_t *pkt, ngx_ssl_conn_t *ssl_conn,
|
||||
ngx_quic_ciphers_t ciphers;
|
||||
uint8_t mask[16], nonce[12];
|
||||
|
||||
if (ngx_quic_ciphers(ssl_conn, &ciphers, pkt->level) == NGX_ERROR) {
|
||||
if (ngx_quic_ciphers(pkt->keys->cipher, &ciphers, pkt->level) == NGX_ERROR)
|
||||
{
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
secret = pkt->secret;
|
||||
secret = &pkt->keys->secrets[pkt->level].client;
|
||||
|
||||
p = pkt->raw->pos;
|
||||
len = pkt->data + pkt->len - p;
|
||||
@ -1099,7 +1169,7 @@ ngx_quic_decrypt(ngx_quic_header_t *pkt, ngx_ssl_conn_t *ssl_conn,
|
||||
key_phase = (clearflags & NGX_QUIC_PKT_KPHASE) != 0;
|
||||
|
||||
if (key_phase != pkt->key_phase) {
|
||||
secret = pkt->next;
|
||||
secret = &pkt->keys->next_key.client;
|
||||
pkt->key_update = 1;
|
||||
}
|
||||
}
|
||||
|
@ -15,37 +15,24 @@
|
||||
#define NGX_QUIC_ENCRYPTION_LAST ((ssl_encryption_application) + 1)
|
||||
|
||||
|
||||
typedef struct ngx_quic_secret_s {
|
||||
ngx_str_t secret;
|
||||
ngx_str_t key;
|
||||
ngx_str_t iv;
|
||||
ngx_str_t hp;
|
||||
} ngx_quic_secret_t;
|
||||
ngx_quic_keys_t *ngx_quic_keys_new(ngx_pool_t *pool);
|
||||
ngx_int_t ngx_quic_keys_set_initial_secret(ngx_pool_t *pool,
|
||||
ngx_quic_keys_t *keys, ngx_str_t *secret);
|
||||
int ngx_quic_keys_set_encryption_secret(ngx_pool_t *pool, ngx_uint_t is_write,
|
||||
ngx_quic_keys_t *keys, enum ssl_encryption_level_t level,
|
||||
const SSL_CIPHER *cipher, const uint8_t *secret, size_t secret_len);
|
||||
ngx_uint_t ngx_quic_keys_available(ngx_quic_keys_t *keys,
|
||||
enum ssl_encryption_level_t level);
|
||||
void ngx_quic_keys_discard(ngx_quic_keys_t *keys,
|
||||
enum ssl_encryption_level_t level);
|
||||
void ngx_quic_keys_switch(ngx_connection_t *c, ngx_quic_keys_t *keys);
|
||||
ngx_int_t ngx_quic_keys_update(ngx_connection_t *c, ngx_quic_keys_t *keys);
|
||||
|
||||
|
||||
typedef struct {
|
||||
ngx_quic_secret_t client;
|
||||
ngx_quic_secret_t server;
|
||||
} ngx_quic_secrets_t;
|
||||
|
||||
|
||||
ngx_int_t ngx_quic_set_initial_secret(ngx_pool_t *pool,
|
||||
ngx_quic_secret_t *client, ngx_quic_secret_t *server,
|
||||
ngx_str_t *secret);
|
||||
|
||||
int ngx_quic_set_encryption_secret(ngx_pool_t *pool, ngx_ssl_conn_t *ssl_conn,
|
||||
enum ssl_encryption_level_t level, const uint8_t *secret, size_t secret_len,
|
||||
ngx_quic_secret_t *peer_secret);
|
||||
|
||||
ngx_int_t ngx_quic_key_update(ngx_connection_t *c,
|
||||
ngx_quic_secrets_t *current, ngx_quic_secrets_t *next);
|
||||
ngx_int_t ngx_quic_new_sr_token(ngx_connection_t *c, ngx_str_t *cid,
|
||||
ngx_str_t *key, u_char *token);
|
||||
|
||||
ngx_int_t ngx_quic_encrypt(ngx_quic_header_t *pkt, ngx_ssl_conn_t *ssl_conn,
|
||||
ngx_str_t *res);
|
||||
ngx_int_t ngx_quic_decrypt(ngx_quic_header_t *pkt, ngx_ssl_conn_t *ssl_conn,
|
||||
uint64_t *largest_pn);
|
||||
ngx_int_t ngx_quic_encrypt(ngx_quic_header_t *pkt, ngx_str_t *res);
|
||||
ngx_int_t ngx_quic_decrypt(ngx_quic_header_t *pkt, uint64_t *largest_pn);
|
||||
|
||||
|
||||
#endif /* _NGX_EVENT_QUIC_PROTECTION_H_INCLUDED_ */
|
||||
|
@ -290,8 +290,8 @@ struct ngx_quic_frame_s {
|
||||
typedef struct {
|
||||
ngx_log_t *log;
|
||||
|
||||
struct ngx_quic_secret_s *secret;
|
||||
struct ngx_quic_secret_s *next;
|
||||
ngx_quic_keys_t *keys;
|
||||
|
||||
ngx_msec_t received;
|
||||
uint64_t number;
|
||||
uint8_t num_len;
|
||||
|
Loading…
Reference in New Issue
Block a user