Flesh out tests, fix a signing bug.

This commit is contained in:
Adam Ierymenko 2020-05-30 19:08:45 -07:00
parent 3621fe8897
commit 89c27c112a
No known key found for this signature in database
GPG key ID: C8877CF2D7A5D7F3
5 changed files with 109 additions and 68 deletions

View file

@ -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);

View file

@ -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;

View file

@ -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);

View file

@ -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

View file

@ -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);
}