]> git.ipfire.org Git - thirdparty/openvpn.git/commitdiff
Extend tls_pre_decrypt_lite to return type of packet and keep state
authorArne Schwabe <arne@rfc2549.org>
Fri, 22 Apr 2022 13:40:34 +0000 (15:40 +0200)
committerGert Doering <gert@greenie.muc.de>
Mon, 25 Apr 2022 15:18:13 +0000 (17:18 +0200)
This allows us to keep the temporary data for a little bit longer
so we can use this to make further checks and ultimatively use the
state to craft the HMAC based RESET reply.

For now we do not use the extra information and keep behaviour
identical.

Signed-off-by: Arne Schwabe <arne@rfc2549.org>
Acked-by: Gert Doering <gert@greenie.muc.de>
Message-Id: <20220422134038.3801239-6-arne@rfc2549.org>
URL: https://www.mail-archive.com/openvpn-devel@lists.sourceforge.net/msg24148.html
Signed-off-by: Gert Doering <gert@greenie.muc.de>
src/openvpn/mudp.c
src/openvpn/ssl.c
src/openvpn/ssl.h

index 780ca171da6c533c28d435dfe6d6555674de181e..7aad1e1d983c45444b77cfdfb0a40dbcfa1a7a2a 100644 (file)
@@ -43,7 +43,16 @@ static bool
 do_pre_decrypt_check(struct multi_context *m)
 {
     ASSERT(m->top.c2.tls_auth_standalone);
-    if (!tls_pre_decrypt_lite(m->top.c2.tls_auth_standalone, &m->top.c2.from, &m->top.c2.buf))
+
+    enum first_packet_verdict verdict;
+    struct tls_pre_decrypt_state state = {0};
+
+    verdict = tls_pre_decrypt_lite(m->top.c2.tls_auth_standalone, &state,
+                                   &m->top.c2.from, &m->top.c2.buf);
+
+    free_tls_pre_decrypt_state(&state);
+
+    if (verdict == VERDICT_INVALID || verdict == VERDICT_VALID_CONTROL_V1)
     {
         return false;
     }
index 76b76738e0a2c2824fececa5f776f393beeabe7a..9540962808fe9eb436e40df872c4f6ca5f235f44 100644 (file)
@@ -3754,6 +3754,17 @@ error:
     goto done;
 }
 
+void
+free_tls_pre_decrypt_state(struct tls_pre_decrypt_state *state)
+{
+    free_buf(&state->newbuf);
+    free_buf(&state->tls_wrap_tmp.tls_crypt_v2_metadata);
+    if (state->tls_wrap_tmp.cleanup_key_ctx)
+    {
+        free_key_ctx_bi(&state->tls_wrap_tmp.opt.key_ctx_bi);
+    }
+}
+
 /*
  * This function is similar to tls_pre_decrypt, except it is called
  * when we are in server mode and receive an initial incoming
@@ -3765,17 +3776,21 @@ error:
  * This function is essentially the first-line HMAC firewall
  * on the UDP port listener in --mode server mode.
  */
-bool
+enum first_packet_verdict
 tls_pre_decrypt_lite(const struct tls_auth_standalone *tas,
+                     struct tls_pre_decrypt_state *state,
                      const struct link_socket_actual *from,
                      const struct buffer *buf)
