mirror of
https://github.com/zerotier/ZeroTierOne.git
synced 2025-05-10 23:53: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
|
IndentWidth: 4
|
||||||
TabWidth: 4
|
TabWidth: 4
|
||||||
AlignAfterOpenBracket: AlwaysBreak
|
AlignAfterOpenBracket: AlwaysBreak
|
||||||
AlignConsecutiveMacros: 'true'
|
AlignConsecutiveMacros: Consecutive
|
||||||
AlignConsecutiveAssignments: 'false'
|
AlignConsecutiveAssignments: Consecutive
|
||||||
AlignConsecutiveDeclarations: 'false'
|
AlignConsecutiveDeclarations: None
|
||||||
AlignEscapedNewlines: Right
|
AlignEscapedNewlines: Right
|
||||||
AlignOperands: 'true'
|
AlignOperands: true
|
||||||
AlignTrailingComments: 'true'
|
AlignTrailingComments: true
|
||||||
AllowAllArgumentsOnNextLine: 'false'
|
AllowAllArgumentsOnNextLine: false
|
||||||
AllowAllConstructorInitializersOnNextLine: 'false'
|
AllowAllConstructorInitializersOnNextLine: false
|
||||||
AllowAllParametersOfDeclarationOnNextLine: 'false'
|
AllowAllParametersOfDeclarationOnNextLine: false
|
||||||
AllowShortBlocksOnASingleLine: 'true'
|
AllowShortBlocksOnASingleLine: Always
|
||||||
AllowShortCaseLabelsOnASingleLine: 'false'
|
AllowShortCaseLabelsOnASingleLine: true
|
||||||
AllowShortFunctionsOnASingleLine: None
|
AllowShortFunctionsOnASingleLine: All
|
||||||
AllowShortIfStatementsOnASingleLine: Never
|
AllowShortIfStatementsOnASingleLine: Never
|
||||||
AlwaysBreakAfterReturnType: None
|
AlwaysBreakAfterReturnType: None
|
||||||
BinPackArguments: 'false'
|
BinPackArguments: true
|
||||||
BinPackParameters: 'false'
|
BinPackParameters: true
|
||||||
BreakBeforeBinaryOperators: NonAssignment
|
BreakBeforeBinaryOperators: NonAssignment
|
||||||
BreakBeforeTernaryOperators: 'true'
|
BreakBeforeTernaryOperators: true
|
||||||
BreakConstructorInitializers: BeforeComma
|
BreakConstructorInitializers: BeforeComma
|
||||||
BreakInheritanceList: BeforeComma
|
BreakInheritanceList: BeforeComma
|
||||||
CompactNamespaces: 'false'
|
CompactNamespaces: false
|
||||||
ConstructorInitializerAllOnOneLineOrOnePerLine: 'true'
|
ConstructorInitializerAllOnOneLineOrOnePerLine: true
|
||||||
ConstructorInitializerIndentWidth: '4'
|
ConstructorInitializerIndentWidth: 4
|
||||||
ContinuationIndentWidth: '4'
|
ContinuationIndentWidth: 4
|
||||||
Cpp11BracedListStyle: 'false'
|
Cpp11BracedListStyle: false
|
||||||
FixNamespaceComments: 'true'
|
FixNamespaceComments: true
|
||||||
IncludeBlocks: Regroup
|
IncludeBlocks: Regroup
|
||||||
IndentCaseLabels: 'true'
|
IndentCaseLabels: true
|
||||||
IndentPPDirectives: None
|
IndentPPDirectives: None
|
||||||
IndentWrappedFunctionNames: 'false'
|
IndentWrappedFunctionNames: false
|
||||||
KeepEmptyLinesAtTheStartOfBlocks: 'false'
|
KeepEmptyLinesAtTheStartOfBlocks: false
|
||||||
MaxEmptyLinesToKeep: '1'
|
MaxEmptyLinesToKeep: 1
|
||||||
NamespaceIndentation: None
|
NamespaceIndentation: None
|
||||||
PointerAlignment: Left
|
PointerAlignment: Right
|
||||||
ReflowComments: 'true'
|
ReflowComments: true
|
||||||
SortIncludes: 'true'
|
SortIncludes: CaseInsensitive
|
||||||
SortUsingDeclarations: 'true'
|
SortUsingDeclarations: true
|
||||||
SpaceAfterCStyleCast: 'false'
|
SpaceAfterCStyleCast: false
|
||||||
SpaceAfterLogicalNot: 'true'
|
SpaceAfterLogicalNot: false
|
||||||
SpaceAfterTemplateKeyword: 'true'
|
SpaceAfterTemplateKeyword: true
|
||||||
SpaceBeforeAssignmentOperators: 'true'
|
SpaceBeforeAssignmentOperators: true
|
||||||
SpaceBeforeCpp11BracedList: 'true'
|
SpaceBeforeCpp11BracedList: true
|
||||||
SpaceBeforeCtorInitializerColon: 'true'
|
SpaceBeforeCtorInitializerColon: true
|
||||||
SpaceBeforeInheritanceColon: 'true'
|
SpaceBeforeInheritanceColon: true
|
||||||
SpaceBeforeParens: ControlStatements
|
SpaceBeforeParens: ControlStatements
|
||||||
SpaceBeforeRangeBasedForLoopColon: 'true'
|
SpaceBeforeRangeBasedForLoopColon: true
|
||||||
SpaceInEmptyParentheses: 'false'
|
SpaceInEmptyParentheses: false
|
||||||
SpacesBeforeTrailingComments: '3'
|
SpacesBeforeTrailingComments: 3
|
||||||
SpacesInAngles: 'false'
|
SpacesInAngles: false
|
||||||
SpacesInCStyleCastParentheses: 'false'
|
SpacesInCStyleCastParentheses: false
|
||||||
SpacesInContainerLiterals: 'true'
|
SpacesInContainerLiterals: true
|
||||||
SpacesInParentheses: 'false'
|
SpacesInParentheses: false
|
||||||
SpacesInSquareBrackets: 'false'
|
SpacesInSquareBrackets: false
|
||||||
UseTab: 'false'
|
UseTab: Never
|
||||||
|
|
||||||
---
|
---
|
||||||
Language: Cpp
|
Language: Cpp
|
||||||
Standard: Cpp03
|
Standard: c++11
|
||||||
ColumnLimit: '240'
|
ColumnLimit: 120
|
||||||
---
|
---
|
||||||
Language: ObjC
|
Language: ObjC
|
||||||
ColumnLimit: '240'
|
ColumnLimit: 120
|
||||||
---
|
---
|
||||||
Language: Java
|
Language: Java
|
||||||
ColumnLimit: '240'
|
ColumnLimit: 120
|
||||||
---
|
---
|
||||||
Language: CSharp
|
Language: CSharp
|
||||||
ColumnLimit: '240'
|
ColumnLimit: 120
|
||||||
...
|
...
|
||||||
|
|
|
@ -25,19 +25,11 @@ Certificate::Certificate() noexcept
|
||||||
Utils::zero<sizeof(ZT_Certificate)>(sup);
|
Utils::zero<sizeof(ZT_Certificate)>(sup);
|
||||||
}
|
}
|
||||||
|
|
||||||
Certificate::Certificate(const ZT_Certificate& apiCert) : Certificate()
|
Certificate::Certificate(const ZT_Certificate &apiCert) : Certificate() { *this = apiCert; }
|
||||||
{
|
|
||||||
*this = apiCert;
|
|
||||||
}
|
|
||||||
|
|
||||||
Certificate::Certificate(const Certificate& cert) : Certificate()
|
Certificate::Certificate(const Certificate &cert) : Certificate() { *this = cert; }
|
||||||
{
|
|
||||||
*this = cert;
|
|
||||||
}
|
|
||||||
|
|
||||||
Certificate::~Certificate()
|
Certificate::~Certificate() {}
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
Certificate &Certificate::operator=(const ZT_Certificate &cert)
|
Certificate &Certificate::operator=(const ZT_Certificate &cert)
|
||||||
{
|
{
|
||||||
|
@ -55,7 +47,9 @@ Certificate& Certificate::operator=(const ZT_Certificate& cert)
|
||||||
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) {
|
||||||
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 {
|
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(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.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.uniqueIdSize = cert.subject.uniqueIdSize;
|
||||||
this->subject.uniqueIdSignatureSize = cert.subject.uniqueIdSignatureSize;
|
this->subject.uniqueIdSignatureSize = cert.subject.uniqueIdSignatureSize;
|
||||||
|
|
||||||
|
@ -339,25 +334,37 @@ bool Certificate::decode(const void* const data, const unsigned int len)
|
||||||
return true;
|
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;
|
return false;
|
||||||
|
|
||||||
switch (reinterpret_cast<const uint8_t *>(issuerPrivateKey)[0]) {
|
switch (reinterpret_cast<const uint8_t *>(issuerPrivateKey)[0]) {
|
||||||
default:
|
default: return false;
|
||||||
return false;
|
|
||||||
case ZT_CERTIFICATE_PUBLIC_KEY_ALGORITHM_ECDSA_NIST_P_384:
|
case ZT_CERTIFICATE_PUBLIC_KEY_ALGORITHM_ECDSA_NIST_P_384:
|
||||||
if (issuerPrivateKeySize == (1 + ZT_ECC384_PUBLIC_KEY_SIZE + ZT_ECC384_PRIVATE_KEY_SIZE)) {
|
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<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
|
issuerPrivateKey); // private is prefixed with public
|
||||||
this->issuerPublicKeySize = 1 + ZT_ECC384_PUBLIC_KEY_SIZE;
|
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());
|
||||||
|
|
||||||
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;
|
this->signatureSize = ZT_ECC384_SIGNATURE_SIZE;
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
@ -382,10 +389,14 @@ ZT_CertificateError Certificate::verify(const int64_t clock, const bool checkSig
|
||||||
return ZT_CERTIFICATE_ERROR_INVALID_FORMAT;
|
return ZT_CERTIFICATE_ERROR_INVALID_FORMAT;
|
||||||
}
|
}
|
||||||
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) && (! 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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -421,7 +432,11 @@ 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;
|
return ZT_CERTIFICATE_ERROR_INVALID_FORMAT;
|
||||||
}
|
}
|
||||||
if ((this->extendedAttributesSize > 0) && (!this->extendedAttributes)) {
|
if ((this->extendedAttributesSize > 0) && (!this->extendedAttributes)) {
|
||||||
|
@ -432,13 +447,27 @@ ZT_CertificateError Certificate::verify(const int64_t clock, const bool checkSig
|
||||||
}
|
}
|
||||||
|
|
||||||
if (checkSignatures) {
|
if (checkSignatures) {
|
||||||
// Signature check fails if main signature is not present or invalid.
|
Dictionary d;
|
||||||
// Note that the serial number / SHA384 hash is computed on decode(), so
|
Vector<uint8_t> enc;
|
||||||
// this value is not something we blindly trust from input.
|
|
||||||
|
// 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) {
|
if (this->issuerPublicKeySize > 0) {
|
||||||
switch (this->issuerPublicKey[0]) {
|
switch (this->issuerPublicKey[0]) {
|
||||||
case ZT_CERTIFICATE_PUBLIC_KEY_ALGORITHM_ECDSA_NIST_P_384:
|
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 ((this->issuerPublicKeySize == (ZT_ECC384_PUBLIC_KEY_SIZE + 1))
|
||||||
|
&& (this->signatureSize == ZT_ECC384_SIGNATURE_SIZE)) {
|
||||||
if (!ECC384ECDSAVerify(this->issuerPublicKey + 1, this->serialNo, this->signature)) {
|
if (!ECC384ECDSAVerify(this->issuerPublicKey + 1, this->serialNo, this->signature)) {
|
||||||
return ZT_CERTIFICATE_ERROR_INVALID_PRIMARY_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;
|
return ZT_CERTIFICATE_ERROR_INVALID_PRIMARY_SIGNATURE;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
default:
|
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;
|
||||||
}
|
}
|
||||||
|
|
||||||
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) {
|
if (this->publicKeySize > 0) {
|
||||||
d.clear();
|
d.clear();
|
||||||
m_encodeSubject(this->subject, d, false);
|
m_encodeSubject(this->subject, d, false);
|
||||||
|
@ -467,7 +490,8 @@ ZT_CertificateError Certificate::verify(const int64_t clock, const bool checkSig
|
||||||
|
|
||||||
switch (this->publicKey[0]) {
|
switch (this->publicKey[0]) {
|
||||||
case ZT_CERTIFICATE_PUBLIC_KEY_ALGORITHM_ECDSA_NIST_P_384:
|
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];
|
uint8_t h[ZT_SHA384_DIGEST_SIZE];
|
||||||
SHA384(h, enc.data(), (unsigned int)enc.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)) {
|
||||||
|
@ -478,13 +502,38 @@ ZT_CertificateError Certificate::verify(const int64_t clock, const bool checkSig
|
||||||
return ZT_CERTIFICATE_ERROR_INVALID_COMPONENT_SIGNATURE;
|
return ZT_CERTIFICATE_ERROR_INVALID_COMPONENT_SIGNATURE;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
default:
|
default: return ZT_CERTIFICATE_ERROR_INVALID_COMPONENT_SIGNATURE;
|
||||||
return ZT_CERTIFICATE_ERROR_INVALID_COMPONENT_SIGNATURE;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
return ZT_CERTIFICATE_ERROR_INVALID_COMPONENT_SIGNATURE;
|
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
|
// 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
|
// 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 > 0) {
|
||||||
if (this->subject.uniqueIdSize <= (unsigned int)sizeof(this->subject.uniqueId)) {
|
if (this->subject.uniqueIdSize <= (unsigned int)sizeof(this->subject.uniqueId)) {
|
||||||
switch (this->subject.uniqueId[0]) {
|
switch (this->subject.uniqueId[0]) {
|
||||||
case ZT_CERTIFICATE_PUBLIC_KEY_ALGORITHM_NONE:
|
case ZT_CERTIFICATE_PUBLIC_KEY_ALGORITHM_NONE: break;
|
||||||
break;
|
|
||||||
case ZT_CERTIFICATE_PUBLIC_KEY_ALGORITHM_ECDSA_NIST_P_384:
|
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();
|
d.clear();
|
||||||
m_encodeSubject(this->subject, d, true);
|
m_encodeSubject(this->subject, d, true);
|
||||||
d.encode(enc);
|
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];
|
uint8_t h[ZT_SHA384_DIGEST_SIZE];
|
||||||
SHA384(h, enc.data(), (unsigned int)enc.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;
|
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;
|
return ZT_CERTIFICATE_ERROR_INVALID_UNIQUE_ID_PROOF;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
default:
|
default: return ZT_CERTIFICATE_ERROR_INVALID_UNIQUE_ID_PROOF;
|
||||||
return ZT_CERTIFICATE_ERROR_INVALID_UNIQUE_ID_PROOF;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
@ -534,7 +585,9 @@ ZT_CertificateError Certificate::verify(const int64_t clock, const bool checkSig
|
||||||
return ZT_CERTIFICATE_ERROR_NONE;
|
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) {
|
switch (type) {
|
||||||
case ZT_CERTIFICATE_PUBLIC_KEY_ALGORITHM_ECDSA_NIST_P_384:
|
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;
|
*publicKeySize = ZT_ECC384_PUBLIC_KEY_SIZE + 1;
|
||||||
*privateKeySize = 1 + ZT_ECC384_PUBLIC_KEY_SIZE + ZT_ECC384_PRIVATE_KEY_SIZE;
|
*privateKeySize = 1 + ZT_ECC384_PUBLIC_KEY_SIZE + ZT_ECC384_PRIVATE_KEY_SIZE;
|
||||||
return true;
|
return true;
|
||||||
default:
|
default: break;
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
return false;
|
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;
|
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 ((! certificatePrivateKey) || (certificatePrivateKeySize != (1 + ZT_ECC384_PUBLIC_KEY_SIZE + ZT_ECC384_PRIVATE_KEY_SIZE))
|
if ((!certificatePrivateKey)
|
||||||
|| (reinterpret_cast<const uint8_t*>(certificatePrivateKey)[0] != ZT_CERTIFICATE_PUBLIC_KEY_ALGORITHM_ECDSA_NIST_P_384))
|
|| (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;
|
return enc;
|
||||||
|
|
||||||
if (m_setSubjectUniqueId(sc, uniqueIdPrivate, uniqueIdPrivateSize)) {
|
if (m_setSubjectUniqueId(sc, uniqueIdPrivate, uniqueIdPrivateSize)) {
|
||||||
|
@ -568,7 +624,9 @@ Vector<uint8_t> Certificate::createCSR(const ZT_Certificate_Subject& s, const vo
|
||||||
|
|
||||||
uint8_t subjectHash[ZT_SHA384_DIGEST_SIZE], subjectSig[ZT_ECC384_SIGNATURE_SIZE];
|
uint8_t subjectHash[ZT_SHA384_DIGEST_SIZE], subjectSig[ZT_ECC384_SIGNATURE_SIZE];
|
||||||
SHA384(subjectHash, enc.data(), (unsigned int)enc.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.add("sS", subjectSig, ZT_ECC384_SIGNATURE_SIZE);
|
||||||
|
@ -594,11 +652,14 @@ void Certificate::m_clear()
|
||||||
m_extendedAttributes.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 (uniqueIdPrivateSize > 0) {
|
||||||
if ((uniqueIdPrivate != nullptr) && (uniqueIdPrivateSize == (1 + ZT_ECC384_PUBLIC_KEY_SIZE + ZT_ECC384_PRIVATE_KEY_SIZE))
|
if ((uniqueIdPrivate != nullptr)
|
||||||
&& (reinterpret_cast<const uint8_t*>(uniqueIdPrivate)[0] == (uint8_t)ZT_CERTIFICATE_PUBLIC_KEY_ALGORITHM_ECDSA_NIST_P_384)) {
|
&& (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);
|
Utils::copy<1 + ZT_ECC384_PUBLIC_KEY_SIZE>(s.uniqueId, uniqueIdPrivate);
|
||||||
s.uniqueIdSize = 1 + ZT_ECC384_PUBLIC_KEY_SIZE; // private is prefixed with public
|
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];
|
uint8_t h[ZT_SHA384_DIGEST_SIZE];
|
||||||
SHA384(h, enc.data(), (unsigned int)enc.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;
|
s.uniqueIdSignatureSize = ZT_ECC384_SIGNATURE_SIZE;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
@ -636,9 +699,13 @@ void Certificate::m_encodeSubject(const ZT_Certificate_Subject& s, Dictionary& d
|
||||||
d.add("s.i$", (uint64_t)s.identityCount);
|
d.add("s.i$", (uint64_t)s.identityCount);
|
||||||
for (unsigned int i = 0; i < s.identityCount; ++i) {
|
for (unsigned int i = 0; i < s.identityCount; ++i) {
|
||||||
if (s.identities[i].identity)
|
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)
|
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));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -61,11 +61,26 @@ class Certificate : public ZT_Certificate {
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return Serial number in a H384 object
|
||||||
|
*/
|
||||||
ZT_INLINE H384 getSerialNo() const noexcept
|
ZT_INLINE H384 getSerialNo() const noexcept
|
||||||
{
|
{
|
||||||
return H384(this->serialNo);
|
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
|
* Add a subject node/identity without a locator
|
||||||
*
|
*
|
||||||
|
|
815
core/ECC384.cpp
815
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
|
ZT_INLINE identityV0ProofOfWorkCriteria(unsigned char* restrict sb, char* restrict gm) noexcept
|
||||||
: digest(sb)
|
: digest(sb)
|
||||||
, genmem(gm)
|
, genmem(gm)
|
||||||
|
|
2027
core/Tests.cpp
2027
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;
|
Vector<Entry*> visited;
|
||||||
visited.reserve(8);
|
visited.reserve(8);
|
||||||
for (Map<H384, SharedPtr<Entry> >::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->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.
|
// Trace the path of each certificate all the way back to a trusted CA.
|
||||||
unsigned int pathLength = 0;
|
unsigned int pathLength = 0;
|
||||||
Map<H384, SharedPtr<Entry> >::const_iterator current(c);
|
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
|
// Repopulate mapping of subject unique IDs to their certificates, marking older
|
||||||
// certificates for the same subject as deprecated. A deprecated certificate is not invalid
|
// 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
|
#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
|
* Compute 32-bit FNV-1a checksum
|
||||||
*
|
*
|
||||||
|
|
|
@ -657,6 +657,11 @@ typedef struct {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Issuer certificate serial number.
|
* 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];
|
uint8_t issuer[ZT_CERTIFICATE_HASH_SIZE];
|
||||||
|
|
||||||
|
@ -673,7 +678,7 @@ typedef struct {
|
||||||
/**
|
/**
|
||||||
* Signature of subject with public key.
|
* 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.
|
* not modified in transit or by the signer.
|
||||||
*/
|
*/
|
||||||
uint8_t subjectSignature[ZT_CERTIFICATE_MAX_SIGNATURE_SIZE];
|
uint8_t subjectSignature[ZT_CERTIFICATE_MAX_SIGNATURE_SIZE];
|
||||||
|
|
|
@ -55,50 +55,6 @@ clock_serv_t OSUtils::s_machMonotonicClock = _machGetMonotonicClock();
|
||||||
|
|
||||||
#endif
|
#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> OSUtils::listDirectory(const char* path, bool includeDirectories)
|
||||||
{
|
{
|
||||||
Vector<String> r;
|
Vector<String> r;
|
||||||
|
|
|
@ -58,21 +58,19 @@ class OSUtils {
|
||||||
* @param ... Format arguments
|
* @param ... Format arguments
|
||||||
* @throws std::length_error buf[] too short (buf[] will still be left null-terminated)
|
* @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, ...);
|
static ZT_INLINE unsigned int ztsnprintf(char* buf, unsigned int len, const char* fmt, ...)
|
||||||
|
{
|
||||||
#ifdef __UNIX_LIKE__
|
va_list ap;
|
||||||
/**
|
va_start(ap, fmt);
|
||||||
* Close STDOUT_FILENO and STDERR_FILENO and replace them with output to given path
|
int n = (int)vsnprintf(buf, len, fmt, ap);
|
||||||
*
|
va_end(ap);
|
||||||
* This can be called after fork() and prior to exec() to suppress output
|
if ((n >= (int)len) || (n < 0)) {
|
||||||
* from a subprocess, such as auto-update.
|
if (len)
|
||||||
*
|
buf[len - 1] = (char)0;
|
||||||
* @param stdoutPath Path to file to use for stdout
|
throw std::length_error("buf[] overflow");
|
||||||
* @param stderrPath Path to file to use for stderr, or NULL for same as stdout (default)
|
}
|
||||||
* @return True on success
|
return (unsigned int)n;
|
||||||
*/
|
}
|
||||||
static bool redirectUnixOutputs(const char* stdoutPath, const char* stderrPath = nullptr);
|
|
||||||
#endif // __UNIX_LIKE__
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Delete a file
|
* Delete a file
|
||||||
|
|
|
@ -98,6 +98,25 @@ impl CertificateSerialNo {
|
||||||
pub fn is_nil(&self) -> bool {
|
pub fn is_nil(&self) -> bool {
|
||||||
is_all_zeroes(self.0)
|
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 {
|
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();
|
let mut cert: Vec<u8> = Vec::new();
|
||||||
cert.resize(16384, 0);
|
cert.resize(16384, 0);
|
||||||
let mut cert_size: c_int = 16384;
|
let mut cert_size: c_int = 16384;
|
||||||
|
@ -682,7 +701,7 @@ impl Certificate {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
cert.resize(cert_size as usize, 0);
|
cert.resize(cert_size as usize, 0);
|
||||||
return Ok(cert.into_boxed_slice());
|
return Ok(cert);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Sign this certificate, returning new signed certificate.
|
/// 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);
|
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).
|
/// Maximum UDP MTU (we never actually get this high).
|
||||||
pub const MAX_UDP_MTU: u32 = ztcore::ZT_MAX_UDP_MTU;
|
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 {
|
pub fn base64_encode<T: AsRef<[u8]>>(t: &T) -> String {
|
||||||
base64::encode_config(t, base64::URL_SAFE_NO_PAD)
|
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> {
|
pub fn base64_decode<T: AsRef<[u8]>>(t: &T) -> Result<Vec<u8>, base64::DecodeError> {
|
||||||
base64::decode_config(t, base64::URL_SAFE_NO_PAD)
|
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());
|
println!("ERROR: unable to read subject unique ID secret file: {}", b.err().unwrap().to_string());
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
let privk_hex = String::from_utf8(b.unwrap());
|
let privk_encoded = String::from_utf8(b.unwrap());
|
||||||
if privk_hex.is_err() {
|
if privk_encoded.is_err() {
|
||||||
println!("ERROR: invalid UTF-8 in secret");
|
println!("ERROR: invalid UTF-8 in secret");
|
||||||
return 1;
|
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() {
|
if privk.is_err() || privk.as_ref().unwrap().is_empty() {
|
||||||
println!("ERROR: invalid unique ID secret: {}", privk.err().unwrap().to_string());
|
println!("ERROR: invalid unique ID secret: {}", privk.err().unwrap().to_string());
|
||||||
return 1;
|
return 1;
|
||||||
|
@ -416,7 +417,7 @@ fn newcsr(cli_args: &ArgMatches) -> i32 {
|
||||||
1
|
1
|
||||||
}, |_| {
|
}, |_| {
|
||||||
let secret_path = cli_args.value_of("secretpath").unwrap();
|
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);
|
let _ = std::fs::remove_file(csr_path);
|
||||||
println!("ERROR: unable to write secret: {}", e.to_string());
|
println!("ERROR: unable to write secret: {}", e.to_string());
|
||||||
1
|
1
|
||||||
|
@ -429,8 +430,98 @@ fn newcsr(cli_args: &ArgMatches) -> i32 {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn sign<'a>(store: &Arc<Store>, cli_args: &ArgMatches<'a>) -> 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
|
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),
|
("delete", Some(sub_cli_args)) => delete(&store, sub_cli_args),
|
||||||
("factoryreset", None) => factoryreset(&store),
|
("factoryreset", None) => factoryreset(&store),
|
||||||
_ => {
|
_ => {
|
||||||
crate::print_help();
|
crate::print_help(true);
|
||||||
1
|
1
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -127,7 +127,7 @@ pub(crate) fn run<'a>(cli_args: &ArgMatches<'a>) -> i32 {
|
||||||
("sign", Some(sub_cli_args)) => sign(sub_cli_args),
|
("sign", Some(sub_cli_args)) => sign(sub_cli_args),
|
||||||
("verify", Some(sub_cli_args)) => verify(sub_cli_args),
|
("verify", Some(sub_cli_args)) => verify(sub_cli_args),
|
||||||
_ => {
|
_ => {
|
||||||
crate::print_help();
|
crate::print_help(true);
|
||||||
1
|
1
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -109,7 +109,7 @@ pub(crate) fn run(cli_args: &ArgMatches) -> i32 {
|
||||||
("verify", Some(sub_cli_args)) => verify(sub_cli_args),
|
("verify", Some(sub_cli_args)) => verify(sub_cli_args),
|
||||||
("show", Some(sub_cli_args)) => show(sub_cli_args),
|
("show", Some(sub_cli_args)) => show(sub_cli_args),
|
||||||
_ => {
|
_ => {
|
||||||
crate::print_help();
|
crate::print_help(true);
|
||||||
1
|
1
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,7 +16,8 @@ mod commands;
|
||||||
mod fastudpsocket;
|
mod fastudpsocket;
|
||||||
mod localconfig;
|
mod localconfig;
|
||||||
mod getifaddrs;
|
mod getifaddrs;
|
||||||
#[macro_use] mod log;
|
#[macro_use]
|
||||||
|
mod log;
|
||||||
mod store;
|
mod store;
|
||||||
mod network;
|
mod network;
|
||||||
mod vnic;
|
mod vnic;
|
||||||
|
@ -38,7 +39,7 @@ use crate::store::Store;
|
||||||
|
|
||||||
pub const HTTP_API_OBJECT_SIZE_LIMIT: usize = 131072;
|
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();
|
let ver = zerotier_core::version();
|
||||||
format!(r###"ZeroTier Network Hypervisor Service Version {}.{}.{}
|
format!(r###"ZeroTier Network Hypervisor Service Version {}.{}.{}
|
||||||
(c)2013-2021 ZeroTier, Inc.
|
(c)2013-2021 ZeroTier, Inc.
|
||||||
|
@ -56,6 +57,7 @@ Global Options:
|
||||||
Common Operations:
|
Common Operations:
|
||||||
|
|
||||||
help Show this help
|
help Show this help
|
||||||
|
longhelp Show help with advanced commands
|
||||||
oldhelp Show v1.x legacy commands
|
oldhelp Show v1.x legacy commands
|
||||||
version Print version (of this binary)
|
version Print version (of this binary)
|
||||||
|
|
||||||
|
@ -85,10 +87,11 @@ Common Operations:
|
||||||
· globalroutes <boolean> Can global IP routes be set?
|
· globalroutes <boolean> Can global IP routes be set?
|
||||||
· defaultroute <boolean> Can default route be overridden?
|
· defaultroute <boolean> Can default route be overridden?
|
||||||
|
|
||||||
· join [-...] <network> Join a virtual network
|
· join <network> Join a virtual network
|
||||||
-c <?identity | fingerprint> Controller identity / fingerprint
|
|
||||||
· leave <network> Leave a virtual network
|
· leave <network> Leave a virtual network
|
||||||
|
{}"###,
|
||||||
|
ver.0, ver.1, ver.2, if long_help {
|
||||||
|
r###"
|
||||||
Advanced Operations:
|
Advanced Operations:
|
||||||
|
|
||||||
service Start node
|
service Start node
|
||||||
|
@ -120,12 +123,27 @@ Advanced Operations:
|
||||||
· list List certificates at local node
|
· list List certificates at local node
|
||||||
show <@cert|·serial> Show certificate details
|
show <@cert|·serial> Show certificate details
|
||||||
newsuid [@secret out] Create a subject unique ID secret
|
newsuid [@secret out] Create a subject unique ID secret
|
||||||
newcsr <@csr> <@secret out> Create a CSR (interactive)
|
newcsr <@csr out> <@secret out> Create a CSR (interactive)
|
||||||
sign <@csr> <@secret> <@cert out> Sign a CSR to create a certificate
|
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
|
verify <@cert> Internally verify certificate
|
||||||
· import <@cert> [trust,trust,...] Import certificate into this node
|
· import <@cert> [trust,trust,...] Import certificate into this node
|
||||||
trust flag: rootca Root (or self-signed) CA
|
ca Trust: root CA or self-signed
|
||||||
trust flag: config Can influence node configuration
|
config Trust: node configuration
|
||||||
· export <serial> [@cert] Export a certificate from this node
|
· export <serial> [@cert] Export a certificate from this node
|
||||||
· delete <serial|ALL> Delete certificate from this node
|
· delete <serial|ALL> Delete certificate from this node
|
||||||
· factoryreset Re-import compiled-in default certs
|
· factoryreset Re-import compiled-in default certs
|
||||||
|
@ -133,11 +151,12 @@ Advanced Operations:
|
||||||
· Command (or command with argument type) requires a running node.
|
· Command (or command with argument type) requires a running node.
|
||||||
@ Argument is the path to a file containing the object.
|
@ Argument is the path to a file containing the object.
|
||||||
? Argument can be either the object or a path to it (auto-detected).
|
? 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() {
|
pub(crate) fn print_help(long_help: bool) {
|
||||||
let h = make_help();
|
let h = make_help(long_help);
|
||||||
let _ = std::io::stdout().write_all(h.as_bytes());
|
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))
|
Err(format!("invalid boolean value: '{}'", v))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
fn is_valid_bool(v: String) -> Result<(), String> {
|
fn is_valid_bool(v: String) -> Result<(), String> {
|
||||||
parse_bool(v.as_str()).map(|_| ())
|
parse_bool(v.as_str()).map(|_| ())
|
||||||
}
|
}
|
||||||
|
@ -188,7 +208,7 @@ fn get_global_flags(cli_args: &ArgMatches) -> GlobalFlags {
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
let cli_args = {
|
let cli_args = {
|
||||||
let help = make_help();
|
let help = make_help(false);
|
||||||
let args = App::new("zerotier")
|
let args = App::new("zerotier")
|
||||||
.arg(Arg::with_name("json").short("j"))
|
.arg(Arg::with_name("json").short("j"))
|
||||||
.arg(Arg::with_name("path").short("p").takes_value(true))
|
.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("setting").index(2).required(false))
|
||||||
.arg(Arg::with_name("value").index(3).required(false))))
|
.arg(Arg::with_name("value").index(3).required(false))))
|
||||||
.subcommand(App::new("join")
|
.subcommand(App::new("join")
|
||||||
.arg(Arg::with_name("controller").short("c").takes_value(true))
|
|
||||||
.arg(Arg::with_name("nwid").index(1).required(true)))
|
.arg(Arg::with_name("nwid").index(1).required(true)))
|
||||||
.subcommand(App::new("leave")
|
.subcommand(App::new("leave")
|
||||||
.arg(Arg::with_name("nwid").index(1).required(true)))
|
.arg(Arg::with_name("nwid").index(1).required(true)))
|
||||||
|
@ -282,8 +301,13 @@ fn main() {
|
||||||
.arg(Arg::with_name("secretpath").index(2).required(true)))
|
.arg(Arg::with_name("secretpath").index(2).required(true)))
|
||||||
.subcommand(App::new("sign")
|
.subcommand(App::new("sign")
|
||||||
.arg(Arg::with_name("csr").index(1).required(true))
|
.arg(Arg::with_name("csr").index(1).required(true))
|
||||||
.arg(Arg::with_name("secretpath").index(2).required(true))
|
.arg(Arg::with_name("certout").index(2).required(true))
|
||||||
.arg(Arg::with_name("output").index(3).required(false)))
|
.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")
|
.subcommand(App::new("verify")
|
||||||
.arg(Arg::with_name("cert").index(1).required(true)))
|
.arg(Arg::with_name("cert").index(1).required(true)))
|
||||||
.subcommand(App::new("dump")
|
.subcommand(App::new("dump")
|
||||||
|
@ -302,13 +326,13 @@ fn main() {
|
||||||
if args.is_err() {
|
if args.is_err() {
|
||||||
let e = args.err().unwrap();
|
let e = args.err().unwrap();
|
||||||
if e.kind != ErrorKind::HelpDisplayed {
|
if e.kind != ErrorKind::HelpDisplayed {
|
||||||
print_help();
|
print_help(false);
|
||||||
}
|
}
|
||||||
std::process::exit(1);
|
std::process::exit(1);
|
||||||
}
|
}
|
||||||
let args = args.unwrap();
|
let args = args.unwrap();
|
||||||
if args.subcommand_name().is_none() {
|
if args.subcommand_name().is_none() {
|
||||||
print_help();
|
print_help(false);
|
||||||
std::process::exit(1);
|
std::process::exit(1);
|
||||||
}
|
}
|
||||||
args
|
args
|
||||||
|
@ -316,36 +340,40 @@ fn main() {
|
||||||
|
|
||||||
std::process::exit({
|
std::process::exit({
|
||||||
match cli_args.subcommand() {
|
match cli_args.subcommand() {
|
||||||
("help", _) => {
|
("help", None) => {
|
||||||
print_help();
|
print_help(false);
|
||||||
0
|
0
|
||||||
}
|
}
|
||||||
("oldhelp", _) => {
|
("longhelp", None) => {
|
||||||
|
print_help(true);
|
||||||
|
0
|
||||||
|
}
|
||||||
|
("oldhelp", None) => {
|
||||||
// TODO
|
// TODO
|
||||||
0
|
0
|
||||||
}
|
}
|
||||||
("version", _) => {
|
("version", None) => {
|
||||||
let ver = zerotier_core::version();
|
let ver = zerotier_core::version();
|
||||||
println!("{}.{}.{}", ver.0, ver.1, ver.2);
|
println!("{}.{}.{}", ver.0, ver.1, ver.2);
|
||||||
0
|
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 }
|
("set", Some(sub_cli_args)) => { 0 }
|
||||||
("peer", Some(sub_cli_args)) => { 0 }
|
("peer", Some(sub_cli_args)) => { 0 }
|
||||||
("network", Some(sub_cli_args)) => { 0 }
|
("network", Some(sub_cli_args)) => { 0 }
|
||||||
("join", Some(sub_cli_args)) => { 0 }
|
("join", Some(sub_cli_args)) => { 0 }
|
||||||
("leave", Some(sub_cli_args)) => { 0 }
|
("leave", Some(sub_cli_args)) => { 0 }
|
||||||
("service", _) => {
|
("service", None) => {
|
||||||
let store = make_store(&cli_args);
|
let store = make_store(&cli_args);
|
||||||
drop(cli_args); // free no longer needed memory before entering service
|
drop(cli_args); // free no longer needed memory before entering service
|
||||||
service::run(store)
|
service::run(store)
|
||||||
},
|
}
|
||||||
("controller", Some(sub_cli_args)) => { 0 }
|
("controller", Some(sub_cli_args)) => { 0 }
|
||||||
("identity", Some(sub_cli_args)) => crate::commands::identity::run(sub_cli_args),
|
("identity", Some(sub_cli_args)) => crate::commands::identity::run(sub_cli_args),
|
||||||
("locator", Some(sub_cli_args)) => crate::commands::locator::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),
|
("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
|
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,
|
/// 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.
|
/// the client and server may check the age of a digest auth exchange.
|
||||||
pub(crate) fn create_http_auth_nonce(timestamp: i64) -> String {
|
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 {
|
unsafe {
|
||||||
osdep::encryptHttpAuthNonce(nonce_plaintext.as_mut_ptr().cast());
|
osdep::encryptHttpAuthNonce(nonce_plaintext.as_mut_ptr().cast());
|
||||||
hex::encode(*nonce_plaintext.as_ptr().cast::<[u8; 16]>())
|
hex::encode(*nonce_plaintext.as_ptr().cast::<[u8; 16]>())
|
||||||
|
@ -109,19 +109,20 @@ pub(crate) fn create_http_auth_nonce(timestamp: i64) -> String {
|
||||||
/// This returns zero if the input was not valid.
|
/// This returns zero if the input was not valid.
|
||||||
pub(crate) fn decrypt_http_auth_nonce(nonce: &str) -> i64 {
|
pub(crate) fn decrypt_http_auth_nonce(nonce: &str) -> i64 {
|
||||||
let nonce = hex::decode(nonce.trim());
|
let nonce = hex::decode(nonce.trim());
|
||||||
if nonce.is_err() {
|
if !nonce.is_err() {
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
let mut nonce = nonce.unwrap();
|
let mut nonce = nonce.unwrap();
|
||||||
if nonce.len() != 16 {
|
if nonce.len() == 16 {
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
unsafe {
|
unsafe {
|
||||||
osdep::decryptHttpAuthNonce(nonce.as_mut_ptr().cast());
|
osdep::decryptHttpAuthNonce(nonce.as_mut_ptr().cast());
|
||||||
let nonce = *nonce.as_ptr().cast::<[u64; 2]>();
|
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.
|
/// Shortcut to use serde_json to serialize an object, returns "null" on error.
|
||||||
pub(crate) fn to_json<O: serde::Serialize>(o: &O) -> String {
|
pub(crate) fn to_json<O: serde::Serialize>(o: &O) -> String {
|
||||||
|
|
|
@ -11,7 +11,7 @@
|
||||||
*/
|
*/
|
||||||
/****/
|
/****/
|
||||||
|
|
||||||
use std::collections::BTreeSet;
|
use std::collections::HashSet;
|
||||||
|
|
||||||
#[allow(unused_imports)]
|
#[allow(unused_imports)]
|
||||||
use zerotier_core::{MAC, MulticastGroup};
|
use zerotier_core::{MAC, MulticastGroup};
|
||||||
|
@ -21,8 +21,8 @@ use num_traits::AsPrimitive;
|
||||||
|
|
||||||
/// BSD based OSes support getifmaddrs().
|
/// 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"))]
|
#[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> {
|
pub(crate) fn get_l2_multicast_subscriptions(dev: &str) -> HashSet<MulticastGroup> {
|
||||||
let mut groups: BTreeSet<MulticastGroup> = BTreeSet::new();
|
let mut groups: HashSet<MulticastGroup> = HashSet::new();
|
||||||
let dev = dev.as_bytes();
|
let dev = dev.as_bytes();
|
||||||
unsafe {
|
unsafe {
|
||||||
let mut maddrs: *mut osdep::ifmaddrs = std::ptr::null_mut();
|
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.
|
/// Linux stores this stuff in /proc and it needs to be fetched from there.
|
||||||
#[cfg(target_os = "linux")]
|
#[cfg(target_os = "linux")]
|
||||||
pub(crate) fn get_l2_multicast_subscriptions(dev: &str) -> BTreeSet<MulticastGroup> {
|
pub(crate) fn get_l2_multicast_subscriptions(dev: &str) -> HashSet<MulticastGroup> {
|
||||||
let mut groups: BTreeSet<MulticastGroup> = BTreeSet::new();
|
let mut groups: HashSet<MulticastGroup> = HashSet::new();
|
||||||
groups
|
groups
|
||||||
}
|
}
|
||||||
|
|
|
@ -36,7 +36,7 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
use std::cell::Cell;
|
use std::cell::Cell;
|
||||||
use std::collections::BTreeSet;
|
use std::collections::HashSet;
|
||||||
use std::error::Error;
|
use std::error::Error;
|
||||||
use std::ffi::CString;
|
use std::ffi::CString;
|
||||||
use std::ptr::{null_mut, copy_nonoverlapping};
|
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::osdep as osdep;
|
||||||
use crate::getifaddrs;
|
use crate::getifaddrs;
|
||||||
use crate::vnic::VNIC;
|
use crate::vnic::vnic::VNIC;
|
||||||
use crate::osdep::getifmaddrs;
|
use crate::osdep::getifmaddrs;
|
||||||
|
|
||||||
const BPF_BUFFER_SIZE: usize = 131072;
|
const BPF_BUFFER_SIZE: usize = 131072;
|
||||||
|
@ -423,7 +423,7 @@ impl VNIC for MacFethTap {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline(always)]
|
#[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())
|
crate::vnic::common::get_l2_multicast_subscriptions(self.device.name.as_str())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Add table
Reference in a new issue