@@ -70,7 +70,7 @@
int ret = dco_new_key(multi->dco, multi->dco_peer_id, ks->key_id, slot,
encrypt_key, encrypt_iv,
decrypt_key, decrypt_iv,
- ciphername);
+ ciphername, ks->crypto_options.flags);
if ((ret == 0) && (multi->dco_keys_installed < 2))
{
multi->dco_keys_installed++;
@@ -253,11 +253,7 @@
* Return whether the dco implementation supports the new protocol features of
* a 64 bit packet counter and AEAD tag at the end.
*/
-static inline bool
-dco_supports_data_v3(struct context *c)
-{
- return false;
-}
+bool dco_supports_data_v3(struct context *c);
#else /* if defined(ENABLE_DCO) */
@@ -415,14 +415,14 @@
dco_key_slot_t slot,
const uint8_t *encrypt_key, const uint8_t *encrypt_iv,
const uint8_t *decrypt_key, const uint8_t *decrypt_iv,
- const char *ciphername)
+ const char *ciphername, unsigned int co_flags)
{
struct ifdrv drv;
nvlist_t *nvl;
int ret;
- msg(D_DCO_DEBUG, "%s: slot %d, key-id %d, peer-id %d, cipher %s",
- __func__, slot, keyid, peerid, ciphername);
+ msg(D_DCO_DEBUG, "%s: slot %d, key-id %d, peer-id %d, cipher %s, co_flags %u",
+ __func__, slot, keyid, peerid, ciphername, co_flags);
nvl = nvlist_create(0);
@@ -778,4 +778,11 @@
return "none:AES-256-GCM:AES-192-GCM:AES-128-GCM:CHACHA20-POLY1305";
}
+bool
+dco_supports_data_v3(struct context *c)
+{
+ /* not implemented */
+ return false;
+}
+
#endif /* defined(ENABLE_DCO) && defined(TARGET_FREEBSD) */
@@ -70,7 +70,7 @@
dco_key_slot_t slot,
const uint8_t *encrypt_key, const uint8_t *encrypt_iv,
const uint8_t *decrypt_key, const uint8_t *decrypt_iv,
- const char *ciphername);
+ const char *ciphername, unsigned int co_flags);
int dco_del_key(dco_context_t *dco, unsigned int peerid, dco_key_slot_t slot);
@@ -557,10 +557,10 @@
dco_key_slot_t slot,
const uint8_t *encrypt_key, const uint8_t *encrypt_iv,
const uint8_t *decrypt_key, const uint8_t *decrypt_iv,
- const char *ciphername)
+ const char *ciphername, unsigned int co_flags)
{
- msg(D_DCO_DEBUG, "%s: slot %d, key-id %d, peer-id %d, cipher %s",
- __func__, slot, keyid, peerid, ciphername);
+ msg(D_DCO_DEBUG, "%s: slot %d, key-id %d, peer-id %d, cipher %s, co_flags %u",
+ __func__, slot, keyid, peerid, ciphername, co_flags);
const size_t key_len = cipher_kt_key_size(ciphername);
const int nonce_tail_len = 8;
@@ -1058,4 +1058,11 @@
return "AES-128-GCM:AES-256-GCM:AES-192-GCM:CHACHA20-POLY1305";
}
+bool
+dco_supports_data_v3(struct context *c)
+{
+ /* not implemented */
+ return false;
+}
+
#endif /* defined(ENABLE_DCO) && defined(TARGET_LINUX) */
@@ -55,6 +55,9 @@
bool
ovpn_dco_init(int mode, dco_context_t *dco)
{
+ dco->supports_data_v3 = dco_supports_data_v3(NULL);
+ msg(D_DCO_DEBUG, "dco supports data_v3: %d", dco->supports_data_v3);
+
return true;
}
@@ -291,47 +294,85 @@
return 0;
}
-int
-dco_new_key(dco_context_t *dco, unsigned int peerid, int keyid,
- dco_key_slot_t slot,
- const uint8_t *encrypt_key, const uint8_t *encrypt_iv,
- const uint8_t *decrypt_key, const uint8_t *decrypt_iv,
- const char *ciphername)
+static int
+dco_new_key_v1(HANDLE handle, OVPN_CRYPTO_DATA *crypto_data)
{
- msg(D_DCO_DEBUG, "%s: slot %d, key-id %d, peer-id %d, cipher %s",
- __func__, slot, keyid, peerid, ciphername);
-
- const int nonce_len = 8;
- size_t key_len = cipher_kt_key_size(ciphername);
-
- OVPN_CRYPTO_DATA crypto_data;
- ZeroMemory(&crypto_data, sizeof(crypto_data));
-
- crypto_data.CipherAlg = dco_get_cipher(ciphername);
- crypto_data.KeyId = keyid;
- crypto_data.PeerId = peerid;
- crypto_data.KeySlot = slot;
-
- CopyMemory(crypto_data.Encrypt.Key, encrypt_key, key_len);
- crypto_data.Encrypt.KeyLen = (char)key_len;
- CopyMemory(crypto_data.Encrypt.NonceTail, encrypt_iv, nonce_len);
-
- CopyMemory(crypto_data.Decrypt.Key, decrypt_key, key_len);
- crypto_data.Decrypt.KeyLen = (char)key_len;
- CopyMemory(crypto_data.Decrypt.NonceTail, decrypt_iv, nonce_len);
-
- ASSERT(crypto_data.CipherAlg > 0);
-
DWORD bytes_returned = 0;
- if (!DeviceIoControl(dco->tt->hand, OVPN_IOCTL_NEW_KEY, &crypto_data,
- sizeof(crypto_data), NULL, 0, &bytes_returned, NULL))
+ if (!DeviceIoControl(handle, OVPN_IOCTL_NEW_KEY, crypto_data, sizeof(*crypto_data), NULL, 0, &bytes_returned, NULL))
{
msg(M_ERR, "DeviceIoControl(OVPN_IOCTL_NEW_KEY) failed");
return -1;
}
return 0;
}
+
+static int
+dco_new_key_v2(HANDLE handle, OVPN_CRYPTO_DATA_V2 *crypto_data, unsigned int co_flags)
+{
+ if (co_flags & CO_AEAD_TAG_AT_THE_END)
+ {
+ crypto_data->CryptoOptions |= CRYPTO_OPTIONS_AEAD_TAG_END;
+ }
+
+ if (co_flags & CO_64_BIT_PKT_ID)
+ {
+ crypto_data->CryptoOptions |= CRYPTO_OPTIONS_64BIT_PKTID;
+ }
+
+ DWORD bytes_returned = 0;
+ if (!DeviceIoControl(handle, OVPN_IOCTL_NEW_KEY_V2, crypto_data, sizeof(*crypto_data), NULL, 0, &bytes_returned, NULL))
+ {
+ msg(M_ERR, "DeviceIoControl(OVPN_IOCTL_NEW_KEY_V2) failed");
+ return -1;
+ }
+
+ return 0;
+}
+
+int
+dco_new_key(dco_context_t *dco, unsigned int peerid, int keyid,
+ dco_key_slot_t slot,
+ const uint8_t *encrypt_key, const uint8_t *encrypt_iv,
+ const uint8_t *decrypt_key, const uint8_t *decrypt_iv,
+ const char *ciphername, unsigned int co_flags)
+{
+ msg(D_DCO_DEBUG, "%s: slot %d, key-id %d, peer-id %d, cipher %s, co_flags %u",
+ __func__, slot, keyid, peerid, ciphername, co_flags);
+
+ const int nonce_len = 8;
+ size_t key_len = cipher_kt_key_size(ciphername);
+
+ OVPN_CRYPTO_DATA_V2 crypto_data_v2;
+ ZeroMemory(&crypto_data_v2, sizeof(crypto_data_v2));
+
+ OVPN_CRYPTO_DATA *crypto_data = &crypto_data_v2.V1;
+
+ crypto_data->CipherAlg = dco_get_cipher(ciphername);
+ crypto_data->KeyId = keyid;
+ crypto_data->PeerId = peerid;
+ crypto_data->KeySlot = slot;
+
+ CopyMemory(crypto_data->Encrypt.Key, encrypt_key, key_len);
+ crypto_data->Encrypt.KeyLen = (char)key_len;
+ CopyMemory(crypto_data->Encrypt.NonceTail, encrypt_iv, nonce_len);
+
+ CopyMemory(crypto_data->Decrypt.Key, decrypt_key, key_len);
+ crypto_data->Decrypt.KeyLen = (char)key_len;
+ CopyMemory(crypto_data->Decrypt.NonceTail, decrypt_iv, nonce_len);
+
+ ASSERT(crypto_data->CipherAlg > 0);
+
+ if (dco->supports_data_v3)
+ {
+ return dco_new_key_v2(dco->tt->hand, &crypto_data_v2, co_flags);
+ }
+ else
+ {
+ return dco_new_key_v1(dco->tt->hand, crypto_data);
+ }
+}
+
int
dco_del_key(dco_context_t *dco, unsigned int peerid, dco_key_slot_t slot)
{
@@ -494,4 +535,39 @@
}
}
+bool
+dco_supports_data_v3(struct context *c)
+{
+ bool res = false;
+
+ HANDLE h = CreateFile("\\\\.\\ovpn-dco-ver", GENERIC_READ,
+ 0, NULL, OPEN_EXISTING, 0, NULL);
+
+ if (h == INVALID_HANDLE_VALUE)
+ {
+ goto done;
+ }
+
+ OVPN_VERSION version;
+ ZeroMemory(&version, sizeof(OVPN_VERSION));
+
+ DWORD bytes_returned = 0;
+ if (!DeviceIoControl(h, OVPN_IOCTL_GET_VERSION, NULL, 0,
+ &version, sizeof(version), &bytes_returned, NULL))
+ {
+ goto done;
+ }
+
+ /* data_v3 is supported starting from 1.4 */
+ res = (version.Major > 1) || (version.Minor >= 4);
+
+done:
+ if (h != INVALID_HANDLE_VALUE)
+ {
+ CloseHandle(h);
+ }
+
+ return res;
+}
+
#endif /* defined(_WIN32) */
@@ -33,6 +33,7 @@
struct dco_context {
struct tuntap *tt;
+ bool supports_data_v3;
};
typedef struct dco_context dco_context_t;
@@ -94,6 +94,14 @@
int PeerId;
} OVPN_CRYPTO_DATA, * POVPN_CRYPTO_DATA;
+#define CRYPTO_OPTIONS_AEAD_TAG_END (1<<1)
+#define CRYPTO_OPTIONS_64BIT_PKTID (1<<2)
+
+typedef struct _OVPN_CRYPTO_DATA_V2 {
+ OVPN_CRYPTO_DATA V1;
+ UINT32 CryptoOptions;
+} OVPN_CRYPTO_DATA_V2, * POVPN_CRYPTO_DATA_V2;
+
typedef struct _OVPN_SET_PEER {
LONG KeepaliveInterval;
LONG KeepaliveTimeout;
@@ -114,3 +122,4 @@
#define OVPN_IOCTL_START_VPN CTL_CODE(FILE_DEVICE_UNKNOWN, 6, METHOD_BUFFERED, FILE_ANY_ACCESS)
#define OVPN_IOCTL_DEL_PEER CTL_CODE(FILE_DEVICE_UNKNOWN, 7, METHOD_BUFFERED, FILE_ANY_ACCESS)
#define OVPN_IOCTL_GET_VERSION CTL_CODE(FILE_DEVICE_UNKNOWN, 8, METHOD_BUFFERED, FILE_ANY_ACCESS)
+#define OVPN_IOCTL_NEW_KEY_V2 CTL_CODE(FILE_DEVICE_UNKNOWN, 9, METHOD_BUFFERED, FILE_ANY_ACCESS)