changeset 8306:058a5af7ddfc quic

Refactored QUIC secrets storage. The quic->keys[4] array now contains secrets related to the corresponding encryption level. All protection-level functions get proper keys and do not need to switch manually between levels.
author Vladimir Homutov <vl@nginx.com>
date Wed, 01 Apr 2020 14:25:25 +0300
parents e35f824f644d
children dc7ac778aafe
files src/event/ngx_event_quic.c src/event/ngx_event_quic_protection.c src/event/ngx_event_quic_protection.h
diffstat 3 files changed, 87 insertions(+), 85 deletions(-) [+]
line wrap: on
line diff
--- a/src/event/ngx_event_quic.c
+++ b/src/event/ngx_event_quic.c
@@ -42,7 +42,9 @@ struct ngx_quic_connection_s {
     ngx_uint_t                        handshake_pn;
     ngx_uint_t                        appdata_pn;
 
-    ngx_quic_secrets_t                secrets;
+    ngx_quic_secrets_t                keys[NGX_QUIC_ENCRYPTION_LAST];
+    uint64_t                          crypto_offset[NGX_QUIC_ENCRYPTION_LAST];
+
     ngx_ssl_t                        *ssl;
     ngx_quic_frame_t                 *frames;
     ngx_quic_frame_t                 *free_frames;
@@ -56,9 +58,6 @@ struct ngx_quic_connection_s {
 
     unsigned                          send_timer_set:1;
     unsigned                          closing:1;
-
-#define SSL_ECRYPTION_LAST ((ssl_encryption_application) + 1)
-    uint64_t                          crypto_offset[SSL_ECRYPTION_LAST];
 };
 
 
@@ -156,20 +155,23 @@ ngx_quic_set_read_secret(ngx_ssl_conn_t 
     enum ssl_encryption_level_t level, const SSL_CIPHER *cipher,
     const uint8_t *rsecret, size_t secret_len)
 {
-    ngx_connection_t  *c;
+    ngx_connection_t    *c;
+    ngx_quic_secrets_t  *keys;
 
     c = ngx_ssl_get_connection((ngx_ssl_conn_t *) ssl_conn);
 
     ngx_quic_hexdump(c->log, "level:%d read secret",
                      rsecret, secret_len, level);
 
+    keys = &c->quic->keys[level];
+
     if (level == ssl_encryption_early_data) {
         c->quic->state = NGX_QUIC_ST_EARLY_DATA;
     }
 
     return ngx_quic_set_encryption_secret(c->pool, ssl_conn, level,
                                           rsecret, secret_len,
-                                          &c->quic->secrets.client);
+                                          &keys->client);
 }
 
 
@@ -178,16 +180,19 @@ ngx_quic_set_write_secret(ngx_ssl_conn_t
     enum ssl_encryption_level_t level, const SSL_CIPHER *cipher,
     const uint8_t *wsecret, size_t secret_len)
 {
-    ngx_connection_t  *c;
+    ngx_connection_t    *c;
+    ngx_quic_secrets_t  *keys;
 
     c = ngx_ssl_get_connection((ngx_ssl_conn_t *) ssl_conn);
 
     ngx_quic_hexdump(c->log, "level:%d write secret",
                      wsecret, secret_len, level);
 
+    keys = &c->quic->keys[level];
+
     return ngx_quic_set_encryption_secret(c->pool, ssl_conn, level,
                                           wsecret, secret_len,
-                                          &c->quic->secrets.server);
+                                          &keys->server);
 }
 
 #else
@@ -197,16 +202,19 @@ ngx_quic_set_encryption_secrets(ngx_ssl_
     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_int_t            rc;
+    ngx_connection_t    *c;
+    ngx_quic_secrets_t  *keys;
 
     c = ngx_ssl_get_connection((ngx_ssl_conn_t *) ssl_conn);
 
     ngx_quic_hexdump(c->log, "level:%d read", rsecret, secret_len, level);
 
+    keys = &c->quic->secrets[level];
+
     rc = ngx_quic_set_encryption_secret(c->pool, ssl_conn, level,
                                         rsecret, secret_len,
-                                        &c->quic->secrets.client);
+                                        &keys->client);
     if (rc != 1) {
         return rc;
     }
@@ -220,7 +228,7 @@ ngx_quic_set_encryption_secrets(ngx_ssl_
 
     return ngx_quic_set_encryption_secret(c->pool, ssl_conn, level,
                                           wsecret, secret_len,
-                                          &c->quic->secrets.server);
+                                          &keys->server);
 }
 
 #endif
