From becc4aa8eaf75e324b8a1390851669090b1fd6b4 Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Tue, 28 Jul 2020 14:38:41 -0700 Subject: [PATCH] More certificate plumbing. --- cmd/zt_service_tests/zt_service_tests.go | 2 +- core/Node.cpp | 55 ++++++++++++++++++++++-- core/Node.hpp | 2 + core/Topology.cpp | 12 ++++++ core/Topology.hpp | 8 ++++ core/zerotier.h | 38 +++++++++++++++- pkg/zerotier/node.go | 17 ++++++++ 7 files changed, 129 insertions(+), 5 deletions(-) diff --git a/cmd/zt_service_tests/zt_service_tests.go b/cmd/zt_service_tests/zt_service_tests.go index 6d6179aca..ce7b36269 100644 --- a/cmd/zt_service_tests/zt_service_tests.go +++ b/cmd/zt_service_tests/zt_service_tests.go @@ -8,7 +8,7 @@ import ( func main() { runtime.GOMAXPROCS(1) - debug.SetGCPercent(15) + debug.SetGCPercent(10) if !TestCertificate() { os.Exit(1) diff --git a/core/Node.cpp b/core/Node.cpp index 266b9c925..3ca48ad13 100644 --- a/core/Node.cpp +++ b/core/Node.cpp @@ -413,6 +413,7 @@ ZT_PeerList *Node::peers() const Utils::zero(buf, bufSize); ZT_PeerList *pl = reinterpret_cast(buf); buf += sizeof(ZT_PeerList); + pl->freeFunction = reinterpret_cast(free); pl->peers = reinterpret_cast(buf); buf += sizeof(ZT_Peer) * peers.size(); ZT_Path *peerPath = reinterpret_cast(buf); @@ -496,6 +497,7 @@ ZT_VirtualNetworkList *Node::networks() const if (!buf) return nullptr; ZT_VirtualNetworkList *nl = (ZT_VirtualNetworkList *)buf; // NOLINT(modernize-use-auto,hicpp-use-auto) + nl->freeFunction = reinterpret_cast(free); nl->networks = (ZT_VirtualNetworkConfig *)(buf + sizeof(ZT_VirtualNetworkList)); nl->networkCount = 0; @@ -584,6 +586,39 @@ ZT_CertificateError Node::addCertificate( return RR->topology->addCertificate(tptr, c, now, localTrust, true, true, true); } +struct p_certificateListInternal +{ + Vector< SharedPtr< const Certificate > > c; + Vector< unsigned int > t; +}; + +static void p_freeCertificateList(const void *cl) +{ + if (cl) { + reinterpret_cast(reinterpret_cast(cl) + sizeof(ZT_CertificateList))->~p_certificateListInternal(); + free(const_cast(cl)); + } +} + +ZT_CertificateList *Node::listCertificates() +{ + ZT_CertificateList *const cl = (ZT_CertificateList *)malloc(sizeof(ZT_CertificateList) + sizeof(p_certificateListInternal)); + if (!cl) + return nullptr; + + p_certificateListInternal *const clint = reinterpret_cast(reinterpret_cast(cl) + sizeof(ZT_CertificateList)); + new (clint) p_certificateListInternal; + RR->topology->allCerts(clint->c, clint->t); + + cl->freeFunction = p_freeCertificateList; + static_assert(sizeof(SharedPtr< const Certificate >) == sizeof(void *), "SharedPtr<> is not just a wrapped pointer"); + cl->certs = reinterpret_cast(clint->c.data()); + cl->localTrust = clint->t.data(); + cl->certCount = (unsigned long)clint->c.size(); + + return cl; +} + int Node::sendUserMessage( void *tptr, uint64_t dest, @@ -840,10 +875,15 @@ void ZT_freeBuffer(void *b) delete _ZT_PTRTOBUF(b); } -void ZT_freeQueryResult(void *qr) +struct p_queryResultBase { - if (qr) - free(qr); + void (*freeFunction)(const void *); +}; + +void ZT_freeQueryResult(const void *qr) +{ + if ((qr) && (reinterpret_cast(qr)->freeFunction)) + reinterpret_cast(qr)->freeFunction(qr); } enum ZT_ResultCode ZT_Node_new(ZT_Node **node, void *uptr, void *tptr, const struct ZT_Node_Callbacks *callbacks, int64_t now) @@ -1066,6 +1106,15 @@ enum ZT_CertificateError ZT_Node_addCertificate( } } +ZT_SDK_API ZT_CertificateList *ZT_Node_listCertificates(ZT_Node *node) +{ + try { + return reinterpret_cast(node)->listCertificates(); + } catch (...) { + return nullptr; + } +} + void ZT_Node_setNetworkUserPtr(ZT_Node *node, uint64_t nwid, void *ptr) { try { diff --git a/core/Node.hpp b/core/Node.hpp index a5327f25e..55091585e 100644 --- a/core/Node.hpp +++ b/core/Node.hpp @@ -147,6 +147,8 @@ public: const void *certData, unsigned int certSize); + ZT_CertificateList *listCertificates(); + int sendUserMessage( void *tptr, uint64_t dest, diff --git a/core/Topology.cpp b/core/Topology.cpp index e05bc4fbc..811e9b951 100644 --- a/core/Topology.cpp +++ b/core/Topology.cpp @@ -242,6 +242,18 @@ ZT_CertificateError Topology::addCertificate(void *tPtr, const Certificate &cert return ZT_CERTIFICATE_ERROR_NONE; } +void Topology::allCerts(Vector< SharedPtr > &c,Vector< unsigned int > &t) const noexcept +{ + Mutex::Lock l(m_certs_l); + const unsigned long cs = (unsigned long)m_certs.size(); + c.reserve(cs); + t.reserve(cs); + for(Map< SHA384Hash, p_CertEntry >::const_iterator i(m_certs.begin());i!=m_certs.end();++i) { + c.push_back(i->second.certificate); + t.push_back(i->second.localTrust); + } +} + struct p_RootRankingComparisonOperator { ZT_INLINE bool operator()(const SharedPtr< Peer > &a, const SharedPtr< Peer > &b) const noexcept diff --git a/core/Topology.hpp b/core/Topology.hpp index 6a2620146..fe6fe175a 100644 --- a/core/Topology.hpp +++ b/core/Topology.hpp @@ -142,6 +142,14 @@ public: */ ZT_CertificateError addCertificate(void *tPtr, const Certificate &cert, const int64_t now, unsigned int localTrust, bool writeToLocalStore, bool refreshRootSets = true, bool verify = true); + /** + * Fill vectors with all certificates and their corresponding local trust flags + * + * @param c Certificate vector + * @param t Local trust vector + */ + void allCerts(Vector< SharedPtr > &c,Vector< unsigned int > &t) const noexcept; + private: void m_rankRoots(int64_t now); void m_eraseCertificate(void *tPtr, const SharedPtr< const Certificate > &cert, const SHA384Hash *uniqueIdHash); diff --git a/core/zerotier.h b/core/zerotier.h index 9bad98231..b2ef498d8 100644 --- a/core/zerotier.h +++ b/core/zerotier.h @@ -618,6 +618,32 @@ typedef struct unsigned int signatureSize; } ZT_Certificate; +/** + * A list of certificates + */ +typedef struct +{ + /** + * Function that is called to free this list (called by ZT_freeQueryResult) + */ + void (*freeFunction)(const void *); + + /** + * Array of pointers to certificates + */ + const ZT_Certificate *const *certs; + + /** + * Array of local trust flags for each certificate + */ + const unsigned int *localTrust; + + /** + * Number of certificates + */ + unsigned long certCount; +} ZT_CertificateList; + /** * Credential type IDs */ @@ -1429,6 +1455,7 @@ typedef struct */ typedef struct { + void (*freeFunction)(const void *); ZT_VirtualNetworkConfig *networks; unsigned long networkCount; } ZT_VirtualNetworkList; @@ -1616,6 +1643,7 @@ typedef struct */ typedef struct { + void (*freeFunction)(const void *); ZT_Peer *peers; unsigned long peerCount; } ZT_PeerList; @@ -2003,7 +2031,7 @@ ZT_SDK_API void ZT_freeBuffer(void *b); * * @param qr Query result buffer */ -ZT_SDK_API void ZT_freeQueryResult(void *qr); +ZT_SDK_API void ZT_freeQueryResult(const void *qr); /* ---------------------------------------------------------------------------------------------------------------- */ @@ -2392,6 +2420,14 @@ ZT_SDK_API enum ZT_CertificateError ZT_Node_addCertificate( const void *certData, unsigned int certSize); +/** + * List certificates installed in this node's trust store + * + * @param node Node instance + * @return List of certificates or NULL on error + */ +ZT_SDK_API ZT_CertificateList *ZT_Node_listCertificates(ZT_Node *node); + /** * Send a VERB_USER_MESSAGE to another ZeroTier node * diff --git a/pkg/zerotier/node.go b/pkg/zerotier/node.go index 540231fcb..0583ac7b5 100644 --- a/pkg/zerotier/node.go +++ b/pkg/zerotier/node.go @@ -541,6 +541,23 @@ func (n *Node) TryPeer(fpOrAddress interface{}, ep *Endpoint, retries int) bool return C.ZT_Node_tryPeer(n.zn, nil, fp.cFingerprint(), &ep.cep, C.int(retries)) != 0 } +// ListCertificates lists certificates and their corresponding local trust flags. +func (n *Node) ListCertificates() (certs []*Certificate, localTrust []uint, err error) { + cl := C.ZT_Node_listCertificates(n.zn) + if cl != nil { + for i := uintptr(0); i < uintptr(cl.certCount); i++ { + c := newCertificateFromCCertificate(unsafe.Pointer(uintptr(unsafe.Pointer(cl.certs)) + (i * pointerSize))) + if c != nil { + lt := *((*C.uint)(unsafe.Pointer(uintptr(unsafe.Pointer(cl.localTrust)) + (i * C.sizeof_int)))) + certs = append(certs, c) + localTrust = append(localTrust, uint(lt)) + } + } + C.ZT_freeQueryResult(unsafe.Pointer(cl)) + } + return +} + // -------------------------------------------------------------------------------------------------------------------- func (n *Node) runMaintenance() {