Преглед на файлове

Flesh out tests, fix a signing bug.

Adam Ierymenko преди 5 години
родител
ревизия
89c27c112a
променени са 5 файла, в които са добавени 109 реда и са изтрити 68 реда
  1. 15 14
      node/AES.cpp
  2. 6 5
      node/Identity.cpp
  3. 3 2
      node/Locator.cpp
  4. 1 0
      node/Locator.hpp
  5. 84 47
      node/Tests.cpp

+ 15 - 14
node/AES.cpp

@@ -647,6 +647,7 @@ static void p_aesCtrInner128(unsigned int &len, uint64_t &c0, uint64_t &c1, cons
 	const __m128i k12 = k[12];
 	const __m128i k13 = k[13];
 	const __m128i k14 = k[14];
+	_mm_prefetch(in, _MM_HINT_T0);
 	do {
 		__m128i d0 = _mm_set_epi64x((long long) Utils::hton(c1), (long long) c0);
 		__m128i d1 = _mm_set_epi64x((long long) Utils::hton(c1 + 1ULL), (long long) c0);
@@ -697,36 +698,36 @@ static void p_aesCtrInner128(unsigned int &len, uint64_t &c0, uint64_t &c1, cons
 		d1 = _mm_aesenc_si128(d1, k10);
 		d2 = _mm_aesenc_si128(d2, k10);
 		d3 = _mm_aesenc_si128(d3, k10);
-		__m128i p0 = _mm_loadu_si128(reinterpret_cast<const __m128i *>(in));
 		d0 = _mm_aesenc_si128(d0, k11);
 		d1 = _mm_aesenc_si128(d1, k11);
 		d2 = _mm_aesenc_si128(d2, k11);
 		d3 = _mm_aesenc_si128(d3, k11);
-		__m128i p1 = _mm_loadu_si128(reinterpret_cast<const __m128i *>(in + 16));
 		d0 = _mm_aesenc_si128(d0, k12);
 		d1 = _mm_aesenc_si128(d1, k12);
 		d2 = _mm_aesenc_si128(d2, k12);
 		d3 = _mm_aesenc_si128(d3, k12);
-		__m128i p2 = _mm_loadu_si128(reinterpret_cast<const __m128i *>(in + 32));
 		d0 = _mm_aesenc_si128(d0, k13);
 		d1 = _mm_aesenc_si128(d1, k13);
 		d2 = _mm_aesenc_si128(d2, k13);
 		d3 = _mm_aesenc_si128(d3, k13);
-		__m128i p3 = _mm_loadu_si128(reinterpret_cast<const __m128i *>(in + 48));
-		in += 64;
-		_mm_prefetch(in, _MM_HINT_T0);
 		d0 = _mm_aesenclast_si128(d0, k14);
 		d1 = _mm_aesenclast_si128(d1, k14);
 		d2 = _mm_aesenclast_si128(d2, k14);
 		d3 = _mm_aesenclast_si128(d3, k14);
-		p0 = _mm_xor_si128(d0, p0);
-		p1 = _mm_xor_si128(d1, p1);
-		p2 = _mm_xor_si128(d2, p2);
-		p3 = _mm_xor_si128(d3, p3);
-		_mm_storeu_si128(reinterpret_cast<__m128i *>(out), p0);
-		_mm_storeu_si128(reinterpret_cast<__m128i *>(out + 16), p1);
-		_mm_storeu_si128(reinterpret_cast<__m128i *>(out + 32), p2);
-		_mm_storeu_si128(reinterpret_cast<__m128i *>(out + 48), p3);
+		__m128i p0 = _mm_loadu_si128(reinterpret_cast<const __m128i *>(in));
+		__m128i p1 = _mm_loadu_si128(reinterpret_cast<const __m128i *>(in + 16));
+		__m128i p2 = _mm_loadu_si128(reinterpret_cast<const __m128i *>(in + 32));
+		__m128i p3 = _mm_loadu_si128(reinterpret_cast<const __m128i *>(in + 48));
+		d0 = _mm_xor_si128(d0, p0);
+		d1 = _mm_xor_si128(d1, p1);
+		d2 = _mm_xor_si128(d2, p2);
+		d3 = _mm_xor_si128(d3, p3);
+		_mm_storeu_si128(reinterpret_cast<__m128i *>(out), d0);
+		_mm_storeu_si128(reinterpret_cast<__m128i *>(out + 16), d1);
+		_mm_storeu_si128(reinterpret_cast<__m128i *>(out + 32), d2);
+		_mm_storeu_si128(reinterpret_cast<__m128i *>(out + 48), d3);
+		in += 64;
+		_mm_prefetch(in, _MM_HINT_T0);
 		out += 64;
 		len -= 64;
 	} while (len >= 64);

+ 6 - 5
node/Identity.cpp

@@ -247,9 +247,10 @@ unsigned int Identity::sign(const void *data, unsigned int len, void *sig, unsig
 			case P384:
 				if (siglen >= ZT_ECC384_SIGNATURE_SIZE) {
 					// SECURITY: signatures also include the public keys to further enforce their coupling.
-					uint8_t h[48];
-					SHA384(h, data, len, m_pub, sizeof(m_pub));
-					ECC384ECDSASign(m_priv + 1 + ZT_C25519_COMBINED_PUBLIC_KEY_SIZE, h, (uint8_t *) sig);
+					static_assert(ZT_ECC384_SIGNATURE_HASH_SIZE == ZT_SHA384_DIGEST_SIZE, "weird!");
+					uint8_t h[ZT_ECC384_SIGNATURE_HASH_SIZE];
+					SHA384(h, data, len, m_pub, ZT_IDENTITY_P384_COMPOUND_PUBLIC_KEY_SIZE);
+					ECC384ECDSASign(m_priv + ZT_C25519_COMBINED_PRIVATE_KEY_SIZE, h, (uint8_t *) sig);
 					return ZT_ECC384_SIGNATURE_SIZE;
 				}
 		}
@@ -264,8 +265,8 @@ bool Identity::verify(const void *data, unsigned int len, const void *sig, unsig
 			return C25519::verify(m_pub, data, len, sig, siglen);
 		case P384:
 			if (siglen == ZT_ECC384_SIGNATURE_SIZE) {
-				uint8_t h[48];
-				SHA384(h, data, len, m_pub, sizeof(m_pub));
+				uint8_t h[ZT_ECC384_SIGNATURE_HASH_SIZE];
+				SHA384(h, data, len, m_pub, ZT_IDENTITY_P384_COMPOUND_PUBLIC_KEY_SIZE);
 				return ECC384ECDSAVerify(m_pub + 1 + ZT_C25519_COMBINED_PUBLIC_KEY_SIZE, h, (const uint8_t *) sig);
 			}
 			break;

+ 3 - 2
node/Locator.cpp

@@ -62,7 +62,7 @@ char *Locator::toString(char s[ZT_LOCATOR_STRING_SIZE_MAX]) const noexcept
 	static_assert(ZT_LOCATOR_STRING_SIZE_MAX > ((((ZT_LOCATOR_MARSHAL_SIZE_MAX / 5) + 1) * 8) + ZT_ADDRESS_LENGTH_HEX + 1), "overflow");
 	uint8_t bin[ZT_LOCATOR_MARSHAL_SIZE_MAX];
 	Address(m_signer.address).toString(s);
-	s[ZT_ADDRESS_LENGTH_HEX] = '@';
+	s[ZT_ADDRESS_LENGTH_HEX] = '-';
 	Utils::b32e(bin, marshal(bin, false), s + (ZT_ADDRESS_LENGTH_HEX + 1), ZT_LOCATOR_STRING_SIZE_MAX - (ZT_ADDRESS_LENGTH_HEX + 1));
 	return s;
 }
@@ -126,7 +126,8 @@ int Locator::unmarshal(const uint8_t *data, const int len) noexcept
 
 	if (unlikely(p + 2) > len)
 		return -1;
-	unsigned int endpointCount = Utils::loadBigEndian<uint16_t>(data + 8);
+	unsigned int endpointCount = Utils::loadBigEndian<uint16_t>(data + p);
+	p += 2;
 	if (unlikely(endpointCount > ZT_LOCATOR_MAX_ENDPOINTS))
 		return -1;
 	m_endpoints.resize(endpointCount);

+ 1 - 0
node/Locator.hpp

@@ -113,6 +113,7 @@ public:
 	 * @return Pointer to buffer
 	 */
 	char *toString(char s[ZT_LOCATOR_STRING_SIZE_MAX]) const noexcept;
+	ZT_INLINE String toString() const { char tmp[ZT_LOCATOR_STRING_SIZE_MAX]; return String(toString(tmp)); }
 
 	/**
 	 * Decode a string format locator

+ 84 - 47
node/Tests.cpp

@@ -13,7 +13,7 @@
 
 #include "Tests.h"
 
-#define ZT_ENABLE_TESTS
+//#define ZT_ENABLE_TESTS
 #ifdef ZT_ENABLE_TESTS
 
 #include "Constants.hpp"
@@ -40,6 +40,8 @@
 #include "Defragmenter.hpp"
 #include "Fingerprint.hpp"
 #include "Containers.hpp"
+#include "Endpoint.hpp"
+#include "Locator.hpp"
 
 #ifdef __UNIX_LIKE__
 #include <unistd.h>
@@ -298,6 +300,14 @@ extern "C" const char *ZTT_general()
 				ZT_T_PRINTF("FAILED (hton/ntoh)" ZT_EOL_S);
 				return "Utils::hton() or ntoh() broken";
 			}
+			if (ZT_CONST_TO_BE_UINT64(0x0102030405060708ULL) != Utils::hton((uint64_t)0x0102030405060708ULL)) {
+				ZT_T_PRINTF("ZT_CONST_TO_BE_UINT64 macro is not working" ZT_EOL_S);
+				return "ZT_CONST_TO_BE_UINT64 macro is not working";
+			}
+			if (ZT_CONST_TO_BE_UINT16(0x0102) != Utils::hton((uint16_t)0x0102)) {
+				ZT_T_PRINTF("ZT_CONST_TO_BE_UINT16 macro is not working" ZT_EOL_S);
+				return "ZT_CONST_TO_BE_UINT16 macro is not working";
+			}
 #if __BYTE_ORDER == __LITTLE_ENDIAN
 			if (Utils::loadAsIsEndian<uint64_t>(&a) != 0x0102030405060708ULL) {
 				ZT_T_PRINTF("FAILED (loadAsIsEndian)" ZT_EOL_S);
@@ -427,44 +437,6 @@ extern "C" const char *ZTT_general()
 			ZT_T_PRINTF("OK" ZT_EOL_S);
 		}
 
-		{
-			ZT_T_PRINTF("[general] Testing Map... ");
-			Map<uint64_t,uint64_t> tm;
-			for(uint64_t i=0;i<100000;++i)
-				tm.set(i,i);
-			for(uint64_t i=0;i<100000;++i) {
-				uint64_t *v = tm.get(i);
-				if ((!v)||(*v != i)) {
-					ZT_T_PRINTF("FAILED (get() failed)" ZT_EOL_S);
-					return "Map::get() failed";
-				}
-			}
-			for(Map<uint64_t,uint64_t>::iterator i(tm.begin());i!=tm.end();) { // NOLINT(hicpp-use-auto,modernize-use-auto)
-				if ((i->first & 1U) == 0)
-					tm.erase(i++);
-				else ++i;
-			}
-			if (tm.size() != 50000) {
-				ZT_T_PRINTF("FAILED (erase() failed (1))" ZT_EOL_S);
-				return "Map::erase() failed (1)";
-			}
-			for(uint64_t i=0;i<100000;++i) {
-				uint64_t *v = tm.get(i);
-				if ((i & 1U) == 0) {
-					if (v) {
-						ZT_T_PRINTF("FAILED (erase() failed (2))" ZT_EOL_S);
-						return "Map::erase() failed (2)";
-					}
-				} else {
-					if (!v) {
-						ZT_T_PRINTF("FAILED (erase() failed (3))" ZT_EOL_S);
-						return "Map::erase() failed (3)";
-					}
-				}
-			}
-			ZT_T_PRINTF("OK" ZT_EOL_S);
-		}
-
 		{
 			ZT_T_PRINTF("[general] Testing Buf memory pool (basic sanity check)... ");
 			try {
@@ -497,8 +469,6 @@ extern "C" const char *ZTT_general()
 		}
 
 		{
-			// This doesn't check behavior when fragments are invalid or input is totally insane.
-			// That's done during fuzzing.
 			ZT_T_PRINTF("[general] Testing Defragmenter... ");
 			Defragmenter<> defrag;
 
@@ -586,11 +556,7 @@ extern "C" const char *ZTT_general()
 			ZT_T_PRINTF("OK (cache remaining: %u)" ZT_EOL_S,defrag.cacheSize());
 		}
 
-		{
-			ZT_T_PRINTF("[general] Testing Endpoint... ");
-			ZT_T_PRINTF("OK" ZT_EOL_S);
-		}
-
+		Identity v0id,v1id;
 		{
 			char tmp[2048];
 
@@ -605,6 +571,23 @@ 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";
 			}
+			v0id = id;
+
+			Utils::getSecureRandom(tmp,sizeof(tmp));
+			for(int k=0;k<32;++k) {
+				uint8_t sig[ZT_SIGNATURE_BUFFER_SIZE];
+				++tmp[0];
+				unsigned int sl = id.sign(tmp,sizeof(tmp),sig,sizeof(sig));
+				if (!id.verify(tmp,sizeof(tmp),sig,sl)) {
+					ZT_T_PRINTF("FAILED (sign/verify)" ZT_EOL_S);
+					return "Identity test failed: sign/verify with type 0";
+				}
+				++tmp[1];
+				if (id.verify(tmp,sizeof(tmp),sig,sl)) {
+					ZT_T_PRINTF("FAILED (sign/verify (2))" ZT_EOL_S);
+					return "Identity test failed: sign/verify with type 0";
+				}
+			}
 
 			uint8_t idm[ZT_IDENTITY_MARSHAL_SIZE_MAX];
 			int ms = id.marshal(idm,true);
@@ -644,6 +627,7 @@ extern "C" const char *ZTT_general()
 			}
 			ZT_T_PRINTF("OK" ZT_EOL_S);
 
+			/*
 			{
 				ZT_T_PRINTF("[general] Generated V1 identity: ");
 				id.generate(Identity::P384);
@@ -652,6 +636,7 @@ extern "C" const char *ZTT_general()
 				id.fingerprint().toString(tmp);
 				ZT_T_PRINTF("[general] Identity fingerprint: %s" ZT_EOL_S,tmp);
 			}
+			*/
 
 			ZT_T_PRINTF("[general] Testing Identity type 1 (P384)... ");
 
@@ -663,6 +648,23 @@ 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";
 			}
+			v1id = id;
+
+			Utils::getSecureRandom(tmp,sizeof(tmp));
+			for(int k=0;k<32;++k) {
+				uint8_t sig[ZT_SIGNATURE_BUFFER_SIZE];
+				++tmp[0];
+				unsigned int sl = id.sign(tmp,sizeof(tmp),sig,sizeof(sig));
+				if (!id.verify(tmp,sizeof(tmp),sig,sl)) {
+					ZT_T_PRINTF("FAILED (sign/verify)" ZT_EOL_S);
+					return "Identity test failed: sign/verify with type 1";
+				}
+				++tmp[1];
+				if (id.verify(tmp,sizeof(tmp),sig,sl)) {
+					ZT_T_PRINTF("FAILED (sign/verify (2))" ZT_EOL_S);
+					return "Identity test failed: sign/verify with type 1";
+				}
+			}
 
 			ms = id.marshal(idm,true);
 			if (ms <= 0) {
@@ -698,6 +700,28 @@ extern "C" const char *ZTT_general()
 
 			ZT_T_PRINTF("OK" ZT_EOL_S);
 		}
+
+		{
+			ZT_T_PRINTF("[general] Testing Endpoint and Locator... ");
+			Endpoint ep0(InetAddress::LO4);
+			Endpoint ep1(InetAddress::LO6);
+			Locator loc;
+			loc.add(ep0);
+			loc.add(ep1);
+			loc.sign(now(),v1id);
+			String locStr(loc.toString());
+			//ZT_T_PRINTF("%s %s %s ",locStr.c_str(),loc.endpoints()[0].toString().c_str(),loc.endpoints()[1].toString().c_str());
+			Locator loc2;
+			if ((!loc2.fromString(locStr.c_str())) || (loc2.toString() != locStr)) {
+				ZT_T_PRINTF("FAILED (fromString)" ZT_EOL_S);
+				return "FAILED (Locator toString/fromString)";
+			}
+			if (!loc2.verify(v1id)) {
+				ZT_T_PRINTF("FAILED (verify)" ZT_EOL_S);
+				return "FAILED (Locator verify)";
+			}
+			ZT_T_PRINTF("OK" ZT_EOL_S);
+		}
 	} catch (std::exception &e) {
 		ZT_T_PRINTF(ZT_EOL_S "[general] Unexpected exception: %s" ZT_EOL_S,e.what());
 		return e.what();
@@ -758,7 +782,7 @@ extern "C" const char *ZTT_crypto()
 
 		{
 			uint8_t key[ZT_ECC384_SHARED_SECRET_SIZE];
-			ZT_T_PRINTF("[crypto] Testing ECC384 (NIST P-384)... ");
+			ZT_T_PRINTF("[crypto] Testing ECC384 (NIST P-384 ECDH/ECDSA)... ");
 			ECC384ECDH(ECC384_TV0_PUBLIC,ECC384_TV0_PRIVATE,key);
 			if (memcmp(key,ECC384_TV0_DH_SELF_AGREE,ZT_ECC384_SHARED_SECRET_SIZE) != 0) {
 				ZT_T_PRINTF("FAILED (test vector 0, self-agree)" ZT_EOL_S);
@@ -768,6 +792,19 @@ extern "C" const char *ZTT_crypto()
 				ZT_T_PRINTF("FAILED (test vector 0, signature check)" ZT_EOL_S);
 				return "ECC384 test vector 0 signature check failed";
 			}
+			uint8_t msg[ZT_ECC384_SIGNATURE_HASH_SIZE];
+			Utils::getSecureRandom(msg,sizeof(msg));
+			uint8_t sig[ZT_ECC384_SIGNATURE_SIZE];
+			ECC384ECDSASign(ECC384_TV0_PRIVATE, msg, sig);
+			if (!ECC384ECDSAVerify(ECC384_TV0_PUBLIC, msg, sig)) {
+				ZT_T_PRINTF("FAILED (test vector 0, sign/verify)" ZT_EOL_S);
+				return "ECC384 test vector 0 sign/verify failed";
+			}
+			++msg[0];
+			if (ECC384ECDSAVerify(ECC384_TV0_PUBLIC, msg, sig)) {
+				ZT_T_PRINTF("FAILED (test vector 0, sign/verify (2))" ZT_EOL_S);
+				return "ECC384 test vector 0 sign/verify failed (2)";
+			}
 			ZT_T_PRINTF("OK" ZT_EOL_S);
 		}