diff --git a/core/Certificate.cpp b/core/Certificate.cpp index 4d58ae2dc..405778402 100644 --- a/core/Certificate.cpp +++ b/core/Certificate.cpp @@ -24,10 +24,12 @@ Certificate::Certificate() noexcept Utils::zero< sizeof(ZT_Certificate) >(sup); } -Certificate::Certificate(const ZT_Certificate &apiCert) +Certificate::Certificate(const ZT_Certificate &apiCert) : + Certificate() { *this = apiCert; } -Certificate::Certificate(const Certificate &cert) +Certificate::Certificate(const Certificate &cert) : + Certificate() { *this = cert; } 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$"); for (unsigned int i = 0; i < cnt; ++i) { const Vector< uint8_t > &identityData = d[Dictionary::arraySubscript(tmp, sizeof(tmp), "s.i$.i", i)]; - if (identityData.empty()) { + if (identityData.empty()) return false; - } Identity id; - if (id.unmarshal(identityData.data(), (unsigned int)identityData.size()) <= 0) { + if (id.unmarshal(identityData.data(), (unsigned int)identityData.size()) <= 0) return false; - } const Vector< uint8_t > &locatorData = d[Dictionary::arraySubscript(tmp, sizeof(tmp), "s.i$.l", i)]; if (!locatorData.empty()) { Locator loc; - if (loc.unmarshal(locatorData.data(), (unsigned int)locatorData.size()) <= 0) { + if (loc.unmarshal(locatorData.data(), (unsigned int)locatorData.size()) <= 0) return false; - } this->addSubjectIdentity(id, loc); } else { 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) { 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)]; - if ((nwid == 0) || (fingerprintData.empty())) { + if ((nwid == 0) || (fingerprintData.empty())) return false; - } Fingerprint fp; - if (fp.unmarshal(fingerprintData.data(), (unsigned int)fingerprintData.size()) <= 0) { + if (fp.unmarshal(fingerprintData.data(), (unsigned int)fingerprintData.size()) <= 0) return false; - } this->addSubjectNetwork(nwid, fp); } cnt = (unsigned int)d.getUI("s.c$"); for (unsigned int i = 0; i < cnt; ++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; - } this->addSubjectCertificate(serial.data()); } @@ -425,15 +421,6 @@ bool Certificate::decode(const void *const data, const unsigned int len) 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) { 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.uniqueId[0] != ZT_CERTIFICATE_UNIQUE_ID_TYPE_NIST_P_384)) 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; - tmp.encode(enc); + d.encode(enc); uint8_t h[ZT_SHA384_DIGEST_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)) return ZT_CERTIFICATE_ERROR_INVALID_UNIQUE_ID_PROOF; } else if (this->subject.uniqueIdSize > 0) { @@ -519,6 +507,45 @@ ZT_CertificateError Certificate::verify() const 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(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(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(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() { ZT_Certificate *const sup = this; @@ -620,16 +647,20 @@ int ZT_Certificate_newSubjectUniqueId( void *uniqueIdPrivate, 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(uniqueId), reinterpret_cast(uniqueIdPrivate)); - return ZT_RESULT_OK; + 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(uniqueId), reinterpret_cast(uniqueIdPrivate)); + return ZT_RESULT_OK; + } + return ZT_RESULT_ERROR_BAD_PARAMETER; + } catch (...) { + return ZT_RESULT_FATAL_ERROR_INTERNAL; } - return ZT_RESULT_ERROR_BAD_PARAMETER; } int ZT_Certificate_newCSR( @@ -641,20 +672,18 @@ int ZT_Certificate_newCSR( void *csr, 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(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; - if (!c.setSubjectUniqueId(reinterpret_cast(uniqueId), reinterpret_cast(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( @@ -663,22 +692,21 @@ int ZT_Certificate_sign( void *signedCert, int *signedCertSize) { - if (!cert) - return ZT_RESULT_ERROR_BAD_PARAMETER; - try { - const ZeroTier::ScopedPtr< ZeroTier::Certificate > c(new ZeroTier::Certificate(*cert)); - if (!c->sign(*reinterpret_cast(signer))) + if (!cert) + return ZT_RESULT_ERROR_BAD_PARAMETER; + ZeroTier::Certificate c(*cert); + if (!c.sign(*reinterpret_cast(signer))) 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) return ZT_RESULT_ERROR_BAD_PARAMETER; ZeroTier::Utils::copy(signedCert, enc.data(), (unsigned int)enc.size()); *signedCertSize = (int)enc.size(); return ZT_RESULT_OK; - } catch ( ... ) { + } catch (...) { return ZT_RESULT_FATAL_ERROR_INTERNAL; } } @@ -717,15 +745,19 @@ int ZT_Certificate_encode( void *encoded, 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) @@ -752,8 +784,10 @@ const ZT_Certificate *ZT_Certificate_clone(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 (...) {} } } diff --git a/core/Certificate.hpp b/core/Certificate.hpp index 671605448..bbeff0d62 100644 --- a/core/Certificate.hpp +++ b/core/Certificate.hpp @@ -145,13 +145,6 @@ public: */ 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). * @@ -170,6 +163,18 @@ public: */ 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 * diff --git a/core/Tests.cpp b/core/Tests.cpp index 0052fdd52..b2e76f8a2 100644 --- a/core/Tests.cpp +++ b/core/Tests.cpp @@ -195,7 +195,7 @@ static const C25519TestVector C25519_TEST_VECTORS[ZT_NUM_C25519_TEST_VECTORS] = #define ZT_ENDIAN_S "big" #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 class LifeCycleTracker @@ -233,7 +233,7 @@ static bool ZTT_deepCompareCertificateIdentities(const ZT_Certificate_Identity * { if (a == 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; if ((a->identity) && (*reinterpret_cast(a->identity) != *reinterpret_cast(b->identity))) return false; @@ -277,7 +277,8 @@ static bool ZTT_deepCompareCertificates(const Certificate &a, const Certificate (a.subject.uniqueIdProofSignatureSize != b.subject.uniqueIdProofSignatureSize) || (a.maxPathLength != b.maxPathLength) || (a.signatureSize != b.signatureSize) - ) return false; + ) + return false; if ((a.subject.uniqueId == nullptr) != (b.subject.uniqueId == nullptr)) return false; @@ -301,12 +302,12 @@ static bool ZTT_deepCompareCertificates(const Certificate &a, const Certificate if ((a.issuer != nullptr) && (*reinterpret_cast(a.issuer) != *reinterpret_cast(b.issuer))) return false; - for(unsigned int i=0;i(&a) != 0x0807060504030201ULL) { - ZT_T_PRINTF("FAILED (loadMachineEndian)" ZT_EOL_S); - return "Utils::loadMachineEndian() broken"; - } - if (Utils::loadMachineEndian(&b) != 0x04030201) { - ZT_T_PRINTF("FAILED (loadMachineEndian)" ZT_EOL_S); - return "Utils::loadMachineEndian() broken"; - } - if (Utils::loadMachineEndian(&c) != 0x0201) { - ZT_T_PRINTF("FAILED (loadMachineEndian)" ZT_EOL_S); - return "Utils::loadMachineEndian() broken"; - } - Utils::zero(t); - Utils::storeMachineEndian(t,0x0807060504030201ULL); - if (t[0] != 8) { - ZT_T_PRINTF("FAILED (storeMachineEndian)" ZT_EOL_S); - return "Utils::storeMachineEndian() broken"; - } - Utils::zero(t); - Utils::storeMachineEndian(t,0x04030201); - if (t[0] != 4) { - ZT_T_PRINTF("FAILED (storeMachineEndian)" ZT_EOL_S); - return "Utils::storeMachineEndian() broken"; - } - Utils::zero(t); - Utils::storeMachineEndian(t,0x0201); - if (t[0] != 2) { - ZT_T_PRINTF("FAILED (storeMachineEndian)" ZT_EOL_S); - return "Utils::storeMachineEndian() broken"; - } + if (Utils::loadMachineEndian(&a) != 0x0807060504030201ULL) { + ZT_T_PRINTF("FAILED (loadMachineEndian)" ZT_EOL_S); + return "Utils::loadMachineEndian() broken"; + } + if (Utils::loadMachineEndian(&b) != 0x04030201) { + ZT_T_PRINTF("FAILED (loadMachineEndian)" ZT_EOL_S); + return "Utils::loadMachineEndian() broken"; + } + if (Utils::loadMachineEndian(&c) != 0x0201) { + ZT_T_PRINTF("FAILED (loadMachineEndian)" ZT_EOL_S); + return "Utils::loadMachineEndian() broken"; + } + Utils::zero(t); + Utils::storeMachineEndian(t,0x0807060504030201ULL); + if (t[0] != 8) { + ZT_T_PRINTF("FAILED (storeMachineEndian)" ZT_EOL_S); + return "Utils::storeMachineEndian() broken"; + } + Utils::zero(t); + Utils::storeMachineEndian(t,0x04030201); + if (t[0] != 4) { + ZT_T_PRINTF("FAILED (storeMachineEndian)" ZT_EOL_S); + return "Utils::storeMachineEndian() broken"; + } + Utils::zero(t); + Utils::storeMachineEndian(t,0x0201); + if (t[0] != 2) { + ZT_T_PRINTF("FAILED (storeMachineEndian)" ZT_EOL_S); + return "Utils::storeMachineEndian() broken"; + } #endif 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(" Create and sign certificate... "); - SharedPtr cert(new Certificate()); + SharedPtr< Certificate > cert(new Certificate()); cert->subject.timestamp = now(); cert->addSubjectIdentity(testSubjectId); cert->addSubjectNetwork(12345, testSubjectId.fingerprint()); @@ -1133,7 +1160,7 @@ extern "C" const char *ZTT_crypto() cert->timestamp = cert->subject.timestamp; cert->validity[0] = 0; cert->validity[1] = 9223372036854775807LL; - Utils::copy(&cert->issuerName, &cert->subject.name); + Utils::copy< sizeof(ZT_Certificate_Name) >(&cert->issuerName, &cert->subject.name); cert->setSubjectUniqueId(uniqueId, uniqueIdPrivate); cert->sign(testIssuerId); 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(" Test certificate decode from marshaled format... "); - SharedPtr cert2(new Certificate()); + SharedPtr< Certificate > cert2(new Certificate()); if (!cert2->decode(enc.data(), (unsigned int)enc.size())) { ZT_T_PRINTF("FAILED (decode)" ZT_EOL_S); return "Certificate decode"; @@ -1163,7 +1190,7 @@ extern "C" const char *ZTT_crypto() ZT_T_PRINTF("OK" ZT_EOL_S); ZT_T_PRINTF(" Test certificate copy/construct... "); - SharedPtr cert3(new Certificate(*cert2)); + SharedPtr< Certificate > cert3(new Certificate(*cert2)); if (!ZTT_deepCompareCertificates(*cert2, *cert3)) { ZT_T_PRINTF("FAILED (compare copy with original)" ZT_EOL_S); return "Certificate copy"; diff --git a/pkg/zerotier/certificate.go b/pkg/zerotier/certificate.go index 31cf13819..6e2068596 100644 --- a/pkg/zerotier/certificate.go +++ b/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. 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 uidp unsafe.Pointer if len(uniqueId) > 0 && len(uniqueIdPrivate) > 0 { uid = unsafe.Pointer(&uniqueId[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 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 { return nil, fmt.Errorf("newCSR error %d", rv) } + ctmp = nil + return append(make([]byte, 0, int(csrSize)), csr[0:int(csrSize)]...), nil }