diff --git a/node/Fingerprint.hpp b/node/Fingerprint.hpp index 3a29e4999..884b29174 100644 --- a/node/Fingerprint.hpp +++ b/node/Fingerprint.hpp @@ -17,6 +17,8 @@ #include "Constants.hpp" #include "TriviallyCopyable.hpp" +#include + namespace ZeroTier { /** @@ -62,12 +64,12 @@ public: return false; } - ZT_ALWAYS_INLINE bool operator==(const Fingerprint &h) const noexcept { return memcmp(_h,h._h,48) == 0; } - ZT_ALWAYS_INLINE bool operator!=(const Fingerprint &h) const noexcept { return memcmp(_h,h._h,48) != 0; } - ZT_ALWAYS_INLINE bool operator<(const Fingerprint &h) const noexcept { return memcmp(_h,h._h,48) < 0; } - ZT_ALWAYS_INLINE bool operator>(const Fingerprint &h) const noexcept { return memcmp(_h,h._h,48) > 0; } - ZT_ALWAYS_INLINE bool operator<=(const Fingerprint &h) const noexcept { return memcmp(_h,h._h,48) <= 0; } - ZT_ALWAYS_INLINE bool operator>=(const Fingerprint &h) const noexcept { return memcmp(_h,h._h,48) >= 0; } + 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 !(*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 (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)]; diff --git a/node/Identity.cpp b/node/Identity.cpp index 838353cee..98f1c7915 100644 --- a/node/Identity.cpp +++ b/node/Identity.cpp @@ -414,9 +414,7 @@ int Identity::marshal(uint8_t data[ZT_IDENTITY_MARSHAL_SIZE_MAX],const bool incl switch(_type) { case C25519: data[ZT_ADDRESS_LENGTH] = (uint8_t)C25519; - memcpy(data + ZT_ADDRESS_LENGTH + 1,_pub.c25519,ZT_C25519_PUBLIC_KEY_LEN); - if ((includePrivate)&&(_hasPrivate)) { data[ZT_ADDRESS_LENGTH + 1 + ZT_C25519_PUBLIC_KEY_LEN] = ZT_C25519_PRIVATE_KEY_LEN; memcpy(data + ZT_ADDRESS_LENGTH + 1 + ZT_C25519_PUBLIC_KEY_LEN + 1,_priv.c25519,ZT_C25519_PRIVATE_KEY_LEN); @@ -428,9 +426,7 @@ int Identity::marshal(uint8_t data[ZT_IDENTITY_MARSHAL_SIZE_MAX],const bool incl case P384: data[ZT_ADDRESS_LENGTH] = (uint8_t)P384; - memcpy(data + ZT_ADDRESS_LENGTH + 1,&_pub,ZT_IDENTITY_P384_COMPOUND_PUBLIC_KEY_SIZE); - if ((includePrivate)&&(_hasPrivate)) { data[ZT_ADDRESS_LENGTH + 1 + ZT_IDENTITY_P384_COMPOUND_PUBLIC_KEY_SIZE] = ZT_IDENTITY_P384_COMPOUND_PRIVATE_KEY_SIZE; memcpy(data + ZT_ADDRESS_LENGTH + 1 + ZT_IDENTITY_P384_COMPOUND_PUBLIC_KEY_SIZE + 1,&_priv,ZT_IDENTITY_P384_COMPOUND_PRIVATE_KEY_SIZE); @@ -451,6 +447,7 @@ int Identity::unmarshal(const uint8_t *data,const int len) noexcept if (len < (ZT_ADDRESS_LENGTH + 1)) return -1; + _address.setTo(data); unsigned int privlen; switch((_type = (Type)data[ZT_ADDRESS_LENGTH])) { @@ -460,21 +457,17 @@ 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); + _computeHash(); privlen = data[ZT_ADDRESS_LENGTH + 1 + ZT_C25519_PUBLIC_KEY_LEN]; if (privlen == ZT_C25519_PRIVATE_KEY_LEN) { if (len < (ZT_ADDRESS_LENGTH + 1 + ZT_C25519_PUBLIC_KEY_LEN + 1 + ZT_C25519_PRIVATE_KEY_LEN)) return -1; - _hasPrivate = true; memcpy(_priv.c25519,data + ZT_ADDRESS_LENGTH + 1 + ZT_C25519_PUBLIC_KEY_LEN + 1,ZT_C25519_PRIVATE_KEY_LEN); - - _computeHash(); return ZT_ADDRESS_LENGTH + 1 + ZT_C25519_PUBLIC_KEY_LEN + 1 + ZT_C25519_PRIVATE_KEY_LEN; } else if (privlen == 0) { _hasPrivate = false; - - _computeHash(); return ZT_ADDRESS_LENGTH + 1 + ZT_C25519_PUBLIC_KEY_LEN + 1; } break; @@ -484,21 +477,19 @@ 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 + return -1; privlen = data[ZT_ADDRESS_LENGTH + 1 + ZT_IDENTITY_P384_COMPOUND_PUBLIC_KEY_SIZE]; if (privlen == ZT_IDENTITY_P384_COMPOUND_PRIVATE_KEY_SIZE) { if (len < (ZT_ADDRESS_LENGTH + 1 + ZT_IDENTITY_P384_COMPOUND_PUBLIC_KEY_SIZE + 1 + ZT_IDENTITY_P384_COMPOUND_PRIVATE_KEY_SIZE)) return -1; - _hasPrivate = true; memcpy(&_priv,data + ZT_ADDRESS_LENGTH + 1 + ZT_IDENTITY_P384_COMPOUND_PUBLIC_KEY_SIZE + 1,ZT_IDENTITY_P384_COMPOUND_PRIVATE_KEY_SIZE); - - _computeHash(); return ZT_ADDRESS_LENGTH + 1 + ZT_IDENTITY_P384_COMPOUND_PUBLIC_KEY_SIZE + 1 + ZT_IDENTITY_P384_COMPOUND_PRIVATE_KEY_SIZE; } else if (privlen == 0) { _hasPrivate = false; - - _computeHash(); return ZT_ADDRESS_LENGTH + 1 + ZT_IDENTITY_P384_COMPOUND_PUBLIC_KEY_SIZE + 1; } break; diff --git a/node/Identity.hpp b/node/Identity.hpp index d0f1d5fac..edf7dce8c 100644 --- a/node/Identity.hpp +++ b/node/Identity.hpp @@ -203,10 +203,7 @@ public: ZT_ALWAYS_INLINE unsigned long hashCode() const noexcept { return _fp.hashCode(); } - ZT_ALWAYS_INLINE bool operator==(const Identity &id) const noexcept - { - return ((_address == id._address)&&(_type == id._type)&&(memcmp(_fp.data(),id._fp.data(),ZT_SHA384_DIGEST_LEN) == 0)); - } + ZT_ALWAYS_INLINE bool operator==(const Identity &id) const noexcept { return ((_address == id._address)&&(_fp == id._fp)); } ZT_ALWAYS_INLINE bool operator!=(const Identity &id) const noexcept { return !(*this == id); } ZT_ALWAYS_INLINE bool operator<(const Identity &id) const noexcept { @@ -216,7 +213,7 @@ public: if ((int)_type < (int)id._type) return true; if (_type == id._type) - return memcmp(_fp.data(),id._fp.data(),ZT_SHA384_DIGEST_LEN) < 0; + return _fp < id._fp; } return false; } diff --git a/node/Tests.cpp b/node/Tests.cpp index acc221ed2..3e3186255 100644 --- a/node/Tests.cpp +++ b/node/Tests.cpp @@ -590,6 +590,24 @@ extern "C" const char *ZTT_general() ZT_T_PRINTF("FAILED (validation of known-good identity failed)" ZT_EOL_S); return "Identity test failed: validation of known-good identity"; } + + uint8_t idm[ZT_IDENTITY_MARSHAL_SIZE_MAX]; + int ms = id.marshal(idm,true); + if (ms <= 0) { + ZT_T_PRINTF("FAILED (v0 marshal)" ZT_EOL_S); + return "Identity test failed: v0 marshal"; + } + ZT_T_PRINTF("(marshal: %d bytes) ",ms); + Identity id2; + if (id2.unmarshal(idm,ms) <= 0) { + ZT_T_PRINTF("FAILED (v0 unmarshal)" ZT_EOL_S); + return "Identity test failed: v0 unmarshal"; + } + if (id != id2) { + ZT_T_PRINTF("FAILED (v0 unmarshal !=)" ZT_EOL_S); + return "Identity test failed: v0 unmarshal !="; + } + if (!id.fromString(IDENTITY_V0_KNOWN_BAD_0)) { ZT_T_PRINTF("FAILED (error parsing test identity #2)" ZT_EOL_S); return "Identity test failed: parse error"; @@ -614,6 +632,22 @@ extern "C" const char *ZTT_general() ZT_T_PRINTF("FAILED (validation of known-good identity failed)" ZT_EOL_S); return "Identity test failed: validation of known-good identity"; } + + ms = id.marshal(idm,true); + if (ms <= 0) { + ZT_T_PRINTF("FAILED (v1 marshal)" ZT_EOL_S); + return "Identity test failed: v1 marshal"; + } + ZT_T_PRINTF("(marshal: %d bytes) ",ms); + if (id2.unmarshal(idm,ms) <= 0) { + ZT_T_PRINTF("FAILED (v1 unmarshal)" ZT_EOL_S); + return "Identity test failed: v1 unmarshal"; + } + if (id != id2) { + ZT_T_PRINTF("FAILED (v1 unmarshal !=)" ZT_EOL_S); + return "Identity test failed: v1 unmarshal !="; + } + if (!id.fromString(IDENTITY_V1_KNOWN_BAD_0)) { ZT_T_PRINTF("FAILED (error parsing test identity #2)" ZT_EOL_S); return "Identity test failed: parse error";