Browse Source

Add tests for identity marshal/unmarshal and fix an issue found.

Adam Ierymenko 5 years ago
parent
commit
6262374205
4 changed files with 49 additions and 25 deletions
  1. 8 6
      node/Fingerprint.hpp
  2. 5 14
      node/Identity.cpp
  3. 2 5
      node/Identity.hpp
  4. 34 0
      node/Tests.cpp

+ 8 - 6
node/Fingerprint.hpp

@@ -17,6 +17,8 @@
 #include "Constants.hpp"
 #include "TriviallyCopyable.hpp"
 
+#include <algorithm>
+
 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)];

+ 5 - 14
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;

+ 2 - 5
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;
 	}

+ 34 - 0
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";