-
 {
-    if (buf->len <= 0)
+    struct gc_arena gc = gc_new();
+    /* A packet needs to have at least an opcode and session id */
+    if (buf->len < (1 + SID_SIZE))
     {
-        return false;
+        dmsg(D_TLS_STATE_ERRORS,
+             "TLS State Error: Too short packet (length  %d) received from %s",
+             buf->len, print_link_socket_actual(from, &gc));
+        goto error;
     }
-    struct gc_arena gc = gc_new();
 
     /* get opcode and key ID */
     uint8_t pkt_firstbyte = *BPTR(buf);
@@ -3785,8 +3800,10 @@ tls_pre_decrypt_lite(const struct tls_auth_standalone *tas,
     /* this packet is from an as-yet untrusted source, so
      * scrutinize carefully */
 
+    /* Allow only the reset packet or the first packet of the actual handshake. */
     if (op != P_CONTROL_HARD_RESET_CLIENT_V2
-        && op != P_CONTROL_HARD_RESET_CLIENT_V3)
+        && op != P_CONTROL_HARD_RESET_CLIENT_V3
+        && op != P_CONTROL_V1)
     {
         /*
          * This can occur due to bogus data or DoS packets.
@@ -3807,17 +3824,28 @@ tls_pre_decrypt_lite(const struct tls_auth_standalone *tas,
         goto error;
     }
 
-    struct buffer newbuf = clone_buf(buf);
-    struct tls_wrap_ctx tls_wrap_tmp = tas->tls_wrap;
-
-    /* HMAC test, if --tls-auth was specified */
-    bool status = read_control_auth(&newbuf, &tls_wrap_tmp, from, NULL);
-    free_buf(&newbuf);
-    free_buf(&tls_wrap_tmp.tls_crypt_v2_metadata);
-    if (tls_wrap_tmp.cleanup_key_ctx)
+    /* read peer session id, we do this at this point since
+     * read_control_auth will skip over it */
+    struct buffer tmp = *buf;
+    buf_advance(&tmp, 1);
+    if (!session_id_read(&state->peer_session_id, &tmp)
+        || !session_id_defined(&state->peer_session_id))
     {
-        free_key_ctx_bi(&tls_wrap_tmp.opt.key_ctx_bi);
+        msg(D_TLS_ERRORS,
+            "TLS Error: session-id not found in packet from %s",
+            print_link_socket_actual(from, &gc));
+        goto error;
     }
+
+    state->newbuf = clone_buf(buf);
+    state->tls_wrap_tmp = tas->tls_wrap;
+
+    /* HMAC test and unwrapping the encrypted part of the control message
+     * into newbuf or just setting newbuf to point to the start of control
+     * message */
+    bool status = read_control_auth(&state->newbuf, &state->tls_wrap_tmp,
+                                    from, NULL);
+
     if (!status)
     {
         goto error;
@@ -3839,12 +3867,19 @@ tls_pre_decrypt_lite(const struct tls_auth_standalone *tas,
      * of authentication solely up to TLS.
      */
     gc_free(&gc);
-    return true;
+    if (op == P_CONTROL_V1)
+    {
+        return VERDICT_VALID_CONTROL_V1;
+    }
+    else
+    {
+        return VERDICT_VALID_RESET;
+    }
 
 error:
     tls_clear_error();
     gc_free(&gc);
-    return false;
+    return VERDICT_INVALID;
 }
 
 struct key_state *
index 6684aa2baa57c9daede1575f435c9b4795c06587..bc9b570f46197f6f77bb6bf9c090e523b309737d 100644 (file)
@@ -323,6 +323,33 @@ bool tls_pre_decrypt(struct tls_multi *multi,
 /** @name Functions for managing security parameter state for data channel packets
  *  @{ */
 
+
+enum first_packet_verdict {
+    /** This packet is a valid reset packet from the peer */
+    VERDICT_VALID_RESET,
+    /** This packet is a valid control packet from the peer,
+     * i.e. it has a valid session id hmac in it */
+    VERDICT_VALID_CONTROL_V1,
+    /** the packet failed on of the various checks */
+    VERDICT_INVALID
+};
+
+/**
+ * struct that stores the temporary data for the tls lite decrypt
+ * functions
+ */
+struct tls_pre_decrypt_state {
+    struct tls_wrap_ctx tls_wrap_tmp;
+    struct buffer newbuf;
+    struct session_id peer_session_id;
+};
+
+/**
+ *
+ * @param state
+ */
+void free_tls_pre_decrypt_state(struct tls_pre_decrypt_state *state);
+
 /**
  * Inspect an incoming packet for which no VPN tunnel is active, and
  * determine whether a new VPN tunnel should be created.
@@ -343,6 +370,8 @@ bool tls_pre_decrypt(struct tls_multi *multi,
  * whether a new VPN tunnel should be created.  If so, that new VPN tunnel
  * instance will handle processing of the packet.
  *
+ * This function is only used in the UDP p2mp server code path
+ *
  * @param tas - The standalone TLS authentication setting structure for
  *     this process.
  * @param from - The source address of the packet.
@@ -354,9 +383,11 @@ bool tls_pre_decrypt(struct tls_multi *multi,
  * @li False if the packet is not valid, did not pass the HMAC firewall
  *     test, or some other error occurred.
  */
-bool tls_pre_decrypt_lite(const struct tls_auth_standalone *tas,
-                          const struct link_socket_actual *from,
-                          const struct buffer *buf);
+enum first_packet_verdict
+tls_pre_decrypt_lite(const struct tls_auth_standalone *tas,
+                     struct tls_pre_decrypt_state *state,
+                     const struct link_socket_actual *from,
+                     const struct buffer *buf);
 
 
 /**