Browse Source

Now with less bugs!

Adam Ierymenko 5 years ago
parent
commit
04d8c3dd79
4 changed files with 206 additions and 136 deletions
  1. 100 66
      core/Certificate.cpp
  2. 12 7
      core/Certificate.hpp
  3. 82 55
      core/Tests.cpp
  4. 12 8
      pkg/zerotier/certificate.go

+ 100 - 66
core/Certificate.cpp

@@ -24,10 +24,12 @@ Certificate::Certificate() noexcept
 	Utils::zero< sizeof(ZT_Certificate) >(sup);
 	Utils::zero< sizeof(ZT_Certificate) >(sup);
 }
 }
 
 
-Certificate::Certificate(const ZT_Certificate &apiCert)
+Certificate::Certificate(const ZT_Certificate &apiCert) :
+	Certificate()
 { *this = apiCert; }
 { *this = apiCert; }
 
 
-Certificate::Certificate(const Certificate &cert)
+Certificate::Certificate(const Certificate &cert) :
+	Certificate()
 { *this = cert; }
 { *this = cert; }
 
 
 Certificate::~Certificate()
 Certificate::~Certificate()
@@ -305,19 +307,16 @@ bool Certificate::decode(const void *const data, const unsigned int len)
 	unsigned int cnt = (unsigned int)d.getUI("s.i$");
 	unsigned int cnt = (unsigned int)d.getUI("s.i$");
 	for (unsigned int i = 0; i < cnt; ++i) {
 	for (unsigned int i = 0; i < cnt; ++i) {
 		const Vector< uint8_t > &identityData = d[Dictionary::arraySubscript(tmp, sizeof(tmp), "s.i$.i", i)];
 		const Vector< uint8_t > &identityData = d[Dictionary::arraySubscript(tmp, sizeof(tmp), "s.i$.i", i)];
-		if (identityData.empty()) {
+		if (identityData.empty())
 			return false;
 			return false;
-		}
 		Identity id;
 		Identity id;
-		if (id.unmarshal(identityData.data(), (unsigned int)identityData.size()) <= 0) {
+		if (id.unmarshal(identityData.data(), (unsigned int)identityData.size()) <= 0)
 			return false;
 			return false;
-		}
 		const Vector< uint8_t > &locatorData = d[Dictionary::arraySubscript(tmp, sizeof(tmp), "s.i$.l", i)];
 		const Vector< uint8_t > &locatorData = d[Dictionary::arraySubscript(tmp, sizeof(tmp), "s.i$.l", i)];
 		if (!locatorData.empty()) {
 		if (!locatorData.empty()) {
 			Locator loc;
 			Locator loc;
-			if (loc.unmarshal(locatorData.data(), (unsigned int)locatorData.size()) <= 0) {
+			if (loc.unmarshal(locatorData.data(), (unsigned int)locatorData.size()) <= 0)
 				return false;
 				return false;
-			}
 			this->addSubjectIdentity(id, loc);
 			this->addSubjectIdentity(id, loc);
 		} else {
 		} else {
 			this->addSubjectIdentity(id);
 			this->addSubjectIdentity(id);
@@ -328,22 +327,19 @@ bool Certificate::decode(const void *const data, const unsigned int len)
 	for (unsigned int i = 0; i < cnt; ++i) {
 	for (unsigned int i = 0; i < cnt; ++i) {
 		const uint64_t nwid = d.getUI(Dictionary::arraySubscript(tmp, sizeof(tmp), "s.nw$.i", i));
 		const uint64_t nwid = d.getUI(Dictionary::arraySubscript(tmp, sizeof(tmp), "s.nw$.i", i));
 		const Vector< uint8_t > &fingerprintData = d[Dictionary::arraySubscript(tmp, sizeof(tmp), "s.nw$.c", i)];
 		const Vector< uint8_t > &fingerprintData = d[Dictionary::arraySubscript(tmp, sizeof(tmp), "s.nw$.c", i)];
-		if ((nwid == 0) || (fingerprintData.empty())) {
+		if ((nwid == 0) || (fingerprintData.empty()))
 			return false;
 			return false;
-		}
 		Fingerprint fp;
 		Fingerprint fp;
-		if (fp.unmarshal(fingerprintData.data(), (unsigned int)fingerprintData.size()) <= 0) {
+		if (fp.unmarshal(fingerprintData.data(), (unsigned int)fingerprintData.size()) <= 0)
 			return false;
 			return false;
-		}
 		this->addSubjectNetwork(nwid, fp);
 		this->addSubjectNetwork(nwid, fp);
 	}
 	}
 
 
 	cnt = (unsigned int)d.getUI("s.c$");
 	cnt = (unsigned int)d.getUI("s.c$");
 	for (unsigned int i = 0; i < cnt; ++i) {
 	for (unsigned int i = 0; i < cnt; ++i) {
 		const Vector< uint8_t > &serial = d[Dictionary::arraySubscript(tmp, sizeof(tmp), "s.c$", i)];
 		const Vector< uint8_t > &serial = d[Dictionary::arraySubscript(tmp, sizeof(tmp), "s.c$", i)];
-		if (serial.size() != ZT_SHA384_DIGEST_SIZE) {
+		if (serial.size() != ZT_SHA384_DIGEST_SIZE)
 			return false;
 			return false;
-		}
 		this->addSubjectCertificate(serial.data());
 		this->addSubjectCertificate(serial.data());
 	}
 	}
 
 
@@ -425,15 +421,6 @@ bool Certificate::decode(const void *const data, const unsigned int len)
 	return true;
 	return true;
 }
 }
 
 
-Vector< uint8_t > Certificate::encodeCSR()
-{
-	Vector< uint8_t > enc;
-	Dictionary d;
-	m_encodeSubject(this->subject, d, false);
-	d.encode(enc);
-	return enc;
-}
-
 bool Certificate::sign(const Identity &issuer)
 bool Certificate::sign(const Identity &issuer)
 {
 {
 	m_identities.push_front(issuer);
 	m_identities.push_front(issuer);
@@ -476,12 +463,13 @@ ZT_CertificateError Certificate::verify() const
 				(this->subject.uniqueIdSize != ZT_CERTIFICATE_UNIQUE_ID_TYPE_NIST_P_384_SIZE) ||
 				(this->subject.uniqueIdSize != ZT_CERTIFICATE_UNIQUE_ID_TYPE_NIST_P_384_SIZE) ||
 				(this->subject.uniqueId[0] != ZT_CERTIFICATE_UNIQUE_ID_TYPE_NIST_P_384))
 				(this->subject.uniqueId[0] != ZT_CERTIFICATE_UNIQUE_ID_TYPE_NIST_P_384))
 				return ZT_CERTIFICATE_ERROR_INVALID_UNIQUE_ID_PROOF;
 				return ZT_CERTIFICATE_ERROR_INVALID_UNIQUE_ID_PROOF;
-			Dictionary tmp;
-			m_encodeSubject(this->subject, tmp, true);
+			Dictionary d;
+			m_encodeSubject(this->subject, d, true);
 			Vector< uint8_t > enc;
 			Vector< uint8_t > enc;
-			tmp.encode(enc);
+			d.encode(enc);
 			uint8_t h[ZT_SHA384_DIGEST_SIZE];
 			uint8_t h[ZT_SHA384_DIGEST_SIZE];
 			SHA384(h, enc.data(), (unsigned int)enc.size());
 			SHA384(h, enc.data(), (unsigned int)enc.size());
+			static_assert(ZT_CERTIFICATE_UNIQUE_ID_TYPE_NIST_P_384_SIZE == (ZT_ECC384_PUBLIC_KEY_SIZE + 1), "incorrect size");
 			if (!ECC384ECDSAVerify(this->subject.uniqueId + 1, h, this->subject.uniqueIdProofSignature))
 			if (!ECC384ECDSAVerify(this->subject.uniqueId + 1, h, this->subject.uniqueIdProofSignature))
 				return ZT_CERTIFICATE_ERROR_INVALID_UNIQUE_ID_PROOF;
 				return ZT_CERTIFICATE_ERROR_INVALID_UNIQUE_ID_PROOF;
 		} else if (this->subject.uniqueIdSize > 0) {
 		} else if (this->subject.uniqueIdSize > 0) {
@@ -519,6 +507,45 @@ ZT_CertificateError Certificate::verify() const
 	return ZT_CERTIFICATE_ERROR_NONE;
 	return ZT_CERTIFICATE_ERROR_NONE;
 }
 }
 
 
+Vector< uint8_t > Certificate::createCSR(const ZT_Certificate_Subject &s, const void *uniqueId, unsigned int uniqueIdSize, const void *uniqueIdPrivate, unsigned int uniqueIdPrivateSize)
+{
+	ZT_Certificate_Subject sc;
+	Utils::copy< sizeof(ZT_Certificate_Subject) >(&sc, &s);
+
+	if ((uniqueId) && (uniqueIdSize > 0) && (uniqueIdPrivate) && (uniqueIdPrivateSize > 0)) {
+		sc.uniqueId = reinterpret_cast<const uint8_t *>(uniqueId);
+		sc.uniqueIdSize = uniqueIdSize;
+	} else {
+		sc.uniqueId = nullptr;
+		sc.uniqueIdSize = 0;
+	}
+
+	Dictionary d;
+	m_encodeSubject(sc, d, true);
+	Vector< uint8_t > enc;
+	d.encode(enc);
+
+	if (sc.uniqueId) {
+		uint8_t h[ZT_SHA384_DIGEST_SIZE];
+		SHA384(h, enc.data(), (unsigned int)enc.size());
+		enc.clear();
+		if (
+			(reinterpret_cast<const uint8_t *>(uniqueId)[0] == ZT_CERTIFICATE_UNIQUE_ID_TYPE_NIST_P_384) &&
+			(uniqueIdSize == ZT_CERTIFICATE_UNIQUE_ID_TYPE_NIST_P_384_SIZE) &&
+			(uniqueIdPrivateSize == ZT_CERTIFICATE_UNIQUE_ID_TYPE_NIST_P_384_PRIVATE_SIZE)) {
+			uint8_t sig[ZT_ECC384_SIGNATURE_SIZE];
+			ECC384ECDSASign(reinterpret_cast<const uint8_t *>(uniqueIdPrivate), h, sig);
+			sc.uniqueIdProofSignature = sig;
+			sc.uniqueIdProofSignatureSize = ZT_ECC384_SIGNATURE_SIZE;
+			d.clear();
+			m_encodeSubject(sc, d, false);
+			d.encode(enc);
+		}
+	}
+
+	return enc;
+}
+
 void Certificate::m_clear()
 void Certificate::m_clear()
 {
 {
 	ZT_Certificate *const sup = this;
 	ZT_Certificate *const sup = this;
@@ -620,16 +647,20 @@ int ZT_Certificate_newSubjectUniqueId(
 	void *uniqueIdPrivate,
 	void *uniqueIdPrivate,
 	int *uniqueIdPrivateSize)
 	int *uniqueIdPrivateSize)
 {
 {
-	switch (type) {
-		case ZT_CERTIFICATE_UNIQUE_ID_TYPE_NIST_P_384:
-			if ((*uniqueIdSize < ZT_CERTIFICATE_UNIQUE_ID_TYPE_NIST_P_384_SIZE) || (*uniqueIdPrivateSize < ZT_CERTIFICATE_UNIQUE_ID_TYPE_NIST_P_384_PRIVATE_SIZE))
-				return ZT_RESULT_ERROR_BAD_PARAMETER;
-			*uniqueIdSize = ZT_CERTIFICATE_UNIQUE_ID_TYPE_NIST_P_384_SIZE;
-			*uniqueIdPrivateSize = ZT_CERTIFICATE_UNIQUE_ID_TYPE_NIST_P_384_PRIVATE_SIZE;
-			ZeroTier::Certificate::createSubjectUniqueId(reinterpret_cast<uint8_t *>(uniqueId), reinterpret_cast<uint8_t *>(uniqueIdPrivate));
-			return ZT_RESULT_OK;
-	}
-	return ZT_RESULT_ERROR_BAD_PARAMETER;
+	try {
+		switch (type) {
+			case ZT_CERTIFICATE_UNIQUE_ID_TYPE_NIST_P_384:
+				if ((*uniqueIdSize < ZT_CERTIFICATE_UNIQUE_ID_TYPE_NIST_P_384_SIZE) || (*uniqueIdPrivateSize < ZT_CERTIFICATE_UNIQUE_ID_TYPE_NIST_P_384_PRIVATE_SIZE))
+					return ZT_RESULT_ERROR_BAD_PARAMETER;
+				*uniqueIdSize = ZT_CERTIFICATE_UNIQUE_ID_TYPE_NIST_P_384_SIZE;
+				*uniqueIdPrivateSize = ZT_CERTIFICATE_UNIQUE_ID_TYPE_NIST_P_384_PRIVATE_SIZE;
+				ZeroTier::Certificate::createSubjectUniqueId(reinterpret_cast<uint8_t *>(uniqueId), reinterpret_cast<uint8_t *>(uniqueIdPrivate));
+				return ZT_RESULT_OK;
+		}
+		return ZT_RESULT_ERROR_BAD_PARAMETER;
+	} catch (...) {
+		return ZT_RESULT_FATAL_ERROR_INTERNAL;
+	}
 }
 }
 
 
 int ZT_Certificate_newCSR(
 int ZT_Certificate_newCSR(
@@ -641,20 +672,18 @@ int ZT_Certificate_newCSR(
 	void *csr,
 	void *csr,
 	int *csrSize)
 	int *csrSize)
 {
 {
-	ZeroTier::Certificate c;
-	ZeroTier::Utils::copy< sizeof(ZT_Certificate_Subject) >(&(c.subject), subject);
-	if ((uniqueId) && (uniqueIdSize > 0) && (uniqueIdPrivate) && (uniqueIdPrivateSize > 0)) {
-		if ((reinterpret_cast<const uint8_t *>(uniqueId)[0] != ZT_CERTIFICATE_UNIQUE_ID_TYPE_NIST_P_384) || (uniqueIdSize != ZT_CERTIFICATE_UNIQUE_ID_TYPE_NIST_P_384_SIZE) || (uniqueIdPrivateSize != ZT_CERTIFICATE_UNIQUE_ID_TYPE_NIST_P_384_PRIVATE_SIZE))
+	try {
+		if (!subject)
 			return ZT_RESULT_ERROR_BAD_PARAMETER;
 			return ZT_RESULT_ERROR_BAD_PARAMETER;
-		if (!c.setSubjectUniqueId(reinterpret_cast<const uint8_t *>(uniqueId), reinterpret_cast<const uint8_t *>(uniqueIdPrivate)))
-			return ZT_RESULT_ERROR_INVALID_CREDENTIAL;
+		const ZeroTier::Vector< uint8_t > csrV(ZeroTier::Certificate::createCSR(*subject, uniqueId, uniqueIdSize, uniqueIdPrivate, uniqueIdPrivateSize));
+		if ((int)csrV.size() > *csrSize)
+			return ZT_RESULT_ERROR_BAD_PARAMETER;
+		ZeroTier::Utils::copy(csr, csrV.data(), (unsigned int)csrV.size());
+		*csrSize = (int)csrV.size();
+		return ZT_RESULT_OK;
+	} catch (...) {
+		return ZT_RESULT_FATAL_ERROR_INTERNAL;
 	}
 	}
-	ZeroTier::Vector< uint8_t > csrV(c.encodeCSR());
-	if ((int)csrV.size() > *csrSize)
-		return ZT_RESULT_ERROR_BAD_PARAMETER;
-	ZeroTier::Utils::copy(csr, csrV.data(), (unsigned int)csrV.size());
-	*csrSize = (int)csrV.size();
-	return ZT_RESULT_OK;
 }
 }
 
 
 int ZT_Certificate_sign(
 int ZT_Certificate_sign(
@@ -663,22 +692,21 @@ int ZT_Certificate_sign(
 	void *signedCert,
 	void *signedCert,
 	int *signedCertSize)
 	int *signedCertSize)
 {
 {
-	if (!cert)
-		return ZT_RESULT_ERROR_BAD_PARAMETER;
-
 	try {
 	try {
-		const ZeroTier::ScopedPtr< ZeroTier::Certificate > c(new ZeroTier::Certificate(*cert));
-		if (!c->sign(*reinterpret_cast<const ZeroTier::Identity *>(signer)))
+		if (!cert)
+			return ZT_RESULT_ERROR_BAD_PARAMETER;
+		ZeroTier::Certificate c(*cert);
+		if (!c.sign(*reinterpret_cast<const ZeroTier::Identity *>(signer)))
 			return ZT_RESULT_ERROR_INTERNAL;
 			return ZT_RESULT_ERROR_INTERNAL;
 
 
-		const ZeroTier::Vector< uint8_t > enc(c->encode());
+		const ZeroTier::Vector< uint8_t > enc(c.encode());
 		if ((int)enc.size() > *signedCertSize)
 		if ((int)enc.size() > *signedCertSize)
 			return ZT_RESULT_ERROR_BAD_PARAMETER;
 			return ZT_RESULT_ERROR_BAD_PARAMETER;
 		ZeroTier::Utils::copy(signedCert, enc.data(), (unsigned int)enc.size());
 		ZeroTier::Utils::copy(signedCert, enc.data(), (unsigned int)enc.size());
 		*signedCertSize = (int)enc.size();
 		*signedCertSize = (int)enc.size();
 
 
 		return ZT_RESULT_OK;
 		return ZT_RESULT_OK;
-	} catch ( ... ) {
+	} catch (...) {
 		return ZT_RESULT_FATAL_ERROR_INTERNAL;
 		return ZT_RESULT_FATAL_ERROR_INTERNAL;
 	}
 	}
 }
 }
@@ -717,15 +745,19 @@ int ZT_Certificate_encode(
 	void *encoded,
 	void *encoded,
 	int *encodedSize)
 	int *encodedSize)
 {
 {
-	if ((!cert) || (!encoded) || (!encodedSize))
-		return ZT_RESULT_ERROR_BAD_PARAMETER;
-	ZeroTier::Certificate c(*cert);
-	ZeroTier::Vector< uint8_t > enc(c.encode());
-	if ((int)enc.size() > *encodedSize)
-		return ZT_RESULT_ERROR_BAD_PARAMETER;
-	ZeroTier::Utils::copy(encoded, enc.data(), (unsigned int)enc.size());
-	*encodedSize = (int)enc.size();
-	return ZT_RESULT_OK;
+	try {
+		if ((!cert) || (!encoded) || (!encodedSize))
+			return ZT_RESULT_ERROR_BAD_PARAMETER;
+		ZeroTier::Certificate c(*cert);
+		ZeroTier::Vector< uint8_t > enc(c.encode());
+		if ((int)enc.size() > *encodedSize)
+			return ZT_RESULT_ERROR_BAD_PARAMETER;
+		ZeroTier::Utils::copy(encoded, enc.data(), (unsigned int)enc.size());
+		*encodedSize = (int)enc.size();
+		return ZT_RESULT_OK;
+	} catch (...) {
+		return ZT_RESULT_FATAL_ERROR_INTERNAL;
+	}
 }
 }
 
 
 enum ZT_CertificateError ZT_Certificate_verify(const ZT_Certificate *cert)
 enum ZT_CertificateError ZT_Certificate_verify(const ZT_Certificate *cert)
@@ -752,8 +784,10 @@ const ZT_Certificate *ZT_Certificate_clone(const ZT_Certificate *cert)
 
 
 void ZT_Certificate_delete(const ZT_Certificate *cert)
 void ZT_Certificate_delete(const ZT_Certificate *cert)
 {
 {
-	if (cert)
-		delete (const ZeroTier::Certificate *)(cert);
+	try {
+		if (cert)
+			delete (const ZeroTier::Certificate *)(cert);
+	} catch (...) {}
 }
 }
 
 
 }
 }

+ 12 - 7
core/Certificate.hpp

@@ -145,13 +145,6 @@ public:
 	 */
 	 */
 	bool decode(const void *data, unsigned int len);
 	bool decode(const void *data, unsigned int len);
 
 
-	/**
-	 * Encode only the subject portion of this certificate as a CSR
-	 *
-	 * @return Encoded CSR
-	 */
-	Vector< uint8_t > encodeCSR();
-
 	/**
 	/**
 	 * Sign this certificate (and also fill in serialNo).
 	 * Sign this certificate (and also fill in serialNo).
 	 *
 	 *
@@ -170,6 +163,18 @@ public:
 	 */
 	 */
 	ZT_CertificateError verify() const;
 	ZT_CertificateError verify() const;
 
 
+	/**
+	 * Create a CSR that encodes the subject of this certificate
+	 *
+	 * @param s Subject to encode
+	 * @param uniqueId Unique ID to sign subject with or NULL if none
+	 * @param uniqueIdSize Size of unique ID or 0 if none
+	 * @param uniqueIdPrivate Unique ID private key for proof signature or NULL if none
+	 * @param uniqueIdPrivateSize Size of unique ID private key
+	 * @return Encoded subject (without any unique ID fields) or empty vector on error
+	 */
+	static Vector< uint8_t > createCSR(const ZT_Certificate_Subject &s, const void *uniqueId, unsigned int uniqueIdSize, const void *uniqueIdPrivate, unsigned int uniqueIdPrivateSize);
+
 	/**
 	/**
 	 * Create a subject unique ID and corresponding private key required for use
 	 * Create a subject unique ID and corresponding private key required for use
 	 *
 	 *

+ 82 - 55
core/Tests.cpp

@@ -195,7 +195,7 @@ static const C25519TestVector C25519_TEST_VECTORS[ZT_NUM_C25519_TEST_VECTORS] =
 #define ZT_ENDIAN_S "big"
 #define ZT_ENDIAN_S "big"
 #endif
 #endif
 
 
-#define ZT_SETSTR(s,v) Utils::scopy((s), sizeof(s), v)
+#define ZT_SETSTR(s, v) Utils::scopy((s), sizeof(s), v)
 
 
 // Increments and decrements a counter based on object create/destroy
 // Increments and decrements a counter based on object create/destroy
 class LifeCycleTracker
 class LifeCycleTracker
@@ -233,7 +233,7 @@ static bool ZTT_deepCompareCertificateIdentities(const ZT_Certificate_Identity *
 {
 {
 	if (a == nullptr)
 	if (a == nullptr)
 		return (b == nullptr);
 		return (b == nullptr);
-	if ( ((a->identity == nullptr) != (b->identity == nullptr)) || ((a->locator == nullptr) != (b->locator == nullptr)) )
+	if (((a->identity == nullptr) != (b->identity == nullptr)) || ((a->locator == nullptr) != (b->locator == nullptr)))
 		return false;
 		return false;
 	if ((a->identity) && (*reinterpret_cast<const Identity *>(a->identity) != *reinterpret_cast<const Identity *>(b->identity)))
 	if ((a->identity) && (*reinterpret_cast<const Identity *>(a->identity) != *reinterpret_cast<const Identity *>(b->identity)))
 		return false;
 		return false;
@@ -277,7 +277,8 @@ static bool ZTT_deepCompareCertificates(const Certificate &a, const Certificate
 		(a.subject.uniqueIdProofSignatureSize != b.subject.uniqueIdProofSignatureSize) ||
 		(a.subject.uniqueIdProofSignatureSize != b.subject.uniqueIdProofSignatureSize) ||
 		(a.maxPathLength != b.maxPathLength) ||
 		(a.maxPathLength != b.maxPathLength) ||
 		(a.signatureSize != b.signatureSize)
 		(a.signatureSize != b.signatureSize)
-		) return false;
+		)
+		return false;
 
 
 	if ((a.subject.uniqueId == nullptr) != (b.subject.uniqueId == nullptr))
 	if ((a.subject.uniqueId == nullptr) != (b.subject.uniqueId == nullptr))
 		return false;
 		return false;
@@ -301,12 +302,12 @@ static bool ZTT_deepCompareCertificates(const Certificate &a, const Certificate
 	if ((a.issuer != nullptr) && (*reinterpret_cast<const Identity *>(a.issuer) != *reinterpret_cast<const Identity *>(b.issuer)))
 	if ((a.issuer != nullptr) && (*reinterpret_cast<const Identity *>(a.issuer) != *reinterpret_cast<const Identity *>(b.issuer)))
 		return false;
 		return false;
 
 
-	for(unsigned int i=0;i<a.subject.identityCount;++i) {
+	for (unsigned int i = 0; i < a.subject.identityCount; ++i) {
 		if (!ZTT_deepCompareCertificateIdentities(a.subject.identities + i, b.subject.identities + i))
 		if (!ZTT_deepCompareCertificateIdentities(a.subject.identities + i, b.subject.identities + i))
 			return false;
 			return false;
 	}
 	}
 
 
-	for(unsigned int i=0;i<a.subject.networkCount;++i) {
+	for (unsigned int i = 0; i < a.subject.networkCount; ++i) {
 		if (a.subject.networks[i].id != b.subject.networks[i].id)
 		if (a.subject.networks[i].id != b.subject.networks[i].id)
 			return false;
 			return false;
 		if (a.subject.networks[i].controller.address != b.subject.networks[i].controller.address)
 		if (a.subject.networks[i].controller.address != b.subject.networks[i].controller.address)
@@ -315,7 +316,7 @@ static bool ZTT_deepCompareCertificates(const Certificate &a, const Certificate
 			return false;
 			return false;
 	}
 	}
 
 
-	for(unsigned int i=0;i<a.subject.certificateCount;++i) {
+	for (unsigned int i = 0; i < a.subject.certificateCount; ++i) {
 		if ((!a.subject.certificates) || (!b.subject.certificates))
 		if ((!a.subject.certificates) || (!b.subject.certificates))
 			return false;
 			return false;
 		if ((!a.subject.certificates[i]) || (!b.subject.certificates[i]))
 		if ((!a.subject.certificates[i]) || (!b.subject.certificates[i]))
@@ -324,7 +325,7 @@ static bool ZTT_deepCompareCertificates(const Certificate &a, const Certificate
 			return false;
 			return false;
 	}
 	}
 
 
-	for(unsigned int i=0;i<a.subject.updateURLCount; ++i) {
+	for (unsigned int i = 0; i < a.subject.updateURLCount; ++i) {
 		if ((!a.subject.updateURLs) || (!b.subject.updateURLs))
 		if ((!a.subject.updateURLs) || (!b.subject.updateURLs))
 			return false;
 			return false;
 		if ((!a.subject.updateURLs[i]) || (!b.subject.updateURLs[i]))
 		if ((!a.subject.updateURLs[i]) || (!b.subject.updateURLs[i]))
@@ -354,14 +355,14 @@ extern "C" const char *ZTT_general()
 			return "__BYTE_ORDER incorrectly defined";
 			return "__BYTE_ORDER incorrectly defined";
 		}
 		}
 #else
 #else
-		if (endian != 0x0102030405060708ULL) {
-			ZT_T_PRINTF("[general] Error: __BYTE_ORDER == __BIG_ENDIAN but byte order is actually %.16llx" ZT_EOL_S,endian);
-			return "__BYTE_ORDER incorrectly defined";
-		}
+			if (endian != 0x0102030405060708ULL) {
+				ZT_T_PRINTF("[general] Error: __BYTE_ORDER == __BIG_ENDIAN but byte order is actually %.16llx" ZT_EOL_S,endian);
+				return "__BYTE_ORDER incorrectly defined";
+			}
 #endif
 #endif
 
 
 #ifdef ZT_NO_UNALIGNED_ACCESS
 #ifdef ZT_NO_UNALIGNED_ACCESS
-		ZT_T_PRINTF("[general] Platform is %d bit, %s-endian (%.16llx), unaligned variable access not allowed" ZT_EOL_S,(int)(sizeof(void *) * 8),ZT_ENDIAN_S,endian);
+			ZT_T_PRINTF("[general] Platform is %d bit, %s-endian (%.16llx), unaligned variable access not allowed" ZT_EOL_S,(int)(sizeof(void *) * 8),ZT_ENDIAN_S,endian);
 #else
 #else
 		ZT_T_PRINTF("[general] Platform is %d bit, %s-endian (%.16llx), unaligned variable access allowed" ZT_EOL_S, (int)(sizeof(void *) * 8), ZT_ENDIAN_S, endian);
 		ZT_T_PRINTF("[general] Platform is %d bit, %s-endian (%.16llx), unaligned variable access allowed" ZT_EOL_S, (int)(sizeof(void *) * 8), ZT_ENDIAN_S, endian);
 #endif
 #endif
@@ -379,17 +380,43 @@ extern "C" const char *ZTT_general()
 			ZT_T_PRINTF("OK" ZT_EOL_S);
 			ZT_T_PRINTF("OK" ZT_EOL_S);
 		}
 		}
 
 
+		{
+			ZT_T_PRINTF("[general] Sanity checking memory zero and copy functions... ");
+			for (unsigned long k = 0; k < 1000; ++k) {
+				uint8_t *tmp = new uint8_t[131072];
+				uint8_t *tmp2 = new uint8_t[131072];
+				for (unsigned long i = 0; i < 131072; ++i) {
+					tmp[i] = (uint8_t)i;
+					tmp2[i] = 0;
+				}
+				unsigned long l = ((unsigned long)Utils::random() % 131072) + 1;
+				Utils::copy(tmp2, tmp, l);
+				if (memcmp(tmp2, tmp, l) != 0) {
+					ZT_T_PRINTF("FAILED (copy)" ZT_EOL_S);
+					return "memory copy";
+				}
+				Utils::zero(tmp2, l);
+				for (unsigned long i = 0; i < l; ++i) {
+					if (tmp2[i] != 0) {
+						ZT_T_PRINTF("FAILED (zero)" ZT_EOL_S);
+						return "memory zero";
+					}
+				}
+			}
+			ZT_T_PRINTF("OK" ZT_EOL_S);
+		}
+
 #ifdef ZT_ARCH_X64
 #ifdef ZT_ARCH_X64
 		ZT_T_PRINTF("[general] X64 CPUID: aes=%d avx=%d avx2=%d avx512f=%d fsrm=%d rdrand=%d sha=%d vaes=%d vpclmulqdq=%d" ZT_EOL_S,
 		ZT_T_PRINTF("[general] X64 CPUID: aes=%d avx=%d avx2=%d avx512f=%d fsrm=%d rdrand=%d sha=%d vaes=%d vpclmulqdq=%d" ZT_EOL_S,
-			Utils::CPUID.aes,
-			Utils::CPUID.avx,
-			Utils::CPUID.avx2,
-			Utils::CPUID.avx512f,
-			Utils::CPUID.fsrm,
-			Utils::CPUID.rdrand,
-			Utils::CPUID.sha,
-			Utils::CPUID.vaes,
-			Utils::CPUID.vpclmulqdq);
+		            Utils::CPUID.aes,
+		            Utils::CPUID.avx,
+		            Utils::CPUID.avx2,
+		            Utils::CPUID.avx512f,
+		            Utils::CPUID.fsrm,
+		            Utils::CPUID.rdrand,
+		            Utils::CPUID.sha,
+		            Utils::CPUID.vaes,
+		            Utils::CPUID.vpclmulqdq);
 #endif
 #endif
 
 
 		{
 		{
@@ -472,36 +499,36 @@ extern "C" const char *ZTT_general()
 				return "Utils::storeMachineEndian() broken";
 				return "Utils::storeMachineEndian() broken";
 			}
 			}
 #else
 #else
-			if (Utils::loadMachineEndian<uint64_t>(&a) != 0x0807060504030201ULL) {
-				ZT_T_PRINTF("FAILED (loadMachineEndian)" ZT_EOL_S);
-				return "Utils::loadMachineEndian() broken";
-			}
-			if (Utils::loadMachineEndian<uint32_t>(&b) != 0x04030201) {
-				ZT_T_PRINTF("FAILED (loadMachineEndian)" ZT_EOL_S);
-				return "Utils::loadMachineEndian() broken";
-			}
-			if (Utils::loadMachineEndian<uint16_t>(&c) != 0x0201) {
-				ZT_T_PRINTF("FAILED (loadMachineEndian)" ZT_EOL_S);
-				return "Utils::loadMachineEndian() broken";
-			}
-			Utils::zero<sizeof(t)>(t);
-			Utils::storeMachineEndian<uint64_t>(t,0x0807060504030201ULL);
-			if (t[0] != 8) {
-				ZT_T_PRINTF("FAILED (storeMachineEndian)" ZT_EOL_S);
-				return "Utils::storeMachineEndian() broken";
-			}
-			Utils::zero<sizeof(t)>(t);
-			Utils::storeMachineEndian<uint32_t>(t,0x04030201);
-			if (t[0] != 4) {
-				ZT_T_PRINTF("FAILED (storeMachineEndian)" ZT_EOL_S);
-				return "Utils::storeMachineEndian() broken";
-			}
-			Utils::zero<sizeof(t)>(t);
-			Utils::storeMachineEndian<uint16_t>(t,0x0201);
-			if (t[0] != 2) {
-				ZT_T_PRINTF("FAILED (storeMachineEndian)" ZT_EOL_S);
-				return "Utils::storeMachineEndian() broken";
-			}
+				if (Utils::loadMachineEndian<uint64_t>(&a) != 0x0807060504030201ULL) {
+					ZT_T_PRINTF("FAILED (loadMachineEndian)" ZT_EOL_S);
+					return "Utils::loadMachineEndian() broken";
+				}
+				if (Utils::loadMachineEndian<uint32_t>(&b) != 0x04030201) {
+					ZT_T_PRINTF("FAILED (loadMachineEndian)" ZT_EOL_S);
+					return "Utils::loadMachineEndian() broken";
+				}
+				if (Utils::loadMachineEndian<uint16_t>(&c) != 0x0201) {
+					ZT_T_PRINTF("FAILED (loadMachineEndian)" ZT_EOL_S);
+					return "Utils::loadMachineEndian() broken";
+				}
+				Utils::zero<sizeof(t)>(t);
+				Utils::storeMachineEndian<uint64_t>(t,0x0807060504030201ULL);
+				if (t[0] != 8) {
+					ZT_T_PRINTF("FAILED (storeMachineEndian)" ZT_EOL_S);
+					return "Utils::storeMachineEndian() broken";
+				}
+				Utils::zero<sizeof(t)>(t);
+				Utils::storeMachineEndian<uint32_t>(t,0x04030201);
+				if (t[0] != 4) {
+					ZT_T_PRINTF("FAILED (storeMachineEndian)" ZT_EOL_S);
+					return "Utils::storeMachineEndian() broken";
+				}
+				Utils::zero<sizeof(t)>(t);
+				Utils::storeMachineEndian<uint16_t>(t,0x0201);
+				if (t[0] != 2) {
+					ZT_T_PRINTF("FAILED (storeMachineEndian)" ZT_EOL_S);
+					return "Utils::storeMachineEndian() broken";
+				}
 #endif
 #endif
 			ZT_T_PRINTF("OK" ZT_EOL_S);
 			ZT_T_PRINTF("OK" ZT_EOL_S);
 		}
 		}
@@ -1113,7 +1140,7 @@ extern "C" const char *ZTT_crypto()
 			ZT_T_PRINTF("OK %s" ZT_EOL_S, tmp);
 			ZT_T_PRINTF("OK %s" ZT_EOL_S, tmp);
 
 
 			ZT_T_PRINTF("  Create and sign certificate... ");
 			ZT_T_PRINTF("  Create and sign certificate... ");
-			SharedPtr<Certificate> cert(new Certificate());
+			SharedPtr< Certificate > cert(new Certificate());
 			cert->subject.timestamp = now();
 			cert->subject.timestamp = now();
 			cert->addSubjectIdentity(testSubjectId);
 			cert->addSubjectIdentity(testSubjectId);
 			cert->addSubjectNetwork(12345, testSubjectId.fingerprint());
 			cert->addSubjectNetwork(12345, testSubjectId.fingerprint());
@@ -1133,7 +1160,7 @@ extern "C" const char *ZTT_crypto()
 			cert->timestamp = cert->subject.timestamp;
 			cert->timestamp = cert->subject.timestamp;
 			cert->validity[0] = 0;
 			cert->validity[0] = 0;
 			cert->validity[1] = 9223372036854775807LL;
 			cert->validity[1] = 9223372036854775807LL;
-			Utils::copy<sizeof(ZT_Certificate_Name)>(&cert->issuerName, &cert->subject.name);
+			Utils::copy< sizeof(ZT_Certificate_Name) >(&cert->issuerName, &cert->subject.name);
 			cert->setSubjectUniqueId(uniqueId, uniqueIdPrivate);
 			cert->setSubjectUniqueId(uniqueId, uniqueIdPrivate);
 			cert->sign(testIssuerId);
 			cert->sign(testIssuerId);
 			Vector< uint8_t > enc(cert->encode());
 			Vector< uint8_t > enc(cert->encode());
@@ -1147,7 +1174,7 @@ extern "C" const char *ZTT_crypto()
 			ZT_T_PRINTF("OK" ZT_EOL_S);
 			ZT_T_PRINTF("OK" ZT_EOL_S);
 
 
 			ZT_T_PRINTF("  Test certificate decode from marshaled format... ");
 			ZT_T_PRINTF("  Test certificate decode from marshaled format... ");
-			SharedPtr<Certificate> cert2(new Certificate());
+			SharedPtr< Certificate > cert2(new Certificate());
 			if (!cert2->decode(enc.data(), (unsigned int)enc.size())) {
 			if (!cert2->decode(enc.data(), (unsigned int)enc.size())) {
 				ZT_T_PRINTF("FAILED (decode)" ZT_EOL_S);
 				ZT_T_PRINTF("FAILED (decode)" ZT_EOL_S);
 				return "Certificate decode";
 				return "Certificate decode";
@@ -1163,7 +1190,7 @@ extern "C" const char *ZTT_crypto()
 			ZT_T_PRINTF("OK" ZT_EOL_S);
 			ZT_T_PRINTF("OK" ZT_EOL_S);
 
 
 			ZT_T_PRINTF("  Test certificate copy/construct... ");
 			ZT_T_PRINTF("  Test certificate copy/construct... ");
-			SharedPtr<Certificate> cert3(new Certificate(*cert2));
+			SharedPtr< Certificate > cert3(new Certificate(*cert2));
 			if (!ZTT_deepCompareCertificates(*cert2, *cert3)) {
 			if (!ZTT_deepCompareCertificates(*cert2, *cert3)) {
 				ZT_T_PRINTF("FAILED (compare copy with original)" ZT_EOL_S);
 				ZT_T_PRINTF("FAILED (compare copy with original)" ZT_EOL_S);
 				return "Certificate copy";
 				return "Certificate copy";

+ 12 - 8
pkg/zerotier/certificate.go

@@ -491,24 +491,28 @@ func NewCertificateSubjectUniqueId(uniqueIdType int) (id []byte, priv []byte, er
 
 
 // NewCertificateCSR creates a new certificate signing request (CSR) from a certificate subject and optional unique ID.
 // NewCertificateCSR creates a new certificate signing request (CSR) from a certificate subject and optional unique ID.
 func NewCertificateCSR(subject *CertificateSubject, uniqueId []byte, uniqueIdPrivate []byte) ([]byte, error) {
 func NewCertificateCSR(subject *CertificateSubject, uniqueId []byte, uniqueIdPrivate []byte) ([]byte, error) {
-	var tmp Certificate
-	tmp.Subject = *subject
-	ctmp := tmp.CCertificate()
-	if ctmp == nil {
-		return nil, ErrInternal
-	}
-	ccert := (*C.ZT_Certificate)(ctmp.C)
 	var uid unsafe.Pointer
 	var uid unsafe.Pointer
 	var uidp unsafe.Pointer
 	var uidp unsafe.Pointer
 	if len(uniqueId) > 0 && len(uniqueIdPrivate) > 0 {
 	if len(uniqueId) > 0 && len(uniqueIdPrivate) > 0 {
 		uid = unsafe.Pointer(&uniqueId[0])
 		uid = unsafe.Pointer(&uniqueId[0])
 		uidp = unsafe.Pointer(&uniqueIdPrivate[0])
 		uidp = unsafe.Pointer(&uniqueIdPrivate[0])
 	}
 	}
+
+	var tmp Certificate
+	tmp.Subject = *subject
+	ctmp := tmp.CCertificate()
+	if ctmp == nil {
+		return nil, ErrInternal
+	}
+
 	var csr [16384]byte
 	var csr [16384]byte
 	csrSize := C.int(16384)
 	csrSize := C.int(16384)
-	rv := int(C.ZT_Certificate_newCSR(&(ccert.subject), uid, C.int(len(uniqueId)), uidp, C.int(len(uniqueIdPrivate)), unsafe.Pointer(&csr[0]), &csrSize))
+	cc := (*C.ZT_Certificate)(ctmp.C)
+	rv := int(C.ZT_Certificate_newCSR(&(cc.subject), uid, C.int(len(uniqueId)), uidp, C.int(len(uniqueIdPrivate)), unsafe.Pointer(&csr[0]), &csrSize))
 	if rv != 0 {
 	if rv != 0 {
 		return nil, fmt.Errorf("newCSR error %d", rv)
 		return nil, fmt.Errorf("newCSR error %d", rv)
 	}
 	}
+	ctmp = nil
+
 	return append(make([]byte, 0, int(csrSize)), csr[0:int(csrSize)]...), nil
 	return append(make([]byte, 0, int(csrSize)), csr[0:int(csrSize)]...), nil
 }
 }