mirror of
https://github.com/zerotier/ZeroTierOne.git
synced 2025-08-02 23:12:51 +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;
|
uintptr_t bb;
|
||||||
for (;;) {
|
for (;;) {
|
||||||
bb = s_pool.exchange(ZT_ATOMIC_PTR_LOCKED, std::memory_order_acquire);
|
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;
|
Buf *b;
|
||||||
if (bb) {
|
if (likely(bb != 0)) {
|
||||||
s_pool.store(((Buf *)bb)->__nextInPool.load(std::memory_order_relaxed), std::memory_order_release);
|
b = reinterpret_cast<Buf *>(bb);
|
||||||
b = (Buf *)bb;
|
s_pool.store(b->__nextInPool, std::memory_order_release);
|
||||||
} else {
|
} else {
|
||||||
s_pool.store(0, std::memory_order_release);
|
s_pool.store(0, std::memory_order_release);
|
||||||
b = (Buf *)malloc(sz);
|
b = reinterpret_cast<Buf *>(malloc(sz));
|
||||||
if (!b)
|
if (!b)
|
||||||
throw Utils::BadAllocException;
|
throw Utils::BadAllocException;
|
||||||
s_allocated.fetch_add(1, std::memory_order_relaxed);
|
s_allocated.fetch_add(1, std::memory_order_relaxed);
|
||||||
}
|
}
|
||||||
|
|
||||||
b->__refCount.store(0, 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)
|
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) {
|
if (s_allocated.load(std::memory_order_relaxed) > ZT_BUF_MAX_POOL_SIZE) {
|
||||||
|
s_allocated.fetch_sub(1, std::memory_order_relaxed);
|
||||||
free(ptr);
|
free(ptr);
|
||||||
} else {
|
} else {
|
||||||
uintptr_t bb;
|
uintptr_t bb;
|
||||||
for (;;) {
|
for (;;) {
|
||||||
bb = s_pool.exchange(ZT_ATOMIC_PTR_LOCKED, std::memory_order_acquire);
|
bb = s_pool.exchange(ZT_ATOMIC_PTR_LOCKED, std::memory_order_acquire);
|
||||||
if (likely(bb != ZT_ATOMIC_PTR_LOCKED))
|
if (likely(bb != ZT_ATOMIC_PTR_LOCKED)) {
|
||||||
break;
|
reinterpret_cast<Buf *>(ptr)->__nextInPool = bb;
|
||||||
|
s_pool.store(reinterpret_cast<uintptr_t>(ptr), std::memory_order_release);
|
||||||
|
return;
|
||||||
|
}
|
||||||
Spinlock::pause();
|
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;
|
uintptr_t bb;
|
||||||
for (;;) {
|
for (;;) {
|
||||||
bb = s_pool.exchange(ZT_ATOMIC_PTR_LOCKED, std::memory_order_acquire);
|
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);
|
s_pool.store(0, std::memory_order_release);
|
||||||
|
|
||||||
while (bb != 0) {
|
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);
|
s_allocated.fetch_sub(1, std::memory_order_relaxed);
|
||||||
free((void *)bb);
|
free(reinterpret_cast<void *>(bb));
|
||||||
bb = next;
|
bb = next;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Spinlock::pause();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
long Buf::poolAllocated() noexcept
|
long Buf::poolAllocated() noexcept
|
||||||
|
|
|
@ -857,10 +857,7 @@ public:
|
||||||
{ return ZT_BUF_MEM_SIZE; }
|
{ return ZT_BUF_MEM_SIZE; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// Next item in free buffer pool linked list if Buf is placed in pool, undefined and unused otherwise
|
volatile uintptr_t __nextInPool;
|
||||||
std::atomic< uintptr_t > __nextInPool;
|
|
||||||
|
|
||||||
// Reference counter for SharedPtr<>
|
|
||||||
std::atomic< int > __refCount;
|
std::atomic< int > __refCount;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -20,6 +20,7 @@
|
||||||
#include "VL1.hpp"
|
#include "VL1.hpp"
|
||||||
#include "VL2.hpp"
|
#include "VL2.hpp"
|
||||||
#include "CallContext.hpp"
|
#include "CallContext.hpp"
|
||||||
|
#include "ECC384.hpp"
|
||||||
|
|
||||||
extern "C" {
|
extern "C" {
|
||||||
|
|
||||||
|
@ -658,24 +659,15 @@ ZT_MAYBE_UNUSED void ZT_Identity_delete(const ZT_Identity *id)
|
||||||
|
|
||||||
/********************************************************************************************************************/
|
/********************************************************************************************************************/
|
||||||
|
|
||||||
ZT_MAYBE_UNUSED int ZT_Certificate_newSubjectUniqueId(
|
ZT_MAYBE_UNUSED int ZT_Certificate_newKeyPair(
|
||||||
enum ZT_CertificateUniqueIdType type,
|
const enum ZT_CertificatePublicKeyAlgorithm type,
|
||||||
void *uniqueId,
|
uint8_t publicKey[ZT_CERTIFICATE_MAX_PUBLIC_KEY_SIZE],
|
||||||
int *uniqueIdSize,
|
int *const publicKeySize,
|
||||||
void *uniqueIdPrivate,
|
uint8_t privateKey[ZT_CERTIFICATE_MAX_PRIVATE_KEY_SIZE],
|
||||||
int *uniqueIdPrivateSize)
|
int *const privateKeySize)
|
||||||
{
|
{
|
||||||
try {
|
try {
|
||||||
switch (type) {
|
return ZeroTier::Certificate::newKeyPair(type, publicKey, publicKeySize, privateKey, privateKeySize) ? ZT_RESULT_OK : ZT_RESULT_ERROR_BAD_PARAMETER;
|
||||||
case ZT_CERTIFICATE_UNIQUE_ID_TYPE_NIST_P_384:
|
|
||||||
if ((*uniqueIdSize < ZT_CERTIFICATE_UNIQUE_ID_TYPE_NIST_P_384_SIZE) || (*uniqueIdPrivateSize < ZT_CERTIFICATE_UNIQUE_ID_TYPE_NIST_P_384_PRIVATE_SIZE))
|
|
||||||
return ZT_RESULT_ERROR_BAD_PARAMETER;
|
|
||||||
*uniqueIdSize = ZT_CERTIFICATE_UNIQUE_ID_TYPE_NIST_P_384_SIZE;
|
|
||||||
*uniqueIdPrivateSize = ZT_CERTIFICATE_UNIQUE_ID_TYPE_NIST_P_384_PRIVATE_SIZE;
|
|
||||||
ZeroTier::Certificate::createSubjectUniqueId(reinterpret_cast<uint8_t *>(uniqueId), reinterpret_cast<uint8_t *>(uniqueIdPrivate));
|
|
||||||
return ZT_RESULT_OK;
|
|
||||||
}
|
|
||||||
return ZT_RESULT_ERROR_BAD_PARAMETER;
|
|
||||||
} catch ( ... ) {
|
} catch ( ... ) {
|
||||||
return ZT_RESULT_FATAL_ERROR_INTERNAL;
|
return ZT_RESULT_FATAL_ERROR_INTERNAL;
|
||||||
}
|
}
|
||||||
|
@ -683,18 +675,18 @@ ZT_MAYBE_UNUSED int ZT_Certificate_newSubjectUniqueId(
|
||||||
|
|
||||||
ZT_MAYBE_UNUSED int ZT_Certificate_newCSR(
|
ZT_MAYBE_UNUSED int ZT_Certificate_newCSR(
|
||||||
const ZT_Certificate_Subject *subject,
|
const ZT_Certificate_Subject *subject,
|
||||||
const void *uniqueId,
|
const void *const certificatePublicKey,
|
||||||
int uniqueIdSize,
|
const int certificatePublicKeySize,
|
||||||
const void *uniqueIdPrivate,
|
const void *const uniqueIdPrivateKey,
|
||||||
int uniqueIdPrivateSize,
|
const int uniqueIdPrivateKeySize,
|
||||||
void *csr,
|
void *const csr,
|
||||||
int *csrSize)
|
int *const csrSize)
|
||||||
{
|
{
|
||||||
try {
|
try {
|
||||||
if (!subject)
|
if ((!subject) || (!certificatePublicKey) || (certificatePublicKeySize <= 0) || (certificatePublicKeySize > ZT_CERTIFICATE_MAX_PUBLIC_KEY_SIZE))
|
||||||
return ZT_RESULT_ERROR_BAD_PARAMETER;
|
return ZT_RESULT_ERROR_BAD_PARAMETER;
|
||||||
const ZeroTier::Vector< uint8_t > csrV(ZeroTier::Certificate::createCSR(*subject, uniqueId, uniqueIdSize, uniqueIdPrivate, uniqueIdPrivateSize));
|
const ZeroTier::Vector< uint8_t > csrV(ZeroTier::Certificate::createCSR(*subject, certificatePublicKey, (unsigned int)certificatePublicKeySize, uniqueIdPrivateKey, (unsigned int)uniqueIdPrivateKeySize));
|
||||||
if ((int)csrV.size() > *csrSize)
|
if (csrV.empty() || ((int)csrV.size() > *csrSize))
|
||||||
return ZT_RESULT_ERROR_BAD_PARAMETER;
|
return ZT_RESULT_ERROR_BAD_PARAMETER;
|
||||||
ZeroTier::Utils::copy(csr, csrV.data(), (unsigned int)csrV.size());
|
ZeroTier::Utils::copy(csr, csrV.data(), (unsigned int)csrV.size());
|
||||||
*csrSize = (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_Certificate *cert,
|
||||||
const ZT_Identity *signer,
|
const uint8_t issuer[ZT_CERTIFICATE_HASH_SIZE],
|
||||||
void *signedCert,
|
const void *issuerPrivateKey,
|
||||||
int *signedCertSize)
|
int issuerPrivateKeySize)
|
||||||
{
|
{
|
||||||
try {
|
try {
|
||||||
if (!cert)
|
ZeroTier::Certificate *const c = new ZeroTier::Certificate(*cert);
|
||||||
return ZT_RESULT_ERROR_BAD_PARAMETER;
|
if (c->sign(issuer, issuerPrivateKey, issuerPrivateKeySize)) {
|
||||||
ZeroTier::Certificate c(*cert);
|
return c;
|
||||||
if (!c.sign(*reinterpret_cast<const ZeroTier::Identity *>(signer)))
|
} else {
|
||||||
return ZT_RESULT_ERROR_INTERNAL;
|
delete c;
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
} catch (...) {}
|
||||||
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
ZT_MAYBE_UNUSED enum ZT_CertificateError ZT_Certificate_decode(
|
ZT_MAYBE_UNUSED enum ZT_CertificateError ZT_Certificate_decode(
|
||||||
|
|
|
@ -39,7 +39,7 @@ Certificate &Certificate::operator=(const ZT_Certificate &cert)
|
||||||
{
|
{
|
||||||
m_clear();
|
m_clear();
|
||||||
|
|
||||||
Utils::copy< 48 >(this->serialNo, cert.serialNo);
|
Utils::copy< sizeof(this->serialNo) >(this->serialNo, cert.serialNo);
|
||||||
this->flags = cert.flags;
|
this->flags = cert.flags;
|
||||||
this->timestamp = cert.timestamp;
|
this->timestamp = cert.timestamp;
|
||||||
this->validity[0] = cert.validity[0];
|
this->validity[0] = cert.validity[0];
|
||||||
|
@ -47,7 +47,7 @@ Certificate &Certificate::operator=(const ZT_Certificate &cert)
|
||||||
|
|
||||||
this->subject.timestamp = cert.subject.timestamp;
|
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) {
|
for (unsigned int i = 0; i < cert.subject.identityCount; ++i) {
|
||||||
if (cert.subject.identities[i].identity) {
|
if (cert.subject.identities[i].identity) {
|
||||||
if (cert.subject.identities[i].locator) {
|
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) {
|
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);
|
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) {
|
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]);
|
addSubjectCertificate(cert.subject.certificates[i]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (cert.subject.updateURLs) {
|
if (cert.subject.updateURLs != nullptr) {
|
||||||
for (unsigned int i = 0; i < cert.subject.updateURLCount; ++i) {
|
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]);
|
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));
|
Utils::copy< sizeof(ZT_Certificate_Name) >(&(this->subject.name), &(cert.subject.name));
|
||||||
|
|
||||||
if ((cert.subject.uniqueId) && (cert.subject.uniqueIdSize > 0)) {
|
Utils::copy< sizeof(this->subject.uniqueId) >(this->subject.uniqueId, cert.subject.uniqueId);
|
||||||
m_subjectUniqueId.assign(cert.subject.uniqueId, cert.subject.uniqueId + cert.subject.uniqueIdSize);
|
Utils::copy< sizeof(this->subject.uniqueIdSignature) >(this->subject.uniqueIdSignature, cert.subject.uniqueIdSignature);
|
||||||
this->subject.uniqueId = m_subjectUniqueId.data();
|
this->subject.uniqueIdSize = cert.subject.uniqueIdSize;
|
||||||
this->subject.uniqueIdSize = (unsigned int)m_subjectUniqueId.size();
|
this->subject.uniqueIdSignatureSize = cert.subject.uniqueIdSignatureSize;
|
||||||
}
|
|
||||||
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();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (cert.issuer) {
|
Utils::copy< sizeof(this->issuer) >(this->issuer, cert.issuer);
|
||||||
m_identities.push_front(*reinterpret_cast<const Identity *>(cert.issuer));
|
|
||||||
this->issuer = &(m_identities.front());
|
|
||||||
}
|
|
||||||
|
|
||||||
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);
|
m_extendedAttributes.assign(cert.extendedAttributes, cert.extendedAttributes + cert.extendedAttributesSize);
|
||||||
this->extendedAttributes = m_extendedAttributes.data();
|
this->extendedAttributes = m_extendedAttributes.data();
|
||||||
this->extendedAttributesSize = (unsigned int)m_extendedAttributes.size();
|
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)) {
|
this->maxPathLength = cert.maxPathLength;
|
||||||
m_signature.assign(cert.signature, cert.signature + cert.signatureSize);
|
|
||||||
this->signature = m_signature.data();
|
|
||||||
this->signatureSize = (unsigned int)m_signature.size();
|
|
||||||
}
|
|
||||||
|
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
@ -127,6 +126,7 @@ ZT_Certificate_Identity *Certificate::addSubjectIdentity(const Identity &id)
|
||||||
m_subjectIdentities.push_back(ZT_Certificate_Identity());
|
m_subjectIdentities.push_back(ZT_Certificate_Identity());
|
||||||
m_subjectIdentities.back().identity = &(m_identities.front());
|
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.identities = m_subjectIdentities.data();
|
||||||
this->subject.identityCount = (unsigned int)m_subjectIdentities.size();
|
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)
|
void Certificate::addSubjectUpdateUrl(const char *url)
|
||||||
{
|
{
|
||||||
if ((!url) || (!url[0]))
|
if ((url != nullptr) && (url[0] != 0)) {
|
||||||
return;
|
|
||||||
|
|
||||||
// Store local copy of URL.
|
// Store local copy of URL.
|
||||||
m_strings.push_front(url);
|
m_strings.push_front(url);
|
||||||
|
|
||||||
|
@ -186,37 +184,6 @@ void Certificate::addSubjectUpdateUrl(const char *url)
|
||||||
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();
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
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
|
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]);
|
d.add("v#0", (uint64_t)this->validity[0]);
|
||||||
if (this->validity[1] > 0)
|
if (this->validity[1] > 0)
|
||||||
d.add("v#1", (uint64_t)this->validity[1]);
|
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);
|
||||||
|
|
||||||
if (this->issuer)
|
if (!Utils::allZero(this->issuer, sizeof(this->issuer)))
|
||||||
d.addO("i", *reinterpret_cast<const Identity *>(this->issuer));
|
d.add("i", this->issuer, sizeof(this->issuer));
|
||||||
|
|
||||||
if (this->issuerName.country[0])
|
if (this->issuerPublicKeySize > 0)
|
||||||
d.add("iN.c", this->issuerName.country);
|
d.add("iPK", this->issuerPublicKey, this->issuerPublicKeySize);
|
||||||
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->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);
|
d["x"].assign(this->extendedAttributes, this->extendedAttributes + this->extendedAttributesSize);
|
||||||
|
|
||||||
if ((!omitSignature) && (this->signature) && (this->signatureSize > 0))
|
if ((!omitSignature) && (this->signatureSize > 0))
|
||||||
d["S"].assign(this->signature, this->signature + this->signatureSize);
|
d["si"].assign(this->signature, this->signature + this->signatureSize);
|
||||||
|
|
||||||
|
if (this->maxPathLength > 0)
|
||||||
|
d.add("l", (uint64_t)this->maxPathLength);
|
||||||
|
|
||||||
d.encode(enc);
|
d.encode(enc);
|
||||||
return 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->timestamp = (int64_t)d.getUI("t");
|
||||||
this->validity[0] = (int64_t)d.getUI("v#0");
|
this->validity[0] = (int64_t)d.getUI("v#0");
|
||||||
this->validity[1] = (int64_t)d.getUI("v#1");
|
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");
|
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.ur", this->subject.name.url, sizeof(this->subject.name.url));
|
||||||
d.getS("s.n.h", this->subject.name.host, sizeof(this->subject.name.host));
|
d.getS("s.n.h", this->subject.name.host, sizeof(this->subject.name.host));
|
||||||
|
|
||||||
m_subjectUniqueId = d["s.uI"];
|
const Vector< uint8_t > &uniqueId = d["s.uI"];
|
||||||
if (!m_subjectUniqueId.empty()) {
|
if ((!uniqueId.empty()) && (uniqueId.size() <= sizeof(this->subject.uniqueId))) {
|
||||||
this->subject.uniqueId = m_subjectUniqueId.data();
|
Utils::copy(this->subject.uniqueId, uniqueId.data(), uniqueId.size());
|
||||||
this->subject.uniqueIdSize = (unsigned int)m_subjectUniqueId.size();
|
this->subject.uniqueIdSize = (unsigned int)uniqueId.size();
|
||||||
}
|
}
|
||||||
m_subjectUniqueIdProofSignature = d["s.uS"];
|
const Vector< uint8_t > &uniqueIdSignature = d["s.uS"];
|
||||||
if (!m_subjectUniqueIdProofSignature.empty()) {
|
if ((!uniqueIdSignature.empty()) && (uniqueIdSignature.size() <= sizeof(this->subject.uniqueIdSignature))) {
|
||||||
this->subject.uniqueIdProofSignature = m_subjectUniqueIdProofSignature.data();
|
Utils::copy(this->subject.uniqueIdSignature, uniqueIdSignature.data(), uniqueIdSignature.size());
|
||||||
this->subject.uniqueIdProofSignatureSize = (unsigned int)m_subjectUniqueIdProofSignature.size();
|
this->subject.uniqueIdSignatureSize = (unsigned int)uniqueIdSignature.size();
|
||||||
}
|
}
|
||||||
|
|
||||||
const Vector< uint8_t > &issuerData = d["i"];
|
const Vector< uint8_t > &issuerData = d["i"];
|
||||||
if (!issuerData.empty()) {
|
if (issuerData.size() == sizeof(this->issuer)) {
|
||||||
Identity id;
|
Utils::copy< sizeof(this->issuer) >(this->issuer, issuerData.data());
|
||||||
if (id.unmarshal(issuerData.data(), (int)issuerData.size()) > 0) {
|
|
||||||
m_identities.push_front(id);
|
|
||||||
this->issuer = reinterpret_cast<const Identity *>(&(m_identities.front()));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
d.getS("iN.sN", this->issuerName.serialNo, sizeof(this->issuerName.serialNo));
|
const Vector< uint8_t > &issuerPublicKey = d["iPK"];
|
||||||
d.getS("iN.cN", this->issuerName.commonName, sizeof(this->issuerName.commonName));
|
if ((!issuerPublicKey.empty()) && (issuerPublicKey.size() <= sizeof(this->issuerPublicKey))) {
|
||||||
d.getS("iN.c", this->issuerName.country, sizeof(this->issuerName.country));
|
Utils::copy(this->issuerPublicKey, issuerPublicKey.data(), issuerPublicKey.size());
|
||||||
d.getS("iN.o", this->issuerName.organization, sizeof(this->issuerName.organization));
|
this->issuerPublicKeySize = (unsigned int)issuerPublicKey.size();
|
||||||
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 > &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"];
|
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();
|
this->extendedAttributesSize = (unsigned int)m_extendedAttributes.size();
|
||||||
}
|
}
|
||||||
|
|
||||||
m_signature = d["S"];
|
const Vector< uint8_t > &signature = d["si"];
|
||||||
if (!m_signature.empty()) {
|
if ((!signature.empty()) && (signature.size() <= sizeof(this->signature))) {
|
||||||
this->signature = m_signature.data();
|
Utils::copy(this->signature, signature.data(), signature.size());
|
||||||
this->signatureSize = (unsigned int)m_signature.size();
|
this->signatureSize = (unsigned int)signature.size();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this->maxPathLength = (unsigned int)d.getUI("l");
|
||||||
|
|
||||||
const Vector< uint8_t > enc(encode(true));
|
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());
|
||||||
|
|
||||||
return true;
|
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);
|
if ((!issuerPrivateKey) || (issuerPrivateKeySize == 0))
|
||||||
m_identities.front().erasePrivateKey();
|
return false;
|
||||||
this->issuer = reinterpret_cast<const ZT_Identity *>(&(m_identities.front()));
|
|
||||||
|
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));
|
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];
|
ECC384ECDSASign(reinterpret_cast<const uint8_t *>(issuerPrivateKey) + 1 + ZT_ECC384_PUBLIC_KEY_SIZE, this->serialNo, this->signature);
|
||||||
const unsigned int sigSize = issuer.sign(enc.data(), (unsigned int)enc.size(), sig, ZT_SIGNATURE_BUFFER_SIZE);
|
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;
|
return true;
|
||||||
}
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
m_signature.clear();
|
|
||||||
this->signature = nullptr;
|
|
||||||
this->signatureSize = 0;
|
|
||||||
return false;
|
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;
|
return ZT_CERTIFICATE_ERROR_OUT_OF_VALID_TIME_WINDOW;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this->issuer) {
|
|
||||||
if (checkSignatures) {
|
if (checkSignatures) {
|
||||||
const Vector< uint8_t > enc(encode(true));
|
// Signature check fails if main signature is not present or invalid.
|
||||||
if (!reinterpret_cast<const Identity *>(this->issuer)->verify(enc.data(), (unsigned int)enc.size(), this->signature, this->signatureSize))
|
// 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;
|
return ZT_CERTIFICATE_ERROR_INVALID_PRIMARY_SIGNATURE;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
return ZT_CERTIFICATE_ERROR_INVALID_PRIMARY_SIGNATURE;
|
return ZT_CERTIFICATE_ERROR_INVALID_PRIMARY_SIGNATURE;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this->subject.uniqueIdProofSignatureSize > 0) {
|
// Subject unique ID signatures are optional, so this only fails if it
|
||||||
if (
|
// is present and invalid. A unique ID with type ALGORITHM_NONE is also
|
||||||
(this->subject.uniqueIdProofSignatureSize != ZT_ECC384_SIGNATURE_SIZE) ||
|
// allowed, but this means its signature is not checked.
|
||||||
(this->subject.uniqueIdSize != ZT_CERTIFICATE_UNIQUE_ID_TYPE_NIST_P_384_SIZE) ||
|
if (this->subject.uniqueIdSize > 0) {
|
||||||
(this->subject.uniqueId[0] != ZT_CERTIFICATE_UNIQUE_ID_TYPE_NIST_P_384))
|
if (this->subject.uniqueIdSize <= (unsigned int)sizeof(this->subject.uniqueId)) {
|
||||||
return ZT_CERTIFICATE_ERROR_INVALID_UNIQUE_ID_PROOF;
|
switch (this->subject.uniqueId[0]) {
|
||||||
|
case ZT_CERTIFICATE_PUBLIC_KEY_ALGORITHM_NONE:
|
||||||
if (checkSignatures) {
|
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;
|
Dictionary d;
|
||||||
m_encodeSubject(this->subject, d, true);
|
m_encodeSubject(this->subject, d, true);
|
||||||
|
|
||||||
Vector< uint8_t > enc;
|
Vector< uint8_t > enc;
|
||||||
|
enc.reserve(1024);
|
||||||
d.encode(enc);
|
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];
|
uint8_t h[ZT_SHA384_DIGEST_SIZE];
|
||||||
SHA384(h, enc.data(), (unsigned int)enc.size());
|
SHA384(h, enc.data(), (unsigned int)enc.size());
|
||||||
static_assert(ZT_CERTIFICATE_UNIQUE_ID_TYPE_NIST_P_384_SIZE == (ZT_ECC384_PUBLIC_KEY_SIZE + 1), "incorrect size");
|
|
||||||
if (!ECC384ECDSAVerify(this->subject.uniqueId + 1, h, this->subject.uniqueIdProofSignature))
|
if (!ECC384ECDSAVerify(this->subject.uniqueId + 1, h, this->subject.uniqueIdSignature)) {
|
||||||
return ZT_CERTIFICATE_ERROR_INVALID_UNIQUE_ID_PROOF;
|
return ZT_CERTIFICATE_ERROR_INVALID_UNIQUE_ID_PROOF;
|
||||||
}
|
}
|
||||||
} else if (this->subject.uniqueIdSize > 0) {
|
} else {
|
||||||
return ZT_CERTIFICATE_ERROR_INVALID_UNIQUE_ID_PROOF;
|
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) {
|
for (unsigned int i = 0; i < this->subject.identityCount; ++i) {
|
||||||
if (!this->subject.identities[i].identity)
|
if (!this->subject.identities[i].identity)
|
||||||
return ZT_CERTIFICATE_ERROR_MISSING_REQUIRED_FIELDS;
|
return ZT_CERTIFICATE_ERROR_MISSING_REQUIRED_FIELDS;
|
||||||
if (checkSignatures) {
|
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;
|
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;
|
return ZT_CERTIFICATE_ERROR_INVALID_COMPONENT_SIGNATURE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (unsigned int i = 0; i < this->subject.networkCount; ++i) {
|
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;
|
return ZT_CERTIFICATE_ERROR_MISSING_REQUIRED_FIELDS;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (this->subject.updateURLCount > 0) {
|
if (this->subject.updateURLCount > 0) {
|
||||||
if (!this->subject.updateURLs)
|
if (!this->subject.updateURLs) {
|
||||||
return ZT_CERTIFICATE_ERROR_MISSING_REQUIRED_FIELDS;
|
return ZT_CERTIFICATE_ERROR_MISSING_REQUIRED_FIELDS;
|
||||||
|
}
|
||||||
for (unsigned int i = 0; i < this->subject.updateURLCount; ++i) {
|
for (unsigned int i = 0; i < this->subject.updateURLCount; ++i) {
|
||||||
if (!this->subject.updateURLs[i])
|
if (!this->subject.updateURLs[i])
|
||||||
return ZT_CERTIFICATE_ERROR_MISSING_REQUIRED_FIELDS;
|
return ZT_CERTIFICATE_ERROR_MISSING_REQUIRED_FIELDS;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (...) {}
|
} catch (...) {
|
||||||
|
return ZT_CERTIFICATE_ERROR_INVALID_FORMAT;
|
||||||
|
}
|
||||||
|
|
||||||
return ZT_CERTIFICATE_ERROR_NONE;
|
return ZT_CERTIFICATE_ERROR_NONE;
|
||||||
}
|
}
|
||||||
|
|
||||||
Vector< uint8_t > Certificate::createCSR(const ZT_Certificate_Subject &s, const void *uniqueId, unsigned int uniqueIdSize, const void *uniqueIdPrivate, unsigned int uniqueIdPrivateSize)
|
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;
|
ZT_Certificate_Subject sc;
|
||||||
Utils::copy< sizeof(ZT_Certificate_Subject) >(&sc, &s);
|
Utils::copy< sizeof(ZT_Certificate_Subject) >(&sc, &s);
|
||||||
|
|
||||||
if ((uniqueId) && (uniqueIdSize > 0) && (uniqueIdPrivate) && (uniqueIdPrivateSize > 0)) {
|
if (m_setSubjectUniqueId(sc, uniqueIdPrivate, uniqueIdPrivateSize)) {
|
||||||
sc.uniqueId = reinterpret_cast<const uint8_t *>(uniqueId);
|
|
||||||
sc.uniqueIdSize = uniqueIdSize;
|
|
||||||
} else {
|
|
||||||
sc.uniqueId = nullptr;
|
|
||||||
sc.uniqueIdSize = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
Dictionary d;
|
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);
|
m_encodeSubject(sc, d, false);
|
||||||
|
if (certificatePublicKeySize > 0)
|
||||||
|
d.add("pK", certificatePublicKey, certificatePublicKeySize);
|
||||||
d.encode(enc);
|
d.encode(enc);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
return enc;
|
return enc;
|
||||||
}
|
}
|
||||||
|
@ -574,9 +536,35 @@ void Certificate::m_clear()
|
||||||
m_updateUrls.clear();
|
m_updateUrls.clear();
|
||||||
m_subjectCertificates.clear();
|
m_subjectCertificates.clear();
|
||||||
m_extendedAttributes.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)
|
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])
|
if (s.name.host[0])
|
||||||
d.add("s.n.h", s.name.host);
|
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);
|
d["s.uI"].assign(s.uniqueId, s.uniqueId + s.uniqueIdSize);
|
||||||
if ((!omitUniqueIdProofSignature) && (s.uniqueIdProofSignature) && (s.uniqueIdProofSignatureSize > 0))
|
if ((!omitUniqueIdProofSignature) && (s.uniqueIdSignatureSize > 0))
|
||||||
d["s.uS"].assign(s.uniqueIdProofSignature, s.uniqueIdProofSignature + s.uniqueIdProofSignatureSize);
|
d["s.uS"].assign(s.uniqueIdSignature, s.uniqueIdSignature + s.uniqueIdSignatureSize);
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace ZeroTier
|
} // namespace ZeroTier
|
||||||
|
|
|
@ -106,22 +106,17 @@ public:
|
||||||
void addSubjectUpdateUrl(const char *url);
|
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);
|
ZT_INLINE bool setSubjectUniqueId(const void *uniqueIdPrivate, unsigned int uniqueIdPrivateSize)
|
||||||
|
{ return m_setSubjectUniqueId(this->subject, uniqueIdPrivate, uniqueIdPrivateSize); }
|
||||||
/**
|
|
||||||
* 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
|
||||||
|
@ -144,12 +139,13 @@ public:
|
||||||
bool decode(const void *data, unsigned int len);
|
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
|
* @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
|
* Verify self-contained signatures and validity of certificate structure
|
||||||
|
@ -163,29 +159,29 @@ public:
|
||||||
*/
|
*/
|
||||||
ZT_CertificateError verify(int64_t clock, bool checkSignatures) const;
|
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
|
* Create a CSR that encodes the subject of this certificate
|
||||||
*
|
*
|
||||||
* @param s Subject to encode
|
* @param s Subject to encode
|
||||||
* @param uniqueId Unique ID to sign subject with or NULL if none
|
* @param certificatePublicKey Public key for certificate
|
||||||
* @param uniqueIdSize Size of unique ID or 0 if none
|
* @param certificatePublicKeySize Size of public key
|
||||||
* @param uniqueIdPrivate Unique ID private key for proof signature or NULL if none
|
* @param uniqueIdPrivate Unique ID private key for proof signature or NULL if none
|
||||||
* @param uniqueIdPrivateSize Size of unique ID private key
|
* @param uniqueIdPrivateSize Size of unique ID private key
|
||||||
* @return Encoded subject (without any unique ID fields) or empty vector on error
|
* @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);
|
static Vector< uint8_t > createCSR(const ZT_Certificate_Subject &s, const void *certificatePublicKey, unsigned int certificatePublicKeySize, 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);
|
|
||||||
}
|
|
||||||
|
|
||||||
ZT_INLINE unsigned long hashCode() const noexcept
|
ZT_INLINE unsigned long hashCode() const noexcept
|
||||||
{ return (unsigned long)Utils::loadMachineEndian< uint32_t >(this->serialNo); }
|
{ return (unsigned long)Utils::loadMachineEndian< uint32_t >(this->serialNo); }
|
||||||
|
@ -210,7 +206,7 @@ public:
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void m_clear();
|
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);
|
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
|
// 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 uint8_t * > m_subjectCertificates;
|
||||||
Vector< const char * > m_updateUrls;
|
Vector< const char * > m_updateUrls;
|
||||||
Vector< uint8_t > m_extendedAttributes;
|
Vector< uint8_t > m_extendedAttributes;
|
||||||
Vector< uint8_t > m_subjectUniqueId;
|
|
||||||
Vector< uint8_t > m_subjectUniqueIdProofSignature;
|
|
||||||
Vector< uint8_t > m_signature;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace ZeroTier
|
} // namespace ZeroTier
|
||||||
|
|
|
@ -198,7 +198,7 @@ struct Blob
|
||||||
|
|
||||||
explicit ZT_INLINE Blob(const void *const d, const unsigned int l) noexcept
|
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) {
|
if (l < S) {
|
||||||
Utils::zero(data + l, S - l);
|
Utils::zero(data + l, S - l);
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,8 +16,9 @@
|
||||||
namespace ZeroTier {
|
namespace ZeroTier {
|
||||||
namespace Defaults {
|
namespace Defaults {
|
||||||
|
|
||||||
const unsigned int CERTIFICATES_BYTES = 0;
|
const uint8_t *CERTIFICATE[DEFAULT_CERTIFICATE_COUNT] = {};
|
||||||
const uint8_t CERTIFICATES[4] = {0,0,0,0};
|
|
||||||
|
unsigned int CERTIFICATE_SIZE[DEFAULT_CERTIFICATE_COUNT] = {};
|
||||||
|
|
||||||
} // namespace Defaults
|
} // namespace Defaults
|
||||||
} // namespace ZeroTier
|
} // namespace ZeroTier
|
||||||
|
|
|
@ -19,8 +19,10 @@
|
||||||
namespace ZeroTier {
|
namespace ZeroTier {
|
||||||
namespace Defaults {
|
namespace Defaults {
|
||||||
|
|
||||||
extern const unsigned int CERTIFICATES_BYTES;
|
#define DEFAULT_CERTIFICATE_COUNT 0
|
||||||
extern const uint8_t CERTIFICATES[];
|
|
||||||
|
extern const uint8_t *CERTIFICATE[DEFAULT_CERTIFICATE_COUNT];
|
||||||
|
extern unsigned int CERTIFICATE_SIZE[DEFAULT_CERTIFICATE_COUNT];
|
||||||
|
|
||||||
} // namespace Defaults
|
} // namespace Defaults
|
||||||
} // namespace ZeroTier
|
} // namespace ZeroTier
|
||||||
|
|
|
@ -54,7 +54,8 @@ public:
|
||||||
ZT_INLINE void set(T *ptr) noexcept
|
ZT_INLINE void set(T *ptr) noexcept
|
||||||
{
|
{
|
||||||
m_release();
|
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
|
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;
|
delete m_ptr;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
T *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.networkCount != b.subject.networkCount) ||
|
||||||
(a.subject.updateURLCount != b.subject.updateURLCount) ||
|
(a.subject.updateURLCount != b.subject.updateURLCount) ||
|
||||||
(a.subject.uniqueIdSize != b.subject.uniqueIdSize) ||
|
(a.subject.uniqueIdSize != b.subject.uniqueIdSize) ||
|
||||||
(a.subject.uniqueIdProofSignatureSize != b.subject.uniqueIdProofSignatureSize) ||
|
(a.subject.uniqueIdSignatureSize != b.subject.uniqueIdSignatureSize) ||
|
||||||
(a.maxPathLength != b.maxPathLength) ||
|
(a.maxPathLength != b.maxPathLength) ||
|
||||||
(a.signatureSize != b.signatureSize)
|
(a.signatureSize != b.signatureSize)
|
||||||
)
|
)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if ((a.subject.uniqueId == nullptr) != (b.subject.uniqueId == nullptr))
|
|
||||||
return false;
|
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))
|
||||||
if ((a.subject.uniqueIdProofSignature == nullptr) != (b.subject.uniqueIdProofSignature == nullptr))
|
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if ((a.subject.uniqueId != nullptr) && (a.subject.uniqueIdProofSignature != nullptr)) {
|
if (!ZTT_deepCompareCertificateName(a.subject.name, b.subject.name))
|
||||||
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)))
|
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if ((a.issuer == nullptr) != (b.issuer == nullptr))
|
if (memcmp(a.issuer, b.issuer, ZT_CERTIFICATE_HASH_SIZE) != 0)
|
||||||
return false;
|
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;
|
return false;
|
||||||
|
|
||||||
for (unsigned int i = 0; i < a.subject.identityCount; ++i) {
|
for (unsigned int i = 0; i < a.subject.identityCount; ++i) {
|
||||||
|
@ -655,7 +648,7 @@ extern "C" const char *ZTT_general()
|
||||||
}
|
}
|
||||||
bufs.clear();
|
bufs.clear();
|
||||||
if (Buf::poolAllocated() != ZT_BUF_MAX_POOL_SIZE) {
|
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";
|
return "Buf memory pool test failed";
|
||||||
}
|
}
|
||||||
Buf::freePool();
|
Buf::freePool();
|
||||||
|
@ -1195,19 +1188,24 @@ extern "C" const char *ZTT_crypto()
|
||||||
|
|
||||||
{
|
{
|
||||||
char tmp[256];
|
char tmp[256];
|
||||||
|
uint8_t fakeIssuer[48];
|
||||||
|
Utils::getSecureRandom(fakeIssuer, sizeof(fakeIssuer));
|
||||||
|
|
||||||
ZT_T_PRINTF("[crypto] Testing Certificate..." ZT_EOL_S);
|
ZT_T_PRINTF("[crypto] Testing Certificate..." ZT_EOL_S);
|
||||||
|
|
||||||
ZT_T_PRINTF(" Create test subject and issuer identities... ");
|
ZT_T_PRINTF(" Create test identities... ");
|
||||||
Identity testSubjectId, testIssuerId;
|
Identity testSubjectId;
|
||||||
testSubjectId.generate(Identity::C25519);
|
testSubjectId.generate(Identity::C25519);
|
||||||
testIssuerId.generate(Identity::P384);
|
|
||||||
ZT_T_PRINTF("OK" ZT_EOL_S);
|
ZT_T_PRINTF("OK" ZT_EOL_S);
|
||||||
|
|
||||||
ZT_T_PRINTF(" Create subject unique ID... ");
|
ZT_T_PRINTF(" Create subject unique ID key pair... ");
|
||||||
uint8_t uniqueId[ZT_CERTIFICATE_UNIQUE_ID_TYPE_NIST_P_384_SIZE], uniqueIdPrivate[ZT_CERTIFICATE_UNIQUE_ID_TYPE_NIST_P_384_PRIVATE_SIZE];
|
uint8_t uniqueId[ZT_CERTIFICATE_MAX_PUBLIC_KEY_SIZE], uniqueIdPrivate[ZT_CERTIFICATE_MAX_PRIVATE_KEY_SIZE];
|
||||||
Certificate::createSubjectUniqueId(uniqueId, uniqueIdPrivate);
|
int uniqueIdSize = 0, uniqueIdPrivateKeySize = 0;
|
||||||
Utils::b32e(uniqueId, ZT_CERTIFICATE_UNIQUE_ID_TYPE_NIST_P_384_SIZE, tmp, sizeof(tmp));
|
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("OK %s" ZT_EOL_S, tmp);
|
||||||
|
|
||||||
ZT_T_PRINTF(" Create and sign certificate... ");
|
ZT_T_PRINTF(" Create and sign certificate... ");
|
||||||
|
@ -1231,9 +1229,15 @@ extern "C" const char *ZTT_crypto()
|
||||||
cert->timestamp = cert->subject.timestamp;
|
cert->timestamp = cert->subject.timestamp;
|
||||||
cert->validity[0] = 0;
|
cert->validity[0] = 0;
|
||||||
cert->validity[1] = 9223372036854775807LL;
|
cert->validity[1] = 9223372036854775807LL;
|
||||||
Utils::copy< sizeof(ZT_Certificate_Name) >(&cert->issuerName, &cert->subject.name);
|
uint8_t issuerPrivateKey[ZT_CERTIFICATE_MAX_PRIVATE_KEY_SIZE], certPrivateKey[ZT_CERTIFICATE_MAX_PRIVATE_KEY_SIZE];
|
||||||
cert->setSubjectUniqueId(uniqueId, uniqueIdPrivate);
|
int issuerPrivateKeySize = 0, certPrivateKeySize = 0;
|
||||||
cert->sign(testIssuerId);
|
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());
|
Vector< uint8_t > enc(cert->encode());
|
||||||
ZT_T_PRINTF("OK (%d bytes)" ZT_EOL_S, (int)enc.size());
|
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
|
SharedPtr< TrustStore::Entry > TrustStore::get(const H384 &serial) const
|
||||||
{
|
{
|
||||||
RWMutex::RLock l(m_lock);
|
RWMutex::RLock l(m_lock);
|
||||||
Map< H384, SharedPtr< Entry > >::const_iterator i(m_bySerial.find(serial));
|
Map< H384, SharedPtr< Entry > >::const_iterator c(m_bySerial.find(serial));
|
||||||
return (i != m_bySerial.end()) ? i->second : SharedPtr< TrustStore::Entry >();
|
return (c != m_bySerial.end()) ? c->second : SharedPtr< TrustStore::Entry >();
|
||||||
}
|
}
|
||||||
|
|
||||||
Map< Identity, SharedPtr< const Locator > > TrustStore::roots()
|
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);
|
RWMutex::RLock l(m_lock);
|
||||||
Vector< SharedPtr< Entry > > r;
|
Vector< SharedPtr< Entry > > r;
|
||||||
r.reserve(m_bySerial.size());
|
r.reserve(m_bySerial.size());
|
||||||
for (Map< H384, SharedPtr< Entry > >::const_iterator i(m_bySerial.begin()); i != m_bySerial.end(); ++i) {
|
for (Map< H384, SharedPtr< Entry > >::const_iterator c(m_bySerial.begin()); c != m_bySerial.end(); ++c) {
|
||||||
if ((includeRejectedCertificates) || (i->second->error() == ZT_CERTIFICATE_ERROR_NONE))
|
if ((includeRejectedCertificates) || (c->second->error() == ZT_CERTIFICATE_ERROR_NONE))
|
||||||
r.push_back(i->second);
|
r.push_back(c->second);
|
||||||
}
|
}
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
@ -75,25 +75,6 @@ void TrustStore::erase(const H384 &serial)
|
||||||
m_deleteQueue.push_front(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)
|
bool TrustStore::update(const int64_t clock, Vector< SharedPtr< Entry > > *const purge)
|
||||||
{
|
{
|
||||||
RWMutex::Lock l(m_lock);
|
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;
|
Map< H384, Vector< SharedPtr< Entry > > > bySignedCert;
|
||||||
for (;;) {
|
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.
|
// 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 (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);
|
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
|
// Populate mapping of subject unique IDs to certificates and reject any certificates
|
||||||
// that have been superseded by newly issued certificates with the same subject.
|
// 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();) {
|
for (Map< H384, SharedPtr< Entry > >::const_iterator c(m_bySerial.begin()); c != m_bySerial.end();) {
|
||||||
if (c->second->error() == ZT_CERTIFICATE_ERROR_NONE) {
|
if (c->second->error() == ZT_CERTIFICATE_ERROR_NONE) {
|
||||||
const unsigned int uniqueIdSize = c->second->m_certificate.subject.uniqueIdSize;
|
const unsigned int uniqueIdSize = c->second->m_certificate.subject.uniqueIdSize;
|
||||||
if ((uniqueIdSize > 0) && (uniqueIdSize <= ZT_CERTIFICATE_UNIQUE_ID_TYPE_NIST_P_384_SIZE)) {
|
if ((uniqueIdSize > 0) && (uniqueIdSize <= ZT_CERTIFICATE_MAX_PUBLIC_KEY_SIZE)) {
|
||||||
SharedPtr< Entry > ¤t = m_bySubjectUniqueId[Blob< ZT_CERTIFICATE_UNIQUE_ID_TYPE_NIST_P_384_SIZE >(c->second->m_certificate.subject.uniqueId, uniqueIdSize)];
|
SharedPtr< Entry > ¤t = m_bySubjectUniqueId[Blob< ZT_CERTIFICATE_MAX_PUBLIC_KEY_SIZE >(c->second->m_certificate.subject.uniqueId, uniqueIdSize)];
|
||||||
if (current) {
|
if (current) {
|
||||||
exitLoop = false;
|
exitLoop = false;
|
||||||
if (c->second->m_certificate.subject.timestamp > current->m_certificate.subject.timestamp) {
|
if (c->second->m_certificate.subject.timestamp > current->m_certificate.subject.timestamp) {
|
||||||
|
|
|
@ -178,7 +178,7 @@ public:
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Map< H384, SharedPtr< Entry > > m_bySerial; // all certificates
|
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
|
Map< Fingerprint, Vector< SharedPtr< Entry > > > m_bySubjectIdentity; // non-rejected certificates only
|
||||||
ForwardList< SharedPtr< Entry > > m_addQueue;
|
ForwardList< SharedPtr< Entry > > m_addQueue;
|
||||||
ForwardList< H384 > m_deleteQueue;
|
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
|
#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.
|
* 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
|
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.
|
* Information about a real world entity.
|
||||||
*
|
*
|
||||||
|
@ -447,7 +462,7 @@ typedef struct
|
||||||
const ZT_Identity *identity;
|
const ZT_Identity *identity;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Locator, or NULL if none
|
* Locator (NULL if no locator included)
|
||||||
*/
|
*/
|
||||||
const ZT_Locator *locator;
|
const ZT_Locator *locator;
|
||||||
} ZT_Certificate_Identity;
|
} ZT_Certificate_Identity;
|
||||||
|
@ -526,28 +541,15 @@ typedef struct
|
||||||
/**
|
/**
|
||||||
* Globally unique ID for this subject
|
* Globally unique ID for this subject
|
||||||
*
|
*
|
||||||
* Unique IDs are actually public keys. Their size makes them globally
|
* This is actually a public key and is generated the same way as a normal
|
||||||
* unique (if generated from good randomness) to within ridiculous
|
* certificate public key.
|
||||||
* 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.
|
|
||||||
*/
|
*/
|
||||||
const uint8_t *uniqueId;
|
uint8_t uniqueId[ZT_CERTIFICATE_MAX_PUBLIC_KEY_SIZE];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Signature proving ownership of unique ID.
|
* 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.
|
* Size of unique ID in bytes or 0 if none.
|
||||||
|
@ -557,7 +559,7 @@ typedef struct
|
||||||
/**
|
/**
|
||||||
* Proof signature size or 0 if none.
|
* Proof signature size or 0 if none.
|
||||||
*/
|
*/
|
||||||
unsigned int uniqueIdProofSignatureSize;
|
unsigned int uniqueIdSignatureSize;
|
||||||
} ZT_Certificate_Subject;
|
} ZT_Certificate_Subject;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -573,9 +575,9 @@ typedef struct
|
||||||
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.
|
* Flags indicating certificate usage and any other attributes.
|
||||||
|
@ -598,14 +600,29 @@ typedef struct
|
||||||
ZT_Certificate_Subject subject;
|
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)
|
* Extended attributes set by issuer (in Dictionary format, NULL if none)
|
||||||
|
@ -617,6 +634,16 @@ typedef struct
|
||||||
*/
|
*/
|
||||||
unsigned int extendedAttributesSize;
|
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.
|
* Maximum path length from this certificate toward further certificates.
|
||||||
*
|
*
|
||||||
|
@ -625,16 +652,6 @@ typedef struct
|
||||||
* may be signed (not a CA).
|
* may be signed (not a CA).
|
||||||
*/
|
*/
|
||||||
unsigned int maxPathLength;
|
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;
|
} 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 type Type to create
|
||||||
* @param uniqueId Unique ID buffer
|
* @param publicKey Public key buffer
|
||||||
* @param uniqueIdSize Value/result: size of buffer
|
* @param publicKeySize Result parameter: set to size of public key
|
||||||
* @param uniqueIdPrivate Unique ID private key buffer
|
* @param privateKey Private key buffer
|
||||||
* @param uniqueIdPrivateSize Value/result: size of buffer
|
* @param privateKeySize Result parameter: set to size of private key
|
||||||
* @return OK (0) or error
|
* @return OK (0) or error
|
||||||
*/
|
*/
|
||||||
ZT_SDK_API int ZT_Certificate_newSubjectUniqueId(
|
ZT_SDK_API int ZT_Certificate_newKeyPair(
|
||||||
enum ZT_CertificateUniqueIdType type,
|
enum ZT_CertificatePublicKeyAlgorithm type,
|
||||||
void *uniqueId,
|
uint8_t publicKey[ZT_CERTIFICATE_MAX_PUBLIC_KEY_SIZE],
|
||||||
int *uniqueIdSize,
|
int *const publicKeySize,
|
||||||
void *uniqueIdPrivate,
|
uint8_t privateKey[ZT_CERTIFICATE_MAX_PRIVATE_KEY_SIZE],
|
||||||
int *uniqueIdPrivateSize);
|
int *const privateKeySize);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a new certificate signing request (CSR)
|
* Create a new certificate signing request (CSR)
|
||||||
|
@ -2784,20 +2802,20 @@ ZT_SDK_API int ZT_Certificate_newSubjectUniqueId(
|
||||||
* supplied subject, these will be ignored.
|
* supplied subject, these will be ignored.
|
||||||
*
|
*
|
||||||
* @param subject Subject filled in with fields for CSR
|
* @param subject Subject filled in with fields for CSR
|
||||||
* @param uniqueId Unique ID or NULL if none
|
* @param certificatePublicKey Public key for new certificate
|
||||||
* @param uniqueIdSize Size of unique ID
|
* @param certificatePublicKeySize Public key size in bytes
|
||||||
* @param uniqueIdPrivate Unique ID private key or NULL if none
|
* @param uniqueIdPrivateKey Unique ID private key or NULL if none
|
||||||
* @param uniqueIdPrivateSize Size of unique ID private key
|
* @param uniqueIdPrivateKeySize Size of unique ID private key
|
||||||
* @param csr Buffer to hold CSR (recommended size: 16384 bytes)
|
* @param csr Buffer to hold CSR (recommended size: 16384 bytes)
|
||||||
* @param csrSize Value/result: size of buffer
|
* @param csrSize Value/result: size of buffer
|
||||||
* @return OK (0) or error
|
* @return OK (0) or error
|
||||||
*/
|
*/
|
||||||
ZT_SDK_API int ZT_Certificate_newCSR(
|
ZT_SDK_API int ZT_Certificate_newCSR(
|
||||||
const ZT_Certificate_Subject *subject,
|
const ZT_Certificate_Subject *subject,
|
||||||
const void *uniqueId,
|
const void *certificatePublicKey,
|
||||||
int uniqueIdSize,
|
int certificatePublicKeySize,
|
||||||
const void *uniqueIdPrivate,
|
const void *uniqueIdPrivateKey,
|
||||||
int uniqueIdPrivateSize,
|
int uniqueIdPrivateKeySize,
|
||||||
void *csr,
|
void *csr,
|
||||||
int *csrSize);
|
int *csrSize);
|
||||||
|
|
||||||
|
@ -2808,17 +2826,19 @@ ZT_SDK_API int ZT_Certificate_newCSR(
|
||||||
* certificate fields before signing. Things outside the subject are
|
* certificate fields before signing. Things outside the subject are
|
||||||
* filled in (or can be modified) by the signer.
|
* 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 cert Certificate to sign
|
||||||
* @param signer Signer identity (must contain secret key)
|
* @param issuer Serial number of issuer certificate
|
||||||
* @param signedCert Signed certificate buffer (recommended size: 16384 bytes)
|
* @param issuerPrivateKey Private key of issuer (also includes public)
|
||||||
* @param signedCertSize Value/result: size of buffer
|
* @param issuerPrivateKeySize Size of private key in bytes
|
||||||
* @return OK (0) or error
|
* @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_Certificate *cert,
|
||||||
const ZT_Identity *signer,
|
const uint8_t issuer[ZT_CERTIFICATE_HASH_SIZE],
|
||||||
void *signedCert,
|
const void *issuerPrivateKey,
|
||||||
int *signedCertSize);
|
int issuerPrivateKeySize);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Decode a certificate or CSR
|
* Decode a certificate or CSR
|
||||||
|
|
|
@ -20,11 +20,11 @@ fn new_(cli_args: &ArgMatches) -> i32 {
|
||||||
if ts.is_empty() {
|
if ts.is_empty() {
|
||||||
0_i64
|
0_i64
|
||||||
} else {
|
} 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 {
|
if revision < 0 {
|
||||||
println!("ERROR: invalid or empty timestamp specified.");
|
println!("ERROR: invalid revision (must be >= 0).");
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -111,7 +111,7 @@ Advanced Operations:
|
||||||
|
|
||||||
locator <command> [args]
|
locator <command> [args]
|
||||||
new [-...] <identity> <endpoint> [...] Create new signed locator
|
new [-...] <identity> <endpoint> [...] Create new signed locator
|
||||||
-r <revision> Revision number
|
-r <revision> Revision number (default: time)
|
||||||
verify <identity> <locator> Verify locator signature
|
verify <identity> <locator> Verify locator signature
|
||||||
show <locator> Show contents of a locator
|
show <locator> Show contents of a locator
|
||||||
|
|
||||||
|
|
Loading…
Add table
Reference in a new issue