@@ -380,6 +388,7 @@ ngx_quic_new_connection(ngx_connection_t
     ngx_quic_header_t *pkt, ngx_connection_handler_pt handler)
 {
     ngx_quic_tp_t          *ctp;
+    ngx_quic_secrets_t     *keys;
     ngx_quic_connection_t  *qc;
     static u_char           buf[NGX_QUIC_DEFAULT_MAX_PACKET_SIZE];
 
@@ -445,14 +454,16 @@ ngx_quic_new_connection(ngx_connection_t
     }
     ngx_memcpy(qc->token.data, pkt->token.data, qc->token.len);
 
+    keys = &c->quic->keys[ssl_encryption_initial];
 
-    if (ngx_quic_set_initial_secret(c->pool, &qc->secrets, &qc->dcid)
+    if (ngx_quic_set_initial_secret(c->pool, &keys->client, &keys->server,
+                                    &qc->dcid)
         != NGX_OK)
     {
         return NGX_ERROR;
     }
 
-    pkt->secret = &qc->secrets.client.in;
+    pkt->secret = &keys->client;
     pkt->level = ssl_encryption_initial;
     pkt->plaintext = buf;
 
@@ -743,13 +754,12 @@ ngx_quic_input(ngx_connection_t *c, ngx_
 static ngx_int_t
 ngx_quic_initial_input(ngx_connection_t *c, ngx_quic_header_t *pkt)
 {
-    ngx_ssl_conn_t         *ssl_conn;
-    ngx_quic_connection_t  *qc;
-    static u_char           buf[NGX_QUIC_DEFAULT_MAX_PACKET_SIZE];
+    ngx_ssl_conn_t      *ssl_conn;
+    ngx_quic_secrets_t  *keys;
+    static u_char        buf[NGX_QUIC_DEFAULT_MAX_PACKET_SIZE];
 
     c->log->action = "processing initial quic packet";
 
-    qc = c->quic;
     ssl_conn = c->ssl->connection;
 
     if (ngx_quic_parse_long_header(pkt) != NGX_OK) {
@@ -760,7 +770,9 @@ ngx_quic_initial_input(ngx_connection_t 
         return NGX_ERROR;
     }
 
-    pkt->secret = &qc->secrets.client.in;
+    keys = &c->quic->keys[ssl_encryption_initial];
+
+    pkt->secret = &keys->client;
     pkt->level = ssl_encryption_initial;
     pkt->plaintext = buf;
 
@@ -775,6 +787,7 @@ ngx_quic_initial_input(ngx_connection_t 
 static ngx_int_t
 ngx_quic_handshake_input(ngx_connection_t *c, ngx_quic_header_t *pkt)
 {
+    ngx_quic_secrets_t     *keys;
     ngx_quic_connection_t  *qc;
     static u_char           buf[NGX_QUIC_DEFAULT_MAX_PACKET_SIZE];
 
@@ -817,7 +830,9 @@ ngx_quic_handshake_input(ngx_connection_
         return NGX_ERROR;
     }
 
-    pkt->secret = &qc->secrets.client.hs;
+    keys = &c->quic->keys[ssl_encryption_handshake];
+
+    pkt->secret = &keys->client;
     pkt->level = ssl_encryption_handshake;
     pkt->plaintext = buf;
 
@@ -832,6 +847,7 @@ ngx_quic_handshake_input(ngx_connection_
 static ngx_int_t
 ngx_quic_early_input(ngx_connection_t *c, ngx_quic_header_t *pkt)
 {
+    ngx_quic_secrets_t     *keys;
     ngx_quic_connection_t  *qc;
     static u_char           buf[NGX_QUIC_DEFAULT_MAX_PACKET_SIZE];
 
@@ -879,7 +895,9 @@ ngx_quic_early_input(ngx_connection_t *c
         return NGX_OK;
     }
 
-    pkt->secret = &qc->secrets.client.ed;
+    keys = &c->quic->keys[ssl_encryption_early_data];
+
+    pkt->secret = &keys->client;
     pkt->level = ssl_encryption_early_data;
     pkt->plaintext = buf;
 
@@ -894,6 +912,7 @@ ngx_quic_early_input(ngx_connection_t *c
 static ngx_int_t
 ngx_quic_app_input(ngx_connection_t *c, ngx_quic_header_t *pkt)
 {
+    ngx_quic_secrets_t     *keys;
     ngx_quic_connection_t  *qc;
     static u_char           buf[NGX_QUIC_DEFAULT_MAX_PACKET_SIZE];
 
@@ -901,7 +920,9 @@ ngx_quic_app_input(ngx_connection_t *c, 
 
     qc = c->quic;
 
-    if (qc->secrets.client.ad.key.len == 0) {
+    keys = &c->quic->keys[ssl_encryption_application];
+
+    if (keys->client.key.len == 0) {
         ngx_log_error(NGX_LOG_INFO, c->log, 0,
                       "no read keys yet, packet ignored");
         return NGX_DECLINED;
@@ -911,7 +932,7 @@ ngx_quic_app_input(ngx_connection_t *c, 
         return NGX_ERROR;
     }
 
-    pkt->secret = &qc->secrets.client.ad;
+    pkt->secret = &keys->client;
     pkt->level = ssl_encryption_application;
     pkt->plaintext = buf;
 
@@ -1085,9 +1106,7 @@ ngx_quic_payload_handler(ngx_connection_
         return NGX_ERROR;
     }
 
-    ack_frame->level = (pkt->level == ssl_encryption_early_data)
-                       ? ssl_encryption_application
-                       : pkt->level;
+    ack_frame->level = pkt->level;
     ack_frame->type = NGX_QUIC_FT_ACK;
     ack_frame->u.ack.pn = pkt->pn;
 
@@ -1434,6 +1453,7 @@ ngx_quic_frames_send(ngx_connection_t *c
     ngx_str_t               out, res;
     ngx_quic_frame_t       *f;
     ngx_quic_header_t       pkt;
+    ngx_quic_secrets_t     *keys;
     ngx_quic_connection_t  *qc;
     static ngx_str_t        initial_token = ngx_null_string;
     static u_char           src[NGX_QUIC_DEFAULT_MAX_PACKET_SIZE];
@@ -1472,20 +1492,21 @@ ngx_quic_frames_send(ngx_connection_t *c
 
     qc = c->quic;
 
+    keys = &c->quic->keys[start->level];
+
+    pkt.secret = &keys->server;
+
     if (start->level == ssl_encryption_initial) {
         pkt.number = &qc->initial_pn;
         pkt.flags = NGX_QUIC_PKT_INITIAL;
-        pkt.secret = &qc->secrets.server.in;
         pkt.token = initial_token;
 
     } else if (start->level == ssl_encryption_handshake) {
         pkt.number = &qc->handshake_pn;
         pkt.flags = NGX_QUIC_PKT_HANDSHAKE;
-        pkt.secret = &qc->secrets.server.hs;
 
     } else {
         pkt.number = &qc->appdata_pn;
-        pkt.secret = &qc->secrets.server.ad;
     }
 
     pkt.log = c->log;
--- a/src/event/ngx_event_quic_protection.c
+++ b/src/event/ngx_event_quic_protection.c
@@ -118,8 +118,8 @@ ngx_quic_ciphers(ngx_ssl_conn_t *ssl_con
 
 
 ngx_int_t
-ngx_quic_set_initial_secret(ngx_pool_t *pool, ngx_quic_secrets_t *qsec,
-    ngx_str_t *secret)
+ngx_quic_set_initial_secret(ngx_pool_t *pool, ngx_quic_secret_t *client,
+    ngx_quic_secret_t *server, ngx_str_t *secret)
 {
     size_t             is_len;
     uint8_t            is[SHA256_DIGEST_LENGTH];
@@ -152,17 +152,17 @@ ngx_quic_set_initial_secret(ngx_pool_t *
     ngx_quic_hexdump0(pool->log, "initial secret", is, is_len);
 
     /* draft-ietf-quic-tls-23#section-5.2 */
-    qsec->client.in.secret.len = SHA256_DIGEST_LENGTH;
-    qsec->server.in.secret.len = SHA256_DIGEST_LENGTH;
+    client->secret.len = SHA256_DIGEST_LENGTH;
+    server->secret.len = SHA256_DIGEST_LENGTH;
 
-    qsec->client.in.key.len = EVP_CIPHER_key_length(cipher);
-    qsec->server.in.key.len = EVP_CIPHER_key_length(cipher);
+    client->key.len = EVP_CIPHER_key_length(cipher);
+    server->key.len = EVP_CIPHER_key_length(cipher);
 
-    qsec->client.in.hp.len = EVP_CIPHER_key_length(cipher);
-    qsec->server.in.hp.len = EVP_CIPHER_key_length(cipher);
+    client->hp.len = EVP_CIPHER_key_length(cipher);
+    server->hp.len = EVP_CIPHER_key_length(cipher);
 
-    qsec->client.in.iv.len = EVP_CIPHER_iv_length(cipher);
-    qsec->server.in.iv.len = EVP_CIPHER_iv_length(cipher);
+    client->iv.len = EVP_CIPHER_iv_length(cipher);
+    server->iv.len = EVP_CIPHER_iv_length(cipher);
 
     struct {
         ngx_str_t   label;
@@ -171,40 +171,40 @@ ngx_quic_set_initial_secret(ngx_pool_t *
     } seq[] = {
 
         /* draft-ietf-quic-tls-23#section-5.2 */
-        { ngx_string("tls13 client in"), &qsec->client.in.secret, &iss },
+        { ngx_string("tls13 client in"), &client->secret, &iss },
         {
             ngx_string("tls13 quic key"),
-            &qsec->client.in.key,
-            &qsec->client.in.secret,
+            &client->key,
+            &client->secret,
         },
         {
             ngx_string("tls13 quic iv"),
-            &qsec->client.in.iv,
-            &qsec->client.in.secret,
+            &client->iv,
+            &client->secret,
         },
         {
             /* AEAD_AES_128_GCM prior to handshake, quic-tls-23#section-5.4.1 */
             ngx_string("tls13 quic hp"),
-            &qsec->client.in.hp,
-            &qsec->client.in.secret,
+            &client->hp,
+            &client->secret,
         },
-        { ngx_string("tls13 server in"), &qsec->server.in.secret, &iss },
+        { ngx_string("tls13 server in"), &server->secret, &iss },
         {
             /* AEAD_AES_128_GCM prior to handshake, quic-tls-23#section-5.3 */
             ngx_string("tls13 quic key"),
-            &qsec->server.in.key,
-            &qsec->server.in.secret,
+            &server->key,
+            &server->secret,
         },
         {
             ngx_string("tls13 quic iv"),
-            &qsec->server.in.iv,
-            &qsec->server.in.secret,
+            &server->iv,
+            &server->secret,
         },
         {
            /* AEAD_AES_128_GCM prior to handshake, quic-tls-23#section-5.4.1 */
             ngx_string("tls13 quic hp"),
-            &qsec->server.in.hp,
-            &qsec->server.in.secret,
+            &server->hp,
+            &server->secret,
         },
 
     };
@@ -604,12 +604,11 @@ 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_peer_secrets_t *qsec)
+    size_t secret_len, ngx_quic_secret_t *peer_secret)
 {
-    ngx_int_t            key_len;
-    ngx_uint_t           i;
-    ngx_quic_secret_t   *peer_secret;
-    ngx_quic_ciphers_t   ciphers;
+    ngx_int_t           key_len;
+    ngx_uint_t          i;
+    ngx_quic_ciphers_t  ciphers;
 
     key_len = ngx_quic_ciphers(ssl_conn, &ciphers, level);
 
@@ -618,21 +617,7 @@ ngx_quic_set_encryption_secret(ngx_pool_
         return 0;
     }
 
-    switch (level) {
-
-    case ssl_encryption_early_data:
-        peer_secret = &qsec->ed;
-        break;
-
-    case ssl_encryption_handshake:
-        peer_secret = &qsec->hs;
-        break;
-
-    case ssl_encryption_application:
-        peer_secret = &qsec->ad;
-        break;
-
-    default:
+    if (level == ssl_encryption_initial) {
         return 0;
     }
 
--- a/src/event/ngx_event_quic_protection.h
+++ b/src/event/ngx_event_quic_protection.h
@@ -8,6 +8,9 @@
 #define _NGX_EVENT_QUIC_PROTECTION_H_INCLUDED_
 
 
+#define NGX_QUIC_ENCRYPTION_LAST  ((ssl_encryption_application) + 1)
+
+
 typedef struct ngx_quic_secret_s {
     ngx_str_t                 secret;
     ngx_str_t                 key;
@@ -17,25 +20,18 @@ typedef struct ngx_quic_secret_s {
 
 
 typedef struct {
-    ngx_quic_secret_t         in;
-    ngx_quic_secret_t         ed;
-    ngx_quic_secret_t         hs;
-    ngx_quic_secret_t         ad;
-} ngx_quic_peer_secrets_t;
-
-
-typedef struct {
-    ngx_quic_peer_secrets_t   client;
-    ngx_quic_peer_secrets_t   server;
+    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_secrets_t *secrets, ngx_str_t *secret);
+    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_peer_secrets_t *qsec);
+    ngx_quic_secret_t *peer_secret);
 
 ssize_t ngx_quic_encrypt(ngx_quic_header_t *pkt, ngx_ssl_conn_t *ssl_conn,
      ngx_str_t *res);