forked from OpenVPN/openvpn3
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
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.
- Loading branch information
1 parent
26d0169
commit 662bf78
Showing
13 changed files
with
776 additions
and
202 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,45 @@ | ||
// 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/>. | ||
|
||
// Special data limits on 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. Note that we trigger early at | ||
// 48 MB to compensate for possible delays in renegotiation and | ||
// rollover to the new key. | ||
|
||
#ifndef OPENVPN_CRYPTO_DATALIMIT_H | ||
#define OPENVPN_CRYPTO_DATALIMIT_H | ||
|
||
#include <openvpn/crypto/cryptoalgs.hpp> | ||
|
||
#ifndef OPENVPN_BS64_DATA_LIMIT | ||
#define OPENVPN_BS64_DATA_LIMIT 48000000 | ||
#endif | ||
|
||
namespace openvpn { | ||
inline bool is_bs64_cipher(const CryptoAlgs::Type cipher) | ||
{ | ||
return CryptoAlgs::get(cipher).block_size() == 8; | ||
} | ||
} | ||
|
||
#endif |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,188 @@ | ||
// OpenVPN | ||
// Copyright (C) 2012-2015 OpenVPN Technologies, Inc. | ||
// All rights reserved | ||
|
||
#ifndef OPENVPN_SSL_DATALIMIT_H | ||
#define OPENVPN_SSL_DATALIMIT_H | ||
|
||
#include <openvpn/common/exception.hpp> | ||
|
||
namespace openvpn { | ||
// Helper for handling keys which can have an upper limit | ||
// on maximum amount of data encrypted/decrypted, such | ||
// as Blowfish. | ||
class DataLimit | ||
{ | ||
public: | ||
typedef unsigned int size_type; | ||
|
||
enum Mode { | ||
Encrypt=0, | ||
Decrypt=1, | ||
}; | ||
|
||
enum State { | ||
None=0, | ||
Green=1, | ||
Red=2, | ||
}; | ||
|
||
struct Parameters | ||
{ | ||
size_type encrypt_red_limit = 0; | ||
size_type decrypt_red_limit = 0; | ||
}; | ||
|
||
DataLimit(const Parameters& p) | ||
: encrypt(p.encrypt_red_limit), | ||
decrypt(p.decrypt_red_limit) | ||
{ | ||
} | ||
|
||
State update_state(const Mode mode, const State newstate) | ||
{ | ||
return elgible(mode, component(mode).update_state(newstate)); | ||
} | ||
|
||
State add(const Mode mode, const size_type n) | ||
{ | ||
return elgible(mode, component(mode).add(n)); | ||
} | ||
|
||
bool is_decrypt_green() | ||
{ | ||
return decrypt.get_state() >= Green; | ||
} | ||
|
||
static const char *mode_str(const Mode m) | ||
{ | ||
switch (m) | ||
{ | ||
case Encrypt: | ||
return "Encrypt"; | ||
case Decrypt: | ||
return "Decrypt"; | ||
default: | ||
return "Mode_???"; | ||
} | ||
} | ||
|
||
static const char *state_str(const State s) | ||
{ | ||
switch (s) | ||
{ | ||
case None: | ||
return "None"; | ||
case Green: | ||
return "Green"; | ||
case Red: | ||
return "Red"; | ||
default: | ||
return "State_???"; | ||
} | ||
} | ||
|
||
private: | ||
// Don't return Encrypt-Red until Decrypt-Green | ||
// has been received. This confirms that the peer | ||
// is now transmitting on the key ID, making it | ||
// eligible for renegotiation. | ||
State elgible(const Mode mode, const State state) | ||
{ | ||
// Bit positions for Encrypt/Decrypt and Green/Red | ||
enum { | ||
EG = 1<<0, | ||
ER = 1<<1, | ||
DG = 1<<2, | ||
DR = 1<<3, | ||
}; | ||
if (state > None) | ||
{ | ||
const unsigned int mask = 1 << ((int(state) - 1) + (int(mode) << 1)); | ||
if (!(flags & mask)) | ||
{ | ||
flags |= mask; | ||
if ((mask & (ER|DG)) && ((flags & (ER|DG)) == (ER|DG))) | ||
return Red; | ||
else if (mask & ER) | ||
return None; | ||
else | ||
return state; | ||
} | ||
} | ||
return None; | ||
} | ||
|
||
class Component | ||
{ | ||
public: | ||
Component(const size_type red_limit_arg) | ||
: red_limit(red_limit_arg) | ||
{ | ||
} | ||
|
||
State add(const size_type n) | ||
{ | ||
bytes += n; | ||
return update_state(transition(state)); | ||
} | ||
|
||
State update_state(const State newstate) | ||
{ | ||
State ret = None; | ||
if (newstate > state) | ||
state = ret = newstate; | ||
return ret; | ||
} | ||
|
||
State get_state() const | ||
{ | ||
return state; | ||
} | ||
|
||
private: | ||
State transition(State s) const | ||
{ | ||
switch (s) | ||
{ | ||
case None: | ||
if (bytes) | ||
return Green; | ||
else | ||
return None; | ||
case Green: | ||
if (red_limit && bytes >= red_limit) | ||
return Red; | ||
else | ||
return None; | ||
case Red: | ||
default: | ||
return None; | ||
} | ||
} | ||
|
||
const size_type red_limit; | ||
size_type bytes = 0; | ||
State state = None; | ||
}; | ||
|
||
Component& component(const Mode m) | ||
{ | ||
switch (m) | ||
{ | ||
case Encrypt: | ||
return encrypt; | ||
case Decrypt: | ||
return decrypt; | ||
default: | ||
throw Exception("DataLimit::Component: unknown mode"); | ||
} | ||
} | ||
|
||
Component encrypt; | ||
Component decrypt; | ||
unsigned int flags = 0; | ||
}; | ||
} | ||
|
||
#endif |
Oops, something went wrong.