mirror of
https://github.com/zerotier/ZeroTierOne.git
synced 2025-06-08 21:43:44 +02:00
550 lines
22 KiB
Go
550 lines
22 KiB
Go
/*
|
|
* 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: 2025-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"
|
|
// static inline void *_ZT_Certificate_clone2(uintptr_t p) { return (void *)ZT_Certificate_clone((const ZT_Certificate *)p); }
|
|
import "C"
|
|
|
|
import (
|
|
"encoding/json"
|
|
"fmt"
|
|
"unsafe"
|
|
)
|
|
|
|
const (
|
|
CertificateSerialNoSize = 48
|
|
CertificateMaxStringLength = int(C.ZT_CERTIFICATE_MAX_STRING_LENGTH)
|
|
|
|
CertificateLocalTrustFlagRootCA = int(C.ZT_CERTIFICATE_LOCAL_TRUST_FLAG_ROOT_CA)
|
|
CertificateLocalTrustFlagZeroTierRootSet = int(C.ZT_CERTIFICATE_LOCAL_TRUST_FLAG_ZEROTIER_ROOT_SET)
|
|
|
|
CertificateUniqueIdTypeNistP384 = int(C.ZT_CERTIFICATE_UNIQUE_ID_TYPE_NIST_P_384)
|
|
CertificateUniqueIdTypeNistP384Size = int(C.ZT_CERTIFICATE_UNIQUE_ID_TYPE_NIST_P_384_SIZE)
|
|
CertificateUniqueIdTypeNistP384PrivateSize = int(C.ZT_CERTIFICATE_UNIQUE_ID_TYPE_NIST_P_384_PRIVATE_SIZE)
|
|
)
|
|
|
|
// CertificateName identifies a real-world entity that owns a subject or has signed a certificate.
|
|
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"`
|
|
}
|
|
|
|
// CertificateIdentity bundles an identity with an optional locator.
|
|
type CertificateIdentity struct {
|
|
Identity *Identity `json:"identity,omitempty"`
|
|
Locator *Locator `json:"locator,omitempty"`
|
|
}
|
|
|
|
// CertificateNetwork bundles a network ID with the fingerprint of its primary controller.
|
|
type CertificateNetwork struct {
|
|
ID uint64 `json:"id"`
|
|
Controller Fingerprint `json:"controller"`
|
|
}
|
|
|
|
// CertificateSubject contains information about the subject of a certificate.
|
|
type CertificateSubject struct {
|
|
Timestamp int64 `json:"timestamp"`
|
|
Identities []CertificateIdentity `json:"identities,omitempty"`
|
|
Networks []CertificateNetwork `json:"networks,omitempty"`
|
|
Certificates []Base32Blob `json:"certificates,omitempty"`
|
|
UpdateURLs []string `json:"updateURLs,omitempty"`
|
|
Name CertificateName `json:"name"`
|
|
UniqueID Base32Blob `json:"uniqueId,omitempty"`
|
|
UniqueIDProofSignature Base32Blob `json:"uniqueIdProofSignature,omitempty"`
|
|
}
|
|
|
|
// Certificate is a Go reflection of the C ZT_Certificate struct.
|
|
type Certificate struct {
|
|
SerialNo Base32Blob `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 Base32Blob `json:"extendedAttributes,omitempty"`
|
|
MaxPathLength uint `json:"maxPathLength,omitempty"`
|
|
CRL []Base32Blob `json:"crl,omitempty"`
|
|
Signature Base32Blob `json:"signature,omitempty"`
|
|
}
|
|
|
|
// CertificateSubjectUniqueIDSecret bundles a certificate subject unique ID and its secret key.
|
|
type CertificateSubjectUniqueIDSecret struct {
|
|
UniqueID Base32Blob `json:"uniqueId,omitempty"`
|
|
UniqueIDSecret Base32Blob `json:"uniqueIdSecret,omitempty"`
|
|
}
|
|
|
|
// LocalCertificate combines a certificate with its local trust flags.
|
|
type LocalCertificate struct {
|
|
Certificate *Certificate `json:"certificate,omitempty"`
|
|
LocalTrust uint `json:"localTrust"`
|
|
}
|
|
|
|
func certificateErrorToError(cerr int) error {
|
|
switch cerr {
|
|
case C.ZT_CERTIFICATE_ERROR_NONE:
|
|
return nil
|
|
case C.ZT_CERTIFICATE_ERROR_HAVE_NEWER_CERT:
|
|
return ErrCertificateHaveNewerCert
|
|
case C.ZT_CERTIFICATE_ERROR_INVALID_FORMAT:
|
|
return ErrCertificateInvalidFormat
|
|
case C.ZT_CERTIFICATE_ERROR_INVALID_IDENTITY:
|
|
return ErrCertificateInvalidIdentity
|
|
case C.ZT_CERTIFICATE_ERROR_INVALID_PRIMARY_SIGNATURE:
|
|
return ErrCertificateInvalidPrimarySignature
|
|
case C.ZT_CERTIFICATE_ERROR_INVALID_CHAIN:
|
|
return ErrCertificateInvalidChain
|
|
case C.ZT_CERTIFICATE_ERROR_INVALID_COMPONENT_SIGNATURE:
|
|
return ErrCertificateInvalidComponentSignature
|
|
case C.ZT_CERTIFICATE_ERROR_INVALID_UNIQUE_ID_PROOF:
|
|
return ErrCertificateInvalidUniqueIDProof
|
|
case C.ZT_CERTIFICATE_ERROR_MISSING_REQUIRED_FIELDS:
|
|
return ErrCertificateMissingRequiredFields
|
|
case C.ZT_CERTIFICATE_ERROR_OUT_OF_VALID_TIME_WINDOW:
|
|
return ErrCertificateOutOfValidTimeWindow
|
|
}
|
|
return ErrInternal
|
|
}
|
|
|
|
// NewCertificateFromBytes decodes a certificate from an encoded byte string.
|
|
// Note that this is also used to decode a CSR. When used for a CSR only the
|
|
// Subject part of the certificate will contain anything and the rest will be
|
|
// blank. If 'verify' is true the certificate will also be verified. If using
|
|
// to decode a CSR this should be false as a CSR will not contain a full set
|
|
// of fields or a certificate signature.
|
|
func NewCertificateFromBytes(cert []byte, verify bool) (*Certificate, error) {
|
|
if len(cert) == 0 {
|
|
return nil, ErrInvalidParameter
|
|
}
|
|
var dec unsafe.Pointer
|
|
ver := C.int(0)
|
|
if verify {
|
|
ver = 1
|
|
}
|
|
cerr := C.ZT_Certificate_decode((**C.ZT_Certificate)(unsafe.Pointer(&dec)), unsafe.Pointer(&cert[0]), C.int(len(cert)), ver)
|
|
if cerr != 0 {
|
|
return nil, certificateErrorToError(int(cerr))
|
|
}
|
|
if dec == nil {
|
|
return nil, ErrInternal
|
|
}
|
|
defer C.ZT_Certificate_delete((*C.ZT_Certificate)(dec))
|
|
|
|
goCert := newCertificateFromCCertificate(dec)
|
|
if goCert == nil {
|
|
return nil, ErrInternal
|
|
}
|
|
return goCert, nil
|
|
}
|
|
|
|
// newCertificateFromCCertificate translates a C ZT_Certificate into a Go Certificate.
|
|
func newCertificateFromCCertificate(ccptr unsafe.Pointer) *Certificate {
|
|
cc := (*C.ZT_Certificate)(ccptr)
|
|
c := new(Certificate)
|
|
|
|
if cc == nil {
|
|
return c
|
|
}
|
|
|
|
sn := (*[48]byte)(unsafe.Pointer(&cc.serialNo[0]))[:]
|
|
if !allZero(sn) {
|
|
var tmp [48]byte
|
|
copy(tmp[:], sn)
|
|
c.SerialNo = tmp[:]
|
|
}
|
|
c.Flags = uint64(cc.flags)
|
|
c.Timestamp = int64(cc.timestamp)
|
|
c.Validity[0] = int64(cc.validity[0])
|
|
c.Validity[1] = int64(cc.validity[1])
|
|
|
|
c.Subject.Timestamp = int64(cc.subject.timestamp)
|
|
|
|
for i := 0; i < int(cc.subject.identityCount); i++ {
|
|
cid := (*C.ZT_Certificate_Identity)(unsafe.Pointer(uintptr(unsafe.Pointer(cc.subject.identities)) + (uintptr(C.sizeof_ZT_Certificate_Identity) * uintptr(i))))
|
|
if cid.identity == nil {
|
|
return nil
|
|
}
|
|
id, err := newIdentityFromCIdentity(cid.identity)
|
|
if err != nil {
|
|
return nil
|
|
}
|
|
var loc *Locator
|
|
if cid.locator != nil {
|
|
loc, err = newLocatorFromCLocator(cid.locator, false)
|
|
if err != nil {
|
|
return nil
|
|
}
|
|
}
|
|
c.Subject.Identities = append(c.Subject.Identities, CertificateIdentity{
|
|
Identity: id,
|
|
Locator: loc,
|
|
})
|
|
}
|
|
|
|
for i := 0; i < int(cc.subject.networkCount); i++ {
|
|
cn := (*C.ZT_Certificate_Network)(unsafe.Pointer(uintptr(unsafe.Pointer(cc.subject.networks)) + (uintptr(C.sizeof_ZT_Certificate_Network) * uintptr(i))))
|
|
fp := newFingerprintFromCFingerprint(&cn.controller)
|
|
if fp == nil {
|
|
return nil
|
|
}
|
|
c.Subject.Networks = append(c.Subject.Networks, CertificateNetwork{
|
|
ID: uint64(cn.id),
|
|
Controller: *fp,
|
|
})
|
|
}
|
|
|
|
for i := 0; i < int(cc.subject.certificateCount); i++ {
|
|
csn := *((**[CertificateSerialNoSize]byte)(unsafe.Pointer(uintptr(unsafe.Pointer(cc.subject.certificates)) + (uintptr(i) * pointerSize))))
|
|
var tmp [CertificateSerialNoSize]byte
|
|
copy(tmp[:], csn[:])
|
|
c.Subject.Certificates = append(c.Subject.Certificates, tmp[:])
|
|
}
|
|
|
|
for i := 0; i < int(cc.subject.updateURLCount); i++ {
|
|
curl := *((**C.char)(unsafe.Pointer(uintptr(unsafe.Pointer(cc.subject.updateURLs)) + (uintptr(i) * pointerSize))))
|
|
c.Subject.UpdateURLs = append(c.Subject.UpdateURLs, C.GoString(curl))
|
|
}
|
|
|
|
c.Subject.Name.SerialNo = C.GoString(&cc.subject.name.serialNo[0])
|
|
c.Subject.Name.CommonName = C.GoString(&cc.subject.name.commonName[0])
|
|
c.Subject.Name.Country = C.GoString(&cc.subject.name.country[0])
|
|
c.Subject.Name.Organization = C.GoString(&cc.subject.name.organization[0])
|
|
c.Subject.Name.Unit = C.GoString(&cc.subject.name.unit[0])
|
|
c.Subject.Name.Locality = C.GoString(&cc.subject.name.locality[0])
|
|
c.Subject.Name.Province = C.GoString(&cc.subject.name.province[0])
|
|
c.Subject.Name.StreetAddress = C.GoString(&cc.subject.name.streetAddress[0])
|
|
c.Subject.Name.PostalCode = C.GoString(&cc.subject.name.postalCode[0])
|
|
c.Subject.Name.Email = C.GoString(&cc.subject.name.email[0])
|
|
c.Subject.Name.URL = C.GoString(&cc.subject.name.url[0])
|
|
c.Subject.Name.Host = C.GoString(&cc.subject.name.host[0])
|
|
|
|
if cc.subject.uniqueIdSize > 0 {
|
|
c.Subject.UniqueID = C.GoBytes(unsafe.Pointer(cc.subject.uniqueId), C.int(cc.subject.uniqueIdSize))
|
|
if cc.subject.uniqueIdProofSignatureSize > 0 {
|
|
c.Subject.UniqueIDProofSignature = C.GoBytes(unsafe.Pointer(cc.subject.uniqueIdProofSignature), C.int(cc.subject.uniqueIdProofSignatureSize))
|
|
}
|
|
}
|
|
|
|
if cc.issuer != nil {
|
|
id, err := newIdentityFromCIdentity(cc.issuer)
|
|
if err != nil {
|
|
return nil
|
|
}
|
|
c.Issuer = id
|
|
}
|
|
|
|
c.IssuerName.SerialNo = C.GoString(&cc.issuerName.serialNo[0])
|
|
c.IssuerName.CommonName = C.GoString(&cc.issuerName.commonName[0])
|
|
c.IssuerName.Country = C.GoString(&cc.issuerName.country[0])
|
|
c.IssuerName.Organization = C.GoString(&cc.issuerName.organization[0])
|
|
c.IssuerName.Unit = C.GoString(&cc.issuerName.unit[0])
|
|
c.IssuerName.Locality = C.GoString(&cc.issuerName.locality[0])
|
|
c.IssuerName.Province = C.GoString(&cc.issuerName.province[0])
|
|
c.IssuerName.StreetAddress = C.GoString(&cc.issuerName.streetAddress[0])
|
|
c.IssuerName.PostalCode = C.GoString(&cc.issuerName.postalCode[0])
|
|
c.IssuerName.Email = C.GoString(&cc.issuerName.email[0])
|
|
c.IssuerName.URL = C.GoString(&cc.issuerName.url[0])
|
|
c.IssuerName.Host = C.GoString(&cc.issuerName.host[0])
|
|
|
|
if cc.extendedAttributesSize > 0 {
|
|
c.ExtendedAttributes = C.GoBytes(unsafe.Pointer(cc.extendedAttributes), C.int(cc.extendedAttributesSize))
|
|
}
|
|
|
|
c.MaxPathLength = uint(cc.maxPathLength)
|
|
|
|
for i := 0; i < int(cc.crlCount); i++ {
|
|
csn := *((**[CertificateSerialNoSize]byte)(unsafe.Pointer(uintptr(unsafe.Pointer(cc.crl)) + (uintptr(i) * pointerSize))))
|
|
var tmp [CertificateSerialNoSize]byte
|
|
copy(tmp[:], csn[:])
|
|
c.CRL = append(c.CRL, tmp[:])
|
|
}
|
|
|
|
if cc.signatureSize > 0 {
|
|
c.Signature = C.GoBytes(unsafe.Pointer(cc.signature), C.int(cc.signatureSize))
|
|
}
|
|
|
|
return c
|
|
}
|
|
|
|
// deleteCCertificate deletes a ZT_Certificate object returned by Certificate.CCertificate()
|
|
func deleteCCertificate(cc unsafe.Pointer) {
|
|
C.ZT_Certificate_delete((*C.ZT_Certificate)(cc))
|
|
}
|
|
|
|
// cCertificate creates a C ZT_Certificate structure from the content of a Certificate.
|
|
// It must be deleted with deleteCCertificate.
|
|
func (c *Certificate) cCertificate() unsafe.Pointer {
|
|
var cc C.ZT_Certificate
|
|
var subjectIdentities []C.ZT_Certificate_Identity
|
|
var subjectNetworks []C.ZT_Certificate_Network
|
|
var subjectCertificates []uintptr
|
|
var subjectUpdateURLs []uintptr
|
|
var subjectUpdateURLsData [][]byte
|
|
var crl []uintptr
|
|
|
|
if len(c.SerialNo) == 48 {
|
|
copy((*[CertificateSerialNoSize]byte)(unsafe.Pointer(&cc.serialNo[0]))[:], c.SerialNo)
|
|
}
|
|
cc.flags = C.uint64_t(c.Flags)
|
|
cc.timestamp = C.int64_t(c.Timestamp)
|
|
cc.validity[0] = C.int64_t(c.Validity[0])
|
|
cc.validity[1] = C.int64_t(c.Validity[1])
|
|
|
|
cc.subject.timestamp = C.int64_t(c.Subject.Timestamp)
|
|
|
|
if len(c.Subject.Identities) > 0 {
|
|
subjectIdentities = make([]C.ZT_Certificate_Identity, len(c.Subject.Identities))
|
|
for i, id := range c.Subject.Identities {
|
|
if id.Identity == nil {
|
|
return nil
|
|
}
|
|
subjectIdentities[i].identity = id.Identity.cIdentity()
|
|
if id.Locator != nil {
|
|
subjectIdentities[i].locator = id.Locator.cl
|
|
}
|
|
}
|
|
cc.subject.identities = &subjectIdentities[0]
|
|
cc.subject.identityCount = C.uint(len(subjectIdentities))
|
|
}
|
|
|
|
if len(c.Subject.Networks) > 0 {
|
|
subjectNetworks = make([]C.ZT_Certificate_Network, len(c.Subject.Networks))
|
|
for i, n := range c.Subject.Networks {
|
|
subjectNetworks[i].id = C.uint64_t(n.ID)
|
|
subjectNetworks[i].controller.address = C.uint64_t(n.Controller.Address)
|
|
if len(n.Controller.Hash) == 48 {
|
|
copy((*[48]byte)(unsafe.Pointer(&subjectNetworks[i].controller.hash[0]))[:], n.Controller.Hash)
|
|
}
|
|
}
|
|
cc.subject.networks = &subjectNetworks[0]
|
|
cc.subject.networkCount = C.uint(len(subjectNetworks))
|
|
}
|
|
|
|
if len(c.Subject.Certificates) > 0 {
|
|
subjectCertificates = make([]uintptr, len(c.Subject.Certificates))
|
|
for i, cert := range c.Subject.Certificates {
|
|
if len(cert) != CertificateSerialNoSize {
|
|
return nil
|
|
}
|
|
subjectCertificates[i] = uintptr(unsafe.Pointer(&cert[0]))
|
|
}
|
|
cc.subject.certificates = (**C.uint8_t)(unsafe.Pointer(&subjectCertificates[0]))
|
|
cc.subject.certificateCount = C.uint(len(subjectCertificates))
|
|
}
|
|
|
|
if len(c.Subject.UpdateURLs) > 0 {
|
|
subjectUpdateURLs = make([]uintptr, len(c.Subject.UpdateURLs))
|
|
subjectUpdateURLsData = make([][]byte, len(c.Subject.UpdateURLs))
|
|
for i, u := range c.Subject.UpdateURLs {
|
|
subjectUpdateURLsData[i] = stringAsZeroTerminatedBytes(u)
|
|
subjectUpdateURLs[i] = uintptr(unsafe.Pointer(&subjectUpdateURLsData[0][0]))
|
|
}
|
|
cc.subject.updateURLs = (**C.char)(unsafe.Pointer(&subjectUpdateURLs[0]))
|
|
cc.subject.updateURLCount = C.uint(len(subjectUpdateURLs))
|
|
}
|
|
|
|
cStrCopy(unsafe.Pointer(&cc.subject.name.serialNo[0]), CertificateMaxStringLength+1, c.Subject.Name.SerialNo)
|
|
cStrCopy(unsafe.Pointer(&cc.subject.name.commonName[0]), CertificateMaxStringLength+1, c.Subject.Name.CommonName)
|
|
cStrCopy(unsafe.Pointer(&cc.subject.name.country[0]), CertificateMaxStringLength+1, c.Subject.Name.Country)
|
|
cStrCopy(unsafe.Pointer(&cc.subject.name.organization[0]), CertificateMaxStringLength+1, c.Subject.Name.Organization)
|
|
cStrCopy(unsafe.Pointer(&cc.subject.name.unit[0]), CertificateMaxStringLength+1, c.Subject.Name.Unit)
|
|
cStrCopy(unsafe.Pointer(&cc.subject.name.locality[0]), CertificateMaxStringLength+1, c.Subject.Name.Locality)
|
|
cStrCopy(unsafe.Pointer(&cc.subject.name.province[0]), CertificateMaxStringLength+1, c.Subject.Name.Province)
|
|
cStrCopy(unsafe.Pointer(&cc.subject.name.streetAddress[0]), CertificateMaxStringLength+1, c.Subject.Name.StreetAddress)
|
|
cStrCopy(unsafe.Pointer(&cc.subject.name.postalCode[0]), CertificateMaxStringLength+1, c.Subject.Name.PostalCode)
|
|
cStrCopy(unsafe.Pointer(&cc.subject.name.email[0]), CertificateMaxStringLength+1, c.Subject.Name.Email)
|
|
cStrCopy(unsafe.Pointer(&cc.subject.name.url[0]), CertificateMaxStringLength+1, c.Subject.Name.URL)
|
|
cStrCopy(unsafe.Pointer(&cc.subject.name.host[0]), CertificateMaxStringLength+1, c.Subject.Name.Host)
|
|
|
|
if len(c.Subject.UniqueID) > 0 {
|
|
cc.subject.uniqueId = (*C.uint8_t)(unsafe.Pointer(&c.Subject.UniqueID[0]))
|
|
cc.subject.uniqueIdSize = C.uint(len(c.Subject.UniqueID))
|
|
if len(c.Subject.UniqueIDProofSignature) > 0 {
|
|
cc.subject.uniqueIdProofSignature = (*C.uint8_t)(unsafe.Pointer(&c.Subject.UniqueIDProofSignature[0]))
|
|
cc.subject.uniqueIdProofSignatureSize = C.uint(len(c.Subject.UniqueIDProofSignature))
|
|
}
|
|
}
|
|
|
|
if c.Issuer != nil {
|
|
cc.issuer = c.Issuer.cIdentity()
|
|
}
|
|
|
|
cStrCopy(unsafe.Pointer(&cc.issuerName.serialNo[0]), CertificateMaxStringLength+1, c.IssuerName.SerialNo)
|
|
cStrCopy(unsafe.Pointer(&cc.issuerName.commonName[0]), CertificateMaxStringLength+1, c.IssuerName.CommonName)
|
|
cStrCopy(unsafe.Pointer(&cc.issuerName.country[0]), CertificateMaxStringLength+1, c.IssuerName.Country)
|
|
cStrCopy(unsafe.Pointer(&cc.issuerName.organization[0]), CertificateMaxStringLength+1, c.IssuerName.Organization)
|
|
cStrCopy(unsafe.Pointer(&cc.issuerName.unit[0]), CertificateMaxStringLength+1, c.IssuerName.Unit)
|
|
cStrCopy(unsafe.Pointer(&cc.issuerName.locality[0]), CertificateMaxStringLength+1, c.IssuerName.Locality)
|
|
cStrCopy(unsafe.Pointer(&cc.issuerName.province[0]), CertificateMaxStringLength+1, c.IssuerName.Province)
|
|
cStrCopy(unsafe.Pointer(&cc.issuerName.streetAddress[0]), CertificateMaxStringLength+1, c.IssuerName.StreetAddress)
|
|
cStrCopy(unsafe.Pointer(&cc.issuerName.postalCode[0]), CertificateMaxStringLength+1, c.IssuerName.PostalCode)
|
|
cStrCopy(unsafe.Pointer(&cc.issuerName.email[0]), CertificateMaxStringLength+1, c.IssuerName.Email)
|
|
cStrCopy(unsafe.Pointer(&cc.issuerName.url[0]), CertificateMaxStringLength+1, c.IssuerName.URL)
|
|
cStrCopy(unsafe.Pointer(&cc.issuerName.host[0]), CertificateMaxStringLength+1, c.IssuerName.Host)
|
|
|
|
if len(c.ExtendedAttributes) > 0 {
|
|
cc.extendedAttributes = (*C.uint8_t)(unsafe.Pointer(&c.ExtendedAttributes[0]))
|
|
cc.extendedAttributesSize = C.uint(len(c.ExtendedAttributes))
|
|
}
|
|
|
|
cc.maxPathLength = C.uint(c.MaxPathLength)
|
|
|
|
if len(c.CRL) > 0 {
|
|
crl = make([]uintptr, len(c.CRL))
|
|
for i, cert := range c.CRL {
|
|
if len(cert) != CertificateSerialNoSize {
|
|
return nil
|
|
}
|
|
crl[i] = uintptr(unsafe.Pointer(&cert[0]))
|
|
}
|
|
cc.crl = (**C.uint8_t)(unsafe.Pointer(&crl[0]))
|
|
cc.crlCount = C.uint(len(crl))
|
|
}
|
|
|
|
if len(c.Signature) > 0 {
|
|
cc.signature = (*C.uint8_t)(unsafe.Pointer(&c.Signature[0]))
|
|
cc.signatureSize = C.uint(len(c.Signature))
|
|
}
|
|
|
|
// HACK: pass pointer to cc as uintptr to disable Go's protection against "Go pointers to
|
|
// Go pointers," as the C function called here will make a deep clone and then we are going
|
|
// to throw away 'cc' and its components.
|
|
return unsafe.Pointer(C._ZT_Certificate_clone2(C.uintptr_t(uintptr(unsafe.Pointer(&cc)))))
|
|
}
|
|
|
|
// Marshal encodes this certificate as a byte array (binary format).
|
|
func (c *Certificate) Marshal() ([]byte, error) {
|
|
cc := c.cCertificate()
|
|
if cc == nil {
|
|
return nil, ErrInternal
|
|
}
|
|
defer deleteCCertificate(cc)
|
|
var encoded [16384]byte
|
|
encodedSize := C.int(16384)
|
|
rv := int(C.ZT_Certificate_encode((*C.ZT_Certificate)(cc), unsafe.Pointer(&encoded[0]), &encodedSize))
|
|
if rv != 0 {
|
|
return nil, fmt.Errorf("Certificate encode error %d", rv)
|
|
}
|
|
return append(make([]byte, 0, int(encodedSize)), encoded[0:int(encodedSize)]...), nil
|
|
}
|
|
|
|
// Sign signs this certificate and returns a new one with signature and issuer filled out.
|
|
// This should only be used after decoding a CSR with NewCertificateFromBytes. The non-subject
|
|
// parts of this Certificate, if any, are ignored. A new Certificate is returned with a completed
|
|
// signature.
|
|
func (c *Certificate) Sign(id *Identity) (*Certificate, error) {
|
|
if id == nil || !id.HasPrivate() {
|
|
return nil, ErrInvalidParameter
|
|
}
|
|
ctmp := c.cCertificate()
|
|
if ctmp == nil {
|
|
return nil, ErrInternal
|
|
}
|
|
defer deleteCCertificate(ctmp)
|
|
var signedCert [16384]byte
|
|
signedCertSize := C.int(16384)
|
|
rv := int(C.ZT_Certificate_sign((*C.ZT_Certificate)(ctmp), id.cIdentity(), unsafe.Pointer(&signedCert[0]), &signedCertSize))
|
|
if rv != 0 {
|
|
return nil, fmt.Errorf("signing failed: error %d", rv)
|
|
}
|
|
return NewCertificateFromBytes(signedCert[0:int(signedCertSize)], true)
|
|
}
|
|
|
|
// Verify returns nil on success or a certificate error if there is a problem with this certificate.
|
|
func (c *Certificate) Verify() error {
|
|
cc := c.cCertificate()
|
|
if cc == nil {
|
|
return ErrInternal
|
|
}
|
|
defer deleteCCertificate(cc)
|
|
return certificateErrorToError(int(C.ZT_Certificate_verify((*C.ZT_Certificate)(cc))))
|
|
}
|
|
|
|
// String returns a compact JSON representation of this certificate.
|
|
func (c *Certificate) String() string {
|
|
j, _ := json.Marshal(c)
|
|
return string(j)
|
|
}
|
|
|
|
// JSON returns this certificate as a human-readable indented JSON string.
|
|
func (c *Certificate) JSON() string {
|
|
j, _ := json.MarshalIndent(c, "", " ")
|
|
return string(j)
|
|
}
|
|
|
|
// NewCertificateSubjectUniqueId creates a new certificate subject unique ID and corresponding private key.
|
|
// Right now only one type is supported: CertificateUniqueIdTypeNistP384
|
|
func NewCertificateSubjectUniqueId(uniqueIdType int) (id []byte, priv []byte, err error) {
|
|
if uniqueIdType != CertificateUniqueIdTypeNistP384 {
|
|
err = ErrInvalidParameter
|
|
return
|
|
}
|
|
id = make([]byte, int(C.ZT_CERTIFICATE_UNIQUE_ID_TYPE_NIST_P_384_SIZE))
|
|
priv = make([]byte, int(C.ZT_CERTIFICATE_UNIQUE_ID_TYPE_NIST_P_384_PRIVATE_SIZE))
|
|
idSize := C.int(len(id))
|
|
idPrivateSize := C.int(len(priv))
|
|
rv := int(C.ZT_Certificate_newSubjectUniqueId((C.enum_ZT_CertificateUniqueIdType)(uniqueIdType), unsafe.Pointer(&id[0]), &idSize, unsafe.Pointer(&priv[0]), &idPrivateSize))
|
|
if rv != 0 {
|
|
id = nil
|
|
priv = nil
|
|
err = fmt.Errorf("error %d", rv)
|
|
return
|
|
}
|
|
if int(idSize) != len(id) || int(idPrivateSize) != len(priv) {
|
|
id = nil
|
|
priv = nil
|
|
err = ErrInvalidParameter
|
|
return
|
|
}
|
|
return
|
|
}
|
|
|
|
// NewCertificateCSR creates a new certificate signing request (CSR) from a certificate subject and optional unique ID.
|
|
func NewCertificateCSR(subject *CertificateSubject, uniqueId []byte, uniqueIdPrivate []byte) ([]byte, error) {
|
|
var uid unsafe.Pointer
|
|
var uidp unsafe.Pointer
|
|
if len(uniqueId) > 0 && len(uniqueIdPrivate) > 0 {
|
|
uid = unsafe.Pointer(&uniqueId[0])
|
|
uidp = unsafe.Pointer(&uniqueIdPrivate[0])
|
|
}
|
|
|
|
var tmp Certificate
|
|
tmp.Subject = *subject
|
|
ctmp := tmp.cCertificate()
|
|
if ctmp == nil {
|
|
return nil, ErrInternal
|
|
}
|
|
defer deleteCCertificate(ctmp)
|
|
|
|
var csr [16384]byte
|
|
csrSize := C.int(16384)
|
|
cc := (*C.ZT_Certificate)(ctmp)
|
|
rv := int(C.ZT_Certificate_newCSR(&(cc.subject), uid, C.int(len(uniqueId)), uidp, C.int(len(uniqueIdPrivate)), unsafe.Pointer(&csr[0]), &csrSize))
|
|
if rv != 0 {
|
|
return nil, fmt.Errorf("ZT_Certificate_newCSR() failed: %d", rv)
|
|
}
|
|
|
|
return append(make([]byte, 0, int(csrSize)), csr[0:int(csrSize)]...), nil
|
|
}
|