Added new packet format P_DATA_V2, which includes peer-id. If server
supports, client sends all data packets in the new format. When data
packet arrives, server identifies peer by peer-id. If peer's ip/port has
changed, server assumes that client has floated, verifies HMAC and
updates ip/port in internal structs.
---
src/openvpn/crypto.c | 66
src/openvpn/crypto.h | 3 ++
src/openvpn/init.c | 10 -
src/openvpn/mudp.c | 111 +--
src/openvpn/multi.c | 6 +++
src/openvpn/multi.h | 2 +
src/openvpn/options.c| 9 +++-
src/openvpn/options.h| 8 +++-
src/openvpn/push.c | 16 ++-
src/openvpn/ssl.c| 66 +---
src/openvpn/ssl.h| 9 +++-
src/openvpn/ssl_common.h | 4 ++
12 files changed, 269 insertions(+), 41 deletions(-)
diff --git a/src/openvpn/crypto.c b/src/openvpn/crypto.c
index ef2bde1..0f1a36f 100644
--- a/src/openvpn/crypto.c
+++ b/src/openvpn/crypto.c
@@ -223,6 +223,30 @@ err:
return;
}
+int verify_hmac(struct buffer *buf, struct key_ctx *ctx, int offset)
+{
+ uint8_t local_hmac[MAX_HMAC_KEY_LENGTH]; /* HMAC of ciphertext computed
locally */
+ int hmac_len = 0;
+
+ hmac_ctx_reset(ctx->hmac);
+ /* Assume the length of the input HMAC */
+ hmac_len = hmac_ctx_size (ctx->hmac);
+
+ /* Authentication fails if insufficient data in packet for HMAC */
+ if (buf->len - offset < hmac_len)
+return 0;
+
+ hmac_ctx_update (ctx->hmac, BPTR (buf) + hmac_len + offset,
+ BLEN (buf) - hmac_len - offset);
+ hmac_ctx_final (ctx->hmac, local_hmac);
+
+ /* Compare locally computed HMAC with packet HMAC */
+ if (memcmp_constant_time (local_hmac, BPTR (buf) + offset, hmac_len) == 0)
+return hmac_len;
+
+ return 0;
+}
+
/*
* If (opt->flags & CO_USE_IV) is not NULL, we will read an IV from the packet.
*
@@ -249,25 +273,9 @@ openvpn_decrypt (struct buffer *buf, struct buffer work,
/* Verify the HMAC */
if (ctx->hmac)
{
- int hmac_len;
- uint8_t local_hmac[MAX_HMAC_KEY_LENGTH]; /* HMAC of ciphertext
computed locally */
-
- hmac_ctx_reset(ctx->hmac);
-
- /* Assume the length of the input HMAC */
- hmac_len = hmac_ctx_size (ctx->hmac);
-
- /* Authentication fails if insufficient data in packet for HMAC */
- if (buf->len < hmac_len)
- CRYPT_ERROR ("missing authentication info");
-
- hmac_ctx_update (ctx->hmac, BPTR (buf) + hmac_len, BLEN (buf) -
hmac_len);
- hmac_ctx_final (ctx->hmac, local_hmac);
-
- /* Compare locally computed HMAC with packet HMAC */
- if (memcmp_constant_time (local_hmac, BPTR (buf), hmac_len))
+ int hmac_len = verify_hmac(buf, ctx, 0);
+ if (hmac_len == 0)
CRYPT_ERROR ("packet HMAC authentication failed");
-
ASSERT (buf_advance (buf, hmac_len));
}
@@ -392,6 +400,28 @@ openvpn_decrypt (struct buffer *buf, struct buffer work,
}
/*
+ * This verifies if a packet and its HMAC fit to a crypto context.
+ *
+ * On success true is returned.
+ */
+bool
+crypto_test_hmac (struct buffer *buf, const struct crypto_options *opt)
+{
+ if (buf->len > 0 && opt->key_ctx_bi)
+{
+ struct key_ctx *ctx = >key_ctx_bi->decrypt;
+
+ /* Verify the HMAC */
+ if (ctx->hmac)
+ {
+ /* sizeof(uint32_t) comes from peer_id (3 bytes) and opcode (1 byte)
*/
+ return verify_hmac(buf, ctx, sizeof(uint32_t)) != 0;
+ }
+}
+ return false;
+}
+
+/*
* How many bytes will we add to frame buffer for a given
* set of crypto options?
*/
diff --git a/src/openvpn/crypto.h b/src/openvpn/crypto.h
index bf2f802..3c4e59d 100644
--- a/src/openvpn/crypto.h
+++ b/src/openvpn/crypto.h
@@ -275,6 +275,9 @@ bool openvpn_decrypt (struct buffer *buf, struct buffer
work,
const struct crypto_options *opt,
const struct frame* frame);
+
+bool crypto_test_hmac (struct buffer *buf, const struct crypto_options *opt);
+
/** @} name Functions for performing security operations on data channel
packets */
void crypto_adjust_frame_parameters(struct frame *frame,
diff --git a/src/openvpn/init.c b/src/openvpn/init.c
index a673be5..3811e09 100644
--- a/src/openvpn/init.c
+++ b/src/openvpn/init.c
@@ -1718,7 +1718,8 @@ pull_permission_mask (const struct context *c)
| OPT_P_MESSAGES
| OPT_P_EXPLICIT_NOTIFY
| OPT_P_ECHO
-| OPT_P_PULL_MODE;
+| OPT_P_PULL_MODE
+| OPT_P_PEER_ID;
if (!c->options.route_nopull)
flags |= (OPT_P_ROUTE | OPT_P_IPWIN32);
@@ -1795,6 +1796,13 @@ do_deferred_options (struct context *c, const unsigned
int found)
msg (D_PUSH, "OPTIONS IMPORT: --ip-win32 and/or --dhcp-option options
modified");
if (found & OPT_P_SETENV)
msg (D_PUSH, "OPTIONS IMPORT: environment modified");
+
+ if (found & OPT_P_PEER_ID)
+{
+ msg (D_PUSH,