mirror of
https://github.com/ZeroTier/ZeroTierOne
synced 2025-08-20 13:24:09 -07:00
Docs, code cleanup, and protect the extra new fields of HELLO with encryption as a precaution.
This commit is contained in:
parent
594cb1fad8
commit
43182f8f57
13 changed files with 163 additions and 116 deletions
|
@ -293,6 +293,11 @@
|
|||
*/
|
||||
#define ZT_PEER_PATH_EXPIRATION ((ZT_PEER_PING_PERIOD * 4) + 3000)
|
||||
|
||||
/**
|
||||
* Send a full HELLO every this often (ms)
|
||||
*/
|
||||
#define ZT_PEER_SEND_FULL_HELLO_EVERY (ZT_PEER_PING_PERIOD * 2)
|
||||
|
||||
/**
|
||||
* How often to retry expired paths that we're still remembering
|
||||
*/
|
||||
|
|
|
@ -46,7 +46,7 @@ static inline void _computeMemoryHardHash(const void *publicKey,unsigned int pub
|
|||
// but is not what we want for sequential memory-harndess.
|
||||
memset(genmem,0,ZT_IDENTITY_GEN_MEMORY);
|
||||
Salsa20 s20(digest,256,(char *)digest + 32);
|
||||
s20.encrypt20((char *)genmem,(char *)genmem,64);
|
||||
s20.crypt20((char *)genmem,(char *)genmem,64);
|
||||
for(unsigned long i=64;i<ZT_IDENTITY_GEN_MEMORY;i+=64) {
|
||||
unsigned long k = i - 64;
|
||||
*((uint64_t *)((char *)genmem + i)) = *((uint64_t *)((char *)genmem + k));
|
||||
|
@ -57,7 +57,7 @@ static inline void _computeMemoryHardHash(const void *publicKey,unsigned int pub
|
|||
*((uint64_t *)((char *)genmem + i + 40)) = *((uint64_t *)((char *)genmem + k + 40));
|
||||
*((uint64_t *)((char *)genmem + i + 48)) = *((uint64_t *)((char *)genmem + k + 48));
|
||||
*((uint64_t *)((char *)genmem + i + 56)) = *((uint64_t *)((char *)genmem + k + 56));
|
||||
s20.encrypt20((char *)genmem + i,(char *)genmem + i,64);
|
||||
s20.crypt20((char *)genmem + i,(char *)genmem + i,64);
|
||||
}
|
||||
|
||||
// Render final digest using genmem as a lookup table
|
||||
|
@ -67,7 +67,7 @@ static inline void _computeMemoryHardHash(const void *publicKey,unsigned int pub
|
|||
uint64_t tmp = ((uint64_t *)genmem)[idx2];
|
||||
((uint64_t *)genmem)[idx2] = ((uint64_t *)digest)[idx1];
|
||||
((uint64_t *)digest)[idx1] = tmp;
|
||||
s20.encrypt20(digest,digest,64);
|
||||
s20.crypt20(digest,digest,64);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -213,44 +213,19 @@ bool IncomingPacket::_doHELLO(const RuntimeEnvironment *RR,const bool alreadyAut
|
|||
const unsigned int vRevision = at<uint16_t>(ZT_PROTO_VERB_HELLO_IDX_REVISION);
|
||||
const uint64_t timestamp = at<uint64_t>(ZT_PROTO_VERB_HELLO_IDX_TIMESTAMP);
|
||||
|
||||
Identity id;
|
||||
InetAddress externalSurfaceAddress;
|
||||
uint64_t planetWorldId = 0;
|
||||
uint64_t planetWorldTimestamp = 0;
|
||||
std::vector< std::pair<uint64_t,uint64_t> > moonIdsAndTimestamps;
|
||||
{
|
||||
unsigned int ptr = ZT_PROTO_VERB_HELLO_IDX_IDENTITY + id.deserialize(*this,ZT_PROTO_VERB_HELLO_IDX_IDENTITY);
|
||||
|
||||
// Get external surface address if present (was not in old versions)
|
||||
if (ptr < size())
|
||||
ptr += externalSurfaceAddress.deserialize(*this,ptr);
|
||||
|
||||
// Get primary planet world ID and world timestamp if present
|
||||
if ((ptr + 16) <= size()) {
|
||||
planetWorldId = at<uint64_t>(ptr); ptr += 8;
|
||||
planetWorldTimestamp = at<uint64_t>(ptr);
|
||||
}
|
||||
|
||||
// Get moon IDs and timestamps if present
|
||||
if ((ptr + 2) <= size()) {
|
||||
unsigned int numMoons = at<uint16_t>(ptr); ptr += 2;
|
||||
for(unsigned int i=0;i<numMoons;++i) {
|
||||
if ((World::Type)(*this)[ptr++] == World::TYPE_MOON)
|
||||
moonIdsAndTimestamps.push_back(std::pair<uint64_t,uint64_t>(at<uint64_t>(ptr),at<uint64_t>(ptr + 8)));
|
||||
ptr += 16;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (fromAddress != id.address()) {
|
||||
TRACE("dropped HELLO from %s(%s): identity not for sending address",fromAddress.toString().c_str(),_path->address().toString().c_str());
|
||||
return true;
|
||||
}
|
||||
if (protoVersion < ZT_PROTO_VERSION_MIN) {
|
||||
TRACE("dropped HELLO from %s(%s): protocol version too old",id.address().toString().c_str(),_path->address().toString().c_str());
|
||||
return true;
|
||||
}
|
||||
|
||||
Identity id;
|
||||
unsigned int ptr = ZT_PROTO_VERB_HELLO_IDX_IDENTITY + id.deserialize(*this,ZT_PROTO_VERB_HELLO_IDX_IDENTITY);
|
||||
|
||||
if (fromAddress != id.address()) {
|
||||
TRACE("dropped HELLO from %s(%s): identity does not match packet source address",fromAddress.toString().c_str(),_path->address().toString().c_str());
|
||||
return true;
|
||||
}
|
||||
|
||||
SharedPtr<Peer> peer(RR->topology->getPeer(id.address()));
|
||||
if (peer) {
|
||||
// We already have an identity with this address -- check for collisions
|
||||
|
@ -324,6 +299,43 @@ bool IncomingPacket::_doHELLO(const RuntimeEnvironment *RR,const bool alreadyAut
|
|||
|
||||
// VALID -- if we made it here, packet passed identity and authenticity checks!
|
||||
|
||||
// Get external surface address if present (was not in old versions)
|
||||
InetAddress externalSurfaceAddress;
|
||||
if (ptr < size())
|
||||
ptr += externalSurfaceAddress.deserialize(*this,ptr);
|
||||
|
||||
// Get primary planet world ID and world timestamp if present
|
||||
uint64_t planetWorldId = 0;
|
||||
uint64_t planetWorldTimestamp = 0;
|
||||
if ((ptr + 16) <= size()) {
|
||||
planetWorldId = at<uint64_t>(ptr); ptr += 8;
|
||||
planetWorldTimestamp = at<uint64_t>(ptr);
|
||||
}
|
||||
|
||||
std::vector< std::pair<uint64_t,uint64_t> > moonIdsAndTimestamps;
|
||||
if (ptr < size()) {
|
||||
// Remainder of packet, if present, is encrypted
|
||||
cryptField(peer->key(),ptr,size() - ptr);
|
||||
|
||||
// Get moon IDs and timestamps if present
|
||||
if ((ptr + 2) <= size()) {
|
||||
unsigned int numMoons = at<uint16_t>(ptr); ptr += 2;
|
||||
for(unsigned int i=0;i<numMoons;++i) {
|
||||
if ((World::Type)(*this)[ptr++] == World::TYPE_MOON)
|
||||
moonIdsAndTimestamps.push_back(std::pair<uint64_t,uint64_t>(at<uint64_t>(ptr),at<uint64_t>(ptr + 8)));
|
||||
ptr += 16;
|
||||
}
|
||||
}
|
||||
|
||||
// Handle COR if present (older versions don't send this)
|
||||
if ((ptr + 2) <= size()) {
|
||||
//const unsigned int corSize = at<uint16_t>(ptr); ptr += 2;
|
||||
ptr += 2;
|
||||
CertificateOfRepresentation cor;
|
||||
ptr += cor.deserialize(*this,ptr);
|
||||
}
|
||||
}
|
||||
|
||||
// Learn our external surface address from other peers to help us negotiate symmetric NATs
|
||||
// and detect changes to our global IP that can trigger path renegotiation.
|
||||
if ((externalSurfaceAddress)&&(hops() == 0))
|
||||
|
@ -337,6 +349,7 @@ bool IncomingPacket::_doHELLO(const RuntimeEnvironment *RR,const bool alreadyAut
|
|||
outp.append((unsigned char)ZEROTIER_ONE_VERSION_MAJOR);
|
||||
outp.append((unsigned char)ZEROTIER_ONE_VERSION_MINOR);
|
||||
outp.append((uint16_t)ZEROTIER_ONE_VERSION_REVISION);
|
||||
|
||||
if (protoVersion >= 5) {
|
||||
_path->address().serialize(outp);
|
||||
} else {
|
||||
|
@ -387,6 +400,11 @@ bool IncomingPacket::_doHELLO(const RuntimeEnvironment *RR,const bool alreadyAut
|
|||
}
|
||||
outp.setAt<uint16_t>(worldUpdateSizeAt,(uint16_t)(outp.size() - (worldUpdateSizeAt + 2)));
|
||||
|
||||
const unsigned int corSizeAt = outp.size();
|
||||
outp.addSize(2);
|
||||
RR->topology->appendCertificateOfRepresentation(outp);
|
||||
outp.setAt(corSizeAt,(uint16_t)(outp.size() - (corSizeAt + 2)));
|
||||
|
||||
outp.armor(peer->key(),true);
|
||||
_path->send(RR,outp.data(),outp.size(),now);
|
||||
|
||||
|
@ -586,7 +604,7 @@ bool IncomingPacket::_doRENDEZVOUS(const RuntimeEnvironment *RR,const SharedPtr<
|
|||
const InetAddress atAddr(field(ZT_PROTO_VERB_RENDEZVOUS_IDX_ADDRESS,addrlen),addrlen,port);
|
||||
if (RR->node->shouldUsePathForZeroTierTraffic(with,_path->localAddress(),atAddr)) {
|
||||
RR->node->putPacket(_path->localAddress(),atAddr,"ABRE",4,2); // send low-TTL junk packet to 'open' local NAT(s) and stateful firewalls
|
||||
rendezvousWith->attemptToContactAt(_path->localAddress(),atAddr,RR->node->now());
|
||||
rendezvousWith->attemptToContactAt(_path->localAddress(),atAddr,RR->node->now(),false);
|
||||
TRACE("RENDEZVOUS from %s says %s might be at %s, sent verification attempt",peer->address().toString().c_str(),with.toString().c_str(),atAddr.toString().c_str());
|
||||
} else {
|
||||
TRACE("RENDEZVOUS from %s says %s might be at %s, ignoring since path is not suitable",peer->address().toString().c_str(),with.toString().c_str(),atAddr.toString().c_str());
|
||||
|
@ -1155,7 +1173,7 @@ bool IncomingPacket::_doPUSH_DIRECT_PATHS(const RuntimeEnvironment *RR,const Sha
|
|||
if ( ((flags & ZT_PUSH_DIRECT_PATHS_FLAG_FORGET_PATH) == 0) && (!redundant) && (RR->node->shouldUsePathForZeroTierTraffic(peer->address(),_path->localAddress(),a)) ) {
|
||||
if (++countPerScope[(int)a.ipScope()][0] <= ZT_PUSH_DIRECT_PATHS_MAX_PER_SCOPE_AND_FAMILY) {
|
||||
TRACE("attempting to contact %s at pushed direct path %s",peer->address().toString().c_str(),a.toString().c_str());
|
||||
peer->attemptToContactAt(InetAddress(),a,now);
|
||||
peer->attemptToContactAt(InetAddress(),a,now,false);
|
||||
} else {
|
||||
TRACE("ignoring contact for %s at %s -- too many per scope",peer->address().toString().c_str(),a.toString().c_str());
|
||||
}
|
||||
|
@ -1174,7 +1192,7 @@ bool IncomingPacket::_doPUSH_DIRECT_PATHS(const RuntimeEnvironment *RR,const Sha
|
|||
if ( ((flags & ZT_PUSH_DIRECT_PATHS_FLAG_FORGET_PATH) == 0) && (!redundant) && (RR->node->shouldUsePathForZeroTierTraffic(peer->address(),_path->localAddress(),a)) ) {
|
||||
if (++countPerScope[(int)a.ipScope()][1] <= ZT_PUSH_DIRECT_PATHS_MAX_PER_SCOPE_AND_FAMILY) {
|
||||
TRACE("attempting to contact %s at pushed direct path %s",peer->address().toString().c_str(),a.toString().c_str());
|
||||
peer->attemptToContactAt(InetAddress(),a,now);
|
||||
peer->attemptToContactAt(InetAddress(),a,now,false);
|
||||
} else {
|
||||
TRACE("ignoring contact for %s at %s -- too many per scope",peer->address().toString().c_str(),a.toString().c_str());
|
||||
}
|
||||
|
|
|
@ -70,7 +70,7 @@ Node::Node(void *uptr,const struct ZT_Node_Callbacks *callbacks,uint64_t now) :
|
|||
Utils::getSecureRandom(foo,32);
|
||||
_prng.init(foo,256,foo);
|
||||
memset(_prngStream,0,sizeof(_prngStream));
|
||||
_prng.encrypt12(_prngStream,_prngStream,sizeof(_prngStream));
|
||||
_prng.crypt12(_prngStream,_prngStream,sizeof(_prngStream));
|
||||
|
||||
std::string idtmp(dataStoreGet("identity.secret"));
|
||||
if ((!idtmp.length())||(!RR->identity.fromString(idtmp))||(!RR->identity.hasPrivate())) {
|
||||
|
@ -686,7 +686,7 @@ uint64_t Node::prng()
|
|||
{
|
||||
unsigned int p = (++_prngStreamPtr % ZT_NODE_PRNG_BUF_SIZE);
|
||||
if (!p)
|
||||
_prng.encrypt12(_prngStream,_prngStream,sizeof(_prngStream));
|
||||
_prng.crypt12(_prngStream,_prngStream,sizeof(_prngStream));
|
||||
return _prngStream[p];
|
||||
}
|
||||
|
||||
|
|
|
@ -18,9 +18,21 @@
|
|||
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "Packet.hpp"
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#define FORCE_INLINE static __forceinline
|
||||
#include <intrin.h>
|
||||
#pragma warning(disable : 4127) /* disable: C4127: conditional expression is constant */
|
||||
#pragma warning(disable : 4293) /* disable: C4293: too large shift (32-bits) */
|
||||
#else
|
||||
#define FORCE_INLINE static inline
|
||||
#endif
|
||||
|
||||
namespace ZeroTier {
|
||||
|
||||
/************************************************************************** */
|
||||
|
@ -367,7 +379,7 @@ LZ4_decompress_*_continue() :
|
|||
#define LZ4_HASH_SIZE_U32 (1 << LZ4_HASHLOG) /* required as macro for static allocation */
|
||||
|
||||
#if defined(__cplusplus) || (defined (__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) /* C99 */)
|
||||
#include <stdint.h>
|
||||
//#include <stdint.h>
|
||||
|
||||
typedef struct {
|
||||
uint32_t hashTable[LZ4_HASH_SIZE_U32];
|
||||
|
@ -536,6 +548,7 @@ union LZ4_streamDecode_u {
|
|||
/*-************************************
|
||||
* Compiler Options
|
||||
**************************************/
|
||||
#if 0
|
||||
#ifdef _MSC_VER /* Visual Studio */
|
||||
# define FORCE_INLINE static __forceinline
|
||||
# include <intrin.h>
|
||||
|
@ -550,6 +563,7 @@ union LZ4_streamDecode_u {
|
|||
# define FORCE_INLINE static
|
||||
# endif
|
||||
#endif /* _MSC_VER */
|
||||
#endif
|
||||
|
||||
#if (defined(__GNUC__) && (__GNUC__ >= 3)) || (defined(__INTEL_COMPILER) && (__INTEL_COMPILER >= 800)) || defined(__clang__)
|
||||
# define expect(expr,value) (__builtin_expect ((expr),(value)) )
|
||||
|
@ -564,38 +578,39 @@ union LZ4_streamDecode_u {
|
|||
/*-************************************
|
||||
* Memory routines
|
||||
**************************************/
|
||||
#include <stdlib.h> /* malloc, calloc, free */
|
||||
//#include <stdlib.h> /* malloc, calloc, free */
|
||||
#define ALLOCATOR(n,s) calloc(n,s)
|
||||
#define FREEMEM free
|
||||
#include <string.h> /* memset, memcpy */
|
||||
//#include <string.h> /* memset, memcpy */
|
||||
#define MEM_INIT memset
|
||||
|
||||
|
||||
/*-************************************
|
||||
* Basic Types
|
||||
**************************************/
|
||||
#if defined(__cplusplus) || (defined (__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) /* C99 */)
|
||||
# include <stdint.h>
|
||||
//#if defined(__cplusplus) || (defined (__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) /* C99 */)
|
||||
//# include <stdint.h>
|
||||
typedef uint8_t BYTE;
|
||||
typedef uint16_t U16;
|
||||
typedef uint32_t U32;
|
||||
typedef int32_t S32;
|
||||
typedef uint64_t U64;
|
||||
typedef uintptr_t uptrval;
|
||||
#else
|
||||
/*#else
|
||||
typedef unsigned char BYTE;
|
||||
typedef unsigned short U16;
|
||||
typedef unsigned int U32;
|
||||
typedef signed int S32;
|
||||
typedef unsigned long long U64;
|
||||
typedef size_t uptrval; /* generally true, except OpenVMS-64 */
|
||||
#endif
|
||||
typedef size_t uptrval;
|
||||
#endif */
|
||||
|
||||
#if defined(__x86_64__)
|
||||
typedef U64 reg_t; /* 64-bits in x32 mode */
|
||||
#else
|
||||
typedef size_t reg_t; /* 32-bits in x32 mode */
|
||||
#endif
|
||||
typedef uintptr_t reg_t;
|
||||
//#if defined(__x86_64__)
|
||||
// typedef U64 reg_t; /* 64-bits in x32 mode */
|
||||
//#else
|
||||
// typedef size_t reg_t; /* 32-bits in x32 mode */
|
||||
//#endif
|
||||
|
||||
/*-************************************
|
||||
* Reading and writing into memory
|
||||
|
@ -606,7 +621,6 @@ static unsigned LZ4_isLittleEndian(void)
|
|||
return one.c[0];
|
||||
}
|
||||
|
||||
|
||||
#if defined(LZ4_FORCE_MEMORY_ACCESS) && (LZ4_FORCE_MEMORY_ACCESS==2)
|
||||
/* lie to the compiler about data alignment; use with caution */
|
||||
|
||||
|
@ -1975,10 +1989,10 @@ void Packet::armor(const void *key,bool encryptPayload)
|
|||
|
||||
// MAC key is always the first 32 bytes of the Salsa20 key stream
|
||||
// This is the same construction DJB's NaCl library uses
|
||||
s20.encrypt12(ZERO_KEY,macKey,sizeof(macKey));
|
||||
s20.crypt12(ZERO_KEY,macKey,sizeof(macKey));
|
||||
|
||||
if (encryptPayload)
|
||||
s20.encrypt12(payload,payload,payloadLen);
|
||||
s20.crypt12(payload,payload,payloadLen);
|
||||
|
||||
Poly1305::compute(mac,payload,payloadLen,macKey);
|
||||
memcpy(field(ZT_PACKET_IDX_MAC,8),mac,8);
|
||||
|
@ -1995,20 +2009,30 @@ bool Packet::dearmor(const void *key)
|
|||
|
||||
if ((cs == ZT_PROTO_CIPHER_SUITE__C25519_POLY1305_NONE)||(cs == ZT_PROTO_CIPHER_SUITE__C25519_POLY1305_SALSA2012)) {
|
||||
_salsa20MangleKey((const unsigned char *)key,mangledKey);
|
||||
Salsa20 s20(mangledKey,256,field(ZT_PACKET_IDX_IV,8)/*,ZT_PROTO_SALSA20_ROUNDS*/);
|
||||
Salsa20 s20(mangledKey,256,field(ZT_PACKET_IDX_IV,8));
|
||||
|
||||
s20.encrypt12(ZERO_KEY,macKey,sizeof(macKey));
|
||||
s20.crypt12(ZERO_KEY,macKey,sizeof(macKey));
|
||||
Poly1305::compute(mac,payload,payloadLen,macKey);
|
||||
if (!Utils::secureEq(mac,field(ZT_PACKET_IDX_MAC,8),8))
|
||||
return false;
|
||||
|
||||
if (cs == ZT_PROTO_CIPHER_SUITE__C25519_POLY1305_SALSA2012)
|
||||
s20.decrypt12(payload,payload,payloadLen);
|
||||
s20.crypt12(payload,payload,payloadLen);
|
||||
|
||||
return true;
|
||||
} else return false; // unrecognized cipher suite
|
||||
}
|
||||
|
||||
void Packet::cryptField(const void *key,unsigned int start,unsigned int len)
|
||||
{
|
||||
unsigned char mangledKey[32];
|
||||
uint64_t iv = Utils::hton((uint64_t)start ^ at<uint64_t>(ZT_PACKET_IDX_IV));
|
||||
_salsa20MangleKey((const unsigned char *)key,mangledKey);
|
||||
Salsa20 s20(mangledKey,256,&iv);
|
||||
unsigned char *const ptr = field(start,len);
|
||||
s20.crypt12(ptr,ptr,len);
|
||||
}
|
||||
|
||||
bool Packet::compress()
|
||||
{
|
||||
unsigned char buf[ZT_PROTO_MAX_PACKET_LENGTH * 2];
|
||||
|
|
|
@ -542,6 +542,7 @@ public:
|
|||
* [<[...] destination address to which packet was sent>]
|
||||
* <[8] 64-bit world ID of current planet>
|
||||
* <[8] 64-bit timestamp of current planet>
|
||||
* [... remainder if packet is encrypted using cryptField() ...]
|
||||
* <[2] 16-bit number of moons>
|
||||
* [<[1] 8-bit type ID of moon>]
|
||||
* [<[8] 64-bit world ID of moon>]
|
||||
|
@ -550,9 +551,10 @@ public:
|
|||
* <[2] 16-bit length of certificate of representation>
|
||||
* [... certificate of representation ...]
|
||||
*
|
||||
* HELLO is sent in the clear, and therefore cannot contain anything
|
||||
* secret or highly confidential. It should contain nothing that is
|
||||
* not either public or easy to obtain via other means.
|
||||
* The initial fields of HELLO are sent in the clear. Fields after the
|
||||
* planet definition (which are common knowledge) are however encrypted
|
||||
* using the cryptField() function. The packet is MAC'd as usual using
|
||||
* the same MAC construct as other packets.
|
||||
*
|
||||
* The destination address is the wire address to which this packet is
|
||||
* being sent, and in OK is *also* the destination address of the OK
|
||||
|
@ -566,7 +568,7 @@ public:
|
|||
* 0x04 - 6-byte IPv4 UDP address/port -- format: <[4] IP>, <[2] port>
|
||||
* 0x06 - 18-byte IPv6 UDP address/port -- format: <[16] IP>, <[2] port>
|
||||
*
|
||||
* OK payload:
|
||||
* OK payload (note that OK is encrypted):
|
||||
* <[8] timestamp (echoed from original HELLO)>
|
||||
* <[1] protocol version (of responder)>
|
||||
* <[1] software major version (of responder)>
|
||||
|
@ -576,6 +578,8 @@ public:
|
|||
* [<[...] destination address>]
|
||||
* <[2] 16-bit length of world update or 0 if none>
|
||||
* [[...] updates to planets and/or moons]
|
||||
* <[2] 16-bit length of certificate of representation (of responder)>
|
||||
* [... certificate of representation ...]
|
||||
*
|
||||
* ERROR has no payload.
|
||||
*/
|
||||
|
@ -1348,6 +1352,25 @@ public:
|
|||
*/
|
||||
bool dearmor(const void *key);
|
||||
|
||||
/**
|
||||
* Encrypt/decrypt a separately armored portion of a packet
|
||||
*
|
||||
* This keys using the same key in the same way as armor/dearmor, but
|
||||
* uses a different IV computed from the packet's IV plus the starting
|
||||
* point index.
|
||||
*
|
||||
* This currently uses Salsa20/12, but any message that uses this should
|
||||
* incorporate a cipher selector to permit this to be changed later.
|
||||
*
|
||||
* This is currently only used to mask portions of HELLO as an extra
|
||||
* security precation since most of that message is sent in the clear.
|
||||
*
|
||||
* @param key 32-byte key
|
||||
* @param start Start of encrypted portion
|
||||
* @param len Length of encrypted portion
|
||||
*/
|
||||
void cryptField(const void *key,unsigned int start,unsigned int len);
|
||||
|
||||
/**
|
||||
* Attempt to compress payload if not already (must be unencrypted)
|
||||
*
|
||||
|
|
|
@ -203,7 +203,7 @@ void Peer::received(
|
|||
#endif
|
||||
} else {
|
||||
TRACE("got %s via unknown path %s(%s), confirming...",Packet::verbString(verb),_id.address().toString().c_str(),path->address().toString().c_str());
|
||||
attemptToContactAt(path->localAddress(),path->address(),now);
|
||||
attemptToContactAt(path->localAddress(),path->address(),now,true);
|
||||
path->sent(now);
|
||||
}
|
||||
}
|
||||
|
@ -357,6 +357,8 @@ void Peer::sendHELLO(const InetAddress &localAddr,const InetAddress &atAddress,u
|
|||
outp.append((uint64_t)RR->topology->planetWorldId());
|
||||
outp.append((uint64_t)RR->topology->planetWorldTimestamp());
|
||||
|
||||
const unsigned int startCryptedPortionAt = outp.size();
|
||||
|
||||
std::vector<World> moons(RR->topology->moons());
|
||||
outp.append((uint16_t)moons.size());
|
||||
for(std::vector<World>::const_iterator m(moons.begin());m!=moons.end();++m) {
|
||||
|
@ -368,21 +370,23 @@ void Peer::sendHELLO(const InetAddress &localAddr,const InetAddress &atAddress,u
|
|||
const unsigned int corSizeAt = outp.size();
|
||||
outp.addSize(2);
|
||||
RR->topology->appendCertificateOfRepresentation(outp);
|
||||
outp.setAt(corSizeAt,(uint16_t)((outp.size() - corSizeAt) - 2));
|
||||
outp.setAt(corSizeAt,(uint16_t)(outp.size() - (corSizeAt + 2)));
|
||||
|
||||
outp.cryptField(_key,startCryptedPortionAt,outp.size() - startCryptedPortionAt);
|
||||
|
||||
RR->node->expectReplyTo(outp.packetId());
|
||||
|
||||
if (atAddress) {
|
||||
outp.armor(_key,false);
|
||||
outp.armor(_key,false); // false == don't encrypt full payload, but add MAC
|
||||
RR->node->putPacket(localAddr,atAddress,outp.data(),outp.size());
|
||||
} else {
|
||||
RR->sw->send(outp,false);
|
||||
RR->sw->send(outp,false); // false == don't encrypt full payload, but add MAC
|
||||
}
|
||||
}
|
||||
|
||||
void Peer::attemptToContactAt(const InetAddress &localAddr,const InetAddress &atAddress,uint64_t now)
|
||||
void Peer::attemptToContactAt(const InetAddress &localAddr,const InetAddress &atAddress,uint64_t now,bool sendFullHello)
|
||||
{
|
||||
if ( (_vProto >= 5) && ( !((_vMajor == 1)&&(_vMinor == 1)&&(_vRevision == 0)) ) ) {
|
||||
if ( (!sendFullHello) && (_vProto >= 5) && (!((_vMajor == 1)&&(_vMinor == 1)&&(_vRevision == 0))) ) {
|
||||
Packet outp(_id.address(),RR->identity.address(),Packet::VERB_ECHO);
|
||||
RR->node->expectReplyTo(outp.packetId());
|
||||
outp.armor(_key,true);
|
||||
|
@ -398,7 +402,7 @@ void Peer::tryMemorizedPath(uint64_t now)
|
|||
_lastTriedMemorizedPath = now;
|
||||
InetAddress mp;
|
||||
if (RR->node->externalPathLookup(_id.address(),-1,mp))
|
||||
attemptToContactAt(InetAddress(),mp,now);
|
||||
attemptToContactAt(InetAddress(),mp,now,true);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -420,7 +424,7 @@ bool Peer::doPingAndKeepalive(uint64_t now,int inetAddressFamily)
|
|||
|
||||
if (bestp >= 0) {
|
||||
if ( ((now - _paths[bestp].lastReceive) >= ZT_PEER_PING_PERIOD) || (_paths[bestp].path->needsHeartbeat(now)) ) {
|
||||
attemptToContactAt(_paths[bestp].path->localAddress(),_paths[bestp].path->address(),now);
|
||||
attemptToContactAt(_paths[bestp].path->localAddress(),_paths[bestp].path->address(),now,false);
|
||||
_paths[bestp].path->sent(now);
|
||||
}
|
||||
return true;
|
||||
|
@ -444,7 +448,7 @@ void Peer::resetWithinScope(InetAddress::IpScope scope,int inetAddressFamily,uin
|
|||
Mutex::Lock _l(_paths_m);
|
||||
for(unsigned int p=0;p<_numPaths;++p) {
|
||||
if ( (_paths[p].path->address().ss_family == inetAddressFamily) && (_paths[p].path->address().ipScope() == scope) ) {
|
||||
attemptToContactAt(_paths[p].path->localAddress(),_paths[p].path->address(),now);
|
||||
attemptToContactAt(_paths[p].path->localAddress(),_paths[p].path->address(),now,false);
|
||||
_paths[p].path->sent(now);
|
||||
_paths[p].lastReceive = 0; // path will not be used unless it speaks again
|
||||
}
|
||||
|
|
|
@ -161,8 +161,9 @@ public:
|
|||
* @param localAddr Local address
|
||||
* @param atAddress Destination address
|
||||
* @param now Current time
|
||||
* @param sendFullHello If true, always send a full HELLO instead of just an ECHO
|
||||
*/
|
||||
void attemptToContactAt(const InetAddress &localAddr,const InetAddress &atAddress,uint64_t now);
|
||||
void attemptToContactAt(const InetAddress &localAddr,const InetAddress &atAddress,uint64_t now,bool sendFullHello);
|
||||
|
||||
/**
|
||||
* Try a memorized or statically defined path if any are known
|
||||
|
|
|
@ -123,7 +123,7 @@ void Salsa20::init(const void *key,unsigned int kbits,const void *iv)
|
|||
#endif
|
||||
}
|
||||
|
||||
void Salsa20::encrypt12(const void *in,void *out,unsigned int bytes)
|
||||
void Salsa20::crypt12(const void *in,void *out,unsigned int bytes)
|
||||
throw()
|
||||
{
|
||||
uint8_t tmp[64];
|
||||
|
@ -623,7 +623,7 @@ void Salsa20::encrypt12(const void *in,void *out,unsigned int bytes)
|
|||
}
|
||||
}
|
||||
|
||||
void Salsa20::encrypt20(const void *in,void *out,unsigned int bytes)
|
||||
void Salsa20::crypt20(const void *in,void *out,unsigned int bytes)
|
||||
throw()
|
||||
{
|
||||
uint8_t tmp[64];
|
||||
|
|
|
@ -56,51 +56,25 @@ public:
|
|||
throw();
|
||||
|
||||
/**
|
||||
* Encrypt data using Salsa20/12
|
||||
* Encrypt/decrypt data using Salsa20/12
|
||||
*
|
||||
* @param in Input data
|
||||
* @param out Output buffer
|
||||
* @param bytes Length of data
|
||||
*/
|
||||
void encrypt12(const void *in,void *out,unsigned int bytes)
|
||||
void crypt12(const void *in,void *out,unsigned int bytes)
|
||||
throw();
|
||||
|
||||
/**
|
||||
* Encrypt data using Salsa20/20
|
||||
* Encrypt/decrypt data using Salsa20/20
|
||||
*
|
||||
* @param in Input data
|
||||
* @param out Output buffer
|
||||
* @param bytes Length of data
|
||||
*/
|
||||
void encrypt20(const void *in,void *out,unsigned int bytes)
|
||||
void crypt20(const void *in,void *out,unsigned int bytes)
|
||||
throw();
|
||||
|
||||
/**
|
||||
* Decrypt data
|
||||
*
|
||||
* @param in Input data
|
||||
* @param out Output buffer
|
||||
* @param bytes Length of data
|
||||
*/
|
||||
inline void decrypt12(const void *in,void *out,unsigned int bytes)
|
||||
throw()
|
||||
{
|
||||
encrypt12(in,out,bytes);
|
||||
}
|
||||
|
||||
/**
|
||||
* Decrypt data
|
||||
*
|
||||
* @param in Input data
|
||||
* @param out Output buffer
|
||||
* @param bytes Length of data
|
||||
*/
|
||||
inline void decrypt20(const void *in,void *out,unsigned int bytes)
|
||||
throw()
|
||||
{
|
||||
encrypt20(in,out,bytes);
|
||||
}
|
||||
|
||||
private:
|
||||
union {
|
||||
#ifdef ZT_SALSA20_SSE
|
||||
|
|
|
@ -777,7 +777,7 @@ bool Switch::_trySend(Packet &packet,bool encrypt)
|
|||
if ((clusterMostRecentMemberId < 0)||(viaPath->lastIn() > clusterMostRecentTs)) {
|
||||
#endif
|
||||
if ((now - viaPath->lastOut()) > std::max((now - viaPath->lastIn()) * 4,(uint64_t)ZT_PATH_MIN_REACTIVATE_INTERVAL)) {
|
||||
peer->attemptToContactAt(viaPath->localAddress(),viaPath->address(),now);
|
||||
peer->attemptToContactAt(viaPath->localAddress(),viaPath->address(),now,false);
|
||||
viaPath->sent(now);
|
||||
}
|
||||
#ifdef ZT_ENABLE_CLUSTER
|
||||
|
|
|
@ -182,7 +182,7 @@ void Utils::getSecureRandom(void *buf,unsigned int bytes)
|
|||
|
||||
#else // not __WINDOWS__
|
||||
|
||||
static char randomBuf[131072];
|
||||
static char randomBuf[65536];
|
||||
static unsigned int randomPtr = sizeof(randomBuf);
|
||||
static int devURandomFd = -1;
|
||||
|
||||
|
@ -215,7 +215,7 @@ void Utils::getSecureRandom(void *buf,unsigned int bytes)
|
|||
|
||||
#endif // __WINDOWS__ or not
|
||||
|
||||
s20.encrypt12(buf,buf,bytes);
|
||||
s20.crypt12(buf,buf,bytes);
|
||||
}
|
||||
|
||||
bool Utils::scopy(char *dest,unsigned int len,const char *src)
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue