[Openvpn-devel] [PATCH] systemd: Reworked the systemd unit file to handle server and client configs better
From: David SommersethSystemd can delay starting a service if the network isn't fully available yet. This feature is useful in client configurations, where OpenVPN will not be started before the client can reach the Internet. It is the network service manager which tells systemd if the system is "online" or not. For server configurations, the OpenVPN should be able to be started, regardless if the system is "online" or not. This is also the old behaviour of most of the old init.d script and the last systemd unit file. This patch splits the previous systemd unit file into to two files. One which is aimed at clients (openvpn-client@.service) and one for server configurations (openvpn-server@.service). These files will also pick the configurations from different sub-directories. The unit file for openvpn-client@ will use /etc/openvpn/client and the server unit file will use /etc/openvpn/server. This also ensures that config files are not started in the wrong manner. The arguments given to the openvpn binary have also shifted order, to ensure that some of them cannot be overridden by the config file, such as --daemon and --writepid. For server configurations a --status file is also added with the status format set to 2. This can be overridden by the configuration file. Signed-off-by: David Sommerseth --- distro/systemd/{openvpn@.service => openvpn-client@.service} | 7 --- distro/systemd/{openvpn@.service => openvpn-server@.service} | 6 +++--- 2 files changed, 7 insertions(+), 6 deletions(-) copy distro/systemd/{openvpn@.service => openvpn-client@.service} (68%) rename distro/systemd/{openvpn@.service => openvpn-server@.service} (65%) diff --git a/distro/systemd/openvpn@.service b/distro/systemd/openvpn-client@.service similarity index 68% copy from distro/systemd/openvpn@.service copy to distro/systemd/openvpn-client@.service index 7cd36c3..56d93a9 100644 --- a/distro/systemd/openvpn@.service +++ b/distro/systemd/openvpn-client@.service @@ -1,6 +1,7 @@ [Unit] Description=OpenVPN tunnel for %I -After=syslog.target network.target +After=syslog.target network-online.target +Wants=network-online.target Documentation=man:openvpn(8) Documentation=https://community.openvpn.net/openvpn/wiki/Openvpn23ManPage Documentation=https://community.openvpn.net/openvpn/wiki/HOWTO @@ -8,8 +9,8 @@ Documentation=https://community.openvpn.net/openvpn/wiki/HOWTO [Service] PrivateTmp=true Type=forking -PIDFile=/var/run/openvpn/%i.pid -ExecStart=/usr/sbin/openvpn --daemon --writepid /var/run/openvpn/%i.pid --cd /etc/openvpn/ --config %i.conf +PIDFile=/var/run/openvpn/client_%i.pid +ExecStart=/usr/sbin/openvpn --cd /etc/openvpn/client --config %i.conf --daemon --writepid /var/run/openvpn/client_%i.pid CapabilityBoundingSet=CAP_IPC_LOCK CAP_NET_ADMIN CAP_NET_BIND_SERVICE CAP_NET_RAW CAP_SETGID CAP_SETUID CAP_SYS_CHROOT CAP_DAC_READ_SEARCH LimitNPROC=10 DeviceAllow=/dev/null rw diff --git a/distro/systemd/openvpn@.service b/distro/systemd/openvpn-server@.service similarity index 65% rename from distro/systemd/openvpn@.service rename to distro/systemd/openvpn-server@.service index 7cd36c3..c4c9a12 100644 --- a/distro/systemd/openvpn@.service +++ b/distro/systemd/openvpn-server@.service @@ -1,5 +1,5 @@ [Unit] -Description=OpenVPN tunnel for %I +Description=OpenVPN service for %I After=syslog.target network.target Documentation=man:openvpn(8) Documentation=https://community.openvpn.net/openvpn/wiki/Openvpn23ManPage @@ -8,8 +8,8 @@ Documentation=https://community.openvpn.net/openvpn/wiki/HOWTO [Service] PrivateTmp=true Type=forking -PIDFile=/var/run/openvpn/%i.pid -ExecStart=/usr/sbin/openvpn --daemon --writepid /var/run/openvpn/%i.pid --cd /etc/openvpn/ --config %i.conf +PIDFile=/var/run/openvpn/server_%i.pid +ExecStart=/usr/sbin/openvpn --cd /etc/openvpn/server --status /var/run/openvpn/server_%i-status.log --status-version 2 --config %i.conf --daemon --writepid /var/run/openvpn/server_%i.pid CapabilityBoundingSet=CAP_IPC_LOCK CAP_NET_ADMIN CAP_NET_BIND_SERVICE CAP_NET_RAW CAP_SETGID CAP_SETUID CAP_SYS_CHROOT CAP_DAC_READ_SEARCH LimitNPROC=10 DeviceAllow=/dev/null rw -- 1.8.3.1
[Openvpn-devel] [PATCH] Peer-id patch v4
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. New in v4: Handles correctly float to an address which is used by another peer. This also has fixed crash on assert in multi_client_disconnect. New in v3: Bugfix: If float happens after TLS renegotiation and there are no data packets between reneg and float, server will not recognize floated client. --- src/openvpn/crypto.c | 66 +++-- src/openvpn/crypto.h | 3 + src/openvpn/init.c | 10 +++- src/openvpn/mudp.c | 150 ++- 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| 67 +++-- src/openvpn/ssl.h| 9 ++- src/openvpn/ssl_common.h | 4 ++ 12 files changed, 308 insertions(+), 42 deletions(-) diff --git a/src/openvpn/crypto.c b/src/openvpn/crypto.c index ef2bde1..ccea1b8 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, struct key_ctx_bi *key_ctx_bi) +{ + if (buf->len > 0 && key_ctx_bi) +{ + struct key_ctx *ctx = _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..b8db85c 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, struct key_ctx_bi *key_ctx_bi); + /** @} 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
[Openvpn-devel] OpenVPN Protocol extensions
In addition to the Peer-ID/DATA_V2 protocol change proposal, here are a couple more proposed extensions for AEAD mode and Compression V2 that we can discuss at the upcoming Munich hackathon. James OpenVPN Protocol extensions 1. DATA_V2 opcode with 24-bit peer ID 2. AEAD mode To support AEAD crypto modes such as AES-GCM, some protocol changes are in order. AES-GCM, for example, requires a 12 byte unique nonce for every packet. I would propose that 4 bytes be taken from the Packet ID which increments for every packet and therefore provides uniqueness. The remaining 8 bytes would be derived from the random key material that would normally be used to key the HMAC key. This is possible since AEAD modes use a combined key for encryption and integrity checking, therefore the random key material for HMAC is unused and can be repurposed as an AEAD nonce source. The 8 byte nonce component derived from the HMAC keying material would remain constant for a given Key State. Only the 4 byte Packet ID would increment for each packet. Because AEAD encryption can be compromised if the nonce ever repeats for a given key, the implementation MUST disable encryption for a key if the 32-bit packet ID wraps. In practical usage, renegotiation usually preempts wrapping, so the disable-encryption-on-wrap feature is a failsafe. AEAD Nonce: [ Packet ID ] [ HMAC keying material ] [ 4 bytes ] [ 8 bytes ] [ AEAD nonce total: 12 bytes ] TLS wire protocol: [ DATA_V2 opcode ] [ Packet ID ] [ AEAD Auth tag ] [ ciphertext ] [ 4 bytes] [ 4 bytes ] [ 16 bytes ] Static Key wire protocol: [ DATA_V2 opcode ] [ Packet ID ] [ Nonce tail (random) ] [ AEAD Auth tag ] [ ciphertext ] [ AEAD nonce ] [ 4 bytes] [ 8 bytes ] [ 4 bytes ] [ 16 bytes ] Note that because the HMAC keying material used to derive the last 8 bytes of the AEAD nonce is negotiated once per key as part of the control channel handshake, we can omit it from the data channel packets, thereby saving 8 bytes per packet. So only the 4-byte Packet ID component of the nonce must be transmitted with every packet. Also note that that the TLS wire protocol overhead is only 24 bytes, including the new 4 byte DATA_V2 opcode that includes the Peer ID! Compare that with traditional AES-CBC mode and DATA_V1 opcode: 1 (DATA_V1 opcode) + 20 (HMAC-SHA1 hash) + 8 (IV) + 4 (Packet ID) + 1-8 (PKCS#7 padding) = 34-41 bytes. 3. Compression V2 I have observed that compression in many cases, even when enabled, often does not produce packet size reduction because much of the packet data typically generated by web sessions is already compressed. Further, the single byte that precedes the packet and indicates whether or not compression occurred has the unfortunate side effect of misaligning the IP packet in cases where compression did not occur. To remedy this, I propose a Compression V2 header that is optimized for the case where compression does not occur. a. No compression occurred and first byte of IP/Ethernet packet is NOT 0x50 (0 bytes of overhead and maintains alignment): [ uncompressed IP/Ethernet packet ] b. No compression occurred and first byte of IP/Ethernet packet is 0x50 (2 bytes of overhead but unlikely since no known IP packet can begin with 0x50): [ 0x50 ] [ 0x00 ] [ uncompressed IP/Ethernet packet ] c. Compression occurred (2 bytes of overhead): [ 0x50 ] [ compression Alg ID ] [ compressed IP/Ethernet packet ] Compression Alg ID is one-byte algorithm identifier for LZ4 (0x1), LZO (0x2), or Snappy (0x3). This approach has several beneficial effects: 1. In the common case where compression does not occur, no compression op is required, therefore there is zero overhead. 2. When compression does not occur, the IP/Ethernet packet alignment is retained. 3. This technique does not require any byte swapping with the tail of the packet which can potentially incur an expensive cache miss.