Skip to content

Commit

Permalink
dco-win: support for data_v3 features
Browse files Browse the repository at this point in the history
Since version 1.4, dco-win drivere supports data_v3 features
such as:

 - AEAD tag at the end
 - 64bit pktid

We have to:

 - check in runtime if driver supports data_v3 features (we might be
 running with the older driver)

 - if those features are negotiated, we pass them to the driver
 as bit flags via the (newly added) NEW_KEY_V2 ioctl

Introduce NEW_KEY_V2 ioctl, which accepts a new OVPN_CRYPTO_DATA_V2
structure, which includes a field for bit flags for the new
crypto options.

Make dco_supports_data_v3() implementation platform-dependend (as it
should be) and indicate data_v3 support by dco-win if the driver version
is at least 1.4. Extend the Windows-specific struct dco_context and
store data_v3 support there so that when dco_new_key() is called, we
know which API to use.

Change the dco internal API and pass crypto options flags to dco_new_key().

Change-Id: I2e0c50d33f8a57c023120cf348f95d34acbfcde5
Signed-off-by: Lev Stipakov <[email protected]>
  • Loading branch information
lstipakov committed Aug 13, 2024
1 parent 88328c5 commit c2f1940
Show file tree
Hide file tree
Showing 8 changed files with 131 additions and 35 deletions.
2 changes: 1 addition & 1 deletion src/openvpn/dco.c
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ dco_install_key(struct tls_multi *multi, struct key_state *ks,
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++;
Expand Down
6 changes: 1 addition & 5 deletions src/openvpn/dco.h
Original file line number Diff line number Diff line change
Expand Up @@ -253,11 +253,7 @@ const char *dco_get_supported_ciphers(void);
* 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) */

Expand Down
13 changes: 10 additions & 3 deletions src/openvpn/dco_freebsd.c
Original file line number Diff line number Diff line change
Expand Up @@ -415,14 +415,14 @@ 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)
const char *ciphername, 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 %d",
__func__, slot, keyid, peerid, ciphername, co_flags);

nvl = nvlist_create(0);

Expand Down Expand Up @@ -778,4 +778,11 @@ dco_get_supported_ciphers(void)
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) */
2 changes: 1 addition & 1 deletion src/openvpn/dco_internal.h
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ 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);
const char *ciphername, int co_flags);

int dco_del_key(dco_context_t *dco, unsigned int peerid, dco_key_slot_t slot);

Expand Down
13 changes: 10 additions & 3 deletions src/openvpn/dco_linux.c
Original file line number Diff line number Diff line change
Expand Up @@ -557,10 +557,10 @@ 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)
const char *ciphername, 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 %d",
__func__, slot, keyid, peerid, ciphername, co_flags);

const size_t key_len = cipher_kt_key_size(ciphername);
const int nonce_tail_len = 8;
Expand Down Expand Up @@ -1058,4 +1058,11 @@ dco_get_supported_ciphers(void)
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) */
120 changes: 98 additions & 22 deletions src/openvpn/dco_win.c
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,9 @@ create_dco_handle(const char *devname, struct gc_arena *gc)
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;
}

Expand Down Expand Up @@ -291,47 +294,85 @@ dco_set_peer(dco_context_t *dco, unsigned int peerid,
return 0;
}

static int
dco_new_key_v1(HANDLE handle, OVPN_CRYPTO_DATA *crypto_data)
{
DWORD bytes_returned = 0;

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, 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)
const char *ciphername, 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 %d",
__func__, slot, keyid, peerid, ciphername, co_flags);

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));
OVPN_CRYPTO_DATA_V2 crypto_data_v2;
ZeroMemory(&crypto_data_v2, sizeof(crypto_data_v2));

crypto_data.CipherAlg = dco_get_cipher(ciphername);
crypto_data.KeyId = keyid;
crypto_data.PeerId = peerid;
crypto_data.KeySlot = slot;
OVPN_CRYPTO_DATA *crypto_data = &crypto_data_v2.V1;

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);
crypto_data->CipherAlg = dco_get_cipher(ciphername);
crypto_data->KeyId = keyid;
crypto_data->PeerId = peerid;
crypto_data->KeySlot = slot;

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);
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);

ASSERT(crypto_data.CipherAlg > 0);
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);

DWORD bytes_returned = 0;
ASSERT(crypto_data->CipherAlg > 0);

if (!DeviceIoControl(dco->tt->hand, OVPN_IOCTL_NEW_KEY, &crypto_data,
sizeof(crypto_data), NULL, 0, &bytes_returned, NULL))
if (dco->supports_data_v3)
{
msg(M_ERR, "DeviceIoControl(OVPN_IOCTL_NEW_KEY) failed");
return -1;
return dco_new_key_v2(dco->tt->hand, &crypto_data_v2, co_flags);
}
else
{
return dco_new_key_v1(dco->tt->hand, crypto_data);
}
return 0;
}

int
dco_del_key(dco_context_t *dco, unsigned int peerid, dco_key_slot_t slot)
{
Expand Down Expand Up @@ -494,4 +535,39 @@ dco_get_supported_ciphers()
}
}

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) */
1 change: 1 addition & 0 deletions src/openvpn/dco_win.h
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ typedef OVPN_CIPHER_ALG dco_cipher_t;

struct dco_context {
struct tuntap *tt;
bool supports_data_v3;
};

typedef struct dco_context dco_context_t;
Expand Down
9 changes: 9 additions & 0 deletions src/openvpn/ovpn_dco_win.h
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,14 @@ typedef struct _OVPN_CRYPTO_DATA {
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;
Expand All @@ -114,3 +122,4 @@ typedef struct _OVPN_VERSION {
#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)

0 comments on commit c2f1940

Please sign in to comment.