mirror of
https://github.com/zerotier/ZeroTierOne.git
synced 2025-04-26 17:03:43 +02:00
Some cleanup, certificate self-signing fixes, test fixes, test full certificate life cycle including CSR.
This commit is contained in:
parent
ec2919ac2e
commit
a8e3cffd16
20 changed files with 2403 additions and 1701 deletions
|
@ -4,72 +4,72 @@ BreakBeforeBraces: Stroustrup
|
|||
IndentWidth: 4
|
||||
TabWidth: 4
|
||||
AlignAfterOpenBracket: AlwaysBreak
|
||||
AlignConsecutiveMacros: 'true'
|
||||
AlignConsecutiveAssignments: 'false'
|
||||
AlignConsecutiveDeclarations: 'false'
|
||||
AlignConsecutiveMacros: Consecutive
|
||||
AlignConsecutiveAssignments: Consecutive
|
||||
AlignConsecutiveDeclarations: None
|
||||
AlignEscapedNewlines: Right
|
||||
AlignOperands: 'true'
|
||||
AlignTrailingComments: 'true'
|
||||
AllowAllArgumentsOnNextLine: 'false'
|
||||
AllowAllConstructorInitializersOnNextLine: 'false'
|
||||
AllowAllParametersOfDeclarationOnNextLine: 'false'
|
||||
AllowShortBlocksOnASingleLine: 'true'
|
||||
AllowShortCaseLabelsOnASingleLine: 'false'
|
||||
AllowShortFunctionsOnASingleLine: None
|
||||
AlignOperands: true
|
||||
AlignTrailingComments: true
|
||||
AllowAllArgumentsOnNextLine: false
|
||||
AllowAllConstructorInitializersOnNextLine: false
|
||||
AllowAllParametersOfDeclarationOnNextLine: false
|
||||
AllowShortBlocksOnASingleLine: Always
|
||||
AllowShortCaseLabelsOnASingleLine: true
|
||||
AllowShortFunctionsOnASingleLine: All
|
||||
AllowShortIfStatementsOnASingleLine: Never
|
||||
AlwaysBreakAfterReturnType: None
|
||||
BinPackArguments: 'false'
|
||||
BinPackParameters: 'false'
|
||||
BinPackArguments: true
|
||||
BinPackParameters: true
|
||||
BreakBeforeBinaryOperators: NonAssignment
|
||||
BreakBeforeTernaryOperators: 'true'
|
||||
BreakBeforeTernaryOperators: true
|
||||
BreakConstructorInitializers: BeforeComma
|
||||
BreakInheritanceList: BeforeComma
|
||||
CompactNamespaces: 'false'
|
||||
ConstructorInitializerAllOnOneLineOrOnePerLine: 'true'
|
||||
ConstructorInitializerIndentWidth: '4'
|
||||
ContinuationIndentWidth: '4'
|
||||
Cpp11BracedListStyle: 'false'
|
||||
FixNamespaceComments: 'true'
|
||||
CompactNamespaces: false
|
||||
ConstructorInitializerAllOnOneLineOrOnePerLine: true
|
||||
ConstructorInitializerIndentWidth: 4
|
||||
ContinuationIndentWidth: 4
|
||||
Cpp11BracedListStyle: false
|
||||
FixNamespaceComments: true
|
||||
IncludeBlocks: Regroup
|
||||
IndentCaseLabels: 'true'
|
||||
IndentCaseLabels: true
|
||||
IndentPPDirectives: None
|
||||
IndentWrappedFunctionNames: 'false'
|
||||
KeepEmptyLinesAtTheStartOfBlocks: 'false'
|
||||
MaxEmptyLinesToKeep: '1'
|
||||
IndentWrappedFunctionNames: false
|
||||
KeepEmptyLinesAtTheStartOfBlocks: false
|
||||
MaxEmptyLinesToKeep: 1
|
||||
NamespaceIndentation: None
|
||||
PointerAlignment: Left
|
||||
ReflowComments: 'true'
|
||||
SortIncludes: 'true'
|
||||
SortUsingDeclarations: 'true'
|
||||
SpaceAfterCStyleCast: 'false'
|
||||
SpaceAfterLogicalNot: 'true'
|
||||
SpaceAfterTemplateKeyword: 'true'
|
||||
SpaceBeforeAssignmentOperators: 'true'
|
||||
SpaceBeforeCpp11BracedList: 'true'
|
||||
SpaceBeforeCtorInitializerColon: 'true'
|
||||
SpaceBeforeInheritanceColon: 'true'
|
||||
PointerAlignment: Right
|
||||
ReflowComments: true
|
||||
SortIncludes: CaseInsensitive
|
||||
SortUsingDeclarations: true
|
||||
SpaceAfterCStyleCast: false
|
||||
SpaceAfterLogicalNot: false
|
||||
SpaceAfterTemplateKeyword: true
|
||||
SpaceBeforeAssignmentOperators: true
|
||||
SpaceBeforeCpp11BracedList: true
|
||||
SpaceBeforeCtorInitializerColon: true
|
||||
SpaceBeforeInheritanceColon: true
|
||||
SpaceBeforeParens: ControlStatements
|
||||
SpaceBeforeRangeBasedForLoopColon: 'true'
|
||||
SpaceInEmptyParentheses: 'false'
|
||||
SpacesBeforeTrailingComments: '3'
|
||||
SpacesInAngles: 'false'
|
||||
SpacesInCStyleCastParentheses: 'false'
|
||||
SpacesInContainerLiterals: 'true'
|
||||
SpacesInParentheses: 'false'
|
||||
SpacesInSquareBrackets: 'false'
|
||||
UseTab: 'false'
|
||||
SpaceBeforeRangeBasedForLoopColon: true
|
||||
SpaceInEmptyParentheses: false
|
||||
SpacesBeforeTrailingComments: 3
|
||||
SpacesInAngles: false
|
||||
SpacesInCStyleCastParentheses: false
|
||||
SpacesInContainerLiterals: true
|
||||
SpacesInParentheses: false
|
||||
SpacesInSquareBrackets: false
|
||||
UseTab: Never
|
||||
|
||||
---
|
||||
Language: Cpp
|
||||
Standard: Cpp03
|
||||
ColumnLimit: '240'
|
||||
Standard: c++11
|
||||
ColumnLimit: 120
|
||||
---
|
||||
Language: ObjC
|
||||
ColumnLimit: '240'
|
||||
ColumnLimit: 120
|
||||
---
|
||||
Language: Java
|
||||
ColumnLimit: '240'
|
||||
ColumnLimit: 120
|
||||
---
|
||||
Language: CSharp
|
||||
ColumnLimit: '240'
|
||||
ColumnLimit: 120
|
||||
...
|
||||
|
|
|
@ -21,25 +21,17 @@ namespace ZeroTier {
|
|||
|
||||
Certificate::Certificate() noexcept
|
||||
{
|
||||
ZT_Certificate* const sup = this;
|
||||
ZT_Certificate *const sup = this;
|
||||
Utils::zero<sizeof(ZT_Certificate)>(sup);
|
||||
}
|
||||
|
||||
Certificate::Certificate(const ZT_Certificate& apiCert) : Certificate()
|
||||
{
|
||||
*this = apiCert;
|
||||
}
|
||||
Certificate::Certificate(const ZT_Certificate &apiCert) : Certificate() { *this = apiCert; }
|
||||
|
||||
Certificate::Certificate(const Certificate& cert) : Certificate()
|
||||
{
|
||||
*this = cert;
|
||||
}
|
||||
Certificate::Certificate(const Certificate &cert) : Certificate() { *this = cert; }
|
||||
|
||||
Certificate::~Certificate()
|
||||
{
|
||||
}
|
||||
Certificate::~Certificate() {}
|
||||
|
||||
Certificate& Certificate::operator=(const ZT_Certificate& cert)
|
||||
Certificate &Certificate::operator=(const ZT_Certificate &cert)
|
||||
{
|
||||
m_clear();
|
||||
|
||||
|
@ -55,10 +47,12 @@ Certificate& Certificate::operator=(const ZT_Certificate& cert)
|
|||
for (unsigned int i = 0; i < cert.subject.identityCount; ++i) {
|
||||
if (cert.subject.identities[i].identity) {
|
||||
if (cert.subject.identities[i].locator) {
|
||||
addSubjectIdentity(*reinterpret_cast<const Identity*>(cert.subject.identities[i].identity), *reinterpret_cast<const Locator*>(cert.subject.identities[i].locator));
|
||||
addSubjectIdentity(
|
||||
*reinterpret_cast<const Identity *>(cert.subject.identities[i].identity),
|
||||
*reinterpret_cast<const Locator *>(cert.subject.identities[i].locator));
|
||||
}
|
||||
else {
|
||||
addSubjectIdentity(*reinterpret_cast<const Identity*>(cert.subject.identities[i].identity));
|
||||
addSubjectIdentity(*reinterpret_cast<const Identity *>(cert.subject.identities[i].identity));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -87,7 +81,8 @@ Certificate& Certificate::operator=(const ZT_Certificate& cert)
|
|||
Utils::copy<sizeof(ZT_Certificate_Name)>(&(this->subject.name), &(cert.subject.name));
|
||||
|
||||
Utils::copy<sizeof(this->subject.uniqueId)>(this->subject.uniqueId, cert.subject.uniqueId);
|
||||
Utils::copy<sizeof(this->subject.uniqueIdSignature)>(this->subject.uniqueIdSignature, cert.subject.uniqueIdSignature);
|
||||
Utils::copy<sizeof(this->subject.uniqueIdSignature)>(
|
||||
this->subject.uniqueIdSignature, cert.subject.uniqueIdSignature);
|
||||
this->subject.uniqueIdSize = cert.subject.uniqueIdSize;
|
||||
this->subject.uniqueIdSignatureSize = cert.subject.uniqueIdSignatureSize;
|
||||
|
||||
|
@ -112,7 +107,7 @@ Certificate& Certificate::operator=(const ZT_Certificate& cert)
|
|||
return *this;
|
||||
}
|
||||
|
||||
ZT_Certificate_Identity* Certificate::addSubjectIdentity(const Identity& id)
|
||||
ZT_Certificate_Identity *Certificate::addSubjectIdentity(const Identity &id)
|
||||
{
|
||||
// Store a local copy of the actual identity.
|
||||
m_identities.push_front(id);
|
||||
|
@ -129,10 +124,10 @@ ZT_Certificate_Identity* Certificate::addSubjectIdentity(const Identity& id)
|
|||
return &(m_subjectIdentities.back());
|
||||
}
|
||||
|
||||
ZT_Certificate_Identity* Certificate::addSubjectIdentity(const Identity& id, const Locator& loc)
|
||||
ZT_Certificate_Identity *Certificate::addSubjectIdentity(const Identity &id, const Locator &loc)
|
||||
{
|
||||
// Add identity as above.
|
||||
ZT_Certificate_Identity* const n = addSubjectIdentity(id);
|
||||
ZT_Certificate_Identity *const n = addSubjectIdentity(id);
|
||||
|
||||
// Store local copy of locator.
|
||||
m_locators.push_front(loc);
|
||||
|
@ -143,7 +138,7 @@ ZT_Certificate_Identity* Certificate::addSubjectIdentity(const Identity& id, con
|
|||
return n;
|
||||
}
|
||||
|
||||
ZT_Certificate_Network* Certificate::addSubjectNetwork(const uint64_t id, const ZT_Fingerprint& controller)
|
||||
ZT_Certificate_Network *Certificate::addSubjectNetwork(const uint64_t id, const ZT_Fingerprint &controller)
|
||||
{
|
||||
// Enlarge array of ZT_Certificate_Network and set pointer to potentially reallocated array.
|
||||
m_subjectNetworks.resize(++this->subject.networkCount);
|
||||
|
@ -156,7 +151,7 @@ ZT_Certificate_Network* Certificate::addSubjectNetwork(const uint64_t id, const
|
|||
return &(m_subjectNetworks.back());
|
||||
}
|
||||
|
||||
void Certificate::addSubjectUpdateUrl(const char* url)
|
||||
void Certificate::addSubjectUpdateUrl(const char *url)
|
||||
{
|
||||
if ((url != nullptr) && (url[0] != 0)) {
|
||||
// Store local copy of URL.
|
||||
|
@ -196,7 +191,7 @@ Vector<uint8_t> Certificate::encode(const bool omitSignature) const
|
|||
|
||||
m_encodeSubject(this->subject, d, false);
|
||||
|
||||
if (! Utils::allZero(this->issuer, sizeof(this->issuer)))
|
||||
if (!Utils::allZero(this->issuer, sizeof(this->issuer)))
|
||||
d.add("i", this->issuer, sizeof(this->issuer));
|
||||
|
||||
if (this->issuerPublicKeySize > 0)
|
||||
|
@ -210,7 +205,7 @@ Vector<uint8_t> Certificate::encode(const bool omitSignature) const
|
|||
if ((this->extendedAttributes != nullptr) && (this->extendedAttributesSize > 0))
|
||||
d["x"].assign(this->extendedAttributes, this->extendedAttributes + this->extendedAttributesSize);
|
||||
|
||||
if ((! omitSignature) && (this->signatureSize > 0))
|
||||
if ((!omitSignature) && (this->signatureSize > 0))
|
||||
d["si"].assign(this->signature, this->signature + this->signatureSize);
|
||||
|
||||
if (this->maxPathLength > 0)
|
||||
|
@ -220,12 +215,12 @@ Vector<uint8_t> Certificate::encode(const bool omitSignature) const
|
|||
return enc;
|
||||
}
|
||||
|
||||
bool Certificate::decode(const void* const data, const unsigned int len)
|
||||
bool Certificate::decode(const void *const data, const unsigned int len)
|
||||
{
|
||||
char tmp[32], tmp2[ZT_CERTIFICATE_MAX_STRING_LENGTH + 1];
|
||||
|
||||
Dictionary d;
|
||||
if (! d.decode(data, len))
|
||||
if (!d.decode(data, len))
|
||||
return false;
|
||||
|
||||
m_clear();
|
||||
|
@ -239,8 +234,8 @@ bool Certificate::decode(const void* const data, const unsigned int len)
|
|||
|
||||
unsigned int cnt = (unsigned int)d.getUI("s.i$");
|
||||
for (unsigned int i = 0; i < cnt; ++i) {
|
||||
const Vector<uint8_t>& identityData = d[Dictionary::arraySubscript(tmp, sizeof(tmp), "s.i$.i", i)];
|
||||
const Vector<uint8_t>& locatorData = d[Dictionary::arraySubscript(tmp, sizeof(tmp), "s.i$.l", i)];
|
||||
const Vector<uint8_t> &identityData = d[Dictionary::arraySubscript(tmp, sizeof(tmp), "s.i$.i", i)];
|
||||
const Vector<uint8_t> &locatorData = d[Dictionary::arraySubscript(tmp, sizeof(tmp), "s.i$.l", i)];
|
||||
if (identityData.empty())
|
||||
return false;
|
||||
Identity id;
|
||||
|
@ -260,7 +255,7 @@ bool Certificate::decode(const void* const data, const unsigned int len)
|
|||
cnt = (unsigned int)d.getUI("s.nw$");
|
||||
for (unsigned int i = 0; i < cnt; ++i) {
|
||||
const uint64_t nwid = d.getUI(Dictionary::arraySubscript(tmp, sizeof(tmp), "s.nw$.i", i));
|
||||
const Vector<uint8_t>& fingerprintData = d[Dictionary::arraySubscript(tmp, sizeof(tmp), "s.nw$.c", i)];
|
||||
const Vector<uint8_t> &fingerprintData = d[Dictionary::arraySubscript(tmp, sizeof(tmp), "s.nw$.c", i)];
|
||||
if ((nwid == 0) || (fingerprintData.empty()))
|
||||
return false;
|
||||
Fingerprint fp;
|
||||
|
@ -286,47 +281,47 @@ 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));
|
||||
|
||||
const Vector<uint8_t>& uniqueId = d["s.uI"];
|
||||
if ((! uniqueId.empty()) && (uniqueId.size() <= sizeof(this->subject.uniqueId))) {
|
||||
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();
|
||||
}
|
||||
const Vector<uint8_t>& uniqueIdSignature = d["s.uS"];
|
||||
if ((! uniqueIdSignature.empty()) && (uniqueIdSignature.size() <= sizeof(this->subject.uniqueIdSignature))) {
|
||||
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"];
|
||||
const Vector<uint8_t> &issuerData = d["i"];
|
||||
if (issuerData.size() == sizeof(this->issuer)) {
|
||||
Utils::copy<sizeof(this->issuer)>(this->issuer, issuerData.data());
|
||||
}
|
||||
|
||||
const Vector<uint8_t>& issuerPublicKey = d["iPK"];
|
||||
if ((! issuerPublicKey.empty()) && (issuerPublicKey.size() <= sizeof(this->issuerPublicKey))) {
|
||||
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))) {
|
||||
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();
|
||||
}
|
||||
const Vector<uint8_t>& subjectSignature = d["sS"];
|
||||
if ((! subjectSignature.empty()) && (subjectSignature.size() <= sizeof(this->subjectSignature))) {
|
||||
const Vector<uint8_t> &subjectSignature = d["sS"];
|
||||
if ((!subjectSignature.empty()) && (subjectSignature.size() <= sizeof(this->subjectSignature))) {
|
||||
Utils::copy(this->subjectSignature, subjectSignature.data(), subjectSignature.size());
|
||||
this->subjectSignatureSize = (unsigned int)subjectSignature.size();
|
||||
}
|
||||
|
||||
m_extendedAttributes = d["x"];
|
||||
if (! m_extendedAttributes.empty()) {
|
||||
if (!m_extendedAttributes.empty()) {
|
||||
this->extendedAttributes = m_extendedAttributes.data();
|
||||
this->extendedAttributesSize = (unsigned int)m_extendedAttributes.size();
|
||||
}
|
||||
|
||||
const Vector<uint8_t>& signature = d["si"];
|
||||
if ((! signature.empty()) && (signature.size() <= sizeof(this->signature))) {
|
||||
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();
|
||||
}
|
||||
|
@ -339,25 +334,37 @@ bool Certificate::decode(const void* const data, const unsigned int len)
|
|||
return true;
|
||||
}
|
||||
|
||||
bool Certificate::sign(const uint8_t issuer[ZT_CERTIFICATE_HASH_SIZE], const void* const issuerPrivateKey, const unsigned int issuerPrivateKeySize)
|
||||
bool Certificate::sign(
|
||||
const uint8_t issuer[ZT_CERTIFICATE_HASH_SIZE], const void *const issuerPrivateKey,
|
||||
const unsigned int issuerPrivateKeySize)
|
||||
{
|
||||
if ((! issuerPrivateKey) || (issuerPrivateKeySize == 0))
|
||||
if ((!issuerPrivateKey) || (issuerPrivateKeySize == 0))
|
||||
return false;
|
||||
|
||||
switch (reinterpret_cast<const uint8_t*>(issuerPrivateKey)[0]) {
|
||||
default:
|
||||
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)) {
|
||||
if ((!issuer)||((this->publicKeySize == (ZT_ECC384_PUBLIC_KEY_SIZE + 1))&&(memcmp(issuerPrivateKey, this->publicKey, ZT_ECC384_PUBLIC_KEY_SIZE + 1) == 0))) {
|
||||
// If public key and issuer public key match, this is a self-signed certificate.
|
||||
// This can also be specified by signing with issuer set to NULL.
|
||||
Utils::fill<sizeof(this->issuer), 0xff>(this->issuer);
|
||||
this->issuerPublicKeySize = 0;
|
||||
} else {
|
||||
// Otherwise set the issuer and issuer public key.
|
||||
Utils::copy<sizeof(this->issuer)>(this->issuer, issuer);
|
||||
Utils::copy<1 + ZT_ECC384_PUBLIC_KEY_SIZE>(this->issuerPublicKey,
|
||||
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());
|
||||
|
||||
ECC384ECDSASign(reinterpret_cast<const uint8_t*>(issuerPrivateKey) + 1 + ZT_ECC384_PUBLIC_KEY_SIZE, this->serialNo, this->signature);
|
||||
ECC384ECDSASign(
|
||||
reinterpret_cast<const uint8_t *>(issuerPrivateKey) + 1 + ZT_ECC384_PUBLIC_KEY_SIZE, this->serialNo,
|
||||
this->signature);
|
||||
this->signatureSize = ZT_ECC384_SIGNATURE_SIZE;
|
||||
|
||||
return true;
|
||||
|
@ -378,14 +385,18 @@ ZT_CertificateError Certificate::verify(const int64_t clock, const bool checkSig
|
|||
if (this->subject.identityCount > 0) {
|
||||
if (this->subject.identities) {
|
||||
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_INVALID_FORMAT;
|
||||
}
|
||||
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) && (! 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;
|
||||
}
|
||||
}
|
||||
|
@ -399,7 +410,7 @@ ZT_CertificateError Certificate::verify(const int64_t clock, const bool checkSig
|
|||
if (this->subject.networkCount > 0) {
|
||||
if (this->subject.networks) {
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
@ -412,7 +423,7 @@ ZT_CertificateError Certificate::verify(const int64_t clock, const bool checkSig
|
|||
if (this->subject.updateURLCount > 0) {
|
||||
if (this->subject.updateURLs) {
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
@ -421,10 +432,14 @@ ZT_CertificateError Certificate::verify(const int64_t clock, const bool checkSig
|
|||
}
|
||||
}
|
||||
|
||||
if ((this->subject.uniqueIdSize > sizeof(this->subject.uniqueId)) || (this->subject.uniqueIdSignatureSize > sizeof(this->subject.uniqueIdSignature)) || (this->issuerPublicKeySize > sizeof(this->issuerPublicKey)) || (this->publicKeySize > sizeof(this->publicKey)) || (this->subjectSignatureSize > sizeof(this->subjectSignature))) {
|
||||
if ((this->subject.uniqueIdSize > sizeof(this->subject.uniqueId))
|
||||
|| (this->subject.uniqueIdSignatureSize > sizeof(this->subject.uniqueIdSignature))
|
||||
|| (this->issuerPublicKeySize > sizeof(this->issuerPublicKey))
|
||||
|| (this->publicKeySize > sizeof(this->publicKey))
|
||||
|| (this->subjectSignatureSize > sizeof(this->subjectSignature))) {
|
||||
return ZT_CERTIFICATE_ERROR_INVALID_FORMAT;
|
||||
}
|
||||
if ((this->extendedAttributesSize > 0) && (! this->extendedAttributes)) {
|
||||
if ((this->extendedAttributesSize > 0) && (!this->extendedAttributes)) {
|
||||
return ZT_CERTIFICATE_ERROR_INVALID_FORMAT;
|
||||
}
|
||||
if (this->signatureSize > sizeof(this->signature)) {
|
||||
|
@ -432,14 +447,28 @@ ZT_CertificateError Certificate::verify(const int64_t clock, const bool checkSig
|
|||
}
|
||||
|
||||
if (checkSignatures) {
|
||||
// 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.
|
||||
Dictionary d;
|
||||
Vector<uint8_t> enc;
|
||||
|
||||
// If the issuer is all 1's (0xffffff...) then this cert is self-signed.
|
||||
bool selfSigned = true;
|
||||
for (unsigned int i = 0; i < ZT_CERTIFICATE_HASH_SIZE; ++i) {
|
||||
if (this->issuer[i] != 0xff) {
|
||||
selfSigned = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!selfSigned) {
|
||||
// Regular certs have an issuer signature and a self-signature
|
||||
// of their subject to ensure CSR integrity.
|
||||
|
||||
if (this->issuerPublicKeySize > 0) {
|
||||
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)) {
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
@ -447,19 +476,13 @@ ZT_CertificateError Certificate::verify(const int64_t clock, const bool checkSig
|
|||
return ZT_CERTIFICATE_ERROR_INVALID_PRIMARY_SIGNATURE;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
return ZT_CERTIFICATE_ERROR_INVALID_PRIMARY_SIGNATURE;
|
||||
default: return ZT_CERTIFICATE_ERROR_INVALID_PRIMARY_SIGNATURE;
|
||||
}
|
||||
}
|
||||
else {
|
||||
return ZT_CERTIFICATE_ERROR_INVALID_PRIMARY_SIGNATURE;
|
||||
}
|
||||
|
||||
Dictionary d;
|
||||
Vector<uint8_t> enc;
|
||||
|
||||
// Check subject signature to verify that CRL was intact and the
|
||||
// public key was the one intended by the CRL creator.
|
||||
if (this->publicKeySize > 0) {
|
||||
d.clear();
|
||||
m_encodeSubject(this->subject, d, false);
|
||||
|
@ -467,10 +490,11 @@ ZT_CertificateError Certificate::verify(const int64_t clock, const bool checkSig
|
|||
|
||||
switch (this->publicKey[0]) {
|
||||
case ZT_CERTIFICATE_PUBLIC_KEY_ALGORITHM_ECDSA_NIST_P_384:
|
||||
if ((this->publicKeySize == (ZT_ECC384_PUBLIC_KEY_SIZE + 1)) && (this->subjectSignatureSize == ZT_ECC384_SIGNATURE_SIZE)) {
|
||||
if ((this->publicKeySize == (ZT_ECC384_PUBLIC_KEY_SIZE + 1))
|
||||
&& (this->subjectSignatureSize == ZT_ECC384_SIGNATURE_SIZE)) {
|
||||
uint8_t h[ZT_SHA384_DIGEST_SIZE];
|
||||
SHA384(h, enc.data(), (unsigned int)enc.size());
|
||||
if (! ECC384ECDSAVerify(this->publicKey + 1, h, this->subjectSignature)) {
|
||||
if (!ECC384ECDSAVerify(this->publicKey + 1, h, this->subjectSignature)) {
|
||||
return ZT_CERTIFICATE_ERROR_INVALID_COMPONENT_SIGNATURE;
|
||||
}
|
||||
}
|
||||
|
@ -478,13 +502,38 @@ ZT_CertificateError Certificate::verify(const int64_t clock, const bool checkSig
|
|||
return ZT_CERTIFICATE_ERROR_INVALID_COMPONENT_SIGNATURE;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
return ZT_CERTIFICATE_ERROR_INVALID_COMPONENT_SIGNATURE;
|
||||
default: return ZT_CERTIFICATE_ERROR_INVALID_COMPONENT_SIGNATURE;
|
||||
}
|
||||
}
|
||||
else {
|
||||
return ZT_CERTIFICATE_ERROR_INVALID_COMPONENT_SIGNATURE;
|
||||
}
|
||||
}
|
||||
else {
|
||||
// Self-signed certs are just signed by their own public keys.
|
||||
// The issuer public key and subject self-signature are ignored
|
||||
// and can be empty.
|
||||
|
||||
if (this->publicKeySize > 0) {
|
||||
switch (this->publicKey[0]) {
|
||||
case ZT_CERTIFICATE_PUBLIC_KEY_ALGORITHM_ECDSA_NIST_P_384:
|
||||
if ((this->publicKeySize == (ZT_ECC384_PUBLIC_KEY_SIZE + 1))
|
||||
&& (this->signatureSize == ZT_ECC384_SIGNATURE_SIZE)) {
|
||||
if (!ECC384ECDSAVerify(this->publicKey + 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;
|
||||
}
|
||||
}
|
||||
|
||||
// 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
|
||||
|
@ -492,19 +541,22 @@ ZT_CertificateError Certificate::verify(const int64_t clock, const bool checkSig
|
|||
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_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)) {
|
||||
if ((this->subject.uniqueIdSize == (ZT_ECC384_PUBLIC_KEY_SIZE + 1))
|
||||
&& (this->subject.uniqueIdSignatureSize == ZT_ECC384_SIGNATURE_SIZE)) {
|
||||
d.clear();
|
||||
m_encodeSubject(this->subject, d, true);
|
||||
d.encode(enc);
|
||||
|
||||
static_assert(ZT_ECC384_SIGNATURE_HASH_SIZE == ZT_SHA384_DIGEST_SIZE, "ECC384 should take 384-bit hash");
|
||||
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());
|
||||
|
||||
if (! ECC384ECDSAVerify(this->subject.uniqueId + 1, h, this->subject.uniqueIdSignature)) {
|
||||
if (!ECC384ECDSAVerify(
|
||||
this->subject.uniqueId + 1, h, this->subject.uniqueIdSignature)) {
|
||||
return ZT_CERTIFICATE_ERROR_INVALID_UNIQUE_ID_PROOF;
|
||||
}
|
||||
}
|
||||
|
@ -512,8 +564,7 @@ ZT_CertificateError Certificate::verify(const int64_t clock, const bool checkSig
|
|||
return ZT_CERTIFICATE_ERROR_INVALID_UNIQUE_ID_PROOF;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
return ZT_CERTIFICATE_ERROR_INVALID_UNIQUE_ID_PROOF;
|
||||
default: return ZT_CERTIFICATE_ERROR_INVALID_UNIQUE_ID_PROOF;
|
||||
}
|
||||
}
|
||||
else {
|
||||
|
@ -523,7 +574,7 @@ ZT_CertificateError Certificate::verify(const int64_t clock, const bool checkSig
|
|||
}
|
||||
|
||||
if (clock >= 0) {
|
||||
if (! this->verifyTimeWindow(clock))
|
||||
if (!this->verifyTimeWindow(clock))
|
||||
return ZT_CERTIFICATE_ERROR_OUT_OF_VALID_TIME_WINDOW;
|
||||
}
|
||||
}
|
||||
|
@ -534,7 +585,9 @@ ZT_CertificateError Certificate::verify(const int64_t clock, const bool checkSig
|
|||
return ZT_CERTIFICATE_ERROR_NONE;
|
||||
}
|
||||
|
||||
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)
|
||||
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:
|
||||
|
@ -544,21 +597,24 @@ bool Certificate::newKeyPair(const ZT_CertificatePublicKeyAlgorithm type, uint8_
|
|||
*publicKeySize = ZT_ECC384_PUBLIC_KEY_SIZE + 1;
|
||||
*privateKeySize = 1 + ZT_ECC384_PUBLIC_KEY_SIZE + ZT_ECC384_PRIVATE_KEY_SIZE;
|
||||
return true;
|
||||
default:
|
||||
break;
|
||||
default: break;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
Vector<uint8_t> Certificate::createCSR(const ZT_Certificate_Subject& s, const void* const certificatePrivateKey, const unsigned int certificatePrivateKeySize, const void* uniqueIdPrivate, unsigned int uniqueIdPrivateSize)
|
||||
Vector<uint8_t> Certificate::createCSR(
|
||||
const ZT_Certificate_Subject &s, const void *const certificatePrivateKey,
|
||||
const unsigned int certificatePrivateKeySize, const void *uniqueIdPrivate, unsigned int uniqueIdPrivateSize)
|
||||
{
|
||||
Vector<uint8_t> enc;
|
||||
|
||||
ZT_Certificate_Subject sc;
|
||||
Utils::copy<sizeof(ZT_Certificate_Subject)>(&sc, &s);
|
||||
|
||||
if ((! certificatePrivateKey) || (certificatePrivateKeySize != (1 + ZT_ECC384_PUBLIC_KEY_SIZE + ZT_ECC384_PRIVATE_KEY_SIZE))
|
||||
|| (reinterpret_cast<const uint8_t*>(certificatePrivateKey)[0] != ZT_CERTIFICATE_PUBLIC_KEY_ALGORITHM_ECDSA_NIST_P_384))
|
||||
if ((!certificatePrivateKey)
|
||||
|| (certificatePrivateKeySize != (1 + ZT_ECC384_PUBLIC_KEY_SIZE + ZT_ECC384_PRIVATE_KEY_SIZE))
|
||||
|| (reinterpret_cast<const uint8_t *>(certificatePrivateKey)[0]
|
||||
!= ZT_CERTIFICATE_PUBLIC_KEY_ALGORITHM_ECDSA_NIST_P_384))
|
||||
return enc;
|
||||
|
||||
if (m_setSubjectUniqueId(sc, uniqueIdPrivate, uniqueIdPrivateSize)) {
|
||||
|
@ -568,9 +624,11 @@ Vector<uint8_t> Certificate::createCSR(const ZT_Certificate_Subject& s, const vo
|
|||
|
||||
uint8_t subjectHash[ZT_SHA384_DIGEST_SIZE], subjectSig[ZT_ECC384_SIGNATURE_SIZE];
|
||||
SHA384(subjectHash, enc.data(), (unsigned int)enc.size());
|
||||
ECC384ECDSASign(reinterpret_cast<const uint8_t*>(certificatePrivateKey) + 1 + ZT_ECC384_PUBLIC_KEY_SIZE, subjectHash, subjectSig);
|
||||
ECC384ECDSASign(
|
||||
reinterpret_cast<const uint8_t *>(certificatePrivateKey) + 1 + ZT_ECC384_PUBLIC_KEY_SIZE, subjectHash,
|
||||
subjectSig);
|
||||
|
||||
d.add("pK", reinterpret_cast<const uint8_t*>(certificatePrivateKey), (1 + ZT_ECC384_PUBLIC_KEY_SIZE));
|
||||
d.add("pK", reinterpret_cast<const uint8_t *>(certificatePrivateKey), (1 + ZT_ECC384_PUBLIC_KEY_SIZE));
|
||||
d.add("sS", subjectSig, ZT_ECC384_SIGNATURE_SIZE);
|
||||
|
||||
d.encode(enc);
|
||||
|
@ -581,7 +639,7 @@ Vector<uint8_t> Certificate::createCSR(const ZT_Certificate_Subject& s, const vo
|
|||
|
||||
void Certificate::m_clear()
|
||||
{
|
||||
ZT_Certificate* const sup = this;
|
||||
ZT_Certificate *const sup = this;
|
||||
Utils::zero<sizeof(ZT_Certificate)>(sup);
|
||||
|
||||
m_identities.clear();
|
||||
|
@ -594,11 +652,14 @@ void Certificate::m_clear()
|
|||
m_extendedAttributes.clear();
|
||||
}
|
||||
|
||||
bool Certificate::m_setSubjectUniqueId(ZT_Certificate_Subject& s, const void* uniqueIdPrivate, unsigned int uniqueIdPrivateSize)
|
||||
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)) {
|
||||
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
|
||||
|
||||
|
@ -610,7 +671,9 @@ bool Certificate::m_setSubjectUniqueId(ZT_Certificate_Subject& s, const void* un
|
|||
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);
|
||||
ECC384ECDSASign(
|
||||
reinterpret_cast<const uint8_t *>(uniqueIdPrivate) + 1 + ZT_ECC384_PUBLIC_KEY_SIZE, h,
|
||||
s.uniqueIdSignature);
|
||||
s.uniqueIdSignatureSize = ZT_ECC384_SIGNATURE_SIZE;
|
||||
}
|
||||
else {
|
||||
|
@ -626,7 +689,7 @@ bool Certificate::m_setSubjectUniqueId(ZT_Certificate_Subject& s, const void* un
|
|||
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)
|
||||
{
|
||||
char tmp[32];
|
||||
|
||||
|
@ -636,9 +699,13 @@ void Certificate::m_encodeSubject(const ZT_Certificate_Subject& s, Dictionary& d
|
|||
d.add("s.i$", (uint64_t)s.identityCount);
|
||||
for (unsigned int i = 0; i < s.identityCount; ++i) {
|
||||
if (s.identities[i].identity)
|
||||
d.addO(Dictionary::arraySubscript(tmp, sizeof(tmp), "s.i$.i", i), *reinterpret_cast<const Identity*>(s.identities[i].identity));
|
||||
d.addO(
|
||||
Dictionary::arraySubscript(tmp, sizeof(tmp), "s.i$.i", i),
|
||||
*reinterpret_cast<const Identity *>(s.identities[i].identity));
|
||||
if (s.identities[i].locator)
|
||||
d.addO(Dictionary::arraySubscript(tmp, sizeof(tmp), "s.i$.l", i), *reinterpret_cast<const Locator*>(s.identities[i].locator));
|
||||
d.addO(
|
||||
Dictionary::arraySubscript(tmp, sizeof(tmp), "s.i$.l", i),
|
||||
*reinterpret_cast<const Locator *>(s.identities[i].locator));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -684,7 +751,7 @@ void Certificate::m_encodeSubject(const ZT_Certificate_Subject& s, Dictionary& d
|
|||
|
||||
if (s.uniqueIdSize > 0)
|
||||
d["s.uI"].assign(s.uniqueId, s.uniqueId + s.uniqueIdSize);
|
||||
if ((! omitUniqueIdProofSignature) && (s.uniqueIdSignatureSize > 0))
|
||||
if ((!omitUniqueIdProofSignature) && (s.uniqueIdSignatureSize > 0))
|
||||
d["s.uS"].assign(s.uniqueIdSignature, s.uniqueIdSignature + s.uniqueIdSignatureSize);
|
||||
}
|
||||
|
||||
|
|
|
@ -61,11 +61,26 @@ class Certificate : public ZT_Certificate {
|
|||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Serial number in a H384 object
|
||||
*/
|
||||
ZT_INLINE H384 getSerialNo() const noexcept
|
||||
{
|
||||
return H384(this->serialNo);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return True if this is a self-signed certificate
|
||||
*/
|
||||
ZT_INLINE bool isSelfSigned() const noexcept
|
||||
{
|
||||
for(unsigned int i=0;i<ZT_CERTIFICATE_HASH_SIZE;++i) {
|
||||
if (this->issuer[i] != 0xff)
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a subject node/identity without a locator
|
||||
*
|
||||
|
|
827
core/ECC384.cpp
827
core/ECC384.cpp
File diff suppressed because it is too large
Load diff
|
@ -65,7 +65,8 @@ void identityV0ProofOfWorkFrankenhash(const void* const restrict c25519CombinedP
|
|||
}
|
||||
}
|
||||
|
||||
struct identityV0ProofOfWorkCriteria {
|
||||
struct identityV0ProofOfWorkCriteria
|
||||
{
|
||||
ZT_INLINE identityV0ProofOfWorkCriteria(unsigned char* restrict sb, char* restrict gm) noexcept
|
||||
: digest(sb)
|
||||
, genmem(gm)
|
||||
|
|
2127
core/Tests.cpp
2127
core/Tests.cpp
File diff suppressed because it is too large
Load diff
|
@ -149,7 +149,15 @@ bool TrustStore::update(const int64_t clock, Vector<SharedPtr<Entry> >* const pu
|
|||
Vector<Entry*> visited;
|
||||
visited.reserve(8);
|
||||
for (Map<H384, SharedPtr<Entry> >::iterator c(m_bySerial.begin()); c != m_bySerial.end(); ++c) {
|
||||
if ((c->second->m_error == ZT_CERTIFICATE_ERROR_NONE) && (! c->second->m_onTrustPath) && ((c->second->m_localTrust & ZT_CERTIFICATE_LOCAL_TRUST_FLAG_ROOT_CA) == 0)) {
|
||||
if (c->second->m_error == ZT_CERTIFICATE_ERROR_NONE) {
|
||||
if (c->second->m_certificate.isSelfSigned()) {
|
||||
// If this is a self-signed certificate it's only valid if it's trusted as a CA.
|
||||
if ((c->second->m_localTrust & ZT_CERTIFICATE_LOCAL_TRUST_FLAG_ROOT_CA) == 0) {
|
||||
c->second->m_error = ZT_CERTIFICATE_ERROR_INVALID_CHAIN;
|
||||
}
|
||||
}
|
||||
else {
|
||||
if ((! c->second->m_onTrustPath) && ((c->second->m_localTrust & ZT_CERTIFICATE_LOCAL_TRUST_FLAG_ROOT_CA) == 0)) {
|
||||
// Trace the path of each certificate all the way back to a trusted CA.
|
||||
unsigned int pathLength = 0;
|
||||
Map<H384, SharedPtr<Entry> >::const_iterator current(c);
|
||||
|
@ -192,6 +200,8 @@ bool TrustStore::update(const int64_t clock, Vector<SharedPtr<Entry> >* const pu
|
|||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Repopulate mapping of subject unique IDs to their certificates, marking older
|
||||
// certificates for the same subject as deprecated. A deprecated certificate is not invalid
|
||||
|
|
|
@ -648,6 +648,37 @@ static ZT_INLINE void zero(void* dest, unsigned long len) noexcept
|
|||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* Zero memory block whose size is known at compile time
|
||||
*
|
||||
* @tparam L Size in bytes
|
||||
* @param dest Memory to zero
|
||||
*/
|
||||
template <unsigned long L, uint8_t B> static ZT_INLINE void fill(void* dest) noexcept
|
||||
{
|
||||
#if defined(ZT_ARCH_X64) && defined(__GNUC__)
|
||||
uintptr_t l = L;
|
||||
__asm__ __volatile__("cld ; rep stosb" : "+c"(l), "+D"(dest) : "a"(B) : "memory");
|
||||
#else
|
||||
memset(dest, B, L);
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* Zero memory block whose size is known at run time
|
||||
*
|
||||
* @param dest Memory to zero
|
||||
* @param len Size in bytes
|
||||
*/
|
||||
template <uint8_t B> static ZT_INLINE void fill(void* dest, unsigned long len) noexcept
|
||||
{
|
||||
#if defined(ZT_ARCH_X64) && defined(__GNUC__)
|
||||
__asm__ __volatile__("cld ; rep stosb" : "+c"(len), "+D"(dest) : "a"(B) : "memory");
|
||||
#else
|
||||
memset(dest, B, len);
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* Compute 32-bit FNV-1a checksum
|
||||
*
|
||||
|
|
|
@ -657,6 +657,11 @@ typedef struct {
|
|||
|
||||
/**
|
||||
* Issuer certificate serial number.
|
||||
*
|
||||
* If this is a self-signed certificate this will be all 0xff (all 1s).
|
||||
* The issuerPublicKey and subjectSignature fields will be empty and
|
||||
* are not used. The signature will be a signature of this certificate
|
||||
* with its own public key.
|
||||
*/
|
||||
uint8_t issuer[ZT_CERTIFICATE_HASH_SIZE];
|
||||
|
||||
|
@ -673,7 +678,7 @@ typedef struct {
|
|||
/**
|
||||
* Signature of subject with public key.
|
||||
*
|
||||
* This couples the subject to the public key, ensuring that the CRL was
|
||||
* This couples the subject to the public key, ensuring that the CSR was
|
||||
* not modified in transit or by the signer.
|
||||
*/
|
||||
uint8_t subjectSignature[ZT_CERTIFICATE_MAX_SIGNATURE_SIZE];
|
||||
|
|
|
@ -55,50 +55,6 @@ clock_serv_t OSUtils::s_machMonotonicClock = _machGetMonotonicClock();
|
|||
|
||||
#endif
|
||||
|
||||
unsigned int OSUtils::ztsnprintf(char* buf, unsigned int len, const char* fmt, ...)
|
||||
{
|
||||
va_list ap;
|
||||
|
||||
va_start(ap, fmt);
|
||||
int n = (int)vsnprintf(buf, len, fmt, ap);
|
||||
va_end(ap);
|
||||
|
||||
if ((n >= (int)len) || (n < 0)) {
|
||||
if (len)
|
||||
buf[len - 1] = (char)0;
|
||||
throw std::length_error("buf[] overflow");
|
||||
}
|
||||
|
||||
return (unsigned int)n;
|
||||
}
|
||||
|
||||
#ifdef __UNIX_LIKE__
|
||||
|
||||
bool OSUtils::redirectUnixOutputs(const char* stdoutPath, const char* stderrPath)
|
||||
{
|
||||
int fdout = open(stdoutPath, O_WRONLY | O_CREAT, 0600);
|
||||
if (fdout > 0) {
|
||||
int fderr;
|
||||
if (stderrPath) {
|
||||
fderr = open(stderrPath, O_WRONLY | O_CREAT, 0600);
|
||||
if (fderr <= 0) {
|
||||
::close(fdout);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else
|
||||
fderr = fdout;
|
||||
::close(STDOUT_FILENO);
|
||||
::close(STDERR_FILENO);
|
||||
::dup2(fdout, STDOUT_FILENO);
|
||||
::dup2(fderr, STDERR_FILENO);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
#endif // __UNIX_LIKE__
|
||||
|
||||
Vector<String> OSUtils::listDirectory(const char* path, bool includeDirectories)
|
||||
{
|
||||
Vector<String> r;
|
||||
|
|
|
@ -58,21 +58,19 @@ class OSUtils {
|
|||
* @param ... Format arguments
|
||||
* @throws std::length_error buf[] too short (buf[] will still be left null-terminated)
|
||||
*/
|
||||
static unsigned int ztsnprintf(char* buf, unsigned int len, const char* fmt, ...);
|
||||
|
||||
#ifdef __UNIX_LIKE__
|
||||
/**
|
||||
* Close STDOUT_FILENO and STDERR_FILENO and replace them with output to given path
|
||||
*
|
||||
* This can be called after fork() and prior to exec() to suppress output
|
||||
* from a subprocess, such as auto-update.
|
||||
*
|
||||
* @param stdoutPath Path to file to use for stdout
|
||||
* @param stderrPath Path to file to use for stderr, or NULL for same as stdout (default)
|
||||
* @return True on success
|
||||
*/
|
||||
static bool redirectUnixOutputs(const char* stdoutPath, const char* stderrPath = nullptr);
|
||||
#endif // __UNIX_LIKE__
|
||||
static ZT_INLINE unsigned int ztsnprintf(char* buf, unsigned int len, const char* fmt, ...)
|
||||
{
|
||||
va_list ap;
|
||||
va_start(ap, fmt);
|
||||
int n = (int)vsnprintf(buf, len, fmt, ap);
|
||||
va_end(ap);
|
||||
if ((n >= (int)len) || (n < 0)) {
|
||||
if (len)
|
||||
buf[len - 1] = (char)0;
|
||||
throw std::length_error("buf[] overflow");
|
||||
}
|
||||
return (unsigned int)n;
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete a file
|
||||
|
|
|
@ -98,6 +98,25 @@ impl CertificateSerialNo {
|
|||
pub fn is_nil(&self) -> bool {
|
||||
is_all_zeroes(self.0)
|
||||
}
|
||||
|
||||
/// Returns true if this serial indicates a self-signed certificate.
|
||||
/// This is meaningful for the serial in the issuer field of Certificate,
|
||||
/// which will be all 0xff in self-signed certificates.
|
||||
#[inline(always)]
|
||||
pub fn is_self_signed(&self) -> bool {
|
||||
for x in self.0.iter() {
|
||||
if *x != 0xff {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/// Set this to all 0xff which in the issuer field means self-signed.
|
||||
#[inline(always)]
|
||||
pub fn set_self_signed(&mut self) {
|
||||
self.0.fill(0xff);
|
||||
}
|
||||
}
|
||||
|
||||
impl Hash for CertificateSerialNo {
|
||||
|
@ -671,7 +690,7 @@ impl Certificate {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn to_bytes(&self) -> Result<Box<[u8]>, ResultCode> {
|
||||
pub fn to_bytes(&self) -> Result<Vec<u8>, ResultCode> {
|
||||
let mut cert: Vec<u8> = Vec::new();
|
||||
cert.resize(16384, 0);
|
||||
let mut cert_size: c_int = 16384;
|
||||
|
@ -682,7 +701,7 @@ impl Certificate {
|
|||
}
|
||||
}
|
||||
cert.resize(cert_size as usize, 0);
|
||||
return Ok(cert.into_boxed_slice());
|
||||
return Ok(cert);
|
||||
}
|
||||
|
||||
/// Sign this certificate, returning new signed certificate.
|
||||
|
@ -709,6 +728,16 @@ impl Certificate {
|
|||
return CertificateError::from_i32(ztcore::ZT_Certificate_verify(&capi.certificate as *const ztcore::ZT_Certificate, clock) as i32).unwrap_or(CertificateError::InvalidFormat);
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns true if this is a self-signed certificate.
|
||||
pub fn is_self_signed(&self) -> bool {
|
||||
for b in self.issuer.0.iter() {
|
||||
if *b != 0xff {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
|
|
@ -84,12 +84,12 @@ pub const DEFAULT_UDP_MTU: u32 = ztcore::ZT_DEFAULT_UDP_MTU;
|
|||
/// Maximum UDP MTU (we never actually get this high).
|
||||
pub const MAX_UDP_MTU: u32 = ztcore::ZT_MAX_UDP_MTU;
|
||||
|
||||
/// Base64 encode using the URL-safe with no padding configuration.
|
||||
/// Base64 encode using the URL-safe alphabet with no padding.
|
||||
pub fn base64_encode<T: AsRef<[u8]>>(t: &T) -> String {
|
||||
base64::encode_config(t, base64::URL_SAFE_NO_PAD)
|
||||
}
|
||||
|
||||
/// Base64 decode using the URL-safe with no padding configuration.
|
||||
/// Base64 decode using the URL-safe alphabet with no padding.
|
||||
pub fn base64_decode<T: AsRef<[u8]>>(t: &T) -> Result<Vec<u8>, base64::DecodeError> {
|
||||
base64::decode_config(t, base64::URL_SAFE_NO_PAD)
|
||||
}
|
||||
|
|
|
@ -252,12 +252,13 @@ fn newcsr(cli_args: &ArgMatches) -> i32 {
|
|||
println!("ERROR: unable to read subject unique ID secret file: {}", b.err().unwrap().to_string());
|
||||
return 1;
|
||||
}
|
||||
let privk_hex = String::from_utf8(b.unwrap());
|
||||
if privk_hex.is_err() {
|
||||
let privk_encoded = String::from_utf8(b.unwrap());
|
||||
if privk_encoded.is_err() {
|
||||
println!("ERROR: invalid UTF-8 in secret");
|
||||
return 1;
|
||||
}
|
||||
let privk = hex::decode(privk_hex.unwrap().trim());
|
||||
let privk_encoded = privk_encoded.unwrap();
|
||||
let privk = base64_decode(&privk_encoded);
|
||||
if privk.is_err() || privk.as_ref().unwrap().is_empty() {
|
||||
println!("ERROR: invalid unique ID secret: {}", privk.err().unwrap().to_string());
|
||||
return 1;
|
||||
|
@ -416,7 +417,7 @@ fn newcsr(cli_args: &ArgMatches) -> i32 {
|
|||
1
|
||||
}, |_| {
|
||||
let secret_path = cli_args.value_of("secretpath").unwrap();
|
||||
std::fs::write(secret_path, hex::encode(privk)).map_or_else(|e| {
|
||||
std::fs::write(secret_path, base64_encode(&privk)).map_or_else(|e| {
|
||||
let _ = std::fs::remove_file(csr_path);
|
||||
println!("ERROR: unable to write secret: {}", e.to_string());
|
||||
1
|
||||
|
@ -429,8 +430,98 @@ fn newcsr(cli_args: &ArgMatches) -> i32 {
|
|||
}
|
||||
|
||||
fn sign<'a>(store: &Arc<Store>, cli_args: &ArgMatches<'a>) -> i32 {
|
||||
let theme = &dialoguer::theme::SimpleTheme;
|
||||
let now = ms_since_epoch();
|
||||
let csr_path = cli_args.value_of("csr").unwrap().trim(); // required
|
||||
let certout_path = cli_args.value_of("certout").unwrap().trim(); // required
|
||||
let usage = cert_string_to_usage_flags(cli_args.value_of("usage").unwrap_or(""));
|
||||
let timestamp = cli_args.value_of("timestamp").map_or_else(|| now, |ts| i64::from_str(ts.trim()).unwrap_or(now));
|
||||
let start_time = cli_args.value_of("start").map_or_else(|| timestamp, |s| i64::from_str(s.trim()).unwrap_or(now));
|
||||
let end_time = cli_args.value_of("ttl").map_or(i64::MAX, |e| i64::from_str(e.trim()).map_or(i64::MAX, |e| timestamp + e));
|
||||
let issuer_path = cli_args.value_of("issuer").unwrap().trim(); // required
|
||||
let issuer_secret_path = cli_args.value_of("issuersecret").unwrap().trim(); // required
|
||||
|
||||
let csr = crate::utils::read_limit(csr_path, 131072);
|
||||
if csr.is_err() {
|
||||
println!("ERROR: unable to read CSR from '{}': {}", csr_path, csr.err().unwrap().to_string());
|
||||
return 1;
|
||||
}
|
||||
let csr = csr.unwrap();
|
||||
|
||||
let cert = Certificate::new_from_bytes(csr.as_slice(), false);
|
||||
if cert.is_err() {
|
||||
println!("ERROR: error decoding CSR read from '{}': {}", csr_path, cert.err().unwrap().to_str());
|
||||
return 1;
|
||||
}
|
||||
let mut cert = cert.ok().unwrap();
|
||||
|
||||
cert.usage_flags = usage;
|
||||
cert.timestamp = timestamp;
|
||||
cert.validity[0] = start_time;
|
||||
cert.validity[1] = end_time;
|
||||
|
||||
let issuer = if issuer_path == "self" {
|
||||
cert.issuer_public_key.clear();
|
||||
cert.subject_signature.clear();
|
||||
cert.issuer.clone()
|
||||
} else {
|
||||
let issuer = crate::utils::read_limit(issuer_path, 131072);
|
||||
if issuer.is_err() {
|
||||
println!("ERROR: unable to read issuer from '{}': {}", issuer_path, issuer.err().unwrap().to_string());
|
||||
return 1;
|
||||
}
|
||||
let issuer = issuer.unwrap();
|
||||
|
||||
let issuer_cert = Certificate::new_from_bytes(issuer.as_slice(), true);
|
||||
if issuer_cert.is_err() {
|
||||
println!("ERROR: issuer at '{}' is invalid: {}", issuer_path, issuer_cert.err().unwrap().to_str());
|
||||
return 1;
|
||||
}
|
||||
let issuer_cert = issuer_cert.ok().unwrap();
|
||||
|
||||
if (issuer_cert.usage_flags & CERTIFICATE_USAGE_CERTIFICATE_SIGNING) == 0 {
|
||||
println!("ERROR: issuer at '{}' usage does not permit certificate signing.", issuer_path);
|
||||
return 1;
|
||||
}
|
||||
|
||||
issuer_cert.issuer.clone()
|
||||
};
|
||||
|
||||
let issuer_secret = crate::utils::read_limit(issuer_secret_path, 1024);
|
||||
if issuer_secret.is_err() {
|
||||
println!("ERROR: unable to read issuer secret from '{}': {}", issuer_secret_path, issuer_secret.err().unwrap().to_string());
|
||||
return 1;
|
||||
}
|
||||
let issuer_secret = issuer_secret.unwrap();
|
||||
let issuer_secret = base64_decode(&issuer_secret);
|
||||
if issuer_secret.is_err() {
|
||||
println!("ERROR: invalid issuer secret in '{}': invalid base64: {}", issuer_secret_path, issuer_secret.err().unwrap().to_string());
|
||||
return 1;
|
||||
}
|
||||
let issuer_secret = issuer_secret.unwrap();
|
||||
|
||||
let signed_cert = cert.sign(&issuer, issuer_secret.as_slice());
|
||||
if signed_cert.is_err() {
|
||||
println!("ERROR: error signing certificate: {}", signed_cert.err().unwrap().to_str());
|
||||
return 1;
|
||||
}
|
||||
let signed_cert = signed_cert.ok().unwrap();
|
||||
|
||||
let signed_cert_check = signed_cert.verify(-1);
|
||||
if signed_cert_check != CertificateError::None {
|
||||
println!("ERROR: error signing certificate: failed verify after sign: {}", signed_cert_check.to_str());
|
||||
return 1;
|
||||
}
|
||||
|
||||
cert_print(&signed_cert);
|
||||
println!();
|
||||
|
||||
let signed_cert = signed_cert.to_bytes().ok().unwrap();
|
||||
let signed_write_result = std::fs::write(certout_path, signed_cert.as_slice());
|
||||
if signed_write_result.is_err() {
|
||||
println!("ERROR: unable to write result to '{}': {}", certout_path, signed_write_result.err().unwrap().to_string());
|
||||
return 1;
|
||||
}
|
||||
println!("Signed certificate written to {}", certout_path);
|
||||
0
|
||||
}
|
||||
|
||||
|
@ -467,7 +558,7 @@ pub(crate) fn run(store: Arc<Store>, global_flags: GlobalFlags, cli_args: &ArgMa
|
|||
("delete", Some(sub_cli_args)) => delete(&store, sub_cli_args),
|
||||
("factoryreset", None) => factoryreset(&store),
|
||||
_ => {
|
||||
crate::print_help();
|
||||
crate::print_help(true);
|
||||
1
|
||||
}
|
||||
}
|
||||
|
|
|
@ -127,7 +127,7 @@ pub(crate) fn run<'a>(cli_args: &ArgMatches<'a>) -> i32 {
|
|||
("sign", Some(sub_cli_args)) => sign(sub_cli_args),
|
||||
("verify", Some(sub_cli_args)) => verify(sub_cli_args),
|
||||
_ => {
|
||||
crate::print_help();
|
||||
crate::print_help(true);
|
||||
1
|
||||
}
|
||||
}
|
||||
|
|
|
@ -109,7 +109,7 @@ pub(crate) fn run(cli_args: &ArgMatches) -> i32 {
|
|||
("verify", Some(sub_cli_args)) => verify(sub_cli_args),
|
||||
("show", Some(sub_cli_args)) => show(sub_cli_args),
|
||||
_ => {
|
||||
crate::print_help();
|
||||
crate::print_help(true);
|
||||
1
|
||||
}
|
||||
}
|
||||
|
|
|
@ -16,7 +16,8 @@ mod commands;
|
|||
mod fastudpsocket;
|
||||
mod localconfig;
|
||||
mod getifaddrs;
|
||||
#[macro_use] mod log;
|
||||
#[macro_use]
|
||||
mod log;
|
||||
mod store;
|
||||
mod network;
|
||||
mod vnic;
|
||||
|
@ -38,7 +39,7 @@ use crate::store::Store;
|
|||
|
||||
pub const HTTP_API_OBJECT_SIZE_LIMIT: usize = 131072;
|
||||
|
||||
fn make_help() -> String {
|
||||
fn make_help(long_help: bool) -> String {
|
||||
let ver = zerotier_core::version();
|
||||
format!(r###"ZeroTier Network Hypervisor Service Version {}.{}.{}
|
||||
(c)2013-2021 ZeroTier, Inc.
|
||||
|
@ -56,6 +57,7 @@ Global Options:
|
|||
Common Operations:
|
||||
|
||||
help Show this help
|
||||
longhelp Show help with advanced commands
|
||||
oldhelp Show v1.x legacy commands
|
||||
version Print version (of this binary)
|
||||
|
||||
|
@ -85,10 +87,11 @@ Common Operations:
|
|||
· globalroutes <boolean> Can global IP routes be set?
|
||||
· defaultroute <boolean> Can default route be overridden?
|
||||
|
||||
· join [-...] <network> Join a virtual network
|
||||
-c <?identity | fingerprint> Controller identity / fingerprint
|
||||
· join <network> Join a virtual network
|
||||
· leave <network> Leave a virtual network
|
||||
|
||||
{}"###,
|
||||
ver.0, ver.1, ver.2, if long_help {
|
||||
r###"
|
||||
Advanced Operations:
|
||||
|
||||
service Start node
|
||||
|
@ -120,12 +123,27 @@ Advanced Operations:
|
|||
· list List certificates at local node
|
||||
show <@cert|·serial> Show certificate details
|
||||
newsuid [@secret out] Create a subject unique ID secret
|
||||
newcsr <@csr> <@secret out> Create a CSR (interactive)
|
||||
sign <@csr> <@secret> <@cert out> Sign a CSR to create a certificate
|
||||
newcsr <@csr out> <@secret out> Create a CSR (interactive)
|
||||
sign <@csr> <@cert out> Sign a CSR to create a certificate
|
||||
-u <usage flags (ex: sedacr)> Set usage flags (recommended)
|
||||
s Usage: digital signature
|
||||
n Usage: non-repudiation
|
||||
e Usage: key encipherment
|
||||
d Usage: key decipherment
|
||||
a Usage: key agreement
|
||||
c Usage: certificate signing (CA)
|
||||
r Usage: CRL signing (CA)
|
||||
x Usage: executable signing
|
||||
t Usage: timestamping
|
||||
-t <timestamp, seconds since epoch> Timestamp (default: current time)
|
||||
-s <validity start time, seconds> Start time (default: timestamp)
|
||||
-l <#y|d|h|m|s... (ex: 1y, 3d12h)> Time to live (default: forever)
|
||||
-i <@issuer | self> Issuer or self-sign (required)
|
||||
-k <@issuer secret> Secret key for issuer (required)
|
||||
verify <@cert> Internally verify certificate
|
||||
· import <@cert> [trust,trust,...] Import certificate into this node
|
||||
trust flag: rootca Root (or self-signed) CA
|
||||
trust flag: config Can influence node configuration
|
||||
ca Trust: root CA or self-signed
|
||||
config Trust: node configuration
|
||||
· export <serial> [@cert] Export a certificate from this node
|
||||
· delete <serial|ALL> Delete certificate from this node
|
||||
· factoryreset Re-import compiled-in default certs
|
||||
|
@ -133,11 +151,12 @@ Advanced Operations:
|
|||
· Command (or command with argument type) requires a running node.
|
||||
@ Argument is the path to a file containing the object.
|
||||
? Argument can be either the object or a path to it (auto-detected).
|
||||
"###, ver.0, ver.1, ver.2)
|
||||
"###
|
||||
} else { "" })
|
||||
}
|
||||
|
||||
pub(crate) fn print_help() {
|
||||
let h = make_help();
|
||||
pub(crate) fn print_help(long_help: bool) {
|
||||
let h = make_help(long_help);
|
||||
let _ = std::io::stdout().write_all(h.as_bytes());
|
||||
}
|
||||
|
||||
|
@ -152,6 +171,7 @@ pub(crate) fn parse_bool(v: &str) -> Result<bool, String> {
|
|||
Err(format!("invalid boolean value: '{}'", v))
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn is_valid_bool(v: String) -> Result<(), String> {
|
||||
parse_bool(v.as_str()).map(|_| ())
|
||||
}
|
||||
|
@ -188,7 +208,7 @@ fn get_global_flags(cli_args: &ArgMatches) -> GlobalFlags {
|
|||
|
||||
fn main() {
|
||||
let cli_args = {
|
||||
let help = make_help();
|
||||
let help = make_help(false);
|
||||
let args = App::new("zerotier")
|
||||
.arg(Arg::with_name("json").short("j"))
|
||||
.arg(Arg::with_name("path").short("p").takes_value(true))
|
||||
|
@ -226,7 +246,6 @@ fn main() {
|
|||
.arg(Arg::with_name("setting").index(2).required(false))
|
||||
.arg(Arg::with_name("value").index(3).required(false))))
|
||||
.subcommand(App::new("join")
|
||||
.arg(Arg::with_name("controller").short("c").takes_value(true))
|
||||
.arg(Arg::with_name("nwid").index(1).required(true)))
|
||||
.subcommand(App::new("leave")
|
||||
.arg(Arg::with_name("nwid").index(1).required(true)))
|
||||
|
@ -282,8 +301,13 @@ fn main() {
|
|||
.arg(Arg::with_name("secretpath").index(2).required(true)))
|
||||
.subcommand(App::new("sign")
|
||||
.arg(Arg::with_name("csr").index(1).required(true))
|
||||
.arg(Arg::with_name("secretpath").index(2).required(true))
|
||||
.arg(Arg::with_name("output").index(3).required(false)))
|
||||
.arg(Arg::with_name("certout").index(2).required(true))
|
||||
.arg(Arg::with_name("usage").short("u").required(false))
|
||||
.arg(Arg::with_name("timestamp").short("t").required(false))
|
||||
.arg(Arg::with_name("start").short("s").required(false))
|
||||
.arg(Arg::with_name("ttl").short("l").required(false))
|
||||
.arg(Arg::with_name("issuer").short("i").required(true))
|
||||
.arg(Arg::with_name("issuersecret").short("k").required(true)))
|
||||
.subcommand(App::new("verify")
|
||||
.arg(Arg::with_name("cert").index(1).required(true)))
|
||||
.subcommand(App::new("dump")
|
||||
|
@ -302,13 +326,13 @@ fn main() {
|
|||
if args.is_err() {
|
||||
let e = args.err().unwrap();
|
||||
if e.kind != ErrorKind::HelpDisplayed {
|
||||
print_help();
|
||||
print_help(false);
|
||||
}
|
||||
std::process::exit(1);
|
||||
}
|
||||
let args = args.unwrap();
|
||||
if args.subcommand_name().is_none() {
|
||||
print_help();
|
||||
print_help(false);
|
||||
std::process::exit(1);
|
||||
}
|
||||
args
|
||||
|
@ -316,36 +340,40 @@ fn main() {
|
|||
|
||||
std::process::exit({
|
||||
match cli_args.subcommand() {
|
||||
("help", _) => {
|
||||
print_help();
|
||||
("help", None) => {
|
||||
print_help(false);
|
||||
0
|
||||
}
|
||||
("oldhelp", _) => {
|
||||
("longhelp", None) => {
|
||||
print_help(true);
|
||||
0
|
||||
}
|
||||
("oldhelp", None) => {
|
||||
// TODO
|
||||
0
|
||||
}
|
||||
("version", _) => {
|
||||
("version", None) => {
|
||||
let ver = zerotier_core::version();
|
||||
println!("{}.{}.{}", ver.0, ver.1, ver.2);
|
||||
0
|
||||
}
|
||||
("status", _) => crate::httpclient::run_command(make_store(&cli_args), get_global_flags(&cli_args), crate::commands::status::run),
|
||||
("status", None) => crate::httpclient::run_command(make_store(&cli_args), get_global_flags(&cli_args), crate::commands::status::run),
|
||||
("set", Some(sub_cli_args)) => { 0 }
|
||||
("peer", Some(sub_cli_args)) => { 0 }
|
||||
("network", Some(sub_cli_args)) => { 0 }
|
||||
("join", Some(sub_cli_args)) => { 0 }
|
||||
("leave", Some(sub_cli_args)) => { 0 }
|
||||
("service", _) => {
|
||||
("service", None) => {
|
||||
let store = make_store(&cli_args);
|
||||
drop(cli_args); // free no longer needed memory before entering service
|
||||
service::run(store)
|
||||
},
|
||||
}
|
||||
("controller", Some(sub_cli_args)) => { 0 }
|
||||
("identity", Some(sub_cli_args)) => crate::commands::identity::run(sub_cli_args),
|
||||
("locator", Some(sub_cli_args)) => crate::commands::locator::run(sub_cli_args),
|
||||
("cert", Some(sub_cli_args)) => crate::commands::cert::run(make_store(&cli_args), get_global_flags(&cli_args), sub_cli_args),
|
||||
_ => {
|
||||
print_help();
|
||||
print_help(false);
|
||||
1
|
||||
}
|
||||
}
|
||||
|
|
|
@ -98,7 +98,7 @@ pub(crate) fn read_locator(input: &str) -> Result<Locator, String> {
|
|||
/// each execution of the process. By decrypting this nonce when it is returned,
|
||||
/// the client and server may check the age of a digest auth exchange.
|
||||
pub(crate) fn create_http_auth_nonce(timestamp: i64) -> String {
|
||||
let mut nonce_plaintext: [u64; 2] = [timestamp as u64, 12345]; // the second u64 is arbitrary and unused
|
||||
let mut nonce_plaintext: [u64; 2] = [timestamp as u64, timestamp as u64];
|
||||
unsafe {
|
||||
osdep::encryptHttpAuthNonce(nonce_plaintext.as_mut_ptr().cast());
|
||||
hex::encode(*nonce_plaintext.as_ptr().cast::<[u8; 16]>())
|
||||
|
@ -109,18 +109,19 @@ pub(crate) fn create_http_auth_nonce(timestamp: i64) -> String {
|
|||
/// This returns zero if the input was not valid.
|
||||
pub(crate) fn decrypt_http_auth_nonce(nonce: &str) -> i64 {
|
||||
let nonce = hex::decode(nonce.trim());
|
||||
if nonce.is_err() {
|
||||
return 0;
|
||||
}
|
||||
if !nonce.is_err() {
|
||||
let mut nonce = nonce.unwrap();
|
||||
if nonce.len() != 16 {
|
||||
return 0;
|
||||
}
|
||||
if nonce.len() == 16 {
|
||||
unsafe {
|
||||
osdep::decryptHttpAuthNonce(nonce.as_mut_ptr().cast());
|
||||
let nonce = *nonce.as_ptr().cast::<[u64; 2]>();
|
||||
nonce[0] as i64
|
||||
if nonce[0] == nonce[1] {
|
||||
return nonce[0] as i64;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/// Shortcut to use serde_json to serialize an object, returns "null" on error.
|
||||
|
|
|
@ -11,7 +11,7 @@
|
|||
*/
|
||||
/****/
|
||||
|
||||
use std::collections::BTreeSet;
|
||||
use std::collections::HashSet;
|
||||
|
||||
#[allow(unused_imports)]
|
||||
use zerotier_core::{MAC, MulticastGroup};
|
||||
|
@ -21,8 +21,8 @@ use num_traits::AsPrimitive;
|
|||
|
||||
/// BSD based OSes support getifmaddrs().
|
||||
#[cfg(any(target_os = "macos", target_os = "ios", target_os = "netbsd", target_os = "openbsd", target_os = "dragonfly", target_os = "freebsd", target_os = "darwin"))]
|
||||
pub(crate) fn get_l2_multicast_subscriptions(dev: &str) -> BTreeSet<MulticastGroup> {
|
||||
let mut groups: BTreeSet<MulticastGroup> = BTreeSet::new();
|
||||
pub(crate) fn get_l2_multicast_subscriptions(dev: &str) -> HashSet<MulticastGroup> {
|
||||
let mut groups: HashSet<MulticastGroup> = HashSet::new();
|
||||
let dev = dev.as_bytes();
|
||||
unsafe {
|
||||
let mut maddrs: *mut osdep::ifmaddrs = std::ptr::null_mut();
|
||||
|
@ -50,7 +50,7 @@ pub(crate) fn get_l2_multicast_subscriptions(dev: &str) -> BTreeSet<MulticastGro
|
|||
|
||||
/// Linux stores this stuff in /proc and it needs to be fetched from there.
|
||||
#[cfg(target_os = "linux")]
|
||||
pub(crate) fn get_l2_multicast_subscriptions(dev: &str) -> BTreeSet<MulticastGroup> {
|
||||
let mut groups: BTreeSet<MulticastGroup> = BTreeSet::new();
|
||||
pub(crate) fn get_l2_multicast_subscriptions(dev: &str) -> HashSet<MulticastGroup> {
|
||||
let mut groups: HashSet<MulticastGroup> = HashSet::new();
|
||||
groups
|
||||
}
|
||||
|
|
|
@ -36,7 +36,7 @@
|
|||
*/
|
||||
|
||||
use std::cell::Cell;
|
||||
use std::collections::BTreeSet;
|
||||
use std::collections::HashSet;
|
||||
use std::error::Error;
|
||||
use std::ffi::CString;
|
||||
use std::ptr::{null_mut, copy_nonoverlapping};
|
||||
|
@ -53,7 +53,7 @@ use zerotier_core::{InetAddress, MAC, MulticastGroup, NetworkId};
|
|||
|
||||
use crate::osdep as osdep;
|
||||
use crate::getifaddrs;
|
||||
use crate::vnic::VNIC;
|
||||
use crate::vnic::vnic::VNIC;
|
||||
use crate::osdep::getifmaddrs;
|
||||
|
||||
const BPF_BUFFER_SIZE: usize = 131072;
|
||||
|
@ -423,7 +423,7 @@ impl VNIC for MacFethTap {
|
|||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn get_multicast_groups(&self) -> BTreeSet<MulticastGroup> {
|
||||
fn get_multicast_groups(&self) -> HashSet<MulticastGroup> {
|
||||
crate::vnic::common::get_l2_multicast_subscriptions(self.device.name.as_str())
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue