mirror of
https://github.com/zerotier/ZeroTierOne.git
synced 2025-06-05 20:13:44 +02:00
Some cleanup, and fix a really obscure bug in Certificate.
This commit is contained in:
parent
8b1c691a5e
commit
1eacbdf374
13 changed files with 367 additions and 268 deletions
|
@ -29,6 +29,12 @@ func TestCertificate() bool {
|
|||
return false
|
||||
}
|
||||
|
||||
uniqueId, uniqueIdPrivate, err := zerotier.NewCertificateSubjectUniqueId(zerotier.CertificateUniqueIdTypeNistP384)
|
||||
if err != nil {
|
||||
fmt.Printf(" Error generating unique ID: %s", err.Error())
|
||||
return false
|
||||
}
|
||||
|
||||
var c zerotier.Certificate
|
||||
|
||||
c.SerialNo = make([]byte, 48)
|
||||
|
@ -39,6 +45,7 @@ func TestCertificate() bool {
|
|||
c.Timestamp = 5678
|
||||
c.Validity[0] = 1010
|
||||
c.Validity[1] = 2020
|
||||
|
||||
c.Subject.Timestamp = 31337
|
||||
c.Subject.Identities = append(c.Subject.Identities, zerotier.CertificateIdentity{
|
||||
Identity: id,
|
||||
|
@ -65,8 +72,8 @@ func TestCertificate() bool {
|
|||
c.Subject.Name.Email = "j"
|
||||
c.Subject.Name.URL = "k"
|
||||
c.Subject.Name.Host = "l"
|
||||
c.Subject.UniqueID = []byte("asdf")
|
||||
c.Subject.UniqueIDProofSignature = []byte("ghij")
|
||||
c.Subject.UniqueID = uniqueId
|
||||
|
||||
c.Issuer = id
|
||||
c.IssuerName.SerialNo = "m"
|
||||
c.IssuerName.CommonName = "n"
|
||||
|
@ -80,6 +87,7 @@ func TestCertificate() bool {
|
|||
c.IssuerName.Email = "v"
|
||||
c.IssuerName.URL = "w"
|
||||
c.IssuerName.Host = "x"
|
||||
|
||||
c.ExtendedAttributes = c.SerialNo
|
||||
c.MaxPathLength = 9999
|
||||
c.Signature = []byte("qwerty")
|
||||
|
@ -96,9 +104,8 @@ func TestCertificate() bool {
|
|||
return false
|
||||
}
|
||||
|
||||
j, _ := json.MarshalIndent(c, "", " ")
|
||||
j2, _ := json.MarshalIndent(c2, "", " ")
|
||||
|
||||
j, _ := json.Marshal(c)
|
||||
j2, _ := json.Marshal(c2)
|
||||
if !bytes.Equal(j, j2) {
|
||||
j, _ = json.MarshalIndent(c, "", " ")
|
||||
fmt.Print(" Deep equality test failed: certificates do not match! (see dumps below)\n\n")
|
||||
|
@ -130,5 +137,28 @@ func TestCertificate() bool {
|
|||
}
|
||||
fmt.Println("OK")
|
||||
|
||||
fmt.Printf("Checking certificate CSR sign/verify... ")
|
||||
csr, err := zerotier.NewCertificateCSR(&c.Subject, uniqueId, uniqueIdPrivate)
|
||||
if err != nil {
|
||||
fmt.Printf("CSR generate FAILED (%s)\n", err.Error())
|
||||
return false
|
||||
}
|
||||
fmt.Printf("CSR size: %d ",len(csr))
|
||||
csr2, err := zerotier.NewCertificateFromBytes(csr, false)
|
||||
if err != nil {
|
||||
fmt.Printf("CSR decode FAILED (%s)\n", err.Error())
|
||||
return false
|
||||
}
|
||||
signedCert, err := csr2.Sign(id)
|
||||
if err != nil {
|
||||
fmt.Printf("CSR sign FAILED (%s)\n", err.Error())
|
||||
return false
|
||||
}
|
||||
if len(signedCert.Signature) == 0 {
|
||||
fmt.Println("CSR sign FAILED (no signature found)", err.Error())
|
||||
return false
|
||||
}
|
||||
fmt.Println("OK")
|
||||
|
||||
return true
|
||||
}
|
||||
|
|
|
@ -14,6 +14,7 @@
|
|||
#include "Certificate.hpp"
|
||||
#include "SHA512.hpp"
|
||||
#include "ECC384.hpp"
|
||||
#include "ScopedPtr.hpp"
|
||||
|
||||
namespace ZeroTier {
|
||||
|
||||
|
@ -24,10 +25,7 @@ Certificate::Certificate() noexcept
|
|||
}
|
||||
|
||||
Certificate::Certificate(const ZT_Certificate &apiCert)
|
||||
{
|
||||
ZT_Certificate *const sup = this;
|
||||
Utils::copy< sizeof(ZT_Certificate) >(sup, &apiCert);
|
||||
}
|
||||
{ *this = apiCert; }
|
||||
|
||||
Certificate::Certificate(const Certificate &cert)
|
||||
{ *this = cert; }
|
||||
|
@ -62,22 +60,30 @@ Certificate &Certificate::operator=(const ZT_Certificate &cert)
|
|||
this->signature = nullptr;
|
||||
this->signatureSize = 0;
|
||||
|
||||
for (unsigned int i = 0; i < cert.subject.identityCount; ++i) {
|
||||
if (cert.subject.identities[i].identity) {
|
||||
if (cert.subject.identities[i].locator)
|
||||
addSubjectIdentity(*reinterpret_cast<const Identity *>(cert.subject.identities[i].identity), *reinterpret_cast<const Locator *>(cert.subject.identities[i].locator));
|
||||
else addSubjectIdentity(*reinterpret_cast<const Identity *>(cert.subject.identities[i].identity));
|
||||
if (cert.subject.identities) {
|
||||
for (unsigned int i = 0; i < cert.subject.identityCount; ++i) {
|
||||
if (cert.subject.identities[i].identity) {
|
||||
if (cert.subject.identities[i].locator) {
|
||||
addSubjectIdentity(*reinterpret_cast<const Identity *>(cert.subject.identities[i].identity), *reinterpret_cast<const Locator *>(cert.subject.identities[i].locator));
|
||||
} else {
|
||||
addSubjectIdentity(*reinterpret_cast<const Identity *>(cert.subject.identities[i].identity));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (unsigned int i = 0; i < cert.subject.networkCount; ++i) {
|
||||
if (cert.subject.networks[i].id)
|
||||
addSubjectNetwork(cert.subject.networks[i].id, cert.subject.networks[i].controller);
|
||||
if (cert.subject.networks) {
|
||||
for (unsigned int i = 0; i < cert.subject.networkCount; ++i) {
|
||||
if (cert.subject.networks[i].id)
|
||||
addSubjectNetwork(cert.subject.networks[i].id, cert.subject.networks[i].controller);
|
||||
}
|
||||
}
|
||||
|
||||
for (unsigned int i = 0; i < cert.subject.certificateCount; ++i) {
|
||||
if (cert.subject.certificates[i])
|
||||
addSubjectCertificate(cert.subject.certificates[i]);
|
||||
if (cert.subject.certificates) {
|
||||
for (unsigned int i = 0; i < cert.subject.certificateCount; ++i) {
|
||||
if (cert.subject.certificates[i])
|
||||
addSubjectCertificate(cert.subject.certificates[i]);
|
||||
}
|
||||
}
|
||||
|
||||
if (cert.subject.updateURLs) {
|
||||
|
@ -99,8 +105,8 @@ Certificate &Certificate::operator=(const ZT_Certificate &cert)
|
|||
}
|
||||
|
||||
if (cert.issuer) {
|
||||
m_identities.push_back(*reinterpret_cast<const Identity *>(cert.issuer));
|
||||
this->issuer = &(m_identities.back());
|
||||
m_identities.push_front(*reinterpret_cast<const Identity *>(cert.issuer));
|
||||
this->issuer = &(m_identities.front());
|
||||
}
|
||||
|
||||
if ((cert.extendedAttributes) && (cert.extendedAttributesSize > 0)) {
|
||||
|
@ -120,16 +126,16 @@ Certificate &Certificate::operator=(const ZT_Certificate &cert)
|
|||
|
||||
ZT_Certificate_Identity *Certificate::addSubjectIdentity(const Identity &id)
|
||||
{
|
||||
// Enlarge array of ZT_Certificate_Identity structs and set pointer to potentially reallocated array.
|
||||
m_subjectIdentities.resize(++this->subject.identityCount);
|
||||
this->subject.identities = m_subjectIdentities.data();
|
||||
|
||||
// Store a local copy of the actual identity.
|
||||
m_identities.push_back(id);
|
||||
m_identities.push_front(id);
|
||||
m_identities.front().erasePrivateKey();
|
||||
|
||||
// Set ZT_Certificate_Identity struct fields to point to local copy of identity.
|
||||
m_subjectIdentities.back().identity = &(m_identities.back());
|
||||
// Enlarge array of ZT_Certificate_Identity structs and set pointer to potentially reallocated array.
|
||||
m_subjectIdentities.push_back(ZT_Certificate_Identity());
|
||||
m_subjectIdentities.back().identity = &(m_identities.front());
|
||||
m_subjectIdentities.back().locator = nullptr;
|
||||
this->subject.identities = m_subjectIdentities.data();
|
||||
this->subject.identityCount = (unsigned int)m_subjectIdentities.size();
|
||||
|
||||
return &(m_subjectIdentities.back());
|
||||
}
|
||||
|
@ -140,10 +146,10 @@ ZT_Certificate_Identity *Certificate::addSubjectIdentity(const Identity &id, con
|
|||
ZT_Certificate_Identity *const n = addSubjectIdentity(id);
|
||||
|
||||
// Store local copy of locator.
|
||||
m_locators.push_back(loc);
|
||||
m_locators.push_front(loc);
|
||||
|
||||
// Set pointer to stored local copy of locator.
|
||||
n->locator = &(m_locators.back());
|
||||
n->locator = &(m_locators.front());
|
||||
|
||||
return n;
|
||||
}
|
||||
|
@ -164,23 +170,26 @@ ZT_Certificate_Network *Certificate::addSubjectNetwork(const uint64_t id, const
|
|||
void Certificate::addSubjectCertificate(const uint8_t serialNo[ZT_SHA384_DIGEST_SIZE])
|
||||
{
|
||||
// Store local copy of serial in m_serials container.
|
||||
m_serials.push_back(SHA384Hash(serialNo));
|
||||
m_serials.push_front(SHA384Hash(serialNo));
|
||||
|
||||
// Enlarge array of uint8_t pointers, set new pointer to local copy of serial, and set
|
||||
// certificates to point to potentially reallocated array.
|
||||
m_subjectCertificates.resize(++this->subject.certificateCount);
|
||||
m_subjectCertificates.back() = m_serials.back().bytes();
|
||||
m_subjectCertificates.back() = m_serials.front().bytes();
|
||||
this->subject.certificates = m_subjectCertificates.data();
|
||||
}
|
||||
|
||||
void Certificate::addSubjectUpdateUrl(const char *url)
|
||||
{
|
||||
if ((!url) || (!url[0]))
|
||||
return;
|
||||
|
||||
// Store local copy of URL.
|
||||
m_strings.push_back(url);
|
||||
m_strings.push_front(url);
|
||||
|
||||
// Add pointer to local copy to pointer array and update C structure to point to
|
||||
// potentially reallocated array.
|
||||
m_updateUrls.push_back(m_strings.back().c_str());
|
||||
m_updateUrls.push_back(m_strings.front().c_str());
|
||||
this->subject.updateURLs = m_updateUrls.data();
|
||||
this->subject.updateURLCount = (unsigned int)m_updateUrls.size();
|
||||
}
|
||||
|
@ -193,6 +202,28 @@ void Certificate::setExtendedAttributes(const Dictionary &x)
|
|||
this->extendedAttributesSize = (unsigned int)m_extendedAttributes.size();
|
||||
}
|
||||
|
||||
bool Certificate::setSubjectUniqueId(const uint8_t uniqueId[ZT_CERTIFICATE_UNIQUE_ID_TYPE_NIST_P_384_SIZE], const uint8_t uniqueIdPrivate[ZT_CERTIFICATE_UNIQUE_ID_TYPE_NIST_P_384_PRIVATE_SIZE])
|
||||
{
|
||||
m_subjectUniqueId.assign(uniqueId, uniqueId + ZT_CERTIFICATE_UNIQUE_ID_TYPE_NIST_P_384_SIZE);
|
||||
this->subject.uniqueId = m_subjectUniqueId.data();
|
||||
this->subject.uniqueIdSize = ZT_CERTIFICATE_UNIQUE_ID_TYPE_NIST_P_384_SIZE;
|
||||
|
||||
Dictionary d;
|
||||
m_encodeSubject(this->subject, d, true);
|
||||
Vector< uint8_t > enc;
|
||||
d.encode(enc);
|
||||
uint8_t h[ZT_SHA384_DIGEST_SIZE];
|
||||
SHA384(h, enc.data(), (unsigned int)enc.size());
|
||||
|
||||
m_subjectUniqueIdProofSignature.resize(ZT_ECC384_SIGNATURE_SIZE);
|
||||
ECC384ECDSASign(uniqueIdPrivate, h, m_subjectUniqueIdProofSignature.data());
|
||||
|
||||
this->subject.uniqueIdProofSignature = m_subjectUniqueIdProofSignature.data();
|
||||
this->subject.uniqueIdProofSignatureSize = ZT_ECC384_SIGNATURE_SIZE;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
Vector< uint8_t > Certificate::encode(const bool omitSignature) const
|
||||
{
|
||||
Vector< uint8_t > enc;
|
||||
|
@ -204,12 +235,14 @@ Vector< uint8_t > Certificate::encode(const bool omitSignature) const
|
|||
|
||||
if (this->flags != 0)
|
||||
d.add("f", this->flags);
|
||||
d.add("t", (uint64_t)this->timestamp);
|
||||
d.add("v#0", (uint64_t)this->validity[0]);
|
||||
d.add("v#1", (uint64_t)this->validity[1]);
|
||||
if ((this->extendedAttributes) && (this->extendedAttributesSize > 0))
|
||||
d["x"].assign(this->extendedAttributes, this->extendedAttributes + this->extendedAttributesSize);
|
||||
d.add("mP", (uint64_t)this->maxPathLength);
|
||||
if (this->timestamp > 0)
|
||||
d.add("t", (uint64_t)this->timestamp);
|
||||
if (this->validity[0] > 0)
|
||||
d.add("v#0", (uint64_t)this->validity[0]);
|
||||
if (this->validity[1] > 0)
|
||||
d.add("v#1", (uint64_t)this->validity[1]);
|
||||
if (this->maxPathLength > 0)
|
||||
d.add("mP", (uint64_t)this->maxPathLength);
|
||||
|
||||
m_encodeSubject(this->subject, d, false);
|
||||
|
||||
|
@ -244,8 +277,8 @@ Vector< uint8_t > Certificate::encode(const bool omitSignature) const
|
|||
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);
|
||||
if ((!omitSignature) && (this->signature) && (this->signatureSize > 0))
|
||||
d["S"].assign(this->signature, this->signature + this->signatureSize);
|
||||
|
||||
d.encode(enc);
|
||||
return enc;
|
||||
|
@ -253,7 +286,7 @@ Vector< uint8_t > Certificate::encode(const bool omitSignature) const
|
|||
|
||||
bool Certificate::decode(const void *const data, const unsigned int len)
|
||||
{
|
||||
char tmp[256], tmp2[ZT_CERTIFICATE_MAX_STRING_LENGTH + 1];
|
||||
char tmp[32], tmp2[ZT_CERTIFICATE_MAX_STRING_LENGTH + 1];
|
||||
|
||||
Dictionary d;
|
||||
if (!d.decode(data, len))
|
||||
|
@ -271,46 +304,52 @@ 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, "s.i$.i", i)];
|
||||
if (identityData.empty())
|
||||
const Vector< uint8_t > &identityData = d[Dictionary::arraySubscript(tmp, sizeof(tmp), "s.i$.i", i)];
|
||||
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, "s.i$.l", i)];
|
||||
}
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
cnt = (unsigned int)d.getUI("s.n$");
|
||||
cnt = (unsigned int)d.getUI("s.nw$");
|
||||
for (unsigned int i = 0; i < cnt; ++i) {
|
||||
const uint64_t nwid = d.getUI(Dictionary::arraySubscript(tmp, "s.n$.i", i));
|
||||
const Vector< uint8_t > &fingerprintData = d[Dictionary::arraySubscript(tmp, "s.n$.c", i)];
|
||||
if ((nwid == 0) || (fingerprintData.empty()))
|
||||
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())) {
|
||||
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, "s.c$", i)];
|
||||
if (serial.size() != ZT_SHA384_DIGEST_SIZE)
|
||||
const Vector< uint8_t > &serial = d[Dictionary::arraySubscript(tmp, sizeof(tmp), "s.c$", i)];
|
||||
if (serial.size() != ZT_SHA384_DIGEST_SIZE) {
|
||||
return false;
|
||||
}
|
||||
this->addSubjectCertificate(serial.data());
|
||||
}
|
||||
|
||||
cnt = (unsigned int)d.getUI("s.u$");
|
||||
for (unsigned int i = 0; i < cnt; ++i)
|
||||
addSubjectUpdateUrl(d.getS(Dictionary::arraySubscript(tmp, "s.u$", i), tmp, sizeof(tmp)));
|
||||
addSubjectUpdateUrl(d.getS(Dictionary::arraySubscript(tmp, sizeof(tmp), "s.u$", i), tmp2, sizeof(tmp2)));
|
||||
|
||||
d.getS("s.n.sN", this->subject.name.serialNo, sizeof(this->subject.name.serialNo));
|
||||
d.getS("s.n.cN", this->subject.name.commonName, sizeof(this->subject.name.commonName));
|
||||
|
@ -340,8 +379,8 @@ bool Certificate::decode(const void *const data, const unsigned int len)
|
|||
if (!issuerData.empty()) {
|
||||
Identity id;
|
||||
if (id.unmarshal(issuerData.data(), (int)issuerData.size()) > 0) {
|
||||
m_identities.push_back(id);
|
||||
this->issuer = reinterpret_cast<const Identity *>(&(m_identities.back()));
|
||||
m_identities.push_front(id);
|
||||
this->issuer = reinterpret_cast<const Identity *>(&(m_identities.front()));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -360,10 +399,12 @@ bool Certificate::decode(const void *const data, const unsigned int len)
|
|||
|
||||
cnt = (unsigned int)d.getUI("u$");
|
||||
for (unsigned int i = 0; i < cnt; ++i) {
|
||||
const char *const url = d.getS(Dictionary::arraySubscript(tmp, "u$", i), tmp2, sizeof(tmp2));
|
||||
if (url)
|
||||
addSubjectUpdateUrl(tmp2);
|
||||
else return false;
|
||||
const char *const url = d.getS(Dictionary::arraySubscript(tmp, sizeof(tmp), "u$", i), tmp2, sizeof(tmp2));
|
||||
if ((url) && (*url != 0)) {
|
||||
addSubjectUpdateUrl(url);
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
m_extendedAttributes = d["x"];
|
||||
|
@ -372,7 +413,7 @@ bool Certificate::decode(const void *const data, const unsigned int len)
|
|||
this->extendedAttributesSize = (unsigned int)m_extendedAttributes.size();
|
||||
}
|
||||
|
||||
m_signature = d["si"];
|
||||
m_signature = d["S"];
|
||||
if (!m_signature.empty()) {
|
||||
this->signature = m_signature.data();
|
||||
this->signatureSize = (unsigned int)m_signature.size();
|
||||
|
@ -395,16 +436,23 @@ Vector< uint8_t > Certificate::encodeCSR()
|
|||
|
||||
bool Certificate::sign(const Identity &issuer)
|
||||
{
|
||||
Vector< uint8_t > enc(encode(true));
|
||||
m_identities.push_front(issuer);
|
||||
m_identities.front().erasePrivateKey();
|
||||
this->issuer = reinterpret_cast<const ZT_Identity *>(&(m_identities.front()));
|
||||
|
||||
const Vector< uint8_t > enc(encode(true));
|
||||
SHA384(this->serialNo, enc.data(), (unsigned int)enc.size());
|
||||
|
||||
uint8_t sig[ZT_SIGNATURE_BUFFER_SIZE];
|
||||
const unsigned int sigSize = issuer.sign(enc.data(), (unsigned int)enc.size(), sig, sizeof(sig));
|
||||
const unsigned int sigSize = issuer.sign(enc.data(), (unsigned int)enc.size(), sig, ZT_SIGNATURE_BUFFER_SIZE);
|
||||
|
||||
if (sigSize > 0) {
|
||||
m_signature.assign(sig, sig + sigSize);
|
||||
this->signature = m_signature.data();
|
||||
this->signatureSize = sigSize;
|
||||
return true;
|
||||
}
|
||||
|
||||
m_signature.clear();
|
||||
this->signature = nullptr;
|
||||
this->signatureSize = 0;
|
||||
|
@ -425,7 +473,7 @@ ZT_CertificateError Certificate::verify() const
|
|||
if (this->subject.uniqueIdProofSignatureSize > 0) {
|
||||
if (
|
||||
(this->subject.uniqueIdProofSignatureSize != ZT_ECC384_SIGNATURE_SIZE) ||
|
||||
(this->subject.uniqueIdSize != (ZT_ECC384_PUBLIC_KEY_SIZE + 1)) ||
|
||||
(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;
|
||||
|
@ -456,7 +504,7 @@ ZT_CertificateError Certificate::verify() const
|
|||
return ZT_CERTIFICATE_ERROR_MISSING_REQUIRED_FIELDS;
|
||||
}
|
||||
|
||||
if (this->subject.updateURLCount) {
|
||||
if (this->subject.updateURLCount > 0) {
|
||||
if (!this->subject.updateURLs)
|
||||
return ZT_CERTIFICATE_ERROR_INVALID_FORMAT;
|
||||
for (unsigned int i = 0; i < this->subject.updateURLCount; ++i) {
|
||||
|
@ -471,26 +519,6 @@ ZT_CertificateError Certificate::verify() const
|
|||
return ZT_CERTIFICATE_ERROR_NONE;
|
||||
}
|
||||
|
||||
bool Certificate::setSubjectUniqueId(const uint8_t uniqueId[ZT_CERTIFICATE_UNIQUE_ID_TYPE_NIST_P_384_SIZE], const uint8_t uniqueIdPrivate[ZT_CERTIFICATE_UNIQUE_ID_TYPE_NIST_P_384_PRIVATE_SIZE])
|
||||
{
|
||||
m_subjectUniqueId.assign(uniqueId, uniqueId + ZT_CERTIFICATE_UNIQUE_ID_TYPE_NIST_P_384_SIZE);
|
||||
this->subject.uniqueId = m_subjectUniqueId.data();
|
||||
this->subject.uniqueIdSize = ZT_CERTIFICATE_UNIQUE_ID_TYPE_NIST_P_384_SIZE;
|
||||
|
||||
Dictionary d;
|
||||
m_encodeSubject(this->subject, d, true);
|
||||
Vector< uint8_t > enc;
|
||||
d.encode(enc);
|
||||
uint8_t h[ZT_SHA384_DIGEST_SIZE];
|
||||
SHA384(h, enc.data(), (unsigned int)enc.size());
|
||||
m_subjectUniqueIdProofSignature.resize(ZT_ECC384_SIGNATURE_SIZE);
|
||||
ECC384ECDSASign(uniqueIdPrivate, h, m_subjectUniqueIdProofSignature.data());
|
||||
this->subject.uniqueIdProofSignature = m_subjectUniqueIdProofSignature.data();
|
||||
this->subject.uniqueIdProofSignatureSize = ZT_ECC384_SIGNATURE_SIZE;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void Certificate::m_clear()
|
||||
{
|
||||
ZT_Certificate *const sup = this;
|
||||
|
@ -513,35 +541,41 @@ void Certificate::m_clear()
|
|||
|
||||
void Certificate::m_encodeSubject(const ZT_Certificate_Subject &s, Dictionary &d, bool omitUniqueIdProofSignature)
|
||||
{
|
||||
char tmp[64];
|
||||
char tmp[32];
|
||||
|
||||
d.add("s.t", (uint64_t)s.timestamp);
|
||||
|
||||
d.add("s.i$", (uint64_t)s.identityCount);
|
||||
for (unsigned int i = 0; i < s.identityCount; ++i) {
|
||||
if (s.identities[i].identity)
|
||||
d.addO(Dictionary::arraySubscript(tmp, "s.i$.i", i), *reinterpret_cast<const Identity *>(s.identities[i].identity));
|
||||
if (s.identities[i].locator)
|
||||
d.addO(Dictionary::arraySubscript(tmp, "s.i$.l", i), *reinterpret_cast<const Locator *>(s.identities[i].locator));
|
||||
if (s.identities) {
|
||||
d.add("s.i$", (uint64_t)s.identityCount);
|
||||
for (unsigned int i = 0; i < s.identityCount; ++i) {
|
||||
if (s.identities[i].identity)
|
||||
d.addO(Dictionary::arraySubscript(tmp, sizeof(tmp), "s.i$.i", i), *reinterpret_cast<const Identity *>(s.identities[i].identity));
|
||||
if (s.identities[i].locator)
|
||||
d.addO(Dictionary::arraySubscript(tmp, sizeof(tmp), "s.i$.l", i), *reinterpret_cast<const Locator *>(s.identities[i].locator));
|
||||
}
|
||||
}
|
||||
|
||||
d.add("s.n$", (uint64_t)s.networkCount);
|
||||
for (unsigned int i = 0; i < s.networkCount; ++i) {
|
||||
d.add(Dictionary::arraySubscript(tmp, "s.n$.i", i), s.networks[i].id);
|
||||
Fingerprint fp(s.networks[i].controller);
|
||||
d.addO(Dictionary::arraySubscript(tmp, "s.n$.c", i), fp);
|
||||
if (s.networks) {
|
||||
d.add("s.nw$", (uint64_t)s.networkCount);
|
||||
for (unsigned int i = 0; i < s.networkCount; ++i) {
|
||||
d.add(Dictionary::arraySubscript(tmp, sizeof(tmp), "s.nw$.i", i), s.networks[i].id);
|
||||
Fingerprint fp(s.networks[i].controller);
|
||||
d.addO(Dictionary::arraySubscript(tmp, sizeof(tmp), "s.nw$.c", i), fp);
|
||||
}
|
||||
}
|
||||
|
||||
d.add("s.c$", (uint64_t)s.certificateCount);
|
||||
for (unsigned int i = 0; i < s.certificateCount; ++i) {
|
||||
if (s.certificates[i])
|
||||
d[Dictionary::arraySubscript(tmp, "s.c$", i)].assign(s.certificates[i], s.certificates[i] + ZT_SHA384_DIGEST_SIZE);
|
||||
if (s.certificates) {
|
||||
d.add("s.c$", (uint64_t)s.certificateCount);
|
||||
for (unsigned int i = 0; i < s.certificateCount; ++i) {
|
||||
if (s.certificates[i])
|
||||
d[Dictionary::arraySubscript(tmp, sizeof(tmp), "s.c$", i)].assign(s.certificates[i], s.certificates[i] + ZT_SHA384_DIGEST_SIZE);
|
||||
}
|
||||
}
|
||||
|
||||
d.add("s.u$", (uint64_t)s.updateURLCount);
|
||||
if (s.updateURLs) {
|
||||
d.add("s.u$", (uint64_t)s.updateURLCount);
|
||||
for (unsigned int i = 0; i < s.updateURLCount; ++i)
|
||||
d.add(Dictionary::arraySubscript(tmp, "s.u$", i), s.updateURLs[i]);
|
||||
d.add(Dictionary::arraySubscript(tmp, sizeof(tmp), "s.u$", i), s.updateURLs[i]);
|
||||
}
|
||||
|
||||
if (s.name.country[0])
|
||||
|
@ -569,9 +603,9 @@ void Certificate::m_encodeSubject(const ZT_Certificate_Subject &s, Dictionary &d
|
|||
if (s.name.host[0])
|
||||
d.add("s.n.h", s.name.host);
|
||||
|
||||
if ((s.uniqueIdSize > 0) && (s.uniqueId != nullptr))
|
||||
if ((s.uniqueId) && (s.uniqueIdSize > 0))
|
||||
d["s.uI"].assign(s.uniqueId, s.uniqueId + s.uniqueIdSize);
|
||||
if ((!omitUniqueIdProofSignature) && (s.uniqueIdProofSignatureSize > 0) && (s.uniqueIdProofSignature != nullptr))
|
||||
if ((!omitUniqueIdProofSignature) && (s.uniqueIdProofSignature) && (s.uniqueIdProofSignatureSize > 0))
|
||||
d["s.uS"].assign(s.uniqueIdProofSignature, s.uniqueIdProofSignature + s.uniqueIdProofSignatureSize);
|
||||
}
|
||||
|
||||
|
@ -586,7 +620,7 @@ int ZT_Certificate_newSubjectUniqueId(
|
|||
void *uniqueIdPrivate,
|
||||
int *uniqueIdPrivateSize)
|
||||
{
|
||||
switch(type) {
|
||||
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;
|
||||
|
@ -631,15 +665,22 @@ int ZT_Certificate_sign(
|
|||
{
|
||||
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_BAD_PARAMETER;
|
||||
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;
|
||||
|
||||
try {
|
||||
const ZeroTier::ScopedPtr< ZeroTier::Certificate > c(new ZeroTier::Certificate(*cert));
|
||||
if (!c->sign(*reinterpret_cast<const ZeroTier::Identity *>(signer)))
|
||||
return ZT_RESULT_ERROR_INTERNAL;
|
||||
|
||||
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 ( ... ) {
|
||||
return ZT_RESULT_FATAL_ERROR_INTERNAL;
|
||||
}
|
||||
}
|
||||
|
||||
enum ZT_CertificateError ZT_Certificate_decode(
|
||||
|
@ -649,7 +690,7 @@ enum ZT_CertificateError ZT_Certificate_decode(
|
|||
int verify)
|
||||
{
|
||||
try {
|
||||
if (!decodedCert)
|
||||
if ((!decodedCert) || (!cert) || (certSize <= 0))
|
||||
return ZT_CERTIFICATE_ERROR_INVALID_FORMAT;
|
||||
*decodedCert = nullptr;
|
||||
ZeroTier::Certificate *const c = new ZeroTier::Certificate();
|
||||
|
@ -658,7 +699,7 @@ enum ZT_CertificateError ZT_Certificate_decode(
|
|||
return ZT_CERTIFICATE_ERROR_INVALID_FORMAT;
|
||||
}
|
||||
if (verify) {
|
||||
ZT_CertificateError err = c->verify();
|
||||
const ZT_CertificateError err = c->verify();
|
||||
if (err != ZT_CERTIFICATE_ERROR_NONE) {
|
||||
delete c;
|
||||
return err;
|
||||
|
@ -666,7 +707,7 @@ enum ZT_CertificateError ZT_Certificate_decode(
|
|||
}
|
||||
*decodedCert = c;
|
||||
return ZT_CERTIFICATE_ERROR_NONE;
|
||||
} catch ( ... ) {
|
||||
} catch (...) {
|
||||
return ZT_CERTIFICATE_ERROR_INVALID_FORMAT;
|
||||
}
|
||||
}
|
||||
|
@ -693,7 +734,7 @@ enum ZT_CertificateError ZT_Certificate_verify(const ZT_Certificate *cert)
|
|||
if (!cert)
|
||||
return ZT_CERTIFICATE_ERROR_INVALID_FORMAT;
|
||||
return ZeroTier::Certificate(*cert).verify();
|
||||
} catch ( ... ) {
|
||||
} catch (...) {
|
||||
return ZT_CERTIFICATE_ERROR_INVALID_FORMAT;
|
||||
}
|
||||
}
|
||||
|
@ -704,7 +745,7 @@ const ZT_Certificate *ZT_Certificate_clone(const ZT_Certificate *cert)
|
|||
if (!cert)
|
||||
return nullptr;
|
||||
return (const ZT_Certificate *)(new ZeroTier::Certificate(*cert));
|
||||
} catch ( ... ) {
|
||||
} catch (...) {
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -114,6 +114,17 @@ public:
|
|||
*/
|
||||
void setExtendedAttributes(const Dictionary &x);
|
||||
|
||||
/**
|
||||
* Set the unique ID of this certificate's subject
|
||||
*
|
||||
* This must be done after all other fields in the subject are set.
|
||||
*
|
||||
* @param uniqueId Unique ID
|
||||
* @param uniqueIdPrivate Private key associated with unique ID to prove ownership of it
|
||||
* @return True if successful
|
||||
*/
|
||||
bool setSubjectUniqueId(const uint8_t uniqueId[ZT_CERTIFICATE_UNIQUE_ID_TYPE_NIST_P_384_SIZE], const uint8_t uniqueIdPrivate[ZT_CERTIFICATE_UNIQUE_ID_TYPE_NIST_P_384_PRIVATE_SIZE]);
|
||||
|
||||
/**
|
||||
* Marshal this certificate in binary form
|
||||
*
|
||||
|
@ -159,17 +170,6 @@ public:
|
|||
*/
|
||||
ZT_CertificateError verify() const;
|
||||
|
||||
/**
|
||||
* Set the unique ID of this certificate's subject
|
||||
*
|
||||
* This must be done after all other fields in the subject are set.
|
||||
*
|
||||
* @param uniqueId Unique ID
|
||||
* @param uniqueIdPrivate Private key associated with unique ID to prove ownership of it
|
||||
* @return True if successful
|
||||
*/
|
||||
bool setSubjectUniqueId(const uint8_t uniqueId[ZT_CERTIFICATE_UNIQUE_ID_TYPE_NIST_P_384_SIZE], const uint8_t uniqueIdPrivate[ZT_CERTIFICATE_UNIQUE_ID_TYPE_NIST_P_384_PRIVATE_SIZE]);
|
||||
|
||||
/**
|
||||
* Create a subject unique ID and corresponding private key required for use
|
||||
*
|
||||
|
@ -211,10 +211,10 @@ private:
|
|||
// These hold any identity or locator objects that are owned by and should
|
||||
// be deleted with this certificate. Lists are used so the pointers never
|
||||
// change.
|
||||
List< Identity > m_identities;
|
||||
List< Locator > m_locators;
|
||||
List< String > m_strings;
|
||||
List< SHA384Hash > m_serials;
|
||||
ForwardList< Identity > m_identities;
|
||||
ForwardList< Locator > m_locators;
|
||||
ForwardList< String > m_strings;
|
||||
ForwardList< SHA384Hash > m_serials;
|
||||
|
||||
// These are stored in a vector because the memory needs to be contiguous.
|
||||
Vector< ZT_Certificate_Identity > m_subjectIdentities;
|
||||
|
|
|
@ -28,6 +28,7 @@
|
|||
#ifdef __CPP11__
|
||||
#include <atomic>
|
||||
#include <unordered_map>
|
||||
#include <forward_list>
|
||||
#endif
|
||||
|
||||
namespace ZeroTier {
|
||||
|
@ -128,6 +129,20 @@ template< typename V >
|
|||
class List : public std::list< V >
|
||||
{};
|
||||
|
||||
#ifdef __CPP11__
|
||||
|
||||
template< typename V >
|
||||
class ForwardList : public std::forward_list< V >
|
||||
{};
|
||||
|
||||
#else
|
||||
|
||||
template< typename V >
|
||||
class ForwardList : public std::list< V >
|
||||
{};
|
||||
|
||||
#endif
|
||||
|
||||
template< typename V >
|
||||
class Set : public std::set< V, std::less< V > >
|
||||
{};
|
||||
|
|
|
@ -22,23 +22,15 @@ Dictionary::~Dictionary()
|
|||
{}
|
||||
|
||||
Vector< uint8_t > &Dictionary::operator[](const char *const k)
|
||||
{ return m_entries[s_key(k)]; }
|
||||
{ return m_entries[k]; }
|
||||
|
||||
const Vector< uint8_t > &Dictionary::operator[](const char *const k) const
|
||||
{
|
||||
static const Vector< uint8_t > s_emptyEntry;
|
||||
const SortedMap< String, Vector< uint8_t > >::const_iterator e(m_entries.find(s_key(k)));
|
||||
const SortedMap< String, Vector< uint8_t > >::const_iterator e(m_entries.find(k));
|
||||
return (e == m_entries.end()) ? s_emptyEntry : e->second;
|
||||
}
|
||||
|
||||
void Dictionary::add(const char *k, bool v)
|
||||
{
|
||||
Vector< uint8_t > &e = (*this)[k];
|
||||
e.resize(2);
|
||||
e[0] = (uint8_t)(v ? '1' : '0');
|
||||
e[1] = 0;
|
||||
}
|
||||
|
||||
void Dictionary::add(const char *k, const Address &v)
|
||||
{
|
||||
char tmp[ZT_ADDRESS_STRING_SIZE_MAX];
|
||||
|
@ -66,24 +58,6 @@ void Dictionary::add(const char *k, const void *data, unsigned int len)
|
|||
}
|
||||
}
|
||||
|
||||
bool Dictionary::getB(const char *k, bool dfl) const
|
||||
{
|
||||
const Vector< uint8_t > &e = (*this)[k];
|
||||
if (!e.empty()) {
|
||||
switch ((char)e[0]) {
|
||||
case '1':
|
||||
case 't':
|
||||
case 'T':
|
||||
case 'y':
|
||||
case 'Y':
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return dfl;
|
||||
}
|
||||
|
||||
uint64_t Dictionary::getUI(const char *k, uint64_t dfl) const
|
||||
{
|
||||
char tmp[32];
|
||||
|
@ -97,23 +71,22 @@ char *Dictionary::getS(const char *k, char *v, const unsigned int cap) const
|
|||
{
|
||||
if (cap == 0) // sanity check
|
||||
return v;
|
||||
|
||||
const Vector< uint8_t > &e = (*this)[k];
|
||||
if (e.empty()) {
|
||||
v[0] = 0;
|
||||
return v;
|
||||
}
|
||||
unsigned int i = 0;
|
||||
const unsigned int last = cap - 1;
|
||||
for (;;) {
|
||||
|
||||
for (unsigned int i = 0, last = (cap - 1);; ++i) {
|
||||
if ((i >= last) || (i >= (unsigned int)e.size())) {
|
||||
v[i] = 0;
|
||||
break;
|
||||
}
|
||||
if ((v[i] = (char)e[i]) == 0) {
|
||||
if ((v[i] = (char)e[i]) == 0)
|
||||
break;
|
||||
}
|
||||
++i;
|
||||
}
|
||||
|
||||
return v;
|
||||
}
|
||||
|
||||
|
@ -131,7 +104,6 @@ void Dictionary::encode(Vector< uint8_t > &out) const
|
|||
s_appendValueByte(out, *i);
|
||||
out.push_back((uint8_t)'\n');
|
||||
}
|
||||
out.push_back(0);
|
||||
}
|
||||
|
||||
bool Dictionary::decode(const void *data, unsigned int len)
|
||||
|
@ -176,20 +148,24 @@ bool Dictionary::decode(const void *data, unsigned int len)
|
|||
} 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 break;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
char *Dictionary::arraySubscript(char buf[256],const char *name,const unsigned long sub) noexcept
|
||||
char *Dictionary::arraySubscript(char *buf, unsigned int bufSize, const char *name, const unsigned long sub) noexcept
|
||||
{
|
||||
for(unsigned int i=0;i<(256 - 17);++i) {
|
||||
if (bufSize < 17) { // sanity check
|
||||
buf[0] = 0;
|
||||
return buf;
|
||||
}
|
||||
for (unsigned int i = 0; i < (bufSize - 17); ++i) {
|
||||
if ((buf[i] = name[i]) == 0) {
|
||||
buf[i++] = '#';
|
||||
Utils::hex(sub, buf + i);
|
||||
|
@ -200,19 +176,4 @@ 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
|
||||
|
|
|
@ -42,9 +42,10 @@ class Identity;
|
|||
class Dictionary
|
||||
{
|
||||
public:
|
||||
typedef SortedMap< String, Vector < uint8_t > >::const_iterator const_iterator;
|
||||
typedef SortedMap< String, Vector< uint8_t > >::const_iterator const_iterator;
|
||||
|
||||
Dictionary();
|
||||
|
||||
~Dictionary();
|
||||
|
||||
/**
|
||||
|
@ -53,7 +54,7 @@ public:
|
|||
* @param k Key to look up
|
||||
* @return Reference to value
|
||||
*/
|
||||
Vector <uint8_t> &operator[](const char *k);
|
||||
Vector< uint8_t > &operator[](const char *k);
|
||||
|
||||
/**
|
||||
* Get a const reference to a value
|
||||
|
@ -61,7 +62,7 @@ public:
|
|||
* @param k Key to look up
|
||||
* @return Reference to value or to empty vector if not found
|
||||
*/
|
||||
const Vector <uint8_t> &operator[](const char *k) const;
|
||||
const Vector< uint8_t > &operator[](const char *k) const;
|
||||
|
||||
/**
|
||||
* @return Start of key->value pairs
|
||||
|
@ -75,11 +76,6 @@ public:
|
|||
ZT_INLINE const_iterator end() const noexcept
|
||||
{ return m_entries.end(); }
|
||||
|
||||
/**
|
||||
* Add a boolean as '1' or '0'
|
||||
*/
|
||||
void add(const char *k, bool v);
|
||||
|
||||
/**
|
||||
* Add an integer as a hexadecimal string value
|
||||
*
|
||||
|
@ -87,7 +83,10 @@ public:
|
|||
* @param v Integer to set, will be cast to uint64_t and stored as hex
|
||||
*/
|
||||
ZT_INLINE void add(const char *const k, const uint64_t v)
|
||||
{ char buf[17]; add(k, Utils::hex((uint64_t)(v), buf)); }
|
||||
{
|
||||
char buf[24];
|
||||
add(k, Utils::hex((uint64_t)(v), buf));
|
||||
}
|
||||
|
||||
/**
|
||||
* Add an integer as a hexadecimal string value
|
||||
|
@ -96,7 +95,10 @@ public:
|
|||
* @param v Integer to set, will be cast to uint64_t and stored as hex
|
||||
*/
|
||||
ZT_INLINE void add(const char *const k, const int64_t v)
|
||||
{ char buf[17]; add(k, Utils::hex((uint64_t)(v), buf)); }
|
||||
{
|
||||
char buf[24];
|
||||
add(k, Utils::hex((uint64_t)(v), buf));
|
||||
}
|
||||
|
||||
/**
|
||||
* Add an address in 10-digit hex string format
|
||||
|
@ -113,15 +115,6 @@ public:
|
|||
*/
|
||||
void add(const char *k, const void *data, unsigned int len);
|
||||
|
||||
/**
|
||||
* Get a boolean
|
||||
*
|
||||
* @param k Key to look up
|
||||
* @param dfl Default value (default: false)
|
||||
* @return Value of key or default if not found
|
||||
*/
|
||||
bool getB(const char *k, bool dfl = false) const;
|
||||
|
||||
/**
|
||||
* Get an integer
|
||||
*
|
||||
|
@ -171,13 +164,14 @@ public:
|
|||
template< typename T >
|
||||
ZT_INLINE bool addO(const char *k, T &obj)
|
||||
{
|
||||
uint8_t tmp[4096];
|
||||
static_assert(sizeof(tmp) >= T::marshalSizeMax(),"buffer too small");
|
||||
int l = obj.marshal(tmp);
|
||||
Vector< uint8_t > &d = (*this)[k];
|
||||
d.resize(T::marshalSizeMax());
|
||||
const int l = obj.marshal(d.data());
|
||||
if (l > 0) {
|
||||
(*this)[k].assign(tmp, tmp + l);
|
||||
d.resize(l);
|
||||
return true;
|
||||
}
|
||||
d.clear();
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -203,7 +197,7 @@ public:
|
|||
*
|
||||
* @param out String encoded dictionary
|
||||
*/
|
||||
void encode(Vector <uint8_t> &out) const;
|
||||
void encode(Vector< uint8_t > &out) const;
|
||||
|
||||
/**
|
||||
* Decode a string encoded dictionary
|
||||
|
@ -362,7 +356,7 @@ public:
|
|||
template< typename V, typename T >
|
||||
static ZT_INLINE int appendObject(V &out, const char *const k, const T &v)
|
||||
{
|
||||
uint8_t tmp[4096]; // large enough for any current object
|
||||
uint8_t tmp[2048]; // large enough for any current object
|
||||
if (T::marshalSizeMax() > sizeof(tmp))
|
||||
return -1;
|
||||
const int mlen = v.marshal(tmp);
|
||||
|
@ -379,7 +373,7 @@ public:
|
|||
* @param sub Subscript index
|
||||
* @return Pointer to 'buf'
|
||||
*/
|
||||
static char *arraySubscript(char buf[256],const char *name,const unsigned long sub) noexcept;
|
||||
static char *arraySubscript(char *buf, unsigned int bufSize, const char *name, const unsigned long sub) noexcept;
|
||||
|
||||
private:
|
||||
template< typename V >
|
||||
|
@ -417,20 +411,17 @@ private:
|
|||
{
|
||||
for (;;) {
|
||||
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)
|
||||
if (c == 0)
|
||||
break;
|
||||
out.push_back((uint8_t)c);
|
||||
}
|
||||
out.push_back((uint8_t)'=');
|
||||
}
|
||||
|
||||
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
|
||||
// where dictionaries are signed and verified the order doesn't matter.
|
||||
SortedMap < String, Vector< uint8_t > > m_entries;
|
||||
SortedMap< String, Vector< uint8_t > > m_entries;
|
||||
};
|
||||
|
||||
} // namespace ZeroTier
|
||||
|
|
|
@ -37,7 +37,7 @@ public:
|
|||
{ memoryZero(this); }
|
||||
|
||||
ZT_INLINE Fingerprint(const ZT_Fingerprint &fp) noexcept
|
||||
{ Utils::copy<sizeof(ZT_Fingerprint)>(this, &fp); }
|
||||
{ Utils::copy< sizeof(ZT_Fingerprint) >(this, &fp); }
|
||||
|
||||
/**
|
||||
* @return True if hash is not all zero (missing/unspecified)
|
||||
|
@ -59,7 +59,12 @@ public:
|
|||
}
|
||||
return s;
|
||||
}
|
||||
ZT_INLINE String toString() const { char tmp[ZT_FINGERPRINT_STRING_SIZE_MAX]; return String(toString(tmp)); }
|
||||
|
||||
ZT_INLINE String toString() const
|
||||
{
|
||||
char tmp[ZT_FINGERPRINT_STRING_SIZE_MAX];
|
||||
return String(toString(tmp));
|
||||
}
|
||||
|
||||
/**
|
||||
* Set this fingerprint to a base32-encoded string
|
||||
|
@ -71,18 +76,18 @@ public:
|
|||
{
|
||||
if (!s)
|
||||
return false;
|
||||
const int l = (int) strlen(s);
|
||||
const int l = (int)strlen(s);
|
||||
if (l < ZT_ADDRESS_LENGTH_HEX)
|
||||
return false;
|
||||
char a[ZT_ADDRESS_LENGTH_HEX + 1];
|
||||
Utils::copy<ZT_ADDRESS_LENGTH_HEX>(a, s);
|
||||
Utils::copy< ZT_ADDRESS_LENGTH_HEX >(a, s);
|
||||
a[ZT_ADDRESS_LENGTH_HEX] = 0;
|
||||
this->address = Utils::hexStrToU64(a) & ZT_ADDRESS_MASK;
|
||||
if (l > (ZT_ADDRESS_LENGTH_HEX + 1)) {
|
||||
if (Utils::b32d(s + (ZT_ADDRESS_LENGTH_HEX + 1), this->hash, ZT_FINGERPRINT_HASH_SIZE) != ZT_FINGERPRINT_HASH_SIZE)
|
||||
return false;
|
||||
} else {
|
||||
Utils::zero<ZT_FINGERPRINT_HASH_SIZE>(this->hash);
|
||||
Utils::zero< ZT_FINGERPRINT_HASH_SIZE >(this->hash);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
@ -120,7 +125,7 @@ public:
|
|||
ZT_INLINE int marshal(uint8_t data[ZT_FINGERPRINT_MARSHAL_SIZE]) const noexcept
|
||||
{
|
||||
Address(this->address).copyTo(data);
|
||||
Utils::copy<ZT_FINGERPRINT_HASH_SIZE>(data + ZT_ADDRESS_LENGTH,this->hash);
|
||||
Utils::copy< ZT_FINGERPRINT_HASH_SIZE >(data + ZT_ADDRESS_LENGTH, this->hash);
|
||||
return ZT_FINGERPRINT_MARSHAL_SIZE;
|
||||
}
|
||||
|
||||
|
@ -129,7 +134,7 @@ public:
|
|||
if (unlikely(len < ZT_FINGERPRINT_MARSHAL_SIZE))
|
||||
return -1;
|
||||
this->address = Address(data);
|
||||
Utils::copy<ZT_FINGERPRINT_HASH_SIZE>(hash,data + ZT_ADDRESS_LENGTH);
|
||||
Utils::copy< ZT_FINGERPRINT_HASH_SIZE >(hash, data + ZT_ADDRESS_LENGTH);
|
||||
return ZT_FINGERPRINT_MARSHAL_SIZE;
|
||||
}
|
||||
|
||||
|
|
|
@ -258,6 +258,7 @@ unsigned int Identity::sign(const void *data, unsigned int len, void *sig, unsig
|
|||
C25519::sign(m_priv, m_pub, data, len, sig);
|
||||
return ZT_C25519_SIGNATURE_LEN;
|
||||
}
|
||||
break;
|
||||
case P384:
|
||||
if (siglen >= ZT_ECC384_SIGNATURE_SIZE) {
|
||||
// SECURITY: signatures also include the public keys to further enforce their coupling.
|
||||
|
@ -267,6 +268,7 @@ unsigned int Identity::sign(const void *data, unsigned int len, void *sig, unsig
|
|||
ECC384ECDSASign(m_priv + ZT_C25519_COMBINED_PRIVATE_KEY_SIZE, h, (uint8_t *)sig);
|
||||
return ZT_ECC384_SIGNATURE_SIZE;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
|
@ -350,6 +352,8 @@ char *Identity::toString(bool includePrivate, char buf[ZT_IDENTITY_STRING_BUFFER
|
|||
*p = (char)0;
|
||||
return buf;
|
||||
}
|
||||
default:
|
||||
buf[0] = 0;
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
|
@ -445,10 +449,9 @@ int Identity::marshal(uint8_t data[ZT_IDENTITY_MARSHAL_SIZE_MAX], const bool inc
|
|||
data[ZT_ADDRESS_LENGTH + 1 + ZT_C25519_COMBINED_PUBLIC_KEY_SIZE] = ZT_C25519_COMBINED_PRIVATE_KEY_SIZE;
|
||||
Utils::copy< ZT_C25519_COMBINED_PRIVATE_KEY_SIZE >(data + ZT_ADDRESS_LENGTH + 1 + ZT_C25519_COMBINED_PUBLIC_KEY_SIZE + 1, m_priv);
|
||||
return ZT_ADDRESS_LENGTH + 1 + ZT_C25519_COMBINED_PUBLIC_KEY_SIZE + 1 + ZT_C25519_COMBINED_PRIVATE_KEY_SIZE;
|
||||
} else {
|
||||
data[ZT_ADDRESS_LENGTH + 1 + ZT_C25519_COMBINED_PUBLIC_KEY_SIZE] = 0;
|
||||
return ZT_ADDRESS_LENGTH + 1 + ZT_C25519_COMBINED_PUBLIC_KEY_SIZE + 1;
|
||||
}
|
||||
data[ZT_ADDRESS_LENGTH + 1 + ZT_C25519_COMBINED_PUBLIC_KEY_SIZE] = 0;
|
||||
return ZT_ADDRESS_LENGTH + 1 + ZT_C25519_COMBINED_PUBLIC_KEY_SIZE + 1;
|
||||
|
||||
case P384:
|
||||
data[ZT_ADDRESS_LENGTH] = (uint8_t)P384;
|
||||
|
@ -457,10 +460,9 @@ int Identity::marshal(uint8_t data[ZT_IDENTITY_MARSHAL_SIZE_MAX], const bool inc
|
|||
data[ZT_ADDRESS_LENGTH + 1 + ZT_IDENTITY_P384_COMPOUND_PUBLIC_KEY_SIZE] = ZT_IDENTITY_P384_COMPOUND_PRIVATE_KEY_SIZE;
|
||||
Utils::copy< ZT_IDENTITY_P384_COMPOUND_PRIVATE_KEY_SIZE >(data + ZT_ADDRESS_LENGTH + 1 + ZT_IDENTITY_P384_COMPOUND_PUBLIC_KEY_SIZE + 1, m_priv);
|
||||
return ZT_ADDRESS_LENGTH + 1 + ZT_IDENTITY_P384_COMPOUND_PUBLIC_KEY_SIZE + 1 + ZT_IDENTITY_P384_COMPOUND_PRIVATE_KEY_SIZE;
|
||||
} else {
|
||||
data[ZT_ADDRESS_LENGTH + 1 + ZT_IDENTITY_P384_COMPOUND_PUBLIC_KEY_SIZE] = 0;
|
||||
return ZT_ADDRESS_LENGTH + 1 + ZT_IDENTITY_P384_COMPOUND_PUBLIC_KEY_SIZE + 1;
|
||||
}
|
||||
data[ZT_ADDRESS_LENGTH + 1 + ZT_IDENTITY_P384_COMPOUND_PUBLIC_KEY_SIZE] = 0;
|
||||
return ZT_ADDRESS_LENGTH + 1 + ZT_IDENTITY_P384_COMPOUND_PUBLIC_KEY_SIZE + 1;
|
||||
|
||||
}
|
||||
return -1;
|
||||
|
|
|
@ -68,6 +68,12 @@ public:
|
|||
memoryZero(this);
|
||||
}
|
||||
|
||||
ZT_INLINE Identity(const Identity &id) noexcept
|
||||
{
|
||||
Utils::memoryLock(this, sizeof(Identity));
|
||||
Utils::copy< sizeof(Identity) >(this, &id);
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct identity from string
|
||||
*
|
||||
|
@ -88,6 +94,13 @@ public:
|
|||
Utils::burn(reinterpret_cast<void *>(&this->m_priv), sizeof(this->m_priv));
|
||||
}
|
||||
|
||||
ZT_INLINE Identity &operator=(const Identity &id) noexcept
|
||||
{
|
||||
if (likely(this != &id))
|
||||
Utils::copy< sizeof(Identity) >(this, &id);
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set identity to NIL value (all zero)
|
||||
*/
|
||||
|
@ -211,6 +224,15 @@ public:
|
|||
*/
|
||||
bool fromString(const char *str);
|
||||
|
||||
/**
|
||||
* Erase any private key in this identity object
|
||||
*/
|
||||
ZT_INLINE void erasePrivateKey() noexcept
|
||||
{
|
||||
Utils::burn(m_priv, sizeof(m_priv));
|
||||
m_hasPrivate = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return True if this identity contains something
|
||||
*/
|
||||
|
@ -222,20 +244,27 @@ public:
|
|||
|
||||
ZT_INLINE bool operator==(const Identity &id) const noexcept
|
||||
{ return (m_fp == id.m_fp); }
|
||||
|
||||
ZT_INLINE bool operator!=(const Identity &id) const noexcept
|
||||
{ return !(*this == id); }
|
||||
|
||||
ZT_INLINE bool operator<(const Identity &id) const noexcept
|
||||
{ return (m_fp < id.m_fp); }
|
||||
|
||||
ZT_INLINE bool operator>(const Identity &id) const noexcept
|
||||
{ return (id < *this); }
|
||||
|
||||
ZT_INLINE bool operator<=(const Identity &id) const noexcept
|
||||
{ return !(id < *this); }
|
||||
|
||||
ZT_INLINE bool operator>=(const Identity &id) const noexcept
|
||||
{ return !(*this < id); }
|
||||
|
||||
static constexpr int marshalSizeMax() noexcept
|
||||
{ return ZT_IDENTITY_MARSHAL_SIZE_MAX; }
|
||||
|
||||
int marshal(uint8_t data[ZT_IDENTITY_MARSHAL_SIZE_MAX], bool includePrivate = false) const noexcept;
|
||||
|
||||
int unmarshal(const uint8_t *data, int len) noexcept;
|
||||
|
||||
private:
|
||||
|
|
|
@ -20,7 +20,7 @@ static const SharedPtr< const Certificate > s_nullCert;
|
|||
Topology::Topology(const RuntimeEnvironment *renv, void *tPtr, const int64_t now) :
|
||||
RR(renv)
|
||||
{
|
||||
char tmp[256];
|
||||
char tmp[32];
|
||||
Vector< uint8_t > trustData(RR->node->stateObjectGet(tPtr, ZT_STATE_OBJECT_TRUST_STORE, Utils::ZERO256));
|
||||
|
||||
Dictionary d;
|
||||
|
@ -30,20 +30,20 @@ Topology::Topology(const RuntimeEnvironment *renv, void *tPtr, const int64_t now
|
|||
const unsigned long certCount = (unsigned long)d.getUI("c$");
|
||||
for (unsigned long idx = 0; idx < certCount; ++idx) {
|
||||
uint64_t id[6];
|
||||
const Vector< uint8_t > &serialNo = d[Dictionary::arraySubscript(tmp, "c$.s", idx)];
|
||||
const Vector< uint8_t > &serialNo = d[Dictionary::arraySubscript(tmp, sizeof(tmp), "c$.s", idx)];
|
||||
if (serialNo.size() == ZT_SHA384_DIGEST_SIZE) {
|
||||
Utils::copy< 48 >(id, serialNo.data());
|
||||
Certificate cert;
|
||||
Vector< uint8_t > enc(RR->node->stateObjectGet(tPtr, ZT_STATE_OBJECT_CERT, id));
|
||||
if (cert.decode(enc.data(), (unsigned int)enc.size()))
|
||||
addCertificate(tPtr, cert, now, (unsigned int)d.getUI(Dictionary::arraySubscript(tmp, "c$.lt", idx)), false, false, false);
|
||||
addCertificate(tPtr, cert, now, (unsigned int)d.getUI(Dictionary::arraySubscript(tmp, sizeof(tmp), "c$.lt", idx)), false, false, false);
|
||||
}
|
||||
}
|
||||
|
||||
const unsigned long localRootCount = (unsigned long)d.getUI("lr$");
|
||||
for (unsigned long idx = 0; idx < localRootCount; ++idx) {
|
||||
Identity lr;
|
||||
if (d.getO(Dictionary::arraySubscript(tmp, "lr$.i", idx), lr)) {
|
||||
if (d.getO(Dictionary::arraySubscript(tmp, sizeof(tmp), "lr$.i", idx), lr)) {
|
||||
if (lr)
|
||||
m_roots[lr].insert(s_nullCert);
|
||||
}
|
||||
|
@ -456,7 +456,7 @@ void Topology::m_writeTrustStore_l_roots_certs(void *tPtr) const
|
|||
{
|
||||
// assumes m_roots_l and m_certs_l are locked for write
|
||||
|
||||
char tmp[256];
|
||||
char tmp[32];
|
||||
Dictionary d;
|
||||
|
||||
d.add("v", (uint64_t)0); // version
|
||||
|
@ -464,15 +464,15 @@ void Topology::m_writeTrustStore_l_roots_certs(void *tPtr) const
|
|||
unsigned long idx = 0;
|
||||
d.add("c$", (uint64_t)m_certs.size());
|
||||
for (Map< SHA384Hash, std::pair< SharedPtr< const Certificate >, unsigned int > >::const_iterator c(m_certs.begin()); c != m_certs.end(); ++c) {
|
||||
d[Dictionary::arraySubscript(tmp, "c$.s", idx)].assign(c->first.data, c->first.data + ZT_SHA384_DIGEST_SIZE);
|
||||
d.add(Dictionary::arraySubscript(tmp, "c$.lt", idx), (uint64_t)c->second.second);
|
||||
d[Dictionary::arraySubscript(tmp, sizeof(tmp), "c$.s", idx)].assign(c->first.data, c->first.data + ZT_SHA384_DIGEST_SIZE);
|
||||
d.add(Dictionary::arraySubscript(tmp, sizeof(tmp), "c$.lt", idx), (uint64_t)c->second.second);
|
||||
++idx;
|
||||
}
|
||||
|
||||
unsigned long localRootCount = 0;
|
||||
for (Map< Identity, Set< SharedPtr< const Certificate > > >::const_iterator r(m_roots.begin()); r != m_roots.end();) {
|
||||
if (r->second.find(s_nullCert) != r->second.end())
|
||||
d.addO(Dictionary::arraySubscript(tmp, "lr$.i", localRootCount++), r->first);
|
||||
d.addO(Dictionary::arraySubscript(tmp, sizeof(tmp), "lr$.i", localRootCount++), r->first);
|
||||
}
|
||||
d.add("lr$", (uint64_t)localRootCount);
|
||||
|
||||
|
|
|
@ -733,7 +733,7 @@ static ZT_INLINE void copy(void *dest, const void *src) noexcept
|
|||
#endif
|
||||
}
|
||||
|
||||
// Avoid rep/movsb startup time for some small common sizes.
|
||||
#ifndef ZT_NO_UNALIGNED_ACCESS
|
||||
template<>
|
||||
ZT_INLINE void copy<4>(void *dest, const void *src) noexcept
|
||||
{
|
||||
|
@ -756,13 +756,7 @@ ZT_INLINE void copy<16>(void *dest, const void *src) noexcept
|
|||
*reinterpret_cast<uint64_t *>(dest) = *reinterpret_cast<const uint64_t *>(src);
|
||||
*reinterpret_cast<uint64_t *>(reinterpret_cast<uint8_t *>(dest) + 8) = *reinterpret_cast<const uint64_t *>(reinterpret_cast<const uint8_t *>(src) + 8);
|
||||
}
|
||||
template<>
|
||||
ZT_INLINE void copy<24>(void *dest, const void *src) noexcept
|
||||
{
|
||||
*reinterpret_cast<uint64_t *>(dest) = *reinterpret_cast<const uint64_t *>(src);
|
||||
*reinterpret_cast<uint64_t *>(reinterpret_cast<uint8_t *>(dest) + 8) = *reinterpret_cast<const uint64_t *>(reinterpret_cast<const uint8_t *>(src) + 8);
|
||||
*reinterpret_cast<uint64_t *>(reinterpret_cast<uint8_t *>(dest) + 16) = *reinterpret_cast<const uint64_t *>(reinterpret_cast<const uint8_t *>(src) + 16);
|
||||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Copy memory block whose size is known at run time
|
||||
|
|
|
@ -18,6 +18,7 @@ package zerotier
|
|||
import "C"
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"runtime"
|
||||
"unsafe"
|
||||
|
@ -136,13 +137,11 @@ func NewCertificateFromBytes(cert []byte, verify bool) (*Certificate, error) {
|
|||
ver = 1
|
||||
}
|
||||
cerr := C.ZT_Certificate_decode((**C.ZT_Certificate)(unsafe.Pointer(&dec)), unsafe.Pointer(&cert[0]), C.int(len(cert)), ver)
|
||||
if dec != unsafe.Pointer(nil) {
|
||||
defer C.ZT_Certificate_delete((*C.ZT_Certificate)(dec))
|
||||
}
|
||||
defer C.ZT_Certificate_delete((*C.ZT_Certificate)(dec))
|
||||
if cerr != 0 {
|
||||
return nil, certificateErrorToError(int(cerr))
|
||||
}
|
||||
if dec == unsafe.Pointer(nil) {
|
||||
if dec == unsafe.Pointer(uintptr(0)) {
|
||||
return nil, ErrInternal
|
||||
}
|
||||
|
||||
|
@ -309,7 +308,7 @@ func (c *Certificate) CCertificate() *CCertificate {
|
|||
}
|
||||
}
|
||||
cc.subject.identities = &subjectIdentities[0]
|
||||
cc.subject.identityCount = C.uint(len(c.Subject.Identities))
|
||||
cc.subject.identityCount = C.uint(len(subjectIdentities))
|
||||
}
|
||||
|
||||
if len(c.Subject.Networks) > 0 {
|
||||
|
@ -322,7 +321,7 @@ func (c *Certificate) CCertificate() *CCertificate {
|
|||
}
|
||||
}
|
||||
cc.subject.networks = &subjectNetworks[0]
|
||||
cc.subject.networkCount = C.uint(len(c.Subject.Networks))
|
||||
cc.subject.networkCount = C.uint(len(subjectNetworks))
|
||||
}
|
||||
|
||||
if len(c.Subject.Certificates) > 0 {
|
||||
|
@ -334,7 +333,7 @@ func (c *Certificate) CCertificate() *CCertificate {
|
|||
subjectCertificates[i] = uintptr(unsafe.Pointer(&cert[0]))
|
||||
}
|
||||
cc.subject.certificates = (**C.uint8_t)(unsafe.Pointer(&subjectCertificates[0]))
|
||||
cc.subject.certificateCount = C.uint(len(c.Subject.Certificates))
|
||||
cc.subject.certificateCount = C.uint(len(subjectCertificates))
|
||||
}
|
||||
|
||||
if len(c.Subject.UpdateURLs) > 0 {
|
||||
|
@ -345,7 +344,7 @@ func (c *Certificate) CCertificate() *CCertificate {
|
|||
subjectUpdateURLs[i] = uintptr(unsafe.Pointer(&subjectUpdateURLsData[0][0]))
|
||||
}
|
||||
cc.subject.updateURLs = (**C.char)(unsafe.Pointer(&subjectUpdateURLs[0]))
|
||||
cc.subject.updateURLCount = C.uint(len(c.Subject.UpdateURLs))
|
||||
cc.subject.updateURLCount = C.uint(len(subjectUpdateURLs))
|
||||
}
|
||||
|
||||
cStrCopy(unsafe.Pointer(&cc.subject.name.serialNo[0]), CertificateMaxStringLength+1, c.Subject.Name.SerialNo)
|
||||
|
@ -402,8 +401,8 @@ func (c *Certificate) CCertificate() *CCertificate {
|
|||
cc.signatureSize = C.uint(len(c.Signature))
|
||||
}
|
||||
|
||||
// HACK: pass pointer to cc as uintptr to disable Go's protection against go pointers to
|
||||
// go pointers, as the C function called here will make a deep clone and then we are going
|
||||
// HACK: pass pointer to cc as uintptr to disable Go's protection against "Go pointers to
|
||||
// Go pointers," as the C function called here will make a deep clone and then we are going
|
||||
// to throw away 'cc' and its components.
|
||||
cc2 := &CCertificate{C: unsafe.Pointer(C._ZT_Certificate_clone2(C.uintptr_t(uintptr(unsafe.Pointer(&cc)))))}
|
||||
runtime.SetFinalizer(cc2, func(obj interface{}) {
|
||||
|
@ -427,6 +426,27 @@ func (c *Certificate) Marshal() ([]byte, error) {
|
|||
return append(make([]byte, 0, int(encodedSize)), encoded[0:int(encodedSize)]...), nil
|
||||
}
|
||||
|
||||
// Sign signs this certificate and returns a new one with signature and issuer filled out.
|
||||
// This should only be used after decoding a CSR with NewCertificateFromBytes. The non-subject
|
||||
// parts of this Certificate, if any, are ignored. A new Certificate is returned with a completed
|
||||
// signature.
|
||||
func (c *Certificate) Sign(id *Identity) (*Certificate, error) {
|
||||
if id == nil || !id.HasPrivate() || !id.initCIdentityPtr() {
|
||||
return nil, ErrInvalidParameter
|
||||
}
|
||||
ctmp := c.CCertificate()
|
||||
if ctmp == nil {
|
||||
return nil, ErrInternal
|
||||
}
|
||||
var signedCert [16384]byte
|
||||
signedCertSize := C.int(16384)
|
||||
rv := int(C.ZT_Certificate_sign((*C.ZT_Certificate)(ctmp.C), id.cid, unsafe.Pointer(&signedCert[0]), &signedCertSize))
|
||||
if rv != 0 {
|
||||
return nil, fmt.Errorf("signing failed: error %d", rv)
|
||||
}
|
||||
return NewCertificateFromBytes(signedCert[0:int(signedCertSize)], true)
|
||||
}
|
||||
|
||||
// Verify returns nil on success or a certificate error if there is a problem with this certificate.
|
||||
func (c *Certificate) Verify() error {
|
||||
cc := c.CCertificate()
|
||||
|
@ -436,6 +456,12 @@ func (c *Certificate) Verify() error {
|
|||
return certificateErrorToError(int(C.ZT_Certificate_verify((*C.ZT_Certificate)(cc.C))))
|
||||
}
|
||||
|
||||
// JSON returns this certificate as a human-readable indented JSON string.
|
||||
func (c *Certificate) JSON() string {
|
||||
j, _ := json.MarshalIndent(c, "", " ")
|
||||
return string(j)
|
||||
}
|
||||
|
||||
// NewCertificateSubjectUniqueId creates a new certificate subject unique ID and corresponding private key.
|
||||
// Right now only one type is supported: CertificateUniqueIdTypeNistP384
|
||||
func NewCertificateSubjectUniqueId(uniqueIdType int) (id []byte, priv []byte, err error) {
|
||||
|
@ -444,13 +470,14 @@ func NewCertificateSubjectUniqueId(uniqueIdType int) (id []byte, priv []byte, er
|
|||
return
|
||||
}
|
||||
id = make([]byte, int(C.ZT_CERTIFICATE_UNIQUE_ID_TYPE_NIST_P_384_SIZE))
|
||||
priv = make([]byte, int(C.ZT_CERTIFICATE_UNIQUE_ID_TYPE_NIST_P_384_SIZE))
|
||||
priv = make([]byte, int(C.ZT_CERTIFICATE_UNIQUE_ID_TYPE_NIST_P_384_PRIVATE_SIZE))
|
||||
idSize := C.int(len(id))
|
||||
idPrivateSize := C.int(len(priv))
|
||||
if C.ZT_Certificate_newSubjectUniqueId((C.enum_ZT_CertificateUniqueIdType)(uniqueIdType), unsafe.Pointer(&id[0]), &idSize, unsafe.Pointer(&priv[0]), &idPrivateSize) != 0 {
|
||||
rv := int(C.ZT_Certificate_newSubjectUniqueId((C.enum_ZT_CertificateUniqueIdType)(uniqueIdType), unsafe.Pointer(&id[0]), &idSize, unsafe.Pointer(&priv[0]), &idPrivateSize))
|
||||
if rv != 0 {
|
||||
id = nil
|
||||
priv = nil
|
||||
err = ErrInvalidParameter
|
||||
err = fmt.Errorf("error %d", rv)
|
||||
return
|
||||
}
|
||||
if int(idSize) != len(id) || int(idPrivateSize) != len(priv) {
|
||||
|
|
|
@ -78,7 +78,11 @@ func newIdentityFromCIdentity(cid unsafe.Pointer) (*Identity, error) {
|
|||
// initCIdentityPtr returns a pointer to the core ZT_Identity instance or nil/0 on error.
|
||||
func (id *Identity) initCIdentityPtr() bool {
|
||||
if uintptr(id.cid) == 0 {
|
||||
idCStr := C.CString(id.String())
|
||||
str := id.PrivateKeyString()
|
||||
if len(str) == 0 {
|
||||
str = id.String()
|
||||
}
|
||||
idCStr := C.CString(str)
|
||||
defer C.free(unsafe.Pointer(idCStr))
|
||||
id.cid = C.ZT_Identity_fromString(idCStr)
|
||||
if uintptr(id.cid) == 0 {
|
||||
|
|
Loading…
Add table
Reference in a new issue