mirror of
https://github.com/zerotier/ZeroTierOne.git
synced 2025-04-24 16:07:23 +02:00
wip
This commit is contained in:
parent
5a4d681af8
commit
b55f98b813
2 changed files with 172 additions and 110 deletions
|
@ -52,30 +52,35 @@ public:
|
|||
};
|
||||
|
||||
ZT_ALWAYS_INLINE Identity() { memset(reinterpret_cast<void *>(this),0,sizeof(Identity)); }
|
||||
ZT_ALWAYS_INLINE Identity(const char *str)
|
||||
{
|
||||
if (!fromString(str))
|
||||
throw ZT_EXCEPTION_INVALID_SERIALIZED_DATA_INVALID_TYPE;
|
||||
}
|
||||
ZT_ALWAYS_INLINE ~Identity() { Utils::burn(reinterpret_cast<void *>(&this->_priv),sizeof(this->_priv)); }
|
||||
|
||||
/**
|
||||
* Construct identity from string
|
||||
*
|
||||
* If the identity is not basically valid (no deep checking is done) the result will
|
||||
* be a null identity.
|
||||
*
|
||||
* @param str Identity in canonical string format
|
||||
*/
|
||||
ZT_ALWAYS_INLINE Identity(const char *str) { fromString(str); }
|
||||
|
||||
template<unsigned int C>
|
||||
ZT_ALWAYS_INLINE Identity(const Buffer<C> &b,unsigned int startAt = 0) { deserialize(b,startAt); }
|
||||
|
||||
ZT_ALWAYS_INLINE ~Identity() { Utils::burn(reinterpret_cast<void *>(this),sizeof(Identity)); }
|
||||
|
||||
/**
|
||||
* Set identity to NIL value (all zero)
|
||||
*/
|
||||
ZT_ALWAYS_INLINE void zero() { memset(reinterpret_cast<void *>(this),0,sizeof(Identity)); }
|
||||
|
||||
/**
|
||||
* @return Identity type
|
||||
* @return Identity type (undefined if identity is null or invalid)
|
||||
*/
|
||||
ZT_ALWAYS_INLINE Type type() const { return _type; }
|
||||
|
||||
/**
|
||||
* Generate a new identity (address, key pair)
|
||||
*
|
||||
* This is a time consuming operation.
|
||||
* This is a time consuming operation taking up to 5-10 seconds on some slower systems.
|
||||
*
|
||||
* @param t Type of identity to generate
|
||||
*/
|
||||
|
@ -94,10 +99,12 @@ public:
|
|||
ZT_ALWAYS_INLINE bool hasPrivate() const { return _hasPrivate; }
|
||||
|
||||
/**
|
||||
* This generates a SHA384 hash of this identity's keys.
|
||||
*
|
||||
* @param h Buffer to receive SHA384 of public key(s)
|
||||
* @param includePrivate If true, hash private key(s) too
|
||||
* @param includePrivate If true, hash private key(s) as well
|
||||
*/
|
||||
ZT_ALWAYS_INLINE bool hash(uint8_t h[48],const bool includePrivate) const
|
||||
ZT_ALWAYS_INLINE bool hash(uint8_t h[48],const bool includePrivate = false) const
|
||||
{
|
||||
switch(_type) {
|
||||
|
||||
|
@ -142,8 +149,10 @@ public:
|
|||
|
||||
case P384:
|
||||
if (siglen >= ZT_ECC384_SIGNATURE_SIZE) {
|
||||
// When signing with P384 we also hash the C25519 public key as an
|
||||
// extra measure to ensure that only this identity can verify.
|
||||
uint8_t h[48];
|
||||
SHA384(h,data,len);
|
||||
SHA384(h,data,len,_pub.c25519,ZT_C25519_PUBLIC_KEY_LEN);
|
||||
ECC384ECDSASign(_priv.p384,h,(uint8_t *)sig);
|
||||
return ZT_ECC384_SIGNATURE_SIZE;
|
||||
}
|
||||
|
@ -165,15 +174,18 @@ public:
|
|||
ZT_ALWAYS_INLINE bool verify(const void *data,unsigned int len,const void *sig,unsigned int siglen) const
|
||||
{
|
||||
switch(_type) {
|
||||
|
||||
case C25519:
|
||||
return C25519::verify(_pub.c25519,data,len,sig,siglen);
|
||||
|
||||
case P384:
|
||||
if (siglen == ZT_ECC384_SIGNATURE_SIZE) {
|
||||
uint8_t h[48];
|
||||
SHA384(h,data,len);
|
||||
SHA384(h,data,len,_pub.c25519,ZT_C25519_PUBLIC_KEY_LEN);
|
||||
return ECC384ECDSAVerify(_pub.p384,h,(const uint8_t *)sig);
|
||||
}
|
||||
break;
|
||||
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
@ -193,6 +205,7 @@ public:
|
|||
uint8_t h[64];
|
||||
if (_hasPrivate) {
|
||||
if (_type == C25519) {
|
||||
|
||||
if ((id._type == C25519)||(id._type == P384)) {
|
||||
// If we are a C25519 key we can agree with another C25519 key or with only the
|
||||
// C25519 portion of a type 1 P-384 key.
|
||||
|
@ -201,12 +214,10 @@ public:
|
|||
memcpy(key,h,ZT_PEER_SECRET_KEY_LENGTH);
|
||||
return true;
|
||||
}
|
||||
|
||||
} else if (_type == P384) {
|
||||
|
||||
if (id._type == P384) {
|
||||
// Perform key agreement over both curves for the same reason that C25519 public
|
||||
// keys are included in P-384 signature inputs: to bind the keys together so
|
||||
// that a type 1 identity with the same C25519 public key (and therefore address)
|
||||
// but a different P-384 key will not work.
|
||||
C25519::agree(_priv.c25519,id._pub.c25519,rawkey);
|
||||
ECC384ECDH(id._pub.p384,_priv.p384,rawkey + ZT_C25519_SHARED_KEY_LEN);
|
||||
SHA384(h,rawkey,ZT_C25519_SHARED_KEY_LEN + ZT_ECC384_SHARED_SECRET_SIZE);
|
||||
|
@ -219,6 +230,7 @@ public:
|
|||
memcpy(key,h,ZT_PEER_SECRET_KEY_LENGTH);
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
return false;
|
||||
|
@ -229,28 +241,6 @@ public:
|
|||
*/
|
||||
ZT_ALWAYS_INLINE const Address &address() const { return _address; }
|
||||
|
||||
/**
|
||||
* Attempt to generate an older type identity from a newer type
|
||||
*
|
||||
* @param dest Destination to fill with downgraded identity
|
||||
* @param toType Desired identity type
|
||||
*/
|
||||
ZT_ALWAYS_INLINE bool downgrade(Identity &dest,const Type toType)
|
||||
{
|
||||
if (_type == toType) {
|
||||
return true;
|
||||
} else if ((_type == P384)&&(toType == C25519)) {
|
||||
dest._address = _address;
|
||||
dest._type = C25519;
|
||||
dest._hasPrivate = _hasPrivate;
|
||||
memcpy(dest._pub.c25519,_pub.c25519,ZT_C25519_PUBLIC_KEY_LEN);
|
||||
if (_hasPrivate)
|
||||
memcpy(dest._priv.c25519,_priv.c25519,ZT_C25519_PRIVATE_KEY_LEN);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Serialize this identity (binary)
|
||||
*
|
||||
|
@ -284,7 +274,7 @@ public:
|
|||
} else {
|
||||
b.append((uint8_t)0);
|
||||
}
|
||||
b.append((uint16_t)0); // size of additional fields
|
||||
b.append((uint16_t)0); // size of additional fields (should have included such a thing in v0!)
|
||||
break;
|
||||
|
||||
}
|
||||
|
@ -358,7 +348,7 @@ public:
|
|||
*
|
||||
* @param includePrivate If true, include private key (if it exists)
|
||||
* @param buf Buffer to store string
|
||||
* @return ASCII string representation of identity
|
||||
* @return ASCII string representation of identity (pointer to buf)
|
||||
*/
|
||||
char *toString(bool includePrivate,char buf[ZT_IDENTITY_STRING_BUFFER_LENGTH]) const;
|
||||
|
||||
|
@ -382,12 +372,9 @@ public:
|
|||
{
|
||||
if ((_address == id._address)&&(_type == id._type)) {
|
||||
switch(_type) {
|
||||
case C25519:
|
||||
return (memcmp(_pub.c25519,id._pub.c25519,ZT_C25519_PUBLIC_KEY_LEN) == 0);
|
||||
case P384:
|
||||
return (memcmp(&_pub,&id._pub,sizeof(_pub)) == 0);
|
||||
default:
|
||||
return false;
|
||||
case C25519: return (memcmp(_pub.c25519,id._pub.c25519,ZT_C25519_PUBLIC_KEY_LEN) == 0);
|
||||
// case P384:
|
||||
default: return (memcmp(&_pub,&id._pub,sizeof(_pub)) == 0);
|
||||
}
|
||||
}
|
||||
return false;
|
||||
|
@ -401,10 +388,9 @@ public:
|
|||
return true;
|
||||
if (_type == id._type) {
|
||||
switch(_type) {
|
||||
case C25519:
|
||||
return (memcmp(_pub.c25519,id._pub.c25519,ZT_C25519_PUBLIC_KEY_LEN) < 0);
|
||||
case P384:
|
||||
return (memcmp(&_pub,&id._pub,sizeof(_pub)) < 0);
|
||||
case C25519: return (memcmp(_pub.c25519,id._pub.c25519,ZT_C25519_PUBLIC_KEY_LEN) < 0);
|
||||
// case P384:
|
||||
default: return (memcmp(&_pub,&id._pub,sizeof(_pub)) < 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
194
node/Packet.hpp
194
node/Packet.hpp
|
@ -424,10 +424,12 @@ public:
|
|||
* <[8] timestamp for determining latency>
|
||||
* <[...] binary serialized identity (see Identity)>
|
||||
* <[...] physical destination address of packet>
|
||||
* [... begin encrypted section ...]
|
||||
* [... begin encrypted region ...]
|
||||
* <[2] 16-bit reserved field, always 0>
|
||||
* <[2] 16-bit length of locator>
|
||||
* <[...] locator for this node>
|
||||
* <[2] 16-bit length of meta-data dictionary>
|
||||
* <[...] meta-data dictionary>
|
||||
*
|
||||
* HELLO is sent in the clear as it is how peers share their identity
|
||||
* public keys.
|
||||
|
@ -441,6 +443,9 @@ public:
|
|||
* very sensitive, but hiding the locator and other meta-data slightly
|
||||
* improves privacy.
|
||||
*
|
||||
* The 16-bit zero after encryption starts is for backward compatibility
|
||||
* with pre-2.0 nodes.
|
||||
*
|
||||
* OK payload:
|
||||
* <[8] HELLO timestamp field echo>
|
||||
* <[1] protocol version>
|
||||
|
@ -578,6 +583,20 @@ public:
|
|||
*/
|
||||
VERB_ECHO = 0x08,
|
||||
|
||||
/**
|
||||
* Announce interest in multicast group(s):
|
||||
* <[8] 64-bit network ID>
|
||||
* <[6] multicast Ethernet address>
|
||||
* <[4] multicast additional distinguishing information (ADI)>
|
||||
* [... additional tuples of network/address/adi ...]
|
||||
*
|
||||
* LIKEs may be sent to any peer, though a good implementation should
|
||||
* restrict them to peers on the same network they're for and to network
|
||||
* controllers and root servers. In the current network, root servers
|
||||
* will provide the service of final multicast cache.
|
||||
*/
|
||||
VERB_MULTICAST_LIKE = 0x09,
|
||||
|
||||
/**
|
||||
* Network credentials push:
|
||||
* [<[...] one or more certificates of membership>]
|
||||
|
@ -682,6 +701,73 @@ public:
|
|||
*/
|
||||
VERB_NETWORK_CONFIG = 0x0c,
|
||||
|
||||
/**
|
||||
* Request endpoints for multicast distribution:
|
||||
* <[8] 64-bit network ID>
|
||||
* <[1] flags>
|
||||
* <[6] MAC address of multicast group being queried>
|
||||
* <[4] 32-bit ADI for multicast group being queried>
|
||||
* <[4] 32-bit requested max number of multicast peers>
|
||||
*
|
||||
* This message asks a peer for additional known endpoints that have
|
||||
* LIKEd a given multicast group. It's sent when the sender wishes
|
||||
* to send multicast but does not have the desired number of recipient
|
||||
* peers.
|
||||
*
|
||||
* OK response payload: (multiple OKs can be generated)
|
||||
* <[8] 64-bit network ID>
|
||||
* <[6] MAC address of multicast group being queried>
|
||||
* <[4] 32-bit ADI for multicast group being queried>
|
||||
* <[4] 32-bit total number of known members in this multicast group>
|
||||
* <[2] 16-bit number of members enumerated in this packet>
|
||||
* <[...] series of 5-byte ZeroTier addresses of enumerated members>
|
||||
*
|
||||
* ERROR is not generated; queries that return no response are dropped.
|
||||
*/
|
||||
VERB_MULTICAST_GATHER = 0x0d,
|
||||
|
||||
/** *** DEPRECATED ***
|
||||
* Multicast frame:
|
||||
* <[8] 64-bit network ID>
|
||||
* <[1] flags>
|
||||
* [<[4] 32-bit implicit gather limit>]
|
||||
* [<[6] source MAC>]
|
||||
* <[6] destination MAC (multicast address)>
|
||||
* <[4] 32-bit multicast ADI (multicast address extension)>
|
||||
* <[2] 16-bit ethertype>
|
||||
* <[...] ethernet payload>
|
||||
*
|
||||
* Flags:
|
||||
* 0x01 - Network certificate of membership attached (DEPRECATED)
|
||||
* 0x02 - Implicit gather limit field is present
|
||||
* 0x04 - Source MAC is specified -- otherwise it's computed from sender
|
||||
* 0x08 - Please replicate (sent to multicast replicators)
|
||||
*
|
||||
* OK and ERROR responses are optional. OK may be generated if there are
|
||||
* implicit gather results or if the recipient wants to send its own
|
||||
* updated certificate of network membership to the sender. ERROR may be
|
||||
* generated if a certificate is needed or if multicasts to this group
|
||||
* are no longer wanted (multicast unsubscribe).
|
||||
*
|
||||
* OK response payload:
|
||||
* <[8] 64-bit network ID>
|
||||
* <[6] MAC address of multicast group>
|
||||
* <[4] 32-bit ADI for multicast group>
|
||||
* <[1] flags>
|
||||
* [<[...] network certificate of membership (DEPRECATED)>]
|
||||
* [<[...] implicit gather results if flag 0x01 is set>]
|
||||
*
|
||||
* OK flags (same bits as request flags):
|
||||
* 0x01 - OK includes certificate of network membership (DEPRECATED)
|
||||
* 0x02 - OK includes implicit gather results
|
||||
*
|
||||
* ERROR response payload:
|
||||
* <[8] 64-bit network ID>
|
||||
* <[6] multicast group MAC>
|
||||
* <[4] 32-bit multicast group ADI>
|
||||
*/
|
||||
VERB_MULTICAST_FRAME = 0x0e,
|
||||
|
||||
/**
|
||||
* Push of potential endpoints for direct communication:
|
||||
* <[2] 16-bit number of paths>
|
||||
|
@ -784,77 +870,67 @@ public:
|
|||
VERB_REMOTE_TRACE = 0x15,
|
||||
|
||||
/**
|
||||
* Multipurpose VL2 network multicast:
|
||||
* <[5] start of range of addresses for propagation>
|
||||
* <[5] end of range of addresses for propagation>
|
||||
* <[1] 8-bit propagation depth / hops or 0xff to not propagate>
|
||||
* <[1] 8-bit length of bloom filter in 256-byte/2048-bit chunks>
|
||||
* <[...] propagation bloom filter>
|
||||
* [... start of signed portion ...]
|
||||
* <[8] 64-bit timestamp>
|
||||
* Peer-to-peer propagated multicast packet:
|
||||
* <[128] 1024-bit bloom filter>
|
||||
* <[2] 16-bit perturbation coefficient to minimize bloom collisions>
|
||||
* <[5] 40-bit start of range of recipient addresses>
|
||||
* <[5] 40-bit end of range of recipient addresses>
|
||||
* [... begin signed portion ...]
|
||||
* <[1] 8-bit flags>
|
||||
* <[5] 40-bit ZeroTier address of sender>
|
||||
* <[8] 64-bit network ID>
|
||||
* <[5] 40-bit address of sender>
|
||||
* <[2] 16-bit length of multicast payload>
|
||||
* [... start multicast payload ...]
|
||||
* <[1] 8-bit payload type>
|
||||
* [... end multicast payload and signed portion ...]
|
||||
* <[2] 16-bit length of signature or 0 if not present>
|
||||
* <[...] signature of signed portion>
|
||||
*
|
||||
* Payload type 0x00: multicast frame:
|
||||
* <[6] MAC address of multicast group>
|
||||
* <[4] 32-bit ADI of multicast group>
|
||||
* <[6] 48-bit source MAC of packet or all 0 if from sender>
|
||||
* <[4] 32-bit ADI for multicast group>
|
||||
* <[6] MAC address of sender>
|
||||
* <[2] 16-bit ethertype>
|
||||
* <[2] 16-bit length of ethernet payload>
|
||||
* <[...] ethernet payload>
|
||||
* [... end signed portion ...]
|
||||
* <[2] 16-bit length of signature or 0 if unsigned>
|
||||
* [<[...] optional signature of multicast>]
|
||||
*
|
||||
* Payload type 0x01: multicast subscribe:
|
||||
* <[2] 16-bit number of multicast group IDs to subscribe>
|
||||
* <[...] series of 32-bit multicast group IDs>
|
||||
*
|
||||
* Payload type 0x02: multicast unsubscribe:
|
||||
* <[2] 16-bit number of multicast group IDs to unsubscribe>
|
||||
* <[...] series of 32-bit multicast group IDs>
|
||||
*
|
||||
* This is the common packet structure for VL2 network-level multicasts
|
||||
* and is used for multicast frames, multicast group subscribe and
|
||||
* unsubscribe, and could be used in the future for other purposes such
|
||||
* as credential propagation or diagnostics.
|
||||
*
|
||||
* The header contains an address range, bloom filter, and depth/hop
|
||||
* counter. The bloom filter tracks which nodes have seen this multicast,
|
||||
* with bits being set prior to send. The range allows the total set of
|
||||
* subscribers to be partitioned in the case of huge networks that would
|
||||
* saturate the bloom filter or have collisions. The propagation depth
|
||||
* allows propagation to stop at some maximum value, and the value 0xff
|
||||
* can be used to indicate that further propagation is not desired.
|
||||
*
|
||||
* Logic connected to the parsing of the multicast payload will determine
|
||||
* whether or not and to whom this multicast is propagated. Subscribe and
|
||||
* unsubscribe messages are propagated to online nodes up to a maximum
|
||||
* depth, while frames have the added constraint of being propagated only
|
||||
* to nodes that subscribe to the target multicast group.
|
||||
* This packet contains a multicast that is to be peer-to-peer replicated.
|
||||
* The range of recipient addresses is a subset of the global list of
|
||||
* subscribers to this multicast group. As the packet is propagated bits
|
||||
* in the bloom filter will be set. The sender may attempt to select a
|
||||
* perturbation coefficient to prevent collisions within the selected
|
||||
* recipient range.
|
||||
*/
|
||||
VERB_VL2_MULTICAST = 0x16,
|
||||
VERB_MULTICAST = 0x16,
|
||||
|
||||
/**
|
||||
* Negotiate a new ephemeral key:
|
||||
* <[8] first 64 bits of SHA-384 of currently known key for destination>
|
||||
* <[...] ephemeral key for sender>
|
||||
* <[48] SHA384 of ephemeral key we currently have for recipient>
|
||||
* [<[...] sender's ephemeral key>]
|
||||
*
|
||||
* If the 64-bit hash of the currently known key sent by the sender does
|
||||
* not match the key the destination is currently using, the destination
|
||||
* will send its own REKEY after sending OK to ensure that keys are up to
|
||||
* date on both sides. This causes either side sending REKEY to trigger
|
||||
* an automatic two-way handshake. Either side may therefore rekey at
|
||||
* any time, though a rate limit should be in effect to prevent flooding.
|
||||
* REKEY is used to negotiate ephemeral keys. The first byte is a step
|
||||
* number from 0 to 2. Here's a new session initiated by Alice:
|
||||
*
|
||||
* OK payload:
|
||||
* <[8] first 64 bits of SHA-384 of received ephemeral key>
|
||||
* Alice: REKEY[0x000...,AliceKey] -> Bob
|
||||
* Bob: REKEY[SHA384(AliceKey),BobKey] -> Alice
|
||||
* Alice: REKEY[SHA384(BobKey),(omitted)] -> Bob
|
||||
*
|
||||
* REKEY messages will continue until both sides have acknowledged each
|
||||
* others' keys. Either Alice or Bob can send REKEY to negotiate a new
|
||||
* ephemeral key pair at any time.
|
||||
*
|
||||
* OK isn't used because this is an ongoing handshake until both sides
|
||||
* agree on a key. REKEY triggers a REKEY in reply if the hash for the
|
||||
* recipient's ephemeral public key doesn't match the ephemeral key it
|
||||
* wants to use.
|
||||
*/
|
||||
VERB_REKEY = 0x17
|
||||
VERB_REKEY = 0x17,
|
||||
|
||||
// TODO: legacy multicast message types must be supported
|
||||
/**
|
||||
* Encapsulate a full ZeroTier packet in another:
|
||||
* <[...] raw encapsulated packet>
|
||||
*
|
||||
* Encapsulation exists to enable secure relaying as opposed to the usual
|
||||
* "dumb" relaying. The latter is faster but secure relaying has roles
|
||||
* where endpoint privacy is desired. Multiply nested ENCAP packets
|
||||
* could allow ZeroTier to act as an onion router.
|
||||
*/
|
||||
VERB_ENCAP = 0x18
|
||||
|
||||
// protocol max: 0x1f
|
||||
};
|
||||
|
|
Loading…
Add table
Reference in a new issue