From 3f4809457f73bbd9ba4b0857f5615077c33f996b Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Tue, 30 Jun 2020 20:31:41 -0700 Subject: [PATCH] A bunch of compile fixes, and an edge case fix in Dictionary. --- core/AES.cpp | 29 +++++++--- core/Certificate.cpp | 109 +++++++++++++++++++++++++------------ core/Certificate.hpp | 36 ++++++++----- core/Containers.hpp | 69 ++++++++---------------- core/Dictionary.cpp | 126 ++++++++++++++++++++++--------------------- core/Dictionary.hpp | 28 +++++----- core/Identity.cpp | 61 ++++++++++++--------- core/OS.hpp | 1 + core/Tests.cpp | 64 +++++++++++----------- core/Utils.hpp | 73 ------------------------- 10 files changed, 293 insertions(+), 303 deletions(-) diff --git a/core/AES.cpp b/core/AES.cpp index 7f93c57ce..3ea81e4fa 100644 --- a/core/AES.cpp +++ b/core/AES.cpp @@ -512,7 +512,9 @@ void AES::GMAC::finish(uint8_t tag[16]) noexcept #ifdef ZT_AES_AESNI -#if !defined(__WINDOWS__) +// Disable VAES stuff on compilers too old to compile these intrinsics, +// and MinGW64 also seems not to support them so disable on Windows. +#if !defined(__WINDOWS__) && ((__GNUC__ >= 8) || (__clang_major__ >= 7)) #define ZT_AES_VAES512 static @@ -793,19 +795,34 @@ void AES::CTR::crypt(const void *const input, unsigned int len) noexcept _len = totalLen + len; if (likely(len >= 64)) { + + // Compiler supports both AVX256 VAES and AVX512 VAES #if defined(ZT_AES_VAES512) && defined(ZT_AES_VAES256) if (Utils::CPUID.vaes) { - if ((!Utils::CPUID.avx512f) || ((len < 1024))) { + if ((!Utils::CPUID.avx512f) || (len < 512)) { p_aesCtrInnerVAES256(len, c0, c1, in, out, k); } else { p_aesCtrInnerVAES512(len, c0, c1, in, out, k); } } else { -#endif p_aesCtrInner128(len, c0, c1, in, out, k); -#if defined(ZT_AES_VAES512) && defined(ZT_AES_VAES256) } #endif + + // Compiler only supports AVX256 VAES +#if !defined(ZT_AES_VAES512) && defined(ZT_AES_VAES256) + if (Utils::CPUID.vaes) { + p_aesCtrInnerVAES256(len, c0, c1, in, out, k); + } else { + p_aesCtrInner128(len, c0, c1, in, out, k); + } +#endif + + // Compiler only support conventional AES-NI +#if !defined(ZT_AES_VAES512) && !defined(ZT_AES_VAES256) + p_aesCtrInner128(len, c0, c1, in, out, k); +#endif + } while (len >= 16) { @@ -1194,7 +1211,7 @@ void AES::_decryptSW(const uint8_t in[16], uint8_t out[16]) const noexcept #ifdef ZT_AES_AESNI -static ZT_INLINE __m128i _init256_1_aesni(__m128i a, __m128i b) noexcept +static __m128i _init256_1_aesni(__m128i a, __m128i b) noexcept { __m128i x, y; b = _mm_shuffle_epi32(b, 0xff); @@ -1208,7 +1225,7 @@ static ZT_INLINE __m128i _init256_1_aesni(__m128i a, __m128i b) noexcept return x; } -static ZT_INLINE __m128i _init256_2_aesni(__m128i a, __m128i b) noexcept +static __m128i _init256_2_aesni(__m128i a, __m128i b) noexcept { __m128i x, y, z; y = _mm_aeskeygenassist_si128(a, 0x00); diff --git a/core/Certificate.cpp b/core/Certificate.cpp index cb12d3d1e..12286c11c 100644 --- a/core/Certificate.cpp +++ b/core/Certificate.cpp @@ -17,35 +17,30 @@ namespace ZeroTier { -void Certificate::clear() +Certificate::Certificate() noexcept { - Utils::zero< sizeof(ZT_Certificate) >((ZT_Certificate *)this); - - m_identities.clear(); - m_locators.clear(); - m_strings.clear(); - m_serials.clear(); - - m_subjectIdentities.clear(); - m_subjectNetworks.clear(); - m_updateUrls.clear(); - m_subjectCertificates.clear(); - m_extendedAttributes.clear(); - m_subjectUniqueId.clear(); - m_subjectUniqueIdProofSignature.clear(); - m_signature.clear(); + ZT_Certificate *const sup = this; + Utils::zero< sizeof(ZT_Certificate) >(sup); } -Certificate &Certificate::operator=(const ZT_Certificate &apiCert) +Certificate::Certificate(const ZT_Certificate &apiCert) { - clear(); - Utils::copy< sizeof(ZT_Certificate) >((ZT_Certificate *)this, &apiCert); - return *this; + ZT_Certificate *const sup = this; + Utils::copy< sizeof(ZT_Certificate) >(sup, &apiCert); } -Certificate &Certificate::operator=(const Certificate &cert) +Certificate::Certificate(const Certificate &cert) +{ *this = cert; } + +Certificate::~Certificate() +{} + +Certificate &Certificate::operator=(const ZT_Certificate &cert) { - *this = *((const ZT_Certificate *)(&cert)); + m_clear(); + + ZT_Certificate *const sup = this; + Utils::copy< sizeof(ZT_Certificate) >(sup, &cert); // Zero these since we must explicitly attach all the objects from // the other certificate to copy them into our containers. @@ -57,9 +52,15 @@ Certificate &Certificate::operator=(const Certificate &cert) this->subject.certificateCount = 0; this->subject.updateUrls = nullptr; this->subject.updateUrlCount = 0; + this->subject.uniqueId = nullptr; + this->subject.uniqueIdProofSignature = nullptr; + this->subject.uniqueIdSize = 0; + this->subject.uniqueIdProofSignatureSize = 0; this->extendedAttributes = nullptr; this->extendedAttributesSize = 0; this->issuer = nullptr; + this->signature = nullptr; + this->signatureSize = 0; for (unsigned int i = 0; i < cert.subject.identityCount; ++i) { if (cert.subject.identities[i].identity) { @@ -86,15 +87,32 @@ Certificate &Certificate::operator=(const Certificate &cert) } } + if ((cert.subject.uniqueId) && (cert.subject.uniqueIdSize > 0)) { + m_subjectUniqueId.assign(cert.subject.uniqueId, cert.subject.uniqueId + cert.subject.uniqueIdSize); + this->subject.uniqueId = m_subjectUniqueId.data(); + this->subject.uniqueIdSize = (unsigned int)m_subjectUniqueId.size(); + } + if ((cert.subject.uniqueIdProofSignature) && (cert.subject.uniqueIdProofSignatureSize > 0)) { + m_subjectUniqueIdProofSignature.assign(cert.subject.uniqueIdProofSignature, cert.subject.uniqueIdProofSignature + cert.subject.uniqueIdProofSignatureSize); + this->subject.uniqueIdProofSignature = m_subjectUniqueIdProofSignature.data(); + this->subject.uniqueIdProofSignatureSize = (unsigned int)m_subjectUniqueIdProofSignature.size(); + } + + if (cert.issuer) { + m_identities.push_back(*reinterpret_cast(cert.issuer)); + this->issuer = &(m_identities.back()); + } + if ((cert.extendedAttributes) && (cert.extendedAttributesSize > 0)) { m_extendedAttributes.assign(cert.extendedAttributes, cert.extendedAttributes + cert.extendedAttributesSize); this->extendedAttributes = m_extendedAttributes.data(); this->extendedAttributesSize = (unsigned int)m_extendedAttributes.size(); } - if (cert.issuer) { - m_identities.push_back(*reinterpret_cast(cert.issuer)); - this->issuer = &(m_identities.back()); + if ((cert.signature) && (cert.signatureSize > 0)) { + m_signature.assign(cert.signature, cert.signature + cert.signatureSize); + this->signature = m_signature.data(); + this->signatureSize = (unsigned int)m_signature.size(); } return *this; @@ -215,7 +233,10 @@ Vector< uint8_t > Certificate::encode(const bool omitSignature) const if (this->issuerName.host[0]) d.add("iN.h", this->issuerName.host); - if ((!omitSignature) && (this->signatureSize > 0) && (this->signatureSize <= sizeof(this->signature))) + if ((this->extendedAttributes) && (this->extendedAttributesSize > 0)) + d["x"].assign(this->extendedAttributes, this->extendedAttributes + this->extendedAttributesSize); + + if ((!omitSignature) && (this->signatureSize > 0) && (this->signature)) d["si"].assign(this->signature, this->signature + this->signatureSize); d.encode(enc); @@ -226,7 +247,7 @@ bool Certificate::decode(const Vector< uint8_t > &data) { char tmp[256], tmp2[ZT_CERTIFICATE_MAX_STRING_LENGTH + 1]; - clear(); + m_clear(); Dictionary d; if (!d.decode(data.data(), (unsigned int)data.size())) @@ -238,12 +259,6 @@ bool Certificate::decode(const Vector< uint8_t > &data) this->validity[1] = (int64_t)d.getUI("v#1"); this->maxPathLength = (unsigned int)d.getUI("mP"); - m_extendedAttributes = d["x"]; - if (!m_extendedAttributes.empty()) { - this->extendedAttributes = m_extendedAttributes.data(); - this->extendedAttributesSize = (unsigned int)m_extendedAttributes.size(); - } - this->subject.timestamp = (int64_t)d.getUI("s.t"); unsigned int cnt = (unsigned int)d.getUI("s.i$"); @@ -343,6 +358,12 @@ bool Certificate::decode(const Vector< uint8_t > &data) else return false; } + m_extendedAttributes = d["x"]; + if (!m_extendedAttributes.empty()) { + this->extendedAttributes = m_extendedAttributes.data(); + this->extendedAttributesSize = (unsigned int)m_extendedAttributes.size(); + } + m_signature = d["si"]; if (!m_signature.empty()) { this->signature = m_signature.data(); @@ -453,9 +474,29 @@ bool Certificate::setSubjectUniqueId(const uint8_t uniqueId[ZT_CERTIFICATE_UNIQU return true; } +void Certificate::m_clear() +{ + ZT_Certificate *const sup = this; + Utils::zero< sizeof(ZT_Certificate) >(sup); + + m_identities.clear(); + m_locators.clear(); + m_strings.clear(); + m_serials.clear(); + + m_subjectIdentities.clear(); + m_subjectNetworks.clear(); + m_updateUrls.clear(); + m_subjectCertificates.clear(); + m_extendedAttributes.clear(); + m_subjectUniqueId.clear(); + m_subjectUniqueIdProofSignature.clear(); + m_signature.clear(); +} + void Certificate::m_encodeSubject(const ZT_Certificate_Subject &s, Dictionary &d, bool omitUniqueIdProofSignature) { - char tmp[256]; + char tmp[64]; d.add("s.t", (uint64_t)s.timestamp); diff --git a/core/Certificate.hpp b/core/Certificate.hpp index f3d538149..2fc71de80 100644 --- a/core/Certificate.hpp +++ b/core/Certificate.hpp @@ -48,25 +48,28 @@ namespace ZeroTier { class Certificate : public ZT_Certificate { friend class SharedPtr< Certificate >; + friend class SharedPtr< const Certificate >; public: - ZT_INLINE Certificate() noexcept - { this->clear(); } + Certificate() noexcept; - ZT_INLINE Certificate(const ZT_Certificate &apiCert) - { *this = apiCert; } + Certificate(const ZT_Certificate &apiCert); - ZT_INLINE Certificate(const Certificate &cert) - { *this = cert; } + Certificate(const Certificate &cert); - /** - * Zero all fields and release all extra memory - */ - void clear(); + ~Certificate(); - Certificate &operator=(const ZT_Certificate &apiCert); - Certificate &operator=(const Certificate &cert); + Certificate &operator=(const ZT_Certificate &cert); + + ZT_INLINE Certificate &operator=(const Certificate &cert) + { + if (likely(&cert != this)) { + const ZT_Certificate *const sup = &cert; + *this = *sup; + } + return *this; + } /** * Add a subject node/identity without a locator @@ -186,18 +189,25 @@ public: ZT_INLINE bool operator==(const ZT_Certificate &c) const noexcept { return memcmp(this->serialNo, c.serialNo, ZT_SHA384_DIGEST_SIZE) == 0; } + ZT_INLINE bool operator!=(const ZT_Certificate &c) const noexcept { return memcmp(this->serialNo, c.serialNo, ZT_SHA384_DIGEST_SIZE) != 0; } + ZT_INLINE bool operator<(const ZT_Certificate &c) const noexcept { return memcmp(this->serialNo, c.serialNo, ZT_SHA384_DIGEST_SIZE) < 0; } + ZT_INLINE bool operator<=(const ZT_Certificate &c) const noexcept { return memcmp(this->serialNo, c.serialNo, ZT_SHA384_DIGEST_SIZE) <= 0; } + ZT_INLINE bool operator>(const ZT_Certificate &c) const noexcept { return memcmp(this->serialNo, c.serialNo, ZT_SHA384_DIGEST_SIZE) > 0; } + ZT_INLINE bool operator>=(const ZT_Certificate &c) const noexcept { return memcmp(this->serialNo, c.serialNo, ZT_SHA384_DIGEST_SIZE) >= 0; } private: + void m_clear(); + static void m_encodeSubject(const ZT_Certificate_Subject &s, Dictionary &d, bool omitUniqueIdProofSignature); // These hold any identity or locator objects that are owned by and should @@ -218,7 +228,7 @@ private: Vector< uint8_t > m_subjectUniqueIdProofSignature; Vector< uint8_t > m_signature; - std::atomic __refCount; + std::atomic< int > __refCount; }; } // namespace ZeroTier diff --git a/core/Containers.hpp b/core/Containers.hpp index 2c4820176..9c1d66f62 100644 --- a/core/Containers.hpp +++ b/core/Containers.hpp @@ -19,18 +19,17 @@ #include "Constants.hpp" #include "Utils.hpp" -#ifdef __CPP11__ - -#include - -#endif - #include #include #include #include #include +#ifdef __CPP11__ +#include +#include +#endif + namespace ZeroTier { #ifdef __CPP11__ @@ -51,7 +50,7 @@ struct intl_MapHasher }; template< typename K, typename V > -class Map : public std::unordered_map< K, V, intl_MapHasher, std::equal_to< K >, Utils::Mallocator < std::pair< const K, V > > > +class Map : public std::unordered_map< K, V, intl_MapHasher > { public: ZT_INLINE V *get(const K &key) noexcept @@ -72,13 +71,13 @@ public: }; template< typename K, typename V > -class MultiMap : public std::unordered_multimap< K, V, intl_MapHasher, std::equal_to< K >, Utils::Mallocator < std::pair< const K, V > > > +class MultiMap : public std::unordered_multimap< K, V, intl_MapHasher, std::equal_to< K > > {}; #else template -class Map : public std::map< K,V,std::less,Utils::Mallocator< std::pair > > +class Map : public std::map< K,V,std::less > { public: ZT_INLINE V *get(const K &key) noexcept @@ -109,55 +108,31 @@ class MultiMap : public std::multimap< K,V,std::less,Utils::Mallocator< std:: #endif template< typename K, typename V > -class SortedMap : public std::map< K, V, std::less< K >, Utils::Mallocator < std::pair< const K, V > > > -{ -public: - ZT_INLINE V *get(const K &key) noexcept - { - typename SortedMap::iterator i(this->find(key)); - if (i == this->end()) - return nullptr; - return &(i->second); - } - ZT_INLINE const V *get(const K &key) const noexcept - { - typename SortedMap::const_iterator i(this->find(key)); - if (i == this->end()) - return nullptr; - return &(i->second); - } - ZT_INLINE void set(const K &key, const V &value) { (*this)[key] = value; } -}; +class SortedMap : public std::map< K, V > +{}; template< typename V > -class Vector : public std::vector< V, Utils::Mallocator < V > > +class Vector : public std::vector< V > { public: - ZT_INLINE Vector() {} + ZT_INLINE Vector() + {} + template< typename I > - ZT_INLINE Vector(I begin,I end) : std::vector< V, Utils::Mallocator < V > >(begin,end) {} + ZT_INLINE Vector(I begin,I end) : + std::vector< V >(begin, end) + {} }; template< typename V > -class List : public std::list< V, Utils::Mallocator < V > > -{ -}; +class List : public std::list< V > +{}; template< typename V > -class Set : public std::set< V, std::less< V >, Utils::Mallocator < V > > -{ -}; +class Set : public std::set< V, std::less< V > > +{}; -class String : public std::basic_string< char, std::char_traits< char >, Utils::Mallocator < char > > -{ -public: - ZT_INLINE String() {} - ZT_INLINE String(const String &s) : std::basic_string< char, std::char_traits< char >, Utils::Mallocator < char > >(s.c_str()) {} - ZT_INLINE String(const std::string &s) : std::basic_string< char, std::char_traits< char >, Utils::Mallocator < char > >(s.c_str()) {} - ZT_INLINE String(const char *const s) : std::basic_string< char, std::char_traits< char >, Utils::Mallocator < char > >(s) {} - ZT_INLINE String &operator=(const char *const s) { assign(s); return *this; } - ZT_INLINE String &operator=(const std::string &s) { assign(s.c_str()); return *this; } -}; +typedef std::string String; } // ZeroTier diff --git a/core/Dictionary.cpp b/core/Dictionary.cpp index b2c93207d..57b7767a5 100644 --- a/core/Dictionary.cpp +++ b/core/Dictionary.cpp @@ -21,23 +21,14 @@ Dictionary::Dictionary() Dictionary::~Dictionary() {} -Vector< uint8_t > &Dictionary::operator[](const char *k) -{ - if (k) - return m_entries[s_key(k)]; - else return m_entries[""]; -} +Vector< uint8_t > &Dictionary::operator[](const char *const k) +{ return m_entries[s_key(k)]; } -const Vector< uint8_t > &Dictionary::operator[](const char *k) const +const Vector< uint8_t > &Dictionary::operator[](const char *const k) const { static const Vector< uint8_t > s_emptyEntry; - if (k) { - SortedMap< String, Vector< uint8_t > >::const_iterator e(m_entries.find(s_key(k))); - return (e == m_entries.end()) ? s_emptyEntry : e->second; - } else { - SortedMap< String, Vector< uint8_t > >::const_iterator e(m_entries.find("")); - return (e == m_entries.end()) ? s_emptyEntry : e->second; - } + const SortedMap< String, Vector< uint8_t > >::const_iterator e(m_entries.find(s_key(k))); + return (e == m_entries.end()) ? s_emptyEntry : e->second; } void Dictionary::add(const char *k, bool v) @@ -50,16 +41,16 @@ void Dictionary::add(const char *k, bool v) void Dictionary::add(const char *k, const Address &v) { - Vector< uint8_t > &e = (*this)[k]; - e.resize(ZT_ADDRESS_STRING_SIZE_MAX); - v.toString((char *)e.data()); + char tmp[ZT_ADDRESS_STRING_SIZE_MAX]; + v.toString(tmp); + add(k, tmp); } void Dictionary::add(const char *k, const char *v) { - if ((v) && (*v)) { - Vector< uint8_t > &e = (*this)[k]; - e.clear(); + Vector< uint8_t > &e = (*this)[k]; + e.clear(); + if (v) { while (*v) e.push_back((uint8_t)*(v++)); } @@ -68,7 +59,7 @@ void Dictionary::add(const char *k, const char *v) void Dictionary::add(const char *k, const void *data, unsigned int len) { Vector< uint8_t > &e = (*this)[k]; - if (len != 0) { + if (likely(len != 0)) { e.assign((const uint8_t *)data, (const uint8_t *)data + len); } else { e.clear(); @@ -150,48 +141,48 @@ bool Dictionary::decode(const void *data, unsigned int len) Vector< uint8_t > *v = nullptr; bool escape = false; for (unsigned int di = 0; di < len; ++di) { - uint8_t c = reinterpret_cast(data)[di]; - if (!c) break; - if (v) { - if (escape) { - escape = false; - switch (c) { - case 48: - v->push_back(0); - break; - case 101: - v->push_back(61); - break; - case 110: - v->push_back(10); - break; - case 114: - v->push_back(13); - break; - default: - v->push_back(c); - break; - } - } else { - if (c == (uint8_t)'\n') { - k.clear(); - v = nullptr; - } else if (c == 92) { // backslash - escape = true; + const uint8_t c = reinterpret_cast(data)[di]; + if (c) { + if (v) { + if (escape) { + escape = false; + switch (c) { + case 48: + v->push_back(0); + break; + case 101: + v->push_back(61); + break; + case 110: + v->push_back(10); + break; + case 114: + v->push_back(13); + break; + default: + v->push_back(c); + break; + } } else { - v->push_back(c); + if (c == (uint8_t)'\n') { + k.clear(); + v = nullptr; + } else if (c == 92) { // backslash + escape = true; + } else { + v->push_back(c); + } + } + } else { + if (c == (uint8_t)'=') { + v = &m_entries[k]; + } else if ((c < 33) || (c > 126) || (c == 92)) { + return false; + } else { + k.push_back(c); } } - } else { - if ((c < 33) || (c > 126) || (c == 92)) { - return false; - } else if (c == (uint8_t)'=') { - k.push_back(0); - v = &m_entries[k]; - } else { - k.push_back(c); - } - } + } else break; } return true; } @@ -209,4 +200,19 @@ char *Dictionary::arraySubscript(char buf[256],const char *name,const unsigned l return buf; } +String Dictionary::s_key(const char *k) noexcept +{ + String buf; + if (likely(k != nullptr)) { + for (;;) { + const char c = *(k++); + if ((c >= 33) && (c <= 126) && (c != 61) && (c != 92)) // printable ASCII with no spaces, equals, or backslash + buf.push_back(c); + else if (c == 0) + break; + } + } + return buf; +} + } // namespace ZeroTier diff --git a/core/Dictionary.hpp b/core/Dictionary.hpp index 3e74f0049..bc368b326 100644 --- a/core/Dictionary.hpp +++ b/core/Dictionary.hpp @@ -268,6 +268,7 @@ public: template< typename V > ZT_INLINE static void append(V &out, const char *const k, const uint64_t v) { + s_appendKey(out, k); char buf[17]; Utils::hex(v, buf); unsigned int i = 0; @@ -370,6 +371,14 @@ public: return mlen; } + /** + * Append #sub where sub is a hexadecimal string to 'name' and store in 'buf' + * + * @param buf Buffer to store subscript key + * @param name Root name + * @param sub Subscript index + * @return Pointer to 'buf' + */ static char *arraySubscript(char buf[256],const char *name,const unsigned long sub) noexcept; private: @@ -407,27 +416,16 @@ private: ZT_INLINE static void s_appendKey(V &out, const char *k) { for (;;) { - char c = *(k++); - if (c == 0) - break; + const char c = *(k++); if ((c >= 33) && (c <= 126) && (c != 61) && (c != 92)) // printable ASCII with no spaces, equals, or backslash out.push_back((uint8_t)c); + else if (c == 0) + break; } out.push_back((uint8_t)'='); } - ZT_INLINE static String s_key(const char *k) noexcept - { - String buf; - for(;;) { - char c = *(k++); - if (c == 0) - break; - if ((c >= 33) && (c <= 126) && (c != 61) && (c != 92)) // printable ASCII with no spaces, equals, or backslash - buf.push_back(c); - } - return buf; - } + static String s_key(const char *k) noexcept; // Dictionary maps need to be sorted so that they always encode in the same order // to yield blobs that can be hashed and signed reproducibly. Other than for areas diff --git a/core/Identity.cpp b/core/Identity.cpp index bb3c96aea..305ab69bf 100644 --- a/core/Identity.cpp +++ b/core/Identity.cpp @@ -18,9 +18,10 @@ #include "Poly1305.hpp" #include "Utils.hpp" #include "Endpoint.hpp" -#include "Locator.hpp" #include +#include +#include namespace ZeroTier { @@ -93,10 +94,8 @@ struct p_CompareLittleEndian }; // This is a simpler memory-intensive frankenhash for V1 identity generation. -bool identityV1ProofOfWorkCriteria(const void *in, const unsigned int len) +bool identityV1ProofOfWorkCriteria(const void *in, const unsigned int len, uint64_t *const w) { - uint64_t w[ZT_IDENTITY_V1_POW_MEMORY_SIZE / 8]; - // Fill work buffer with pseudorandom bytes using a construction that should be // relatively hostile to GPU acceleration. GPUs usually implement branching by // executing all branches and then selecting the answer, which means this @@ -165,29 +164,36 @@ bool Identity::generate(const Type t) break; case P384: { - for (;;) { - // Loop until we pass the PoW criteria. The nonce is only 8 bits, so generate - // some new key material every time it wraps. The ECC384 generator is slightly - // faster so use that one. - m_pub[0] = 0; // zero nonce - C25519::generateCombined(m_pub + 1, m_priv + 1); - ECC384GenerateKey(m_pub + 1 + ZT_C25519_COMBINED_PUBLIC_KEY_SIZE, m_priv + ZT_C25519_COMBINED_PRIVATE_KEY_SIZE); + //uint64_t w[ZT_IDENTITY_V1_POW_MEMORY_SIZE / 8]; + uint64_t *const w = (uint64_t *)malloc(ZT_IDENTITY_V1_POW_MEMORY_SIZE); + if (!w) + return false; + try { for (;;) { - if (identityV1ProofOfWorkCriteria(m_pub, sizeof(m_pub))) - break; - if (++m_pub[0] == 0) - ECC384GenerateKey(m_pub + 1 + ZT_C25519_COMBINED_PUBLIC_KEY_SIZE, m_priv + ZT_C25519_COMBINED_PRIVATE_KEY_SIZE); - } + // Loop until we pass the PoW criteria. The nonce is only 8 bits, so generate + // some new key material every time it wraps. The ECC384 generator is slightly + // faster so use that one. + m_pub[0] = 0; // zero nonce + C25519::generateCombined(m_pub + 1, m_priv + 1); + ECC384GenerateKey(m_pub + 1 + ZT_C25519_COMBINED_PUBLIC_KEY_SIZE, m_priv + ZT_C25519_COMBINED_PRIVATE_KEY_SIZE); + for (;;) { + if (identityV1ProofOfWorkCriteria(m_pub, sizeof(m_pub), w)) + break; + if (++m_pub[0] == 0) + ECC384GenerateKey(m_pub + 1 + ZT_C25519_COMBINED_PUBLIC_KEY_SIZE, m_priv + ZT_C25519_COMBINED_PRIVATE_KEY_SIZE); + } - // If we passed PoW then check that the address is valid, otherwise loop - // back around and run the whole process again. - m_computeHash(); - const Address addr(m_fp.hash); - if (!addr.isReserved()) { - m_fp.address = addr; - break; + // If we passed PoW then check that the address is valid, otherwise loop + // back around and run the whole process again. + m_computeHash(); + const Address addr(m_fp.hash); + if (!addr.isReserved()) { + m_fp.address = addr; + break; + } } - } + } catch ( ... ) {} + free(w); } break; @@ -215,7 +221,12 @@ bool Identity::locallyValidate() const noexcept case P384: { if (Address(m_fp.hash) != m_fp.address) return false; - return identityV1ProofOfWorkCriteria(m_pub, sizeof(m_pub)); + uint64_t *const w = (uint64_t *)malloc(ZT_IDENTITY_V1_POW_MEMORY_SIZE); + if (!w) + return false; + const bool valid = identityV1ProofOfWorkCriteria(m_pub, sizeof(m_pub), w); + free(w); + return valid; } } } diff --git a/core/OS.hpp b/core/OS.hpp index 9b6e473e7..f7cb1a4a9 100644 --- a/core/OS.hpp +++ b/core/OS.hpp @@ -110,6 +110,7 @@ #include #include #include +#include #include #endif diff --git a/core/Tests.cpp b/core/Tests.cpp index 5f512aa56..265fbda5a 100644 --- a/core/Tests.cpp +++ b/core/Tests.cpp @@ -283,6 +283,7 @@ static bool ZTT_deepCompareCertificates(const Certificate &a, const Certificate return false; if ((a.subject.uniqueIdProofSignature == nullptr) != (b.subject.uniqueIdProofSignature == nullptr)) return false; + if ((a.subject.uniqueId != nullptr) && (a.subject.uniqueIdProofSignature != nullptr)) { if ( (memcmp(a.subject.uniqueId, b.subject.uniqueId, a.subject.uniqueIdSize) != 0) || @@ -1082,10 +1083,9 @@ extern "C" const char *ZTT_crypto() } { - char tmp[4096]; + char tmp[256]; ZT_T_PRINTF("[crypto] Testing Certificate..." ZT_EOL_S); - Certificate cert; ZT_T_PRINTF(" Create test subject and issuer identities... "); Identity testSubjectId, testIssuerId; @@ -1100,53 +1100,57 @@ extern "C" const char *ZTT_crypto() ZT_T_PRINTF("OK %s" ZT_EOL_S, tmp); ZT_T_PRINTF(" Create and sign certificate... "); - cert.subject.timestamp = now(); - cert.addSubjectIdentity(testSubjectId); - cert.addSubjectNetwork(12345, testSubjectId.fingerprint()); - cert.addSubjectUpdateUrl("https://www.zerotier.com/"); - ZT_SETSTR(cert.subject.name.serialNo, "serialNo"); - ZT_SETSTR(cert.subject.name.commonName, "commonName"); - ZT_SETSTR(cert.subject.name.country, "country"); - ZT_SETSTR(cert.subject.name.organization, "organization"); - ZT_SETSTR(cert.subject.name.unit, "unit"); - ZT_SETSTR(cert.subject.name.locality, "locality"); - ZT_SETSTR(cert.subject.name.province, "province"); - ZT_SETSTR(cert.subject.name.streetAddress, "streetAddress"); - ZT_SETSTR(cert.subject.name.postalCode, "postalCode"); - ZT_SETSTR(cert.subject.name.email, "email"); - ZT_SETSTR(cert.subject.name.url, "url"); - ZT_SETSTR(cert.subject.name.host, "host"); - cert.timestamp = cert.subject.timestamp; - cert.validity[0] = 0; - cert.validity[1] = 9223372036854775807LL; - Utils::copy(&cert.issuerName, &cert.subject.name); - cert.setSubjectUniqueId(uniqueId, uniqueIdPrivate); - cert.sign(testIssuerId); - Vector< uint8_t > enc(cert.encode()); + SharedPtr cert(new Certificate()); + cert->subject.timestamp = now(); + cert->addSubjectIdentity(testSubjectId); + cert->addSubjectNetwork(12345, testSubjectId.fingerprint()); + cert->addSubjectUpdateUrl("https://www.zerotier.com/"); + ZT_SETSTR(cert->subject.name.serialNo, "serialNo"); + ZT_SETSTR(cert->subject.name.commonName, "commonName"); + ZT_SETSTR(cert->subject.name.country, "country"); + ZT_SETSTR(cert->subject.name.organization, "organization"); + ZT_SETSTR(cert->subject.name.unit, "unit"); + ZT_SETSTR(cert->subject.name.locality, "locality"); + ZT_SETSTR(cert->subject.name.province, "province"); + ZT_SETSTR(cert->subject.name.streetAddress, "streetAddress"); + ZT_SETSTR(cert->subject.name.postalCode, "postalCode"); + ZT_SETSTR(cert->subject.name.email, "email"); + ZT_SETSTR(cert->subject.name.url, "url"); + ZT_SETSTR(cert->subject.name.host, "host"); + cert->timestamp = cert->subject.timestamp; + cert->validity[0] = 0; + cert->validity[1] = 9223372036854775807LL; + Utils::copy(&cert->issuerName, &cert->subject.name); + cert->setSubjectUniqueId(uniqueId, uniqueIdPrivate); + cert->sign(testIssuerId); + Vector< uint8_t > enc(cert->encode()); ZT_T_PRINTF("OK (%d bytes)" ZT_EOL_S, (int)enc.size()); ZT_T_PRINTF(" Testing certificate verify... "); - if (!cert.verify()) { + if (!cert->verify()) { ZT_T_PRINTF("FAILED (verify original)" ZT_EOL_S); return "Verify original certificate"; } ZT_T_PRINTF("OK" ZT_EOL_S); ZT_T_PRINTF(" Test certificate decode from marshaled format... "); - Certificate cert2; - if (!cert2.decode(enc)) { + SharedPtr cert2(new Certificate()); + if (!cert2->decode(enc)) { ZT_T_PRINTF("FAILED (decode)" ZT_EOL_S); return "Certificate decode"; } - if (!ZTT_deepCompareCertificates(cert, cert2)) { + if (!ZTT_deepCompareCertificates(*cert, *cert2)) { ZT_T_PRINTF("FAILED (compare decoded with original)" ZT_EOL_S); return "Certificate decode and compare"; } - if (!cert2.verify()) { + if (!cert2->verify()) { ZT_T_PRINTF("FAILED (verify decoded certificate)"); return "Verify decoded certificate"; } ZT_T_PRINTF("OK" ZT_EOL_S); + + cert.zero(); + cert2.zero(); } } catch (std::exception &e) { ZT_T_PRINTF(ZT_EOL_S "[crypto] Unexpected exception: %s" ZT_EOL_S, e.what()); diff --git a/core/Utils.hpp b/core/Utils.hpp index 25c4ff7f4..0af45de59 100644 --- a/core/Utils.hpp +++ b/core/Utils.hpp @@ -762,79 +762,6 @@ static ZT_INLINE void zero(void *const dest) noexcept static ZT_INLINE void zero(void *const dest, const unsigned long len) noexcept { memset(dest, 0, len); } -/** - * Simple malloc/free based C++ STL allocator. - * - * This is used to make sure our containers don't use weird libc++ - * allocators but instead use whatever malloc() is, which in turn - * can be overridden by things like jemaclloc or tcmalloc. - * - * @tparam T Allocated type - */ -template< typename T > -struct Mallocator -{ - typedef size_t size_type; - typedef ptrdiff_t difference_type; - typedef T *pointer; - typedef const T *const_pointer; - typedef T &reference; - typedef const T &const_reference; - typedef T value_type; - - template< class U > - struct rebind - { - typedef Mallocator< U > other; - }; - ZT_INLINE Mallocator() noexcept - {} - - ZT_INLINE Mallocator(const Mallocator &) noexcept - {} - - template< class U > - ZT_INLINE Mallocator(const Mallocator< U > &) noexcept - {} - - ZT_INLINE ~Mallocator() noexcept - {} - - ZT_INLINE pointer allocate(size_type s, void const * = nullptr) - { - if (0 == s) - return nullptr; - pointer temp = (pointer)malloc(s * sizeof(T)); - if (temp == nullptr) - throw BadAllocException; - return temp; - } - - ZT_INLINE pointer address(reference x) const - { return &x; } - - ZT_INLINE const_pointer address(const_reference x) const - { return &x; } - - ZT_INLINE void deallocate(pointer p, size_type) - { free(p); } - - ZT_INLINE size_type max_size() const noexcept - { return std::numeric_limits< size_t >::max() / sizeof(T); } - - ZT_INLINE void construct(pointer p, const T &val) - { new((void *)p) T(val); } - - ZT_INLINE void destroy(pointer p) - { p->~T(); } - - constexpr bool operator==(const Mallocator &) const noexcept - { return true; } - - constexpr bool operator!=(const Mallocator &) const noexcept - { return false; } -}; - } // namespace Utils } // namespace ZeroTier