فهرست منبع

A bunch of compile fixes, and an edge case fix in Dictionary.

Adam Ierymenko 5 سال پیش
والد
کامیت
3f4809457f
10فایلهای تغییر یافته به همراه289 افزوده شده و 299 حذف شده
  1. 22 5
      core/AES.cpp
  2. 75 34
      core/Certificate.cpp
  3. 23 13
      core/Certificate.hpp
  4. 22 47
      core/Containers.hpp
  5. 63 57
      core/Dictionary.cpp
  6. 13 15
      core/Dictionary.hpp
  7. 36 25
      core/Identity.cpp
  8. 1 0
      core/OS.hpp
  9. 34 30
      core/Tests.cpp
  10. 0 73
      core/Utils.hpp

+ 22 - 5
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 {
+				p_aesCtrInner128(len, c0, c1, in, out, k);
+			}
 #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);
-#if defined(ZT_AES_VAES512) && defined(ZT_AES_VAES256)
 			}
 #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);

+ 75 - 34
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<const Identity *>(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<const Identity *>(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);
 

+ 23 - 13
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<int> __refCount;
+	std::atomic< int > __refCount;
 };
 
 } // namespace ZeroTier

+ 22 - 47
core/Containers.hpp

@@ -19,18 +19,17 @@
 #include "Constants.hpp"
 #include "Utils.hpp"
 
-#ifdef __CPP11__
-
-#include <unordered_map>
-
-#endif
-
 #include <map>
 #include <vector>
 #include <list>
 #include <set>
 #include <string>
 
+#ifdef __CPP11__
+#include <atomic>
+#include <unordered_map>
+#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<typename K,typename V>
-class Map : public std::map< K,V,std::less<K>,Utils::Mallocator< std::pair<const K,V> > >
+class Map : public std::map< K,V,std::less<K> >
 {
 public:
 	ZT_INLINE V *get(const K &key) noexcept
@@ -109,55 +108,31 @@ class MultiMap : public std::multimap< K,V,std::less<K>,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
 

+ 63 - 57
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<const uint8_t *>(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:
+		const uint8_t c = reinterpret_cast<const uint8_t *>(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 {
+					if (c == (uint8_t)'\n') {
+						k.clear();
+						v = nullptr;
+					} else if (c == 92) { // backslash
+						escape = true;
+					} else {
 						v->push_back(c);
-						break;
+					}
 				}
 			} else {
-				if (c == (uint8_t)'\n') {
-					k.clear();
-					v = nullptr;
-				} else if (c == 92) { // backslash
-					escape = true;
+				if (c == (uint8_t)'=') {
+					v = &m_entries[k];
+				} else if ((c < 33) || (c > 126) || (c == 92)) {
+					return false;
 				} else {
-					v->push_back(c);
+					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

+ 13 - 15
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

+ 36 - 25
core/Identity.cpp

@@ -18,9 +18,10 @@
 #include "Poly1305.hpp"
 #include "Utils.hpp"
 #include "Endpoint.hpp"
-#include "Locator.hpp"
 
 #include <algorithm>
+#include <memory>
+#include <utility>
 
 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;
 				}
 			}
 		}

+ 1 - 0
core/OS.hpp

@@ -110,6 +110,7 @@
 #include <xmmintrin.h>
 #include <emmintrin.h>
 #include <immintrin.h>
+#include <tmmintrin.h>
 #include <mmintrin.h>
 #endif
 

+ 34 - 30
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<sizeof(ZT_Certificate_Subject)>(&cert.issuerName, &cert.subject.name);
-			cert.setSubjectUniqueId(uniqueId, uniqueIdPrivate);
-			cert.sign(testIssuerId);
-			Vector< uint8_t > enc(cert.encode());
+			SharedPtr<Certificate> 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<sizeof(ZT_Certificate_Name)>(&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<Certificate> 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());

+ 0 - 73
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