mirror of
https://github.com/SoftEtherVPN/SoftEtherVPN.git
synced 2024-11-26 19:39:53 +03:00
Merge PR #796: Cedar/Proto_OpenVPN: add support for GCM ciphers
This commit is contained in:
commit
ba930668ba
@ -176,88 +176,131 @@ void OvsLog(OPENVPN_SERVER *s, OPENVPN_SESSION *se, OPENVPN_CHANNEL *c, char *na
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Encrypt the data
|
// Encrypt the data
|
||||||
UINT OvsEncrypt(CIPHER *cipher, MD *md, UCHAR *iv, UCHAR *dest, UCHAR *src, UINT size)
|
UINT OvsEncrypt(CIPHER *cipher, MD *md, UCHAR *iv, UCHAR *tag, UCHAR *dest, UCHAR *src, UINT src_size, UCHAR *aad, UINT aad_size)
|
||||||
{
|
{
|
||||||
UINT dest_size, ret;
|
|
||||||
// Validate arguments
|
// Validate arguments
|
||||||
if (cipher == NULL || md == NULL)
|
if (cipher == NULL || (cipher->IsAeadCipher == false && md == NULL))
|
||||||
{
|
{
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Encrypt
|
if (cipher->IsAeadCipher)
|
||||||
dest_size = CipherProcess(cipher, iv, dest + md->Size + cipher->IvSize, src, size);
|
|
||||||
if (dest_size == 0)
|
|
||||||
{
|
{
|
||||||
Debug("OvsEncrypt(): CipherProcess() failed!\n");
|
// Encrypt in AEAD mode (no HMAC)
|
||||||
return 0;
|
UINT dest_size = CipherProcessAead(cipher, iv, tag, 16, dest, src, src_size, aad, aad_size);
|
||||||
|
if (dest_size == 0)
|
||||||
|
{
|
||||||
|
Debug("OvsEncrypt(): CipherProcessAead() failed!\n");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return dest_size;
|
||||||
}
|
}
|
||||||
|
else
|
||||||
// Copy the IV
|
|
||||||
Copy(dest + md->Size, iv, cipher->IvSize);
|
|
||||||
dest_size += cipher->IvSize;
|
|
||||||
|
|
||||||
// Calculate the HMAC
|
|
||||||
ret = MdProcess(md, dest, dest + md->Size, dest_size);
|
|
||||||
if (ret == 0)
|
|
||||||
{
|
{
|
||||||
Debug("OvsEncrypt(): MdProcess() failed!\n");
|
// Encrypt in non-AEAD mode (with HMAC)
|
||||||
return 0;
|
UINT ret;
|
||||||
}
|
UINT dest_size = CipherProcess(cipher, iv, dest + md->Size + cipher->IvSize, src, src_size);
|
||||||
|
if (dest_size == 0)
|
||||||
|
{
|
||||||
|
Debug("OvsEncrypt(): CipherProcess() failed!\n");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
return dest_size + ret;
|
// Copy the IV
|
||||||
|
Copy(dest + md->Size, iv, cipher->IvSize);
|
||||||
|
dest_size += cipher->IvSize;
|
||||||
|
|
||||||
|
// Calculate the HMAC
|
||||||
|
ret = MdProcess(md, dest, dest + md->Size, dest_size);
|
||||||
|
if (ret == 0)
|
||||||
|
{
|
||||||
|
Debug("OvsEncrypt(): MdProcess() failed!\n");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return dest_size + ret;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Decrypt the data
|
// Decrypt the data
|
||||||
UINT OvsDecrypt(CIPHER *cipher, MD *md, UCHAR *dest, UCHAR *src, UINT size)
|
UINT OvsDecrypt(CIPHER *cipher, MD *md, UCHAR *iv, UCHAR *dest, UCHAR *src, UINT size)
|
||||||
{
|
{
|
||||||
UCHAR *hmac;
|
|
||||||
UCHAR *iv;
|
|
||||||
UCHAR hmac_test[128];
|
|
||||||
// Validate arguments
|
// Validate arguments
|
||||||
if (cipher == NULL || md == NULL)
|
if (cipher == NULL)
|
||||||
{
|
{
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (size < (md->Size + cipher->IvSize + sizeof(UINT)))
|
if (cipher->IsAeadCipher)
|
||||||
{
|
{
|
||||||
return 0;
|
UCHAR *tag = src;
|
||||||
}
|
|
||||||
|
|
||||||
// HMAC
|
if (iv == NULL || size <= OPENVPN_TAG_SIZE)
|
||||||
hmac = src;
|
|
||||||
src += md->Size;
|
|
||||||
size -= md->Size;
|
|
||||||
|
|
||||||
if (MdProcess(md, hmac_test, src, size) == 0)
|
|
||||||
{
|
|
||||||
Debug("OvsDecrypt(): MdProcess() failed!\n");
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (Cmp(hmac_test, hmac, md->Size) != 0)
|
|
||||||
{
|
|
||||||
Debug("OvsDecrypt(): HMAC verification failed!\n");
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
// IV
|
|
||||||
iv = src;
|
|
||||||
src += cipher->IvSize;
|
|
||||||
size -= cipher->IvSize;
|
|
||||||
|
|
||||||
// Payload
|
|
||||||
if (size >= 1 && (cipher->BlockSize == 0 || (size % cipher->BlockSize) == 0))
|
|
||||||
{
|
|
||||||
// Decryption
|
|
||||||
UINT ret = CipherProcess(cipher, iv, dest, src, size);
|
|
||||||
if (ret == 0)
|
|
||||||
{
|
{
|
||||||
Debug("OvsDecrypt(): CipherProcess() failed!\n");
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
return ret;
|
src += OPENVPN_TAG_SIZE;
|
||||||
|
size -= OPENVPN_TAG_SIZE;
|
||||||
|
|
||||||
|
// Payload
|
||||||
|
if (size >= 1 && (cipher->BlockSize == 0 || (size % cipher->BlockSize) == 0))
|
||||||
|
{
|
||||||
|
// Decryption
|
||||||
|
UINT ret = CipherProcessAead(cipher, iv, tag, OPENVPN_TAG_SIZE, dest, src, size, iv, sizeof(UINT));
|
||||||
|
if (ret == 0)
|
||||||
|
{
|
||||||
|
Debug("OvsDecrypt(): CipherProcessAead() failed!\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
UCHAR *hmac;
|
||||||
|
UCHAR hmac_test[128];
|
||||||
|
|
||||||
|
if (md == NULL || iv == NULL || size < (md->Size + cipher->IvSize + sizeof(UINT)))
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// HMAC
|
||||||
|
hmac = src;
|
||||||
|
src += md->Size;
|
||||||
|
size -= md->Size;
|
||||||
|
|
||||||
|
if (MdProcess(md, hmac_test, src, size) == 0)
|
||||||
|
{
|
||||||
|
Debug("OvsDecrypt(): MdProcess() failed!\n");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Cmp(hmac_test, hmac, md->Size) != 0)
|
||||||
|
{
|
||||||
|
Debug("OvsDecrypt(): HMAC verification failed!\n");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// IV
|
||||||
|
Copy(iv, src, cipher->IvSize);
|
||||||
|
src += cipher->IvSize;
|
||||||
|
size -= cipher->IvSize;
|
||||||
|
|
||||||
|
// Payload
|
||||||
|
if (size >= 1 && (cipher->BlockSize == 0 || (size % cipher->BlockSize) == 0))
|
||||||
|
{
|
||||||
|
// Decryption
|
||||||
|
UINT ret = CipherProcess(cipher, iv, dest, src, size);
|
||||||
|
if (ret == 0)
|
||||||
|
{
|
||||||
|
Debug("OvsDecrypt(): CipherProcess() failed!\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
@ -373,32 +416,42 @@ void OvsProceccRecvPacket(OPENVPN_SERVER *s, UDPPACKET *p, UINT protocol)
|
|||||||
OPENVPN_CHANNEL *c = se->Channels[recv_packet->KeyId];
|
OPENVPN_CHANNEL *c = se->Channels[recv_packet->KeyId];
|
||||||
if (c->Status == OPENVPN_CHANNEL_STATUS_ESTABLISHED)
|
if (c->Status == OPENVPN_CHANNEL_STATUS_ESTABLISHED)
|
||||||
{
|
{
|
||||||
UINT size = OvsDecrypt(c->CipherDecrypt, c->MdRecv, s->TmpBuf, recv_packet->Data, recv_packet->DataSize);
|
UINT size;
|
||||||
if (size >= sizeof(UINT))
|
UCHAR *data = s->TmpBuf;
|
||||||
|
if (c->CipherDecrypt->IsAeadCipher)
|
||||||
{
|
{
|
||||||
UCHAR *data = s->TmpBuf;
|
// Update variable part (packet ID) of IV
|
||||||
|
Copy(c->IvRecv, recv_packet->Data, sizeof(recv_packet->PacketId));
|
||||||
|
|
||||||
// Update of last communication time
|
// Decrypt
|
||||||
se->LastCommTick = s->Now;
|
size = OvsDecrypt(c->CipherDecrypt, NULL, c->IvRecv, data, recv_packet->Data + sizeof(UINT), recv_packet->DataSize - sizeof(UINT));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Decrypt
|
||||||
|
size = OvsDecrypt(c->CipherDecrypt, c->MdRecv, c->IvRecv, data, recv_packet->Data, recv_packet->DataSize);
|
||||||
|
|
||||||
// Seek buffer after the packet ID
|
// Seek buffer after the packet ID
|
||||||
data += sizeof(UINT);
|
data += sizeof(UINT);
|
||||||
size -= sizeof(UINT);
|
size -= sizeof(UINT);
|
||||||
|
}
|
||||||
|
|
||||||
if (size < sizeof(ping_signature) || Cmp(data, ping_signature, sizeof(ping_signature)) != 0)
|
// Update of last communication time
|
||||||
|
se->LastCommTick = s->Now;
|
||||||
|
|
||||||
|
if (size < sizeof(ping_signature) || Cmp(data, ping_signature, sizeof(ping_signature)) != 0)
|
||||||
|
{
|
||||||
|
// Receive a packet!
|
||||||
|
if (se->Ipc != NULL)
|
||||||
{
|
{
|
||||||
// Receive a packet!
|
switch (se->Mode)
|
||||||
if (se->Ipc != NULL)
|
|
||||||
{
|
{
|
||||||
switch (se->Mode)
|
case OPENVPN_MODE_L2: // Send an Ethernet packet to a session
|
||||||
{
|
IPCSendL2(se->Ipc, data, size);
|
||||||
case OPENVPN_MODE_L2: // Send an Ethernet packet to a session
|
break;
|
||||||
IPCSendL2(se->Ipc, data, size);
|
case OPENVPN_MODE_L3: // Send an IPv4 packet to a session
|
||||||
break;
|
IPCSendIPv4(se->Ipc, data, size);
|
||||||
case OPENVPN_MODE_L3: // Send an IPv4 packet to a session
|
break;
|
||||||
IPCSendIPv4(se->Ipc, data, size);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -818,7 +871,7 @@ void OvsSetupSessionParameters(OPENVPN_SERVER *s, OPENVPN_SESSION *se, OPENVPN_C
|
|||||||
LIST *o;
|
LIST *o;
|
||||||
BUF *b;
|
BUF *b;
|
||||||
char opt_str[MAX_SIZE];
|
char opt_str[MAX_SIZE];
|
||||||
char *cipher_name;
|
char *cipher_name, *md_name;
|
||||||
// Validate arguments
|
// Validate arguments
|
||||||
if (s == NULL || se == NULL || c == NULL || data == NULL)
|
if (s == NULL || se == NULL || c == NULL || data == NULL)
|
||||||
{
|
{
|
||||||
@ -897,7 +950,6 @@ void OvsSetupSessionParameters(OPENVPN_SERVER *s, OPENVPN_SESSION *se, OPENVPN_C
|
|||||||
if (se->Protocol == OPENVPN_PROTOCOL_TCP)
|
if (se->Protocol == OPENVPN_PROTOCOL_TCP)
|
||||||
{
|
{
|
||||||
// TCP
|
// TCP
|
||||||
// UDP
|
|
||||||
if (IsIP6(&se->ClientIp) == false)
|
if (IsIP6(&se->ClientIp) == false)
|
||||||
{
|
{
|
||||||
StrCpy(c->Proto, sizeof(c->Proto), "TCPv4_SERVER");
|
StrCpy(c->Proto, sizeof(c->Proto), "TCPv4_SERVER");
|
||||||
@ -922,12 +974,9 @@ void OvsSetupSessionParameters(OPENVPN_SERVER *s, OPENVPN_SESSION *se, OPENVPN_C
|
|||||||
|
|
||||||
// Encryption algorithm
|
// Encryption algorithm
|
||||||
cipher_name = EntryListStrValue(o, "cipher");
|
cipher_name = EntryListStrValue(o, "cipher");
|
||||||
c->CipherEncrypt = OvsGetCipher(cipher_name);
|
|
||||||
c->CipherDecrypt = OvsGetCipher(cipher_name);
|
|
||||||
|
|
||||||
// Hash algorithm
|
// Hash algorithm
|
||||||
c->MdSend = OvsGetMd(EntryListStrValue(o, "auth"));
|
md_name = EntryListStrValue(o, "auth");
|
||||||
c->MdRecv = NewMd(c->MdSend->Name);
|
|
||||||
|
|
||||||
// Random number generation
|
// Random number generation
|
||||||
Rand(c->ServerKey.Random1, sizeof(c->ServerKey.Random1));
|
Rand(c->ServerKey.Random1, sizeof(c->ServerKey.Random1));
|
||||||
@ -954,13 +1003,26 @@ void OvsSetupSessionParameters(OPENVPN_SERVER *s, OPENVPN_SESSION *se, OPENVPN_C
|
|||||||
c->ExpansionKey, sizeof(c->ExpansionKey));
|
c->ExpansionKey, sizeof(c->ExpansionKey));
|
||||||
FreeBuf(b);
|
FreeBuf(b);
|
||||||
|
|
||||||
// Set the key
|
// Set up the encryption algorithm
|
||||||
|
c->CipherEncrypt = OvsGetCipher(cipher_name);
|
||||||
|
c->CipherDecrypt = OvsGetCipher(cipher_name);
|
||||||
SetCipherKey(c->CipherDecrypt, c->ExpansionKey + 0, false);
|
SetCipherKey(c->CipherDecrypt, c->ExpansionKey + 0, false);
|
||||||
SetCipherKey(c->CipherEncrypt, c->ExpansionKey + 128, true);
|
SetCipherKey(c->CipherEncrypt, c->ExpansionKey + 128, true);
|
||||||
SetMdKey(c->MdRecv, c->ExpansionKey + 64, c->MdRecv->Size);
|
|
||||||
SetMdKey(c->MdSend, c->ExpansionKey + 192, c->MdSend->Size);
|
|
||||||
|
|
||||||
FreeEntryList(o);
|
if (c->CipherDecrypt->IsAeadCipher)
|
||||||
|
{
|
||||||
|
// In AEAD mode the IV is composed by the packet ID and a part of the HMAC key
|
||||||
|
Copy(c->IvRecv + sizeof(c->LastDataPacketId), c->ExpansionKey + 64, c->CipherDecrypt->IvSize - sizeof(c->LastDataPacketId));
|
||||||
|
Copy(c->IvSend + sizeof(c->LastDataPacketId), c->ExpansionKey + 192, c->CipherEncrypt->IvSize - sizeof(c->LastDataPacketId));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Set up the hash algorithm
|
||||||
|
c->MdSend = OvsGetMd(md_name);
|
||||||
|
c->MdRecv = OvsGetMd(md_name);
|
||||||
|
SetMdKey(c->MdRecv, c->ExpansionKey + 64, c->MdRecv->Size);
|
||||||
|
SetMdKey(c->MdSend, c->ExpansionKey + 192, c->MdSend->Size);
|
||||||
|
}
|
||||||
|
|
||||||
// We pass the cipher name sent from the OpenVPN client, unless it's a different cipher, to prevent a message such as:
|
// We pass the cipher name sent from the OpenVPN client, unless it's a different cipher, to prevent a message such as:
|
||||||
// WARNING: 'cipher' is used inconsistently, local='cipher AES-128-GCM', remote='cipher aes-128-gcm'
|
// WARNING: 'cipher' is used inconsistently, local='cipher AES-128-GCM', remote='cipher aes-128-gcm'
|
||||||
@ -979,9 +1041,11 @@ void OvsSetupSessionParameters(OPENVPN_SERVER *s, OPENVPN_SESSION *se, OPENVPN_C
|
|||||||
se->LinkMtu,
|
se->LinkMtu,
|
||||||
se->TunMtu,
|
se->TunMtu,
|
||||||
c->Proto,
|
c->Proto,
|
||||||
cipher_name, c->MdSend->Name, c->CipherEncrypt->KeySize * 8);
|
cipher_name, md_name, c->CipherEncrypt->KeySize * 8);
|
||||||
Debug("Building OptionStr: %s\n", c->ServerKey.OptionString);
|
|
||||||
|
|
||||||
|
FreeEntryList(o);
|
||||||
|
|
||||||
|
Debug("OvsSetupSessionParameters(): Built OptionString: %s\n", c->ServerKey.OptionString);
|
||||||
OvsLog(s, se, c, "LO_OPTION_STR_SEND", c->ServerKey.OptionString);
|
OvsLog(s, se, c, "LO_OPTION_STR_SEND", c->ServerKey.OptionString);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1379,7 +1443,8 @@ OPENVPN_CHANNEL *OvsNewChannel(OPENVPN_SESSION *se, UCHAR key_id)
|
|||||||
|
|
||||||
c->KeyId = key_id;
|
c->KeyId = key_id;
|
||||||
|
|
||||||
Rand(c->NextIv, sizeof(c->NextIv));
|
Rand(c->IvSend, sizeof(c->IvSend));
|
||||||
|
Rand(c->IvRecv, sizeof(c->IvRecv));
|
||||||
|
|
||||||
//c->NextRekey = se->Server->Now + (UINT64)5000;
|
//c->NextRekey = se->Server->Now + (UINT64)5000;
|
||||||
|
|
||||||
@ -1427,8 +1492,7 @@ UINT64 OvsNewServerSessionId(OPENVPN_SERVER *s)
|
|||||||
// Build and submit the OpenVPN data packet
|
// Build and submit the OpenVPN data packet
|
||||||
void OvsSendDataPacket(OPENVPN_CHANNEL *c, UCHAR key_id, UINT data_packet_id, void *data, UINT data_size)
|
void OvsSendDataPacket(OPENVPN_CHANNEL *c, UCHAR key_id, UINT data_packet_id, void *data, UINT data_size)
|
||||||
{
|
{
|
||||||
UCHAR *encrypted_data;
|
const UCHAR op = ((OPENVPN_P_DATA_V1 << 3) & 0xF8) | (key_id & 0x07);
|
||||||
UINT encrypted_size;
|
|
||||||
UCHAR *dest_data;
|
UCHAR *dest_data;
|
||||||
UINT dest_size;
|
UINT dest_size;
|
||||||
// Validate arguments
|
// Validate arguments
|
||||||
@ -1437,29 +1501,63 @@ void OvsSendDataPacket(OPENVPN_CHANNEL *c, UCHAR key_id, UINT data_packet_id, vo
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Generate the data to be encrypted
|
// [ xxx ] = unprotected
|
||||||
encrypted_size = sizeof(UINT) + data_size;
|
// [ - xxx - ] = authenticated
|
||||||
encrypted_data = ZeroMalloc(encrypted_size);
|
// [ * xxx * ] = encrypted and authenticated
|
||||||
|
|
||||||
WRITE_UINT(encrypted_data, data_packet_id);
|
if (c->CipherEncrypt->IsAeadCipher)
|
||||||
Copy(encrypted_data + sizeof(UINT), data, data_size);
|
{
|
||||||
|
// [ opcode ] [ - packet ID - ] [ TAG ] [ * packet payload * ]
|
||||||
|
UCHAR tag[16];
|
||||||
|
|
||||||
// Prepare a buffer to store the results
|
// Update variable part (packet ID) of IV
|
||||||
dest_data = Malloc(sizeof(UCHAR) + c->MdSend->Size + c->CipherEncrypt->IvSize + encrypted_size + 256);
|
WRITE_UINT(c->IvSend, data_packet_id);
|
||||||
|
|
||||||
// Encrypt
|
// Prepare a buffer to store the results
|
||||||
dest_size = OvsEncrypt(c->CipherEncrypt, c->MdSend, c->NextIv, dest_data + sizeof(CHAR), encrypted_data, encrypted_size);
|
dest_data = Malloc(sizeof(op) + sizeof(data_packet_id) + sizeof(tag) + data_size + 256);
|
||||||
dest_size += sizeof(UCHAR);
|
|
||||||
|
|
||||||
// Update the NextIV
|
// Set data size to the maximum known
|
||||||
Copy(c->NextIv, dest_data + dest_size - c->CipherEncrypt->IvSize, c->CipherEncrypt->IvSize);
|
dest_size = sizeof(op) + sizeof(data_packet_id) + sizeof(tag);
|
||||||
|
|
||||||
// Op-code
|
// Write opcode
|
||||||
dest_data[0] = ((OPENVPN_P_DATA_V1 << 3) & 0xF8) | (key_id & 0x07);
|
dest_data[0] = op;
|
||||||
|
|
||||||
|
// Write packet ID
|
||||||
|
WRITE_UINT(dest_data + sizeof(op), data_packet_id);
|
||||||
|
|
||||||
|
// Write encrypted payload
|
||||||
|
dest_size += OvsEncrypt(c->CipherEncrypt, NULL, c->IvSend, tag, dest_data + dest_size, data, data_size, c->IvSend, sizeof(data_packet_id));
|
||||||
|
|
||||||
|
// Write authentication tag
|
||||||
|
Copy(dest_data + sizeof(op) + sizeof(data_packet_id), tag, sizeof(tag));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// [ opcode ] [ HMAC ] [ - IV - ] [ * packet ID * ] [ * packet payload * ]
|
||||||
|
UINT encrypted_size = sizeof(data_packet_id) + data_size;
|
||||||
|
UCHAR *encrypted_data = ZeroMalloc(encrypted_size);
|
||||||
|
WRITE_UINT(encrypted_data, data_packet_id);
|
||||||
|
Copy(encrypted_data + sizeof(data_packet_id), data, data_size);
|
||||||
|
|
||||||
|
// Prepare a buffer to store the results
|
||||||
|
dest_data = Malloc(sizeof(op) + c->MdSend->Size + c->CipherEncrypt->IvSize + encrypted_size + 256);
|
||||||
|
|
||||||
|
// Set data size to the maximum known
|
||||||
|
dest_size = sizeof(op);
|
||||||
|
|
||||||
|
// Write opcode
|
||||||
|
dest_data[0] = op;
|
||||||
|
|
||||||
|
// Write IV, encrypted packet ID and payload
|
||||||
|
dest_size += OvsEncrypt(c->CipherEncrypt, c->MdSend, c->IvSend, NULL, dest_data + sizeof(op), encrypted_data, encrypted_size, NULL, 0);
|
||||||
|
|
||||||
|
Free(encrypted_data);
|
||||||
|
|
||||||
|
// Update the IV
|
||||||
|
Copy(c->IvSend, dest_data + dest_size - c->CipherEncrypt->IvSize, c->CipherEncrypt->IvSize);
|
||||||
|
}
|
||||||
|
|
||||||
OvsSendPacketRawNow(c->Server, c->Session, dest_data, dest_size);
|
OvsSendPacketRawNow(c->Server, c->Session, dest_data, dest_size);
|
||||||
|
|
||||||
Free(encrypted_data);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Build an OpenVPN control packet
|
// Build an OpenVPN control packet
|
||||||
|
@ -127,6 +127,7 @@
|
|||||||
#define OPENVPN_MAX_SSL_RECV_BUF_SIZE (256 * 1024) // SSL receive buffer maximum length
|
#define OPENVPN_MAX_SSL_RECV_BUF_SIZE (256 * 1024) // SSL receive buffer maximum length
|
||||||
|
|
||||||
#define OPENVPN_MAX_KEY_SIZE 64 // Maximum key size
|
#define OPENVPN_MAX_KEY_SIZE 64 // Maximum key size
|
||||||
|
#define OPENVPN_TAG_SIZE 16 // Tag size (for packet authentication in AEAD mode)
|
||||||
|
|
||||||
#define OPENVPN_TMP_BUFFER_SIZE (65536 + 256) // Temporary buffer size
|
#define OPENVPN_TMP_BUFFER_SIZE (65536 + 256) // Temporary buffer size
|
||||||
|
|
||||||
@ -241,9 +242,10 @@ struct OPENVPN_CHANNEL
|
|||||||
CIPHER *CipherDecrypt; // Decryption algorithm
|
CIPHER *CipherDecrypt; // Decryption algorithm
|
||||||
MD *MdSend; // Transmission MD algorithm
|
MD *MdSend; // Transmission MD algorithm
|
||||||
MD *MdRecv; // Reception MD algorithm
|
MD *MdRecv; // Reception MD algorithm
|
||||||
|
UCHAR IvSend[64]; // Transmission IV
|
||||||
|
UCHAR IvRecv[64]; // Reception IV
|
||||||
UCHAR MasterSecret[48]; // Master Secret
|
UCHAR MasterSecret[48]; // Master Secret
|
||||||
UCHAR ExpansionKey[256]; // Expansion Key
|
UCHAR ExpansionKey[256]; // Expansion Key
|
||||||
UCHAR NextIv[64]; // Next IV
|
|
||||||
UINT LastDataPacketId; // Previous Data Packet ID
|
UINT LastDataPacketId; // Previous Data Packet ID
|
||||||
UINT64 EstablishedTick; // Established time
|
UINT64 EstablishedTick; // Established time
|
||||||
UCHAR KeyId; // KEY ID
|
UCHAR KeyId; // KEY ID
|
||||||
|
@ -570,6 +570,7 @@ CIPHER *NewCipher(char *name)
|
|||||||
EVP_CIPHER_CTX_init(c->Ctx);
|
EVP_CIPHER_CTX_init(c->Ctx);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
c->IsAeadCipher = EVP_CIPHER_flags(c->Cipher) & EVP_CIPH_FLAG_AEAD_CIPHER;
|
||||||
c->BlockSize = EVP_CIPHER_block_size(c->Cipher);
|
c->BlockSize = EVP_CIPHER_block_size(c->Cipher);
|
||||||
c->KeySize = EVP_CIPHER_key_length(c->Cipher);
|
c->KeySize = EVP_CIPHER_key_length(c->Cipher);
|
||||||
c->IvSize = EVP_CIPHER_iv_length(c->Cipher);
|
c->IvSize = EVP_CIPHER_iv_length(c->Cipher);
|
||||||
@ -634,6 +635,74 @@ UINT CipherProcess(CIPHER *c, void *iv, void *dest, void *src, UINT size)
|
|||||||
return r + r2;
|
return r + r2;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Process encryption / decryption (AEAD)
|
||||||
|
UINT CipherProcessAead(CIPHER *c, void *iv, void *tag, UINT tag_size, void *dest, void *src, UINT src_size, void *aad, UINT aad_size)
|
||||||
|
{
|
||||||
|
int r = src_size;
|
||||||
|
int r2 = 0;
|
||||||
|
// Validate arguments
|
||||||
|
if (c == NULL)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
else if (c->IsNullCipher)
|
||||||
|
{
|
||||||
|
Copy(dest, src, src_size);
|
||||||
|
return src_size;
|
||||||
|
}
|
||||||
|
else if (c->IsAeadCipher == false || iv == NULL || tag == NULL || tag_size == 0 || dest == NULL || src == NULL || src_size == 0)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (EVP_CipherInit_ex(c->Ctx, NULL, NULL, NULL, iv, c->Encrypt) == false)
|
||||||
|
{
|
||||||
|
Debug("CipherProcessAead(): EVP_CipherInit_ex() failed with error: %s\n", OpenSSL_Error());
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (c->Encrypt == false)
|
||||||
|
{
|
||||||
|
if (EVP_CIPHER_CTX_ctrl(c->Ctx, EVP_CTRL_AEAD_SET_TAG, tag_size, tag) == false)
|
||||||
|
{
|
||||||
|
Debug("CipherProcessAead(): EVP_CIPHER_CTX_ctrl() failed to set the tag!\n");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (aad != NULL && aad_size != 0)
|
||||||
|
{
|
||||||
|
if (EVP_CipherUpdate(c->Ctx, NULL, &r, aad, aad_size) == false)
|
||||||
|
{
|
||||||
|
Debug("CipherProcessAead(): EVP_CipherUpdate() failed with error: %s\n", OpenSSL_Error());
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (EVP_CipherUpdate(c->Ctx, dest, &r, src, src_size) == false)
|
||||||
|
{
|
||||||
|
Debug("CipherProcessAead(): EVP_CipherUpdate() failed with error: %s\n", OpenSSL_Error());
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (EVP_CipherFinal_ex(c->Ctx, ((UCHAR *)dest) + (UINT)r, &r2) == false)
|
||||||
|
{
|
||||||
|
Debug("CipherProcessAead(): EVP_CipherFinal_ex() failed with error: %s\n", OpenSSL_Error());
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (c->Encrypt)
|
||||||
|
{
|
||||||
|
if (EVP_CIPHER_CTX_ctrl(c->Ctx, EVP_CTRL_AEAD_GET_TAG, tag_size, tag) == false)
|
||||||
|
{
|
||||||
|
Debug("CipherProcessAead(): EVP_CIPHER_CTX_ctrl() failed to get the tag!\n");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return r + r2;
|
||||||
|
}
|
||||||
|
|
||||||
// Release of the cipher object
|
// Release of the cipher object
|
||||||
void FreeCipher(CIPHER *c)
|
void FreeCipher(CIPHER *c)
|
||||||
{
|
{
|
||||||
|
@ -239,6 +239,8 @@ void RAND_Free_For_SoftEther();
|
|||||||
|
|
||||||
// OpenSSL <1.1 Shims
|
// OpenSSL <1.1 Shims
|
||||||
#if OPENSSL_VERSION_NUMBER < 0x10100000L
|
#if OPENSSL_VERSION_NUMBER < 0x10100000L
|
||||||
|
# define EVP_CTRL_AEAD_GET_TAG EVP_CTRL_GCM_GET_TAG
|
||||||
|
# define EVP_CTRL_AEAD_SET_TAG EVP_CTRL_GCM_SET_TAG
|
||||||
# define EVP_PKEY_get0_RSA(obj) ((obj)->pkey.rsa)
|
# define EVP_PKEY_get0_RSA(obj) ((obj)->pkey.rsa)
|
||||||
# define EVP_PKEY_base_id(pkey) ((pkey)->type)
|
# define EVP_PKEY_base_id(pkey) ((pkey)->type)
|
||||||
# define X509_get0_notBefore(x509) ((x509)->cert_info->validity->notBefore)
|
# define X509_get0_notBefore(x509) ((x509)->cert_info->validity->notBefore)
|
||||||
@ -348,7 +350,7 @@ struct DH_CTX
|
|||||||
struct CIPHER
|
struct CIPHER
|
||||||
{
|
{
|
||||||
char Name[MAX_PATH];
|
char Name[MAX_PATH];
|
||||||
bool IsNullCipher;
|
bool IsNullCipher, IsAeadCipher;
|
||||||
const struct evp_cipher_st *Cipher;
|
const struct evp_cipher_st *Cipher;
|
||||||
struct evp_cipher_ctx_st *Ctx;
|
struct evp_cipher_ctx_st *Ctx;
|
||||||
bool Encrypt;
|
bool Encrypt;
|
||||||
@ -523,6 +525,7 @@ CIPHER *NewCipher(char *name);
|
|||||||
void FreeCipher(CIPHER *c);
|
void FreeCipher(CIPHER *c);
|
||||||
void SetCipherKey(CIPHER *c, void *key, bool enc);
|
void SetCipherKey(CIPHER *c, void *key, bool enc);
|
||||||
UINT CipherProcess(CIPHER *c, void *iv, void *dest, void *src, UINT size);
|
UINT CipherProcess(CIPHER *c, void *iv, void *dest, void *src, UINT size);
|
||||||
|
UINT CipherProcessAead(CIPHER *c, void *iv, void *tag, UINT tag_size, void *dest, void *src, UINT src_size, void *aad, UINT aad_size);
|
||||||
|
|
||||||
// Hashing
|
// Hashing
|
||||||
MD *NewMd(char *name);
|
MD *NewMd(char *name);
|
||||||
|
@ -98,14 +98,9 @@ $TAG_BEFORE_REMOTE$remote $TAG_HOSTNAME$ $TAG_PORT$
|
|||||||
###############################################################################
|
###############################################################################
|
||||||
# The encryption and authentication algorithm.
|
# The encryption and authentication algorithm.
|
||||||
#
|
#
|
||||||
# Default setting is good. Modify it as you prefer.
|
# The default setting is compatible with most clients. Modify it as you prefer.
|
||||||
# When you specify an unsupported algorithm, the error will occur.
|
# It is recommended to use a better algorithm if your client supports it.
|
||||||
#
|
# When you specify an unsupported algorithm, an error will occur.
|
||||||
# The supported algorithms are as follows:
|
|
||||||
# cipher: [NULL-CIPHER] NULL AES-128-CBC AES-192-CBC AES-256-CBC BF-CBC
|
|
||||||
# CAST-CBC CAST5-CBC DES-CBC DES-EDE-CBC DES-EDE3-CBC DESX-CBC
|
|
||||||
# RC2-40-CBC RC2-64-CBC RC2-CBC CAMELLIA-128-CBC CAMELLIA-192-CBC CAMELLIA-256-CBC
|
|
||||||
# auth: SHA SHA1 SHA256 SHA384 SHA512 MD5 MD4 RMD160
|
|
||||||
|
|
||||||
cipher AES-128-CBC
|
cipher AES-128-CBC
|
||||||
auth SHA1
|
auth SHA1
|
||||||
|
Loading…
Reference in New Issue
Block a user