Add version number to handshake extension header
This commit is contained in:
parent
567cace5f8
commit
d5ab432941
5 changed files with 94 additions and 65 deletions
|
@ -2,21 +2,35 @@
|
||||||
// Copyright (C) 2018 Ludvig Strigeus <info@tunsafe.com>. All Rights Reserved.
|
// Copyright (C) 2018 Ludvig Strigeus <info@tunsafe.com>. All Rights Reserved.
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#define TUNSAFE_VERSION_STRING "TunSafe 1.5-rc1"
|
#define TUNSAFE_VERSION_STRING "TunSafe 1.5-rc2"
|
||||||
#define TUNSAFE_VERSION_STRING_LONG "TunSafe 1.5-rc1"
|
#define TUNSAFE_VERSION_STRING_LONG "TunSafe 1.5-rc2"
|
||||||
|
|
||||||
|
// Enable support for handshake extensions
|
||||||
#define WITH_HANDSHAKE_EXT 1
|
#define WITH_HANDSHAKE_EXT 1
|
||||||
#define WITH_CIPHER_SUITES 0
|
|
||||||
|
// Whether to enable the boolean features functionality
|
||||||
#define WITH_BOOLEAN_FEATURES 1
|
#define WITH_BOOLEAN_FEATURES 1
|
||||||
|
|
||||||
|
// Enable support for header obfuscation
|
||||||
|
#define WITH_HEADER_OBFUSCATION 1
|
||||||
|
|
||||||
|
// Enable support for two-factor authentication (requires WITH_HANDSHAKE_EXT)
|
||||||
|
#define WITH_TWO_FACTOR_AUTHENTICATION 1
|
||||||
|
|
||||||
|
// Whether to enable the short MAC feature, that uses an 8-byte MAC instead of 16-byte (Saves overhead)
|
||||||
|
#define WITH_SHORT_MAC 0
|
||||||
|
|
||||||
|
// Enable support for the keypair->compress_handler_ feature
|
||||||
#define WITH_PACKET_COMPRESSION 0
|
#define WITH_PACKET_COMPRESSION 0
|
||||||
|
|
||||||
|
// Enable support for short (down to 2 byte headers) instead of 16 bytes
|
||||||
#define WITH_SHORT_HEADERS 0
|
#define WITH_SHORT_HEADERS 0
|
||||||
#define WITH_HEADER_OBFUSCATION 1
|
|
||||||
|
// Enable support for alternative cipher suites
|
||||||
|
#define WITH_CIPHER_SUITES 0
|
||||||
|
|
||||||
#define WITH_AVX512_OPTIMIZATIONS 0
|
#define WITH_AVX512_OPTIMIZATIONS 0
|
||||||
#define WITH_BENCHMARK 0
|
#define WITH_BENCHMARK 0
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// Use bytell hashmap instead. Only works in 64-bit builds
|
// Use bytell hashmap instead. Only works in 64-bit builds
|
||||||
#define WITH_BYTELL_HASHMAP 0
|
#define WITH_BYTELL_HASHMAP 0
|
||||||
|
|
|
@ -15,10 +15,6 @@ enum {
|
||||||
WG_SESSION_AUTH_LEN = 16,
|
WG_SESSION_AUTH_LEN = 16,
|
||||||
};
|
};
|
||||||
|
|
||||||
enum {
|
|
||||||
WITH_TWO_FACTOR_AUTHENTICATION = 1,
|
|
||||||
};
|
|
||||||
|
|
||||||
class PluginPeer;
|
class PluginPeer;
|
||||||
class TunsafePluginImpl;
|
class TunsafePluginImpl;
|
||||||
|
|
||||||
|
@ -52,23 +48,21 @@ bool ExtFieldWriter::WriteField(uint8 code, const uint8 *data, uint32 size) {
|
||||||
}
|
}
|
||||||
|
|
||||||
enum {
|
enum {
|
||||||
kExtensionType_Padding = 0x00,
|
|
||||||
// The other peer has no way of identifying a specific instance of
|
// The other peer has no way of identifying a specific instance of
|
||||||
// a connection. There's no way to distinguish a periodic handshake from
|
// a connection. There's no way to distinguish a periodic handshake from
|
||||||
// a new client connection. Add a session ID to the Peer to solve this.
|
// a new client connection. Add a session ID to the Peer to solve this.
|
||||||
// We don't send the actual session id, instead we send:
|
// We don't send the actual session id, instead we send:
|
||||||
// Hash(plaintext ephemeral public key, session id)
|
// Hash(plaintext ephemeral public key, session id)
|
||||||
kExtensionType_SessionIDAuth = 0x01,
|
kExtensionType_SessionIDAuth = 0x20,
|
||||||
kExtensionType_SetSessionID = 0x02,
|
kExtensionType_SetSessionID = 0x21,
|
||||||
|
|
||||||
// This is sent by the server to request an additional token to allow
|
// This is sent by the server to request an additional token to allow
|
||||||
// login, for example a TOTP token, or a password.
|
// login, for example a TOTP token, or a password.
|
||||||
// By cleverly using session ids, the server can avoid having to request
|
// By cleverly using session ids, the server can avoid having to request
|
||||||
// this for every new handshake, even when roaming.
|
// this for every new handshake, even when roaming.
|
||||||
kExtensionType_TokenRequest = 0x03,
|
kExtensionType_TokenRequest = 0x22,
|
||||||
|
|
||||||
// This holds the token reply.
|
// This holds the token reply.
|
||||||
kExtensionType_TokenReply = 0x04,
|
kExtensionType_TokenReply = 0x23,
|
||||||
};
|
};
|
||||||
|
|
||||||
class TokenClientHandler {
|
class TokenClientHandler {
|
||||||
|
@ -597,6 +591,10 @@ uint32 TunsafePluginImpl::OnHandshake1(WgPeer *peer, const uint8 *ext, uint32 ex
|
||||||
PluginPeer *pp = GetPluginPeer(peer);
|
PluginPeer *pp = GetPluginPeer(peer);
|
||||||
ExtFieldWriter writer(extout, extout_size);
|
ExtFieldWriter writer(extout, extout_size);
|
||||||
|
|
||||||
|
// Skip the version
|
||||||
|
if (ext_size >= 4)
|
||||||
|
ext += 4, ext_size -= 4;
|
||||||
|
|
||||||
bool has_valid_session_id = false;
|
bool has_valid_session_id = false;
|
||||||
uint8 *token_reply = NULL;
|
uint8 *token_reply = NULL;
|
||||||
uint8 token_reply_size = 0;
|
uint8 token_reply_size = 0;
|
||||||
|
@ -639,6 +637,10 @@ uint32 TunsafePluginImpl::OnHandshake1(WgPeer *peer, const uint8 *ext, uint32 ex
|
||||||
uint32 TunsafePluginImpl::OnHandshake2(WgPeer *peer, const uint8 *ext, uint32 ext_size, const uint8 salt[WG_PUBLIC_KEY_LEN]) {
|
uint32 TunsafePluginImpl::OnHandshake2(WgPeer *peer, const uint8 *ext, uint32 ext_size, const uint8 salt[WG_PUBLIC_KEY_LEN]) {
|
||||||
PluginPeer *pp = GetPluginPeer(peer);
|
PluginPeer *pp = GetPluginPeer(peer);
|
||||||
|
|
||||||
|
// Skip the version
|
||||||
|
if (ext_size >= 4)
|
||||||
|
ext += 4, ext_size -= 4;
|
||||||
|
|
||||||
bool has_valid_session_id = false;
|
bool has_valid_session_id = false;
|
||||||
|
|
||||||
while (ext_size >= 2) {
|
while (ext_size >= 2) {
|
||||||
|
|
|
@ -54,19 +54,19 @@ static int ParseFeature(const char *str) {
|
||||||
else if (str[len - 1] == '!')
|
else if (str[len - 1] == '!')
|
||||||
what = WG_BOOLEAN_FEATURE_ENFORCES, len--;
|
what = WG_BOOLEAN_FEATURE_ENFORCES, len--;
|
||||||
}
|
}
|
||||||
if (len == 5 && memcmp(str, "mac64", 5) == 0)
|
if (WITH_SHORT_MAC && len == 5 && memcmp(str, "mac64", 5) == 0)
|
||||||
return what + WG_FEATURE_ID_SHORT_MAC * 16;
|
return what + WG_FEATURE_ID_SHORT_MAC * 16;
|
||||||
if (len == 5 && memcmp(str, "ipzip", 5) == 0)
|
if (WITH_PACKET_COMPRESSION && len == 5 && memcmp(str, "ipzip", 5) == 0)
|
||||||
return what + WG_FEATURE_ID_IPZIP * 16;
|
return what + WG_FEATURE_ID_IPZIP * 16;
|
||||||
if (len == 10 && memcmp(str, "hybrid_tcp", 10) == 0)
|
if (len == 10 && memcmp(str, "hybrid_tcp", 10) == 0)
|
||||||
return what + WG_FEATURE_HYBRID_TCP * 16;
|
return what + WG_FEATURE_HYBRID_TCP * 16;
|
||||||
if (len == 10 && memcmp(str, "skip_keyid", 10) == 0)
|
if (WITH_SHORT_HEADERS && len == 10 && memcmp(str, "skip_keyid", 10) == 0)
|
||||||
return what + WG_FEATURE_ID_SKIP_KEYID_IN * 16 + 1 * 4;
|
return what + WG_FEATURE_ID_SKIP_KEYID_IN * 16 + 1 * 4;
|
||||||
if (len == 12 && memcmp(str, "short_header", 12) == 0)
|
if (WITH_SHORT_HEADERS && len == 12 && memcmp(str, "short_header", 12) == 0)
|
||||||
return what + WG_FEATURE_ID_SHORT_HEADER * 16;
|
return what + WG_FEATURE_ID_SHORT_HEADER * 16;
|
||||||
if (len == 13 && memcmp(str, "skip_keyid_in", 13) == 0)
|
if (WITH_SHORT_HEADERS && len == 13 && memcmp(str, "skip_keyid_in", 13) == 0)
|
||||||
return what + WG_FEATURE_ID_SKIP_KEYID_IN * 16;
|
return what + WG_FEATURE_ID_SKIP_KEYID_IN * 16;
|
||||||
if (len == 14 && memcmp(str, "skip_keyid_out", 14) == 0)
|
if (WITH_SHORT_HEADERS && len == 14 && memcmp(str, "skip_keyid_out", 14) == 0)
|
||||||
return what + WG_FEATURE_ID_SKIP_KEYID_OUT * 16;
|
return what + WG_FEATURE_ID_SKIP_KEYID_OUT * 16;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
@ -171,9 +171,9 @@ bool WgFileParser::ParseFlag(const char *group, const char *key, char *value) {
|
||||||
}
|
}
|
||||||
|
|
||||||
wg_->SetInternetBlocking((InternetBlockState)v);
|
wg_->SetInternetBlocking((InternetBlockState)v);
|
||||||
} else if (strcmp(key, "ObfuscateKey") == 0) {
|
} else if (WITH_HEADER_OBFUSCATION && strcmp(key, "ObfuscateKey") == 0) {
|
||||||
wg_->dev().packet_obfuscator().SetKey((uint8*)value, strlen(value));
|
wg_->dev().packet_obfuscator().SetKey((uint8*)value, strlen(value));
|
||||||
} else if (strcmp(key, "ObfuscateTCP") == 0) {
|
} else if (WITH_HEADER_OBFUSCATION && strcmp(key, "ObfuscateTCP") == 0) {
|
||||||
bool flag;
|
bool flag;
|
||||||
int v = 1;
|
int v = 1;
|
||||||
if (ParseBoolean(value, &flag)) {
|
if (ParseBoolean(value, &flag)) {
|
||||||
|
|
|
@ -17,6 +17,10 @@
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
|
enum {
|
||||||
|
kTunsafeExtensionClientID = ('T' | 'S' << 8)
|
||||||
|
};
|
||||||
|
|
||||||
static const uint8 kLabelCookie[] = {'c', 'o', 'o', 'k', 'i', 'e', '-', '-'};
|
static const uint8 kLabelCookie[] = {'c', 'o', 'o', 'k', 'i', 'e', '-', '-'};
|
||||||
static const uint8 kLabelMac1[] = {'m', 'a', 'c', '1', '-', '-', '-', '-'};
|
static const uint8 kLabelMac1[] = {'m', 'a', 'c', '1', '-', '-', '-', '-'};
|
||||||
static const uint8 kWgInitHash[WG_HASH_LEN] = {0x22,0x11,0xb3,0x61,0x08,0x1a,0xc5,0x66,0x69,0x12,0x43,0xdb,0x45,0x8a,0xd5,0x32,0x2d,0x9c,0x6c,0x66,0x22,0x93,0xe8,0xb7,0x0e,0xe1,0x9c,0x65,0xba,0x07,0x9e,0xf3};
|
static const uint8 kWgInitHash[WG_HASH_LEN] = {0x22,0x11,0xb3,0x61,0x08,0x1a,0xc5,0x66,0x69,0x12,0x43,0xdb,0x45,0x8a,0xd5,0x32,0x2d,0x9c,0x6c,0x66,0x22,0x93,0xe8,0xb7,0x0e,0xe1,0x9c,0x65,0xba,0x07,0x9e,0xf3};
|
||||||
|
@ -346,7 +350,6 @@ WgPeer::WgPeer(WgDevice *dev) {
|
||||||
marked_for_delete_ = false;
|
marked_for_delete_ = false;
|
||||||
allow_multicast_through_peer_ = false;
|
allow_multicast_through_peer_ = false;
|
||||||
allow_endpoint_change_ = true;
|
allow_endpoint_change_ = true;
|
||||||
supports_handshake_extensions_ = true;
|
|
||||||
local_key_id_during_hs_ = 0;
|
local_key_id_during_hs_ = 0;
|
||||||
last_handshake_init_timestamp_ = -1000000ll;
|
last_handshake_init_timestamp_ = -1000000ll;
|
||||||
last_handshake_init_recv_timestamp_ = 0;
|
last_handshake_init_recv_timestamp_ = 0;
|
||||||
|
@ -545,15 +548,18 @@ void WgPeer::CreateMessageHandshakeInitiation(Packet *packet) {
|
||||||
|
|
||||||
|
|
||||||
int extfield_size = 0;
|
int extfield_size = 0;
|
||||||
if (WITH_HANDSHAKE_EXT && supports_handshake_extensions_)
|
if (WITH_HANDSHAKE_EXT) {
|
||||||
extfield_size = WriteHandshakeExtension(dst->timestamp_enc + WG_TIMESTAMP_LEN, NULL);
|
extfield_size = WriteHandshakeExtension(dst->timestamp_enc + WG_TIMESTAMP_LEN + 4, NULL);
|
||||||
|
|
||||||
if (dev_->plugin_) {
|
if (dev_->plugin_) {
|
||||||
uint32 rv = dev_->plugin_->OnHandshake0(this, dst->timestamp_enc + WG_TIMESTAMP_LEN + extfield_size, MAX_SIZE_OF_HANDSHAKE_EXTENSION - extfield_size, dst->ephemeral);
|
uint32 rv = dev_->plugin_->OnHandshake0(this, dst->timestamp_enc + WG_TIMESTAMP_LEN + 4 + extfield_size, MAX_SIZE_OF_HANDSHAKE_EXTENSION - 4 - extfield_size, dst->ephemeral);
|
||||||
assert(!(rv & WgPlugin::kHandshakeResponseFail));
|
assert(!(rv & WgPlugin::kHandshakeResponseFail));
|
||||||
extfield_size += rv;
|
extfield_size += rv;
|
||||||
}
|
}
|
||||||
|
if (extfield_size) {
|
||||||
|
WriteLE32(dst->timestamp_enc + WG_TIMESTAMP_LEN, kTunsafeExtensionClientID);
|
||||||
|
extfield_size += 4;
|
||||||
|
}
|
||||||
|
}
|
||||||
// msg.timestamp := AEAD(K, 0, timestamp, hi)
|
// msg.timestamp := AEAD(K, 0, timestamp, hi)
|
||||||
chacha20poly1305_encrypt(dst->timestamp_enc, dst->timestamp_enc, extfield_size + WG_TIMESTAMP_LEN, hs_.hi, sizeof(hs_.hi), 0, k);
|
chacha20poly1305_encrypt(dst->timestamp_enc, dst->timestamp_enc, extfield_size + WG_TIMESTAMP_LEN, hs_.hi, sizeof(hs_.hi), 0, k);
|
||||||
// Hi := HASH(Hi || msg.timestamp)
|
// Hi := HASH(Hi || msg.timestamp)
|
||||||
|
@ -619,7 +625,7 @@ WgPeer *WgPeer::ParseMessageHandshakeInitiation(WgDevice *dev, Packet *packet) {
|
||||||
// Hi2 := Hi
|
// Hi2 := Hi
|
||||||
memcpy(hi2, hi, sizeof(hi2));
|
memcpy(hi2, hi, sizeof(hi2));
|
||||||
extfield_size = packet->size - sizeof(MessageHandshakeInitiation);
|
extfield_size = packet->size - sizeof(MessageHandshakeInitiation);
|
||||||
if ((uint32)extfield_size > MAX_SIZE_OF_HANDSHAKE_EXTENSION || (extfield_size && !peer->supports_handshake_extensions_))
|
if ((uint32)extfield_size > MAX_SIZE_OF_HANDSHAKE_EXTENSION)
|
||||||
goto getout;
|
goto getout;
|
||||||
// Hi := HASH(Hi || msg.timestamp)
|
// Hi := HASH(Hi || msg.timestamp)
|
||||||
BlakeMix(hi, src->timestamp_enc, extfield_size + WG_TIMESTAMP_LEN + WG_MAC_LEN);
|
BlakeMix(hi, src->timestamp_enc, extfield_size + WG_TIMESTAMP_LEN + WG_MAC_LEN);
|
||||||
|
@ -668,19 +674,23 @@ WgPeer *WgPeer::ParseMessageHandshakeInitiation(WgDevice *dev, Packet *packet) {
|
||||||
|
|
||||||
int extfield_out_size = 0;
|
int extfield_out_size = 0;
|
||||||
if (WITH_HANDSHAKE_EXT && extfield_size)
|
if (WITH_HANDSHAKE_EXT && extfield_size)
|
||||||
extfield_out_size = peer->WriteHandshakeExtension(dst->empty_enc, keypair);
|
extfield_out_size = peer->WriteHandshakeExtension(dst->empty_enc + 4, keypair);
|
||||||
|
|
||||||
// Allow plugin to determine what to do with the packet,
|
// Allow plugin to determine what to do with the packet,
|
||||||
// it can append new headers to the response, and decide what to do.
|
// it can append new headers to the response, and decide what to do.
|
||||||
if (dev->plugin_) {
|
if (WITH_HANDSHAKE_EXT && dev->plugin_) {
|
||||||
uint32 rv = dev->plugin_->OnHandshake1(peer, extbuf + WG_TIMESTAMP_LEN, extfield_size, e_remote,
|
uint32 rv = dev->plugin_->OnHandshake1(peer, extbuf + WG_TIMESTAMP_LEN, extfield_size, e_remote,
|
||||||
dst->empty_enc + extfield_out_size, MAX_SIZE_OF_HANDSHAKE_EXTENSION - extfield_out_size, dst->ephemeral);
|
dst->empty_enc + 4 + extfield_out_size, MAX_SIZE_OF_HANDSHAKE_EXTENSION - 4 - extfield_out_size, dst->ephemeral);
|
||||||
if (rv == WgPlugin::kHandshakeResponseDrop)
|
if (rv == WgPlugin::kHandshakeResponseDrop)
|
||||||
goto getout;
|
goto getout;
|
||||||
if (rv & WgPlugin::kHandshakeResponseFail)
|
if (rv & WgPlugin::kHandshakeResponseFail)
|
||||||
delete exch_null(keypair);
|
delete exch_null(keypair);
|
||||||
extfield_out_size += rv & ~WgPlugin::kHandshakeResponseFail;
|
extfield_out_size += rv & ~WgPlugin::kHandshakeResponseFail;
|
||||||
}
|
}
|
||||||
|
if (extfield_out_size) {
|
||||||
|
WriteLE32(dst->empty_enc, kTunsafeExtensionClientID);
|
||||||
|
extfield_out_size += 4;
|
||||||
|
}
|
||||||
|
|
||||||
dst->sender_key_id = keypair ? dev->InsertInKeyIdLookup(peer, keypair) : 0;
|
dst->sender_key_id = keypair ? dev->InsertInKeyIdLookup(peer, keypair) : 0;
|
||||||
|
|
||||||
|
@ -764,7 +774,7 @@ WgPeer *WgPeer::ParseMessageHandshakeResponse(WgDevice *dev, const Packet *packe
|
||||||
|
|
||||||
// Allow plugin to determine what to do with the packet,
|
// Allow plugin to determine what to do with the packet,
|
||||||
// it can append new headers to the response, and decide what to do.
|
// it can append new headers to the response, and decide what to do.
|
||||||
if (dev->plugin_) {
|
if (WITH_HANDSHAKE_EXT && dev->plugin_) {
|
||||||
uint32 rv = dev->plugin_->OnHandshake2(peer, src->empty_enc, extfield_size, src->ephemeral);
|
uint32 rv = dev->plugin_->OnHandshake2(peer, src->empty_enc, extfield_size, src->ephemeral);
|
||||||
if (rv & WgPlugin::kHandshakeResponseFail) {
|
if (rv & WgPlugin::kHandshakeResponseFail) {
|
||||||
delete keypair;
|
delete keypair;
|
||||||
|
@ -841,7 +851,7 @@ int WgPeer::WriteHandshakeExtension(uint8 *dst, WgKeypair *keypair) {
|
||||||
uint8 value = 0;
|
uint8 value = 0;
|
||||||
// Include the supported features extension
|
// Include the supported features extension
|
||||||
if (!IsOnlyZeros(features_, sizeof(features_))) {
|
if (!IsOnlyZeros(features_, sizeof(features_))) {
|
||||||
*dst++ = EXT_BOOLEAN_FEATURES;
|
*dst++ = kExtensionType_Booleans;
|
||||||
*dst++ = (WG_FEATURES_COUNT + 3) >> 2;
|
*dst++ = (WG_FEATURES_COUNT + 3) >> 2;
|
||||||
for (size_t i = 0; i != WG_FEATURES_COUNT; i++) {
|
for (size_t i = 0; i != WG_FEATURES_COUNT; i++) {
|
||||||
if ((i & 3) == 0)
|
if ((i & 3) == 0)
|
||||||
|
@ -857,7 +867,7 @@ int WgPeer::WriteHandshakeExtension(uint8 *dst, WgKeypair *keypair) {
|
||||||
// Ordered list of cipher suites
|
// Ordered list of cipher suites
|
||||||
size_t ciphers = num_ciphers_;
|
size_t ciphers = num_ciphers_;
|
||||||
if (ciphers) {
|
if (ciphers) {
|
||||||
*dst++ = EXT_CIPHER_SUITES + cipher_prio_;
|
*dst++ = kExtensionType_CipherSuites + cipher_prio_;
|
||||||
if (keypair) {
|
if (keypair) {
|
||||||
*dst++ = 1;
|
*dst++ = 1;
|
||||||
*dst++ = keypair->cipher_suite;
|
*dst++ = keypair->cipher_suite;
|
||||||
|
@ -928,7 +938,14 @@ void WgPeer::DeleteKeypair(WgKeypair **kp) {
|
||||||
}
|
}
|
||||||
|
|
||||||
bool WgPeer::ParseExtendedHandshake(WgKeypair *kp, const uint8 *data, size_t data_size) {
|
bool WgPeer::ParseExtendedHandshake(WgKeypair *kp, const uint8 *data, size_t data_size) {
|
||||||
assert(WITH_HANDSHAKE_EXT);
|
// Empty handshake is always OK
|
||||||
|
if (data_size == 0)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
// The first four bytes contain a client ID and major, minor version
|
||||||
|
if (data_size < 4 || (ReadLE32(data) & 0xFFFFFF) != kTunsafeExtensionClientID)
|
||||||
|
return false;
|
||||||
|
data += 4, data_size -= 4;
|
||||||
|
|
||||||
while (data_size >= 2) {
|
while (data_size >= 2) {
|
||||||
uint8 type = data[0], size = data[1];
|
uint8 type = data[0], size = data[1];
|
||||||
|
@ -936,15 +953,15 @@ bool WgPeer::ParseExtendedHandshake(WgKeypair *kp, const uint8 *data, size_t dat
|
||||||
if (size > data_size)
|
if (size > data_size)
|
||||||
return false;
|
return false;
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case EXT_CIPHER_SUITES_PRIO:
|
case kExtensionType_CipherSuitesPrio:
|
||||||
case EXT_CIPHER_SUITES:
|
case kExtensionType_CipherSuites:
|
||||||
if (WITH_CIPHER_SUITES) {
|
if (WITH_CIPHER_SUITES) {
|
||||||
kp->cipher_suite = ResolveCipherSuite(cipher_prio_ - (type - EXT_CIPHER_SUITES),
|
kp->cipher_suite = ResolveCipherSuite(cipher_prio_ - (type - kExtensionType_CipherSuites),
|
||||||
ciphers_, num_ciphers_, data, size);
|
ciphers_, num_ciphers_, data, size);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case EXT_BOOLEAN_FEATURES:
|
case kExtensionType_Booleans:
|
||||||
if (WITH_BOOLEAN_FEATURES) {
|
if (WITH_BOOLEAN_FEATURES) {
|
||||||
for (uint32 i = 0, j = std::max<uint32>(WG_FEATURES_COUNT, size * 4); i != j; i++) {
|
for (uint32 i = 0, j = std::max<uint32>(WG_FEATURES_COUNT, size * 4); i != j; i++) {
|
||||||
uint8 value = (i < (uint32)size * 4) ? (data[i >> 2] >> ((i * 2) & 7)) & 3 : 0;
|
uint8 value = (i < (uint32)size * 4) ? (data[i >> 2] >> ((i * 2) & 7)) & 3 : 0;
|
||||||
|
@ -960,10 +977,8 @@ bool WgPeer::ParseExtendedHandshake(WgKeypair *kp, const uint8 *data, size_t dat
|
||||||
if (data_size != 0)
|
if (data_size != 0)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (WITH_BOOLEAN_FEATURES)
|
if (WITH_BOOLEAN_FEATURES && WITH_SHORT_MAC)
|
||||||
kp->auth_tag_length = (kp->enabled_features[WG_FEATURE_ID_SHORT_MAC] ? 8 : CHACHA20POLY1305_AUTHTAGLEN);
|
kp->auth_tag_length = (kp->enabled_features[WG_FEATURE_ID_SHORT_MAC] ? 8 : CHACHA20POLY1305_AUTHTAGLEN);
|
||||||
return true;
|
|
||||||
|
|
||||||
|
|
||||||
if (WITH_CIPHER_SUITES && kp->cipher_suite >= EXT_CIPHER_SUITE_AES128_GCM && kp->cipher_suite <= EXT_CIPHER_SUITE_AES256_GCM) {
|
if (WITH_CIPHER_SUITES && kp->cipher_suite >= EXT_CIPHER_SUITE_AES128_GCM && kp->cipher_suite <= EXT_CIPHER_SUITE_AES256_GCM) {
|
||||||
#if WITH_AESGCM
|
#if WITH_AESGCM
|
||||||
|
@ -978,6 +993,7 @@ bool WgPeer::ParseExtendedHandshake(WgKeypair *kp, const uint8 *data, size_t dat
|
||||||
#endif // WITH_AESGCM
|
#endif // WITH_AESGCM
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
WgKeypair *WgPeer::CreateNewKeypair(bool is_initiator, const uint8 chaining_key[WG_HASH_LEN], uint32 remote_key_id) {
|
WgKeypair *WgPeer::CreateNewKeypair(bool is_initiator, const uint8 chaining_key[WG_HASH_LEN], uint32 remote_key_id) {
|
||||||
|
@ -1157,12 +1173,13 @@ void WgPeer::OnHandshakeFullyComplete() {
|
||||||
for(size_t i = 0; i < WG_FEATURES_COUNT; i++)
|
for(size_t i = 0; i < WG_FEATURES_COUNT; i++)
|
||||||
any_feature |= curr_keypair_->enabled_features[i];
|
any_feature |= curr_keypair_->enabled_features[i];
|
||||||
if (curr_keypair_->cipher_suite != 0 || any_feature) {
|
if (curr_keypair_->cipher_suite != 0 || any_feature) {
|
||||||
RINFO("Using %s, %s %s %s %s %s", kCipherSuites[curr_keypair_->cipher_suite],
|
RINFO("Using %s%s%s%s%s%s%s", kCipherSuites[curr_keypair_->cipher_suite],
|
||||||
curr_keypair_->enabled_features[0] ? "short_header" : "",
|
curr_keypair_->enabled_features[WG_FEATURE_ID_SHORT_HEADER] ? ", short_header" : "",
|
||||||
curr_keypair_->enabled_features[1] ? "mac64" : "",
|
curr_keypair_->enabled_features[WG_FEATURE_ID_SHORT_MAC] ? ", mac64" : "",
|
||||||
curr_keypair_->enabled_features[2] ? "ipzip" : "",
|
curr_keypair_->enabled_features[WG_FEATURE_ID_IPZIP] ? ", ipzip" : "",
|
||||||
curr_keypair_->enabled_features[4] ? "skip_keyid_in" : "",
|
curr_keypair_->enabled_features[WG_FEATURE_ID_SKIP_KEYID_IN] ? ", skip_keyid_in" : "",
|
||||||
curr_keypair_->enabled_features[5] ? "skip_keyid_out" : "");
|
curr_keypair_->enabled_features[WG_FEATURE_ID_SKIP_KEYID_OUT] ? ", skip_keyid_out" : "",
|
||||||
|
curr_keypair_->enabled_features[WG_FEATURE_HYBRID_TCP] ? ", hybrid_tcp" : "");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
last_complete_handskake_timestamp_ = now;
|
last_complete_handskake_timestamp_ = now;
|
||||||
|
@ -1572,7 +1589,7 @@ void WgPacketObfuscator::ObfuscatePacket(Packet *packet) {
|
||||||
assert(data_size >= 48);
|
assert(data_size >= 48);
|
||||||
data[35 + packet_type * 4] ^= data[15];
|
data[35 + packet_type * 4] ^= data[15];
|
||||||
}
|
}
|
||||||
packet->size = data_size = InsertRandomBytesIntoPacket(data, data_size);
|
packet->size = (uint)(data_size = InsertRandomBytesIntoPacket(data, data_size));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Scramble the header bytes of the packet
|
// Scramble the header bytes of the packet
|
||||||
|
|
|
@ -165,10 +165,10 @@ struct MessageData {
|
||||||
STATIC_ASSERT(sizeof(MessageData) == 16, MessageData_wrong_size);
|
STATIC_ASSERT(sizeof(MessageData) == 16, MessageData_wrong_size);
|
||||||
|
|
||||||
enum {
|
enum {
|
||||||
EXT_BOOLEAN_FEATURES = 0x16,
|
kExtensionType_Padding = 0x00,
|
||||||
|
kExtensionType_Booleans = 0x01,
|
||||||
EXT_CIPHER_SUITES = 0x18,
|
kExtensionType_CipherSuites = 0x02,
|
||||||
EXT_CIPHER_SUITES_PRIO = 0x19,
|
kExtensionType_CipherSuitesPrio = 0x03,
|
||||||
|
|
||||||
// The standard wireguard chacha
|
// The standard wireguard chacha
|
||||||
EXT_CIPHER_SUITE_CHACHA20POLY1305 = 0x00,
|
EXT_CIPHER_SUITE_CHACHA20POLY1305 = 0x00,
|
||||||
|
@ -180,7 +180,6 @@ enum {
|
||||||
EXT_CIPHER_SUITE_NONE_POLY1305 = 0x03,
|
EXT_CIPHER_SUITE_NONE_POLY1305 = 0x03,
|
||||||
|
|
||||||
EXT_CIPHER_SUITE_COUNT = 4,
|
EXT_CIPHER_SUITE_COUNT = 4,
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
enum {
|
enum {
|
||||||
|
@ -610,9 +609,6 @@ private:
|
||||||
// from being sent out over the VPN link.
|
// from being sent out over the VPN link.
|
||||||
uint32 ipv4_broadcast_addr_;
|
uint32 ipv4_broadcast_addr_;
|
||||||
|
|
||||||
// Whether the tunsafe specific handshake extensions are supported
|
|
||||||
bool supports_handshake_extensions_;
|
|
||||||
|
|
||||||
// Whether any data was sent since the keepalive timer was set
|
// Whether any data was sent since the keepalive timer was set
|
||||||
bool pending_keepalive_;
|
bool pending_keepalive_;
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue