mirror of
https://github.com/OpenVPN/openvpn3.git
synced 2024-09-19 11:42:15 +02:00
Differentiate Packet ID types into data channel and control channel ids
Data channel packet ids (in the formats that OpenVPN 3.x supports) are plain 32 or 64 bit ids while control channel is a 32 bit time + 32 bit counter id. Seperate these more clearly and let CBC mode use the same Packet ID implementation that AEAD mode uses. Also add more unit tests related to data channel tests packets by adapting the control channel test where applicable and add a few more related to packet id wrapping Signed-off-by: Arne Schwabe <arne@openvpn.net>
This commit is contained in:
parent
16b2c4afe0
commit
c78aaecad7
@ -32,7 +32,7 @@
|
||||
#include <openvpn/buffer/buffer.hpp>
|
||||
#include <openvpn/frame/frame.hpp>
|
||||
#include <openvpn/crypto/static_key.hpp>
|
||||
#include <openvpn/crypto/packet_id_aead.hpp>
|
||||
#include <openvpn/crypto/packet_id_data.hpp>
|
||||
#include <openvpn/log/sessionstats.hpp>
|
||||
#include <openvpn/crypto/cryptodc.hpp>
|
||||
|
||||
@ -85,12 +85,12 @@ class Crypto : public CryptoDCInstance
|
||||
}
|
||||
|
||||
// for encrypt
|
||||
Nonce(const Nonce &ref, PacketIDAEADSend &pid_send, const unsigned char *op32)
|
||||
Nonce(const Nonce &ref, PacketIDDataSend &pid_send, const unsigned char *op32)
|
||||
{
|
||||
/** Copy op code and tail of packet ID */
|
||||
std::memcpy(data, ref.data, sizeof(data));
|
||||
|
||||
Buffer buf(data + data_offset_pkt_id, PacketIDAEAD::long_id_size, false);
|
||||
Buffer buf(data + data_offset_pkt_id, PacketIDData::long_id_size, false);
|
||||
pid_send.write_next(buf);
|
||||
if (op32)
|
||||
{
|
||||
@ -102,13 +102,13 @@ class Crypto : public CryptoDCInstance
|
||||
}
|
||||
|
||||
// for encrypt
|
||||
void prepend_ad(Buffer &buf, const PacketIDAEADSend &pid_send) const
|
||||
void prepend_ad(Buffer &buf, const PacketIDDataSend &pid_send) const
|
||||
{
|
||||
buf.prepend(data + data_offset_pkt_id, pid_send.length());
|
||||
}
|
||||
|
||||
// for decrypt
|
||||
Nonce(const Nonce &ref, const PacketIDAEADReceive &recv_pid, Buffer &buf, const unsigned char *op32)
|
||||
Nonce(const Nonce &ref, const PacketIDDataReceive &recv_pid, Buffer &buf, const unsigned char *op32)
|
||||
{
|
||||
/* Copy opcode and tail of packet ID */
|
||||
std::memcpy(data, ref.data, sizeof(data));
|
||||
@ -125,10 +125,10 @@ class Crypto : public CryptoDCInstance
|
||||
}
|
||||
|
||||
// for decrypt
|
||||
bool verify_packet_id(PacketIDAEADReceive &pid_recv, const PacketID::time_t now)
|
||||
bool verify_packet_id(PacketIDDataReceive &pid_recv, const PacketIDControl::time_t now)
|
||||
{
|
||||
Buffer buf(data + data_offset_pkt_id, PacketIDAEAD::long_id_size, true);
|
||||
const PacketIDAEAD pid = pid_recv.read_next(buf);
|
||||
Buffer buf(data + data_offset_pkt_id, PacketIDData::long_id_size, true);
|
||||
const PacketIDData pid = pid_recv.read_next(buf);
|
||||
return pid_recv.test_add(pid, now); // verify packet ID
|
||||
}
|
||||
|
||||
@ -142,12 +142,12 @@ class Crypto : public CryptoDCInstance
|
||||
return ad_op32 ? data : data + data_offset_pkt_id;
|
||||
}
|
||||
|
||||
size_t ad_len(const PacketIDAEADSend &pid_send) const
|
||||
size_t ad_len(const PacketIDDataSend &pid_send) const
|
||||
{
|
||||
return (ad_op32 ? op32_size : 0) + pid_send.length();
|
||||
}
|
||||
|
||||
size_t ad_len(const PacketIDAEADReceive &pid_recv) const
|
||||
size_t ad_len(const PacketIDDataReceive &pid_recv) const
|
||||
{
|
||||
return (ad_op32 ? op32_size : 0) + pid_recv.length();
|
||||
}
|
||||
@ -168,7 +168,7 @@ class Crypto : public CryptoDCInstance
|
||||
{
|
||||
typename CRYPTO_API::CipherContextAEAD impl;
|
||||
Nonce nonce;
|
||||
PacketIDAEADSend pid_send{false};
|
||||
PacketIDDataSend pid_send{false};
|
||||
BufferAllocated work;
|
||||
};
|
||||
|
||||
@ -176,7 +176,7 @@ class Crypto : public CryptoDCInstance
|
||||
{
|
||||
typename CRYPTO_API::CipherContextAEAD impl;
|
||||
Nonce nonce;
|
||||
PacketIDAEADReceive pid_recv{};
|
||||
PacketIDDataReceive pid_recv{};
|
||||
BufferAllocated work;
|
||||
};
|
||||
|
||||
@ -197,7 +197,7 @@ class Crypto : public CryptoDCInstance
|
||||
// Encrypt/Decrypt
|
||||
|
||||
// returns true if packet ID is close to wrapping
|
||||
bool encrypt(BufferAllocated &buf, const PacketID::time_t now, const unsigned char *op32) override
|
||||
bool encrypt(BufferAllocated &buf, const unsigned char *op32) override
|
||||
{
|
||||
// only process non-null packets
|
||||
if (buf.size())
|
||||
@ -251,7 +251,7 @@ class Crypto : public CryptoDCInstance
|
||||
return e.pid_send.wrap_warning();
|
||||
}
|
||||
|
||||
Error::Type decrypt(BufferAllocated &buf, const PacketID::time_t now, const unsigned char *op32) override
|
||||
Error::Type decrypt(BufferAllocated &buf, const std::time_t now, const unsigned char *op32) override
|
||||
{
|
||||
// only process non-null packets
|
||||
if (buf.size())
|
||||
@ -337,7 +337,7 @@ class Crypto : public CryptoDCInstance
|
||||
const int recv_unit,
|
||||
const SessionStats::Ptr &recv_stats_arg) override
|
||||
{
|
||||
e.pid_send = PacketIDAEADSend{dc_settings.use64bitPktCounter()};
|
||||
e.pid_send = PacketIDDataSend{dc_settings.use64bitPktCounter()};
|
||||
d.pid_recv.init(recv_name, recv_unit, dc_settings.use64bitPktCounter(), recv_stats_arg);
|
||||
}
|
||||
|
||||
|
@ -58,13 +58,13 @@ class CryptoCHM : public CryptoDCInstance
|
||||
// Encrypt/Decrypt
|
||||
|
||||
/* returns true if packet ID is close to wrapping */
|
||||
bool encrypt(BufferAllocated &buf, const PacketID::time_t now, const unsigned char *op32) override
|
||||
bool encrypt(BufferAllocated &buf, const unsigned char *op32) override
|
||||
{
|
||||
encrypt_.encrypt(buf, now);
|
||||
encrypt_.encrypt(buf);
|
||||
return encrypt_.pid_send.wrap_warning();
|
||||
}
|
||||
|
||||
Error::Type decrypt(BufferAllocated &buf, const PacketID::time_t now, const unsigned char *op32) override
|
||||
Error::Type decrypt(BufferAllocated &buf, const std::time_t now, const unsigned char *op32) override
|
||||
{
|
||||
return decrypt_.decrypt(buf, now);
|
||||
}
|
||||
@ -90,10 +90,10 @@ class CryptoCHM : public CryptoDCInstance
|
||||
const SessionStats::Ptr &recv_stats_arg) override
|
||||
{
|
||||
/* CBC encryption always uses short packet ID */
|
||||
auto pid_form = PacketID::SHORT_FORM;
|
||||
constexpr bool wide = false;
|
||||
|
||||
encrypt_.pid_send.init(pid_form);
|
||||
decrypt_.pid_recv.init(pid_form, recv_name, recv_unit, recv_stats_arg);
|
||||
encrypt_.pid_send = PacketIDDataSend{wide};
|
||||
decrypt_.pid_recv.init(recv_name, recv_unit, wide, recv_stats_arg);
|
||||
}
|
||||
|
||||
bool consider_compression(const CompressContext &comp_ctx) override
|
||||
|
@ -33,7 +33,7 @@
|
||||
#include <openvpn/common/rc.hpp>
|
||||
#include <openvpn/frame/frame.hpp>
|
||||
#include <openvpn/crypto/static_key.hpp>
|
||||
#include <openvpn/crypto/packet_id.hpp>
|
||||
#include <openvpn/crypto/packet_id_control.hpp>
|
||||
#include <openvpn/crypto/cryptoalgs.hpp>
|
||||
#include <openvpn/compress/compress.hpp>
|
||||
|
||||
@ -48,9 +48,9 @@ class CryptoDCInstance : public RC<thread_unsafe_refcount>
|
||||
// Encrypt/Decrypt
|
||||
|
||||
// returns true if packet ID is close to wrapping
|
||||
virtual bool encrypt(BufferAllocated &buf, const PacketID::time_t now, const unsigned char *op32) = 0;
|
||||
virtual bool encrypt(BufferAllocated &buf, const unsigned char *op32) = 0;
|
||||
|
||||
virtual Error::Type decrypt(BufferAllocated &buf, const PacketID::time_t now, const unsigned char *op32) = 0;
|
||||
virtual Error::Type decrypt(BufferAllocated &buf, std::time_t now, const unsigned char *op32) = 0;
|
||||
|
||||
// Initialization
|
||||
|
||||
|
@ -34,7 +34,7 @@
|
||||
#include <openvpn/crypto/cipher.hpp>
|
||||
#include <openvpn/crypto/ovpnhmac.hpp>
|
||||
#include <openvpn/crypto/static_key.hpp>
|
||||
#include <openvpn/crypto/packet_id.hpp>
|
||||
#include <openvpn/crypto/packet_id_control.hpp>
|
||||
#include <openvpn/log/sessionstats.hpp>
|
||||
|
||||
namespace openvpn {
|
||||
@ -45,7 +45,7 @@ class DecryptCHM
|
||||
public:
|
||||
OPENVPN_SIMPLE_EXCEPTION(chm_unsupported_cipher_mode);
|
||||
|
||||
Error::Type decrypt(BufferAllocated &buf, const PacketID::time_t now)
|
||||
Error::Type decrypt(BufferAllocated &buf, const std::time_t now)
|
||||
{
|
||||
// skip null packets
|
||||
if (!buf.size())
|
||||
@ -118,19 +118,13 @@ class DecryptCHM
|
||||
Frame::Ptr frame;
|
||||
CipherContext<CRYPTO_API> cipher;
|
||||
OvpnHMAC<CRYPTO_API> hmac;
|
||||
PacketIDReceive pid_recv;
|
||||
PacketIDDataReceive pid_recv;
|
||||
|
||||
private:
|
||||
bool verify_packet_id(BufferAllocated &buf, const PacketID::time_t now)
|
||||
bool verify_packet_id(BufferAllocated &buf, const std::time_t now)
|
||||
{
|
||||
// ignore packet ID if pid_recv is not initialized
|
||||
if (pid_recv.initialized())
|
||||
{
|
||||
const PacketID pid = pid_recv.read_next(buf);
|
||||
if (!pid_recv.test_add(pid, now, true)) // verify packet ID
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
const PacketIDData pid = pid_recv.read_next(buf);
|
||||
return pid_recv.test_add(pid, now);
|
||||
}
|
||||
|
||||
BufferAllocated work;
|
||||
|
@ -35,7 +35,7 @@
|
||||
#include <openvpn/crypto/cipher.hpp>
|
||||
#include <openvpn/crypto/ovpnhmac.hpp>
|
||||
#include <openvpn/crypto/static_key.hpp>
|
||||
#include <openvpn/crypto/packet_id.hpp>
|
||||
#include <openvpn/crypto/packet_id_data.hpp>
|
||||
|
||||
namespace openvpn {
|
||||
template <typename CRYPTO_API>
|
||||
@ -44,7 +44,7 @@ class EncryptCHM
|
||||
public:
|
||||
OPENVPN_SIMPLE_EXCEPTION(chm_unsupported_cipher_mode);
|
||||
|
||||
void encrypt(BufferAllocated &buf, const PacketID::time_t now)
|
||||
void encrypt(BufferAllocated &buf)
|
||||
{
|
||||
// skip null packets
|
||||
if (!buf.size())
|
||||
@ -64,7 +64,7 @@ class EncryptCHM
|
||||
rng->rand_bytes(iv_buf, iv_length);
|
||||
|
||||
// generate fresh outgoing packet ID and prepend to cleartext buffer
|
||||
pid_send.write_next(buf, true, now);
|
||||
pid_send.prepend_next(buf);
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -95,7 +95,7 @@ class EncryptCHM
|
||||
else // no encryption
|
||||
{
|
||||
// generate fresh outgoing packet ID and prepend to cleartext buffer
|
||||
pid_send.write_next(buf, true, now);
|
||||
pid_send.prepend_next(buf);
|
||||
|
||||
// HMAC the cleartext
|
||||
prepend_hmac(buf);
|
||||
@ -110,7 +110,7 @@ class EncryptCHM
|
||||
Frame::Ptr frame;
|
||||
CipherContext<CRYPTO_API> cipher;
|
||||
OvpnHMAC<CRYPTO_API> hmac;
|
||||
PacketIDSend pid_send;
|
||||
PacketIDDataSend pid_send{false};
|
||||
|
||||
private:
|
||||
// compute HMAC signature of data buffer,
|
||||
|
@ -21,8 +21,7 @@
|
||||
|
||||
// Manage OpenVPN protocol Packet IDs for packet replay detection
|
||||
|
||||
#ifndef OPENVPN_CRYPTO_PACKET_ID_H
|
||||
#define OPENVPN_CRYPTO_PACKET_ID_H
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include <cstring>
|
||||
@ -42,59 +41,38 @@
|
||||
|
||||
namespace openvpn {
|
||||
/*
|
||||
* Communicate packet-id over the wire.
|
||||
* A short packet-id is just a 32 bit
|
||||
* sequence number. A long packet-id
|
||||
* includes a timestamp as well.
|
||||
* Control channel Packet ID. These IDs have the format
|
||||
*
|
||||
* Long packet-ids are used as IVs for
|
||||
* CFB/OFB ciphers.
|
||||
* | 32 bit integer timestamp in BE | 32 bit packet counter in BE |
|
||||
*
|
||||
* This data structure is always sent
|
||||
* over the net in network byte order,
|
||||
* by calling htonl, ntohl, on the
|
||||
* 32-bit data elements, id_t and
|
||||
* net_time_t, to change them to and
|
||||
* from network order.
|
||||
* This format of long packet-ids is also used as IVs for CFB/OFB ciphers
|
||||
* in OpenVPN 2.x but OpenVPN 3.x supports only CBC and AEAD ciphers, so
|
||||
* it is only used for control channel and control chanel authentication/encryption
|
||||
* schemes like tls-auth/tls-crypt.
|
||||
*
|
||||
* In addition, time is converted to
|
||||
* a PacketID::net_time_t before sending,
|
||||
* since openvpn always
|
||||
* uses a 32-bit time_t but some
|
||||
* 64 bit platforms use a
|
||||
* 64 bit time_t.
|
||||
* This data structure is always sent over the net in network byte order,
|
||||
* by calling htonl, ntohl, on the 32-bit data elements, id_t and
|
||||
* net_time_t, to change them to and from network order.
|
||||
*/
|
||||
struct PacketID
|
||||
struct PacketIDControl
|
||||
{
|
||||
typedef std::uint32_t id_t;
|
||||
typedef std::uint32_t net_time_t;
|
||||
typedef Time::base_type time_t;
|
||||
|
||||
enum
|
||||
{
|
||||
SHORT_FORM = 0, // short form of ID (4 bytes)
|
||||
LONG_FORM = 1, // long form of ID (8 bytes)
|
||||
|
||||
UNDEF = 0, // special undefined/null id_t value
|
||||
};
|
||||
|
||||
id_t id; // legal values are 1 through 2^32-1
|
||||
time_t time; // converted to PacketID::net_time_t before transmission
|
||||
|
||||
static constexpr size_t size(const int form)
|
||||
static constexpr size_t size()
|
||||
{
|
||||
if (form == PacketID::LONG_FORM)
|
||||
return longidsize;
|
||||
else
|
||||
return shortidsize;
|
||||
return idsize;
|
||||
}
|
||||
|
||||
constexpr static size_t shortidsize = sizeof(id_t);
|
||||
constexpr static size_t longidsize = sizeof(id_t) + sizeof(net_time_t);
|
||||
constexpr static size_t idsize = sizeof(id_t) + sizeof(net_time_t);
|
||||
|
||||
bool is_valid() const
|
||||
{
|
||||
return id != UNDEF;
|
||||
return id != 0;
|
||||
}
|
||||
|
||||
void reset()
|
||||
@ -104,7 +82,7 @@ struct PacketID
|
||||
}
|
||||
|
||||
template <typename BufType> // so it can take a Buffer or a ConstBuffer
|
||||
void read(BufType &buf, const int form)
|
||||
void read(BufType &buf)
|
||||
{
|
||||
id_t net_id;
|
||||
net_time_t net_time;
|
||||
@ -112,16 +90,11 @@ struct PacketID
|
||||
buf.read((unsigned char *)&net_id, sizeof(net_id));
|
||||
id = ntohl(net_id);
|
||||
|
||||
if (form == LONG_FORM)
|
||||
{
|
||||
buf.read((unsigned char *)&net_time, sizeof(net_time));
|
||||
time = ntohl(net_time);
|
||||
}
|
||||
else
|
||||
time = time_t(0);
|
||||
buf.read((unsigned char *)&net_time, sizeof(net_time));
|
||||
time = ntohl(net_time);
|
||||
}
|
||||
|
||||
void write(Buffer &buf, const int form, const bool prepend) const
|
||||
void write(Buffer &buf, const bool prepend) const
|
||||
{
|
||||
const id_t net_id = htonl(id);
|
||||
const net_time_t net_time = htonl(static_cast<uint32_t>(time & 0x00000000FFFFFFFF));
|
||||
@ -130,15 +103,13 @@ struct PacketID
|
||||
|
||||
if (prepend)
|
||||
{
|
||||
if (form == LONG_FORM)
|
||||
buf.prepend((unsigned char *)&net_time, sizeof(net_time));
|
||||
buf.prepend((unsigned char *)&net_time, sizeof(net_time));
|
||||
buf.prepend((unsigned char *)&net_id, sizeof(net_id));
|
||||
}
|
||||
else
|
||||
{
|
||||
buf.write((unsigned char *)&net_id, sizeof(net_id));
|
||||
if (form == LONG_FORM)
|
||||
buf.write((unsigned char *)&net_time, sizeof(net_time));
|
||||
buf.write((unsigned char *)&net_time, sizeof(net_time));
|
||||
}
|
||||
}
|
||||
|
||||
@ -150,51 +121,36 @@ struct PacketID
|
||||
}
|
||||
};
|
||||
|
||||
struct PacketIDConstruct : public PacketID
|
||||
{
|
||||
PacketIDConstruct(const PacketID::time_t v_time = PacketID::time_t(0), const PacketID::id_t v_id = PacketID::id_t(0))
|
||||
{
|
||||
id = v_id;
|
||||
time = v_time;
|
||||
}
|
||||
};
|
||||
|
||||
class PacketIDSend
|
||||
class PacketIDControlSend
|
||||
{
|
||||
public:
|
||||
OPENVPN_SIMPLE_EXCEPTION(packet_id_wrap);
|
||||
|
||||
PacketIDSend()
|
||||
{
|
||||
init(PacketID::SHORT_FORM);
|
||||
}
|
||||
|
||||
explicit PacketIDSend(int form, PacketID::id_t start_at = PacketID::id_t(0))
|
||||
explicit PacketIDControlSend(PacketIDControl::id_t start_at = PacketIDControl::id_t(0))
|
||||
{
|
||||
init(form, start_at);
|
||||
init(start_at);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param form PacketID::LONG_FORM or PacketID::SHORT_FORM
|
||||
* @param start_at initial id for the sending
|
||||
*/
|
||||
void init(const int form, PacketID::id_t start_at = 0)
|
||||
void init(PacketIDControl::id_t start_at = 0)
|
||||
{
|
||||
pid_.id = start_at;
|
||||
pid_.time = PacketID::time_t(0);
|
||||
form_ = form;
|
||||
pid_.time = PacketIDControl::time_t(0);
|
||||
}
|
||||
|
||||
PacketID next(const PacketID::time_t now)
|
||||
PacketIDControl next(const PacketIDControl::time_t now)
|
||||
{
|
||||
PacketID ret;
|
||||
PacketIDControl ret;
|
||||
if (!pid_.time)
|
||||
pid_.time = now;
|
||||
ret.id = ++pid_.id;
|
||||
if (unlikely(!pid_.id)) // wraparound
|
||||
{
|
||||
if (form_ != PacketID::LONG_FORM)
|
||||
throw packet_id_wrap();
|
||||
pid_.time = now;
|
||||
ret.id = pid_.id = 1;
|
||||
}
|
||||
@ -202,35 +158,22 @@ class PacketIDSend
|
||||
return ret;
|
||||
}
|
||||
|
||||
void write_next(Buffer &buf, const bool prepend, const PacketID::time_t now)
|
||||
void write_next(Buffer &buf, const bool prepend, const PacketIDControl::time_t now)
|
||||
{
|
||||
const PacketID pid = next(now);
|
||||
pid.write(buf, form_, prepend);
|
||||
}
|
||||
|
||||
/*
|
||||
* In TLS mode, when a packet ID gets to this level,
|
||||
* start thinking about triggering a new
|
||||
* SSL/TLS handshake.
|
||||
*/
|
||||
bool wrap_warning() const
|
||||
{
|
||||
const PacketID::id_t wrap_at = 0xFF000000;
|
||||
return pid_.id >= wrap_at;
|
||||
const PacketIDControl pid = next(now);
|
||||
pid.write(buf, prepend);
|
||||
}
|
||||
|
||||
std::string str() const
|
||||
{
|
||||
std::string ret;
|
||||
ret = pid_.str();
|
||||
if (form_ == PacketID::LONG_FORM)
|
||||
ret += 'L';
|
||||
ret += 'L';
|
||||
return ret;
|
||||
}
|
||||
|
||||
private:
|
||||
PacketID pid_;
|
||||
int form_;
|
||||
PacketIDControl pid_;
|
||||
};
|
||||
|
||||
/*
|
||||
@ -243,7 +186,7 @@ class PacketIDSend
|
||||
*/
|
||||
template <unsigned int REPLAY_WINDOW_ORDER,
|
||||
unsigned int PKTID_RECV_EXPIRE>
|
||||
class PacketIDReceiveType
|
||||
class PacketIDControlReceiveType
|
||||
{
|
||||
public:
|
||||
static constexpr unsigned int REPLAY_WINDOW_BYTES = 1 << REPLAY_WINDOW_ORDER;
|
||||
@ -252,13 +195,11 @@ class PacketIDReceiveType
|
||||
OPENVPN_SIMPLE_EXCEPTION(packet_id_not_initialized);
|
||||
|
||||
// TODO: [OVPN3-933] Consider RAII'ifying this code
|
||||
PacketIDReceiveType()
|
||||
: initialized_(false)
|
||||
PacketIDControlReceiveType()
|
||||
{
|
||||
}
|
||||
|
||||
void init(const int form_arg,
|
||||
const char *name_arg,
|
||||
void init(const char *name_arg,
|
||||
const int unit_arg,
|
||||
const SessionStats::Ptr &stats_arg)
|
||||
{
|
||||
@ -270,20 +211,19 @@ class PacketIDReceiveType
|
||||
time_high = 0;
|
||||
id_floor = 0;
|
||||
max_backtrack = 0;
|
||||
form = form_arg;
|
||||
unit = unit_arg;
|
||||
name = name_arg;
|
||||
stats = stats_arg;
|
||||
std::memset(history, 0, sizeof(history));
|
||||
}
|
||||
|
||||
bool initialized() const
|
||||
[[nodiscard]] bool initialized() const
|
||||
{
|
||||
return initialized_;
|
||||
}
|
||||
|
||||
bool test_add(const PacketID &pin,
|
||||
const PacketID::time_t now,
|
||||
bool test_add(const PacketIDControl &pin,
|
||||
const PacketIDControl::time_t now,
|
||||
const bool mod) // don't modify history unless mod is true
|
||||
{
|
||||
const Error::Type err = do_test_add(pin, now, mod);
|
||||
@ -296,8 +236,8 @@ class PacketIDReceiveType
|
||||
return true;
|
||||
}
|
||||
|
||||
Error::Type do_test_add(const PacketID &pin,
|
||||
const PacketID::time_t now,
|
||||
Error::Type do_test_add(const PacketIDControl &pin,
|
||||
const PacketIDControl::time_t now,
|
||||
const bool mod) // don't modify history unless mod is true
|
||||
{
|
||||
// make sure we were initialized
|
||||
@ -402,12 +342,12 @@ class PacketIDReceiveType
|
||||
return Error::SUCCESS;
|
||||
}
|
||||
|
||||
PacketID read_next(Buffer &buf) const
|
||||
PacketIDControl read_next(Buffer &buf) const
|
||||
{
|
||||
if (!initialized_)
|
||||
throw packet_id_not_initialized();
|
||||
PacketID pid;
|
||||
pid.read(buf, form);
|
||||
PacketIDControl pid{};
|
||||
pid.read(buf);
|
||||
return pid;
|
||||
}
|
||||
|
||||
@ -424,18 +364,17 @@ class PacketIDReceiveType
|
||||
return (base + i) & (REPLAY_WINDOW_SIZE - 1);
|
||||
}
|
||||
|
||||
bool initialized_;
|
||||
bool initialized_ = false;
|
||||
|
||||
unsigned int base; // bit position of deque base in history
|
||||
unsigned int extent; // extent (in bits) of deque in history
|
||||
PacketID::time_t expire; // expiration of history
|
||||
PacketID::id_t id_high; // highest sequence number received
|
||||
PacketID::time_t time_high; // highest time stamp received
|
||||
PacketID::id_t id_floor; // we will only accept backtrack IDs > id_floor
|
||||
unsigned int max_backtrack;
|
||||
unsigned int base = 0; // bit position of deque base in history
|
||||
unsigned int extent = 0; // extent (in bits) of deque in history
|
||||
PacketIDControl::time_t expire = 0; // expiration of history
|
||||
PacketIDControl::id_t id_high = 0; // highest sequence number received
|
||||
PacketIDControl::time_t time_high = 0; // highest time stamp received
|
||||
PacketIDControl::id_t id_floor = 0; // we will only accept backtrack IDs > id_floor
|
||||
unsigned int max_backtrack = 0;
|
||||
|
||||
int form; // PacketID::LONG_FORM or PacketID::SHORT_FORM
|
||||
int unit; // unit number of this object (for debugging)
|
||||
int unit = -1; // unit number of this object (for debugging)
|
||||
std::string name; // name of this object (for debugging)
|
||||
|
||||
SessionStats::Ptr stats;
|
||||
@ -445,8 +384,6 @@ class PacketIDReceiveType
|
||||
|
||||
// Our standard packet ID window with order=8 (window size=2048).
|
||||
// and recv expire=30 seconds.
|
||||
typedef PacketIDReceiveType<8, 30> PacketIDReceive;
|
||||
typedef PacketIDControlReceiveType<8, 30> PacketIDControlReceive;
|
||||
|
||||
} // namespace openvpn
|
||||
|
||||
#endif // OPENVPN_CRYPTO_PACKET_ID_H
|
@ -43,24 +43,25 @@
|
||||
|
||||
namespace openvpn {
|
||||
/**
|
||||
* Communicate packet-id over the wire for AEAD
|
||||
* Communicate packet-id over the wire for data channel packets
|
||||
* A short packet-id is just a 32 bit sequence number. A long packet-id is a
|
||||
* 64 bit sequence number. This sequence number is reused for AEAD IV.
|
||||
* 64 bit sequence number. This sequence number is reused for AEAD IV when
|
||||
* AEAD is used as a cipher. CBC transmits an additional IV.
|
||||
*
|
||||
* This data structure is always sent over the net in network byte order,
|
||||
*
|
||||
* This class is different from PacketID in the way that it always uses
|
||||
* a "flat" packet id that is either 32 or 64 bit while PacketID has a long
|
||||
* This class is different from PacketIDControl in the way that it always uses
|
||||
* a "flat" packet id that is either 32 or 64 bit while PacketIDControl has a long
|
||||
* packet id that is 32bit + 32bit but follow different rules and includes
|
||||
* a timestamp. Merging PacketIDAEAD and PacketID would result in a much
|
||||
* more convoluted and hard to understand class than keeping them seperate
|
||||
* a timestamp. Merging PacketIData and PacketIDControl would result in a much
|
||||
* more convoluted and hard to understand class than keeping them separate.
|
||||
*
|
||||
*/
|
||||
struct PacketIDAEAD
|
||||
struct PacketIDData
|
||||
{
|
||||
typedef std::uint64_t aead_id_t;
|
||||
typedef std::uint64_t data_id_t;
|
||||
|
||||
aead_id_t id = 0; // legal values are 1 through 2^64-1
|
||||
data_id_t id = 0; // legal values are 1 through 2^64-1
|
||||
bool wide = false;
|
||||
|
||||
/**
|
||||
@ -81,12 +82,12 @@ struct PacketIDAEAD
|
||||
}
|
||||
|
||||
|
||||
explicit PacketIDAEAD(bool wide_arg)
|
||||
explicit PacketIDData(bool wide_arg)
|
||||
: wide(wide_arg)
|
||||
{
|
||||
}
|
||||
|
||||
explicit PacketIDAEAD(bool wide_arg, aead_id_t id_arg)
|
||||
explicit PacketIDData(bool wide_arg, data_id_t id_arg)
|
||||
: id(id_arg), wide(wide_arg)
|
||||
{
|
||||
}
|
||||
@ -94,14 +95,14 @@ struct PacketIDAEAD
|
||||
constexpr static std::size_t short_id_size = sizeof(std::uint32_t);
|
||||
constexpr static std::size_t long_id_size = sizeof(std::uint64_t);
|
||||
|
||||
bool is_valid() const
|
||||
[[nodiscard]] bool is_valid() const
|
||||
{
|
||||
return id != 0;
|
||||
}
|
||||
|
||||
void reset()
|
||||
{
|
||||
id = aead_id_t(0);
|
||||
id = data_id_t(0);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -139,7 +140,23 @@ struct PacketIDAEAD
|
||||
}
|
||||
}
|
||||
|
||||
std::string str() const
|
||||
/** Prepend the packet id to a buffer */
|
||||
void write_prepend(Buffer &buf) const
|
||||
{
|
||||
if (wide)
|
||||
{
|
||||
const std::uint64_t net_id = Endian::rev64(id);
|
||||
buf.prepend(reinterpret_cast<const unsigned char *>(&net_id), sizeof(net_id));
|
||||
}
|
||||
else
|
||||
{
|
||||
const std::uint32_t net_id = htonl(static_cast<std::uint32_t>(id));
|
||||
buf.prepend(reinterpret_cast<const unsigned char *>(&net_id), sizeof(net_id));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
[[nodiscard]] std::string str() const
|
||||
{
|
||||
std::ostringstream os;
|
||||
os << std::hex << "[0x" << id << "]";
|
||||
@ -147,12 +164,12 @@ struct PacketIDAEAD
|
||||
}
|
||||
};
|
||||
|
||||
class PacketIDAEADSend
|
||||
class PacketIDDataSend
|
||||
{
|
||||
public:
|
||||
OPENVPN_SIMPLE_EXCEPTION(packet_id_wrap);
|
||||
|
||||
PacketIDAEADSend(bool wide_arg)
|
||||
explicit PacketIDDataSend(bool wide_arg)
|
||||
: pid_(wide_arg)
|
||||
{
|
||||
}
|
||||
@ -163,10 +180,10 @@ class PacketIDAEADSend
|
||||
* @throws packet_id_wrap if the packet id space is exhausted
|
||||
* @return packet id to use next.
|
||||
*/
|
||||
PacketIDAEAD next()
|
||||
[[nodiscard]] PacketIDData next()
|
||||
{
|
||||
++pid_.id;
|
||||
PacketIDAEAD ret{pid_.wide, pid_.id};
|
||||
PacketIDData ret{pid_.wide, pid_.id};
|
||||
if (!pid_.wide && unlikely(pid_.id == std::numeric_limits<std::uint32_t>::max())) // wraparound
|
||||
{
|
||||
throw packet_id_wrap();
|
||||
@ -184,26 +201,21 @@ class PacketIDAEADSend
|
||||
*/
|
||||
void write_next(Buffer &buf)
|
||||
{
|
||||
const PacketIDAEAD pid = next();
|
||||
const PacketIDData pid = next();
|
||||
pid.write(buf);
|
||||
}
|
||||
|
||||
/**
|
||||
* When a VPN runs in TLS mode (the only mode that OpenVPN supports,
|
||||
* there is no --secret mode anymore), it needs to be warned about wrapping to
|
||||
* start thinking about triggering a new SSL/TLS handshake.
|
||||
* This method can be called to see if that level has been reached.
|
||||
* increases the packet id and prepends it to a buffer
|
||||
* @param buf buffer to write to
|
||||
*/
|
||||
bool wrap_warning() const
|
||||
void prepend_next(Buffer &buf)
|
||||
{
|
||||
if (pid_.wide)
|
||||
return false;
|
||||
|
||||
const PacketIDAEAD::aead_id_t wrap_at = 0xFF000000;
|
||||
return pid_.id >= wrap_at;
|
||||
const PacketIDData pid = next();
|
||||
pid.write_prepend(buf);
|
||||
}
|
||||
|
||||
std::string str() const
|
||||
[[nodiscard]] std::string str() const
|
||||
{
|
||||
std::string ret;
|
||||
ret = pid_.str();
|
||||
@ -221,8 +233,28 @@ class PacketIDAEADSend
|
||||
return pid_.size();
|
||||
}
|
||||
|
||||
private:
|
||||
PacketIDAEAD pid_;
|
||||
/**
|
||||
* When a VPN runs in TLS mode (the only mode that OpenVPN supports,
|
||||
* there is no --secret mode anymore), it needs to be warned about wrapping to
|
||||
* start thinking about triggering a new SSL/TLS handshake.
|
||||
* This method can be called to see if that level has been reached.
|
||||
*
|
||||
* For 64bit counters, even with (non-existing) 1 byte packets, we would need
|
||||
* to transfer 16 EB (exabytes) and 1,6 ZB (zettabytes) with 100 byte packets.
|
||||
* This is not reachable in reasonable amount of time. And we still have the
|
||||
* failsafe to throw an exception if we would overflow the ocunter.
|
||||
*/
|
||||
bool wrap_warning() const
|
||||
{
|
||||
if (pid_.wide)
|
||||
return false;
|
||||
|
||||
const PacketIDData::data_id_t wrap_at = 0xFF000000;
|
||||
return pid_.id >= wrap_at;
|
||||
}
|
||||
|
||||
protected:
|
||||
PacketIDData pid_;
|
||||
};
|
||||
|
||||
/*
|
||||
@ -234,7 +266,7 @@ class PacketIDAEADSend
|
||||
*/
|
||||
template <unsigned int REPLAY_WINDOW_ORDER,
|
||||
unsigned int PKTID_RECV_EXPIRE>
|
||||
class PacketIDAEADReceiveType
|
||||
class PacketIDDataReceiveType
|
||||
{
|
||||
public:
|
||||
static constexpr unsigned int REPLAY_WINDOW_BYTES = 1u << REPLAY_WINDOW_ORDER;
|
||||
@ -268,7 +300,7 @@ class PacketIDAEADReceiveType
|
||||
* @param now Current time to check that reordered packets are in the allowed time
|
||||
* @return true if the packet id is okay and has been accepted
|
||||
*/
|
||||
[[nodiscard]] bool test_add(const PacketIDAEAD &pin,
|
||||
[[nodiscard]] bool test_add(const PacketIDData &pin,
|
||||
const Time::base_type now)
|
||||
{
|
||||
const Error::Type err = do_test_add(pin, now);
|
||||
@ -290,7 +322,7 @@ class PacketIDAEADReceiveType
|
||||
* @param now Current time to check that reordered packets are in the allowed time
|
||||
* @return Error::SUCCESS if successful, otherwise PKTID_EXPIRE, PKTID_BACKTRACK or PKTID_REPLAY
|
||||
*/
|
||||
[[nodiscard]] Error::Type do_test_add(const PacketIDAEAD &pin,
|
||||
[[nodiscard]] Error::Type do_test_add(const PacketIDData &pin,
|
||||
const Time::base_type now)
|
||||
{
|
||||
// expire backtracks at or below id_floor after PKTID_RECV_EXPIRE time
|
||||
@ -364,9 +396,9 @@ class PacketIDAEADReceiveType
|
||||
return Error::SUCCESS;
|
||||
}
|
||||
|
||||
PacketIDAEAD read_next(Buffer &buf) const
|
||||
PacketIDData read_next(Buffer &buf) const
|
||||
{
|
||||
PacketIDAEAD pid{wide};
|
||||
PacketIDData pid{wide};
|
||||
pid.read(buf);
|
||||
return pid;
|
||||
}
|
||||
@ -380,11 +412,11 @@ class PacketIDAEADReceiveType
|
||||
|
||||
[[nodiscard]] std::size_t constexpr length() const
|
||||
{
|
||||
return PacketIDAEAD::size(wide);
|
||||
return PacketIDData::size(wide);
|
||||
}
|
||||
|
||||
private:
|
||||
[[nodiscard]] constexpr std::size_t replay_index(PacketIDAEAD::aead_id_t i) const
|
||||
[[nodiscard]] constexpr std::size_t replay_index(PacketIDData::data_id_t i) const
|
||||
{
|
||||
return (base + i) & (REPLAY_WINDOW_SIZE - 1);
|
||||
}
|
||||
@ -392,8 +424,8 @@ class PacketIDAEADReceiveType
|
||||
std::size_t base; // bit position of deque base in history
|
||||
std::size_t extent; // extent (in bits) of deque in history
|
||||
Time::base_type expire; // expiration of history
|
||||
PacketIDAEAD::aead_id_t id_high; // highest sequence number received
|
||||
PacketIDAEAD::aead_id_t id_floor; // we will only accept backtrack IDs > id_floor
|
||||
PacketIDData::data_id_t id_high; // highest sequence number received
|
||||
PacketIDData::data_id_t id_floor; // we will only accept backtrack IDs > id_floor
|
||||
|
||||
//!< 32 or 64 bit packet counter
|
||||
bool wide;
|
||||
@ -408,6 +440,6 @@ class PacketIDAEADReceiveType
|
||||
|
||||
// Our standard packet ID window with order=8 (window size=2048).
|
||||
// and recv expire=30 seconds.
|
||||
typedef PacketIDAEADReceiveType<8, 30> PacketIDAEADReceive;
|
||||
typedef PacketIDDataReceiveType<8, 30> PacketIDDataReceive;
|
||||
|
||||
} // namespace openvpn
|
@ -32,7 +32,7 @@
|
||||
#include <openvpn/common/memneq.hpp>
|
||||
#include <openvpn/crypto/static_key.hpp>
|
||||
#include <openvpn/crypto/cryptoalgs.hpp>
|
||||
#include <openvpn/crypto/packet_id.hpp>
|
||||
#include <openvpn/crypto/packet_id_control.hpp>
|
||||
#include <openvpn/ssl/psid.hpp>
|
||||
|
||||
namespace openvpn {
|
||||
@ -190,7 +190,7 @@ class TLSCryptContext : public RC<thread_unsafe_refcount>
|
||||
// [OP] [PSID] [PID] [HMAC] [...]
|
||||
//
|
||||
|
||||
constexpr const static size_t hmac_offset = 1 + ProtoSessionID::SIZE + PacketID::longidsize;
|
||||
constexpr const static size_t hmac_offset = 1 + ProtoSessionID::SIZE + PacketIDControl::idsize;
|
||||
};
|
||||
|
||||
|
||||
|
@ -108,12 +108,12 @@ class Instance : public CryptoDCInstance
|
||||
// should never be reached.
|
||||
|
||||
// returns true if packet ID is close to wrapping
|
||||
bool encrypt(BufferAllocated &buf, const PacketID::time_t now, const unsigned char *op32) override
|
||||
bool encrypt(BufferAllocated &buf, const unsigned char *op32) override
|
||||
{
|
||||
throw korekey_error("encrypt");
|
||||
}
|
||||
|
||||
Error::Type decrypt(BufferAllocated &buf, const PacketID::time_t now, const unsigned char *op32) override
|
||||
Error::Type decrypt(BufferAllocated &buf, const std::time_t now, const unsigned char *op32) override
|
||||
{
|
||||
throw korekey_error("decrypt");
|
||||
}
|
||||
|
@ -30,7 +30,7 @@
|
||||
|
||||
#include <openvpn/common/socktypes.hpp>
|
||||
#include <openvpn/buffer/buffer.hpp>
|
||||
#include <openvpn/crypto/packet_id.hpp>
|
||||
#include <openvpn/crypto/packet_id_control.hpp>
|
||||
#include <openvpn/reliable/relcommon.hpp>
|
||||
|
||||
namespace openvpn {
|
||||
|
@ -24,13 +24,15 @@
|
||||
#ifndef OPENVPN_RELIABLE_RELCOMMON_H
|
||||
#define OPENVPN_RELIABLE_RELCOMMON_H
|
||||
|
||||
#include <openvpn/crypto/packet_id.hpp>
|
||||
#include <openvpn/crypto/packet_id_control.hpp>
|
||||
|
||||
namespace openvpn {
|
||||
|
||||
namespace reliable {
|
||||
typedef PacketID::id_t id_t;
|
||||
}
|
||||
typedef std::uint32_t id_t;
|
||||
constexpr static std::size_t id_size = sizeof(id_t);
|
||||
|
||||
} // namespace reliable
|
||||
|
||||
template <typename PACKET>
|
||||
class ReliableMessageBase
|
||||
|
@ -66,7 +66,7 @@
|
||||
#include <openvpn/crypto/ovpnhmac.hpp>
|
||||
#include <openvpn/crypto/tls_crypt.hpp>
|
||||
#include <openvpn/crypto/tls_crypt_v2.hpp>
|
||||
#include <openvpn/crypto/packet_id.hpp>
|
||||
#include <openvpn/crypto/packet_id_control.hpp>
|
||||
#include <openvpn/crypto/static_key.hpp>
|
||||
#include <openvpn/crypto/bs64_data_limit.hpp>
|
||||
#include <openvpn/log/sessionstats.hpp>
|
||||
@ -1180,11 +1180,11 @@ class ProtoContext : public logging::LoggingMixin<OPENVPN_DEBUG_PROTO,
|
||||
{
|
||||
dc_overhead = dc.context().encap_overhead();
|
||||
}
|
||||
const size_t adj = protocol.extra_transport_bytes() + // extra 2 bytes for TCP-streamed packet length
|
||||
(enable_op32 ? 4 : 1) + // leading op
|
||||
comp_ctx.extra_payload_bytes() + // compression header
|
||||
PacketID::size(PacketID::SHORT_FORM) + // sequence number
|
||||
dc_overhead; // data channel crypto layer overhead
|
||||
const size_t adj = protocol.extra_transport_bytes() + // extra 2 bytes for TCP-streamed packet length
|
||||
(enable_op32 ? 4 : 1) + // leading op
|
||||
comp_ctx.extra_payload_bytes() + // compression header
|
||||
PacketIDData::size(false) + // sequence number
|
||||
dc_overhead; // data channel crypto layer overhead
|
||||
return (unsigned int)adj;
|
||||
}
|
||||
|
||||
@ -1438,8 +1438,8 @@ class ProtoContext : public logging::LoggingMixin<OPENVPN_DEBUG_PROTO,
|
||||
|
||||
if (tls_wrap_mode == TLS_CRYPT || tls_wrap_mode == TLS_CRYPT_V2)
|
||||
{
|
||||
PacketID pid;
|
||||
pid.read(b, PacketID::LONG_FORM);
|
||||
PacketIDControl pid;
|
||||
pid.read(b);
|
||||
out << " PID=" << pid.str();
|
||||
|
||||
const unsigned char *hmac = b.read_alloc(hmac_size);
|
||||
@ -1453,8 +1453,8 @@ class ProtoContext : public logging::LoggingMixin<OPENVPN_DEBUG_PROTO,
|
||||
const unsigned char *hmac = b.read_alloc(hmac_size);
|
||||
out << " HMAC=" << render_hex(hmac, hmac_size);
|
||||
|
||||
PacketID pid;
|
||||
pid.read(b, PacketID::LONG_FORM);
|
||||
PacketIDControl pid;
|
||||
pid.read(b);
|
||||
out << " PID=" << pid.str();
|
||||
}
|
||||
|
||||
@ -2213,7 +2213,7 @@ class ProtoContext : public logging::LoggingMixin<OPENVPN_DEBUG_PROTO,
|
||||
}
|
||||
|
||||
if (CryptoAlgs::mode(c.dc.cipher()) == CryptoAlgs::CBC_HMAC)
|
||||
payload_overhead += PacketID::size(PacketID::SHORT_FORM);
|
||||
payload_overhead += PacketIDData::size(false);
|
||||
|
||||
// account for IPv4 and TCP headers of the payload, mssfix method
|
||||
// will add 20 extra bytes if payload is IPv6
|
||||
@ -2225,7 +2225,7 @@ class ProtoContext : public logging::LoggingMixin<OPENVPN_DEBUG_PROTO,
|
||||
|
||||
// in CBC mode, the packet id is part of the payload size / overhead
|
||||
if (CryptoAlgs::mode(c.dc.cipher()) != CryptoAlgs::CBC_HMAC)
|
||||
overhead += PacketID::size(PacketID::SHORT_FORM);
|
||||
overhead += PacketIDData::size(false);
|
||||
|
||||
if (c.mss_parms.mtu)
|
||||
{
|
||||
@ -2361,7 +2361,7 @@ class ProtoContext : public logging::LoggingMixin<OPENVPN_DEBUG_PROTO,
|
||||
orig_size,
|
||||
1 + ProtoSessionID::SIZE,
|
||||
proto.hmac_size,
|
||||
PacketID::size(PacketID::LONG_FORM)))
|
||||
PacketIDControl::size()))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
@ -2372,10 +2372,10 @@ class ProtoContext : public logging::LoggingMixin<OPENVPN_DEBUG_PROTO,
|
||||
return false;
|
||||
|
||||
// read tls_auth packet ID
|
||||
const PacketID pid = proto.ta_pid_recv.read_next(recv);
|
||||
const PacketIDControl pid = proto.ta_pid_recv.read_next(recv);
|
||||
|
||||
// get current time_t
|
||||
const PacketID::time_t t = now->seconds_since_epoch();
|
||||
const PacketIDControl::time_t t = now->seconds_since_epoch();
|
||||
|
||||
// verify tls_auth packet ID
|
||||
const bool pid_ok = proto.ta_pid_recv.test_add(pid, t, false);
|
||||
@ -2401,11 +2401,11 @@ class ProtoContext : public logging::LoggingMixin<OPENVPN_DEBUG_PROTO,
|
||||
// get source PSID
|
||||
ProtoSessionID src_psid(recv);
|
||||
// read tls_auth packet ID
|
||||
const PacketID pid = proto.ta_pid_recv.read_next(recv);
|
||||
const PacketIDControl pid = proto.ta_pid_recv.read_next(recv);
|
||||
|
||||
recv.advance(proto.hmac_size);
|
||||
|
||||
const size_t head_size = 1 + ProtoSessionID::SIZE + PacketID::size(PacketID::LONG_FORM);
|
||||
const size_t head_size = 1 + ProtoSessionID::SIZE + PacketIDControl::size();
|
||||
const size_t data_offset = head_size + proto.hmac_size;
|
||||
if (orig_size < data_offset)
|
||||
return false;
|
||||
@ -2445,7 +2445,7 @@ class ProtoContext : public logging::LoggingMixin<OPENVPN_DEBUG_PROTO,
|
||||
}
|
||||
|
||||
// get current time_t
|
||||
const PacketID::time_t t = now->seconds_since_epoch();
|
||||
const PacketIDControl::time_t t = now->seconds_since_epoch();
|
||||
|
||||
// verify tls_auth packet ID
|
||||
const bool pid_ok = proto.ta_pid_recv.test_add(pid, t, false);
|
||||
@ -2507,7 +2507,7 @@ class ProtoContext : public logging::LoggingMixin<OPENVPN_DEBUG_PROTO,
|
||||
static_assert(sizeof(op32) == OP_SIZE_V2, "OP_SIZE_V2 inconsistency");
|
||||
|
||||
// encrypt packet
|
||||
pid_wrap = crypto->encrypt(buf, now->seconds_since_epoch(), (const unsigned char *)&op32);
|
||||
pid_wrap = crypto->encrypt(buf, (const unsigned char *)&op32);
|
||||
|
||||
// prepend op
|
||||
buf.prepend((const unsigned char *)&op32, sizeof(op32));
|
||||
@ -2515,7 +2515,7 @@ class ProtoContext : public logging::LoggingMixin<OPENVPN_DEBUG_PROTO,
|
||||
else
|
||||
{
|
||||
// encrypt packet
|
||||
pid_wrap = crypto->encrypt(buf, now->seconds_since_epoch(), nullptr);
|
||||
pid_wrap = crypto->encrypt(buf, nullptr);
|
||||
|
||||
// prepend op
|
||||
buf.push_front(op_compose(DATA_V1, key_id_));
|
||||
@ -3002,7 +3002,7 @@ class ProtoContext : public logging::LoggingMixin<OPENVPN_DEBUG_PROTO,
|
||||
buf.size(),
|
||||
1 + ProtoSessionID::SIZE,
|
||||
proto.hmac_size,
|
||||
PacketID::size(PacketID::LONG_FORM));
|
||||
PacketIDControl::size());
|
||||
}
|
||||
|
||||
void gen_head_tls_crypt(const unsigned int opcode, BufferAllocated &buf)
|
||||
@ -3104,7 +3104,7 @@ class ProtoContext : public logging::LoggingMixin<OPENVPN_DEBUG_PROTO,
|
||||
gen_head(ACK_V1, buf);
|
||||
}
|
||||
|
||||
bool decapsulate_post_process(Packet &pkt, ProtoSessionID &src_psid, const PacketID pid)
|
||||
bool decapsulate_post_process(Packet &pkt, ProtoSessionID &src_psid, const PacketIDControl pid)
|
||||
{
|
||||
Buffer &recv = *pkt.buf;
|
||||
|
||||
@ -3116,7 +3116,7 @@ class ProtoContext : public logging::LoggingMixin<OPENVPN_DEBUG_PROTO,
|
||||
return false;
|
||||
|
||||
// get current time_t
|
||||
const PacketID::time_t t = now->seconds_since_epoch();
|
||||
const PacketIDControl::time_t t = now->seconds_since_epoch();
|
||||
// verify tls_auth/crypt packet ID
|
||||
const bool pid_ok = proto.ta_pid_recv.test_add(pid, t, false);
|
||||
|
||||
@ -3190,7 +3190,7 @@ class ProtoContext : public logging::LoggingMixin<OPENVPN_DEBUG_PROTO,
|
||||
orig_size,
|
||||
1 + ProtoSessionID::SIZE,
|
||||
proto.hmac_size,
|
||||
PacketID::size(PacketID::LONG_FORM)))
|
||||
PacketIDControl::size()))
|
||||
{
|
||||
proto.stats->error(Error::HMAC_ERROR);
|
||||
if (proto.is_tcp())
|
||||
@ -3200,7 +3200,7 @@ class ProtoContext : public logging::LoggingMixin<OPENVPN_DEBUG_PROTO,
|
||||
}
|
||||
|
||||
// read tls_auth packet ID
|
||||
const PacketID pid = proto.ta_pid_recv.read_next(recv);
|
||||
const PacketIDControl pid = proto.ta_pid_recv.read_next(recv);
|
||||
|
||||
return decapsulate_post_process(pkt, src_psid, pid);
|
||||
}
|
||||
@ -3216,7 +3216,7 @@ class ProtoContext : public logging::LoggingMixin<OPENVPN_DEBUG_PROTO,
|
||||
// get source PSID
|
||||
ProtoSessionID src_psid(recv);
|
||||
// get tls-crypt packet ID
|
||||
const PacketID pid = proto.ta_pid_recv.read_next(recv);
|
||||
const PacketIDControl pid = proto.ta_pid_recv.read_next(recv);
|
||||
// skip the hmac
|
||||
recv.advance(proto.hmac_size);
|
||||
|
||||
@ -3319,7 +3319,7 @@ class ProtoContext : public logging::LoggingMixin<OPENVPN_DEBUG_PROTO,
|
||||
const size_t orig_size = recv.size();
|
||||
const size_t hmac_size = proto.config->tls_crypt_context->digest_size();
|
||||
const size_t tls_frame_size = 1 + ProtoSessionID::SIZE
|
||||
+ PacketID::size(PacketID::LONG_FORM)
|
||||
+ PacketIDControl::size()
|
||||
+ hmac_size
|
||||
// the following is the tls-crypt payload
|
||||
+ sizeof(char) // length of ACK array
|
||||
@ -3631,7 +3631,7 @@ class ProtoContext : public logging::LoggingMixin<OPENVPN_DEBUG_PROTO,
|
||||
net_buf.size(),
|
||||
1 + ProtoSessionID::SIZE,
|
||||
ta_hmac_recv->output_size(),
|
||||
PacketID::size(PacketID::LONG_FORM));
|
||||
PacketIDControl::size());
|
||||
}
|
||||
catch (BufferException &)
|
||||
{
|
||||
@ -3825,8 +3825,8 @@ class ProtoContext : public logging::LoggingMixin<OPENVPN_DEBUG_PROTO,
|
||||
// get HMAC size from Digest object
|
||||
hmac_size = c.tls_crypt_context->digest_size();
|
||||
|
||||
ta_pid_send.init(PacketID::LONG_FORM);
|
||||
ta_pid_recv.init(PacketID::LONG_FORM, "SSL-CC", 0, stats);
|
||||
ta_pid_send.init();
|
||||
ta_pid_recv.init("SSL-CC", 0, stats);
|
||||
|
||||
reset_tls_crypt(c, dyn_key);
|
||||
}
|
||||
@ -3874,7 +3874,7 @@ class ProtoContext : public logging::LoggingMixin<OPENVPN_DEBUG_PROTO,
|
||||
upcoming_key_id = 0;
|
||||
|
||||
unsigned int key_dir;
|
||||
const PacketID::id_t EARLY_NEG_START = 0x0f000000;
|
||||
const PacketIDControl::id_t EARLY_NEG_START = 0x0f000000;
|
||||
|
||||
// tls-auth initialization
|
||||
reset_tls_wrap_mode(c);
|
||||
@ -3883,8 +3883,8 @@ class ProtoContext : public logging::LoggingMixin<OPENVPN_DEBUG_PROTO,
|
||||
case TLS_CRYPT:
|
||||
reset_tls_crypt(c, c.tls_key);
|
||||
// init tls_crypt packet ID
|
||||
ta_pid_send.init(PacketID::LONG_FORM);
|
||||
ta_pid_recv.init(PacketID::LONG_FORM, "SSL-CC", 0, stats);
|
||||
ta_pid_send.init();
|
||||
ta_pid_recv.init("SSL-CC", 0, stats);
|
||||
break;
|
||||
case TLS_CRYPT_V2:
|
||||
if (is_server())
|
||||
@ -3897,8 +3897,8 @@ class ProtoContext : public logging::LoggingMixin<OPENVPN_DEBUG_PROTO,
|
||||
/** tls-auth/tls-crypt packet id. We start with a different id here
|
||||
* to indicate EARLY_NEG_START/CONTROL_WKC_V1 support */
|
||||
// init tls_crypt packet ID
|
||||
ta_pid_send.init(PacketID::LONG_FORM, EARLY_NEG_START);
|
||||
ta_pid_recv.init(PacketID::LONG_FORM, "SSL-CC", 0, stats);
|
||||
ta_pid_send.init(EARLY_NEG_START);
|
||||
ta_pid_recv.init("SSL-CC", 0, stats);
|
||||
break;
|
||||
case TLS_AUTH:
|
||||
// init OvpnHMACInstance
|
||||
@ -3929,8 +3929,8 @@ class ProtoContext : public logging::LoggingMixin<OPENVPN_DEBUG_PROTO,
|
||||
* expect to handle the 1st packet, id 0.
|
||||
*
|
||||
*/
|
||||
ta_pid_send.init(PacketID::LONG_FORM, cookie_psid.defined() ? 1 : 0);
|
||||
ta_pid_recv.init(PacketID::LONG_FORM, "SSL-CC", 0, stats);
|
||||
ta_pid_send.init(cookie_psid.defined() ? 1 : 0);
|
||||
ta_pid_recv.init("SSL-CC", 0, stats);
|
||||
break;
|
||||
case TLS_PLAIN:
|
||||
break;
|
||||
@ -4702,8 +4702,8 @@ class ProtoContext : public logging::LoggingMixin<OPENVPN_DEBUG_PROTO,
|
||||
TLSCryptInstance::Ptr tls_crypt_server;
|
||||
TLSCryptMetadata::Ptr tls_crypt_metadata;
|
||||
|
||||
PacketIDSend ta_pid_send;
|
||||
PacketIDReceive ta_pid_recv;
|
||||
PacketIDControlSend ta_pid_send;
|
||||
PacketIDControlReceive ta_pid_recv;
|
||||
|
||||
ProtoSessionID psid_self;
|
||||
ProtoSessionID psid_peer;
|
||||
|
@ -144,7 +144,7 @@ class PsidCookieImpl : public PsidCookie
|
||||
{
|
||||
static const size_t hmac_size = ta_hmac_recv_->output_size();
|
||||
// ovpn_hmac_cmp checks for adequate pkt_buf.size()
|
||||
bool pkt_hmac_valid = ta_hmac_recv_->ovpn_hmac_cmp(pkt_buf.c_data(), pkt_buf.size(), 1 + SID_SIZE, hmac_size, long_pktid_size_);
|
||||
bool pkt_hmac_valid = ta_hmac_recv_->ovpn_hmac_cmp(pkt_buf.c_data(), pkt_buf.size(), 1 + SID_SIZE, hmac_size, PacketIDControl::idsize);
|
||||
if (!pkt_hmac_valid)
|
||||
{
|
||||
// JMD_TODO: log failure? Logging DDoS?
|
||||
@ -155,7 +155,7 @@ class PsidCookieImpl : public PsidCookie
|
||||
static const size_t reqd_packet_size
|
||||
// clang-format off
|
||||
// [op_field] [cli_psid] [HMAC] [cli_auth_pktid] [cli_pktid]
|
||||
= 1 + SID_SIZE + hmac_size + long_pktid_size_ + short_pktid_size_;
|
||||
= 1 + SID_SIZE + hmac_size + PacketIDControl::idsize + reliable::id_size;
|
||||
// clang-format on
|
||||
if (pkt_buf.size() < reqd_packet_size)
|
||||
{
|
||||
@ -169,10 +169,13 @@ class PsidCookieImpl : public PsidCookie
|
||||
// decapsulate_tls_auth
|
||||
const ProtoSessionID cli_psid(recv_buf_copy);
|
||||
recv_buf_copy.advance(hmac_size);
|
||||
PacketID cli_auth_pktid; // a.k.a, replay_packet_id in draft RFC
|
||||
cli_auth_pktid.read(recv_buf_copy, PacketID::LONG_FORM);
|
||||
PacketID cli_pktid; // a.k.a., packet_id in draft RFC
|
||||
cli_pktid.read(recv_buf_copy, PacketID::SHORT_FORM);
|
||||
|
||||
PacketIDControl cli_auth_pktid; // a.k.a, replay_packet_id in draft RFC
|
||||
cli_auth_pktid.read(recv_buf_copy);
|
||||
|
||||
uint8_t cli_net_id[4]; // a.k.a., packet_id in draft RFC
|
||||
|
||||
recv_buf_copy.read(cli_net_id, sizeof(cli_net_id));
|
||||
|
||||
// start building the server reply HARD_RESET packet
|
||||
BufferAllocated send_buf;
|
||||
@ -186,12 +189,11 @@ class PsidCookieImpl : public PsidCookie
|
||||
|
||||
// prepend_dest_psid_and_acks
|
||||
cli_psid.prepend(send_buf);
|
||||
const id_t cli_net_id = htonl(cli_pktid.id);
|
||||
send_buf.prepend((unsigned char *)&cli_net_id, sizeof(cli_net_id));
|
||||
send_buf.prepend(cli_net_id, sizeof(cli_net_id));
|
||||
send_buf.push_front((unsigned char)1);
|
||||
|
||||
// gen head
|
||||
PacketIDSend svr_auth_pid(PacketID::LONG_FORM);
|
||||
PacketIDControlSend svr_auth_pid{};
|
||||
svr_auth_pid.write_next(send_buf, true, now_->seconds_since_epoch());
|
||||
// make space for tls-auth HMAC
|
||||
send_buf.prepend_alloc(ta_hmac_send_->output_size());
|
||||
@ -202,7 +204,7 @@ class PsidCookieImpl : public PsidCookie
|
||||
const unsigned char op_field = CookieHelper::get_server_hard_reset_opfield();
|
||||
send_buf.push_front(op_field);
|
||||
// write hmac
|
||||
ta_hmac_send_->ovpn_hmac_gen(send_buf.data(), send_buf.size(), 1 + SID_SIZE, ta_hmac_send_->output_size(), long_pktid_size_);
|
||||
ta_hmac_send_->ovpn_hmac_gen(send_buf.data(), send_buf.size(), 1 + SID_SIZE, ta_hmac_send_->output_size(), PacketIDControl::idsize);
|
||||
|
||||
// consumer's implementation to send the SERVER_HARD_RESET to the client
|
||||
bool send_ok = pctb_->psid_cookie_send_const(send_buf, pcaib);
|
||||
@ -218,7 +220,7 @@ class PsidCookieImpl : public PsidCookie
|
||||
{
|
||||
static const size_t hmac_size = ta_hmac_recv_->output_size();
|
||||
// ovpn_hmac_cmp checks for adequate pkt_buf.size()
|
||||
bool pkt_hmac_valid = ta_hmac_recv_->ovpn_hmac_cmp(pkt_buf.c_data(), pkt_buf.size(), 1 + SID_SIZE, hmac_size, long_pktid_size_);
|
||||
bool pkt_hmac_valid = ta_hmac_recv_->ovpn_hmac_cmp(pkt_buf.c_data(), pkt_buf.size(), 1 + SID_SIZE, hmac_size, PacketIDControl::idsize);
|
||||
if (!pkt_hmac_valid)
|
||||
{
|
||||
// JMD_TODO: log failure? Logging DDoS?
|
||||
@ -228,7 +230,7 @@ class PsidCookieImpl : public PsidCookie
|
||||
static const size_t reqd_packet_size
|
||||
// clang-format off
|
||||
// [op_field] [cli_psid] [HMAC] [cli_auth_pktid] [acked] [srv_psid]
|
||||
= 1 + SID_SIZE + hmac_size + long_pktid_size_ + 5 + SID_SIZE;
|
||||
= 1 + SID_SIZE + hmac_size + PacketIDControl::size() + 5 + SID_SIZE;
|
||||
// the fixed size, 5, of the [acked] field recognizes that the client's first
|
||||
// response will ack exactly one packet, the server's HARD_RESET
|
||||
// clang-format on
|
||||
@ -244,8 +246,10 @@ class PsidCookieImpl : public PsidCookie
|
||||
// decapsulate_tls_auth
|
||||
const ProtoSessionID cli_psid(recv_buf_copy);
|
||||
recv_buf_copy.advance(hmac_size);
|
||||
PacketID cli_auth_pktid; // a.k.a, replay_packet_id in draft RFC
|
||||
cli_auth_pktid.read(recv_buf_copy, PacketID::LONG_FORM);
|
||||
|
||||
PacketIDControl cli_auth_pktid; // a.k.a, replay_packet_id in draft RFC
|
||||
cli_auth_pktid.read(recv_buf_copy);
|
||||
|
||||
unsigned int ack_count = recv_buf_copy[0];
|
||||
if (ack_count != 1)
|
||||
{
|
||||
@ -349,8 +353,6 @@ class PsidCookieImpl : public PsidCookie
|
||||
}
|
||||
|
||||
static constexpr CryptoAlgs::Type digest_ = CryptoAlgs::Type::SHA256;
|
||||
static constexpr size_t long_pktid_size_ = PacketID::size(PacketID::LONG_FORM);
|
||||
static constexpr size_t short_pktid_size_ = PacketID::size(PacketID::SHORT_FORM);
|
||||
|
||||
const ProtoContext::ProtoConfig &pcfg_;
|
||||
bool not_tls_auth_mode_;
|
||||
|
@ -63,7 +63,8 @@ add_executable(coreUnitTests
|
||||
test_ostream_containers.cpp
|
||||
test_parseargv.cpp
|
||||
test_path.cpp
|
||||
test_pktid.cpp
|
||||
test_pktid_control.cpp
|
||||
test_pktid_data.cpp
|
||||
test_prefixlen.cpp
|
||||
test_randapi.cpp
|
||||
test_rc.cpp
|
||||
|
@ -149,11 +149,11 @@ void test_datachannel_crypto(bool tag_at_the_end, bool longpktcounter = false)
|
||||
const unsigned char *data = work.data();
|
||||
EXPECT_TRUE(std::memcmp(data, plaintext, std::strlen(plaintext)) == 0);
|
||||
|
||||
const openvpn::PacketID::time_t now = 42;
|
||||
const std::time_t now = 42;
|
||||
|
||||
const unsigned char op32[]{7, 0, 0, 23};
|
||||
|
||||
bool const wrapwarn = cryptodc.encrypt(work, now, op32);
|
||||
bool const wrapwarn = cryptodc.encrypt(work, op32);
|
||||
ASSERT_FALSE(wrapwarn);
|
||||
|
||||
size_t pkt_counter_len = longpktcounter ? 8 : 4;
|
||||
|
@ -1,29 +1,38 @@
|
||||
#include "test_common.h"
|
||||
|
||||
#include <openvpn/crypto/packet_id.hpp>
|
||||
#include <openvpn/crypto/packet_id_aead.hpp>
|
||||
#include <openvpn/crypto/packet_id_control.hpp>
|
||||
|
||||
using namespace openvpn;
|
||||
|
||||
struct PacketIDControlConstruct : public PacketIDControl
|
||||
{
|
||||
PacketIDControlConstruct(const PacketIDControl::time_t v_time = PacketIDControl::time_t(0), const PacketIDControl::id_t v_id = PacketIDControl::id_t(0))
|
||||
{
|
||||
id = v_id;
|
||||
time = v_time;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
template <typename PIDRecv>
|
||||
void testcase(PIDRecv &pr,
|
||||
const PacketID::time_t t,
|
||||
const PacketID::time_t pkt_time,
|
||||
const PacketID::id_t pkt_id,
|
||||
const PacketIDControl::time_t t,
|
||||
const PacketIDControl::time_t pkt_time,
|
||||
const PacketIDControl::id_t pkt_id,
|
||||
const Error::Type expected_status)
|
||||
{
|
||||
const PacketIDConstruct pid(pkt_time, pkt_id);
|
||||
const PacketIDControlConstruct pid(pkt_time, pkt_id);
|
||||
const Error::Type status = pr.do_test_add(pid, t, true);
|
||||
// OPENVPN_LOG("[" << t << "] id=" << pkt_id << " time=" << pkt_time << ' ' << Error::name(status));
|
||||
ASSERT_EQ(status, expected_status);
|
||||
}
|
||||
|
||||
template <typename PIDRecv>
|
||||
void do_packet_id_recv_test()
|
||||
TEST(misc, pktid_test_control)
|
||||
{
|
||||
typedef PacketIDControlReceiveType<3, 5> PIDRecv;
|
||||
SessionStats::Ptr stats(new SessionStats());
|
||||
PIDRecv pr;
|
||||
pr.init(PacketID::SHORT_FORM, "test", 0, stats);
|
||||
pr.init("test", 0, stats);
|
||||
|
||||
testcase(pr, 0, 0, 0, Error::PKTID_INVALID);
|
||||
testcase(pr, 1, 0, 1, Error::SUCCESS);
|
||||
@ -78,12 +87,6 @@ void do_packet_id_recv_test()
|
||||
testcase(pr, 85, 15, 66, Error::SUCCESS);
|
||||
}
|
||||
|
||||
TEST(misc, pktid_test_normal)
|
||||
{
|
||||
do_packet_id_recv_test<PacketIDReceiveType<3, 5>>();
|
||||
}
|
||||
|
||||
|
||||
template <unsigned int ORDER, unsigned int EXPIRE>
|
||||
void perfiter(const long n,
|
||||
const long range,
|
||||
@ -91,20 +94,20 @@ void perfiter(const long n,
|
||||
const long iter_per_step_pre,
|
||||
long &count)
|
||||
{
|
||||
typedef PacketIDReceiveType<ORDER, EXPIRE> PIDRecv;
|
||||
typedef PacketIDControlReceiveType<ORDER, EXPIRE> PIDRecv;
|
||||
|
||||
const long iter_per_step = iter_per_step_pre * step;
|
||||
// OPENVPN_LOG("ITER order=" << ORDER << " n=" << n << " range=" << range << " step=" << step << " iter_per_step="
|
||||
// << iter_per_step);
|
||||
|
||||
constexpr PacketID::time_t pkt_time = 1234;
|
||||
constexpr PacketIDControl::time_t pkt_time = 1234;
|
||||
|
||||
MTRand urand;
|
||||
std::vector<bool> bv(n);
|
||||
long high = 0;
|
||||
SessionStats::Ptr stats(new SessionStats());
|
||||
PIDRecv pr;
|
||||
pr.init(PacketID::SHORT_FORM, "test", 0, stats);
|
||||
pr.init("test", 0, stats);
|
||||
|
||||
for (long i = 1; i < n; i += step)
|
||||
{
|
||||
@ -123,7 +126,7 @@ void perfiter(const long n,
|
||||
expected = Error::PKTID_BACKTRACK;
|
||||
else if (bv[id])
|
||||
expected = Error::PKTID_REPLAY;
|
||||
const PacketIDConstruct pid(0, static_cast<unsigned>(id));
|
||||
const PacketIDControlConstruct pid(0, static_cast<unsigned>(id));
|
||||
const Error::Type result = pr.do_test_add(pid, pkt_time, true);
|
||||
++count;
|
||||
#define INFO "i=" << i << " id=" << id << " high=" << high << " result=" << Error::name(result) << " expected=" << Error::name(expected)
|
||||
@ -139,7 +142,7 @@ void perfiter(const long n,
|
||||
template <unsigned int ORDER, unsigned int EXPIRE>
|
||||
void perf(long &count)
|
||||
{
|
||||
typedef PacketIDReceiveType<ORDER, EXPIRE> PIDRecv;
|
||||
typedef PacketIDControlReceiveType<ORDER, EXPIRE> PIDRecv;
|
||||
|
||||
perfiter<ORDER, EXPIRE>(20000, PIDRecv::REPLAY_WINDOW_SIZE * 3, 1, 10, count);
|
||||
perfiter<ORDER, EXPIRE>(20000, PIDRecv::REPLAY_WINDOW_SIZE * 3, PIDRecv::REPLAY_WINDOW_SIZE / 2, 10, count);
|
||||
@ -151,13 +154,11 @@ void perf(long &count)
|
||||
perfiter<ORDER, EXPIRE>(20000, 4, PIDRecv::REPLAY_WINDOW_SIZE / 2, 10, count);
|
||||
}
|
||||
|
||||
TEST(misc, pktid_perf)
|
||||
TEST(misc, pktid_control_perf)
|
||||
{
|
||||
{
|
||||
long count = 0;
|
||||
perf<3, 5>(count);
|
||||
perf<6, 5>(count);
|
||||
perf<8, 5>(count);
|
||||
// ASSERT_EQ(4746439, count);
|
||||
}
|
||||
long count = 0;
|
||||
perf<3, 5>(count);
|
||||
perf<6, 5>(count);
|
||||
perf<8, 5>(count);
|
||||
// ASSERT_EQ(4746439, count);
|
||||
}
|
264
test/unittests/test_pktid_data.cpp
Normal file
264
test/unittests/test_pktid_data.cpp
Normal file
@ -0,0 +1,264 @@
|
||||
#include "test_common.h"
|
||||
|
||||
#include <openvpn/crypto/packet_id_control.hpp>
|
||||
#include <openvpn/crypto/packet_id_data.hpp>
|
||||
|
||||
using namespace openvpn;
|
||||
|
||||
struct PacketIDDataConstruct : public PacketIDData
|
||||
{
|
||||
explicit PacketIDDataConstruct(const PacketIDData::data_id_t v_id = PacketIDData::data_id_t{0}, bool wide = false)
|
||||
: PacketIDData(wide)
|
||||
{
|
||||
id = v_id;
|
||||
}
|
||||
};
|
||||
|
||||
template <typename PIDRecv>
|
||||
void testcase(PIDRecv &pr,
|
||||
const std::time_t t,
|
||||
const PacketIDData::data_id_t pkt_id,
|
||||
const Error::Type expected_status)
|
||||
{
|
||||
bool wide = pr.length() > 4;
|
||||
const PacketIDDataConstruct pid(pkt_id, wide);
|
||||
const Error::Type status = pr.do_test_add(pid, t);
|
||||
// OPENVPN_LOG("[" << t << "] id=" << pkt_id << ' ' << Error::name(status));
|
||||
ASSERT_EQ(status, expected_status);
|
||||
}
|
||||
|
||||
void do_packet_id_recv_test_short_ids(bool usewide)
|
||||
{
|
||||
typedef PacketIDDataReceiveType<3, 5> PIDRecv;
|
||||
SessionStats::Ptr stats(new SessionStats());
|
||||
PIDRecv pr;
|
||||
pr.init("test", 0, usewide, stats);
|
||||
|
||||
testcase(pr, 0, 0, Error::PKTID_INVALID);
|
||||
testcase(pr, 1, 1, Error::SUCCESS);
|
||||
testcase(pr, 1, 1, Error::PKTID_REPLAY); /* replay */
|
||||
testcase(pr, 2, 2, Error::SUCCESS);
|
||||
testcase(pr, 3, 4, Error::SUCCESS);
|
||||
testcase(pr, 4, 1, Error::PKTID_REPLAY); /* replay */
|
||||
testcase(pr, 5, 3, Error::SUCCESS);
|
||||
|
||||
testcase(pr, 6, 8, Error::SUCCESS);
|
||||
testcase(pr, 10, 5, Error::SUCCESS);
|
||||
testcase(pr, 15, 7, Error::PKTID_EXPIRE); /* expire backtrack */
|
||||
|
||||
testcase(pr, 20, 127, Error::SUCCESS);
|
||||
testcase(pr, 20, 127, Error::PKTID_REPLAY);
|
||||
testcase(pr, 21, 128, Error::SUCCESS);
|
||||
testcase(pr, 22, 64, Error::PKTID_BACKTRACK); /* large backtrack */
|
||||
testcase(pr, 23, 65, Error::SUCCESS);
|
||||
testcase(pr, 24, 66, Error::SUCCESS);
|
||||
|
||||
testcase(pr, 30, 0, Error::PKTID_INVALID);
|
||||
testcase(pr, 33, 3, Error::PKTID_BACKTRACK); /* time backtrack */
|
||||
|
||||
testcase(pr, 40, 0xfffffffe, Error::SUCCESS);
|
||||
testcase(pr, 41, 0xffffffff, Error::SUCCESS);
|
||||
}
|
||||
|
||||
TEST(misc, do_packet_id_recv_test_long_ids)
|
||||
{
|
||||
typedef PacketIDDataReceiveType<3, 5> PIDRecv;
|
||||
PIDRecv pr;
|
||||
SessionStats::Ptr stats{new SessionStats()};
|
||||
pr.init("test", 0, true, stats);
|
||||
|
||||
testcase(pr, 40, 0xfffffffe, Error::SUCCESS);
|
||||
testcase(pr, 41, 0xffffffff, Error::SUCCESS);
|
||||
testcase(pr, 42, 0x100000001, Error::SUCCESS);
|
||||
testcase(pr, 42, 0xffffff0d, Error::PKTID_BACKTRACK);
|
||||
testcase(pr, 50, 0x200000000, Error::SUCCESS);
|
||||
testcase(pr, 50, 0x500000000, Error::SUCCESS);
|
||||
testcase(pr, 50, 0x400000000, Error::PKTID_BACKTRACK);
|
||||
testcase(pr, 50, 0x399999999, Error::PKTID_BACKTRACK);
|
||||
testcase(pr, 50, 0x3ffffffff, Error::PKTID_BACKTRACK);
|
||||
testcase(pr, 50, 0x4ffffffff, Error::SUCCESS);
|
||||
}
|
||||
|
||||
|
||||
TEST(misc, pktid_test_data_32bit)
|
||||
{
|
||||
do_packet_id_recv_test_short_ids(false);
|
||||
}
|
||||
|
||||
TEST(misc, pktid_test_data_64bit)
|
||||
{
|
||||
do_packet_id_recv_test_short_ids(true);
|
||||
}
|
||||
|
||||
|
||||
template <unsigned int ORDER, unsigned int EXPIRE>
|
||||
void perfiter(const long n,
|
||||
const long range,
|
||||
const long step,
|
||||
const long iter_per_step_pre,
|
||||
long &count)
|
||||
{
|
||||
typedef PacketIDDataReceiveType<ORDER, EXPIRE> PIDRecv;
|
||||
|
||||
const long iter_per_step = iter_per_step_pre * step;
|
||||
// OPENVPN_LOG("ITER order=" << ORDER << " n=" << n << " range=" << range << " step=" << step << " iter_per_step="
|
||||
// << iter_per_step);
|
||||
|
||||
constexpr std::time_t pkt_time = 1234;
|
||||
|
||||
MTRand urand;
|
||||
std::vector<bool> bv(n);
|
||||
long high = 0;
|
||||
SessionStats::Ptr stats(new SessionStats());
|
||||
PIDRecv pr;
|
||||
pr.init("test", 0, false, stats);
|
||||
|
||||
for (long i = 1; i < n; i += step)
|
||||
{
|
||||
for (long j = 0; j < iter_per_step; ++j)
|
||||
{
|
||||
const long delta = long(urand.randrange32(static_cast<uint32_t>(range))) - range / 2;
|
||||
const long id = i + delta;
|
||||
if (id >= 0 && id < n)
|
||||
{
|
||||
if (id > high)
|
||||
high = id;
|
||||
Error::Type expected = Error::SUCCESS;
|
||||
if (!id)
|
||||
expected = Error::PKTID_INVALID;
|
||||
else if (high - id >= (const long)PIDRecv::REPLAY_WINDOW_SIZE)
|
||||
expected = Error::PKTID_BACKTRACK;
|
||||
else if (bv[id])
|
||||
expected = Error::PKTID_REPLAY;
|
||||
const PacketIDDataConstruct pid(id);
|
||||
const Error::Type result = pr.do_test_add(pid, pkt_time);
|
||||
++count;
|
||||
#define INFO "i=" << i << " id=" << id << " high=" << high << " result=" << Error::name(result) << " expected=" << Error::name(expected)
|
||||
// OPENVPN_LOG(INFO);
|
||||
ASSERT_EQ(result, expected) << INFO;
|
||||
if (expected == Error::SUCCESS)
|
||||
bv[id] = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template <unsigned int ORDER, unsigned int EXPIRE>
|
||||
void perf(long &count)
|
||||
{
|
||||
typedef PacketIDDataReceiveType<ORDER, EXPIRE> PIDRecv;
|
||||
|
||||
perfiter<ORDER, EXPIRE>(20000, PIDRecv::REPLAY_WINDOW_SIZE * 3, 1, 10, count);
|
||||
perfiter<ORDER, EXPIRE>(20000, PIDRecv::REPLAY_WINDOW_SIZE * 3, PIDRecv::REPLAY_WINDOW_SIZE / 2, 10, count);
|
||||
perfiter<ORDER, EXPIRE>(20000, PIDRecv::REPLAY_WINDOW_SIZE * 2, 1, 10, count);
|
||||
perfiter<ORDER, EXPIRE>(20000, PIDRecv::REPLAY_WINDOW_SIZE * 2, PIDRecv::REPLAY_WINDOW_SIZE / 2, 10, count);
|
||||
perfiter<ORDER, EXPIRE>(20000, 16, 1, 10, count);
|
||||
perfiter<ORDER, EXPIRE>(20000, 16, PIDRecv::REPLAY_WINDOW_SIZE / 2, 10, count);
|
||||
perfiter<ORDER, EXPIRE>(20000, 4, 1, 10, count);
|
||||
perfiter<ORDER, EXPIRE>(20000, 4, PIDRecv::REPLAY_WINDOW_SIZE / 2, 10, count);
|
||||
}
|
||||
|
||||
|
||||
class PacketIDDataSendTest : public openvpn::PacketIDDataSend
|
||||
{
|
||||
public:
|
||||
PacketIDDataSendTest(bool wide, std::uint64_t start)
|
||||
: openvpn::PacketIDDataSend(wide)
|
||||
{
|
||||
pid_ = PacketIDDataConstruct{start, wide};
|
||||
}
|
||||
};
|
||||
|
||||
TEST(misc, pktid_32_bit_overrun_32bit_counter)
|
||||
{
|
||||
PacketIDDataSendTest pidsend{false, 0xfffffffc};
|
||||
|
||||
auto ret = pidsend.next();
|
||||
EXPECT_EQ(ret.str(), "[0xfffffffd]");
|
||||
|
||||
ret = pidsend.next();
|
||||
EXPECT_EQ(ret.str(), "[0xfffffffe]");
|
||||
|
||||
EXPECT_THROW(ret = pidsend.next(), PacketIDDataSend::packet_id_wrap);
|
||||
}
|
||||
|
||||
|
||||
TEST(misc, pktid_32_bit_overrun_64bit_counter)
|
||||
{
|
||||
PacketIDDataSendTest pidsend{true, 0xfffffffd};
|
||||
|
||||
auto ret = pidsend.next();
|
||||
EXPECT_EQ(ret.str(), "[0xfffffffe]");
|
||||
|
||||
ret = pidsend.next();
|
||||
EXPECT_EQ(ret.str(), "[0xffffffff]");
|
||||
|
||||
ret = pidsend.next();
|
||||
EXPECT_EQ(ret.str(), "[0x100000000]");
|
||||
|
||||
ret = pidsend.next();
|
||||
EXPECT_EQ(ret.str(), "[0x100000001]");
|
||||
}
|
||||
|
||||
|
||||
TEST(misc, pktid_64_bit_overrun_64bit_counter)
|
||||
{
|
||||
PacketIDDataSendTest pidsend{true, 0xfffffffffffffffc};
|
||||
|
||||
auto ret = pidsend.next();
|
||||
EXPECT_EQ(ret.str(), "[0xfffffffffffffffd]");
|
||||
|
||||
ret = pidsend.next();
|
||||
EXPECT_EQ(ret.str(), "[0xfffffffffffffffe]");
|
||||
|
||||
EXPECT_THROW(ret = pidsend.next(), PacketIDDataSend::packet_id_wrap);
|
||||
}
|
||||
|
||||
TEST(misc, pktid_32_bit_warn)
|
||||
{
|
||||
PacketIDDataSendTest pidsend{false, 0xfefffffe};
|
||||
|
||||
EXPECT_FALSE(pidsend.wrap_warning());
|
||||
auto ret = pidsend.next();
|
||||
EXPECT_EQ(ret.str(), "[0xfeffffff]");
|
||||
EXPECT_FALSE(pidsend.wrap_warning());
|
||||
|
||||
ret = pidsend.next();
|
||||
EXPECT_EQ(ret.str(), "[0xff000000]");
|
||||
EXPECT_TRUE(pidsend.wrap_warning());
|
||||
|
||||
ret = pidsend.next();
|
||||
EXPECT_EQ(ret.str(), "[0xff000001]");
|
||||
EXPECT_TRUE(pidsend.wrap_warning());
|
||||
}
|
||||
|
||||
TEST(misc, pktid_64_bit_warn_32bit)
|
||||
{
|
||||
// Test we are not warning at 32bit
|
||||
PacketIDDataSendTest pidsend{true, 0xfefffffe};
|
||||
|
||||
EXPECT_FALSE(pidsend.wrap_warning());
|
||||
auto ret = pidsend.next();
|
||||
EXPECT_EQ(ret.str(), "[0xfeffffff]");
|
||||
EXPECT_FALSE(pidsend.wrap_warning());
|
||||
|
||||
ret = pidsend.next();
|
||||
EXPECT_EQ(ret.str(), "[0xff000000]");
|
||||
EXPECT_FALSE(pidsend.wrap_warning());
|
||||
|
||||
ret = pidsend.next();
|
||||
EXPECT_EQ(ret.str(), "[0xff000001]");
|
||||
EXPECT_FALSE(pidsend.wrap_warning());
|
||||
}
|
||||
|
||||
|
||||
TEST(misc, pktid_data_perf)
|
||||
{
|
||||
{
|
||||
long count = 0;
|
||||
perf<3, 5>(count);
|
||||
perf<6, 5>(count);
|
||||
perf<8, 5>(count);
|
||||
// ASSERT_EQ(4746439, count);
|
||||
}
|
||||
}
|
@ -18,7 +18,7 @@
|
||||
#include <openvpn/reliable/relrecv.hpp>
|
||||
#include <openvpn/reliable/relsend.hpp>
|
||||
#include <openvpn/reliable/relack.hpp>
|
||||
#include <openvpn/crypto/packet_id.hpp>
|
||||
#include <openvpn/crypto/packet_id_control.hpp>
|
||||
|
||||
using namespace openvpn;
|
||||
|
||||
@ -154,14 +154,14 @@ typedef ReliableRecvTemplate<Packet> ReliableRecv;
|
||||
|
||||
struct Message
|
||||
{
|
||||
openvpn::PacketID::id_t id;
|
||||
openvpn::PacketIDControl::id_t id;
|
||||
BufferPtr buffer;
|
||||
};
|
||||
|
||||
void print_msg(const Time::Duration t,
|
||||
const char *title,
|
||||
BufferPtr &buf,
|
||||
const openvpn::PacketID::id_t id,
|
||||
const openvpn::PacketIDControl::id_t id,
|
||||
std::stringstream &case_detail)
|
||||
{
|
||||
case_detail << t.raw() << ' ' << title
|
||||
@ -175,7 +175,7 @@ void test(MTRand &rand,
|
||||
const Time::Duration end,
|
||||
const Time::Duration step,
|
||||
const Time::Duration end_sends,
|
||||
const openvpn::PacketID::id_t relsize,
|
||||
const openvpn::PacketIDControl::id_t relsize,
|
||||
const size_t wiresize,
|
||||
const unsigned int reorder_prob,
|
||||
const unsigned int drop_prob,
|
||||
@ -193,8 +193,8 @@ void test(MTRand &rand,
|
||||
long iterations = 0;
|
||||
Time::Duration t;
|
||||
|
||||
openvpn::PacketID::id_t send_id = 0;
|
||||
openvpn::PacketID::id_t rec_id = 0;
|
||||
openvpn::PacketIDControl::id_t send_id = 0;
|
||||
openvpn::PacketIDControl::id_t rec_id = 0;
|
||||
|
||||
for (t = Time::Duration(); t < end; t += step)
|
||||
{
|
||||
@ -204,7 +204,7 @@ void test(MTRand &rand,
|
||||
// sender processes ACKs received from receiver
|
||||
while (!acklist.empty())
|
||||
{
|
||||
const openvpn::PacketID::id_t id = acklist.front();
|
||||
const openvpn::PacketIDControl::id_t id = acklist.front();
|
||||
acklist.pop_front();
|
||||
if (rand.randrange(40)) // with small probability, simulate a dropped ACK
|
||||
// JMD_TODO: why wouldn't this have drop_prob probability
|
||||
@ -221,7 +221,7 @@ void test(MTRand &rand,
|
||||
// scan the sender history for un-ACKed packets that need to be retransmitted
|
||||
if (now >= retrans)
|
||||
{
|
||||
for (openvpn::PacketID::id_t i = send.head_id(); i < send.tail_id(); ++i)
|
||||
for (openvpn::PacketIDControl::id_t i = send.head_id(); i < send.tail_id(); ++i)
|
||||
{
|
||||
ReliableSend::Message &m = send.ref_by_id(i);
|
||||
if (m.ready_retransmit(now))
|
||||
@ -327,7 +327,7 @@ void test(MTRand &rand,
|
||||
struct test_params
|
||||
{
|
||||
int test_case;
|
||||
openvpn::PacketID::id_t relsize;
|
||||
openvpn::PacketIDControl::id_t relsize;
|
||||
size_t wiresize;
|
||||
unsigned int reorder_prob;
|
||||
unsigned int drop_prob;
|
||||
|
Loading…
Reference in New Issue
Block a user