[Openvpn-devel,v32] init: Extract init_tls_wrap_ctx() control-channel wrap helper

Message ID 20261114175158.13434-1-gert@greenie.muc.de
State New
Headers
Series [Openvpn-devel,v32] init: Extract init_tls_wrap_ctx() control-channel wrap helper |

Commit Message

Gert Doering Nov. 14, 2026, 5:51 p.m. UTC
  From: Lev Stipakov <lev@openvpn.net>

Factor the tls-auth/tls-crypt wrapping-context setup out of
do_init_crypto_tls() into a reusable init_tls_wrap_ctx() helper, and
expose it in init.h together with do_init_tls_wrap_key(), which now
takes the connection entry to read its keys from instead of using
options.ce. Both call sites pass &c->options.ce, so there is no behavior
change.

A planned server-probe feature will use the helper to build the wrapping
context before a connection exists, so that a probe can be wrapped with
tls-auth/tls-crypt like any other control packet.

Change-Id: I7d8546da9ef06c2226ea77e461f9550d24894c61
Signed-off-by: Lev Stipakov <lev@openvpn.net>
Acked-by: Razvan Cojocaru <razvanc@mailbox.org>
Gerrit URL: https://gerrit.openvpn.net/c/openvpn/+/1749
---

This change was reviewed on Gerrit and approved by at least one
developer. I request to merge it to master.

Gerrit URL: https://gerrit.openvpn.net/c/openvpn/+/1749
This mail reflects revision 32 of this Change.

Acked-by according to Gerrit (reflected above):
Razvan Cojocaru <razvanc@mailbox.org>
  

Patch

diff --git a/src/openvpn/init.c b/src/openvpn/init.c
index ff3bfe5..bea8e60 100644
--- a/src/openvpn/init.c
+++ b/src/openvpn/init.c
@@ -3097,13 +3097,13 @@ 
 /*
  * Initialize the tls-auth/crypt key context
  */
-static void
-do_init_tls_wrap_key(struct context *c)
+void
+do_init_tls_wrap_key(struct context *c, const struct connection_entry *ce)
 {
     const struct options *options = &c->options;
 
     /* TLS handshake authentication (--tls-auth) */
-    if (options->ce.tls_auth_file)
+    if (ce->tls_auth_file)
     {
         /* Initialize key_type for tls-auth with auth only */
         CLEAR(c->c1.ks.tls_auth_key_type);
@@ -3118,33 +3118,31 @@ 
         }
 
         crypto_read_openvpn_key(&c->c1.ks.tls_auth_key_type, &c->c1.ks.tls_wrap_key,
-                                options->ce.tls_auth_file, options->ce.tls_auth_file_inline,
-                                options->ce.key_direction, "Control Channel Authentication",
-                                "tls-auth", &c->c1.ks.original_wrap_keydata);
+                                ce->tls_auth_file, ce->tls_auth_file_inline, ce->key_direction,
+                                "Control Channel Authentication", "tls-auth",
+                                &c->c1.ks.original_wrap_keydata);
     }
 
     /* TLS handshake encryption+authentication (--tls-crypt) */
-    if (options->ce.tls_crypt_file)
+    if (ce->tls_crypt_file)
     {
         tls_crypt_init_key(&c->c1.ks.tls_wrap_key, &c->c1.ks.original_wrap_keydata,
-                           options->ce.tls_crypt_file, options->ce.tls_crypt_file_inline,
-                           options->tls_server);
+                           ce->tls_crypt_file, ce->tls_crypt_file_inline, options->tls_server);
     }
 
     /* tls-crypt with client-specific keys (--tls-crypt-v2) */
-    if (options->ce.tls_crypt_v2_file)
+    if (ce->tls_crypt_v2_file)
     {
         if (options->tls_server)
         {
             tls_crypt_v2_init_server_key(&c->c1.ks.tls_crypt_v2_server_key, true,
-                                         options->ce.tls_crypt_v2_file,
-                                         options->ce.tls_crypt_v2_file_inline);
+                                         ce->tls_crypt_v2_file, ce->tls_crypt_v2_file_inline);
         }
         else
         {
             tls_crypt_v2_init_client_key(&c->c1.ks.tls_wrap_key, &c->c1.ks.original_wrap_keydata,
-                                         &c->c1.ks.tls_crypt_v2_wkc, options->ce.tls_crypt_v2_file,
-                                         options->ce.tls_crypt_v2_file_inline);
+                                         &c->c1.ks.tls_crypt_v2_wkc, ce->tls_crypt_v2_file,
+                                         ce->tls_crypt_v2_file_inline);
         }
         /* We have to ensure that the loaded tls-crypt key is small enough
          * to fit into the initial hard reset v3 packet */
@@ -3153,18 +3151,45 @@ 
         /* empty ACK/message id, tls-crypt, Opcode, UDP, ipv6 */
         int required_size = 5 + wkc_len + tls_crypt_buf_overhead() + 1 + 8 + 40;
 
-        if (required_size > c->options.ce.tls_mtu)
+        if (required_size > ce->tls_mtu)
         {
             msg(M_WARN,
                 "ERROR: tls-crypt-v2 client key too large to work with "
                 "requested --max-packet-size %d, requires at least "
                 "--max-packet-size %d. Packets will ignore requested "
                 "maximum packet size",
-                c->options.ce.tls_mtu, required_size);
+                ce->tls_mtu, required_size);
         }
     }
 }
 
