CGO glue for certificates, and Go formatting and other boring stuff.

This commit is contained in:
Adam Ierymenko 2020-07-03 13:08:40 -07:00
parent 899f0c9749
commit 0d764f5a3d
No known key found for this signature in database
GPG key ID: C8877CF2D7A5D7F3
27 changed files with 276 additions and 49 deletions

View file

@ -81,7 +81,7 @@ Commands:
verify <identity> <file> <sig> Verify a signature
certificate <command> [args] - Certificate commands
newid Create a new unique subject ID
newcsr <settings path> Create a new CSR (signing request)
newcsr <subject json path> Create a new CSR (signing request)
sign <csr path> <identity path> Sign a CSR to create a certificate
verify <certificate> Verify a certificate
show List certificate for current node

View file

@ -50,8 +50,8 @@ Certificate &Certificate::operator=(const ZT_Certificate &cert)
this->subject.networkCount = 0;
this->subject.certificates = nullptr;
this->subject.certificateCount = 0;
this->subject.updateUrls = nullptr;
this->subject.updateUrlCount = 0;
this->subject.updateURLs = nullptr;
this->subject.updateURLCount = 0;
this->subject.uniqueId = nullptr;
this->subject.uniqueIdProofSignature = nullptr;
this->subject.uniqueIdSize = 0;
@ -80,10 +80,10 @@ Certificate &Certificate::operator=(const ZT_Certificate &cert)
addSubjectCertificate(cert.subject.certificates[i]);
}
if (cert.subject.updateUrls) {
for (unsigned int i = 0; i < cert.subject.updateUrlCount; ++i) {
if (cert.subject.updateUrls[i])
addSubjectUpdateUrl(cert.subject.updateUrls[i]);
if (cert.subject.updateURLs) {
for (unsigned int i = 0; i < cert.subject.updateURLCount; ++i) {
if (cert.subject.updateURLs[i])
addSubjectUpdateUrl(cert.subject.updateURLs[i]);
}
}
@ -181,8 +181,8 @@ void Certificate::addSubjectUpdateUrl(const char *url)
// Add pointer to local copy to pointer array and update C structure to point to
// potentially reallocated array.
m_updateUrls.push_back(m_strings.back().c_str());
this->subject.updateUrls = m_updateUrls.data();
this->subject.updateUrlCount = (unsigned int)m_updateUrls.size();
this->subject.updateURLs = m_updateUrls.data();
this->subject.updateURLCount = (unsigned int)m_updateUrls.size();
}
void Certificate::setExtendedAttributes(const Dictionary &x)
@ -456,14 +456,14 @@ ZT_CertificateError Certificate::verify() const
return ZT_CERTIFICATE_ERROR_MISSING_REQUIRED_FIELDS;
}
if (this->subject.updateUrlCount) {
if (!this->subject.updateUrls)
if (this->subject.updateURLCount) {
if (!this->subject.updateURLs)
return ZT_CERTIFICATE_ERROR_INVALID_FORMAT;
for (unsigned int i = 0; i < this->subject.updateUrlCount; ++i) {
if (!this->subject.updateUrls[i])
for (unsigned int i = 0; i < this->subject.updateURLCount; ++i) {
if (!this->subject.updateURLs[i])
return ZT_CERTIFICATE_ERROR_MISSING_REQUIRED_FIELDS;
}
} else if (this->subject.updateUrls) {
} else if (this->subject.updateURLs) {
return ZT_CERTIFICATE_ERROR_INVALID_FORMAT;
}
} catch (...) {}
@ -538,10 +538,10 @@ void Certificate::m_encodeSubject(const ZT_Certificate_Subject &s, Dictionary &d
d[Dictionary::arraySubscript(tmp, "s.c$", i)].assign(s.certificates[i], s.certificates[i] + ZT_SHA384_DIGEST_SIZE);
}
d.add("s.u$", (uint64_t)s.updateUrlCount);
if (s.updateUrls) {
for (unsigned int i = 0; i < s.updateUrlCount; ++i)
d.add(Dictionary::arraySubscript(tmp, "s.u$", i), s.updateUrls[i]);
d.add("s.u$", (uint64_t)s.updateURLCount);
if (s.updateURLs) {
for (unsigned int i = 0; i < s.updateURLCount; ++i)
d.add(Dictionary::arraySubscript(tmp, "s.u$", i), s.updateURLs[i]);
}
if (s.name.country[0])

View file

@ -272,7 +272,7 @@ static bool ZTT_deepCompareCertificates(const Certificate &a, const Certificate
(a.subject.timestamp != b.subject.timestamp) ||
(a.subject.identityCount != b.subject.identityCount) ||
(a.subject.networkCount != b.subject.networkCount) ||
(a.subject.updateUrlCount != b.subject.updateUrlCount) ||
(a.subject.updateURLCount != b.subject.updateURLCount) ||
(a.subject.uniqueIdSize != b.subject.uniqueIdSize) ||
(a.subject.uniqueIdProofSignatureSize != b.subject.uniqueIdProofSignatureSize) ||
(a.maxPathLength != b.maxPathLength) ||
@ -324,12 +324,12 @@ static bool ZTT_deepCompareCertificates(const Certificate &a, const Certificate
return false;
}
for(unsigned int i=0;i<a.subject.updateUrlCount;++i) {
if ((!a.subject.updateUrls) || (!b.subject.updateUrls))
for(unsigned int i=0;i<a.subject.updateURLCount; ++i) {
if ((!a.subject.updateURLs) || (!b.subject.updateURLs))
return false;
if ((!a.subject.updateUrls[i]) || (!b.subject.updateUrls[i]))
if ((!a.subject.updateURLs[i]) || (!b.subject.updateURLs[i]))
return false;
if (strcmp(a.subject.updateUrls[i], b.subject.updateUrls[i]) != 0)
if (strcmp(a.subject.updateURLs[i], b.subject.updateURLs[i]) != 0)
return false;
}

View file

@ -467,7 +467,7 @@ typedef struct
/**
* URLs that can be consulted for updates to this certificate.
*/
const char *const *updateUrls;
const char *const *updateURLs;
/**
* Number of identities
@ -487,7 +487,7 @@ typedef struct
/**
* Number of update URLs
*/
unsigned int updateUrlCount;
unsigned int updateURLCount;
/**
* Information about owner of items.
@ -581,7 +581,7 @@ typedef struct
/**
* Extended attributes set by issuer (in Dictionary format, NULL if none)
*/
uint8_t *extendedAttributes;
const uint8_t *extendedAttributes;
/**
* Size of extended attributes field in bytes
@ -2702,7 +2702,7 @@ ZT_SDK_API void ZT_Locator_delete(ZT_Locator *loc);
/* ---------------------------------------------------------------------------------------------------------------- */
/**
* Get ZeroTier One version
* Get ZeroTier core version
*
* @param major Result: major version
* @param minor Result: minor version

View file

@ -1,5 +1,5 @@
/*
* Copyright (c)2013-2020 ZeroTier, Inc.
* Copyright (C)2013-2020 ZeroTier, Inc.
*
* Use of this software is governed by the Business Source License included
* in the LICENSE.TXT file in the project's root directory.

View file

@ -1,5 +1,5 @@
/*
* Copyright (c)2013-2020 ZeroTier, Inc.
* Copyright (C)2013-2020 ZeroTier, Inc.
*
* Use of this software is governed by the Business Source License included
* in the LICENSE.TXT file in the project's root directory.

203
pkg/zerotier/certificate.go Normal file
View file

@ -0,0 +1,203 @@
/*
* Copyright (C)2013-2020 ZeroTier, Inc.
*
* Use of this software is governed by the Business Source License included
* in the LICENSE.TXT file in the project's root directory.
*
* Change Date: 2024-01-01
*
* On the date above, in accordance with the Business Source License, use
* of this software will be governed by version 2.0 of the Apache License.
*/
/****/
package zerotier
// #include "../../serviceiocore/GoGlue.h"
import "C"
import (
"unsafe"
)
const (
CertificateSerialNoSize = 48
CertificateMaxStringLength = int(C.ZT_CERTIFICATE_MAX_STRING_LENGTH)
)
type CertificateName struct {
SerialNo string `json:"serialNo,omitempty"`
CommonName string `json:"commonName,omitempty"`
StreetAddress string `json:"streetAddress,omitempty"`
Locality string `json:"locality,omitempty"`
Province string `json:"province,omitempty"`
PostalCode string `json:"postalCode,omitempty"`
Country string `json:"country,omitempty"`
Organization string `json:"organization,omitempty"`
Unit string `json:"unit,omitempty"`
Email string `json:"email,omitempty"`
URL string `json:"url,omitempty"`
Host string `json:"host,omitempty"`
}
type CertificateIdentity struct {
Identity *Identity `json:"identity"`
Locator *Locator `json:"locator,omitempty"`
}
type CertificateNetwork struct {
ID uint64 `json:"id"`
Controller *Fingerprint `json:"controller"`
}
type CertificateSubject struct {
Timestamp int64 `json:"timestamp"`
Identities []CertificateIdentity `json:"identities,omitempty"`
Networks []CertificateNetwork `json:"networks,omitempty"`
Certificates [][CertificateSerialNoSize]byte `json:"certificates,omitempty"`
UpdateURLs []string `json:"updateURLs,omitempty"`
Name CertificateName `json:"name"`
UniqueID []byte `json:"uniqueId,omitempty"`
UniqueIDProofSignature []byte `json:"uniqueIdProofSignature,omitempty"`
}
type Certificate struct {
SerialNo []byte `json:"serialNo,omitempty"`
Flags uint64 `json:"flags"`
Timestamp int64 `json:"timestamp"`
Validity [2]int64 `json:"validity"`
Subject CertificateSubject `json:"subject"`
Issuer *Identity `json:"issuer,omitempty"`
IssuerName CertificateName `json:"issuerName"`
ExtendedAttributes []byte `json:"extendedAttributes,omitempty"`
MaxPathLength uint `json:"maxPathLength,omitempty"`
Signature []byte `json:"signature,omitempty"`
}
type cCertificate struct {
C C.ZT_Certificate
internalSubjectIdentities []C.ZT_Certificate_Identity
internalSubjectNetworks []C.ZT_Certificate_Network
internalSubjectUpdateURLs []*C.char
internalSubjectUpdateURLsData [][]byte
}
// cCertificate creates a C ZT_Certificate structure
// The returned Go structure bundles this with some objects that have
// to be created to set their pointers in ZT_Certificate. It's easier to
// manage allocation of these in Go and bundle them so Go's GC will clean
// them up automatically when cCertificate is releaed. Only the 'C' field
// in cCertificate should be directly used.
func (c *Certificate) cCertificate() *cCertificate {
var cc cCertificate
if len(c.SerialNo) == 48 {
copy((*[48]byte)(unsafe.Pointer(&cc.C.serialNo[0]))[:], c.SerialNo[:])
}
cc.C.flags = C.uint64_t(c.Flags)
cc.C.timestamp = C.int64_t(c.Timestamp)
cc.C.validity[0] = C.int64_t(c.Validity[0])
cc.C.validity[1] = C.int64_t(c.Validity[1])
cc.C.subject.timestamp = C.int64_t(c.Subject.Timestamp)
if len(c.Subject.Identities) > 0 {
cc.internalSubjectIdentities = make([]C.ZT_Certificate_Identity, len(c.Subject.Identities))
for i, id := range c.Subject.Identities {
if id.Identity == nil || !id.Identity.initCIdentityPtr() {
return nil
}
cc.internalSubjectIdentities[i].identity = id.Identity.cid
if id.Locator != nil {
cc.internalSubjectIdentities[i].locator = id.Locator.cl
}
}
cc.C.subject.identities = &cc.internalSubjectIdentities[0]
cc.C.subject.identityCount = C.uint(len(c.Subject.Identities))
}
if len(c.Subject.Networks) > 0 {
cc.internalSubjectNetworks = make([]C.ZT_Certificate_Network, len(c.Subject.Networks))
for i, n := range c.Subject.Networks {
cc.internalSubjectNetworks[i].id = C.uint64_t(n.ID)
cc.internalSubjectNetworks[i].controller.address = C.uint64_t(n.Controller.Address)
if len(n.Controller.Hash) == 48 {
copy((*[48]byte)(unsafe.Pointer(&cc.internalSubjectNetworks[i].controller.hash[0]))[:], n.Controller.Hash)
}
}
cc.C.subject.networks = &cc.internalSubjectNetworks[0]
cc.C.subject.networkCount = C.uint(len(c.Subject.Networks))
}
if len(c.Subject.Certificates) > 0 {
cc.C.subject.certificates = (**C.uint8_t)(unsafe.Pointer(&c.Subject.Certificates[0]))
cc.C.subject.certificateCount = C.uint(len(c.Subject.Certificates))
}
if len(c.Subject.UpdateURLs) > 0 {
cc.internalSubjectUpdateURLs = make([]*C.char, len(c.Subject.UpdateURLs))
cc.internalSubjectUpdateURLsData = make([][]byte, len(c.Subject.UpdateURLs))
for i, u := range c.Subject.UpdateURLs {
cc.internalSubjectUpdateURLsData[i] = stringAsZeroTerminatedBytes(u)
cc.internalSubjectUpdateURLs[i] = (*C.char)(unsafe.Pointer(&cc.internalSubjectUpdateURLsData[0]))
}
cc.C.subject.updateURLs = (**C.char)(unsafe.Pointer(&cc.internalSubjectUpdateURLs[0]))
cc.C.subject.updateURLCount = C.uint(len(c.Subject.UpdateURLs))
}
cStrCopy(unsafe.Pointer(&cc.C.subject.name.serialNo[0]), CertificateMaxStringLength+1, c.Subject.Name.SerialNo)
cStrCopy(unsafe.Pointer(&cc.C.subject.name.commonName[0]), CertificateMaxStringLength+1, c.Subject.Name.CommonName)
cStrCopy(unsafe.Pointer(&cc.C.subject.name.country[0]), CertificateMaxStringLength+1, c.Subject.Name.Country)
cStrCopy(unsafe.Pointer(&cc.C.subject.name.organization[0]), CertificateMaxStringLength+1, c.Subject.Name.Organization)
cStrCopy(unsafe.Pointer(&cc.C.subject.name.unit[0]), CertificateMaxStringLength+1, c.Subject.Name.Unit)
cStrCopy(unsafe.Pointer(&cc.C.subject.name.locality[0]), CertificateMaxStringLength+1, c.Subject.Name.Locality)
cStrCopy(unsafe.Pointer(&cc.C.subject.name.province[0]), CertificateMaxStringLength+1, c.Subject.Name.Province)
cStrCopy(unsafe.Pointer(&cc.C.subject.name.streetAddress[0]), CertificateMaxStringLength+1, c.Subject.Name.StreetAddress)
cStrCopy(unsafe.Pointer(&cc.C.subject.name.postalCode[0]), CertificateMaxStringLength+1, c.Subject.Name.PostalCode)
cStrCopy(unsafe.Pointer(&cc.C.subject.name.email[0]), CertificateMaxStringLength+1, c.Subject.Name.Email)
cStrCopy(unsafe.Pointer(&cc.C.subject.name.url[0]), CertificateMaxStringLength+1, c.Subject.Name.URL)
cStrCopy(unsafe.Pointer(&cc.C.subject.name.host[0]), CertificateMaxStringLength+1, c.Subject.Name.Host)
if len(c.Subject.UniqueID) > 0 {
cc.C.subject.uniqueId = (*C.uint8_t)(unsafe.Pointer(&c.Subject.UniqueID[0]))
cc.C.subject.uniqueIdSize = C.uint(len(c.Subject.UniqueID))
if len(c.Subject.UniqueIDProofSignature) > 0 {
cc.C.subject.uniqueIdProofSignature = (*C.uint8_t)(unsafe.Pointer(&c.Subject.UniqueIDProofSignature[0]))
cc.C.subject.uniqueIdProofSignatureSize = C.uint(len(c.Subject.UniqueIDProofSignature))
}
}
if c.Issuer != nil {
if !c.Issuer.initCIdentityPtr() {
return nil
}
cc.C.issuer = c.Issuer.cid
}
cStrCopy(unsafe.Pointer(&cc.C.issuerName.serialNo[0]), CertificateMaxStringLength+1, c.IssuerName.SerialNo)
cStrCopy(unsafe.Pointer(&cc.C.issuerName.commonName[0]), CertificateMaxStringLength+1, c.IssuerName.CommonName)
cStrCopy(unsafe.Pointer(&cc.C.issuerName.country[0]), CertificateMaxStringLength+1, c.IssuerName.Country)
cStrCopy(unsafe.Pointer(&cc.C.issuerName.organization[0]), CertificateMaxStringLength+1, c.IssuerName.Organization)
cStrCopy(unsafe.Pointer(&cc.C.issuerName.unit[0]), CertificateMaxStringLength+1, c.IssuerName.Unit)
cStrCopy(unsafe.Pointer(&cc.C.issuerName.locality[0]), CertificateMaxStringLength+1, c.IssuerName.Locality)
cStrCopy(unsafe.Pointer(&cc.C.issuerName.province[0]), CertificateMaxStringLength+1, c.IssuerName.Province)
cStrCopy(unsafe.Pointer(&cc.C.issuerName.streetAddress[0]), CertificateMaxStringLength+1, c.IssuerName.StreetAddress)
cStrCopy(unsafe.Pointer(&cc.C.issuerName.postalCode[0]), CertificateMaxStringLength+1, c.IssuerName.PostalCode)
cStrCopy(unsafe.Pointer(&cc.C.issuerName.email[0]), CertificateMaxStringLength+1, c.IssuerName.Email)
cStrCopy(unsafe.Pointer(&cc.C.issuerName.url[0]), CertificateMaxStringLength+1, c.IssuerName.URL)
cStrCopy(unsafe.Pointer(&cc.C.issuerName.host[0]), CertificateMaxStringLength+1, c.IssuerName.Host)
if len(c.ExtendedAttributes) > 0 {
cc.C.extendedAttributes = (*C.uint8_t)(unsafe.Pointer(&c.ExtendedAttributes[0]))
cc.C.extendedAttributesSize = C.uint(len(c.ExtendedAttributes))
}
cc.C.maxPathLength = C.uint(c.MaxPathLength)
if len(c.Signature) > 0 {
cc.C.signature = (*C.uint8_t)(unsafe.Pointer(&c.Signature[0]))
cc.C.signatureSize = C.uint(len(c.Signature))
}
return &cc
}

View file

@ -1,5 +1,5 @@
/*
* Copyright (c)2013-2020 ZeroTier, Inc.
* Copyright (C)2013-2020 ZeroTier, Inc.
*
* Use of this software is governed by the Business Source License included
* in the LICENSE.TXT file in the project's root directory.

View file

@ -1,5 +1,5 @@
/*
* Copyright (c)2013-2020 ZeroTier, Inc.
* Copyright (C)2013-2020 ZeroTier, Inc.
*
* Use of this software is governed by the Business Source License included
* in the LICENSE.TXT file in the project's root directory.

View file

@ -1,5 +1,5 @@
/*
* Copyright (c)2013-2020 ZeroTier, Inc.
* Copyright (C)2013-2020 ZeroTier, Inc.
*
* Use of this software is governed by the Business Source License included
* in the LICENSE.TXT file in the project's root directory.

View file

@ -1,5 +1,5 @@
/*
* Copyright (c)2013-2020 ZeroTier, Inc.
* Copyright (C)2013-2020 ZeroTier, Inc.
*
* Use of this software is governed by the Business Source License included
* in the LICENSE.TXT file in the project's root directory.

View file

@ -1,5 +1,5 @@
/*
* Copyright (c)2013-2020 ZeroTier, Inc.
* Copyright (C)2013-2020 ZeroTier, Inc.
*
* Use of this software is governed by the Business Source License included
* in the LICENSE.TXT file in the project's root directory.

View file

@ -1,5 +1,5 @@
/*
* Copyright (c)2013-2020 ZeroTier, Inc.
* Copyright (C)2013-2020 ZeroTier, Inc.
*
* Use of this software is governed by the Business Source License included
* in the LICENSE.TXT file in the project's root directory.

View file

@ -1,5 +1,5 @@
/*
* Copyright (c)2013-2020 ZeroTier, Inc.
* Copyright (C)2013-2020 ZeroTier, Inc.
*
* Use of this software is governed by the Business Source License included
* in the LICENSE.TXT file in the project's root directory.

View file

@ -1,5 +1,5 @@
/*
* Copyright (c)2013-2020 ZeroTier, Inc.
* Copyright (C)2013-2020 ZeroTier, Inc.
*
* Use of this software is governed by the Business Source License included
* in the LICENSE.TXT file in the project's root directory.

View file

@ -1,5 +1,5 @@
/*
* Copyright (c)2013-2020 ZeroTier, Inc.
* Copyright (C)2013-2020 ZeroTier, Inc.
*
* Use of this software is governed by the Business Source License included
* in the LICENSE.TXT file in the project's root directory.
@ -259,3 +259,27 @@ func ipClassify(ip net.IP) int {
return ipClassificationNone
}
// stringAsZeroTerminatedBytes creates a C string but as a Go []byte
func stringAsZeroTerminatedBytes(s string) (b []byte) {
if len(s) == 0 {
b = []byte{0} // single zero
return
}
sb := []byte(s)
b = make([]byte, len(sb) + 1)
copy(b, sb)
// make() will zero memory, so b[len(sb)+1] will be 0
return
}
// cStrCopy copies src into dest as a zero-terminated C string
func cStrCopy(dest unsafe.Pointer, destSize int, src string) {
sb := []byte(src)
b := C.GoBytes(dest, C.int(destSize))
if len(sb) > (destSize - 1) {
sb = sb[0:destSize - 1]
}
copy(b[:], sb[:])
b[len(sb)] = 0
}

View file

@ -1,5 +1,5 @@
/*
* Copyright (c)2013-2020 ZeroTier, Inc.
* Copyright (C)2013-2020 ZeroTier, Inc.
*
* Use of this software is governed by the Business Source License included
* in the LICENSE.TXT file in the project's root directory.

View file

@ -1,5 +1,5 @@
/*
* Copyright (c)2013-2020 ZeroTier, Inc.
* Copyright (C)2013-2020 ZeroTier, Inc.
*
* Use of this software is governed by the Business Source License included
* in the LICENSE.TXT file in the project's root directory.

View file

@ -1,5 +1,5 @@
/*
* Copyright (c)2013-2020 ZeroTier, Inc.
* Copyright (C)2013-2020 ZeroTier, Inc.
*
* Use of this software is governed by the Business Source License included
* in the LICENSE.TXT file in the project's root directory.

View file

@ -1,5 +1,5 @@
/*
* Copyright (c)2013-2020 ZeroTier, Inc.
* Copyright (C)2013-2020 ZeroTier, Inc.
*
* Use of this software is governed by the Business Source License included
* in the LICENSE.TXT file in the project's root directory.

View file

@ -1,7 +1,7 @@
// +build !windows
/*
* Copyright (c)2013-2020 ZeroTier, Inc.
* Copyright (C)2013-2020 ZeroTier, Inc.
*
* Use of this software is governed by the Business Source License included
* in the LICENSE.TXT file in the project's root directory.

View file

@ -1,7 +1,7 @@
// +build windows
/*
* Copyright (c)2013-2020 ZeroTier, Inc.
* Copyright (C)2013-2020 ZeroTier, Inc.
*
* Use of this software is governed by the Business Source License included
* in the LICENSE.TXT file in the project's root directory.

View file

@ -1,5 +1,5 @@
/*
* Copyright (c)2013-2020 ZeroTier, Inc.
* Copyright (C)2013-2020 ZeroTier, Inc.
*
* Use of this software is governed by the Business Source License included
* in the LICENSE.TXT file in the project's root directory.

View file

@ -1,5 +1,5 @@
/*
* Copyright (c)2013-2020 ZeroTier, Inc.
* Copyright (C)2013-2020 ZeroTier, Inc.
*
* Use of this software is governed by the Business Source License included
* in the LICENSE.TXT file in the project's root directory.

View file

@ -1,5 +1,5 @@
/*
* Copyright (c)2013-2020 ZeroTier, Inc.
* Copyright (C)2013-2020 ZeroTier, Inc.
*
* Use of this software is governed by the Business Source License included
* in the LICENSE.TXT file in the project's root directory.

View file

@ -1,5 +1,5 @@
/*
* Copyright (c)2013-2020 ZeroTier, Inc.
* Copyright (C)2013-2020 ZeroTier, Inc.
*
* Use of this software is governed by the Business Source License included
* in the LICENSE.TXT file in the project's root directory.

View file

@ -1,5 +1,5 @@
/*
* Copyright (c)2013-2020 ZeroTier, Inc.
* Copyright (C)2013-2020 ZeroTier, Inc.
*
* Use of this software is governed by the Business Source License included
* in the LICENSE.TXT file in the project's root directory.