mirror of
https://github.com/zerotier/ZeroTierOne.git
synced 2025-08-02 07:02:49 +02:00
Refactor certificates to have their own keys instead of being signed by identities, and fix certificate chain validation to be like how X509 certs are validated.
This commit is contained in:
parent
ad92a46b8d
commit
e7ed8051c6
15 changed files with 498 additions and 509 deletions
48
core/Buf.cpp
48
core/Buf.cpp
|
@ -27,43 +27,46 @@ void *Buf::operator new(std::size_t sz)
|
|||
uintptr_t bb;
|
||||
for (;;) {
|
||||
bb = s_pool.exchange(ZT_ATOMIC_PTR_LOCKED, std::memory_order_acquire);
|
||||
if (likely(bb != ZT_ATOMIC_PTR_LOCKED))
|
||||
break;
|
||||
Spinlock::pause();
|
||||
}
|
||||
|
||||
if (likely(bb != ZT_ATOMIC_PTR_LOCKED)) {
|
||||
Buf *b;
|
||||
if (bb) {
|
||||
s_pool.store(((Buf *)bb)->__nextInPool.load(std::memory_order_relaxed), std::memory_order_release);
|
||||
b = (Buf *)bb;
|
||||
if (likely(bb != 0)) {
|
||||
b = reinterpret_cast<Buf *>(bb);
|
||||
s_pool.store(b->__nextInPool, std::memory_order_release);
|
||||
} else {
|
||||
s_pool.store(0, std::memory_order_release);
|
||||
b = (Buf *)malloc(sz);
|
||||
b = reinterpret_cast<Buf *>(malloc(sz));
|
||||
if (!b)
|
||||
throw Utils::BadAllocException;
|
||||
s_allocated.fetch_add(1, std::memory_order_relaxed);
|
||||
}
|
||||
|
||||
b->__refCount.store(0, std::memory_order_relaxed);
|
||||
return (void *)b;
|
||||
|
||||
return reinterpret_cast<void *>(b);
|
||||
}
|
||||
|
||||
Spinlock::pause();
|
||||
}
|
||||
}
|
||||
|
||||
void Buf::operator delete(void *ptr)
|
||||
{
|
||||
if (ptr) {
|
||||
if (likely(ptr != nullptr)) {
|
||||
if (s_allocated.load(std::memory_order_relaxed) > ZT_BUF_MAX_POOL_SIZE) {
|
||||
s_allocated.fetch_sub(1, std::memory_order_relaxed);
|
||||
free(ptr);
|
||||
} else {
|
||||
uintptr_t bb;
|
||||
for (;;) {
|
||||
bb = s_pool.exchange(ZT_ATOMIC_PTR_LOCKED, std::memory_order_acquire);
|
||||
if (likely(bb != ZT_ATOMIC_PTR_LOCKED))
|
||||
break;
|
||||
if (likely(bb != ZT_ATOMIC_PTR_LOCKED)) {
|
||||
reinterpret_cast<Buf *>(ptr)->__nextInPool = bb;
|
||||
s_pool.store(reinterpret_cast<uintptr_t>(ptr), std::memory_order_release);
|
||||
return;
|
||||
}
|
||||
Spinlock::pause();
|
||||
}
|
||||
|
||||
((Buf *)ptr)->__nextInPool.store(bb, std::memory_order_relaxed);
|
||||
s_pool.store((uintptr_t)ptr, std::memory_order_release);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -73,19 +76,22 @@ void Buf::freePool() noexcept
|
|||
uintptr_t bb;
|
||||
for (;;) {
|
||||
bb = s_pool.exchange(ZT_ATOMIC_PTR_LOCKED, std::memory_order_acquire);
|
||||
if (likely(bb != ZT_ATOMIC_PTR_LOCKED))
|
||||
break;
|
||||
Spinlock::pause();
|
||||
}
|
||||
|
||||
if (likely(bb != ZT_ATOMIC_PTR_LOCKED)) {
|
||||
s_pool.store(0, std::memory_order_release);
|
||||
|
||||
while (bb != 0) {
|
||||
const uintptr_t next = ((Buf *)bb)->__nextInPool.load(std::memory_order_relaxed);
|
||||
const uintptr_t next = reinterpret_cast<Buf *>(bb)->__nextInPool;
|
||||
s_allocated.fetch_sub(1, std::memory_order_relaxed);
|
||||
free((void *)bb);
|
||||
free(reinterpret_cast<void *>(bb));
|
||||
bb = next;
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
Spinlock::pause();
|
||||
}
|
||||
}
|
||||
|
||||
long Buf::poolAllocated() noexcept
|
||||
|
|
|
@ -857,10 +857,7 @@ public:
|
|||
{ return ZT_BUF_MEM_SIZE; }
|
||||
|
||||
private:
|
||||
// Next item in free buffer pool linked list if Buf is placed in pool, undefined and unused otherwise
|
||||
std::atomic< uintptr_t > __nextInPool;
|
||||
|
||||
// Reference counter for SharedPtr<>
|
||||
volatile uintptr_t __nextInPool;
|
||||
std::atomic< int > __refCount;
|
||||
};
|
||||
|
||||
|
|
|
@ -20,6 +20,7 @@
|
|||
#include "VL1.hpp"
|
||||
#include "VL2.hpp"
|
||||
#include "CallContext.hpp"
|
||||
#include "ECC384.hpp"
|
||||
|
||||
extern "C" {
|
||||
|
||||
|
@ -658,24 +659,15 @@ ZT_MAYBE_UNUSED void ZT_Identity_delete(const ZT_Identity *id)
|
|||
|
||||
/********************************************************************************************************************/
|
||||
|
||||
ZT_MAYBE_UNUSED int ZT_Certificate_newSubjectUniqueId(
|
||||
enum ZT_CertificateUniqueIdType type,
|
||||
void *uniqueId,
|
||||
int *uniqueIdSize,
|
||||
void *uniqueIdPrivate,
|
||||
int *uniqueIdPrivateSize)
|
||||
ZT_MAYBE_UNUSED int ZT_Certificate_newKeyPair(
|
||||
const enum ZT_CertificatePublicKeyAlgorithm type,
|
||||
uint8_t publicKey[ZT_CERTIFICATE_MAX_PUBLIC_KEY_SIZE],
|
||||
int *const publicKeySize,
|
||||
uint8_t privateKey[ZT_CERTIFICATE_MAX_PRIVATE_KEY_SIZE],
|
||||
int *const privateKeySize)
|
||||
{
|
||||
try {
|
||||
switch (type) {
|
||||
case ZT_CERTIFICATE_UNIQUE_ID_TYPE_NIST_P_384:
|
||||
if ((*uniqueIdSize < ZT_CERTIFICATE_UNIQUE_ID_TYPE_NIST_P_384_SIZE) || (*uniqueIdPrivateSize < ZT_CERTIFICATE_UNIQUE_ID_TYPE_NIST_P_384_PRIVATE_SIZE))
|
||||
return ZT_RESULT_ERROR_BAD_PARAMETER;
|
||||
*uniqueIdSize = ZT_CERTIFICATE_UNIQUE_ID_TYPE_NIST_P_384_SIZE;
|
||||
*uniqueIdPrivateSize = ZT_CERTIFICATE_UNIQUE_ID_TYPE_NIST_P_384_PRIVATE_SIZE;
|
||||
ZeroTier::Certificate::createSubjectUniqueId(reinterpret_cast<uint8_t *>(uniqueId), reinterpret_cast<uint8_t *>(uniqueIdPrivate));
|
||||
return ZT_RESULT_OK;
|
||||
}
|
||||
return ZT_RESULT_ERROR_BAD_PARAMETER;
|
||||
return ZeroTier::Certificate::newKeyPair(type, publicKey, publicKeySize, privateKey, privateKeySize) ? ZT_RESULT_OK : ZT_RESULT_ERROR_BAD_PARAMETER;
|
||||
} catch ( ... ) {
|
||||
return ZT_RESULT_FATAL_ERROR_INTERNAL;
|
||||
}
|
||||
|
@ -683,18 +675,18 @@ ZT_MAYBE_UNUSED int ZT_Certificate_newSubjectUniqueId(
|
|||
|
||||
ZT_MAYBE_UNUSED int ZT_Certificate_newCSR(
|
||||
const ZT_Certificate_Subject *subject,
|
||||
const void *uniqueId,
|
||||
int uniqueIdSize,
|
||||
const void *uniqueIdPrivate,
|
||||
int uniqueIdPrivateSize,
|
||||
void *csr,
|
||||
int *csrSize)
|
||||
const void *const certificatePublicKey,
|
||||
const int certificatePublicKeySize,
|
||||
const void *const uniqueIdPrivateKey,
|
||||
const int uniqueIdPrivateKeySize,
|
||||
void *const csr,
|
||||
int *const csrSize)
|
||||
{
|
||||
try {
|
||||
if (!subject)
|
||||
if ((!subject) || (!certificatePublicKey) || (certificatePublicKeySize <= 0) || (certificatePublicKeySize > ZT_CERTIFICATE_MAX_PUBLIC_KEY_SIZE))
|
||||
return ZT_RESULT_ERROR_BAD_PARAMETER;
|
||||
const ZeroTier::Vector< uint8_t > csrV(ZeroTier::Certificate::createCSR(*subject, uniqueId, uniqueIdSize, uniqueIdPrivate, uniqueIdPrivateSize));
|
||||
if ((int)csrV.size() > *csrSize)
|
||||
const ZeroTier::Vector< uint8_t > csrV(ZeroTier::Certificate::createCSR(*subject, certificatePublicKey, (unsigned int)certificatePublicKeySize, uniqueIdPrivateKey, (unsigned int)uniqueIdPrivateKeySize));
|
||||
if (csrV.empty() || ((int)csrV.size() > *csrSize))
|
||||
return ZT_RESULT_ERROR_BAD_PARAMETER;
|
||||
ZeroTier::Utils::copy(csr, csrV.data(), (unsigned int)csrV.size());
|
||||
*csrSize = (int)csrV.size();
|
||||
|
@ -704,29 +696,21 @@ ZT_MAYBE_UNUSED int ZT_Certificate_newCSR(
|
|||
}
|
||||
}
|
||||
|
||||
ZT_MAYBE_UNUSED int ZT_Certificate_sign(
|
||||
ZT_MAYBE_UNUSED ZT_Certificate *ZT_Certificate_sign(
|
||||
const ZT_Certificate *cert,
|
||||
const ZT_Identity *signer,
|
||||
void *signedCert,
|
||||
int *signedCertSize)
|
||||
const uint8_t issuer[ZT_CERTIFICATE_HASH_SIZE],
|
||||
const void *issuerPrivateKey,
|
||||
int issuerPrivateKeySize)
|
||||
{
|
||||
try {
|
||||
if (!cert)
|
||||
return ZT_RESULT_ERROR_BAD_PARAMETER;
|
||||
ZeroTier::Certificate c(*cert);
|
||||
if (!c.sign(*reinterpret_cast<const ZeroTier::Identity *>(signer)))
|
||||
return ZT_RESULT_ERROR_INTERNAL;
|
||||
|
||||
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;
|
||||
ZeroTier::Certificate *const c = new ZeroTier::Certificate(*cert);
|
||||
if (c->sign(issuer, issuerPrivateKey, issuerPrivateKeySize)) {
|
||||
return c;
|
||||
} else {
|
||||
delete c;
|
||||
}
|
||||
} catch (...) {}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
ZT_MAYBE_UNUSED enum ZT_CertificateError ZT_Certificate_decode(
|
||||
|
|
|
@ -39,7 +39,7 @@ Certificate &Certificate::operator=(const ZT_Certificate &cert)
|
|||
{
|
||||
m_clear();
|
||||
|
||||
Utils::copy< 48 >(this->serialNo, cert.serialNo);
|
||||
Utils::copy< sizeof(this->serialNo) >(this->serialNo, cert.serialNo);
|
||||
this->flags = cert.flags;
|
||||
this->timestamp = cert.timestamp;
|
||||
this->validity[0] = cert.validity[0];
|
||||
|
@ -47,7 +47,7 @@ Certificate &Certificate::operator=(const ZT_Certificate &cert)
|
|||
|
||||
this->subject.timestamp = cert.subject.timestamp;
|
||||
|
||||
if (cert.subject.identities) {
|
||||
if (cert.subject.identities != nullptr) {
|
||||
for (unsigned int i = 0; i < cert.subject.identityCount; ++i) {
|
||||
if (cert.subject.identities[i].identity) {
|
||||
if (cert.subject.identities[i].locator) {
|
||||
|
@ -59,60 +59,59 @@ Certificate &Certificate::operator=(const ZT_Certificate &cert)
|
|||
}
|
||||
}
|
||||
|
||||
if (cert.subject.networks) {
|
||||
if (cert.subject.networks != nullptr) {
|
||||
for (unsigned int i = 0; i < cert.subject.networkCount; ++i) {
|
||||
if (cert.subject.networks[i].id)
|
||||
if (cert.subject.networks[i].id) {
|
||||
addSubjectNetwork(cert.subject.networks[i].id, cert.subject.networks[i].controller);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (cert.subject.certificates) {
|
||||
if (cert.subject.certificates != nullptr) {
|
||||
for (unsigned int i = 0; i < cert.subject.certificateCount; ++i) {
|
||||
if (cert.subject.certificates[i])
|
||||
if (cert.subject.certificates[i]) {
|
||||
addSubjectCertificate(cert.subject.certificates[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (cert.subject.updateURLs) {
|
||||
if (cert.subject.updateURLs != nullptr) {
|
||||
for (unsigned int i = 0; i < cert.subject.updateURLCount; ++i) {
|
||||
if (cert.subject.updateURLs[i])
|
||||
if (cert.subject.updateURLs[i]) {
|
||||
addSubjectUpdateUrl(cert.subject.updateURLs[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
this->subject.identityCount = cert.subject.identityCount;
|
||||
this->subject.networkCount = cert.subject.networkCount;
|
||||
this->subject.certificateCount = cert.subject.certificateCount;
|
||||
this->subject.updateURLCount = cert.subject.updateURLCount;
|
||||
|
||||
Utils::copy< sizeof(ZT_Certificate_Name) >(&(this->subject.name), &(cert.subject.name));
|
||||
|
||||
if ((cert.subject.uniqueId) && (cert.subject.uniqueIdSize > 0)) {
|
||||
m_subjectUniqueId.assign(cert.subject.uniqueId, cert.subject.uniqueId + cert.subject.uniqueIdSize);
|
||||
this->subject.uniqueId = m_subjectUniqueId.data();
|
||||
this->subject.uniqueIdSize = (unsigned int)m_subjectUniqueId.size();
|
||||
}
|
||||
if ((cert.subject.uniqueIdProofSignature) && (cert.subject.uniqueIdProofSignatureSize > 0)) {
|
||||
m_subjectUniqueIdProofSignature.assign(cert.subject.uniqueIdProofSignature, cert.subject.uniqueIdProofSignature + cert.subject.uniqueIdProofSignatureSize);
|
||||
this->subject.uniqueIdProofSignature = m_subjectUniqueIdProofSignature.data();
|
||||
this->subject.uniqueIdProofSignatureSize = (unsigned int)m_subjectUniqueIdProofSignature.size();
|
||||
}
|
||||
Utils::copy< sizeof(this->subject.uniqueId) >(this->subject.uniqueId, cert.subject.uniqueId);
|
||||
Utils::copy< sizeof(this->subject.uniqueIdSignature) >(this->subject.uniqueIdSignature, cert.subject.uniqueIdSignature);
|
||||
this->subject.uniqueIdSize = cert.subject.uniqueIdSize;
|
||||
this->subject.uniqueIdSignatureSize = cert.subject.uniqueIdSignatureSize;
|
||||
|
||||
if (cert.issuer) {
|
||||
m_identities.push_front(*reinterpret_cast<const Identity *>(cert.issuer));
|
||||
this->issuer = &(m_identities.front());
|
||||
}
|
||||
Utils::copy< sizeof(this->issuer) >(this->issuer, cert.issuer);
|
||||
|
||||
Utils::copy< sizeof(ZT_Certificate_Name) >(&(this->issuerName), &(cert.issuerName));
|
||||
Utils::copy< sizeof(this->issuerPublicKey) >(this->issuerPublicKey, cert.issuerPublicKey);
|
||||
Utils::copy< sizeof(this->publicKey) >(this->publicKey, cert.publicKey);
|
||||
this->issuerPublicKeySize = cert.issuerPublicKeySize;
|
||||
this->publicKeySize = cert.publicKeySize;
|
||||
|
||||
if ((cert.extendedAttributes) && (cert.extendedAttributesSize > 0)) {
|
||||
if ((cert.extendedAttributes != nullptr) && (cert.extendedAttributesSize > 0)) {
|
||||
m_extendedAttributes.assign(cert.extendedAttributes, cert.extendedAttributes + cert.extendedAttributesSize);
|
||||
this->extendedAttributes = m_extendedAttributes.data();
|
||||
this->extendedAttributesSize = (unsigned int)m_extendedAttributes.size();
|
||||
}
|
||||
|
||||
this->maxPathLength = cert.maxPathLength;
|
||||
Utils::copy< sizeof(this->signature) >(this->signature, cert.signature);
|
||||
this->signatureSize = cert.signatureSize;
|
||||
|
||||
if ((cert.signature) && (cert.signatureSize > 0)) {
|
||||
m_signature.assign(cert.signature, cert.signature + cert.signatureSize);
|
||||
this->signature = m_signature.data();
|
||||
this->signatureSize = (unsigned int)m_signature.size();
|
||||
}
|
||||
this->maxPathLength = cert.maxPathLength;
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
@ -127,6 +126,7 @@ ZT_Certificate_Identity *Certificate::addSubjectIdentity(const Identity &id)
|
|||
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();
|
||||
|
||||
|
@ -174,9 +174,7 @@ void Certificate::addSubjectCertificate(const uint8_t serialNo[ZT_SHA384_DIGEST_
|
|||
|
||||
void Certificate::addSubjectUpdateUrl(const char *url)
|
||||
{
|
||||
if ((!url) || (!url[0]))
|
||||
return;
|
||||
|
||||
if ((url != nullptr) && (url[0] != 0)) {
|
||||
// Store local copy of URL.
|
||||
m_strings.push_front(url);
|
||||
|
||||
|
@ -186,37 +184,6 @@ void Certificate::addSubjectUpdateUrl(const char *url)
|
|||
this->subject.updateURLs = m_updateUrls.data();
|
||||
this->subject.updateURLCount = (unsigned int)m_updateUrls.size();
|
||||
}
|
||||
|
||||
/*
|
||||
void Certificate::setExtendedAttributes(const Dictionary &x)
|
||||
{
|
||||
m_extendedAttributes.clear();
|
||||
x.encode(m_extendedAttributes);
|
||||
this->extendedAttributes = m_extendedAttributes.data();
|
||||
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
|
||||
|
@ -242,44 +209,26 @@ Vector< uint8_t > Certificate::encode(const bool omitSignature) const
|
|||
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);
|
||||
|
||||
if (this->issuer)
|
||||
d.addO("i", *reinterpret_cast<const Identity *>(this->issuer));
|
||||
if (!Utils::allZero(this->issuer, sizeof(this->issuer)))
|
||||
d.add("i", this->issuer, sizeof(this->issuer));
|
||||
|
||||
if (this->issuerName.country[0])
|
||||
d.add("iN.c", this->issuerName.country);
|
||||
if (this->issuerName.organization[0])
|
||||
d.add("iN.o", this->issuerName.organization);
|
||||
if (this->issuerName.unit[0])
|
||||
d.add("iN.u", this->issuerName.unit);
|
||||
if (this->issuerName.locality[0])
|
||||
d.add("iN.l", this->issuerName.locality);
|
||||
if (this->issuerName.province[0])
|
||||
d.add("iN.p", this->issuerName.province);
|
||||
if (this->issuerName.streetAddress[0])
|
||||
d.add("iN.sA", this->issuerName.streetAddress);
|
||||
if (this->issuerName.postalCode[0])
|
||||
d.add("iN.pC", this->issuerName.postalCode);
|
||||
if (this->issuerName.commonName[0])
|
||||
d.add("iN.cN", this->issuerName.commonName);
|
||||
if (this->issuerName.serialNo[0])
|
||||
d.add("iN.sN", this->issuerName.serialNo);
|
||||
if (this->issuerName.email[0])
|
||||
d.add("iN.e", this->issuerName.email);
|
||||
if (this->issuerName.url[0])
|
||||
d.add("iN.ur", this->issuerName.url);
|
||||
if (this->issuerName.host[0])
|
||||
d.add("iN.h", this->issuerName.host);
|
||||
if (this->issuerPublicKeySize > 0)
|
||||
d.add("iPK", this->issuerPublicKey, this->issuerPublicKeySize);
|
||||
|
||||
if ((this->extendedAttributes) && (this->extendedAttributesSize > 0))
|
||||
if (this->publicKeySize > 0)
|
||||
d.add("pK", this->publicKey, this->publicKeySize);
|
||||
|
||||
if ((this->extendedAttributes != nullptr) && (this->extendedAttributesSize > 0))
|
||||
d["x"].assign(this->extendedAttributes, this->extendedAttributes + this->extendedAttributesSize);
|
||||
|
||||
if ((!omitSignature) && (this->signature) && (this->signatureSize > 0))
|
||||
d["S"].assign(this->signature, this->signature + this->signatureSize);
|
||||
if ((!omitSignature) && (this->signatureSize > 0))
|
||||
d["si"].assign(this->signature, this->signature + this->signatureSize);
|
||||
|
||||
if (this->maxPathLength > 0)
|
||||
d.add("l", (uint64_t)this->maxPathLength);
|
||||
|
||||
d.encode(enc);
|
||||
return enc;
|
||||
|
@ -299,7 +248,6 @@ bool Certificate::decode(const void *const data, const unsigned int len)
|
|||
this->timestamp = (int64_t)d.getUI("t");
|
||||
this->validity[0] = (int64_t)d.getUI("v#0");
|
||||
this->validity[1] = (int64_t)d.getUI("v#1");
|
||||
this->maxPathLength = (unsigned int)d.getUI("mP");
|
||||
|
||||
this->subject.timestamp = (int64_t)d.getUI("s.t");
|
||||
|
||||
|
@ -359,47 +307,32 @@ bool Certificate::decode(const void *const data, const unsigned int len)
|
|||
d.getS("s.n.ur", this->subject.name.url, sizeof(this->subject.name.url));
|
||||
d.getS("s.n.h", this->subject.name.host, sizeof(this->subject.name.host));
|
||||
|
||||
m_subjectUniqueId = d["s.uI"];
|
||||
if (!m_subjectUniqueId.empty()) {
|
||||
this->subject.uniqueId = m_subjectUniqueId.data();
|
||||
this->subject.uniqueIdSize = (unsigned int)m_subjectUniqueId.size();
|
||||
const Vector< uint8_t > &uniqueId = d["s.uI"];
|
||||
if ((!uniqueId.empty()) && (uniqueId.size() <= sizeof(this->subject.uniqueId))) {
|
||||
Utils::copy(this->subject.uniqueId, uniqueId.data(), uniqueId.size());
|
||||
this->subject.uniqueIdSize = (unsigned int)uniqueId.size();
|
||||
}
|
||||
m_subjectUniqueIdProofSignature = d["s.uS"];
|
||||
if (!m_subjectUniqueIdProofSignature.empty()) {
|
||||
this->subject.uniqueIdProofSignature = m_subjectUniqueIdProofSignature.data();
|
||||
this->subject.uniqueIdProofSignatureSize = (unsigned int)m_subjectUniqueIdProofSignature.size();
|
||||
const Vector< uint8_t > &uniqueIdSignature = d["s.uS"];
|
||||
if ((!uniqueIdSignature.empty()) && (uniqueIdSignature.size() <= sizeof(this->subject.uniqueIdSignature))) {
|
||||
Utils::copy(this->subject.uniqueIdSignature, uniqueIdSignature.data(), uniqueIdSignature.size());
|
||||
this->subject.uniqueIdSignatureSize = (unsigned int)uniqueIdSignature.size();
|
||||
}
|
||||
|
||||
const Vector< uint8_t > &issuerData = d["i"];
|
||||
if (!issuerData.empty()) {
|
||||
Identity id;
|
||||
if (id.unmarshal(issuerData.data(), (int)issuerData.size()) > 0) {
|
||||
m_identities.push_front(id);
|
||||
this->issuer = reinterpret_cast<const Identity *>(&(m_identities.front()));
|
||||
}
|
||||
if (issuerData.size() == sizeof(this->issuer)) {
|
||||
Utils::copy< sizeof(this->issuer) >(this->issuer, issuerData.data());
|
||||
}
|
||||
|
||||
d.getS("iN.sN", this->issuerName.serialNo, sizeof(this->issuerName.serialNo));
|
||||
d.getS("iN.cN", this->issuerName.commonName, sizeof(this->issuerName.commonName));
|
||||
d.getS("iN.c", this->issuerName.country, sizeof(this->issuerName.country));
|
||||
d.getS("iN.o", this->issuerName.organization, sizeof(this->issuerName.organization));
|
||||
d.getS("iN.u", this->issuerName.unit, sizeof(this->issuerName.unit));
|
||||
d.getS("iN.l", this->issuerName.locality, sizeof(this->issuerName.locality));
|
||||
d.getS("iN.p", this->issuerName.province, sizeof(this->issuerName.province));
|
||||
d.getS("iN.sA", this->issuerName.streetAddress, sizeof(this->issuerName.streetAddress));
|
||||
d.getS("iN.pC", this->issuerName.postalCode, sizeof(this->issuerName.postalCode));
|
||||
d.getS("iN.e", this->issuerName.email, sizeof(this->issuerName.email));
|
||||
d.getS("iN.ur", this->issuerName.url, sizeof(this->issuerName.url));
|
||||
d.getS("iN.h", this->issuerName.host, sizeof(this->issuerName.host));
|
||||
|
||||
cnt = (unsigned int)d.getUI("u$");
|
||||
for (unsigned int i = 0; i < cnt; ++i) {
|
||||
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;
|
||||
const Vector< uint8_t > &issuerPublicKey = d["iPK"];
|
||||
if ((!issuerPublicKey.empty()) && (issuerPublicKey.size() <= sizeof(this->issuerPublicKey))) {
|
||||
Utils::copy(this->issuerPublicKey, issuerPublicKey.data(), issuerPublicKey.size());
|
||||
this->issuerPublicKeySize = (unsigned int)issuerPublicKey.size();
|
||||
}
|
||||
|
||||
const Vector< uint8_t > &publicKey = d["pK"];
|
||||
if ((!publicKey.empty()) && (publicKey.size() <= sizeof(this->publicKey))) {
|
||||
Utils::copy(this->publicKey, publicKey.data(), publicKey.size());
|
||||
this->publicKeySize = (unsigned int)publicKey.size();
|
||||
}
|
||||
|
||||
m_extendedAttributes = d["x"];
|
||||
|
@ -408,40 +341,45 @@ bool Certificate::decode(const void *const data, const unsigned int len)
|
|||
this->extendedAttributesSize = (unsigned int)m_extendedAttributes.size();
|
||||
}
|
||||
|
||||
m_signature = d["S"];
|
||||
if (!m_signature.empty()) {
|
||||
this->signature = m_signature.data();
|
||||
this->signatureSize = (unsigned int)m_signature.size();
|
||||
const Vector< uint8_t > &signature = d["si"];
|
||||
if ((!signature.empty()) && (signature.size() <= sizeof(this->signature))) {
|
||||
Utils::copy(this->signature, signature.data(), signature.size());
|
||||
this->signatureSize = (unsigned int)signature.size();
|
||||
}
|
||||
|
||||
this->maxPathLength = (unsigned int)d.getUI("l");
|
||||
|
||||
const Vector< uint8_t > enc(encode(true));
|
||||
SHA384(this->serialNo, enc.data(), (unsigned int)enc.size());
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Certificate::sign(const Identity &issuer)
|
||||
bool Certificate::sign(const uint8_t issuer[ZT_CERTIFICATE_HASH_SIZE], const void *const issuerPrivateKey, const unsigned int issuerPrivateKeySize)
|
||||
{
|
||||
m_identities.push_front(issuer);
|
||||
m_identities.front().erasePrivateKey();
|
||||
this->issuer = reinterpret_cast<const ZT_Identity *>(&(m_identities.front()));
|
||||
if ((!issuerPrivateKey) || (issuerPrivateKeySize == 0))
|
||||
return false;
|
||||
|
||||
switch (reinterpret_cast<const uint8_t *>(issuerPrivateKey)[0]) {
|
||||
default:
|
||||
return false;
|
||||
case ZT_CERTIFICATE_PUBLIC_KEY_ALGORITHM_ECDSA_NIST_P_384:
|
||||
if (issuerPrivateKeySize == (1 + ZT_ECC384_PUBLIC_KEY_SIZE + ZT_ECC384_PRIVATE_KEY_SIZE)) {
|
||||
Utils::copy< sizeof(this->issuer) >(this->issuer, issuer);
|
||||
Utils::copy< 1 + ZT_ECC384_PUBLIC_KEY_SIZE >(this->issuerPublicKey, issuerPrivateKey); // private is prefixed with public
|
||||
this->issuerPublicKeySize = 1 + ZT_ECC384_PUBLIC_KEY_SIZE;
|
||||
|
||||
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, ZT_SIGNATURE_BUFFER_SIZE);
|
||||
ECC384ECDSASign(reinterpret_cast<const uint8_t *>(issuerPrivateKey) + 1 + ZT_ECC384_PUBLIC_KEY_SIZE, this->serialNo, this->signature);
|
||||
this->signatureSize = ZT_ECC384_SIGNATURE_SIZE;
|
||||
|
||||
if (sigSize > 0) {
|
||||
m_signature.assign(sig, sig + sigSize);
|
||||
this->signature = m_signature.data();
|
||||
this->signatureSize = sigSize;
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
m_signature.clear();
|
||||
this->signature = nullptr;
|
||||
this->signatureSize = 0;
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -455,106 +393,130 @@ ZT_CertificateError Certificate::verify(const int64_t clock, const bool checkSig
|
|||
return ZT_CERTIFICATE_ERROR_OUT_OF_VALID_TIME_WINDOW;
|
||||
}
|
||||
|
||||
if (this->issuer) {
|
||||
if (checkSignatures) {
|
||||
const Vector< uint8_t > enc(encode(true));
|
||||
if (!reinterpret_cast<const Identity *>(this->issuer)->verify(enc.data(), (unsigned int)enc.size(), this->signature, this->signatureSize))
|
||||
// Signature check fails if main signature is not present or invalid.
|
||||
// Note that the serial number / SHA384 hash is computed on decode(), so
|
||||
// this value is not something we blindly trust from input.
|
||||
if ((this->issuerPublicKeySize > 0) && (this->issuerPublicKeySize <= (unsigned int)sizeof(this->issuerPublicKey))) {
|
||||
switch (this->issuerPublicKey[0]) {
|
||||
case ZT_CERTIFICATE_PUBLIC_KEY_ALGORITHM_ECDSA_NIST_P_384:
|
||||
if ((this->issuerPublicKeySize == (ZT_ECC384_PUBLIC_KEY_SIZE + 1)) && (this->signatureSize == ZT_ECC384_SIGNATURE_SIZE)) {
|
||||
if (!ECC384ECDSAVerify(this->issuerPublicKey + 1, this->serialNo, this->signature)) {
|
||||
return ZT_CERTIFICATE_ERROR_INVALID_PRIMARY_SIGNATURE;
|
||||
}
|
||||
} else {
|
||||
return ZT_CERTIFICATE_ERROR_INVALID_PRIMARY_SIGNATURE;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
return ZT_CERTIFICATE_ERROR_INVALID_PRIMARY_SIGNATURE;
|
||||
}
|
||||
} else {
|
||||
return ZT_CERTIFICATE_ERROR_INVALID_PRIMARY_SIGNATURE;
|
||||
}
|
||||
|
||||
if (this->subject.uniqueIdProofSignatureSize > 0) {
|
||||
if (
|
||||
(this->subject.uniqueIdProofSignatureSize != ZT_ECC384_SIGNATURE_SIZE) ||
|
||||
(this->subject.uniqueIdSize != ZT_CERTIFICATE_UNIQUE_ID_TYPE_NIST_P_384_SIZE) ||
|
||||
(this->subject.uniqueId[0] != ZT_CERTIFICATE_UNIQUE_ID_TYPE_NIST_P_384))
|
||||
return ZT_CERTIFICATE_ERROR_INVALID_UNIQUE_ID_PROOF;
|
||||
|
||||
if (checkSignatures) {
|
||||
// Subject unique ID signatures are optional, so this only fails if it
|
||||
// is present and invalid. A unique ID with type ALGORITHM_NONE is also
|
||||
// allowed, but this means its signature is not checked.
|
||||
if (this->subject.uniqueIdSize > 0) {
|
||||
if (this->subject.uniqueIdSize <= (unsigned int)sizeof(this->subject.uniqueId)) {
|
||||
switch (this->subject.uniqueId[0]) {
|
||||
case ZT_CERTIFICATE_PUBLIC_KEY_ALGORITHM_NONE:
|
||||
break;
|
||||
case ZT_CERTIFICATE_PUBLIC_KEY_ALGORITHM_ECDSA_NIST_P_384:
|
||||
if ((this->subject.uniqueIdSize == (ZT_ECC384_PUBLIC_KEY_SIZE + 1)) && (this->subject.uniqueIdSignatureSize == ZT_ECC384_SIGNATURE_SIZE)) {
|
||||
Dictionary d;
|
||||
m_encodeSubject(this->subject, d, true);
|
||||
|
||||
Vector< uint8_t > enc;
|
||||
enc.reserve(1024);
|
||||
d.encode(enc);
|
||||
|
||||
static_assert(ZT_ECC384_SIGNATURE_HASH_SIZE == ZT_SHA384_DIGEST_SIZE, "ECC384 should take 384-bit hash");
|
||||
uint8_t h[ZT_SHA384_DIGEST_SIZE];
|
||||
SHA384(h, enc.data(), (unsigned int)enc.size());
|
||||
static_assert(ZT_CERTIFICATE_UNIQUE_ID_TYPE_NIST_P_384_SIZE == (ZT_ECC384_PUBLIC_KEY_SIZE + 1), "incorrect size");
|
||||
if (!ECC384ECDSAVerify(this->subject.uniqueId + 1, h, this->subject.uniqueIdProofSignature))
|
||||
|
||||
if (!ECC384ECDSAVerify(this->subject.uniqueId + 1, h, this->subject.uniqueIdSignature)) {
|
||||
return ZT_CERTIFICATE_ERROR_INVALID_UNIQUE_ID_PROOF;
|
||||
}
|
||||
} else if (this->subject.uniqueIdSize > 0) {
|
||||
} else {
|
||||
return ZT_CERTIFICATE_ERROR_INVALID_UNIQUE_ID_PROOF;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
return ZT_CERTIFICATE_ERROR_INVALID_UNIQUE_ID_PROOF;
|
||||
}
|
||||
} else {
|
||||
return ZT_CERTIFICATE_ERROR_INVALID_UNIQUE_ID_PROOF;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (unsigned int i = 0; i < this->subject.identityCount; ++i) {
|
||||
if (!this->subject.identities[i].identity)
|
||||
return ZT_CERTIFICATE_ERROR_MISSING_REQUIRED_FIELDS;
|
||||
if (checkSignatures) {
|
||||
if (!reinterpret_cast<const Identity *>(this->subject.identities[i].identity)->locallyValidate())
|
||||
if (!reinterpret_cast<const Identity *>(this->subject.identities[i].identity)->locallyValidate()) {
|
||||
return ZT_CERTIFICATE_ERROR_INVALID_IDENTITY;
|
||||
if (this->subject.identities[i].locator) {
|
||||
if (!reinterpret_cast<const Locator *>(this->subject.identities[i].locator)->verify(*reinterpret_cast<const Identity *>(this->subject.identities[i].identity)))
|
||||
}
|
||||
if ((this->subject.identities[i].locator) && (!reinterpret_cast<const Locator *>(this->subject.identities[i].locator)->verify(*reinterpret_cast<const Identity *>(this->subject.identities[i].identity)))) {
|
||||
return ZT_CERTIFICATE_ERROR_INVALID_COMPONENT_SIGNATURE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (unsigned int i = 0; i < this->subject.networkCount; ++i) {
|
||||
if (!this->subject.networks[i].id)
|
||||
if (!this->subject.networks[i].id) {
|
||||
return ZT_CERTIFICATE_ERROR_MISSING_REQUIRED_FIELDS;
|
||||
}
|
||||
}
|
||||
|
||||
if (this->subject.updateURLCount > 0) {
|
||||
if (!this->subject.updateURLs)
|
||||
if (!this->subject.updateURLs) {
|
||||
return ZT_CERTIFICATE_ERROR_MISSING_REQUIRED_FIELDS;
|
||||
}
|
||||
for (unsigned int i = 0; i < this->subject.updateURLCount; ++i) {
|
||||
if (!this->subject.updateURLs[i])
|
||||
return ZT_CERTIFICATE_ERROR_MISSING_REQUIRED_FIELDS;
|
||||
}
|
||||
}
|
||||
} catch (...) {}
|
||||
} catch (...) {
|
||||
return ZT_CERTIFICATE_ERROR_INVALID_FORMAT;
|
||||
}
|
||||
|
||||
return ZT_CERTIFICATE_ERROR_NONE;
|
||||
}
|
||||
|
||||
Vector< uint8_t > Certificate::createCSR(const ZT_Certificate_Subject &s, const void *uniqueId, unsigned int uniqueIdSize, const void *uniqueIdPrivate, unsigned int uniqueIdPrivateSize)
|
||||
bool Certificate::newKeyPair(const ZT_CertificatePublicKeyAlgorithm type, uint8_t publicKey[ZT_CERTIFICATE_MAX_PUBLIC_KEY_SIZE], int *const publicKeySize, uint8_t privateKey[ZT_CERTIFICATE_MAX_PRIVATE_KEY_SIZE], int *const privateKeySize)
|
||||
{
|
||||
switch (type) {
|
||||
case ZT_CERTIFICATE_PUBLIC_KEY_ALGORITHM_ECDSA_NIST_P_384:
|
||||
publicKey[0] = (uint8_t)ZT_CERTIFICATE_PUBLIC_KEY_ALGORITHM_ECDSA_NIST_P_384;
|
||||
ZeroTier::ECC384GenerateKey(publicKey + 1, privateKey + ZT_ECC384_PUBLIC_KEY_SIZE + 1);
|
||||
ZeroTier::Utils::copy< ZT_ECC384_PUBLIC_KEY_SIZE + 1 >(privateKey, publicKey);
|
||||
*publicKeySize = ZT_ECC384_PUBLIC_KEY_SIZE + 1;
|
||||
*privateKeySize = ZT_ECC384_PUBLIC_KEY_SIZE + 1 + ZT_ECC384_PRIVATE_KEY_SIZE;
|
||||
return true;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
Vector< uint8_t > Certificate::createCSR(const ZT_Certificate_Subject &s, const void *const certificatePublicKey, const unsigned int certificatePublicKeySize, const void *uniqueIdPrivate, unsigned int uniqueIdPrivateSize)
|
||||
{
|
||||
Vector< uint8_t > enc;
|
||||
|
||||
ZT_Certificate_Subject sc;
|
||||
Utils::copy< sizeof(ZT_Certificate_Subject) >(&sc, &s);
|
||||
|
||||
if ((uniqueId) && (uniqueIdSize > 0) && (uniqueIdPrivate) && (uniqueIdPrivateSize > 0)) {
|
||||
sc.uniqueId = reinterpret_cast<const uint8_t *>(uniqueId);
|
||||
sc.uniqueIdSize = uniqueIdSize;
|
||||
} else {
|
||||
sc.uniqueId = nullptr;
|
||||
sc.uniqueIdSize = 0;
|
||||
}
|
||||
|
||||
if (m_setSubjectUniqueId(sc, uniqueIdPrivate, uniqueIdPrivateSize)) {
|
||||
Dictionary d;
|
||||
m_encodeSubject(sc, d, true);
|
||||
Vector< uint8_t > enc;
|
||||
d.encode(enc);
|
||||
|
||||
if (sc.uniqueId) {
|
||||
uint8_t h[ZT_SHA384_DIGEST_SIZE];
|
||||
SHA384(h, enc.data(), (unsigned int)enc.size());
|
||||
enc.clear();
|
||||
if ((reinterpret_cast<const uint8_t *>(uniqueId)[0] == ZT_CERTIFICATE_UNIQUE_ID_TYPE_NIST_P_384) &&
|
||||
(uniqueIdSize == ZT_CERTIFICATE_UNIQUE_ID_TYPE_NIST_P_384_SIZE) &&
|
||||
(uniqueIdPrivateSize == ZT_CERTIFICATE_UNIQUE_ID_TYPE_NIST_P_384_PRIVATE_SIZE)) {
|
||||
uint8_t sig[ZT_ECC384_SIGNATURE_SIZE];
|
||||
ECC384ECDSASign(reinterpret_cast<const uint8_t *>(uniqueIdPrivate), h, sig);
|
||||
|
||||
sc.uniqueIdProofSignature = sig;
|
||||
sc.uniqueIdProofSignatureSize = ZT_ECC384_SIGNATURE_SIZE;
|
||||
|
||||
d.clear();
|
||||
m_encodeSubject(sc, d, false);
|
||||
if (certificatePublicKeySize > 0)
|
||||
d.add("pK", certificatePublicKey, certificatePublicKeySize);
|
||||
d.encode(enc);
|
||||
}
|
||||
}
|
||||
|
||||
return enc;
|
||||
}
|
||||
|
@ -574,9 +536,35 @@ void Certificate::m_clear()
|
|||
m_updateUrls.clear();
|
||||
m_subjectCertificates.clear();
|
||||
m_extendedAttributes.clear();
|
||||
m_subjectUniqueId.clear();
|
||||
m_subjectUniqueIdProofSignature.clear();
|
||||
m_signature.clear();
|
||||
}
|
||||
|
||||
bool Certificate::m_setSubjectUniqueId(ZT_Certificate_Subject &s, const void *uniqueIdPrivate, unsigned int uniqueIdPrivateSize)
|
||||
{
|
||||
if (uniqueIdPrivateSize > 0) {
|
||||
if ((uniqueIdPrivate != nullptr) && (uniqueIdPrivateSize == (1 + ZT_ECC384_PUBLIC_KEY_SIZE + ZT_ECC384_PRIVATE_KEY_SIZE)) && (reinterpret_cast<const uint8_t *>(uniqueIdPrivate)[0] == (uint8_t)ZT_CERTIFICATE_PUBLIC_KEY_ALGORITHM_ECDSA_NIST_P_384)) {
|
||||
Utils::copy< 1 + ZT_ECC384_PUBLIC_KEY_SIZE >(s.uniqueId, uniqueIdPrivate);
|
||||
s.uniqueIdSize = 1 + ZT_ECC384_PUBLIC_KEY_SIZE; // private is prefixed with public
|
||||
|
||||
Vector< uint8_t > enc;
|
||||
Dictionary d;
|
||||
m_encodeSubject(s, d, true);
|
||||
d.encode(enc);
|
||||
|
||||
uint8_t h[ZT_SHA384_DIGEST_SIZE];
|
||||
SHA384(h, enc.data(), (unsigned int)enc.size());
|
||||
|
||||
ECC384ECDSASign(reinterpret_cast<const uint8_t *>(uniqueIdPrivate) + 1 + ZT_ECC384_PUBLIC_KEY_SIZE, h, s.uniqueIdSignature);
|
||||
s.uniqueIdSignatureSize = ZT_ECC384_SIGNATURE_SIZE;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
Utils::zero< sizeof(s.uniqueId) >(s.uniqueId);
|
||||
s.uniqueIdSize = 0;
|
||||
Utils::zero< sizeof(s.uniqueIdSignature) >(s.uniqueIdSignature);
|
||||
s.uniqueIdSignatureSize = 0;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void Certificate::m_encodeSubject(const ZT_Certificate_Subject &s, Dictionary &d, bool omitUniqueIdProofSignature)
|
||||
|
@ -643,10 +631,10 @@ 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.uniqueId) && (s.uniqueIdSize > 0))
|
||||
if (s.uniqueIdSize > 0)
|
||||
d["s.uI"].assign(s.uniqueId, s.uniqueId + s.uniqueIdSize);
|
||||
if ((!omitUniqueIdProofSignature) && (s.uniqueIdProofSignature) && (s.uniqueIdProofSignatureSize > 0))
|
||||
d["s.uS"].assign(s.uniqueIdProofSignature, s.uniqueIdProofSignature + s.uniqueIdProofSignatureSize);
|
||||
if ((!omitUniqueIdProofSignature) && (s.uniqueIdSignatureSize > 0))
|
||||
d["s.uS"].assign(s.uniqueIdSignature, s.uniqueIdSignature + s.uniqueIdSignatureSize);
|
||||
}
|
||||
|
||||
} // namespace ZeroTier
|
||||
|
|
|
@ -106,22 +106,17 @@ public:
|
|||
void addSubjectUpdateUrl(const char *url);
|
||||
|
||||
/**
|
||||
* Set the extended attributes of this certificate
|
||||
* Sign subject with unique ID private key and set.
|
||||
*
|
||||
* @param x Extended attributes (set by issuer)
|
||||
* This is done when you createCSR but can also be done explicitly here. This
|
||||
* is mostly for testing purposes.
|
||||
*
|
||||
* @param uniqueIdPrivate Unique ID private key (includes public)
|
||||
* @param uniqueIdPrivateSize Size of private key
|
||||
* @return True on success
|
||||
*/
|
||||
//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]);
|
||||
ZT_INLINE bool setSubjectUniqueId(const void *uniqueIdPrivate, unsigned int uniqueIdPrivateSize)
|
||||
{ return m_setSubjectUniqueId(this->subject, uniqueIdPrivate, uniqueIdPrivateSize); }
|
||||
|
||||
/**
|
||||
* Marshal this certificate in binary form
|
||||
|
@ -144,12 +139,13 @@ public:
|
|||
bool decode(const void *data, unsigned int len);
|
||||
|
||||
/**
|
||||
* Sign this certificate (and also fill in serialNo).
|
||||
* Sign this certificate.
|
||||
*
|
||||
* This sets serialNo, issuer, issuerPublicKey, and signature.
|
||||
*
|
||||
* @param issuer Issuer identity (must have secret key)
|
||||
* @return True on success
|
||||
*/
|
||||
bool sign(const Identity &issuer);
|
||||
bool sign(const uint8_t issuer[ZT_CERTIFICATE_HASH_SIZE], const void *issuerPrivateKey, unsigned int issuerPrivateKeySize);
|
||||
|
||||
/**
|
||||
* Verify self-contained signatures and validity of certificate structure
|
||||
|
@ -163,29 +159,29 @@ public:
|
|||
*/
|
||||
ZT_CertificateError verify(int64_t clock, bool checkSignatures) const;
|
||||
|
||||
/**
|
||||
* Create a new certificate public/private key pair
|
||||
*
|
||||
* @param type Key pair type to create
|
||||
* @param publicKey Buffer to fill with public key
|
||||
* @param publicKeySize Result parameter: set to size of public key
|
||||
* @param privateKey Buffer to fill with private key
|
||||
* @param privateKeySize Result parameter: set to size of private key
|
||||
* @return True on success
|
||||
*/
|
||||
static bool newKeyPair(const ZT_CertificatePublicKeyAlgorithm type, uint8_t publicKey[ZT_CERTIFICATE_MAX_PUBLIC_KEY_SIZE], int *const publicKeySize, uint8_t privateKey[ZT_CERTIFICATE_MAX_PRIVATE_KEY_SIZE], int *const privateKeySize);
|
||||
|
||||
/**
|
||||
* Create a CSR that encodes the subject of this certificate
|
||||
*
|
||||
* @param s Subject to encode
|
||||
* @param uniqueId Unique ID to sign subject with or NULL if none
|
||||
* @param uniqueIdSize Size of unique ID or 0 if none
|
||||
* @param certificatePublicKey Public key for certificate
|
||||
* @param certificatePublicKeySize Size of public key
|
||||
* @param uniqueIdPrivate Unique ID private key for proof signature or NULL if none
|
||||
* @param uniqueIdPrivateSize Size of unique ID private key
|
||||
* @return Encoded subject (without any unique ID fields) or empty vector on error
|
||||
*/
|
||||
static Vector< uint8_t > createCSR(const ZT_Certificate_Subject &s, const void *uniqueId, unsigned int uniqueIdSize, const void *uniqueIdPrivate, unsigned int uniqueIdPrivateSize);
|
||||
|
||||
/**
|
||||
* Create a subject unique ID and corresponding private key required for use
|
||||
*
|
||||
* @param uniqueId Buffer to receive unique ID
|
||||
* @param uniqueIdPrivate Buffer to receive private key
|
||||
*/
|
||||
static ZT_INLINE void createSubjectUniqueId(uint8_t uniqueId[ZT_CERTIFICATE_UNIQUE_ID_TYPE_NIST_P_384_SIZE], uint8_t uniqueIdPrivate[ZT_CERTIFICATE_UNIQUE_ID_TYPE_NIST_P_384_PRIVATE_SIZE])
|
||||
{
|
||||
uniqueId[0] = ZT_CERTIFICATE_UNIQUE_ID_TYPE_NIST_P_384;
|
||||
ECC384GenerateKey(uniqueId + 1, uniqueIdPrivate);
|
||||
}
|
||||
static Vector< uint8_t > createCSR(const ZT_Certificate_Subject &s, const void *certificatePublicKey, unsigned int certificatePublicKeySize, const void *uniqueIdPrivate, unsigned int uniqueIdPrivateSize);
|
||||
|
||||
ZT_INLINE unsigned long hashCode() const noexcept
|
||||
{ return (unsigned long)Utils::loadMachineEndian< uint32_t >(this->serialNo); }
|
||||
|
@ -210,7 +206,7 @@ public:
|
|||
|
||||
private:
|
||||
void m_clear();
|
||||
|
||||
static bool m_setSubjectUniqueId(ZT_Certificate_Subject &s, const void *uniqueIdPrivate, unsigned int uniqueIdPrivateSize);
|
||||
static void m_encodeSubject(const ZT_Certificate_Subject &s, Dictionary &d, bool omitUniqueIdProofSignature);
|
||||
|
||||
// These hold any identity or locator objects that are owned by and should
|
||||
|
@ -227,9 +223,6 @@ private:
|
|||
Vector< const uint8_t * > m_subjectCertificates;
|
||||
Vector< const char * > m_updateUrls;
|
||||
Vector< uint8_t > m_extendedAttributes;
|
||||
Vector< uint8_t > m_subjectUniqueId;
|
||||
Vector< uint8_t > m_subjectUniqueIdProofSignature;
|
||||
Vector< uint8_t > m_signature;
|
||||
};
|
||||
|
||||
} // namespace ZeroTier
|
||||
|
|
|
@ -198,7 +198,7 @@ struct Blob
|
|||
|
||||
explicit ZT_INLINE Blob(const void *const d, const unsigned int l) noexcept
|
||||
{
|
||||
Utils::copy(data, d, l);
|
||||
Utils::copy(data, d, (l > (unsigned int)S) ? (unsigned int)S : l);
|
||||
if (l < S) {
|
||||
Utils::zero(data + l, S - l);
|
||||
}
|
||||
|
|
|
@ -16,8 +16,9 @@
|
|||
namespace ZeroTier {
|
||||
namespace Defaults {
|
||||
|
||||
const unsigned int CERTIFICATES_BYTES = 0;
|
||||
const uint8_t CERTIFICATES[4] = {0,0,0,0};
|
||||
const uint8_t *CERTIFICATE[DEFAULT_CERTIFICATE_COUNT] = {};
|
||||
|
||||
unsigned int CERTIFICATE_SIZE[DEFAULT_CERTIFICATE_COUNT] = {};
|
||||
|
||||
} // namespace Defaults
|
||||
} // namespace ZeroTier
|
||||
|
|
|
@ -19,8 +19,10 @@
|
|||
namespace ZeroTier {
|
||||
namespace Defaults {
|
||||
|
||||
extern const unsigned int CERTIFICATES_BYTES;
|
||||
extern const uint8_t CERTIFICATES[];
|
||||
#define DEFAULT_CERTIFICATE_COUNT 0
|
||||
|
||||
extern const uint8_t *CERTIFICATE[DEFAULT_CERTIFICATE_COUNT];
|
||||
extern unsigned int CERTIFICATE_SIZE[DEFAULT_CERTIFICATE_COUNT];
|
||||
|
||||
} // namespace Defaults
|
||||
} // namespace ZeroTier
|
||||
|
|
|
@ -54,7 +54,8 @@ public:
|
|||
ZT_INLINE void set(T *ptr) noexcept
|
||||
{
|
||||
m_release();
|
||||
const_cast<std::atomic< int > *>(&((m_ptr = ptr)->__refCount))->fetch_add(1, std::memory_order_acquire);
|
||||
m_ptr = ptr;
|
||||
const_cast<std::atomic< int > *>(&(ptr->__refCount))->fetch_add(1, std::memory_order_acquire);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -169,9 +170,11 @@ private:
|
|||
|
||||
ZT_INLINE void m_release() const noexcept
|
||||
{
|
||||
if (unlikely((m_ptr != nullptr)&&(const_cast<std::atomic< int > *>(&(m_ptr->__refCount))->fetch_sub(1, std::memory_order_release) <= 1)))
|
||||
if (likely(m_ptr != nullptr)) {
|
||||
if (unlikely(const_cast<std::atomic< int > *>(&(m_ptr->__refCount))->fetch_sub(1, std::memory_order_release) <= 1))
|
||||
delete m_ptr;
|
||||
}
|
||||
}
|
||||
|
||||
T *m_ptr;
|
||||
};
|
||||
|
|
|
@ -309,32 +309,25 @@ static bool ZTT_deepCompareCertificates(const Certificate &a, const Certificate
|
|||
(a.subject.networkCount != b.subject.networkCount) ||
|
||||
(a.subject.updateURLCount != b.subject.updateURLCount) ||
|
||||
(a.subject.uniqueIdSize != b.subject.uniqueIdSize) ||
|
||||
(a.subject.uniqueIdProofSignatureSize != b.subject.uniqueIdProofSignatureSize) ||
|
||||
(a.subject.uniqueIdSignatureSize != b.subject.uniqueIdSignatureSize) ||
|
||||
(a.maxPathLength != b.maxPathLength) ||
|
||||
(a.signatureSize != b.signatureSize)
|
||||
)
|
||||
return false;
|
||||
|
||||
if ((a.subject.uniqueId == nullptr) != (b.subject.uniqueId == nullptr))
|
||||
return false;
|
||||
if ((a.subject.uniqueIdProofSignature == nullptr) != (b.subject.uniqueIdProofSignature == nullptr))
|
||||
|
||||
if ((memcmp(a.subject.uniqueId, b.subject.uniqueId, a.subject.uniqueIdSize) != 0) || (memcmp(a.subject.uniqueIdSignature, b.subject.uniqueIdSignature, a.subject.uniqueIdSignatureSize) != 0) || (memcmp(a.signature, b.signature, a.signatureSize) != 0))
|
||||
return false;
|
||||
|
||||
if ((a.subject.uniqueId != nullptr) && (a.subject.uniqueIdProofSignature != nullptr)) {
|
||||
if (
|
||||
(memcmp(a.subject.uniqueId, b.subject.uniqueId, a.subject.uniqueIdSize) != 0) ||
|
||||
(memcmp(a.subject.uniqueIdProofSignature, b.subject.uniqueIdProofSignature, a.subject.uniqueIdProofSignatureSize) != 0) ||
|
||||
(memcmp(a.signature, b.signature, a.signatureSize) != 0)
|
||||
)
|
||||
return false;
|
||||
}
|
||||
|
||||
if ((!ZTT_deepCompareCertificateName(a.subject.name, b.subject.name)) || (!ZTT_deepCompareCertificateName(a.issuerName, b.issuerName)))
|
||||
if (!ZTT_deepCompareCertificateName(a.subject.name, b.subject.name))
|
||||
return false;
|
||||
|
||||
if ((a.issuer == nullptr) != (b.issuer == nullptr))
|
||||
if (memcmp(a.issuer, b.issuer, ZT_CERTIFICATE_HASH_SIZE) != 0)
|
||||
return false;
|
||||
if ((a.issuer != nullptr) && ((*reinterpret_cast<const Identity *>(a.issuer)) != (*reinterpret_cast<const Identity *>(b.issuer))))
|
||||
if ((a.issuerPublicKeySize != b.issuerPublicKeySize) || (memcmp(a.issuerPublicKey, b.issuerPublicKey, a.issuerPublicKeySize) != 0))
|
||||
return false;
|
||||
|
||||
if ((a.publicKeySize != b.publicKeySize) || (memcmp(a.publicKey, b.publicKey, a.publicKeySize)))
|
||||
return false;
|
||||
|
||||
for (unsigned int i = 0; i < a.subject.identityCount; ++i) {
|
||||
|
@ -655,7 +648,7 @@ extern "C" const char *ZTT_general()
|
|||
}
|
||||
bufs.clear();
|
||||
if (Buf::poolAllocated() != ZT_BUF_MAX_POOL_SIZE) {
|
||||
ZT_T_PRINTF("FAILED (2)" ZT_EOL_S);
|
||||
ZT_T_PRINTF("FAILED (2) (%ld)" ZT_EOL_S, Buf::poolAllocated());
|
||||
return "Buf memory pool test failed";
|
||||
}
|
||||
Buf::freePool();
|
||||
|
@ -1195,19 +1188,24 @@ extern "C" const char *ZTT_crypto()
|
|||
|
||||
{
|
||||
char tmp[256];
|
||||
uint8_t fakeIssuer[48];
|
||||
Utils::getSecureRandom(fakeIssuer, sizeof(fakeIssuer));
|
||||
|
||||
ZT_T_PRINTF("[crypto] Testing Certificate..." ZT_EOL_S);
|
||||
|
||||
ZT_T_PRINTF(" Create test subject and issuer identities... ");
|
||||
Identity testSubjectId, testIssuerId;
|
||||
ZT_T_PRINTF(" Create test identities... ");
|
||||
Identity testSubjectId;
|
||||
testSubjectId.generate(Identity::C25519);
|
||||
testIssuerId.generate(Identity::P384);
|
||||
ZT_T_PRINTF("OK" ZT_EOL_S);
|
||||
|
||||
ZT_T_PRINTF(" Create subject unique ID... ");
|
||||
uint8_t uniqueId[ZT_CERTIFICATE_UNIQUE_ID_TYPE_NIST_P_384_SIZE], uniqueIdPrivate[ZT_CERTIFICATE_UNIQUE_ID_TYPE_NIST_P_384_PRIVATE_SIZE];
|
||||
Certificate::createSubjectUniqueId(uniqueId, uniqueIdPrivate);
|
||||
Utils::b32e(uniqueId, ZT_CERTIFICATE_UNIQUE_ID_TYPE_NIST_P_384_SIZE, tmp, sizeof(tmp));
|
||||
ZT_T_PRINTF(" Create subject unique ID key pair... ");
|
||||
uint8_t uniqueId[ZT_CERTIFICATE_MAX_PUBLIC_KEY_SIZE], uniqueIdPrivate[ZT_CERTIFICATE_MAX_PRIVATE_KEY_SIZE];
|
||||
int uniqueIdSize = 0, uniqueIdPrivateKeySize = 0;
|
||||
if (!Certificate::newKeyPair(ZT_CERTIFICATE_PUBLIC_KEY_ALGORITHM_ECDSA_NIST_P_384, uniqueId, &uniqueIdSize, uniqueIdPrivate, &uniqueIdPrivateKeySize)) {
|
||||
ZT_T_PRINTF("FAILED" ZT_EOL_S);
|
||||
return "Certificate key pair create";
|
||||
}
|
||||
Utils::b32e(uniqueId, uniqueIdSize, tmp, sizeof(tmp));
|
||||
ZT_T_PRINTF("OK %s" ZT_EOL_S, tmp);
|
||||
|
||||
ZT_T_PRINTF(" Create and sign certificate... ");
|
||||
|
@ -1231,9 +1229,15 @@ extern "C" const char *ZTT_crypto()
|
|||
cert->timestamp = cert->subject.timestamp;
|
||||
cert->validity[0] = 0;
|
||||
cert->validity[1] = 9223372036854775807LL;
|
||||
Utils::copy< sizeof(ZT_Certificate_Name) >(&cert->issuerName, &cert->subject.name);
|
||||
cert->setSubjectUniqueId(uniqueId, uniqueIdPrivate);
|
||||
cert->sign(testIssuerId);
|
||||
uint8_t issuerPrivateKey[ZT_CERTIFICATE_MAX_PRIVATE_KEY_SIZE], certPrivateKey[ZT_CERTIFICATE_MAX_PRIVATE_KEY_SIZE];
|
||||
int issuerPrivateKeySize = 0, certPrivateKeySize = 0;
|
||||
Certificate::newKeyPair(ZT_CERTIFICATE_PUBLIC_KEY_ALGORITHM_ECDSA_NIST_P_384, cert->issuerPublicKey, (int *)&cert->issuerPublicKeySize, issuerPrivateKey, &issuerPrivateKeySize);
|
||||
Certificate::newKeyPair(ZT_CERTIFICATE_PUBLIC_KEY_ALGORITHM_ECDSA_NIST_P_384, cert->publicKey, (int *)&cert->publicKeySize, certPrivateKey, &certPrivateKeySize);
|
||||
cert->setSubjectUniqueId(uniqueIdPrivate, uniqueIdPrivateKeySize);
|
||||
if (!cert->sign(fakeIssuer, issuerPrivateKey, issuerPrivateKeySize)) {
|
||||
ZT_T_PRINTF("FAILED" ZT_EOL_S);
|
||||
return "Certificate sign";
|
||||
}
|
||||
Vector< uint8_t > enc(cert->encode());
|
||||
ZT_T_PRINTF("OK (%d bytes)" ZT_EOL_S, (int)enc.size());
|
||||
|
||||
|
|
|
@ -25,8 +25,8 @@ TrustStore::~TrustStore()
|
|||
SharedPtr< TrustStore::Entry > TrustStore::get(const H384 &serial) const
|
||||
{
|
||||
RWMutex::RLock l(m_lock);
|
||||
Map< H384, SharedPtr< Entry > >::const_iterator i(m_bySerial.find(serial));
|
||||
return (i != m_bySerial.end()) ? i->second : SharedPtr< TrustStore::Entry >();
|
||||
Map< H384, SharedPtr< Entry > >::const_iterator c(m_bySerial.find(serial));
|
||||
return (c != m_bySerial.end()) ? c->second : SharedPtr< TrustStore::Entry >();
|
||||
}
|
||||
|
||||
Map< Identity, SharedPtr< const Locator > > TrustStore::roots()
|
||||
|
@ -56,9 +56,9 @@ Vector< SharedPtr< TrustStore::Entry > > TrustStore::all(const bool includeRejec
|
|||
RWMutex::RLock l(m_lock);
|
||||
Vector< SharedPtr< Entry > > r;
|
||||
r.reserve(m_bySerial.size());
|
||||
for (Map< H384, SharedPtr< Entry > >::const_iterator i(m_bySerial.begin()); i != m_bySerial.end(); ++i) {
|
||||
if ((includeRejectedCertificates) || (i->second->error() == ZT_CERTIFICATE_ERROR_NONE))
|
||||
r.push_back(i->second);
|
||||
for (Map< H384, SharedPtr< Entry > >::const_iterator c(m_bySerial.begin()); c != m_bySerial.end(); ++c) {
|
||||
if ((includeRejectedCertificates) || (c->second->error() == ZT_CERTIFICATE_ERROR_NONE))
|
||||
r.push_back(c->second);
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
@ -75,25 +75,6 @@ void TrustStore::erase(const H384 &serial)
|
|||
m_deleteQueue.push_front(serial);
|
||||
}
|
||||
|
||||
// Recursive function to trace a certificate up the chain to a CA, returning true
|
||||
// if the CA is reached and the path length is less than the maximum. Note that only
|
||||
// non-rejected (no errors) certificates will be in bySignedCert.
|
||||
static bool p_validatePath(const Map< H384, Vector< SharedPtr< TrustStore::Entry > > > &bySignedCert, const SharedPtr< TrustStore::Entry > &entry, unsigned int pathLength)
|
||||
{
|
||||
if (((entry->localTrust() & ZT_CERTIFICATE_LOCAL_TRUST_FLAG_ROOT_CA) != 0) && (pathLength <= entry->certificate().maxPathLength))
|
||||
return true;
|
||||
if (pathLength < ZT_CERTIFICATE_MAX_PATH_LENGTH) {
|
||||
const Map< H384, Vector< SharedPtr< TrustStore::Entry > > >::const_iterator signers(bySignedCert.find(H384(entry->certificate().serialNo)));
|
||||
if (signers != bySignedCert.end()) {
|
||||
for (Vector< SharedPtr< TrustStore::Entry > >::const_iterator signer(signers->second.begin()); signer != signers->second.end(); ++signer) {
|
||||
if ((*signer != entry) && (p_validatePath(bySignedCert, *signer, pathLength + 1)))
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool TrustStore::update(const int64_t clock, Vector< SharedPtr< Entry > > *const purge)
|
||||
{
|
||||
RWMutex::Lock l(m_lock);
|
||||
|
@ -135,22 +116,32 @@ bool TrustStore::update(const int64_t clock, Vector< SharedPtr< Entry > > *const
|
|||
|
||||
Map< H384, Vector< SharedPtr< Entry > > > bySignedCert;
|
||||
for (;;) {
|
||||
// Create a reverse lookup mapping from signed certs to signer certs for certificate
|
||||
// path validation. Only include good certificates.
|
||||
for (Map< H384, SharedPtr< Entry > >::const_iterator c(m_bySerial.begin()); c != m_bySerial.end(); ++c) {
|
||||
if (c->second->error() == ZT_CERTIFICATE_ERROR_NONE) {
|
||||
for (unsigned int j = 0; j < c->second->m_certificate.subject.certificateCount; ++j)
|
||||
bySignedCert[H384(c->second->m_certificate.subject.certificates[j])].push_back(c->second);
|
||||
}
|
||||
}
|
||||
|
||||
// Validate certificate paths and reject any certificates that do not trace back to a CA.
|
||||
for (Map< H384, SharedPtr< Entry > >::const_iterator c(m_bySerial.begin()); c != m_bySerial.end(); ++c) {
|
||||
for (Map< H384, SharedPtr< Entry > >::iterator c(m_bySerial.begin()); c != m_bySerial.end(); ++c) {
|
||||
if (c->second->error() == ZT_CERTIFICATE_ERROR_NONE) {
|
||||
if (!p_validatePath(bySignedCert, c->second, 0))
|
||||
unsigned int pathLength = 0;
|
||||
Map< H384, SharedPtr< Entry > >::const_iterator current(c);
|
||||
Set< H384 > visited; // prevent infinite loops if there's a cycle
|
||||
for (;;) {
|
||||
if (pathLength <= current->second->m_certificate.maxPathLength) {
|
||||
if ((current->second->localTrust() & ZT_CERTIFICATE_LOCAL_TRUST_FLAG_ROOT_CA) == 0) {
|
||||
visited.insert(current->second->m_certificate.getSerialNo());
|
||||
const H384 next(current->second->m_certificate.issuer);
|
||||
if (visited.find(next) == visited.end()) {
|
||||
current = m_bySerial.find(next);
|
||||
if ((current != m_bySerial.end()) && (current->second->error() == ZT_CERTIFICATE_ERROR_NONE)) {
|
||||
++pathLength;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
break; // traced to root CA, abort without setting error
|
||||
}
|
||||
}
|
||||
c->second->m_error.store((int)ZT_CERTIFICATE_ERROR_INVALID_CHAIN, std::memory_order_relaxed);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Populate mapping of subject unique IDs to certificates and reject any certificates
|
||||
// that have been superseded by newly issued certificates with the same subject.
|
||||
|
@ -159,8 +150,8 @@ bool TrustStore::update(const int64_t clock, Vector< SharedPtr< Entry > > *const
|
|||
for (Map< H384, SharedPtr< Entry > >::const_iterator c(m_bySerial.begin()); c != m_bySerial.end();) {
|
||||
if (c->second->error() == ZT_CERTIFICATE_ERROR_NONE) {
|
||||
const unsigned int uniqueIdSize = c->second->m_certificate.subject.uniqueIdSize;
|
||||
if ((uniqueIdSize > 0) && (uniqueIdSize <= ZT_CERTIFICATE_UNIQUE_ID_TYPE_NIST_P_384_SIZE)) {
|
||||
SharedPtr< Entry > ¤t = m_bySubjectUniqueId[Blob< ZT_CERTIFICATE_UNIQUE_ID_TYPE_NIST_P_384_SIZE >(c->second->m_certificate.subject.uniqueId, uniqueIdSize)];
|
||||
if ((uniqueIdSize > 0) && (uniqueIdSize <= ZT_CERTIFICATE_MAX_PUBLIC_KEY_SIZE)) {
|
||||
SharedPtr< Entry > ¤t = m_bySubjectUniqueId[Blob< ZT_CERTIFICATE_MAX_PUBLIC_KEY_SIZE >(c->second->m_certificate.subject.uniqueId, uniqueIdSize)];
|
||||
if (current) {
|
||||
exitLoop = false;
|
||||
if (c->second->m_certificate.subject.timestamp > current->m_certificate.subject.timestamp) {
|
||||
|
|
|
@ -178,7 +178,7 @@ public:
|
|||
|
||||
private:
|
||||
Map< H384, SharedPtr< Entry > > m_bySerial; // all certificates
|
||||
Map< Blob< ZT_CERTIFICATE_UNIQUE_ID_TYPE_NIST_P_384_SIZE >, SharedPtr< Entry > > m_bySubjectUniqueId; // non-rejected certificates only
|
||||
Map< Blob< ZT_CERTIFICATE_MAX_PUBLIC_KEY_SIZE >, SharedPtr< Entry > > m_bySubjectUniqueId; // non-rejected certificates only
|
||||
Map< Fingerprint, Vector< SharedPtr< Entry > > > m_bySubjectIdentity; // non-rejected certificates only
|
||||
ForwardList< SharedPtr< Entry > > m_addQueue;
|
||||
ForwardList< H384 > m_deleteQueue;
|
||||
|
|
190
core/zerotier.h
190
core/zerotier.h
|
@ -337,27 +337,6 @@ typedef struct
|
|||
*/
|
||||
#define ZT_CERTIFICATE_LOCAL_TRUST_FLAG_ZEROTIER_ROOT_SET 0x0002U
|
||||
|
||||
/**
|
||||
* Size of a unique ID of the given key type (with type prefix byte)
|
||||
*/
|
||||
#define ZT_CERTIFICATE_UNIQUE_ID_TYPE_NIST_P_384_SIZE 50
|
||||
|
||||
/**
|
||||
* Size of the private key corresponding to a unique ID of the given type.
|
||||
*/
|
||||
#define ZT_CERTIFICATE_UNIQUE_ID_TYPE_NIST_P_384_PRIVATE_SIZE 48
|
||||
|
||||
/**
|
||||
* Unique ID types supported for certificate subject unique IDs
|
||||
*/
|
||||
enum ZT_CertificateUniqueIdType
|
||||
{
|
||||
/**
|
||||
* Public key type for NIST P-384 public keys used as subject unique IDs.
|
||||
*/
|
||||
ZT_CERTIFICATE_UNIQUE_ID_TYPE_NIST_P_384 = 1
|
||||
};
|
||||
|
||||
/**
|
||||
* Errors returned by functions that verify or handle certificates.
|
||||
*/
|
||||
|
@ -414,6 +393,42 @@ enum ZT_CertificateError
|
|||
ZT_CERTIFICATE_ERROR_OUT_OF_VALID_TIME_WINDOW = -8
|
||||
};
|
||||
|
||||
/**
|
||||
* Public key signing algorithm for certificates
|
||||
*/
|
||||
enum ZT_CertificatePublicKeyAlgorithm
|
||||
{
|
||||
/**
|
||||
* Nil value indicating no signature.
|
||||
*/
|
||||
ZT_CERTIFICATE_PUBLIC_KEY_ALGORITHM_NONE = 0,
|
||||
|
||||
/**
|
||||
* ECDSA with the NIST P-384 curve.
|
||||
*/
|
||||
ZT_CERTIFICATE_PUBLIC_KEY_ALGORITHM_ECDSA_NIST_P_384 = 1
|
||||
};
|
||||
|
||||
/**
|
||||
* Maximum size of a public key in bytes (can be increased)
|
||||
*/
|
||||
#define ZT_CERTIFICATE_MAX_PUBLIC_KEY_SIZE 64
|
||||
|
||||
/**
|
||||
* Maximum size of a private key in bytes (can be increased)
|
||||
*/
|
||||
#define ZT_CERTIFICATE_MAX_PRIVATE_KEY_SIZE 128
|
||||
|
||||
/**
|
||||
* Maximum size of a signature in bytes (can be increased)
|
||||
*/
|
||||
#define ZT_CERTIFICATE_MAX_SIGNATURE_SIZE 128
|
||||
|
||||
/**
|
||||
* Size of a SHA384 hash
|
||||
*/
|
||||
#define ZT_CERTIFICATE_HASH_SIZE 48
|
||||
|
||||
/**
|
||||
* Information about a real world entity.
|
||||
*
|
||||
|
@ -447,7 +462,7 @@ typedef struct
|
|||
const ZT_Identity *identity;
|
||||
|
||||
/**
|
||||
* Locator, or NULL if none
|
||||
* Locator (NULL if no locator included)
|
||||
*/
|
||||
const ZT_Locator *locator;
|
||||
} ZT_Certificate_Identity;
|
||||
|
@ -526,28 +541,15 @@ typedef struct
|
|||
/**
|
||||
* Globally unique ID for this subject
|
||||
*
|
||||
* Unique IDs are actually public keys. Their size makes them globally
|
||||
* unique (if generated from good randomness) to within ridiculous
|
||||
* probability bounds. If a subject has a unique ID it must also have
|
||||
* a unique ID proof signature, which is the signature of the subject
|
||||
* with the private key corresponding to its unique ID.
|
||||
*
|
||||
* This allows subjects to "own" themselves and exist independent of
|
||||
* CAs or delegated signers. It also allows a certificate for a given
|
||||
* subject to be updated.
|
||||
*
|
||||
* Subject unique IDs are optional. If no unique ID is specified these
|
||||
* and their corresponding size fields must be empty/zero.
|
||||
*
|
||||
* A subject is valid if it has no unique ID or has one with a valid
|
||||
* proof signature.
|
||||
* This is actually a public key and is generated the same way as a normal
|
||||
* certificate public key.
|
||||
*/
|
||||
const uint8_t *uniqueId;
|
||||
uint8_t uniqueId[ZT_CERTIFICATE_MAX_PUBLIC_KEY_SIZE];
|
||||
|
||||
/**
|
||||
* Signature proving ownership of unique ID.
|
||||
*/
|
||||
const uint8_t *uniqueIdProofSignature;
|
||||
uint8_t uniqueIdSignature[ZT_CERTIFICATE_MAX_SIGNATURE_SIZE];
|
||||
|
||||
/**
|
||||
* Size of unique ID in bytes or 0 if none.
|
||||
|
@ -557,7 +559,7 @@ typedef struct
|
|||
/**
|
||||
* Proof signature size or 0 if none.
|
||||
*/
|
||||
unsigned int uniqueIdProofSignatureSize;
|
||||
unsigned int uniqueIdSignatureSize;
|
||||
} ZT_Certificate_Subject;
|
||||
|
||||
/**
|
||||
|
@ -573,9 +575,9 @@ typedef struct
|
|||
typedef struct
|
||||
{
|
||||
/**
|
||||
* Serial number, a SHA384 hash of this certificate.
|
||||
* Serial number, a SHA384 hash of this certificate (minus signature).
|
||||
*/
|
||||
uint8_t serialNo[48];
|
||||
uint8_t serialNo[ZT_CERTIFICATE_HASH_SIZE];
|
||||
|
||||
/**
|
||||
* Flags indicating certificate usage and any other attributes.
|
||||
|
@ -598,14 +600,29 @@ typedef struct
|
|||
ZT_Certificate_Subject subject;
|
||||
|
||||
/**
|
||||
* Issuer node identity and public key(s).
|
||||
* Issuer certificate serial number.
|
||||
*/
|
||||
const ZT_Identity *issuer;
|
||||
uint8_t issuer[ZT_CERTIFICATE_HASH_SIZE];
|
||||
|
||||
/**
|
||||
* Issuer information
|
||||
* Public key of issuer certificate.
|
||||
*/
|
||||
ZT_Certificate_Name issuerName;
|
||||
uint8_t issuerPublicKey[ZT_CERTIFICATE_MAX_PUBLIC_KEY_SIZE];
|
||||
|
||||
/**
|
||||
* Certificate public key (first byte is ZT_CertificatePublicKeyAlgorithm)
|
||||
*/
|
||||
uint8_t publicKey[ZT_CERTIFICATE_MAX_PUBLIC_KEY_SIZE];
|
||||
|
||||
/**
|
||||
* Size of issuer public key.
|
||||
*/
|
||||
unsigned int issuerPublicKeySize;
|
||||
|
||||
/**
|
||||
* Size of public key in bytes
|
||||
*/
|
||||
unsigned int publicKeySize;
|
||||
|
||||
/**
|
||||
* Extended attributes set by issuer (in Dictionary format, NULL if none)
|
||||
|
@ -617,6 +634,16 @@ typedef struct
|
|||
*/
|
||||
unsigned int extendedAttributesSize;
|
||||
|
||||
/**
|
||||
* Signature by issuer.
|
||||
*/
|
||||
uint8_t signature[ZT_CERTIFICATE_MAX_SIGNATURE_SIZE];
|
||||
|
||||
/**
|
||||
* Size of signature in bytes.
|
||||
*/
|
||||
unsigned int signatureSize;
|
||||
|
||||
/**
|
||||
* Maximum path length from this certificate toward further certificates.
|
||||
*
|
||||
|
@ -625,16 +652,6 @@ typedef struct
|
|||
* may be signed (not a CA).
|
||||
*/
|
||||
unsigned int maxPathLength;
|
||||
|
||||
/**
|
||||
* Signature by issuer (algorithm determined by identity type).
|
||||
*/
|
||||
const uint8_t *signature;
|
||||
|
||||
/**
|
||||
* Size of signature in bytes.
|
||||
*/
|
||||
unsigned int signatureSize;
|
||||
} ZT_Certificate;
|
||||
|
||||
/**
|
||||
|
@ -2756,23 +2773,24 @@ ZT_SDK_API void ZT_version(
|
|||
/* ---------------------------------------------------------------------------------------------------------------- */
|
||||
|
||||
/**
|
||||
* Create a new certificate subject unique ID and private key
|
||||
* Create a new public/private key pair.
|
||||
*
|
||||
* A unique ID is really a public/private key pair.
|
||||
* This is for use as a certificate public key or as the unique ID for
|
||||
* enforcing subject ownership.
|
||||
*
|
||||
* @param type Unique ID type (key pair algorithm)
|
||||
* @param uniqueId Unique ID buffer
|
||||
* @param uniqueIdSize Value/result: size of buffer
|
||||
* @param uniqueIdPrivate Unique ID private key buffer
|
||||
* @param uniqueIdPrivateSize Value/result: size of buffer
|
||||
* @param type Type to create
|
||||
* @param publicKey Public key buffer
|
||||
* @param publicKeySize Result parameter: set to size of public key
|
||||
* @param privateKey Private key buffer
|
||||
* @param privateKeySize Result parameter: set to size of private key
|
||||
* @return OK (0) or error
|
||||
*/
|
||||
ZT_SDK_API int ZT_Certificate_newSubjectUniqueId(
|
||||
enum ZT_CertificateUniqueIdType type,
|
||||
void *uniqueId,
|
||||
int *uniqueIdSize,
|
||||
void *uniqueIdPrivate,
|
||||
int *uniqueIdPrivateSize);
|
||||
ZT_SDK_API int ZT_Certificate_newKeyPair(
|
||||
enum ZT_CertificatePublicKeyAlgorithm type,
|
||||
uint8_t publicKey[ZT_CERTIFICATE_MAX_PUBLIC_KEY_SIZE],
|
||||
int *const publicKeySize,
|
||||
uint8_t privateKey[ZT_CERTIFICATE_MAX_PRIVATE_KEY_SIZE],
|
||||
int *const privateKeySize);
|
||||
|
||||
/**
|
||||
* Create a new certificate signing request (CSR)
|
||||
|
@ -2784,20 +2802,20 @@ ZT_SDK_API int ZT_Certificate_newSubjectUniqueId(
|
|||
* supplied subject, these will be ignored.
|
||||
*
|
||||
* @param subject Subject filled in with fields for CSR
|
||||
* @param uniqueId Unique ID or NULL if none
|
||||
* @param uniqueIdSize Size of unique ID
|
||||
* @param uniqueIdPrivate Unique ID private key or NULL if none
|
||||
* @param uniqueIdPrivateSize Size of unique ID private key
|
||||
* @param certificatePublicKey Public key for new certificate
|
||||
* @param certificatePublicKeySize Public key size in bytes
|
||||
* @param uniqueIdPrivateKey Unique ID private key or NULL if none
|
||||
* @param uniqueIdPrivateKeySize Size of unique ID private key
|
||||
* @param csr Buffer to hold CSR (recommended size: 16384 bytes)
|
||||
* @param csrSize Value/result: size of buffer
|
||||
* @return OK (0) or error
|
||||
*/
|
||||
ZT_SDK_API int ZT_Certificate_newCSR(
|
||||
const ZT_Certificate_Subject *subject,
|
||||
const void *uniqueId,
|
||||
int uniqueIdSize,
|
||||
const void *uniqueIdPrivate,
|
||||
int uniqueIdPrivateSize,
|
||||
const void *certificatePublicKey,
|
||||
int certificatePublicKeySize,
|
||||
const void *uniqueIdPrivateKey,
|
||||
int uniqueIdPrivateKeySize,
|
||||
void *csr,
|
||||
int *csrSize);
|
||||
|
||||
|
@ -2808,17 +2826,19 @@ ZT_SDK_API int ZT_Certificate_newCSR(
|
|||
* certificate fields before signing. Things outside the subject are
|
||||
* filled in (or can be modified) by the signer.
|
||||
*
|
||||
* The returned certificate must be freed with ZT_Certificate_delete().
|
||||
*
|
||||
* @param cert Certificate to sign
|
||||
* @param signer Signer identity (must contain secret key)
|
||||
* @param signedCert Signed certificate buffer (recommended size: 16384 bytes)
|
||||
* @param signedCertSize Value/result: size of buffer
|
||||
* @return OK (0) or error
|
||||
* @param issuer Serial number of issuer certificate
|
||||
* @param issuerPrivateKey Private key of issuer (also includes public)
|
||||
* @param issuerPrivateKeySize Size of private key in bytes
|
||||
* @return Signed certificate or NULL on error
|
||||
*/
|
||||
ZT_SDK_API int ZT_Certificate_sign(
|
||||
ZT_SDK_API ZT_Certificate *ZT_Certificate_sign(
|
||||
const ZT_Certificate *cert,
|
||||
const ZT_Identity *signer,
|
||||
void *signedCert,
|
||||
int *signedCertSize);
|
||||
const uint8_t issuer[ZT_CERTIFICATE_HASH_SIZE],
|
||||
const void *issuerPrivateKey,
|
||||
int issuerPrivateKeySize);
|
||||
|
||||
/**
|
||||
* Decode a certificate or CSR
|
||||
|
|
|
@ -20,11 +20,11 @@ fn new_(cli_args: &ArgMatches) -> i32 {
|
|||
if ts.is_empty() {
|
||||
0_i64
|
||||
} else {
|
||||
i64::from_str_radix(ts, 10).unwrap_or(0_i64) * 1000_i64 // internally uses ms since epoch
|
||||
i64::from_str_radix(ts, 10).unwrap_or(0)
|
||||
}
|
||||
});
|
||||
if revision <= 0 {
|
||||
println!("ERROR: invalid or empty timestamp specified.");
|
||||
if revision < 0 {
|
||||
println!("ERROR: invalid revision (must be >= 0).");
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
|
|
@ -111,7 +111,7 @@ Advanced Operations:
|
|||
|
||||
locator <command> [args]
|
||||
new [-...] <identity> <endpoint> [...] Create new signed locator
|
||||
-r <revision> Revision number
|
||||
-r <revision> Revision number (default: time)
|
||||
verify <identity> <locator> Verify locator signature
|
||||
show <locator> Show contents of a locator
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue