mirror of
https://github.com/zerotier/ZeroTierOne.git
synced 2025-04-21 14:36:55 +02:00
Flesh out tests, fix a signing bug.
This commit is contained in:
parent
3621fe8897
commit
89c27c112a
5 changed files with 109 additions and 68 deletions
29
node/AES.cpp
29
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);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
|
131
node/Tests.cpp
131
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);
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue