Regularize use of fingerprint concept across code.

This commit is contained in:
Adam Ierymenko 2020-03-02 12:09:38 -08:00
parent a8db4a8d2d
commit 416068f68e
No known key found for this signature in database
GPG key ID: C8877CF2D7A5D7F3
18 changed files with 156 additions and 160 deletions

View file

@ -278,6 +278,32 @@ extern "C" {
/* ----------------------------------------------------------------------------------------------------------------- */
/**
* Identity type codes
*/
enum ZT_Identity_Type
{
/* These values must be the same as in Identity.hpp in the core. */
ZT_IDENTITY_TYPE_C25519 = 0,
ZT_IDENTITY_TYPE_P384 = 1
};
/**
* A ZeroTier identity (opaque)
*/
typedef void ZT_Identity;
/**
* Full identity fingerprint with address and 384-bit hash of public key(s)
*/
ZT_PACKED_STRUCT(struct _ZT_Fingerprint
{
uint64_t address;
uint8_t hash[48];
});
typedef struct _ZT_Fingerprint ZT_Fingerprint;
/**
* Credential type IDs
*/
@ -460,8 +486,7 @@ _ZT_TRACE_EVENT_STRUCT_END()
* move around on the network.
*/
_ZT_TRACE_EVENT_STRUCT_START(VL1_RESETTING_PATHS_IN_SCOPE)
uint64_t reporter; /* ZeroTier address that triggered the reset */
uint8_t reporterIdentityHash[48]; /* full identity hash of triggering node's identity */
ZT_Fingerprint reporter; /* node that triggered the reset */
struct ZT_TraceEventPathAddress from; /* physical origin of triggering packet */
struct ZT_TraceEventPathAddress oldExternal; /* previous detected external address */
struct ZT_TraceEventPathAddress newExternal; /* new detected external address */
@ -475,14 +500,12 @@ _ZT_TRACE_EVENT_STRUCT_END()
* we might hear of them. A node tries a path by sending a trial message to it.
*/
_ZT_TRACE_EVENT_STRUCT_START(VL1_TRYING_NEW_PATH)
uint64_t address; /* short address of node we're trying to reach */
uint8_t identityHash[48]; /* identity hash of node we're trying to reach */
ZT_Fingerprint peer; /* node we're trying to reach */
struct ZT_TraceEventPathAddress physicalAddress; /* physical address being tried */
struct ZT_TraceEventPathAddress triggerAddress; /* physical origin of triggering packet */
uint64_t triggeringPacketId; /* packet ID of triggering packet */
uint8_t triggeringPacketVerb; /* packet verb of triggering packet */
uint64_t triggeredByAddress; /* short address of node triggering attempt */
uint8_t triggeredByIdentityHash[48]; /* full identity hash of node triggering attempt */
ZT_Fingerprint triggeringPeer; /* peer that triggered attempt */
uint8_t reason; /* ZT_TraceTryingNewPathReason */
_ZT_TRACE_EVENT_STRUCT_END()
@ -491,8 +514,7 @@ _ZT_TRACE_EVENT_STRUCT_END()
*/
_ZT_TRACE_EVENT_STRUCT_START(VL1_LEARNED_NEW_PATH)
uint64_t packetId; /* packet ID of confirming packet */
uint64_t address; /* short address of learned peer */
uint8_t identityHash[48]; /* full identity hash of learned peer */
ZT_Fingerprint peer; /* peer on other side of new path */
struct ZT_TraceEventPathAddress physicalAddress; /* physical address learned */
struct ZT_TraceEventPathAddress replaced; /* if non-empty, an older address that was replaced */
_ZT_TRACE_EVENT_STRUCT_END()
@ -506,8 +528,7 @@ _ZT_TRACE_EVENT_STRUCT_END()
_ZT_TRACE_EVENT_STRUCT_START(VL1_INCOMING_PACKET_DROPPED)
uint64_t packetId; /* packet ID of failed packet */
uint64_t networkId; /* VL2 network ID or 0 if unrelated to a network or unknown */
uint64_t address; /* short address that sent packet */
uint8_t identityHash[48]; /* full identity hash of sending node */
ZT_Fingerprint peer; /* peer that sent packet */
struct ZT_TraceEventPathAddress physicalAddress; /* physical origin address of packet */
uint8_t hops; /* hop count of packet */
uint8_t verb; /* packet verb */
@ -535,7 +556,7 @@ _ZT_TRACE_EVENT_STRUCT_START(VL2_INCOMING_FRAME_DROPPED)
uint64_t networkId; /* VL2 network ID */
uint64_t sourceMac; /* 48-bit source MAC */
uint64_t destMac; /* 48-bit destination MAC */
uint64_t address; /* short address of sending peer */
ZT_Fingerprint sender; /* sending peer */
struct ZT_TraceEventPathAddress physicalAddress; /* physical source address of packet */
uint8_t hops; /* hop count of packet */
uint16_t frameLength; /* length of frame in bytes */
@ -582,7 +603,7 @@ _ZT_TRACE_EVENT_STRUCT_END()
*/
_ZT_TRACE_EVENT_STRUCT_START(VL2_CREDENTIAL_REJECTED)
uint64_t networkId; /* VL2 network ID */
uint64_t address; /* short address of sender */
ZT_Fingerprint peer; /* sending peer */
uint32_t credentialId; /* credential ID */
int64_t credentialTimestamp; /* credential timestamp */
uint8_t credentialType; /* credential type */
@ -728,21 +749,6 @@ enum ZT_Event
ZT_EVENT_USER_MESSAGE = 6
};
/**
* Identity type codes
*/
enum ZT_Identity_Type
{
/* These values must be the same as in Identity.hpp in the core. */
ZT_IDENTITY_TYPE_C25519 = 0,
ZT_IDENTITY_TYPE_P384 = 1
};
/**
* A ZeroTier identity (opaque)
*/
typedef void ZT_Identity;
/**
* User message used with ZT_EVENT_USER_MESSAGE
*
@ -1343,11 +1349,6 @@ typedef struct
*/
const ZT_Identity *identity;
/**
* SHA384 hash of identity public key(s)
*/
uint8_t identityHash[48];
/**
* Remote major version or -1 if not known
*/
@ -2141,15 +2142,6 @@ ZT_SDK_API int ZT_Identity_hasPrivate(const ZT_Identity *id);
*/
ZT_SDK_API uint64_t ZT_Identity_address(const ZT_Identity *id);
/**
* Compute a hash of this identity's public keys (or both public and private if includePrivate is true)
*
* @param id Identity to query
* @param h Buffer for 384-bit hash
* @param includePrivate If true include private keys if any
*/
ZT_SDK_API void ZT_Identity_hash(const ZT_Identity *id,uint8_t h[48],int includePrivate);
/**
* Delete an identity and free associated memory
*

View file

@ -16,11 +16,14 @@
#include "Constants.hpp"
#include "TriviallyCopyable.hpp"
#include "Address.hpp"
#include <algorithm>
namespace ZeroTier {
class Identity;
/**
* Container for 384-bit identity hashes
*
@ -33,39 +36,32 @@ namespace ZeroTier {
*/
class Fingerprint : public TriviallyCopyable
{
friend class Identity;
public:
ZT_ALWAYS_INLINE Fingerprint() noexcept {}
/**
* Create an empty/nil fingerprint
*/
ZT_ALWAYS_INLINE Fingerprint() noexcept { memoryZero(this); }
ZT_ALWAYS_INLINE Address address() const noexcept { return Address(_fp.address); }
ZT_ALWAYS_INLINE const uint8_t *hash() const noexcept { return _fp.hash; }
ZT_ALWAYS_INLINE void setZTFingerprint(ZT_Fingerprint *fp) const noexcept { memcpy(fp,&_fp,sizeof(ZT_Fingerprint)); }
ZT_ALWAYS_INLINE void zero() noexcept { memoryZero(this); }
ZT_ALWAYS_INLINE unsigned long hashCode() const noexcept { return _fp.address; }
ZT_ALWAYS_INLINE uint8_t *data() noexcept { return reinterpret_cast<uint8_t *>(_h); }
ZT_ALWAYS_INLINE const uint8_t *data() const noexcept { return reinterpret_cast<const uint8_t *>(_h); }
ZT_ALWAYS_INLINE operator bool() const noexcept { return (_fp.address != 0); }
ZT_ALWAYS_INLINE uint8_t operator[](const unsigned int i) const noexcept { return reinterpret_cast<const uint8_t *>(_h)[i]; }
ZT_ALWAYS_INLINE uint8_t &operator[](const unsigned int i) noexcept { return reinterpret_cast<uint8_t *>(_h)[i]; }
static constexpr unsigned int size() noexcept { return 48; }
ZT_ALWAYS_INLINE unsigned long hashCode() const noexcept { return _h[0]; }
ZT_ALWAYS_INLINE operator bool() const noexcept
{
for(unsigned int i=0;i<(384 / (sizeof(unsigned long) * 8));++i) {
if (_h[i] != 0)
return true;
}
return false;
}
ZT_ALWAYS_INLINE bool operator==(const Fingerprint &h) const noexcept { return std::equal(_h,_h + (384 / (sizeof(unsigned long) * 8)),h._h); }
ZT_ALWAYS_INLINE bool operator==(const Fingerprint &h) const noexcept { return ((_fp.address == h._fp.address)&&(memcmp(_fp.hash,h._fp.hash,ZT_IDENTITY_HASH_SIZE) == 0)); }
ZT_ALWAYS_INLINE bool operator!=(const Fingerprint &h) const noexcept { return !(*this == h); }
ZT_ALWAYS_INLINE bool operator<(const Fingerprint &h) const noexcept { return std::lexicographical_compare(_h,_h + (384 / (sizeof(unsigned long) * 8)),h._h,h._h + (384 / (sizeof(unsigned long) * 8))); }
ZT_ALWAYS_INLINE bool operator<(const Fingerprint &h) const noexcept { return ((_fp.address < h._fp.address) || ((_fp.address == h._fp.address)&&(memcmp(_fp.hash,h._fp.hash,ZT_IDENTITY_HASH_SIZE) < 0))); }
ZT_ALWAYS_INLINE bool operator>(const Fingerprint &h) const noexcept { return (h < *this); }
ZT_ALWAYS_INLINE bool operator<=(const Fingerprint &h) const noexcept { return !(h < *this); }
ZT_ALWAYS_INLINE bool operator>=(const Fingerprint &h) const noexcept { return !(*this < h); }
private:
unsigned long _h[384 / (sizeof(unsigned long) * 8)];
ZT_Fingerprint _fp;
};
} // namespace ZeroTier