+void
+init_tls_wrap_ctx(struct tls_wrap_ctx *tls_wrap, const struct connection_entry *ce, bool tls_client,
+                  const struct key_schedule *ks, struct packet_id_persist *pid_persist)
+{
+    CLEAR(*tls_wrap);
+
+    /* TLS handshake authentication (--tls-auth) */
+    if (ce->tls_auth_file)
+    {
+        tls_wrap->mode = TLS_WRAP_AUTH;
+    }
+
+    /* TLS handshake encryption (--tls-crypt) */
+    if (ce->tls_crypt_file || (ce->tls_crypt_v2_file && tls_client))
+    {
+        tls_wrap->mode = TLS_WRAP_CRYPT;
+    }
+
+    if (tls_wrap->mode == TLS_WRAP_AUTH || tls_wrap->mode == TLS_WRAP_CRYPT)
+    {
+        tls_wrap->opt.key_ctx_bi = ks->tls_wrap_key;
+        tls_wrap->opt.pid_persist = pid_persist;
+        tls_wrap->opt.flags |= CO_PACKET_ID_LONG_FORM;
+        tls_wrap->original_wrap_keydata = ks->original_wrap_keydata;
+    }
+}
+
 /*
  * Initialize the persistent component of OpenVPN's TLS mode,
  * which is preserved across SIGUSR1 resets.
@@ -3236,7 +3261,7 @@ 
         init_key_type(&c->c1.ks.key_type, ciphername, options->authname, true, warn);
 
         /* initialize tls-auth/crypt/crypt-v2 key */
-        do_init_tls_wrap_key(c);
+        do_init_tls_wrap_key(c, &c->options.ce);
 
         /* initialise auth-token crypto support */
         if (c->options.auth_token_generate)
@@ -3261,7 +3286,7 @@ 
          * tls-auth/crypt key can be configured per connection block, therefore
          * we must reload it as it may have changed
          */
-        do_init_tls_wrap_key(c);
+        do_init_tls_wrap_key(c, &c->options.ce);
     }
 }
 
@@ -3439,25 +3464,9 @@ 
         to.ekm_size = 0;
     }
 
-    /* TLS handshake authentication (--tls-auth) */
-    if (options->ce.tls_auth_file)
-    {
-        to.tls_wrap.mode = TLS_WRAP_AUTH;
-    }
-
-    /* TLS handshake encryption (--tls-crypt) */
-    if (options->ce.tls_crypt_file || (options->ce.tls_crypt_v2_file && options->tls_client))
-    {
-        to.tls_wrap.mode = TLS_WRAP_CRYPT;
-    }
-
-    if (to.tls_wrap.mode == TLS_WRAP_AUTH || to.tls_wrap.mode == TLS_WRAP_CRYPT)
-    {
-        to.tls_wrap.opt.key_ctx_bi = c->c1.ks.tls_wrap_key;
-        to.tls_wrap.opt.pid_persist = &c->c1.pid_persist;
-        to.tls_wrap.opt.flags |= CO_PACKET_ID_LONG_FORM;
-        to.tls_wrap.original_wrap_keydata = c->c1.ks.original_wrap_keydata;
-    }
+    /* Control-channel wrapping (--tls-auth / --tls-crypt) */
+    init_tls_wrap_ctx(&to.tls_wrap, &c->options.ce, options->tls_client, &c->c1.ks,
+                      &c->c1.pid_persist);
 
     if (options->ce.tls_crypt_v2_file)
     {
diff --git a/src/openvpn/init.h b/src/openvpn/init.h
index c486158..67834a9 100644
--- a/src/openvpn/init.h
+++ b/src/openvpn/init.h
@@ -73,6 +73,39 @@ 
 
 void do_test_crypto(struct context *o);
 
+/**
+ * @brief Load the tls-auth/tls-crypt(-v2) key material into c->c1.ks.
+ *
+ * Reads the key from the file configured on connection entry ce (--tls-auth,
+ * --tls-crypt or --tls-crypt-v2); a no-op when none of them is set. May be
+ * called more than once (the key can be configured per connection block, so it
+ * is reloaded for each connection).
+ *
+ * @param c  The context whose c1.ks key schedule is populated.
+ * @param ce The connection entry whose tls-wrap key file is loaded.
+ */
+void do_init_tls_wrap_key(struct context *c, const struct connection_entry *ce);
+
+/**
+ * @brief Configure a control-channel wrapping context from a connection entry
+ *        and previously loaded tls-wrap key material.
+ *
+ * Sets tls_wrap to TLS_WRAP_AUTH (--tls-auth) or TLS_WRAP_CRYPT
+ * (--tls-crypt / client --tls-crypt-v2) and installs the key context, or
+ * leaves it in TLS_WRAP_NONE when neither is configured. The key material must
+ * already have been loaded with do_init_tls_wrap_key(). tls-crypt-v2 specifics
+ * (the wrapped client key and the server key) are left to the caller.
+ *
+ * @param tls_wrap    The wrapping context to configure.
+ * @param ce          The connection entry selecting the wrapping mode.
+ * @param tls_client  Whether this is a TLS client (selects tls-crypt-v2 mode).
+ * @param ks          Key schedule holding the loaded tls-wrap key material.
+ * @param pid_persist Packet-id persistence object to attach to the context.
+ */
+void init_tls_wrap_ctx(struct tls_wrap_ctx *tls_wrap, const struct connection_entry *ce,
+                       bool tls_client, const struct key_schedule *ks,
+                       struct packet_id_persist *pid_persist);
+
 void context_gc_free(struct context *c);
 
 bool do_up(struct context *c, bool pulled_options, uint64_t option_types_found);