mirror of
https://github.com/zerotier/ZeroTierOne.git
synced 2025-06-06 20:43: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
|
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
|
var c zerotier.Certificate
|
||||||
|
|
||||||
c.SerialNo = make([]byte, 48)
|
c.SerialNo = make([]byte, 48)
|
||||||
|
@ -39,6 +45,7 @@ func TestCertificate() bool {
|
||||||
c.Timestamp = 5678
|
c.Timestamp = 5678
|
||||||
c.Validity[0] = 1010
|
c.Validity[0] = 1010
|
||||||
c.Validity[1] = 2020
|
c.Validity[1] = 2020
|
||||||
|
|
||||||
c.Subject.Timestamp = 31337
|
c.Subject.Timestamp = 31337
|
||||||
c.Subject.Identities = append(c.Subject.Identities, zerotier.CertificateIdentity{
|
c.Subject.Identities = append(c.Subject.Identities, zerotier.CertificateIdentity{
|
||||||
Identity: id,
|
Identity: id,
|
||||||
|
@ -65,8 +72,8 @@ func TestCertificate() bool {
|
||||||
c.Subject.Name.Email = "j"
|
c.Subject.Name.Email = "j"
|
||||||
c.Subject.Name.URL = "k"
|
c.Subject.Name.URL = "k"
|
||||||
c.Subject.Name.Host = "l"
|
c.Subject.Name.Host = "l"
|
||||||
c.Subject.UniqueID = []byte("asdf")
|
c.Subject.UniqueID = uniqueId
|
||||||
c.Subject.UniqueIDProofSignature = []byte("ghij")
|
|
||||||
c.Issuer = id
|
c.Issuer = id
|
||||||
c.IssuerName.SerialNo = "m"
|
c.IssuerName.SerialNo = "m"
|
||||||
c.IssuerName.CommonName = "n"
|
c.IssuerName.CommonName = "n"
|
||||||
|
@ -80,6 +87,7 @@ func TestCertificate() bool {
|
||||||
c.IssuerName.Email = "v"
|
c.IssuerName.Email = "v"
|
||||||
c.IssuerName.URL = "w"
|
c.IssuerName.URL = "w"
|
||||||
c.IssuerName.Host = "x"
|
c.IssuerName.Host = "x"
|
||||||
|
|
||||||
c.ExtendedAttributes = c.SerialNo
|
c.ExtendedAttributes = c.SerialNo
|
||||||
c.MaxPathLength = 9999
|
c.MaxPathLength = 9999
|
||||||
c.Signature = []byte("qwerty")
|
c.Signature = []byte("qwerty")
|
||||||
|
@ -96,9 +104,8 @@ func TestCertificate() bool {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
j, _ := json.MarshalIndent(c, "", " ")
|
j, _ := json.Marshal(c)
|
||||||
j2, _ := json.MarshalIndent(c2, "", " ")
|
j2, _ := json.Marshal(c2)
|
||||||
|
|
||||||
if !bytes.Equal(j, j2) {
|
if !bytes.Equal(j, j2) {
|
||||||
j, _ = json.MarshalIndent(c, "", " ")
|
j, _ = json.MarshalIndent(c, "", " ")
|
||||||
fmt.Print(" Deep equality test failed: certificates do not match! (see dumps below)\n\n")
|
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.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
|
return true
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,6 +14,7 @@
|
||||||
#include "Certificate.hpp"
|
#include "Certificate.hpp"
|
||||||
#include "SHA512.hpp"
|
#include "SHA512.hpp"
|
||||||
#include "ECC384.hpp"
|
#include "ECC384.hpp"
|
||||||
|
#include "ScopedPtr.hpp"
|
||||||
|
|
||||||
namespace ZeroTier {
|
namespace ZeroTier {
|
||||||
|
|
||||||
|
@ -24,10 +25,7 @@ Certificate::Certificate() noexcept
|
||||||
}
|
}
|
||||||
|
|
||||||
Certificate::Certificate(const ZT_Certificate &apiCert)
|
Certificate::Certificate(const ZT_Certificate &apiCert)
|
||||||
{
|
{ *this = apiCert; }
|
||||||
ZT_Certificate *const sup = this;
|
|
||||||
Utils::copy< sizeof(ZT_Certificate) >(sup, &apiCert);
|
|
||||||
}
|
|
||||||
|
|
||||||
Certificate::Certificate(const Certificate &cert)
|
Certificate::Certificate(const Certificate &cert)
|
||||||
{ *this = cert; }
|
{ *this = cert; }
|
||||||
|
@ -62,22 +60,30 @@ Certificate &Certificate::operator=(const ZT_Certificate &cert)
|
||||||
this->signature = nullptr;
|
this->signature = nullptr;
|
||||||
this->signatureSize = 0;
|
this->signatureSize = 0;
|
||||||
|
|
||||||
for (unsigned int i = 0; i < cert.subject.identityCount; ++i) {
|
if (cert.subject.identities) {
|
||||||
if (cert.subject.identities[i].identity) {
|
for (unsigned int i = 0; i < cert.subject.identityCount; ++i) {
|
||||||
if (cert.subject.identities[i].locator)
|
if (cert.subject.identities[i].identity) {
|
||||||
addSubjectIdentity(*reinterpret_cast<const Identity *>(cert.subject.identities[i].identity), *reinterpret_cast<const Locator *>(cert.subject.identities[i].locator));
|
if (cert.subject.identities[i].locator) {
|
||||||
else addSubjectIdentity(*reinterpret_cast<const Identity *>(cert.subject.identities[i].identity));
|
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) {
|
||||||
if (cert.subject.networks[i].id)
|
for (unsigned int i = 0; i < cert.subject.networkCount; ++i) {
|
||||||
addSubjectNetwork(cert.subject.networks[i].id, cert.subject.networks[i].controller);
|
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) {
|
||||||
if (cert.subject.certificates[i])
|
for (unsigned int i = 0; i < cert.subject.certificateCount; ++i) {
|
||||||
addSubjectCertificate(cert.subject.certificates[i]);
|
if (cert.subject.certificates[i])
|
||||||
|
addSubjectCertificate(cert.subject.certificates[i]);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (cert.subject.updateURLs) {
|
if (cert.subject.updateURLs) {
|
||||||
|
@ -99,8 +105,8 @@ Certificate &Certificate::operator=(const ZT_Certificate &cert)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (cert.issuer) {
|
if (cert.issuer) {
|
||||||
m_identities.push_back(*reinterpret_cast<const Identity *>(cert.issuer));
|
m_identities.push_front(*reinterpret_cast<const Identity *>(cert.issuer));
|
||||||
this->issuer = &(m_identities.back());
|
this->issuer = &(m_identities.front());
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((cert.extendedAttributes) && (cert.extendedAttributesSize > 0)) {
|
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)
|
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.
|
// 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.
|
// Enlarge array of ZT_Certificate_Identity structs and set pointer to potentially reallocated array.
|
||||||
m_subjectIdentities.back().identity = &(m_identities.back());
|
m_subjectIdentities.push_back(ZT_Certificate_Identity());
|
||||||
|
m_subjectIdentities.back().identity = &(m_identities.front());
|
||||||
m_subjectIdentities.back().locator = nullptr;
|
m_subjectIdentities.back().locator = nullptr;
|
||||||
|
this->subject.identities = m_subjectIdentities.data();
|
||||||
|
this->subject.identityCount = (unsigned int)m_subjectIdentities.size();
|
||||||
|
|
||||||
return &(m_subjectIdentities.back());
|
return &(m_subjectIdentities.back());
|
||||||
}
|
}
|
||||||
|
@ -140,10 +146,10 @@ ZT_Certificate_Identity *Certificate::addSubjectIdentity(const Identity &id, con
|
||||||
ZT_Certificate_Identity *const n = addSubjectIdentity(id);
|
ZT_Certificate_Identity *const n = addSubjectIdentity(id);
|
||||||
|
|
||||||
// Store local copy of locator.
|
// Store local copy of locator.
|
||||||
m_locators.push_back(loc);
|
m_locators.push_front(loc);
|
||||||
|
|
||||||
// Set pointer to stored local copy of locator.
|
// Set pointer to stored local copy of locator.
|
||||||
n->locator = &(m_locators.back());
|
n->locator = &(m_locators.front());
|
||||||
|
|
||||||
return n;
|
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])
|
void Certificate::addSubjectCertificate(const uint8_t serialNo[ZT_SHA384_DIGEST_SIZE])
|
||||||
{
|
{
|
||||||
// Store local copy of serial in m_serials container.
|
// 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
|
// Enlarge array of uint8_t pointers, set new pointer to local copy of serial, and set
|
||||||
// certificates to point to potentially reallocated array.
|
// certificates to point to potentially reallocated array.
|
||||||
m_subjectCertificates.resize(++this->subject.certificateCount);
|
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();
|
this->subject.certificates = m_subjectCertificates.data();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Certificate::addSubjectUpdateUrl(const char *url)
|
void Certificate::addSubjectUpdateUrl(const char *url)
|
||||||
{
|
{
|
||||||
|
if ((!url) || (!url[0]))
|
||||||
|
return;
|
||||||
|
|
||||||
// Store local copy of URL.
|
// 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
|
// Add pointer to local copy to pointer array and update C structure to point to
|
||||||
// potentially reallocated array.
|
// 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.updateURLs = m_updateUrls.data();
|
||||||
this->subject.updateURLCount = (unsigned int)m_updateUrls.size();
|
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();
|
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 > Certificate::encode(const bool omitSignature) const
|
||||||
{
|
{
|
||||||
Vector< uint8_t > enc;
|
Vector< uint8_t > enc;
|
||||||
|
@ -204,12 +235,14 @@ Vector< uint8_t > Certificate::encode(const bool omitSignature) const
|
||||||
|
|
||||||
if (this->flags != 0)
|
if (this->flags != 0)
|
||||||
d.add("f", this->flags);
|
d.add("f", this->flags);
|
||||||
d.add("t", (uint64_t)this->timestamp);
|
if (this->timestamp > 0)
|
||||||
d.add("v#0", (uint64_t)this->validity[0]);
|
d.add("t", (uint64_t)this->timestamp);
|
||||||
d.add("v#1", (uint64_t)this->validity[1]);
|
if (this->validity[0] > 0)
|
||||||
if ((this->extendedAttributes) && (this->extendedAttributesSize > 0))
|
d.add("v#0", (uint64_t)this->validity[0]);
|
||||||
d["x"].assign(this->extendedAttributes, this->extendedAttributes + this->extendedAttributesSize);
|
if (this->validity[1] > 0)
|
||||||
d.add("mP", (uint64_t)this->maxPathLength);
|
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);
|
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))
|
if ((this->extendedAttributes) && (this->extendedAttributesSize > 0))
|
||||||
d["x"].assign(this->extendedAttributes, this->extendedAttributes + this->extendedAttributesSize);
|
d["x"].assign(this->extendedAttributes, this->extendedAttributes + this->extendedAttributesSize);
|
||||||
|
|
||||||
if ((!omitSignature) && (this->signatureSize > 0) && (this->signature))
|
if ((!omitSignature) && (this->signature) && (this->signatureSize > 0))
|
||||||
d["si"].assign(this->signature, this->signature + this->signatureSize);
|
d["S"].assign(this->signature, this->signature + this->signatureSize);
|
||||||
|
|
||||||
d.encode(enc);
|
d.encode(enc);
|
||||||
return 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)
|
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;
|
Dictionary d;
|
||||||
if (!d.decode(data, len))
|
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$");
|
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, "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, "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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
cnt = (unsigned int)d.getUI("s.n$");
|
cnt = (unsigned int)d.getUI("s.nw$");
|
||||||
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, "s.n$.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, "s.n$.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, "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());
|
||||||
}
|
}
|
||||||
|
|
||||||
cnt = (unsigned int)d.getUI("s.u$");
|
cnt = (unsigned int)d.getUI("s.u$");
|
||||||
for (unsigned int i = 0; i < cnt; ++i)
|
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.sN", this->subject.name.serialNo, sizeof(this->subject.name.serialNo));
|
||||||
d.getS("s.n.cN", this->subject.name.commonName, sizeof(this->subject.name.commonName));
|
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()) {
|
if (!issuerData.empty()) {
|
||||||
Identity id;
|
Identity id;
|
||||||
if (id.unmarshal(issuerData.data(), (int)issuerData.size()) > 0) {
|
if (id.unmarshal(issuerData.data(), (int)issuerData.size()) > 0) {
|
||||||
m_identities.push_back(id);
|
m_identities.push_front(id);
|
||||||
this->issuer = reinterpret_cast<const Identity *>(&(m_identities.back()));
|
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$");
|
cnt = (unsigned int)d.getUI("u$");
|
||||||
for (unsigned int i = 0; i < cnt; ++i) {
|
for (unsigned int i = 0; i < cnt; ++i) {
|
||||||
const char *const url = d.getS(Dictionary::arraySubscript(tmp, "u$", i), tmp2, sizeof(tmp2));
|
const char *const url = d.getS(Dictionary::arraySubscript(tmp, sizeof(tmp), "u$", i), tmp2, sizeof(tmp2));
|
||||||
if (url)
|
if ((url) && (*url != 0)) {
|
||||||
addSubjectUpdateUrl(tmp2);
|
addSubjectUpdateUrl(url);
|
||||||
else return false;
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
m_extendedAttributes = d["x"];
|
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();
|
this->extendedAttributesSize = (unsigned int)m_extendedAttributes.size();
|
||||||
}
|
}
|
||||||
|
|
||||||
m_signature = d["si"];
|
m_signature = d["S"];
|
||||||
if (!m_signature.empty()) {
|
if (!m_signature.empty()) {
|
||||||
this->signature = m_signature.data();
|
this->signature = m_signature.data();
|
||||||
this->signatureSize = (unsigned int)m_signature.size();
|
this->signatureSize = (unsigned int)m_signature.size();
|
||||||
|
@ -395,16 +436,23 @@ Vector< uint8_t > Certificate::encodeCSR()
|
||||||
|
|
||||||
bool Certificate::sign(const Identity &issuer)
|
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());
|
SHA384(this->serialNo, enc.data(), (unsigned int)enc.size());
|
||||||
|
|
||||||
uint8_t sig[ZT_SIGNATURE_BUFFER_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) {
|
if (sigSize > 0) {
|
||||||
m_signature.assign(sig, sig + sigSize);
|
m_signature.assign(sig, sig + sigSize);
|
||||||
this->signature = m_signature.data();
|
this->signature = m_signature.data();
|
||||||
this->signatureSize = sigSize;
|
this->signatureSize = sigSize;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
m_signature.clear();
|
m_signature.clear();
|
||||||
this->signature = nullptr;
|
this->signature = nullptr;
|
||||||
this->signatureSize = 0;
|
this->signatureSize = 0;
|
||||||
|
@ -425,7 +473,7 @@ ZT_CertificateError Certificate::verify() const
|
||||||
if (this->subject.uniqueIdProofSignatureSize > 0) {
|
if (this->subject.uniqueIdProofSignatureSize > 0) {
|
||||||
if (
|
if (
|
||||||
(this->subject.uniqueIdProofSignatureSize != ZT_ECC384_SIGNATURE_SIZE) ||
|
(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))
|
(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;
|
Dictionary tmp;
|
||||||
|
@ -456,7 +504,7 @@ ZT_CertificateError Certificate::verify() const
|
||||||
return ZT_CERTIFICATE_ERROR_MISSING_REQUIRED_FIELDS;
|
return ZT_CERTIFICATE_ERROR_MISSING_REQUIRED_FIELDS;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this->subject.updateURLCount) {
|
if (this->subject.updateURLCount > 0) {
|
||||||
if (!this->subject.updateURLs)
|
if (!this->subject.updateURLs)
|
||||||
return ZT_CERTIFICATE_ERROR_INVALID_FORMAT;
|
return ZT_CERTIFICATE_ERROR_INVALID_FORMAT;
|
||||||
for (unsigned int i = 0; i < this->subject.updateURLCount; ++i) {
|
for (unsigned int i = 0; i < this->subject.updateURLCount; ++i) {
|
||||||
|
@ -471,26 +519,6 @@ ZT_CertificateError Certificate::verify() const
|
||||||
return ZT_CERTIFICATE_ERROR_NONE;
|
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()
|
void Certificate::m_clear()
|
||||||
{
|
{
|
||||||
ZT_Certificate *const sup = this;
|
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)
|
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.t", (uint64_t)s.timestamp);
|
||||||
|
|
||||||
d.add("s.i$", (uint64_t)s.identityCount);
|
if (s.identities) {
|
||||||
for (unsigned int i = 0; i < s.identityCount; ++i) {
|
d.add("s.i$", (uint64_t)s.identityCount);
|
||||||
if (s.identities[i].identity)
|
for (unsigned int i = 0; i < s.identityCount; ++i) {
|
||||||
d.addO(Dictionary::arraySubscript(tmp, "s.i$.i", i), *reinterpret_cast<const Identity *>(s.identities[i].identity));
|
if (s.identities[i].identity)
|
||||||
if (s.identities[i].locator)
|
d.addO(Dictionary::arraySubscript(tmp, sizeof(tmp), "s.i$.i", i), *reinterpret_cast<const Identity *>(s.identities[i].identity));
|
||||||
d.addO(Dictionary::arraySubscript(tmp, "s.i$.l", i), *reinterpret_cast<const Locator *>(s.identities[i].locator));
|
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);
|
if (s.networks) {
|
||||||
for (unsigned int i = 0; i < s.networkCount; ++i) {
|
d.add("s.nw$", (uint64_t)s.networkCount);
|
||||||
d.add(Dictionary::arraySubscript(tmp, "s.n$.i", i), s.networks[i].id);
|
for (unsigned int i = 0; i < s.networkCount; ++i) {
|
||||||
Fingerprint fp(s.networks[i].controller);
|
d.add(Dictionary::arraySubscript(tmp, sizeof(tmp), "s.nw$.i", i), s.networks[i].id);
|
||||||
d.addO(Dictionary::arraySubscript(tmp, "s.n$.c", i), fp);
|
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);
|
if (s.certificates) {
|
||||||
for (unsigned int i = 0; i < s.certificateCount; ++i) {
|
d.add("s.c$", (uint64_t)s.certificateCount);
|
||||||
if (s.certificates[i])
|
for (unsigned int i = 0; i < s.certificateCount; ++i) {
|
||||||
d[Dictionary::arraySubscript(tmp, "s.c$", i)].assign(s.certificates[i], s.certificates[i] + ZT_SHA384_DIGEST_SIZE);
|
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) {
|
if (s.updateURLs) {
|
||||||
|
d.add("s.u$", (uint64_t)s.updateURLCount);
|
||||||
for (unsigned int i = 0; i < s.updateURLCount; ++i)
|
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])
|
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])
|
if (s.name.host[0])
|
||||||
d.add("s.n.h", s.name.host);
|
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);
|
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);
|
d["s.uS"].assign(s.uniqueIdProofSignature, s.uniqueIdProofSignature + s.uniqueIdProofSignatureSize);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -586,7 +620,7 @@ int ZT_Certificate_newSubjectUniqueId(
|
||||||
void *uniqueIdPrivate,
|
void *uniqueIdPrivate,
|
||||||
int *uniqueIdPrivateSize)
|
int *uniqueIdPrivateSize)
|
||||||
{
|
{
|
||||||
switch(type) {
|
switch (type) {
|
||||||
case ZT_CERTIFICATE_UNIQUE_ID_TYPE_NIST_P_384:
|
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))
|
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;
|
return ZT_RESULT_ERROR_BAD_PARAMETER;
|
||||||
|
@ -631,15 +665,22 @@ int ZT_Certificate_sign(
|
||||||
{
|
{
|
||||||
if (!cert)
|
if (!cert)
|
||||||
return ZT_RESULT_ERROR_BAD_PARAMETER;
|
return ZT_RESULT_ERROR_BAD_PARAMETER;
|
||||||
ZeroTier::Certificate c(*cert);
|
|
||||||
if (!c.sign(*reinterpret_cast<const ZeroTier::Identity *>(signer)))
|
try {
|
||||||
return ZT_RESULT_ERROR_BAD_PARAMETER;
|
const ZeroTier::ScopedPtr< ZeroTier::Certificate > c(new ZeroTier::Certificate(*cert));
|
||||||
ZeroTier::Vector< uint8_t > enc(c.encode());
|
if (!c->sign(*reinterpret_cast<const ZeroTier::Identity *>(signer)))
|
||||||
if ((int)enc.size() > *signedCertSize)
|
return ZT_RESULT_ERROR_INTERNAL;
|
||||||
return ZT_RESULT_ERROR_BAD_PARAMETER;
|
|
||||||
ZeroTier::Utils::copy(signedCert, enc.data(), (unsigned int)enc.size());
|
const ZeroTier::Vector< uint8_t > enc(c->encode());
|
||||||
*signedCertSize = (int)enc.size();
|
if ((int)enc.size() > *signedCertSize)
|
||||||
return ZT_RESULT_OK;
|
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(
|
enum ZT_CertificateError ZT_Certificate_decode(
|
||||||
|
@ -649,7 +690,7 @@ enum ZT_CertificateError ZT_Certificate_decode(
|
||||||
int verify)
|
int verify)
|
||||||
{
|
{
|
||||||
try {
|
try {
|
||||||
if (!decodedCert)
|
if ((!decodedCert) || (!cert) || (certSize <= 0))
|
||||||
return ZT_CERTIFICATE_ERROR_INVALID_FORMAT;
|
return ZT_CERTIFICATE_ERROR_INVALID_FORMAT;
|
||||||
*decodedCert = nullptr;
|
*decodedCert = nullptr;
|
||||||
ZeroTier::Certificate *const c = new ZeroTier::Certificate();
|
ZeroTier::Certificate *const c = new ZeroTier::Certificate();
|
||||||
|
@ -658,7 +699,7 @@ enum ZT_CertificateError ZT_Certificate_decode(
|
||||||
return ZT_CERTIFICATE_ERROR_INVALID_FORMAT;
|
return ZT_CERTIFICATE_ERROR_INVALID_FORMAT;
|
||||||
}
|
}
|
||||||
if (verify) {
|
if (verify) {
|
||||||
ZT_CertificateError err = c->verify();
|
const ZT_CertificateError err = c->verify();
|
||||||
if (err != ZT_CERTIFICATE_ERROR_NONE) {
|
if (err != ZT_CERTIFICATE_ERROR_NONE) {
|
||||||
delete c;
|
delete c;
|
||||||
return err;
|
return err;
|
||||||
|
@ -666,7 +707,7 @@ enum ZT_CertificateError ZT_Certificate_decode(
|
||||||
}
|
}
|
||||||
*decodedCert = c;
|
*decodedCert = c;
|
||||||
return ZT_CERTIFICATE_ERROR_NONE;
|
return ZT_CERTIFICATE_ERROR_NONE;
|
||||||
} catch ( ... ) {
|
} catch (...) {
|
||||||
return ZT_CERTIFICATE_ERROR_INVALID_FORMAT;
|
return ZT_CERTIFICATE_ERROR_INVALID_FORMAT;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -693,7 +734,7 @@ enum ZT_CertificateError ZT_Certificate_verify(const ZT_Certificate *cert)
|
||||||
if (!cert)
|
if (!cert)
|
||||||
return ZT_CERTIFICATE_ERROR_INVALID_FORMAT;
|
return ZT_CERTIFICATE_ERROR_INVALID_FORMAT;
|
||||||
return ZeroTier::Certificate(*cert).verify();
|
return ZeroTier::Certificate(*cert).verify();
|
||||||
} catch ( ... ) {
|
} catch (...) {
|
||||||
return ZT_CERTIFICATE_ERROR_INVALID_FORMAT;
|
return ZT_CERTIFICATE_ERROR_INVALID_FORMAT;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -704,7 +745,7 @@ const ZT_Certificate *ZT_Certificate_clone(const ZT_Certificate *cert)
|
||||||
if (!cert)
|
if (!cert)
|
||||||
return nullptr;
|
return nullptr;
|
||||||
return (const ZT_Certificate *)(new ZeroTier::Certificate(*cert));
|
return (const ZT_Certificate *)(new ZeroTier::Certificate(*cert));
|
||||||
} catch ( ... ) {
|
} catch (...) {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -114,6 +114,17 @@ public:
|
||||||
*/
|
*/
|
||||||
void setExtendedAttributes(const Dictionary &x);
|
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
|
* Marshal this certificate in binary form
|
||||||
*
|
*
|
||||||
|
@ -159,17 +170,6 @@ public:
|
||||||
*/
|
*/
|
||||||
ZT_CertificateError verify() const;
|
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
|
* 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
|
// 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
|
// be deleted with this certificate. Lists are used so the pointers never
|
||||||
// change.
|
// change.
|
||||||
List< Identity > m_identities;
|
ForwardList< Identity > m_identities;
|
||||||
List< Locator > m_locators;
|
ForwardList< Locator > m_locators;
|
||||||
List< String > m_strings;
|
ForwardList< String > m_strings;
|
||||||
List< SHA384Hash > m_serials;
|
ForwardList< SHA384Hash > m_serials;
|
||||||
|
|
||||||
// These are stored in a vector because the memory needs to be contiguous.
|
// These are stored in a vector because the memory needs to be contiguous.
|
||||||
Vector< ZT_Certificate_Identity > m_subjectIdentities;
|
Vector< ZT_Certificate_Identity > m_subjectIdentities;
|
||||||
|
|
|
@ -28,6 +28,7 @@
|
||||||
#ifdef __CPP11__
|
#ifdef __CPP11__
|
||||||
#include <atomic>
|
#include <atomic>
|
||||||
#include <unordered_map>
|
#include <unordered_map>
|
||||||
|
#include <forward_list>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
namespace ZeroTier {
|
namespace ZeroTier {
|
||||||
|
@ -128,6 +129,20 @@ template< typename V >
|
||||||
class List : public std::list< 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 >
|
template< typename V >
|
||||||
class Set : public std::set< V, std::less< 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)
|
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
|
const Vector< uint8_t > &Dictionary::operator[](const char *const k) const
|
||||||
{
|
{
|
||||||
static const Vector< uint8_t > s_emptyEntry;
|
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;
|
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)
|
void Dictionary::add(const char *k, const Address &v)
|
||||||
{
|
{
|
||||||
char tmp[ZT_ADDRESS_STRING_SIZE_MAX];
|
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
|
uint64_t Dictionary::getUI(const char *k, uint64_t dfl) const
|
||||||
{
|
{
|
||||||
char tmp[32];
|
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
|
if (cap == 0) // sanity check
|
||||||
return v;
|
return v;
|
||||||
|
|
||||||
const Vector< uint8_t > &e = (*this)[k];
|
const Vector< uint8_t > &e = (*this)[k];
|
||||||
if (e.empty()) {
|
if (e.empty()) {
|
||||||
v[0] = 0;
|
v[0] = 0;
|
||||||
return v;
|
return v;
|
||||||
}
|
}
|
||||||
unsigned int i = 0;
|
|
||||||
const unsigned int last = cap - 1;
|
for (unsigned int i = 0, last = (cap - 1);; ++i) {
|
||||||
for (;;) {
|
|
||||||
if ((i >= last) || (i >= (unsigned int)e.size())) {
|
if ((i >= last) || (i >= (unsigned int)e.size())) {
|
||||||
v[i] = 0;
|
v[i] = 0;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if ((v[i] = (char)e[i]) == 0) {
|
if ((v[i] = (char)e[i]) == 0)
|
||||||
break;
|
break;
|
||||||
}
|
|
||||||
++i;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return v;
|
return v;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -131,7 +104,6 @@ void Dictionary::encode(Vector< uint8_t > &out) const
|
||||||
s_appendValueByte(out, *i);
|
s_appendValueByte(out, *i);
|
||||||
out.push_back((uint8_t)'\n');
|
out.push_back((uint8_t)'\n');
|
||||||
}
|
}
|
||||||
out.push_back(0);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Dictionary::decode(const void *data, unsigned int len)
|
bool Dictionary::decode(const void *data, unsigned int len)
|
||||||
|
@ -176,20 +148,24 @@ bool Dictionary::decode(const void *data, unsigned int len)
|
||||||
} else {
|
} else {
|
||||||
if (c == (uint8_t)'=') {
|
if (c == (uint8_t)'=') {
|
||||||
v = &m_entries[k];
|
v = &m_entries[k];
|
||||||
} else if ((c < 33) || (c > 126) || (c == 92)) {
|
|
||||||
return false;
|
|
||||||
} else {
|
} else {
|
||||||
k.push_back(c);
|
k.push_back(c);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else break;
|
} else {
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return true;
|
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) {
|
if ((buf[i] = name[i]) == 0) {
|
||||||
buf[i++] = '#';
|
buf[i++] = '#';
|
||||||
Utils::hex(sub, 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;
|
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
|
} // namespace ZeroTier
|
||||||
|
|
|
@ -42,9 +42,10 @@ class Identity;
|
||||||
class Dictionary
|
class Dictionary
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
typedef SortedMap< String, Vector < uint8_t > >::const_iterator const_iterator;
|
typedef SortedMap< String, Vector< uint8_t > >::const_iterator const_iterator;
|
||||||
|
|
||||||
Dictionary();
|
Dictionary();
|
||||||
|
|
||||||
~Dictionary();
|
~Dictionary();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -53,7 +54,7 @@ public:
|
||||||
* @param k Key to look up
|
* @param k Key to look up
|
||||||
* @return Reference to value
|
* @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
|
* Get a const reference to a value
|
||||||
|
@ -61,7 +62,7 @@ public:
|
||||||
* @param k Key to look up
|
* @param k Key to look up
|
||||||
* @return Reference to value or to empty vector if not found
|
* @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
|
* @return Start of key->value pairs
|
||||||
|
@ -75,11 +76,6 @@ public:
|
||||||
ZT_INLINE const_iterator end() const noexcept
|
ZT_INLINE const_iterator end() const noexcept
|
||||||
{ return m_entries.end(); }
|
{ 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
|
* 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
|
* @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)
|
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
|
* 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
|
* @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)
|
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
|
* 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);
|
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
|
* Get an integer
|
||||||
*
|
*
|
||||||
|
@ -171,13 +164,14 @@ public:
|
||||||
template< typename T >
|
template< typename T >
|
||||||
ZT_INLINE bool addO(const char *k, T &obj)
|
ZT_INLINE bool addO(const char *k, T &obj)
|
||||||
{
|
{
|
||||||
uint8_t tmp[4096];
|
Vector< uint8_t > &d = (*this)[k];
|
||||||
static_assert(sizeof(tmp) >= T::marshalSizeMax(),"buffer too small");
|
d.resize(T::marshalSizeMax());
|
||||||
int l = obj.marshal(tmp);
|
const int l = obj.marshal(d.data());
|
||||||
if (l > 0) {
|
if (l > 0) {
|
||||||
(*this)[k].assign(tmp, tmp + l);
|
d.resize(l);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
d.clear();
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -203,7 +197,7 @@ public:
|
||||||
*
|
*
|
||||||
* @param out String encoded dictionary
|
* @param out String encoded dictionary
|
||||||
*/
|
*/
|
||||||
void encode(Vector <uint8_t> &out) const;
|
void encode(Vector< uint8_t > &out) const;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Decode a string encoded dictionary
|
* Decode a string encoded dictionary
|
||||||
|
@ -362,7 +356,7 @@ public:
|
||||||
template< typename V, typename T >
|
template< typename V, typename T >
|
||||||
static ZT_INLINE int appendObject(V &out, const char *const k, const T &v)
|
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))
|
if (T::marshalSizeMax() > sizeof(tmp))
|
||||||
return -1;
|
return -1;
|
||||||
const int mlen = v.marshal(tmp);
|
const int mlen = v.marshal(tmp);
|
||||||
|
@ -379,7 +373,7 @@ public:
|
||||||
* @param sub Subscript index
|
* @param sub Subscript index
|
||||||
* @return Pointer to 'buf'
|
* @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:
|
private:
|
||||||
template< typename V >
|
template< typename V >
|
||||||
|
@ -417,20 +411,17 @@ private:
|
||||||
{
|
{
|
||||||
for (;;) {
|
for (;;) {
|
||||||
const char c = *(k++);
|
const char c = *(k++);
|
||||||
if ((c >= 33) && (c <= 126) && (c != 61) && (c != 92)) // printable ASCII with no spaces, equals, or backslash
|
if (c == 0)
|
||||||
out.push_back((uint8_t)c);
|
|
||||||
else if (c == 0)
|
|
||||||
break;
|
break;
|
||||||
|
out.push_back((uint8_t)c);
|
||||||
}
|
}
|
||||||
out.push_back((uint8_t)'=');
|
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
|
// 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
|
// 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.
|
// 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
|
} // namespace ZeroTier
|
||||||
|
|
|
@ -37,7 +37,7 @@ public:
|
||||||
{ memoryZero(this); }
|
{ memoryZero(this); }
|
||||||
|
|
||||||
ZT_INLINE Fingerprint(const ZT_Fingerprint &fp) noexcept
|
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)
|
* @return True if hash is not all zero (missing/unspecified)
|
||||||
|
@ -59,7 +59,12 @@ public:
|
||||||
}
|
}
|
||||||
return s;
|
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
|
* Set this fingerprint to a base32-encoded string
|
||||||
|
@ -71,18 +76,18 @@ public:
|
||||||
{
|
{
|
||||||
if (!s)
|
if (!s)
|
||||||
return false;
|
return false;
|
||||||
const int l = (int) strlen(s);
|
const int l = (int)strlen(s);
|
||||||
if (l < ZT_ADDRESS_LENGTH_HEX)
|
if (l < ZT_ADDRESS_LENGTH_HEX)
|
||||||
return false;
|
return false;
|
||||||
char a[ZT_ADDRESS_LENGTH_HEX + 1];
|
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;
|
a[ZT_ADDRESS_LENGTH_HEX] = 0;
|
||||||
this->address = Utils::hexStrToU64(a) & ZT_ADDRESS_MASK;
|
this->address = Utils::hexStrToU64(a) & ZT_ADDRESS_MASK;
|
||||||
if (l > (ZT_ADDRESS_LENGTH_HEX + 1)) {
|
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)
|
if (Utils::b32d(s + (ZT_ADDRESS_LENGTH_HEX + 1), this->hash, ZT_FINGERPRINT_HASH_SIZE) != ZT_FINGERPRINT_HASH_SIZE)
|
||||||
return false;
|
return false;
|
||||||
} else {
|
} else {
|
||||||
Utils::zero<ZT_FINGERPRINT_HASH_SIZE>(this->hash);
|
Utils::zero< ZT_FINGERPRINT_HASH_SIZE >(this->hash);
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -120,7 +125,7 @@ public:
|
||||||
ZT_INLINE int marshal(uint8_t data[ZT_FINGERPRINT_MARSHAL_SIZE]) const noexcept
|
ZT_INLINE int marshal(uint8_t data[ZT_FINGERPRINT_MARSHAL_SIZE]) const noexcept
|
||||||
{
|
{
|
||||||
Address(this->address).copyTo(data);
|
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;
|
return ZT_FINGERPRINT_MARSHAL_SIZE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -129,7 +134,7 @@ public:
|
||||||
if (unlikely(len < ZT_FINGERPRINT_MARSHAL_SIZE))
|
if (unlikely(len < ZT_FINGERPRINT_MARSHAL_SIZE))
|
||||||
return -1;
|
return -1;
|
||||||
this->address = Address(data);
|
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;
|
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);
|
C25519::sign(m_priv, m_pub, data, len, sig);
|
||||||
return ZT_C25519_SIGNATURE_LEN;
|
return ZT_C25519_SIGNATURE_LEN;
|
||||||
}
|
}
|
||||||
|
break;
|
||||||
case P384:
|
case P384:
|
||||||
if (siglen >= ZT_ECC384_SIGNATURE_SIZE) {
|
if (siglen >= ZT_ECC384_SIGNATURE_SIZE) {
|
||||||
// SECURITY: signatures also include the public keys to further enforce their coupling.
|
// 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);
|
ECC384ECDSASign(m_priv + ZT_C25519_COMBINED_PRIVATE_KEY_SIZE, h, (uint8_t *)sig);
|
||||||
return ZT_ECC384_SIGNATURE_SIZE;
|
return ZT_ECC384_SIGNATURE_SIZE;
|
||||||
}
|
}
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -350,6 +352,8 @@ char *Identity::toString(bool includePrivate, char buf[ZT_IDENTITY_STRING_BUFFER
|
||||||
*p = (char)0;
|
*p = (char)0;
|
||||||
return buf;
|
return buf;
|
||||||
}
|
}
|
||||||
|
default:
|
||||||
|
buf[0] = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
return nullptr;
|
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;
|
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);
|
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;
|
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:
|
case P384:
|
||||||
data[ZT_ADDRESS_LENGTH] = (uint8_t)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;
|
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);
|
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;
|
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;
|
return -1;
|
||||||
|
|
|
@ -68,6 +68,12 @@ public:
|
||||||
memoryZero(this);
|
memoryZero(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ZT_INLINE Identity(const Identity &id) noexcept
|
||||||
|
{
|
||||||
|
Utils::memoryLock(this, sizeof(Identity));
|
||||||
|
Utils::copy< sizeof(Identity) >(this, &id);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Construct identity from string
|
* Construct identity from string
|
||||||
*
|
*
|
||||||
|
@ -88,6 +94,13 @@ public:
|
||||||
Utils::burn(reinterpret_cast<void *>(&this->m_priv), sizeof(this->m_priv));
|
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)
|
* Set identity to NIL value (all zero)
|
||||||
*/
|
*/
|
||||||
|
@ -211,6 +224,15 @@ public:
|
||||||
*/
|
*/
|
||||||
bool fromString(const char *str);
|
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
|
* @return True if this identity contains something
|
||||||
*/
|
*/
|
||||||
|
@ -222,20 +244,27 @@ public:
|
||||||
|
|
||||||
ZT_INLINE bool operator==(const Identity &id) const noexcept
|
ZT_INLINE bool operator==(const Identity &id) const noexcept
|
||||||
{ return (m_fp == id.m_fp); }
|
{ return (m_fp == id.m_fp); }
|
||||||
|
|
||||||
ZT_INLINE bool operator!=(const Identity &id) const noexcept
|
ZT_INLINE bool operator!=(const Identity &id) const noexcept
|
||||||
{ return !(*this == id); }
|
{ return !(*this == id); }
|
||||||
|
|
||||||
ZT_INLINE bool operator<(const Identity &id) const noexcept
|
ZT_INLINE bool operator<(const Identity &id) const noexcept
|
||||||
{ return (m_fp < id.m_fp); }
|
{ return (m_fp < id.m_fp); }
|
||||||
|
|
||||||
ZT_INLINE bool operator>(const Identity &id) const noexcept
|
ZT_INLINE bool operator>(const Identity &id) const noexcept
|
||||||
{ return (id < *this); }
|
{ return (id < *this); }
|
||||||
|
|
||||||
ZT_INLINE bool operator<=(const Identity &id) const noexcept
|
ZT_INLINE bool operator<=(const Identity &id) const noexcept
|
||||||
{ return !(id < *this); }
|
{ return !(id < *this); }
|
||||||
|
|
||||||
ZT_INLINE bool operator>=(const Identity &id) const noexcept
|
ZT_INLINE bool operator>=(const Identity &id) const noexcept
|
||||||
{ return !(*this < id); }
|
{ return !(*this < id); }
|
||||||
|
|
||||||
static constexpr int marshalSizeMax() noexcept
|
static constexpr int marshalSizeMax() noexcept
|
||||||
{ return ZT_IDENTITY_MARSHAL_SIZE_MAX; }
|
{ return ZT_IDENTITY_MARSHAL_SIZE_MAX; }
|
||||||
|
|
||||||
int marshal(uint8_t data[ZT_IDENTITY_MARSHAL_SIZE_MAX], bool includePrivate = false) const noexcept;
|
int marshal(uint8_t data[ZT_IDENTITY_MARSHAL_SIZE_MAX], bool includePrivate = false) const noexcept;
|
||||||
|
|
||||||
int unmarshal(const uint8_t *data, int len) noexcept;
|
int unmarshal(const uint8_t *data, int len) noexcept;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
|
@ -20,7 +20,7 @@ static const SharedPtr< const Certificate > s_nullCert;
|
||||||
Topology::Topology(const RuntimeEnvironment *renv, void *tPtr, const int64_t now) :
|
Topology::Topology(const RuntimeEnvironment *renv, void *tPtr, const int64_t now) :
|
||||||
RR(renv)
|
RR(renv)
|
||||||
{
|
{
|
||||||
char tmp[256];
|
char tmp[32];
|
||||||
Vector< uint8_t > trustData(RR->node->stateObjectGet(tPtr, ZT_STATE_OBJECT_TRUST_STORE, Utils::ZERO256));
|
Vector< uint8_t > trustData(RR->node->stateObjectGet(tPtr, ZT_STATE_OBJECT_TRUST_STORE, Utils::ZERO256));
|
||||||
|
|
||||||
Dictionary d;
|
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$");
|
const unsigned long certCount = (unsigned long)d.getUI("c$");
|
||||||
for (unsigned long idx = 0; idx < certCount; ++idx) {
|
for (unsigned long idx = 0; idx < certCount; ++idx) {
|
||||||
uint64_t id[6];
|
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) {
|
if (serialNo.size() == ZT_SHA384_DIGEST_SIZE) {
|
||||||
Utils::copy< 48 >(id, serialNo.data());
|
Utils::copy< 48 >(id, serialNo.data());
|
||||||
Certificate cert;
|
Certificate cert;
|
||||||
Vector< uint8_t > enc(RR->node->stateObjectGet(tPtr, ZT_STATE_OBJECT_CERT, id));
|
Vector< uint8_t > enc(RR->node->stateObjectGet(tPtr, ZT_STATE_OBJECT_CERT, id));
|
||||||
if (cert.decode(enc.data(), (unsigned int)enc.size()))
|
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$");
|
const unsigned long localRootCount = (unsigned long)d.getUI("lr$");
|
||||||
for (unsigned long idx = 0; idx < localRootCount; ++idx) {
|
for (unsigned long idx = 0; idx < localRootCount; ++idx) {
|
||||||
Identity lr;
|
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)
|
if (lr)
|
||||||
m_roots[lr].insert(s_nullCert);
|
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
|
// assumes m_roots_l and m_certs_l are locked for write
|
||||||
|
|
||||||
char tmp[256];
|
char tmp[32];
|
||||||
Dictionary d;
|
Dictionary d;
|
||||||
|
|
||||||
d.add("v", (uint64_t)0); // version
|
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;
|
unsigned long idx = 0;
|
||||||
d.add("c$", (uint64_t)m_certs.size());
|
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) {
|
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[Dictionary::arraySubscript(tmp, sizeof(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.add(Dictionary::arraySubscript(tmp, sizeof(tmp), "c$.lt", idx), (uint64_t)c->second.second);
|
||||||
++idx;
|
++idx;
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned long localRootCount = 0;
|
unsigned long localRootCount = 0;
|
||||||
for (Map< Identity, Set< SharedPtr< const Certificate > > >::const_iterator r(m_roots.begin()); r != m_roots.end();) {
|
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())
|
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);
|
d.add("lr$", (uint64_t)localRootCount);
|
||||||
|
|
||||||
|
|
|
@ -733,7 +733,7 @@ static ZT_INLINE void copy(void *dest, const void *src) noexcept
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
// Avoid rep/movsb startup time for some small common sizes.
|
#ifndef ZT_NO_UNALIGNED_ACCESS
|
||||||
template<>
|
template<>
|
||||||
ZT_INLINE void copy<4>(void *dest, const void *src) noexcept
|
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 *>(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) + 8) = *reinterpret_cast<const uint64_t *>(reinterpret_cast<const uint8_t *>(src) + 8);
|
||||||
}
|
}
|
||||||
template<>
|
#endif
|
||||||
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);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Copy memory block whose size is known at run time
|
* Copy memory block whose size is known at run time
|
||||||
|
|
|
@ -18,6 +18,7 @@ package zerotier
|
||||||
import "C"
|
import "C"
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"runtime"
|
"runtime"
|
||||||
"unsafe"
|
"unsafe"
|
||||||
|
@ -136,13 +137,11 @@ func NewCertificateFromBytes(cert []byte, verify bool) (*Certificate, error) {
|
||||||
ver = 1
|
ver = 1
|
||||||
}
|
}
|
||||||
cerr := C.ZT_Certificate_decode((**C.ZT_Certificate)(unsafe.Pointer(&dec)), unsafe.Pointer(&cert[0]), C.int(len(cert)), ver)
|
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 {
|
if cerr != 0 {
|
||||||
return nil, certificateErrorToError(int(cerr))
|
return nil, certificateErrorToError(int(cerr))
|
||||||
}
|
}
|
||||||
if dec == unsafe.Pointer(nil) {
|
if dec == unsafe.Pointer(uintptr(0)) {
|
||||||
return nil, ErrInternal
|
return nil, ErrInternal
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -309,7 +308,7 @@ func (c *Certificate) CCertificate() *CCertificate {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
cc.subject.identities = &subjectIdentities[0]
|
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 {
|
if len(c.Subject.Networks) > 0 {
|
||||||
|
@ -322,7 +321,7 @@ func (c *Certificate) CCertificate() *CCertificate {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
cc.subject.networks = &subjectNetworks[0]
|
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 {
|
if len(c.Subject.Certificates) > 0 {
|
||||||
|
@ -334,7 +333,7 @@ func (c *Certificate) CCertificate() *CCertificate {
|
||||||
subjectCertificates[i] = uintptr(unsafe.Pointer(&cert[0]))
|
subjectCertificates[i] = uintptr(unsafe.Pointer(&cert[0]))
|
||||||
}
|
}
|
||||||
cc.subject.certificates = (**C.uint8_t)(unsafe.Pointer(&subjectCertificates[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 {
|
if len(c.Subject.UpdateURLs) > 0 {
|
||||||
|
@ -345,7 +344,7 @@ func (c *Certificate) CCertificate() *CCertificate {
|
||||||
subjectUpdateURLs[i] = uintptr(unsafe.Pointer(&subjectUpdateURLsData[0][0]))
|
subjectUpdateURLs[i] = uintptr(unsafe.Pointer(&subjectUpdateURLsData[0][0]))
|
||||||
}
|
}
|
||||||
cc.subject.updateURLs = (**C.char)(unsafe.Pointer(&subjectUpdateURLs[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)
|
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))
|
cc.signatureSize = C.uint(len(c.Signature))
|
||||||
}
|
}
|
||||||
|
|
||||||
// HACK: pass pointer to cc as uintptr to disable Go's protection against go pointers to
|
// 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
|
// 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.
|
// to throw away 'cc' and its components.
|
||||||
cc2 := &CCertificate{C: unsafe.Pointer(C._ZT_Certificate_clone2(C.uintptr_t(uintptr(unsafe.Pointer(&cc)))))}
|
cc2 := &CCertificate{C: unsafe.Pointer(C._ZT_Certificate_clone2(C.uintptr_t(uintptr(unsafe.Pointer(&cc)))))}
|
||||||
runtime.SetFinalizer(cc2, func(obj interface{}) {
|
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
|
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.
|
// Verify returns nil on success or a certificate error if there is a problem with this certificate.
|
||||||
func (c *Certificate) Verify() error {
|
func (c *Certificate) Verify() error {
|
||||||
cc := c.CCertificate()
|
cc := c.CCertificate()
|
||||||
|
@ -436,6 +456,12 @@ func (c *Certificate) Verify() error {
|
||||||
return certificateErrorToError(int(C.ZT_Certificate_verify((*C.ZT_Certificate)(cc.C))))
|
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.
|
// NewCertificateSubjectUniqueId creates a new certificate subject unique ID and corresponding private key.
|
||||||
// Right now only one type is supported: CertificateUniqueIdTypeNistP384
|
// Right now only one type is supported: CertificateUniqueIdTypeNistP384
|
||||||
func NewCertificateSubjectUniqueId(uniqueIdType int) (id []byte, priv []byte, err error) {
|
func NewCertificateSubjectUniqueId(uniqueIdType int) (id []byte, priv []byte, err error) {
|
||||||
|
@ -444,13 +470,14 @@ func NewCertificateSubjectUniqueId(uniqueIdType int) (id []byte, priv []byte, er
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
id = make([]byte, int(C.ZT_CERTIFICATE_UNIQUE_ID_TYPE_NIST_P_384_SIZE))
|
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))
|
idSize := C.int(len(id))
|
||||||
idPrivateSize := C.int(len(priv))
|
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
|
id = nil
|
||||||
priv = nil
|
priv = nil
|
||||||
err = ErrInvalidParameter
|
err = fmt.Errorf("error %d", rv)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if int(idSize) != len(id) || int(idPrivateSize) != len(priv) {
|
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.
|
// initCIdentityPtr returns a pointer to the core ZT_Identity instance or nil/0 on error.
|
||||||
func (id *Identity) initCIdentityPtr() bool {
|
func (id *Identity) initCIdentityPtr() bool {
|
||||||
if uintptr(id.cid) == 0 {
|
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))
|
defer C.free(unsafe.Pointer(idCStr))
|
||||||
id.cid = C.ZT_Identity_fromString(idCStr)
|
id.cid = C.ZT_Identity_fromString(idCStr)
|
||||||
if uintptr(id.cid) == 0 {
|
if uintptr(id.cid) == 0 {
|
||||||
|
|
Loading…
Add table
Reference in a new issue