View file

@ -111,8 +111,7 @@ bool Identity::generate(const Type t)
Utils::storeBigEndian(_pub.t1mimc52,mimc52Delay(&_pub,sizeof(_pub) - sizeof(_pub.t1mimc52),ZT_V1_IDENTITY_MIMC52_VDF_ROUNDS_BASE));
// Compute SHA384 fingerprint hash of keys and MIMC output and generate address directly from it.
_computeHash();
_address.setTo(_fp.data());
_computeHash(); // this sets the address for P384
if (!_address.isReserved())
break;
}
@ -140,7 +139,7 @@ bool Identity::locallyValidate() const noexcept
}
case P384:
if (_address == Address(_fp.data())) {
if (_address == Address(_fp.hash())) {
// The most significant 8 bits of the MIMC proof included with v1 identities can be used to store a multiplier
// that can indicate that more work than the required minimum has been performed. Right now this is never done
// but it could have some use in the future. There is no harm in doing it, and we'll accept any round count
@ -445,10 +444,8 @@ int Identity::unmarshal(const uint8_t *data,const int len) noexcept
_fp.zero();
_hasPrivate = false;
if (len < (ZT_ADDRESS_LENGTH + 1))
if (len < (1 + ZT_ADDRESS_LENGTH))
return -1;
_address.setTo(data);
unsigned int privlen;
switch((_type = (Type)data[ZT_ADDRESS_LENGTH])) {
@ -457,6 +454,7 @@ int Identity::unmarshal(const uint8_t *data,const int len) noexcept
return -1;
memcpy(_pub.c25519,data + ZT_ADDRESS_LENGTH + 1,ZT_C25519_PUBLIC_KEY_LEN);
_address.setTo(data);
_computeHash();
privlen = data[ZT_ADDRESS_LENGTH + 1 + ZT_C25519_PUBLIC_KEY_LEN];
@ -477,8 +475,8 @@ int Identity::unmarshal(const uint8_t *data,const int len) noexcept
return -1;
memcpy(&_pub,data + ZT_ADDRESS_LENGTH + 1,ZT_IDENTITY_P384_COMPOUND_PUBLIC_KEY_SIZE);
_computeHash();
if (_address != Address(_fp.data())) // for v1 we can sanity check this here, but this isn't a full validate
_computeHash(); // this sets the address for P384
if (_address != Address(data)) // sanity check address in data stream
return -1;
privlen = data[ZT_ADDRESS_LENGTH + 1 + ZT_IDENTITY_P384_COMPOUND_PUBLIC_KEY_SIZE];
@ -507,11 +505,14 @@ void Identity::_computeHash()
break;
case C25519:
SHA384(_fp.data(),_pub.c25519,ZT_C25519_PUBLIC_KEY_LEN);
_fp._fp.address = _address.toInt();
SHA384(_fp._fp.hash,_pub.c25519,ZT_C25519_PUBLIC_KEY_LEN);
break;
case P384:
SHA384(_fp.data(),&_pub,sizeof(_pub));
SHA384(_fp._fp.hash,&_pub,sizeof(_pub));
_address.setTo(reinterpret_cast<const uint8_t *>(_fp._fp.hash));
_fp._fp.address = _address.toInt();
break;
}
}
@ -601,13 +602,6 @@ uint64_t ZT_Identity_address(const ZT_Identity *id)
return reinterpret_cast<const ZeroTier::Identity *>(id)->address().toInt();
}
void ZT_Identity_hash(const ZT_Identity *id,uint8_t h[48],int includePrivate)
{
if (includePrivate)
reinterpret_cast<const ZeroTier::Identity *>(id)->hashWithPrivate(h);
else memcpy(h,reinterpret_cast<const ZeroTier::Identity *>(id)->fingerprint().data(),ZT_IDENTITY_HASH_SIZE);
}
ZT_SDK_API void ZT_Identity_delete(ZT_Identity *id)
{
if (id)

View file

@ -130,13 +130,13 @@ Membership::AddCredentialResult Membership::addCredential(const RuntimeEnvironme
{
const int64_t newts = com.timestamp();
if (newts <= _comRevocationThreshold) {
RR->t->credentialRejected(tPtr,0xd9992121,com.networkId(),sourcePeerIdentity.address(),com.id(),com.timestamp(),ZT_CREDENTIAL_TYPE_COM,ZT_TRACE_CREDENTIAL_REJECTION_REASON_REVOKED);
RR->t->credentialRejected(tPtr,0xd9992121,com.networkId(),sourcePeerIdentity.address(),sourcePeerIdentity,com.id(),com.timestamp(),ZT_CREDENTIAL_TYPE_COM,ZT_TRACE_CREDENTIAL_REJECTION_REASON_REVOKED);
return ADD_REJECTED;
}
const int64_t oldts = _com.timestamp();
if (newts < oldts) {
RR->t->credentialRejected(tPtr,0xd9928192,com.networkId(),sourcePeerIdentity.address(),com.id(),com.timestamp(),ZT_CREDENTIAL_TYPE_COM,ZT_TRACE_CREDENTIAL_REJECTION_REASON_OLDER_THAN_LATEST);
RR->t->credentialRejected(tPtr,0xd9928192,com.networkId(),sourcePeerIdentity.address(),sourcePeerIdentity,com.id(),com.timestamp(),ZT_CREDENTIAL_TYPE_COM,ZT_TRACE_CREDENTIAL_REJECTION_REASON_OLDER_THAN_LATEST);
return ADD_REJECTED;
}
if ((newts == oldts)&&(_com == com))
@ -144,13 +144,13 @@ Membership::AddCredentialResult Membership::addCredential(const RuntimeEnvironme
switch(com.verify(RR,tPtr)) {
default:
RR->t->credentialRejected(tPtr,0x0f198241,com.networkId(),sourcePeerIdentity.address(),com.id(),com.timestamp(),ZT_CREDENTIAL_TYPE_COM,ZT_TRACE_CREDENTIAL_REJECTION_REASON_INVALID);
RR->t->credentialRejected(tPtr,0x0f198241,com.networkId(),sourcePeerIdentity.address(),sourcePeerIdentity,com.id(),com.timestamp(),ZT_CREDENTIAL_TYPE_COM,ZT_TRACE_CREDENTIAL_REJECTION_REASON_INVALID);
return Membership::ADD_REJECTED;
case Credential::VERIFY_OK:
_com = com;
return ADD_ACCEPTED_NEW;
case Credential::VERIFY_BAD_SIGNATURE:
RR->t->credentialRejected(tPtr,0xbaf0aaaa,com.networkId(),sourcePeerIdentity.address(),com.id(),com.timestamp(),ZT_CREDENTIAL_TYPE_COM,ZT_TRACE_CREDENTIAL_REJECTION_REASON_SIGNATURE_VERIFICATION_FAILED);
RR->t->credentialRejected(tPtr,0xbaf0aaaa,com.networkId(),sourcePeerIdentity.address(),sourcePeerIdentity,com.id(),com.timestamp(),ZT_CREDENTIAL_TYPE_COM,ZT_TRACE_CREDENTIAL_REJECTION_REASON_SIGNATURE_VERIFICATION_FAILED);
return ADD_REJECTED;
case Credential::VERIFY_NEED_IDENTITY:
return ADD_DEFERRED_FOR_WHOIS;
@ -171,7 +171,7 @@ static ZT_ALWAYS_INLINE Membership::AddCredentialResult _addCredImpl(
C *rc = remoteCreds.get(cred.id());
if (rc) {
if (rc->timestamp() > cred.timestamp()) {
RR->t->credentialRejected(tPtr,0x40000001,nconf.networkId,sourcePeerIdentity.address(),cred.id(),cred.timestamp(),C::credentialType(),ZT_TRACE_CREDENTIAL_REJECTION_REASON_OLDER_THAN_LATEST);
RR->t->credentialRejected(tPtr,0x40000001,nconf.networkId,sourcePeerIdentity.address(),sourcePeerIdentity,cred.id(),cred.timestamp(),C::credentialType(),ZT_TRACE_CREDENTIAL_REJECTION_REASON_OLDER_THAN_LATEST);
return Membership::ADD_REJECTED;
}
if (*rc == cred)
@ -180,13 +180,13 @@ static ZT_ALWAYS_INLINE Membership::AddCredentialResult _addCredImpl(
const int64_t *const rt = revocations.get(Membership::credentialKey(C::credentialType(),cred.id()));
if ((rt)&&(*rt >= cred.timestamp())) {
RR->t->credentialRejected(tPtr,0x24248124,nconf.networkId,sourcePeerIdentity.address(),cred.id(),cred.timestamp(),C::credentialType(),ZT_TRACE_CREDENTIAL_REJECTION_REASON_REVOKED);
RR->t->credentialRejected(tPtr,0x24248124,nconf.networkId,sourcePeerIdentity.address(),sourcePeerIdentity,cred.id(),cred.timestamp(),C::credentialType(),ZT_TRACE_CREDENTIAL_REJECTION_REASON_REVOKED);
return Membership::ADD_REJECTED;
}
switch(cred.verify(RR,tPtr)) {
default:
RR->t->credentialRejected(tPtr,0x01feba012,nconf.networkId,sourcePeerIdentity.address(),cred.id(),cred.timestamp(),C::credentialType(),ZT_TRACE_CREDENTIAL_REJECTION_REASON_INVALID);
RR->t->credentialRejected(tPtr,0x01feba012,nconf.networkId,sourcePeerIdentity.address(),sourcePeerIdentity,cred.id(),cred.timestamp(),C::credentialType(),ZT_TRACE_CREDENTIAL_REJECTION_REASON_INVALID);
return Membership::ADD_REJECTED;
case 0:
if (!rc)
@ -206,7 +206,7 @@ Membership::AddCredentialResult Membership::addCredential(const RuntimeEnvironme
int64_t *rt;
switch(rev.verify(RR,tPtr)) {
default:
RR->t->credentialRejected(tPtr,0x938fffff,nconf.networkId,sourcePeerIdentity.address(),rev.id(),0,ZT_CREDENTIAL_TYPE_REVOCATION,ZT_TRACE_CREDENTIAL_REJECTION_REASON_INVALID);
RR->t->credentialRejected(tPtr,0x938fffff,nconf.networkId,sourcePeerIdentity.address(),sourcePeerIdentity,rev.id(),0,ZT_CREDENTIAL_TYPE_REVOCATION,ZT_TRACE_CREDENTIAL_REJECTION_REASON_INVALID);
return ADD_REJECTED;
case 0: {
const ZT_CredentialType ct = rev.typeBeingRevoked();
@ -228,7 +228,7 @@ Membership::AddCredentialResult Membership::addCredential(const RuntimeEnvironme
}
return ADD_ACCEPTED_REDUNDANT;
default:
RR->t->credentialRejected(tPtr,0x0bbbb1a4,nconf.networkId,sourcePeerIdentity.address(),rev.id(),0,ZT_CREDENTIAL_TYPE_REVOCATION,ZT_TRACE_CREDENTIAL_REJECTION_REASON_INVALID);
RR->t->credentialRejected(tPtr,0x0bbbb1a4,nconf.networkId,sourcePeerIdentity.address(),sourcePeerIdentity,rev.id(),0,ZT_CREDENTIAL_TYPE_REVOCATION,ZT_TRACE_CREDENTIAL_REJECTION_REASON_INVALID);
return ADD_REJECTED;
}
}

View file

@ -1010,7 +1010,7 @@ int Network::setConfiguration(void *tPtr,const NetworkConfig &nconf,bool saveToD
try {
if ((nconf.issuedTo != RR->identity.address())||(nconf.networkId != _id))
return 0; // invalid config that is not for us or not for this network
if ((!Utils::allZero(nconf.issuedToIdentityHash,ZT_IDENTITY_HASH_SIZE))&&(memcmp(nconf.issuedToIdentityHash,RR->identity.fingerprint().data(),ZT_IDENTITY_HASH_SIZE) != 0))
if ((!Utils::allZero(nconf.issuedToFingerprintHash,ZT_IDENTITY_HASH_SIZE))&&(memcmp(nconf.issuedToFingerprintHash,RR->identity.fingerprint().hash(),ZT_IDENTITY_HASH_SIZE) != 0))
return 0; // full identity hash is present and does not match
if (_config == nconf)

View file

@ -32,7 +32,7 @@ bool NetworkConfig::toDictionary(Dictionary &d,bool includeLegacy) const
d.add(ZT_NETWORKCONFIG_DICT_KEY_CREDENTIAL_TIME_MAX_DELTA,this->credentialTimeMaxDelta);
d.add(ZT_NETWORKCONFIG_DICT_KEY_REVISION,this->revision);
d.add(ZT_NETWORKCONFIG_DICT_KEY_ISSUED_TO,this->issuedTo.toString((char *)tmp));
d.add(ZT_NETWORKCONFIG_DICT_KEY_ISSUED_TO_IDENTITY_HASH,this->issuedToIdentityHash,ZT_IDENTITY_HASH_SIZE);
d.add(ZT_NETWORKCONFIG_DICT_KEY_ISSUED_TO_IDENTITY_HASH,this->issuedToFingerprintHash,ZT_IDENTITY_HASH_SIZE);
d.add(ZT_NETWORKCONFIG_DICT_KEY_FLAGS,this->flags);
d.add(ZT_NETWORKCONFIG_DICT_KEY_MULTICAST_LIMIT,(uint64_t)this->multicastLimit);
d.add(ZT_NETWORKCONFIG_DICT_KEY_TYPE,(uint16_t)this->type);
@ -122,9 +122,9 @@ bool NetworkConfig::fromDictionary(const Dictionary &d)
this->issuedTo = d.getUI(ZT_NETWORKCONFIG_DICT_KEY_ISSUED_TO,0);
const std::vector<uint8_t> *blob = &(d[ZT_NETWORKCONFIG_DICT_KEY_ISSUED_TO_IDENTITY_HASH]);
if (blob->size() == ZT_IDENTITY_HASH_SIZE) {
memcpy(this->issuedToIdentityHash,blob->data(),ZT_IDENTITY_HASH_SIZE);
memcpy(this->issuedToFingerprintHash,blob->data(),ZT_IDENTITY_HASH_SIZE);
} else {
memset(this->issuedToIdentityHash,0,ZT_IDENTITY_HASH_SIZE);
memset(this->issuedToFingerprintHash,0,ZT_IDENTITY_HASH_SIZE);
}
if (!this->issuedTo)
return false;

View file

@ -280,7 +280,7 @@ struct NetworkConfig : TriviallyCopyable
* If this field is all zero it is treated as undefined since old controllers
* do not set it.
*/
uint8_t issuedToIdentityHash[ZT_IDENTITY_HASH_SIZE];
uint8_t issuedToFingerprintHash[ZT_IDENTITY_HASH_SIZE];
/**
* Flags (64-bit)

View file

@ -111,7 +111,10 @@ Node::Node(void *uPtr,void *tPtr,const struct ZT_Node_Callbacks *callbacks,int64
stateObjectPut(tPtr,ZT_STATE_OBJECT_IDENTITY_PUBLIC,idtmp,RR->publicIdentityStr,(unsigned int)strlen(RR->publicIdentityStr));
}
RR->identity.hashWithPrivate(RR->localCacheSymmetricKey);
uint8_t tmph[ZT_IDENTITY_HASH_SIZE];
RR->identity.hashWithPrivate(tmph);
RR->localCacheSymmetric.init(tmph);
Utils::burn(tmph,sizeof(tmph));
// This constructs all the components of the ZeroTier core within a single contiguous memory container,
// which reduces memory fragmentation and may improve cache locality.
@ -483,7 +486,6 @@ ZT_PeerList *Node::peers() const
p->address = (*pi)->address().toInt();
identities[pl->peerCount] = (*pi)->identity(); // need to make a copy in case peer gets deleted
p->identity = &identities[pl->peerCount];
memcpy(p->identityHash,(*pi)->identity().fingerprint().data(),ZT_IDENTITY_HASH_SIZE);
if ((*pi)->remoteVersionKnown()) {
p->versionMajor = (int)(*pi)->remoteVersionMajor();
p->versionMinor = (int)(*pi)->remoteVersionMinor();

View file

@ -123,7 +123,7 @@ void Peer::received(
RR->t->learnedNewPath(tPtr,0x582fabdd,packetId,_id,path->address(),old);
} else {
if (RR->node->shouldUsePathForZeroTierTraffic(tPtr,_id,path->localSocket(),path->address())) {
RR->t->tryingNewPath(tPtr,0xb7747ddd,_id,path->address(),path->address(),packetId,(uint8_t)verb,_id.address(),_id.fingerprint().data(),ZT_TRACE_TRYING_NEW_PATH_REASON_PACKET_RECEIVED_FROM_UNKNOWN_PATH);
RR->t->tryingNewPath(tPtr,0xb7747ddd,_id,path->address(),path->address(),packetId,(uint8_t)verb,_id,ZT_TRACE_TRYING_NEW_PATH_REASON_PACKET_RECEIVED_FROM_UNKNOWN_PATH);
path->sent(now,sendHELLO(tPtr,path->localSocket(),path->address(),now));
}
}
@ -135,11 +135,11 @@ path_check_done:
InetAddress addr;
if ((_bootstrap.type() == Endpoint::TYPE_INETADDR_V4)||(_bootstrap.type() == Endpoint::TYPE_INETADDR_V6)) {
RR->t->tryingNewPath(tPtr,0x0a009444,_id,_bootstrap.inetAddr(),InetAddress::NIL,0,0,0,nullptr,ZT_TRACE_TRYING_NEW_PATH_REASON_BOOTSTRAP_ADDRESS);
RR->t->tryingNewPath(tPtr,0x0a009444,_id,_bootstrap.inetAddr(),InetAddress::NIL,0,0,Identity::NIL,ZT_TRACE_TRYING_NEW_PATH_REASON_BOOTSTRAP_ADDRESS);
sendHELLO(tPtr,-1,_bootstrap.inetAddr(),now);
} if (RR->node->externalPathLookup(tPtr,_id,-1,addr)) {
if (RR->node->shouldUsePathForZeroTierTraffic(tPtr,_id,-1,addr)) {
RR->t->tryingNewPath(tPtr,0x84a10000,_id,_bootstrap.inetAddr(),InetAddress::NIL,0,0,0,nullptr,ZT_TRACE_TRYING_NEW_PATH_REASON_EXPLICITLY_SUGGESTED_ADDRESS);
RR->t->tryingNewPath(tPtr,0x84a10000,_id,_bootstrap.inetAddr(),InetAddress::NIL,0,0,Identity::NIL,ZT_TRACE_TRYING_NEW_PATH_REASON_EXPLICITLY_SUGGESTED_ADDRESS);
sendHELLO(tPtr,-1,addr,now);
}
}
@ -485,14 +485,23 @@ void Peer::alarm(void *tPtr,const int64_t now)
int Peer::marshal(uint8_t data[ZT_PEER_MARSHAL_SIZE_MAX]) const noexcept
{
RWMutex::RLock l(_lock);
data[0] = 0; // serialized peer version
int s = _id.marshal(data + 1,false);
// For faster unmarshaling on large nodes the long-term secret key is cached. It's
// encrypted with a symmetric key derived from a hash of the local node's identity
// secrets, so the local node's address is also included. That way the unmarshal
// code can check this address and not use this cached key if the local identity has
// changed. In that case agreement must be executed again.
RR->identity.address().copyTo(data + 1);
RR->localCacheSymmetric.encrypt(_key,data + 6);
RR->localCacheSymmetric.encrypt(_key + 16,data + 22);
RWMutex::RLock l(_lock);
int s = _id.marshal(data + 38,false);
if (s <= 0)
return s;
int p = 1 + s;
int p = s + 38;
s = _locator.marshal(data + p);
if (s <= 0)
return s;
@ -520,17 +529,26 @@ int Peer::marshal(uint8_t data[ZT_PEER_MARSHAL_SIZE_MAX]) const noexcept
int Peer::unmarshal(const uint8_t *restrict data,const int len) noexcept
{
int p;
bool mustRecomputeSecret;
{
RWMutex::Lock l(_lock);
if ((len <= 1) || (data[0] != 0))
if ((len <= 38) || (data[0] != 0))
return -1;
int s = _id.unmarshal(data + 1,len - 1);
if (Address(data + 1) == RR->identity.address()) {
RR->localCacheSymmetric.decrypt(data + 6,_key);
RR->localCacheSymmetric.decrypt(data + 22,_key + 16);
mustRecomputeSecret = false;
} else {
mustRecomputeSecret = true; // can't use cached key if local identity has changed
}
int s = _id.unmarshal(data + 38,len - 38);
if (s <= 0)
return s;
p = 1 + s;
p = s + 38;
s = _locator.unmarshal(data + p,len - p);
if (s <= 0)
return s;
@ -542,6 +560,7 @@ int Peer::unmarshal(const uint8_t *restrict data,const int len) noexcept
if ((p + 10) > len)
return -1;
_vProto = Utils::loadBigEndian<uint16_t>(data + p);
p += 2;
_vMajor = Utils::loadBigEndian<uint16_t>(data + p);
@ -551,12 +570,16 @@ int Peer::unmarshal(const uint8_t *restrict data,const int len) noexcept
_vRevision = Utils::loadBigEndian<uint16_t>(data + p);
p += 2;
p += 2 + (int)Utils::loadBigEndian<uint16_t>(data + p);
if (p > len)
return -1;
}
if (!RR->identity.agree(_id,_key))
return -1;
if (mustRecomputeSecret) {
if (!RR->identity.agree(_id,_key))
return -1;
}
_incomingProbe = Protocol::createProbe(_id,RR->identity,_key);
return p;

View file

@ -33,7 +33,7 @@
#include <list>
// version, identity, locator, bootstrap, version info, length of any additional fields
#define ZT_PEER_MARSHAL_SIZE_MAX (1 + ZT_IDENTITY_MARSHAL_SIZE_MAX + ZT_LOCATOR_MARSHAL_SIZE_MAX + ZT_INETADDRESS_MARSHAL_SIZE_MAX + (2*4) + 2)
#define ZT_PEER_MARSHAL_SIZE_MAX (1 + ZT_ADDRESS_LENGTH + ZT_PEER_SECRET_KEY_LENGTH + ZT_IDENTITY_MARSHAL_SIZE_MAX + ZT_LOCATOR_MARSHAL_SIZE_MAX + ZT_INETADDRESS_MARSHAL_SIZE_MAX + (2*4) + 2)
namespace ZeroTier {

View file

@ -33,8 +33,8 @@ std::atomic<uint64_t> _s_packetIdCtr((uint64_t)time(nullptr) << 32U);
uint64_t createProbe(const Identity &sender,const Identity &recipient,const uint8_t key[ZT_PEER_SECRET_KEY_LENGTH]) noexcept
{
uint8_t tmp[ZT_IDENTITY_HASH_SIZE + ZT_IDENTITY_HASH_SIZE];
memcpy(tmp,sender.fingerprint().data(),ZT_IDENTITY_HASH_SIZE);
memcpy(tmp + ZT_IDENTITY_HASH_SIZE,recipient.fingerprint().data(),ZT_IDENTITY_HASH_SIZE);
memcpy(tmp,sender.fingerprint().hash(),ZT_IDENTITY_HASH_SIZE);
memcpy(tmp + ZT_IDENTITY_HASH_SIZE,recipient.fingerprint().hash(),ZT_IDENTITY_HASH_SIZE);
uint64_t hash[6];
SHA384(hash,tmp,sizeof(tmp),key,ZT_PEER_SECRET_KEY_LENGTH);
return hash[0];

View file

@ -17,6 +17,7 @@
#include "Constants.hpp"
#include "Utils.hpp"
#include "Identity.hpp"
#include "AES.hpp"
namespace ZeroTier {
@ -57,7 +58,6 @@ public:
ZT_ALWAYS_INLINE ~RuntimeEnvironment()
{
Utils::burn(secretIdentityStr,sizeof(secretIdentityStr));
Utils::burn(localCacheSymmetricKey,sizeof(localCacheSymmetricKey));
}
// Node instance that owns this RuntimeEnvironment
@ -81,9 +81,8 @@ public:
char publicIdentityStr[ZT_IDENTITY_STRING_BUFFER_LENGTH];
char secretIdentityStr[ZT_IDENTITY_STRING_BUFFER_LENGTH];
// A hash of this node identity's public and private keys that is used as
// a secret key to encrypt locally cached sensitive information.
uint8_t localCacheSymmetricKey[ZT_IDENTITY_HASH_SIZE];
// AES keyed with a hash of this node's identity secret keys for local cache encryption at rest (where needed).
AES localCacheSymmetric;
};
} // namespace ZeroTier

View file

@ -285,7 +285,7 @@ extern "C" const char *ZTT_general()
ZT_T_ASSERT(sizeof(sockaddr_in) <= sizeof(InetAddress));
ZT_T_ASSERT(sizeof(sockaddr_in6) <= sizeof(InetAddress));
ZT_T_ASSERT(sizeof(sockaddr) <= sizeof(InetAddress));
ZT_T_ASSERT(sizeof(Fingerprint) == 48);
ZT_T_ASSERT(sizeof(Fingerprint) == sizeof(ZT_Fingerprint));
ZT_T_PRINTF("OK" ZT_EOL_S);
}

View file

@ -351,7 +351,7 @@ private:
#endif
return h + (uint64_t)Utils::ntoh(reinterpret_cast<const struct sockaddr_in6 *>(&r)->sin6_port) + (uint64_t)l;
} else {
return Utils::hashString(reinterpret_cast<const void *>(&r),sizeof(InetAddress)) + (uint64_t)l;
return Utils::fnv1a32(reinterpret_cast<const void *>(&r),sizeof(InetAddress)) + (uint64_t)l;
}
}

View file

@ -109,24 +109,19 @@ void Trace::_tryingNewPath(
const InetAddress &triggerAddress,
const uint64_t triggeringPacketId,
const uint8_t triggeringPacketVerb,
const uint64_t triggeredByAddress,
const uint8_t *triggeredByIdentityHash,
const Identity &triggeringPeer,
const ZT_TraceTryingNewPathReason reason)
{
ZT_TraceEvent_VL1_TRYING_NEW_PATH ev;
ev.evSize = ZT_CONST_TO_BE_UINT16(sizeof(ev));
ev.evType = ZT_CONST_TO_BE_UINT16(ZT_TRACE_VL1_TRYING_NEW_PATH);
ev.codeLocation = Utils::hton(codeLocation);
ev.address = Utils::hton(trying.address().toInt());
memcpy(ev.identityHash,trying.fingerprint().data(),48);
trying.fingerprint().setZTFingerprint(&ev.peer);
physicalAddress.forTrace(ev.physicalAddress);
triggerAddress.forTrace(ev.triggerAddress);
ev.triggeringPacketId = triggeringPacketId;
ev.triggeringPacketVerb = triggeringPacketVerb;
ev.triggeredByAddress = Utils::hton(triggeredByAddress);
if (triggeredByIdentityHash)
memcpy(ev.triggeredByIdentityHash,triggeredByIdentityHash,ZT_IDENTITY_HASH_SIZE);
else memset(ev.triggeredByIdentityHash,0,ZT_IDENTITY_HASH_SIZE);
triggeringPeer.fingerprint().setZTFingerprint(&ev.triggeringPeer);
ev.reason = (uint8_t)reason;
RR->node->postEvent(tPtr,ZT_EVENT_TRACE,&ev);
}
@ -144,8 +139,7 @@ void Trace::_learnedNewPath(
ev.evType = ZT_CONST_TO_BE_UINT16(ZT_TRACE_VL1_LEARNED_NEW_PATH);
ev.codeLocation = Utils::hton(codeLocation);
ev.packetId = packetId; // packet IDs are kept in big-endian
ev.address = Utils::hton(peerIdentity.address().toInt());
memcpy(ev.identityHash,peerIdentity.fingerprint().data(),ZT_IDENTITY_HASH_SIZE);
peerIdentity.fingerprint().setZTFingerprint(&ev.peer);
physicalAddress.forTrace(ev.physicalAddress);
replaced.forTrace(ev.replaced);
@ -169,13 +163,7 @@ void Trace::_incomingPacketDropped(
ev.codeLocation = Utils::hton(codeLocation);
ev.packetId = packetId; // packet IDs are kept in big-endian
ev.networkId = Utils::hton(networkId);
if (peerIdentity) {
ev.address = Utils::hton(peerIdentity.address().toInt());
memcpy(ev.identityHash,peerIdentity.fingerprint().data(),ZT_IDENTITY_HASH_SIZE);
} else {
ev.address = 0;
memset(ev.identityHash,0,ZT_IDENTITY_HASH_SIZE);
}
peerIdentity.fingerprint().setZTFingerprint(&ev.peer);
physicalAddress.forTrace(ev.physicalAddress);
ev.hops = hops;
ev.verb = verb;
@ -238,7 +226,7 @@ void Trace::_incomingNetworkFrameDropped(
ev.networkId = Utils::hton(networkId);
ev.sourceMac = Utils::hton(sourceMac.toInt());
ev.destMac = Utils::hton(destMac.toInt());
ev.address = Utils::hton(peerIdentity.address().toInt());
peerIdentity.fingerprint().setZTFingerprint(&ev.sender);
physicalAddress.forTrace(ev.physicalAddress);
ev.hops = hops;
ev.frameLength = Utils::hton(frameLength);
@ -325,6 +313,7 @@ void Trace::_credentialRejected(
const uint32_t codeLocation,
const uint64_t networkId,
const Address &address,
const Identity &identity,
const uint32_t credentialId,
const int64_t credentialTimestamp,
const uint8_t credentialType,
@ -335,7 +324,12 @@ void Trace::_credentialRejected(
ev.evType = ZT_CONST_TO_BE_UINT16(ZT_TRACE_VL2_NETWORK_FILTER);
ev.codeLocation = Utils::hton(codeLocation);
ev.networkId = Utils::hton(networkId);
ev.address = Utils::hton(address.toInt());
if (identity) {
identity.fingerprint().setZTFingerprint(&ev.peer);
} else {
ev.peer.address = address.toInt();
memset(ev.peer.hash,0,sizeof(ev.peer.hash));
}
ev.credentialId = Utils::hton(credentialId);
ev.credentialTimestamp = Utils::hton(credentialTimestamp);
ev.credentialType = credentialType;

View file

@ -119,11 +119,10 @@ public:
const InetAddress &triggerAddress,
uint64_t triggeringPacketId,
uint8_t triggeringPacketVerb,
uint64_t triggeredByAddress,
const uint8_t *triggeredByIdentityHash,
const Identity &triggeringPeer,
ZT_TraceTryingNewPathReason reason)
{
if (_vl1) _tryingNewPath(tPtr,codeLocation,trying,physicalAddress,triggerAddress,triggeringPacketId,triggeringPacketVerb,triggeredByAddress,triggeredByIdentityHash,reason);
if (_vl1) _tryingNewPath(tPtr,codeLocation,trying,physicalAddress,triggerAddress,triggeringPacketId,triggeringPacketVerb,triggeringPeer,reason);
}
ZT_ALWAYS_INLINE void learnedNewPath(
@ -239,12 +238,13 @@ public:
const uint32_t codeLocation,
uint64_t networkId,
const Address &address,
const Identity &identity,
uint32_t credentialId,
int64_t credentialTimestamp,
uint8_t credentialType,
ZT_TraceCredentialRejectionReason reason)
{
if (_vl2) _credentialRejected(tPtr,codeLocation,networkId,address,credentialId,credentialTimestamp,credentialType,reason);
if (_vl2) _credentialRejected(tPtr,codeLocation,networkId,address,identity,credentialId,credentialTimestamp,credentialType,reason);
}
private:
@ -264,8 +264,7 @@ private:
const InetAddress &triggerAddress,
uint64_t triggeringPacketId,
uint8_t triggeringPacketVerb,
uint64_t triggeredByAddress,
const uint8_t *triggeredByIdentityHash,
const Identity &triggeringPeer,
ZT_TraceTryingNewPathReason reason);
void _learnedNewPath(
void *tPtr,
@ -336,6 +335,7 @@ private:
uint32_t codeLocation,
uint64_t networkId,
const Address &address,
const Identity &identity,
uint32_t credentialId,
int64_t credentialTimestamp,
uint8_t credentialType,

View file

@ -258,24 +258,20 @@ static ZT_ALWAYS_INLINE unsigned long long hexStrToU64(const char *s) noexcept
}
/**
* Calculate a non-cryptographic hash of a byte string
* Compute 32-bit FNV-1a checksum
*
* @param key Key to hash
* @param len Length in bytes
* @return Non-cryptographic hash suitable for use in a hash table
* See: http://www.isthe.com/chongo/tech/comp/fnv/
*
* @param data Data to checksum
* @param len Length of data
* @return FNV1a checksum
*/
static ZT_ALWAYS_INLINE unsigned long hashString(const void *restrict key,const unsigned int len) noexcept
static ZT_ALWAYS_INLINE uint32_t fnv1a32(const void *const data,const unsigned int len) noexcept
{
const uint8_t *p = reinterpret_cast<const uint8_t *>(key);
unsigned long h = 0;
for (unsigned int i=0;i<len;++i) {
h += p[i];
h += (h << 10U);
h ^= (h >> 6U);
}
h += (h << 3U);
h ^= (h >> 11U);
h += (h << 15U);
uint32_t h = 0x811c9dc5;
const uint32_t p = 0x01000193;
for(unsigned int i=0;i<len;++i)
h = (h ^ (uint32_t)reinterpret_cast<const uint8_t *>(data)[i]) * p;
return h;
}

View file

@ -823,7 +823,7 @@ bool VL1::_RENDEZVOUS(void *tPtr,const SharedPtr<Path> &path,const SharedPtr<Pee
if ((sizeof(Protocol::RENDEZVOUS) + rdv.addressLength) <= packetSize) {
const InetAddress atAddr(pkt.unsafeData + sizeof(Protocol::RENDEZVOUS),rdv.addressLength,port);
peer->contact(tPtr,Endpoint(atAddr),now,false);
RR->t->tryingNewPath(tPtr,0x55a19aaa,with->identity(),atAddr,path->address(),Protocol::packetId(pkt,packetSize),Protocol::VERB_RENDEZVOUS,peer->address(),peer->identity().fingerprint().data(),ZT_TRACE_TRYING_NEW_PATH_REASON_RENDEZVOUS);
RR->t->tryingNewPath(tPtr,0x55a19aaa,with->identity(),atAddr,path->address(),Protocol::packetId(pkt,packetSize),Protocol::VERB_RENDEZVOUS,peer->identity(),ZT_TRACE_TRYING_NEW_PATH_REASON_RENDEZVOUS);
}
break;
case 255: {
@ -835,7 +835,7 @@ bool VL1::_RENDEZVOUS(void *tPtr,const SharedPtr<Path> &path,const SharedPtr<Pee
case Endpoint::TYPE_INETADDR_V4:
case Endpoint::TYPE_INETADDR_V6:
peer->contact(tPtr,ep,now,false);
RR->t->tryingNewPath(tPtr,0x55a19aab,with->identity(),ep.inetAddr(),path->address(),Protocol::packetId(pkt,packetSize),Protocol::VERB_RENDEZVOUS,peer->address(),peer->identity().fingerprint().data(),ZT_TRACE_TRYING_NEW_PATH_REASON_RENDEZVOUS);
RR->t->tryingNewPath(tPtr,0x55a19aab,with->identity(),ep.inetAddr(),path->address(),Protocol::packetId(pkt,packetSize),Protocol::VERB_RENDEZVOUS,peer->identity(),ZT_TRACE_TRYING_NEW_PATH_REASON_RENDEZVOUS);
break;
default:
break;
@ -969,7 +969,7 @@ bool VL1::_PUSH_DIRECT_PATHS(void *tPtr,const SharedPtr<Path> &path,const Shared
}
if (a) {
RR->t->tryingNewPath(tPtr,0xa5ab1a43,peer->identity(),a,path->address(),Protocol::packetId(pkt,packetSize),Protocol::VERB_RENDEZVOUS,peer->address(),peer->identity().fingerprint().data(),ZT_TRACE_TRYING_NEW_PATH_REASON_RECEIVED_PUSH_DIRECT_PATHS);
RR->t->tryingNewPath(tPtr,0xa5ab1a43,peer->identity(),a,path->address(),Protocol::packetId(pkt,packetSize),Protocol::VERB_RENDEZVOUS,peer->identity(),ZT_TRACE_TRYING_NEW_PATH_REASON_RECEIVED_PUSH_DIRECT_PATHS);
}
ptr += (int)addrRecordLen;