0
0
mirror of https://github.com/OpenVPN/openvpn3.git synced 2024-09-20 04:02:15 +02:00
openvpn3/openvpn/reliable/relsend.hpp
James Yonan 662bf7833e ovpn3 core : Added automatic data limits for Blowfish,
Triple DES, and other 64-bit block-size ciphers vulnerable
to "Sweet32" birthday attack (CVE-2016-6329).  Limit such
cipher keys to no more than 64 MB of data
encrypted/decrypted.  While our overall goal is to limit
data-limited keys to 64 MB, we trigger a renegotiation
at 48 MB to compensate for possible delays in renegotiation
and rollover to the new key.

This client-side implementation extends data limit
protection to the entire session, even when the server
doesn't implement data limits.

This capability is advertised to servers via the a
peer info setting:

  IV_BS64DL=1

meaning "Block-Size 64-bit Data Limit".  The "1" indicates
the implementation version.

The implementation currently has some limitations:

* Keys are renegotiated at a maximum rate of once per
  5 seconds to reduce the likelihood of loss of
  synchronization between peers.

* The maximum renegotiation rate may be further extended
  if the peer delays rollover from the old to new key
  after renegotiation.

Added N_KEY_LIMIT_RENEG stats counter to count the number
of data-limit-triggered renegotiations.

Added new stats counter KEY_STATE_ERROR which roughly
corresponds to the OpenVPN 2.x error "TLS Error:
local/remote TLS keys are out of sync".

Prevously, the TLS ack/retransmit timeout was hardcoded to
2 seconds.  Now we lower the default to 1 second and make
it variable using the (pushable) "tls-timeout" directive.
Additionally, the tls-timeout directive can be specified
in milliseconds instead of seconds by using the
"tls-timeout-ms" form of the directive.

Made the "become primary" time duration configurable via
the (pushable) "become-primary" directive which accepts
a number-of-seconds parameter.  become-primary indicates
the time delay between renegotiation and rollover to the
new key for encryption/transmission.  become-primary
defaults to the handshake-window which in turn defaults
to 60 seconds.

Incremented core version to 3.0.20.
2016-09-01 15:19:00 -06:00

149 lines
4.1 KiB
C++

// OpenVPN -- An application to securely tunnel IP networks
// over a single port, with support for SSL/TLS-based
// session authentication and key exchange,
// packet encryption, packet authentication, and
// packet compression.
//
// Copyright (C) 2012-2015 OpenVPN Technologies, Inc.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License Version 3
// as published by the Free Software Foundation.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program in the COPYING file.
// If not, see <http://www.gnu.org/licenses/>.
// Sender side of reliability layer
#ifndef OPENVPN_RELIABLE_RELSEND_H
#define OPENVPN_RELIABLE_RELSEND_H
#include <openvpn/common/size.hpp>
#include <openvpn/common/exception.hpp>
#include <openvpn/common/msgwin.hpp>
#include <openvpn/time/time.hpp>
#include <openvpn/reliable/relcommon.hpp>
namespace openvpn {
template <typename PACKET>
class ReliableSendTemplate
{
public:
typedef reliable::id_t id_t;
class Message : public ReliableMessageBase<PACKET>
{
friend class ReliableSendTemplate;
using ReliableMessageBase<PACKET>::defined;
public:
bool ready_retransmit(const Time& now) const
{
return defined() && now >= retransmit_at_;
}
Time::Duration until_retransmit(const Time& now) const
{
Time::Duration ret;
if (now < retransmit_at_)
ret = retransmit_at_ - now;
return ret;
}
void reset_retransmit(const Time& now, const Time::Duration& tls_timeout)
{
retransmit_at_ = now + tls_timeout;
}
private:
Time retransmit_at_;
};
ReliableSendTemplate() : next(0) {}
ReliableSendTemplate(const id_t span) { init(span); }
void init(const id_t span)
{
next = 0;
window_.init(next, span);
}
// Return the id that the object at the head of the queue
// would have (even if it isn't defined yet).
id_t head_id() const { return window_.head_id(); }
// Return the ID of one past the end of the window
id_t tail_id() const { return window_.tail_id(); }
// Return the window size
id_t span() const { return window_.span(); }
// Return a reference to M object at id, throw exception
// if id is not in current window
Message& ref_by_id(const id_t id)
{
return window_.ref_by_id(id);
}
// Return the shortest duration for any pending retransmissions
Time::Duration until_retransmit(const Time& now)
{
Time::Duration ret = Time::Duration::infinite();
for (id_t i = head_id(); i < tail_id(); ++i)
{
const Message& msg = ref_by_id(i);
if (msg.defined())
{
Time::Duration ut = msg.until_retransmit(now);
if (ut < ret)
ret = ut;
}
}
return ret;
}
// Return number of unacknowleged packets in send queue
unsigned int n_unacked()
{
unsigned int ret = 0;
for (id_t i = head_id(); i < tail_id(); ++i)
{
if (ref_by_id(i).defined())
++ret;
}
return ret;
}
// Return a fresh Message object that can be used to
// construct the next packet in the sequence. Don't call
// unless ready() returns true.
Message& send(const Time& now, const Time::Duration& tls_timeout)
{
Message& msg = window_.ref_by_id(next);
msg.id_ = next++;
msg.reset_retransmit(now, tls_timeout);
return msg;
}
// Return true if send queue is ready to receive another packet
bool ready() const { return window_.in_window(next); }
// Remove a message from send queue that has been acknowledged
void ack(const id_t id) { window_.rm_by_id(id); }
private:
id_t next;
MessageWindow<Message, id_t> window_;
};
} // namespace openvpn
#endif // OPENVPN_RELIABLE_RELSEND_H