diff --git a/CMakeLists.txt b/CMakeLists.txt index d2620512f..1ed543b4f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -30,8 +30,6 @@ if(WIN32) set(CMAKE_SYSTEM_VERSION "7" CACHE STRING INTERNAL FORCE) endif(WIN32) -set(CMAKE_OSX_DEPLOYMENT_TARGET "10.12" CACHE STRING "Minimum OS X Deployment Version") - if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES) message(STATUS "Setting build type to '${default_build_type}' as none was specified.") set(CMAKE_BUILD_TYPE "${default_build_type}" CACHE STRING "Choose the type of build." FORCE) @@ -64,10 +62,25 @@ endif(CMAKE_BUILD_TYPE STREQUAL "Debug") if(WIN32) message("++ Setting Windows Compiler Flags ${CMAKE_BUILD_TYPE}") + add_definitions(-DNOMINMAX) + add_compile_options( + -Wall + -Wno-deprecated + -Wno-unused-function + -Wno-format + $<$:-g> + $<$:-O0> + $<$:-O3> + $<$:-ffast-math> + $<$:-O3> + $<$:-g> + ) set(GOFLAGS + -a -trimpath + -ldflags '-w' ) else(WIN32) @@ -77,6 +90,8 @@ else(WIN32) -buildmode=pie ) + set(MACOS_VERSION_MIN "10.12") + if(APPLE) message("++ Setting MacOS Compiler Flags ${CMAKE_BUILD_TYPE}") @@ -85,7 +100,7 @@ else(WIN32) -Wall -Wno-deprecated -Wno-unused-function - -mmacosx-version-min=10.12 + -mmacosx-version-min=${MACOS_VERSION_MIN} $<$:-g> $<$:-O0> $<$:-Ofast> @@ -98,7 +113,7 @@ else(WIN32) ) add_link_options( - -mmacosx-version-min=10.12 + -mmacosx-version-min=${MACOS_VERSION_MIN} $<$:-flto> ) @@ -111,6 +126,7 @@ else(WIN32) else(APPLE) message("++ Setting Linux/BSD/Posix Compiler Flags (${CMAKE_BUILD_TYPE})") + add_compile_options( -Wall -Wno-deprecated @@ -186,7 +202,8 @@ add_subdirectory(serviceiocore) file(GLOB go_src ${CMAKE_SOURCE_DIR}/cmd/*.go ${CMAKE_SOURCE_DIR}/cmd/cmd/*.go - ${CMAKE_SOURCE_DIR}/pkg/zerotier/*.go) + ${CMAKE_SOURCE_DIR}/pkg/zerotier/*.go +) if(WIN32) set(GO_EXE_NAME "zerotier.exe") diff --git a/attic/java/jni/Android.mk b/attic/java/jni/Android.mk index f018950d2..346b337af 100644 --- a/attic/java/jni/Android.mk +++ b/attic/java/jni/Android.mk @@ -17,8 +17,8 @@ LOCAL_CFLAGS := -DZT_USE_MINIUPNPC LOCAL_SRC_FILES := \ $(ZT1)/node/C25519.cpp \ $(ZT1)/node/Capability.cpp \ - $(ZT1)/node/CertificateOfMembership.cpp \ - $(ZT1)/node/CertificateOfOwnership.cpp \ + $(ZT1)/node/MembershipCredential.cpp \ + $(ZT1)/node/OwnershipCredential.cpp \ $(ZT1)/node/Identity.cpp \ $(ZT1)/node/IncomingPacket.cpp \ $(ZT1)/node/InetAddress.cpp \ diff --git a/build.bat b/build.bat index bfefefef1..d5f34d43a 100644 --- a/build.bat +++ b/build.bat @@ -3,3 +3,4 @@ mkdir build cd build cmake .. -G "MinGW Makefiles" make -j4 +cd .. diff --git a/cmd/zerotier/cli/help.go b/cmd/zerotier/cli/help.go index 403923fd1..40eb86572 100644 --- a/cmd/zerotier/cli/help.go +++ b/cmd/zerotier/cli/help.go @@ -54,17 +54,16 @@ Commands: peer
[command] [option] - Peer management commands show Show peer details (default) try [...] Try peer at explicit endpoint - locator Explicitly update peer locator - roots List root peers - root [command] - Root management commands - add [endpoint] Add a root or a set of roots - remove
Remove a root or set of roots set [option] [value] - Get or set a core config option port Primary P2P port secondaryport Secondary P2P port (0 to disable) blacklist cidr Toggle physical path blacklisting blacklist if Toggle interface prefix blacklisting portmap Toggle use of uPnP or NAT-PMP + roots List root peers + root [command] - Root management commands + trust [endpoint] Add a root or a set of roots + remove
Remove a root or set of roots controller [option] - Local controller management commands networks List networks run by local controller new Create a new network @@ -80,6 +79,7 @@ Commands: validate Locally validate an identity sign Sign a file with an identity's key verify Verify a signature + certificate [args] - Certificate commands An
may be specified as a 10-digit short ZeroTier address, a fingerprint containing both an address and a SHA384 hash, or an identity. diff --git a/cmd/zerotier/cli/service.go b/cmd/zerotier/cli/service.go index 5b8dc3f9a..14d58aae6 100644 --- a/cmd/zerotier/cli/service.go +++ b/cmd/zerotier/cli/service.go @@ -25,7 +25,7 @@ import ( "zerotier/pkg/zerotier" ) -func Service(basePath, authToken string, args []string) { +func Service(basePath string, args []string) { if len(args) > 0 { Help() os.Exit(1) diff --git a/cmd/zerotier/zerotier.go b/cmd/zerotier/zerotier.go index 2c8a855ce..5345361f5 100644 --- a/cmd/zerotier/zerotier.go +++ b/cmd/zerotier/zerotier.go @@ -43,12 +43,40 @@ func getAuthTokenPaths(basePath string) (p []string) { return p } -func authTokenRequired(authToken string) { +func authTokenRequired(basePath, tflag, tTflag string) string { + authTokenPaths := getAuthTokenPaths(basePath) + var authToken string + if len(tflag) > 0 { + at, err := ioutil.ReadFile(tflag) + if err != nil || len(at) == 0 { + fmt.Println("FATAL: unable to read local service API authorization token from " + tflag) + os.Exit(1) + } + authToken = string(at) + } else if len(tTflag) > 0 { + authToken = tTflag + } else { + for _, p := range authTokenPaths { + tmp, _ := ioutil.ReadFile(p) + if len(tmp) > 0 { + authToken = string(tmp) + break + } + } + if len(authToken) == 0 { + fmt.Println("FATAL: unable to read local service API authorization token from any of:") + for _, p := range authTokenPaths { + fmt.Println(" " + p) + } + os.Exit(1) + } + } + authToken = strings.TrimSpace(authToken) if len(authToken) == 0 { fmt.Println("FATAL: unable to read API authorization token from command line or any filesystem location.") os.Exit(1) - } + return authToken } func main() { @@ -56,7 +84,7 @@ func main() { // were doing a lot, but it's not. It just manages the core and is not directly involved // in pushing a lot of packets around. If that ever changes this should be adjusted. runtime.GOMAXPROCS(1) - debug.SetGCPercent(20) + debug.SetGCPercent(15) globalOpts := flag.NewFlagSet("global", flag.ContinueOnError) hflag := globalOpts.Bool("h", false, "") // support -h to be canonical with other Unix utilities @@ -80,89 +108,43 @@ func main() { if len(args) > 1 { cmdArgs = args[1:] } - basePath := zerotier.PlatformDefaultHomePath if len(*pflag) > 0 { basePath = *pflag } - authTokenPaths := getAuthTokenPaths(basePath) - - var authToken string - if len(*tflag) > 0 { - at, err := ioutil.ReadFile(*tflag) - if err != nil || len(at) == 0 { - fmt.Println("FATAL: unable to read local service API authorization token from " + *tflag) - os.Exit(1) - } - authToken = string(at) - } else if len(*tTflag) > 0 { - authToken = *tTflag - } else { - for _, p := range authTokenPaths { - tmp, _ := ioutil.ReadFile(p) - if len(tmp) > 0 { - authToken = string(tmp) - break - } - } - if len(authToken) == 0 { - fmt.Println("FATAL: unable to read local service API authorization token from any of:") - for _, p := range authTokenPaths { - fmt.Println(" " + p) - } - os.Exit(1) - } - } - authToken = strings.TrimSpace(authToken) switch args[0] { - case "help": + default: + //case "help": cli.Help() - os.Exit(0) case "version": fmt.Printf("%d.%d.%d\n", zerotier.CoreVersionMajor, zerotier.CoreVersionMinor, zerotier.CoreVersionRevision) - os.Exit(0) case "service": - cli.Service(basePath, authToken, cmdArgs) + cli.Service(basePath, cmdArgs) case "status", "info": - authTokenRequired(authToken) - cli.Status(basePath, authToken, cmdArgs, *jflag) + cli.Status(basePath, authTokenRequired(basePath, *tflag, *tTflag), cmdArgs, *jflag) case "join": - authTokenRequired(authToken) - cli.Join(basePath, authToken, cmdArgs) + cli.Join(basePath, authTokenRequired(basePath, *tflag, *tTflag), cmdArgs) case "leave": - authTokenRequired(authToken) - cli.Leave(basePath, authToken, cmdArgs) + cli.Leave(basePath, authTokenRequired(basePath, *tflag, *tTflag), cmdArgs) case "networks", "listnetworks": - authTokenRequired(authToken) - cli.Networks(basePath, authToken, cmdArgs, *jflag) + cli.Networks(basePath, authTokenRequired(basePath, *tflag, *tTflag), cmdArgs, *jflag) case "network": - authTokenRequired(authToken) - cli.Network(basePath, authToken, cmdArgs, *jflag) + cli.Network(basePath, authTokenRequired(basePath, *tflag, *tTflag), cmdArgs, *jflag) case "peers", "listpeers", "lspeers": - authTokenRequired(authToken) - cli.Peers(basePath, authToken, cmdArgs, *jflag, false) + cli.Peers(basePath, authTokenRequired(basePath, *tflag, *tTflag), cmdArgs, *jflag, false) case "peer": - authTokenRequired(authToken) + authTokenRequired(basePath, *tflag, *tTflag) case "roots": - authTokenRequired(authToken) - cli.Peers(basePath, authToken, cmdArgs, *jflag, true) + cli.Peers(basePath, authTokenRequired(basePath, *tflag, *tTflag), cmdArgs, *jflag, true) case "root": - authTokenRequired(authToken) - cli.Root(basePath, authToken, cmdArgs, *jflag) + cli.Root(basePath, authTokenRequired(basePath, *tflag, *tTflag), cmdArgs, *jflag) case "set": - authTokenRequired(authToken) - cli.Set(basePath, authToken, cmdArgs) + cli.Set(basePath, authTokenRequired(basePath, *tflag, *tTflag), cmdArgs) case "controller": - authTokenRequired(authToken) - cli.Controller(basePath, authToken, cmdArgs, *jflag) + cli.Controller(basePath, authTokenRequired(basePath, *tflag, *tTflag), cmdArgs, *jflag) case "identity": cli.Identity(cmdArgs) } - - // Commands in the 'cli' sub-package do not return, so if we make - // it here the command was not recognized. - - cli.Help() - os.Exit(1) + os.Exit(0) } diff --git a/controller/EmbeddedNetworkController.cpp b/controller/EmbeddedNetworkController.cpp index 4fe8a7002..ad18b0817 100644 --- a/controller/EmbeddedNetworkController.cpp +++ b/controller/EmbeddedNetworkController.cpp @@ -23,7 +23,7 @@ #include "../core/Constants.hpp" #include "../core/Node.hpp" -#include "../core/CertificateOfMembership.hpp" +#include "../core/MembershipCredential.hpp" #include "../core/NetworkConfig.hpp" #include "../core/Dictionary.hpp" #include "../core/MAC.hpp" @@ -1123,7 +1123,7 @@ void EmbeddedNetworkController::onNetworkMemberUpdate(const void *db,uint64_t ne void EmbeddedNetworkController::onNetworkMemberDeauthorize(const void *db,uint64_t networkId,uint64_t memberId) { const int64_t now = OSUtils::now(); - Revocation rev((uint32_t)Utils::random(),networkId,0,now,ZT_REVOCATION_FLAG_FAST_PROPAGATE,Address(memberId),ZT_CREDENTIAL_TYPE_COM); + RevocationCredential rev((uint32_t)Utils::random(), networkId, 0, now, ZT_REVOCATION_FLAG_FAST_PROPAGATE, Address(memberId), ZT_CREDENTIAL_TYPE_COM); rev.sign(_signingId); { std::lock_guard l(_memberStatus_l); @@ -1370,7 +1370,7 @@ void EmbeddedNetworkController::_request( ++caprc; } } - nc->capabilities[nc->capabilityCount] = Capability((uint32_t)capId,nwid,now,capr,caprc); + nc->capabilities[nc->capabilityCount] = CapabilityCredential((uint32_t)capId, nwid, now, capr, caprc); if (nc->capabilities[nc->capabilityCount].sign(_signingId,identity.address())) ++nc->capabilityCount; if (nc->capabilityCount >= ZT_MAX_NETWORK_CAPABILITIES) @@ -1406,7 +1406,7 @@ void EmbeddedNetworkController::_request( for(std::map< uint32_t,uint32_t >::const_iterator t(memberTagsById.begin());t!=memberTagsById.end();++t) { if (nc->tagCount >= ZT_MAX_NETWORK_TAGS) break; - nc->tags[nc->tagCount] = Tag(nwid,now,identity.address(),t->first,t->second); + nc->tags[nc->tagCount] = TagCredential(nwid, now, identity.address(), t->first, t->second); if (nc->tags[nc->tagCount].sign(_signingId)) ++nc->tagCount; } @@ -1609,14 +1609,14 @@ void EmbeddedNetworkController::_request( // Issue a certificate of ownership for all static IPs if (nc->staticIpCount) { - nc->certificatesOfOwnership[0] = CertificateOfOwnership(nwid,now,identity.address(),1); + nc->certificatesOfOwnership[0] = OwnershipCredential(nwid, now, identity.address(), 1); for(unsigned int i=0;istaticIpCount;++i) nc->certificatesOfOwnership[0].addThing(nc->staticIps[i]); nc->certificatesOfOwnership[0].sign(_signingId); nc->certificateOfOwnershipCount = 1; } - CertificateOfMembership com(now,credentialtmd,nwid,identity); + MembershipCredential com(now, credentialtmd, nwid, identity); if (com.sign(_signingId)) { nc->com = com; } else { diff --git a/core/Address.hpp b/core/Address.hpp index e8f464257..614070f5f 100644 --- a/core/Address.hpp +++ b/core/Address.hpp @@ -136,37 +136,26 @@ public: ZT_INLINE bool operator==(const Address &a) const noexcept { return _a == a._a; } - ZT_INLINE bool operator!=(const Address &a) const noexcept { return _a != a._a; } - ZT_INLINE bool operator>(const Address &a) const noexcept { return _a > a._a; } - ZT_INLINE bool operator<(const Address &a) const noexcept { return _a < a._a; } - ZT_INLINE bool operator>=(const Address &a) const noexcept { return _a >= a._a; } - ZT_INLINE bool operator<=(const Address &a) const noexcept { return _a <= a._a; } - ZT_INLINE bool operator==(const uint64_t a) const noexcept { return _a == a; } - ZT_INLINE bool operator!=(const uint64_t a) const noexcept { return _a != a; } - ZT_INLINE bool operator>(const uint64_t a) const noexcept { return _a > a; } - ZT_INLINE bool operator<(const uint64_t a) const noexcept { return _a < a; } - ZT_INLINE bool operator>=(const uint64_t a) const noexcept { return _a >= a; } - ZT_INLINE bool operator<=(const uint64_t a) const noexcept { return _a <= a; } diff --git a/core/Blob.hpp b/core/Blob.hpp index 583fd4e5a..922ad128e 100644 --- a/core/Blob.hpp +++ b/core/Blob.hpp @@ -29,7 +29,10 @@ struct Blob { uint8_t data[S]; - ZT_INLINE Blob() { Utils::zero(data); } + ZT_INLINE Blob() noexcept { Utils::zero(data); } + explicit ZT_INLINE Blob(const void *const d) noexcept { Utils::copy(data,d); } + + ZT_INLINE operator bool() const noexcept { return !Utils::allZero(data); } ZT_INLINE bool operator==(const Blob &b) const noexcept { return (memcmp(data,b.data,S) == 0); } ZT_INLINE bool operator!=(const Blob &b) const noexcept { return (memcmp(data,b.data,S) != 0); } diff --git a/core/CMakeLists.txt b/core/CMakeLists.txt index 219d3988d..1810ef390 100644 --- a/core/CMakeLists.txt +++ b/core/CMakeLists.txt @@ -12,9 +12,10 @@ set(core_headers Blob.hpp Buf.hpp C25519.hpp - Capability.hpp - CertificateOfMembership.hpp - CertificateOfOwnership.hpp + CapabilityCredential.hpp + Certificate.hpp + MembershipCredential.hpp + OwnershipCredential.hpp Constants.hpp Containers.hpp Credential.hpp @@ -25,13 +26,12 @@ set(core_headers Expect.hpp FCV.hpp Fingerprint.hpp - IdentificationCertificate.hpp Identity.hpp InetAddress.hpp Locator.hpp LZ4.hpp MAC.hpp - Membership.hpp + Member.hpp MulticastGroup.hpp Mutex.hpp Network.hpp @@ -49,7 +49,7 @@ set(core_headers SHA512.hpp SharedPtr.hpp SymmetricKey.hpp - Tag.hpp + TagCredential.hpp Topology.hpp Trace.hpp TriviallyCopyable.hpp @@ -62,30 +62,30 @@ set(core_src AES.cpp Buf.cpp C25519.cpp - Capability.cpp - CertificateOfMembership.cpp - CertificateOfOwnership.cpp + CapabilityCredential.cpp + Certificate.cpp + MembershipCredential.cpp + OwnershipCredential.cpp Credential.cpp Dictionary.cpp ECC384.cpp Endpoint.cpp - IdentificationCertificate.cpp Identity.cpp InetAddress.cpp Locator.cpp LZ4.cpp - Membership.cpp + Member.cpp Network.cpp NetworkConfig.cpp Node.cpp Path.cpp Peer.cpp Poly1305.cpp - Revocation.cpp + RevocationCredential.cpp Salsa20.cpp SelfAwareness.cpp SHA512.cpp - Tag.cpp + TagCredential.cpp Topology.cpp Trace.cpp Utils.cpp diff --git a/core/Capability.cpp b/core/CapabilityCredential.cpp similarity index 94% rename from core/Capability.cpp rename to core/CapabilityCredential.cpp index e70724bf0..27cb75788 100644 --- a/core/Capability.cpp +++ b/core/CapabilityCredential.cpp @@ -11,14 +11,14 @@ */ /****/ -#include "Capability.hpp" +#include "CapabilityCredential.hpp" #include "Utils.hpp" #include "Constants.hpp" #include "MAC.hpp" namespace ZeroTier { -bool Capability::sign(const Identity &from, const Address &to) noexcept +bool CapabilityCredential::sign(const Identity &from, const Address &to) noexcept { uint8_t buf[ZT_CAPABILITY_MARSHAL_SIZE_MAX + 16]; m_issuedTo = to; @@ -27,7 +27,7 @@ bool Capability::sign(const Identity &from, const Address &to) noexcept return m_signatureLength > 0; } -int Capability::marshal(uint8_t data[ZT_CAPABILITY_MARSHAL_SIZE_MAX], const bool forSign) const noexcept +int CapabilityCredential::marshal(uint8_t data[ZT_CAPABILITY_MARSHAL_SIZE_MAX], const bool forSign) const noexcept { int p = 0; @@ -45,7 +45,7 @@ int Capability::marshal(uint8_t data[ZT_CAPABILITY_MARSHAL_SIZE_MAX], const bool Utils::storeBigEndian(data + p, (uint16_t) m_ruleCount); p += 2; - p += Capability::marshalVirtualNetworkRules(data + p, m_rules, m_ruleCount); + p += CapabilityCredential::marshalVirtualNetworkRules(data + p, m_rules, m_ruleCount); // LEGACY: older versions supported multiple records with this being a maximum custody // chain length. This is deprecated so set the max chain length to one. @@ -78,7 +78,7 @@ int Capability::marshal(uint8_t data[ZT_CAPABILITY_MARSHAL_SIZE_MAX], const bool return p; } -int Capability::unmarshal(const uint8_t *data, int len) noexcept +int CapabilityCredential::unmarshal(const uint8_t *data, int len) noexcept { if (len < 22) return -1; @@ -138,7 +138,7 @@ int Capability::unmarshal(const uint8_t *data, int len) noexcept return p; } -int Capability::marshalVirtualNetworkRules(uint8_t *data, const ZT_VirtualNetworkRule *const rules, const unsigned int ruleCount) noexcept +int CapabilityCredential::marshalVirtualNetworkRules(uint8_t *data, const ZT_VirtualNetworkRule *const rules, const unsigned int ruleCount) noexcept { int p = 0; for (unsigned int i = 0;i < ruleCount;++i) { @@ -273,7 +273,7 @@ int Capability::marshalVirtualNetworkRules(uint8_t *data, const ZT_VirtualNetwor return p; } -int Capability::unmarshalVirtualNetworkRules(const uint8_t *const data, const int len, ZT_VirtualNetworkRule *const rules, unsigned int &ruleCount, const unsigned int maxRuleCount) noexcept +int CapabilityCredential::unmarshalVirtualNetworkRules(const uint8_t *const data, const int len, ZT_VirtualNetworkRule *const rules, unsigned int &ruleCount, const unsigned int maxRuleCount) noexcept { int p = 0; unsigned int rc = 0; diff --git a/core/Capability.hpp b/core/CapabilityCredential.hpp similarity index 88% rename from core/Capability.hpp rename to core/CapabilityCredential.hpp index bf2501b9a..fe32eba77 100644 --- a/core/Capability.hpp +++ b/core/CapabilityCredential.hpp @@ -50,14 +50,14 @@ class RuntimeEnvironment; * Note that this is after evaluation of network scope rules and only if * network scope rules do not deliver an explicit match. */ -class Capability : public Credential +class CapabilityCredential : public Credential { friend class Credential; public: static constexpr ZT_CredentialType credentialType() noexcept { return ZT_CREDENTIAL_TYPE_CAPABILITY; } - ZT_INLINE Capability() noexcept { memoryZero(this); } + ZT_INLINE CapabilityCredential() noexcept { memoryZero(this); } /** * @param id Capability ID @@ -67,7 +67,7 @@ public: * @param rules Network flow rules for this capability * @param ruleCount Number of flow rules */ - ZT_INLINE Capability(const uint32_t id,const uint64_t nwid,const int64_t ts,const ZT_VirtualNetworkRule *const rules,const unsigned int ruleCount) noexcept : // NOLINT(cppcoreguidelines-pro-type-member-init,hicpp-member-init) + ZT_INLINE CapabilityCredential(const uint32_t id, const uint64_t nwid, const int64_t ts, const ZT_VirtualNetworkRule *const rules, const unsigned int ruleCount) noexcept : // NOLINT(cppcoreguidelines-pro-type-member-init,hicpp-member-init) m_nwid(nwid), m_ts(ts), m_id(id), @@ -145,10 +145,10 @@ public: static int unmarshalVirtualNetworkRules(const uint8_t *data,int len,ZT_VirtualNetworkRule *rules,unsigned int &ruleCount,unsigned int maxRuleCount) noexcept; // Provides natural sort order by ID - ZT_INLINE bool operator<(const Capability &c) const noexcept { return (m_id < c.m_id); } + ZT_INLINE bool operator<(const CapabilityCredential &c) const noexcept { return (m_id < c.m_id); } - ZT_INLINE bool operator==(const Capability &c) const noexcept { return (memcmp(this,&c,sizeof(Capability)) == 0); } - ZT_INLINE bool operator!=(const Capability &c) const noexcept { return (memcmp(this,&c,sizeof(Capability)) != 0); } + ZT_INLINE bool operator==(const CapabilityCredential &c) const noexcept { return (memcmp(this, &c, sizeof(CapabilityCredential)) == 0); } + ZT_INLINE bool operator!=(const CapabilityCredential &c) const noexcept { return (memcmp(this, &c, sizeof(CapabilityCredential)) != 0); } private: uint64_t m_nwid; diff --git a/core/IdentificationCertificate.cpp b/core/Certificate.cpp similarity index 53% rename from core/IdentificationCertificate.cpp rename to core/Certificate.cpp index 55f714560..652e1af1b 100644 --- a/core/IdentificationCertificate.cpp +++ b/core/Certificate.cpp @@ -11,118 +11,177 @@ */ /****/ -#include "IdentificationCertificate.hpp" +#include "Certificate.hpp" #include "SHA512.hpp" namespace ZeroTier { -void IdentificationCertificate::clear() +void Certificate::clear() { - Utils::zero< sizeof(ZT_IdentificationCertificate) >((ZT_IdentificationCertificate *)this); + Utils::zero< sizeof(ZT_Certificate) >((ZT_Certificate *)this); + m_identities.clear(); m_locators.clear(); m_strings.clear(); - m_nodes.clear(); - m_networks.clear(); + m_serials.clear(); + + m_subjectIdentities.clear(); + m_subjectNetworks.clear(); m_updateUrls.clear(); + m_subjectCertificates.clear(); } -IdentificationCertificate &IdentificationCertificate::operator=(const ZT_IdentificationCertificate &apiCert) +Certificate &Certificate::operator=(const ZT_Certificate &apiCert) { clear(); - Utils::copy< sizeof(ZT_IdentificationCertificate) >((ZT_IdentificationCertificate *)this, &apiCert); + Utils::copy< sizeof(ZT_Certificate) >((ZT_Certificate *)this, &apiCert); return *this; } -IdentificationCertificate &IdentificationCertificate::operator=(const IdentificationCertificate &cert) +Certificate &Certificate::operator=(const Certificate &cert) { - *this = *((const ZT_IdentificationCertificate *)(&cert)); + *this = *((const ZT_Certificate *)(&cert)); - this->subject.nodeCount = 0; + // Zero these since we must explicitly attach all the objects from + // the other certificate to copy them into our containers. + this->subject.identityCount = 0; this->subject.networkCount = 0; + this->subject.certificateCount = 0; + + for (unsigned int i = 0; i < cert.subject.identityCount; ++i) { + if (cert.subject.identities[i].identity) { + if (cert.subject.identities[i].locator) + addSubjectNode(*reinterpret_cast(cert.subject.identities[i].identity), *reinterpret_cast(cert.subject.identities[i].locator)); + else addSubjectNode(*reinterpret_cast(cert.subject.identities[i].identity)); + } + } + + for (unsigned int i = 0; i < cert.subject.networkCount; ++i) { + if (cert.subject.networks[i].id) + addSubjectNetwork(cert.subject.networks[i].id, cert.subject.networks[i].controller); + } + + for (unsigned int i = 0; i < cert.subject.certificateCount; ++i) { + if (cert.subject.certificates[i]) + addSubjectCertificate(cert.subject.certificates[i]); + } if (cert.issuer) { m_identities.push_back(*reinterpret_cast(cert.issuer)); this->issuer = reinterpret_cast(&(m_identities.back())); } - for (unsigned int i = 0; i < cert.subject.nodeCount; ++i) { - if (cert.subject.nodes[i].locator) - addSubjectNode(*reinterpret_cast(cert.subject.nodes[i].identity), *reinterpret_cast(cert.subject.nodes[i].locator)); - else if (cert.subject.nodes[i].identity) - addSubjectNode(*reinterpret_cast(cert.subject.nodes[i].identity)); - } - - for (unsigned int i = 0; i < cert.subject.networkCount; ++i) - addSubjectNetwork(cert.subject.networks[i].id, cert.subject.networks[i].controller); - if (cert.updateUrls) { - for (unsigned int i = 0; i < cert.updateUrlCount; ++i) - addUpdateUrl(cert.updateUrls[i]); + for (unsigned int i = 0; i < cert.updateUrlCount; ++i) { + if (cert.updateUrls[i]) + addUpdateUrl(cert.updateUrls[i]); + } } return *this; } -ZT_IdentificationCertificate_Node *IdentificationCertificate::addSubjectNode(const Identity &id) +ZT_Certificate_Identity *Certificate::addSubjectNode(const Identity &id) { - m_nodes.resize(++this->subject.nodeCount); - this->subject.nodes = m_nodes.data(); + // Enlarge array of ZT_Certificate_Identity structs and set pointer to potentially reallocated array. + m_subjectIdentities.resize(++this->subject.identityCount); + this->subject.identities = m_subjectIdentities.data(); + + // Store a local copy of the actual identity. m_identities.push_back(id); - m_nodes.back().identity = reinterpret_cast(&(m_identities.back())); - m_nodes.back().locator = nullptr; - return &(m_nodes.back()); + + // Set ZT_Certificate_Identity struct fields to point to local copy of identity. + m_subjectIdentities.back().identity = reinterpret_cast(&(m_identities.back())); + m_subjectIdentities.back().locator = nullptr; + + return &(m_subjectIdentities.back()); } -ZT_IdentificationCertificate_Node *IdentificationCertificate::addSubjectNode(const Identity &id, const Locator &loc) +ZT_Certificate_Identity *Certificate::addSubjectNode(const Identity &id, const Locator &loc) { - ZT_IdentificationCertificate_Node *n = addSubjectNode(id); + // Add identity as above. + ZT_Certificate_Identity *const n = addSubjectNode(id); + + // Store local copy of locator. m_locators.push_back(loc); + + // Set pointer to stored local copy of locator. n->locator = reinterpret_cast(&(m_locators.back())); + return n; } -ZT_IdentificationCertificate_Network *IdentificationCertificate::addSubjectNetwork(const uint64_t id, const ZT_Fingerprint &controller) +ZT_Certificate_Network *Certificate::addSubjectNetwork(const uint64_t id, const ZT_Fingerprint &controller) { - m_networks.resize(++this->subject.networkCount); - this->subject.networks = m_networks.data(); - m_networks.back().id = id; - Utils::copy< sizeof(ZT_Fingerprint) >(&(m_networks.back().controller), &controller); - return &(m_networks.back()); + // Enlarge array of ZT_Certificate_Network and set pointer to potentially reallocated array. + m_subjectNetworks.resize(++this->subject.networkCount); + this->subject.networks = m_subjectNetworks.data(); + + // Set fields in new ZT_Certificate_Network structure. + m_subjectNetworks.back().id = id; + Utils::copy< sizeof(ZT_Fingerprint) >(&(m_subjectNetworks.back().controller), &controller); + + return &(m_subjectNetworks.back()); } -void IdentificationCertificate::addUpdateUrl(const char *url) +void Certificate::addSubjectCertificate(const uint8_t serialNo[ZT_SHA384_DIGEST_SIZE]) { + // Store local copy of serial in m_serials container. + m_serials.push_back(Blob< ZT_SHA384_DIGEST_SIZE >(serialNo)); + + // Enlarge array of uint8_t pointers, set new pointer to local copy of serial, and set + // certificates to point to potentially reallocated array. + m_subjectCertificates.resize(++this->subject.certificateCount); + m_subjectCertificates.back() = m_serials.back().data; + this->subject.certificates = m_subjectCertificates.data(); +} + +void Certificate::addUpdateUrl(const char *url) +{ + // Store local copy of URL. m_strings.push_back(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->updateUrls = m_updateUrls.data(); this->updateUrlCount = (unsigned int)m_updateUrls.size(); } -Vector< uint8_t > IdentificationCertificate::encode(const bool omitSignature) const +Vector< uint8_t > Certificate::encode(const bool omitSignature) const { char tmp[256]; Vector< uint8_t > enc; Dictionary d; - d.add("v", (uint64_t)this->version); - d.add("mP", (uint64_t)this->maxPathLength); + // A Dictionary is used to encode certificates as it's a common and extensible + // format. Custom packed formats are used for credentials as these are smaller + // and faster to marshal/unmarshal. + d.add("f", this->flags); d.add("v0", this->validity[0]); d.add("v1", this->validity[1]); + d.add("mP", (uint64_t)this->maxPathLength); - d.add("s.n[]", (uint64_t)this->subject.nodeCount); - for (unsigned int i = 0; i < this->subject.nodeCount; ++i) { - d.addO(Dictionary::arraySubscript(tmp, "s.n[].i", i), *reinterpret_cast(this->subject.nodes[i].identity)); - if (this->subject.nodes[i].locator) - d.addO(Dictionary::arraySubscript(tmp, "s.n[].l", i), *reinterpret_cast(this->subject.nodes[i].locator)); + d.add("s.i$", (uint64_t)this->subject.identityCount); + for (unsigned int i = 0; i < this->subject.identityCount; ++i) { + if (this->subject.identities[i].identity) + d.addO(Dictionary::arraySubscript(tmp, "s.i$.i", i), *reinterpret_cast(this->subject.identities[i].identity)); + if (this->subject.identities[i].locator) + d.addO(Dictionary::arraySubscript(tmp, "s.i$.l", i), *reinterpret_cast(this->subject.identities[i].locator)); } - d.add("s.nw[]", (uint64_t)this->subject.networkCount); + d.add("s.n$", (uint64_t)this->subject.networkCount); for (unsigned int i = 0; i < this->subject.networkCount; ++i) { - d.add(Dictionary::arraySubscript(tmp, "s.nw[].i", i), this->subject.networks[i].id); + d.add(Dictionary::arraySubscript(tmp, "s.n$.i", i), this->subject.networks[i].id); Fingerprint fp(this->subject.networks[i].controller); - d.addO(Dictionary::arraySubscript(tmp, "s.nw[].c", i), fp); + d.addO(Dictionary::arraySubscript(tmp, "s.n$.c", i), fp); + } + + d.add("s.c$", (uint64_t)this->subject.certificateCount); + for (unsigned int i = 0; i < this->subject.certificateCount; ++i) { + if (this->subject.certificates[i]) + d[Dictionary::arraySubscript(tmp, "s.c$", i)].assign(this->subject.certificates[i], this->subject.certificates[i] + ZT_SHA384_DIGEST_SIZE); } d.add("s.n.c", this->subject.name.country); @@ -152,10 +211,10 @@ Vector< uint8_t > IdentificationCertificate::encode(const bool omitSignature) co d.add("iN.e", this->issuerName.email); d.add("iN.ur", this->issuerName.url); - d.add("uU[]", (uint64_t)this->updateUrlCount); + d.add("u$", (uint64_t)this->updateUrlCount); if (this->updateUrls) { for (unsigned int i = 0; i < this->updateUrlCount; ++i) - d.add(Dictionary::arraySubscript(tmp, "uU[]", i), this->updateUrls[i]); + d.add(Dictionary::arraySubscript(tmp, "u$", i), this->updateUrls[i]); } if ((!omitSignature) && (this->signatureSize > 0) && (this->signatureSize <= sizeof(this->signature))) @@ -165,9 +224,9 @@ Vector< uint8_t > IdentificationCertificate::encode(const bool omitSignature) co return enc; } -bool IdentificationCertificate::decode(const Vector< uint8_t > &data) +bool Certificate::decode(const Vector< uint8_t > &data) { - char tmp[256], tmp2[ZT_IDENTIFICATION_CERTIFICATE_MAX_STRING_LENGTH + 1]; + char tmp[256], tmp2[ZT_CERTIFICATE_MAX_STRING_LENGTH + 1]; clear(); @@ -175,21 +234,20 @@ bool IdentificationCertificate::decode(const Vector< uint8_t > &data) if (!d.decode(data.data(), (unsigned int)data.size())) return false; - this->version = (unsigned int)d.getUI("v"); - this->maxPathLength = (unsigned int)d.getUI("mP"); this->flags = d.getUI("f"); this->validity[0] = (int64_t)d.getUI("v0"); this->validity[1] = (int64_t)d.getUI("v1"); + this->maxPathLength = (unsigned int)d.getUI("mP"); - unsigned int cnt = (unsigned int)d.getUI("s.n[]"); + unsigned int cnt = (unsigned int)d.getUI("s.i$"); for (unsigned int i = 0; i < cnt; ++i) { - const Vector< uint8_t > &identityData = d[Dictionary::arraySubscript(tmp, "s.n[].i", i)]; + const Vector< uint8_t > &identityData = d[Dictionary::arraySubscript(tmp, "s.i$.i", i)]; if (identityData.empty()) return false; Identity id; if (id.unmarshal(identityData.data(), (unsigned int)identityData.size()) <= 0) return false; - const Vector< uint8_t > &locatorData = d[Dictionary::arraySubscript(tmp, "s.n[].l", i)]; + const Vector< uint8_t > &locatorData = d[Dictionary::arraySubscript(tmp, "s.i$.l", i)]; if (!locatorData.empty()) { Locator loc; if (loc.unmarshal(locatorData.data(), (unsigned int)locatorData.size()) <= 0) @@ -200,13 +258,11 @@ bool IdentificationCertificate::decode(const Vector< uint8_t > &data) } } - cnt = (unsigned int)d.getUI("s.nw[]"); + cnt = (unsigned int)d.getUI("s.n$"); for (unsigned int i = 0; i < cnt; ++i) { - const uint64_t nwid = d.getUI(Dictionary::arraySubscript(tmp, "s.nw[].i", i)); - if (nwid == 0) - return false; - const Vector< uint8_t > &fingerprintData = d[Dictionary::arraySubscript(tmp, "s.nw[].c", i)]; - if (fingerprintData.empty()) + const uint64_t nwid = d.getUI(Dictionary::arraySubscript(tmp, "s.n$.i", i)); + const Vector< uint8_t > &fingerprintData = d[Dictionary::arraySubscript(tmp, "s.n$.c", i)]; + if ((nwid == 0) || (fingerprintData.empty())) return false; Fingerprint fp; if (fp.unmarshal(fingerprintData.data(), (unsigned int)fingerprintData.size()) <= 0) @@ -214,6 +270,14 @@ bool IdentificationCertificate::decode(const Vector< uint8_t > &data) this->addSubjectNetwork(nwid, fp); } + cnt = (unsigned int)d.getUI("s.c$"); + for (unsigned int i=0;i &serial = d[Dictionary::arraySubscript(tmp, "s.c$", i)]; + if (serial.size() != ZT_SHA384_DIGEST_SIZE) + return false; + this->addSubjectCertificate(serial.data()); + } + d.getS("s.n.c", this->subject.name.country, sizeof(this->subject.name.country)); d.getS("s.n.o", this->subject.name.organization, sizeof(this->subject.name.organization)); d.getS("s.n.u", this->subject.name.unit, sizeof(this->subject.name.unit)); @@ -247,9 +311,9 @@ bool IdentificationCertificate::decode(const Vector< uint8_t > &data) d.getS("iN.e", this->issuerName.email, sizeof(this->issuerName.email)); d.getS("iN.ur", this->issuerName.url, sizeof(this->issuerName.url)); - cnt = (unsigned int)d.getUI("uU[]"); + cnt = (unsigned int)d.getUI("u$"); for (unsigned int i = 0; i < cnt; ++i) { - const char *const url = d.getS(Dictionary::arraySubscript(tmp, "uU[]", i), tmp2, sizeof(tmp2)); + const char *const url = d.getS(Dictionary::arraySubscript(tmp, "u$", i), tmp2, sizeof(tmp2)); if (url) addUpdateUrl(tmp2); else return false; @@ -267,19 +331,21 @@ bool IdentificationCertificate::decode(const Vector< uint8_t > &data) return true; } -bool IdentificationCertificate::sign(const Identity &issuer) +bool Certificate::sign(const Identity &issuer) { Vector< uint8_t > enc(encode(true)); SHA384(this->serialNo, enc.data(), (unsigned int)enc.size()); return (this->signatureSize = issuer.sign(enc.data(), (unsigned int)enc.size(), this->signature, sizeof(this->signature))) > 0; } -bool IdentificationCertificate::verify() const +bool Certificate::verify() const { - if (this->issuer) { - Vector< uint8_t > enc(encode(true)); - return reinterpret_cast(this->issuer)->verify(enc.data(), (unsigned int)enc.size(), this->signature, this->signatureSize); - } + try { + if (this->issuer) { + Vector< uint8_t > enc(encode(true)); + return reinterpret_cast(this->issuer)->verify(enc.data(), (unsigned int)enc.size(), this->signature, this->signatureSize); + } + } catch ( ... ) {} return false; } diff --git a/core/IdentificationCertificate.hpp b/core/Certificate.hpp similarity index 73% rename from core/IdentificationCertificate.hpp rename to core/Certificate.hpp index 17060d74b..f1a4b3c38 100644 --- a/core/IdentificationCertificate.hpp +++ b/core/Certificate.hpp @@ -11,8 +11,8 @@ */ /****/ -#ifndef ZT_IDENTIFICATIONCERTIFICATE_HPP -#define ZT_IDENTIFICATIONCERTIFICATE_HPP +#ifndef ZT_CERTIFICATE_HPP +#define ZT_CERTIFICATE_HPP #include "Constants.hpp" #include "SHA512.hpp" @@ -23,12 +23,13 @@ #include "Locator.hpp" #include "Dictionary.hpp" #include "Utils.hpp" +#include "Blob.hpp" #include "Containers.hpp" namespace ZeroTier { /** - * Certificate identifying the real world owner of an identity or network. + * Certificate describing and grouping a set of objects. * * This is a wrapper around the straight C ZT_IdentificationCertificate and * handles allocating memory for objects added via addXXX() and disposing of @@ -44,16 +45,16 @@ namespace ZeroTier { * field, so these will not work correctly before sign() or decode() is * called. */ -class IdentificationCertificate : public ZT_IdentificationCertificate +class Certificate : public ZT_Certificate { public: - ZT_INLINE IdentificationCertificate() noexcept + ZT_INLINE Certificate() noexcept { this->clear(); } - ZT_INLINE IdentificationCertificate(const ZT_IdentificationCertificate &apiCert) + ZT_INLINE Certificate(const ZT_Certificate &apiCert) { *this = apiCert; } - ZT_INLINE IdentificationCertificate(const IdentificationCertificate &cert) + ZT_INLINE Certificate(const Certificate &cert) { *this = cert; } /** @@ -61,9 +62,9 @@ public: */ void clear(); - IdentificationCertificate &operator=(const ZT_IdentificationCertificate &apiCert); + Certificate &operator=(const ZT_Certificate &apiCert); - IdentificationCertificate &operator=(const IdentificationCertificate &cert); + Certificate &operator=(const Certificate &cert); /** * Add a subject node/identity without a locator @@ -71,7 +72,7 @@ public: * @param id Identity * @return Pointer to C struct */ - ZT_IdentificationCertificate_Node *addSubjectNode(const Identity &id); + ZT_Certificate_Identity *addSubjectNode(const Identity &id); /** * Add a subject node/identity with a locator @@ -80,7 +81,7 @@ public: * @param loc Locator signed by identity (signature is NOT checked here) * @return Pointer to C struct */ - ZT_IdentificationCertificate_Node *addSubjectNode(const Identity &id, const Locator &loc); + ZT_Certificate_Identity *addSubjectNode(const Identity &id, const Locator &loc); /** * Add a subject network @@ -89,7 +90,14 @@ public: * @param controller Network controller's full fingerprint * @return Pointer to C struct */ - ZT_IdentificationCertificate_Network *addSubjectNetwork(const uint64_t id, const ZT_Fingerprint &controller); + ZT_Certificate_Network *addSubjectNetwork(const uint64_t id, const ZT_Fingerprint &controller); + + /** + * Add a subject certificate (by its serial number) + * + * @param serialNo 384-bit serial number + */ + void addSubjectCertificate(const uint8_t serialNo[ZT_SHA384_DIGEST_SIZE]); /** * Add an update URL to the updateUrls list @@ -135,22 +143,22 @@ public: ZT_INLINE unsigned long hashCode() const noexcept { return (unsigned long)Utils::loadAsIsEndian< uint32_t >(this->serialNo); } - ZT_INLINE bool operator==(const ZT_IdentificationCertificate &c) const noexcept + ZT_INLINE bool operator==(const ZT_Certificate &c) const noexcept { return memcmp(this->serialNo, c.serialNo, ZT_SHA384_DIGEST_SIZE) == 0; } - ZT_INLINE bool operator!=(const ZT_IdentificationCertificate &c) const noexcept + ZT_INLINE bool operator!=(const ZT_Certificate &c) const noexcept { return memcmp(this->serialNo, c.serialNo, ZT_SHA384_DIGEST_SIZE) != 0; } - ZT_INLINE bool operator<(const ZT_IdentificationCertificate &c) const noexcept + ZT_INLINE bool operator<(const ZT_Certificate &c) const noexcept { return memcmp(this->serialNo, c.serialNo, ZT_SHA384_DIGEST_SIZE) < 0; } - ZT_INLINE bool operator<=(const ZT_IdentificationCertificate &c) const noexcept + ZT_INLINE bool operator<=(const ZT_Certificate &c) const noexcept { return memcmp(this->serialNo, c.serialNo, ZT_SHA384_DIGEST_SIZE) <= 0; } - ZT_INLINE bool operator>(const ZT_IdentificationCertificate &c) const noexcept + ZT_INLINE bool operator>(const ZT_Certificate &c) const noexcept { return memcmp(this->serialNo, c.serialNo, ZT_SHA384_DIGEST_SIZE) > 0; } - ZT_INLINE bool operator>=(const ZT_IdentificationCertificate &c) const noexcept + ZT_INLINE bool operator>=(const ZT_Certificate &c) const noexcept { return memcmp(this->serialNo, c.serialNo, ZT_SHA384_DIGEST_SIZE) >= 0; } private: @@ -160,10 +168,12 @@ private: List< Identity > m_identities; List< Locator > m_locators; List< String > m_strings; + List< Blob< ZT_SHA384_DIGEST_SIZE > > m_serials; // These are stored in a vector because the memory needs to be contiguous. - Vector< ZT_IdentificationCertificate_Node > m_nodes; - Vector< ZT_IdentificationCertificate_Network > m_networks; + Vector< ZT_Certificate_Identity > m_subjectIdentities; + Vector< ZT_Certificate_Network > m_subjectNetworks; + Vector< const uint8_t * > m_subjectCertificates; Vector< const char * > m_updateUrls; }; diff --git a/core/Containers.hpp b/core/Containers.hpp index cfca4ce46..2c4820176 100644 --- a/core/Containers.hpp +++ b/core/Containers.hpp @@ -11,8 +11,8 @@ */ /****/ -#ifndef ZT_MAP_HPP -#define ZT_MAP_HPP +#ifndef ZT_CONTAINERS_HPP +#define ZT_CONTAINERS_HPP /* This defines a Map, SortedMap, Vector, etc. based on STL templates. */ @@ -40,51 +40,40 @@ struct intl_MapHasher template< typename O > std::size_t operator()(const O &obj) const noexcept { return (std::size_t)obj.hashCode(); } - std::size_t operator()(const uint64_t i) const noexcept { return (std::size_t)Utils::hash64(i + Utils::s_mapNonce); } - std::size_t operator()(const int64_t i) const noexcept { return (std::size_t)Utils::hash64((uint64_t)i + Utils::s_mapNonce); } - std::size_t operator()(const uint32_t i) const noexcept { return (std::size_t)Utils::hash32(i + (uint32_t)Utils::s_mapNonce); } - std::size_t operator()(const int32_t i) const noexcept { return (std::size_t)Utils::hash32((uint32_t)i + (uint32_t)Utils::s_mapNonce); } }; template< typename K, typename V > -class Map : public std::unordered_map< K, V, intl_MapHasher, std::equal_to< K >, Utils::Mallocator < std::pair< const K, V > > - -> { +class Map : public std::unordered_map< K, V, intl_MapHasher, std::equal_to< K >, Utils::Mallocator < std::pair< const K, V > > > +{ public: -ZT_INLINE V *get(const K &key) noexcept -{ - typename Map::iterator i(this->find(key)); - if (i == this->end()) - return nullptr; - return &(i->second); -} - -ZT_INLINE const V *get(const K &key) const noexcept -{ - typename Map::const_iterator i(this->find(key)); - if (i == this->end()) - return nullptr; - return &(i->second); -} - -ZT_INLINE void set(const K &key, const V &value) -{ this->emplace(key, value); } + ZT_INLINE V *get(const K &key) noexcept + { + typename Map::iterator i(this->find(key)); + if (i == this->end()) + return nullptr; + return &(i->second); + } + ZT_INLINE const V *get(const K &key) const noexcept + { + typename Map::const_iterator i(this->find(key)); + if (i == this->end()) + return nullptr; + return &(i->second); + } + ZT_INLINE void set(const K &key, const V &value) { this->emplace(key, value); } }; template< typename K, typename V > -class MultiMap : public std::unordered_multimap< K, V, intl_MapHasher, std::equal_to< K >, Utils::Mallocator < std::pair< const K, V > > - -> -{ -}; +class MultiMap : public std::unordered_multimap< K, V, intl_MapHasher, std::equal_to< K >, Utils::Mallocator < std::pair< const K, V > > > +{}; #else @@ -120,103 +109,54 @@ class MultiMap : public std::multimap< K,V,std::less,Utils::Mallocator< std:: #endif template< typename K, typename V > -class SortedMap : public std::map< K, V, std::less< K >, Utils::Mallocator < std::pair< const K, V > > - -> +class SortedMap : public std::map< K, V, std::less< K >, Utils::Mallocator < std::pair< const K, V > > > { public: -ZT_INLINE V *get(const K &key) noexcept -{ - typename SortedMap::iterator i(this->find(key)); - if (i == this->end()) - return nullptr; - return &(i->second); -} - -ZT_INLINE const V *get(const K &key) const noexcept -{ - typename SortedMap::const_iterator i(this->find(key)); - if (i == this->end()) - return nullptr; - return &(i->second); -} - -ZT_INLINE void set(const K &key, const V &value) -{ (*this)[key] = value; } - + ZT_INLINE V *get(const K &key) noexcept + { + typename SortedMap::iterator i(this->find(key)); + if (i == this->end()) + return nullptr; + return &(i->second); + } + ZT_INLINE const V *get(const K &key) const noexcept + { + typename SortedMap::const_iterator i(this->find(key)); + if (i == this->end()) + return nullptr; + return &(i->second); + } + ZT_INLINE void set(const K &key, const V &value) { (*this)[key] = value; } }; template< typename V > -class Vector : public std::vector< V, Utils::Mallocator < V > - -> +class Vector : public std::vector< V, Utils::Mallocator < V > > { public: -ZT_INLINE Vector() -{} - -template< typename I > -ZT_INLINE Vector(I -begin, -I end -) : std::vector< V, Utils::Mallocator < V > >(begin,end) { -} + ZT_INLINE Vector() {} + template< typename I > + ZT_INLINE Vector(I begin,I end) : std::vector< V, Utils::Mallocator < V > >(begin,end) {} }; template< typename V > -class List : public std::list< V, Utils::Mallocator < V > - -> +class List : public std::list< V, Utils::Mallocator < V > > { }; template< typename V > -class Set : public std::set< V, std::less< V >, Utils::Mallocator < V > - -> +class Set : public std::set< V, std::less< V >, Utils::Mallocator < V > > { }; -class String : public std::basic_string< char, std::char_traits< char >, Utils::Mallocator < char > - -> +class String : public std::basic_string< char, std::char_traits< char >, Utils::Mallocator < char > > { public: -ZT_INLINE String() -{} - -ZT_INLINE String(const String &s) : std::basic_string< char, std::char_traits< char >, Utils::Mallocator < char > - ->(s. - -c_str() - -) { -} -ZT_INLINE String(const std::string &s) : std::basic_string< char, std::char_traits< char >, Utils::Mallocator < char > - ->(s. - -c_str() - -) { -} -ZT_INLINE String(const char *const s) : std::basic_string< char, std::char_traits< char >, Utils::Mallocator < char > - ->(s) { -} -ZT_INLINE String &operator=(const char *const s) -{ - assign(s); - return *this; -} - -ZT_INLINE String &operator=(const std::string &s) -{ - assign(s.c_str()); - return *this; -} - + ZT_INLINE String() {} + ZT_INLINE String(const String &s) : std::basic_string< char, std::char_traits< char >, Utils::Mallocator < char > >(s.c_str()) {} + ZT_INLINE String(const std::string &s) : std::basic_string< char, std::char_traits< char >, Utils::Mallocator < char > >(s.c_str()) {} + ZT_INLINE String(const char *const s) : std::basic_string< char, std::char_traits< char >, Utils::Mallocator < char > >(s) {} + ZT_INLINE String &operator=(const char *const s) { assign(s); return *this; } + ZT_INLINE String &operator=(const std::string &s) { assign(s.c_str()); return *this; } }; } // ZeroTier diff --git a/core/Credential.cpp b/core/Credential.cpp index ab34e3f79..94e23b1ef 100644 --- a/core/Credential.cpp +++ b/core/Credential.cpp @@ -14,11 +14,11 @@ #include "Constants.hpp" #include "RuntimeEnvironment.hpp" #include "Credential.hpp" -#include "Capability.hpp" -#include "Tag.hpp" -#include "CertificateOfMembership.hpp" -#include "CertificateOfOwnership.hpp" -#include "Revocation.hpp" +#include "CapabilityCredential.hpp" +#include "TagCredential.hpp" +#include "MembershipCredential.hpp" +#include "OwnershipCredential.hpp" +#include "RevocationCredential.hpp" #include "Network.hpp" #include "Topology.hpp" @@ -66,12 +66,12 @@ static ZT_INLINE Credential::VerifyResult _credVerify(const RuntimeEnvironment * return Credential::VERIFY_BAD_SIGNATURE; } -Credential::VerifyResult Credential::_verify(const RuntimeEnvironment *const RR,void *tPtr,const Revocation &credential) const { return _credVerify(RR,tPtr,credential); } -Credential::VerifyResult Credential::_verify(const RuntimeEnvironment *const RR,void *tPtr,const Tag &credential) const { return _credVerify(RR,tPtr,credential); } -Credential::VerifyResult Credential::_verify(const RuntimeEnvironment *const RR,void *tPtr,const Capability &credential) const { return _credVerify(RR,tPtr,credential); } -Credential::VerifyResult Credential::_verify(const RuntimeEnvironment *const RR,void *tPtr,const CertificateOfOwnership &credential) const { return _credVerify(RR,tPtr,credential); } +Credential::VerifyResult Credential::_verify(const RuntimeEnvironment *const RR,void *tPtr,const RevocationCredential &credential) const { return _credVerify(RR, tPtr, credential); } +Credential::VerifyResult Credential::_verify(const RuntimeEnvironment *const RR,void *tPtr,const TagCredential &credential) const { return _credVerify(RR, tPtr, credential); } +Credential::VerifyResult Credential::_verify(const RuntimeEnvironment *const RR,void *tPtr,const CapabilityCredential &credential) const { return _credVerify(RR, tPtr, credential); } +Credential::VerifyResult Credential::_verify(const RuntimeEnvironment *const RR,void *tPtr,const OwnershipCredential &credential) const { return _credVerify(RR, tPtr, credential); } -Credential::VerifyResult Credential::_verify(const RuntimeEnvironment *const RR,void *tPtr,const CertificateOfMembership &credential) const +Credential::VerifyResult Credential::_verify(const RuntimeEnvironment *const RR,void *tPtr,const MembershipCredential &credential) const { // Sanity check network ID. if ((!credential.m_signedBy) || (credential.m_signedBy != Network::controllerFor(credential.m_networkId))) diff --git a/core/Credential.hpp b/core/Credential.hpp index 5ae95012a..06ee4949e 100644 --- a/core/Credential.hpp +++ b/core/Credential.hpp @@ -23,11 +23,11 @@ namespace ZeroTier { -class Capability; -class Revocation; -class Tag; -class CertificateOfMembership; -class CertificateOfOwnership; +class CapabilityCredential; +class RevocationCredential; +class TagCredential; +class MembershipCredential; +class OwnershipCredential; class RuntimeEnvironment; /** @@ -52,11 +52,11 @@ public: }; protected: - VerifyResult _verify(const RuntimeEnvironment *RR,void *tPtr,const CertificateOfMembership &credential) const; - VerifyResult _verify(const RuntimeEnvironment *RR,void *tPtr,const Revocation &credential) const; - VerifyResult _verify(const RuntimeEnvironment *RR,void *tPtr,const Tag &credential) const; - VerifyResult _verify(const RuntimeEnvironment *RR,void *tPtr,const CertificateOfOwnership &credential) const; - VerifyResult _verify(const RuntimeEnvironment *RR,void *tPtr,const Capability &credential) const; + VerifyResult _verify(const RuntimeEnvironment *RR,void *tPtr,const MembershipCredential &credential) const; + VerifyResult _verify(const RuntimeEnvironment *RR,void *tPtr,const RevocationCredential &credential) const; + VerifyResult _verify(const RuntimeEnvironment *RR,void *tPtr,const TagCredential &credential) const; + VerifyResult _verify(const RuntimeEnvironment *RR,void *tPtr,const OwnershipCredential &credential) const; + VerifyResult _verify(const RuntimeEnvironment *RR,void *tPtr,const CapabilityCredential &credential) const; }; } // namespace ZeroTier diff --git a/core/Dictionary.hpp b/core/Dictionary.hpp index d0c836d90..653be053f 100644 --- a/core/Dictionary.hpp +++ b/core/Dictionary.hpp @@ -431,7 +431,10 @@ private: return buf; } - SortedMap > m_entries; + // Dictionary maps need to be sorted so that they always encode in the same order + // to yield blobs that can be hashed and signed reproducibly. Other than for areas + // where dictionaries are signed and verified the order doesn't matter. + SortedMap < String, Vector< uint8_t > > m_entries; }; } // namespace ZeroTier diff --git a/core/Expect.hpp b/core/Expect.hpp index 6546632d8..14c8c08f2 100644 --- a/core/Expect.hpp +++ b/core/Expect.hpp @@ -49,9 +49,7 @@ public: * @param now Current time */ ZT_INLINE void sending(const uint64_t packetId, const int64_t now) noexcept - { - m_packetIdSent[Utils::hash64(packetId ^ Utils::s_mapNonce) % ZT_EXPECT_BUCKETS].store((uint32_t)(now / ZT_EXPECT_TTL)); - } + { m_packetIdSent[Utils::hash64(packetId ^ Utils::s_mapNonce) % ZT_EXPECT_BUCKETS].store((uint32_t)(now / ZT_EXPECT_TTL)); } /** * Check if an OK is expected and if so reset the corresponding bucket. @@ -64,9 +62,7 @@ public: * @return True if we're expecting a reply (and a reset occurred) */ ZT_INLINE bool expecting(const uint64_t inRePacketId, const int64_t now) noexcept - { - return (((now / ZT_EXPECT_TTL) - (int64_t)m_packetIdSent[(unsigned long)Utils::hash64(inRePacketId ^ Utils::s_mapNonce) % ZT_EXPECT_BUCKETS].exchange(0)) <= 1); - } + { return (((now / ZT_EXPECT_TTL) - (int64_t)m_packetIdSent[(unsigned long)Utils::hash64(inRePacketId ^ Utils::s_mapNonce) % ZT_EXPECT_BUCKETS].exchange(0)) <= 1); } private: // Each bucket contains a timestamp in units of the max expect duration. diff --git a/core/Identity.hpp b/core/Identity.hpp index 4b9d8ff71..81e8a972c 100644 --- a/core/Identity.hpp +++ b/core/Identity.hpp @@ -222,27 +222,20 @@ public: ZT_INLINE bool operator==(const Identity &id) const noexcept { return (m_fp == id.m_fp); } - ZT_INLINE bool operator!=(const Identity &id) const noexcept { return !(*this == id); } - ZT_INLINE bool operator<(const Identity &id) const noexcept { return (m_fp < id.m_fp); } - ZT_INLINE bool operator>(const Identity &id) const noexcept { return (id < *this); } - ZT_INLINE bool operator<=(const Identity &id) const noexcept { return !(id < *this); } - ZT_INLINE bool operator>=(const Identity &id) const noexcept { return !(*this < id); } static constexpr int marshalSizeMax() noexcept { return ZT_IDENTITY_MARSHAL_SIZE_MAX; } - int marshal(uint8_t data[ZT_IDENTITY_MARSHAL_SIZE_MAX], bool includePrivate = false) const noexcept; - int unmarshal(const uint8_t *data, int len) noexcept; private: diff --git a/core/MAC.hpp b/core/MAC.hpp index b2090d407..59e1a1017 100644 --- a/core/MAC.hpp +++ b/core/MAC.hpp @@ -62,9 +62,7 @@ public: * @param len Length, must be >= 6 or result is zero */ ZT_INLINE void setTo(const uint8_t b[6]) noexcept - { - m_mac = ((uint64_t)b[0] << 40U) | ((uint64_t)b[1] << 32U) | ((uint64_t)b[2] << 24U) | ((uint64_t)b[3] << 16U) | ((uint64_t)b[4] << 8U) | (uint64_t)b[5]; - } + { m_mac = ((uint64_t)b[0] << 40U) | ((uint64_t)b[1] << 32U) | ((uint64_t)b[2] << 24U) | ((uint64_t)b[3] << 16U) | ((uint64_t)b[4] << 8U) | (uint64_t)b[5]; } /** * @param buf Destination buffer for MAC in big-endian byte order @@ -221,44 +219,30 @@ public: } ZT_INLINE MAC &operator=(const uint64_t m) noexcept - { - m_mac = m; - return *this; - } + { m_mac = m; return *this; } ZT_INLINE bool operator==(const MAC &m) const noexcept { return (m_mac == m.m_mac); } - ZT_INLINE bool operator!=(const MAC &m) const noexcept { return (m_mac != m.m_mac); } - ZT_INLINE bool operator<(const MAC &m) const noexcept { return (m_mac < m.m_mac); } - ZT_INLINE bool operator<=(const MAC &m) const noexcept { return (m_mac <= m.m_mac); } - ZT_INLINE bool operator>(const MAC &m) const noexcept { return (m_mac > m.m_mac); } - ZT_INLINE bool operator>=(const MAC &m) const noexcept { return (m_mac >= m.m_mac); } - ZT_INLINE bool operator==(const uint64_t m) const noexcept { return (m_mac == m); } - ZT_INLINE bool operator!=(const uint64_t m) const noexcept { return (m_mac != m); } - ZT_INLINE bool operator<(const uint64_t m) const noexcept { return (m_mac < m); } - ZT_INLINE bool operator<=(const uint64_t m) const noexcept { return (m_mac <= m); } - ZT_INLINE bool operator>(const uint64_t m) const noexcept { return (m_mac > m); } - ZT_INLINE bool operator>=(const uint64_t m) const noexcept { return (m_mac >= m); } diff --git a/core/Membership.cpp b/core/Member.cpp similarity index 77% rename from core/Membership.cpp rename to core/Member.cpp index 21874e705..e7ad98864 100644 --- a/core/Membership.cpp +++ b/core/Member.cpp @@ -13,14 +13,14 @@ #include -#include "Membership.hpp" +#include "Member.hpp" #include "RuntimeEnvironment.hpp" #include "Peer.hpp" #include "Topology.hpp" namespace ZeroTier { -Membership::Membership() : +Member::Member() : m_comRevocationThreshold(0), m_lastPushedCredentials(0), m_comAgreementLocalTimestamp(0), @@ -28,14 +28,14 @@ Membership::Membership() : { } -void Membership::pushCredentials(const RuntimeEnvironment *RR,void *tPtr,const int64_t now,const SharedPtr &to,const NetworkConfig &nconf) +void Member::pushCredentials(const RuntimeEnvironment *RR, void *tPtr, const int64_t now, const SharedPtr &to, const NetworkConfig &nconf) { if (!nconf.com) // sanity check return; #if 0 SharedPtr outp(new Buf()); - Protocol::Header &ph = outp->as(); // NOLINT(hicpp-use-auto,modernize-use-auto) + Protocol::Header &ph = outp->as(); unsigned int capPtr = 0,tagPtr = 0,cooPtr = 0; bool sendCom = true; @@ -115,14 +115,14 @@ void Membership::pushCredentials(const RuntimeEnvironment *RR,void *tPtr,const i m_lastPushedCredentials = now; } -void Membership::clean(const int64_t now,const NetworkConfig &nconf) +void Member::clean(const int64_t now, const NetworkConfig &nconf) { - m_cleanCredImpl(nconf, m_remoteTags); - m_cleanCredImpl(nconf, m_remoteCaps); - m_cleanCredImpl(nconf, m_remoteCoos); + m_cleanCredImpl(nconf, m_remoteTags); + m_cleanCredImpl(nconf, m_remoteCaps); + m_cleanCredImpl(nconf, m_remoteCoos); } -Membership::AddCredentialResult Membership::addCredential(const RuntimeEnvironment *RR,void *tPtr,const Identity &sourcePeerIdentity,const NetworkConfig &nconf,const CertificateOfMembership &com) +Member::AddCredentialResult Member::addCredential(const RuntimeEnvironment *RR, void *tPtr, const Identity &sourcePeerIdentity, const NetworkConfig &nconf, const MembershipCredential &com) { const int64_t newts = com.timestamp(); if (newts <= m_comRevocationThreshold) { @@ -141,7 +141,7 @@ Membership::AddCredentialResult Membership::addCredential(const RuntimeEnvironme switch(com.verify(RR,tPtr)) { default: RR->t->credentialRejected(tPtr,0x0f198241,com.networkId(),sourcePeerIdentity,com.id(),com.timestamp(),ZT_CREDENTIAL_TYPE_COM,ZT_TRACE_CREDENTIAL_REJECTION_REASON_INVALID); - return Membership::ADD_REJECTED; + return Member::ADD_REJECTED; case Credential::VERIFY_OK: m_com = com; return ADD_ACCEPTED_NEW; @@ -155,7 +155,7 @@ Membership::AddCredentialResult Membership::addCredential(const RuntimeEnvironme // 3/5 of the credential types have identical addCredential() code template -static ZT_INLINE Membership::AddCredentialResult _addCredImpl( +static ZT_INLINE Member::AddCredentialResult _addCredImpl( Map &remoteCreds, const Map &revocations, const RuntimeEnvironment *const RR, @@ -168,36 +168,36 @@ static ZT_INLINE Membership::AddCredentialResult _addCredImpl( if (rc) { if (rc->timestamp() > cred.timestamp()) { RR->t->credentialRejected(tPtr,0x40000001,nconf.networkId,sourcePeerIdentity,cred.id(),cred.timestamp(),C::credentialType(),ZT_TRACE_CREDENTIAL_REJECTION_REASON_OLDER_THAN_LATEST); - return Membership::ADD_REJECTED; + return Member::ADD_REJECTED; } if (*rc == cred) - return Membership::ADD_ACCEPTED_REDUNDANT; + return Member::ADD_ACCEPTED_REDUNDANT; } - const int64_t *const rt = revocations.get(Membership::credentialKey(C::credentialType(),cred.id())); + const int64_t *const rt = revocations.get(Member::credentialKey(C::credentialType(), cred.id())); if ((rt)&&(*rt >= cred.timestamp())) { RR->t->credentialRejected(tPtr,0x24248124,nconf.networkId,sourcePeerIdentity,cred.id(),cred.timestamp(),C::credentialType(),ZT_TRACE_CREDENTIAL_REJECTION_REASON_REVOKED); - return Membership::ADD_REJECTED; + return Member::ADD_REJECTED; } switch(cred.verify(RR,tPtr)) { default: RR->t->credentialRejected(tPtr,0x01feba012,nconf.networkId,sourcePeerIdentity,cred.id(),cred.timestamp(),C::credentialType(),ZT_TRACE_CREDENTIAL_REJECTION_REASON_INVALID); - return Membership::ADD_REJECTED; + return Member::ADD_REJECTED; case 0: if (!rc) rc = &(remoteCreds[cred.id()]); *rc = cred; - return Membership::ADD_ACCEPTED_NEW; + return Member::ADD_ACCEPTED_NEW; case 1: - return Membership::ADD_DEFERRED_FOR_WHOIS; + return Member::ADD_DEFERRED_FOR_WHOIS; } } -Membership::AddCredentialResult Membership::addCredential(const RuntimeEnvironment *RR,void *tPtr,const Identity &sourcePeerIdentity,const NetworkConfig &nconf,const Tag &tag) { return _addCredImpl(m_remoteTags, m_revocations, RR, tPtr, sourcePeerIdentity, nconf, tag); } -Membership::AddCredentialResult Membership::addCredential(const RuntimeEnvironment *RR,void *tPtr,const Identity &sourcePeerIdentity,const NetworkConfig &nconf,const Capability &cap) { return _addCredImpl(m_remoteCaps, m_revocations, RR, tPtr, sourcePeerIdentity, nconf, cap); } -Membership::AddCredentialResult Membership::addCredential(const RuntimeEnvironment *RR,void *tPtr,const Identity &sourcePeerIdentity,const NetworkConfig &nconf,const CertificateOfOwnership &coo) { return _addCredImpl(m_remoteCoos, m_revocations, RR, tPtr, sourcePeerIdentity, nconf, coo); } +Member::AddCredentialResult Member::addCredential(const RuntimeEnvironment *RR, void *tPtr, const Identity &sourcePeerIdentity, const NetworkConfig &nconf, const TagCredential &tag) { return _addCredImpl(m_remoteTags, m_revocations, RR, tPtr, sourcePeerIdentity, nconf, tag); } +Member::AddCredentialResult Member::addCredential(const RuntimeEnvironment *RR, void *tPtr, const Identity &sourcePeerIdentity, const NetworkConfig &nconf, const CapabilityCredential &cap) { return _addCredImpl(m_remoteCaps, m_revocations, RR, tPtr, sourcePeerIdentity, nconf, cap); } +Member::AddCredentialResult Member::addCredential(const RuntimeEnvironment *RR, void *tPtr, const Identity &sourcePeerIdentity, const NetworkConfig &nconf, const OwnershipCredential &coo) { return _addCredImpl(m_remoteCoos, m_revocations, RR, tPtr, sourcePeerIdentity, nconf, coo); } -Membership::AddCredentialResult Membership::addCredential(const RuntimeEnvironment *RR,void *tPtr,const Identity &sourcePeerIdentity,const NetworkConfig &nconf,const Revocation &rev) +Member::AddCredentialResult Member::addCredential(const RuntimeEnvironment *RR, void *tPtr, const Identity &sourcePeerIdentity, const NetworkConfig &nconf, const RevocationCredential &rev) { int64_t *rt; switch(rev.verify(RR,tPtr)) { @@ -233,7 +233,7 @@ Membership::AddCredentialResult Membership::addCredential(const RuntimeEnvironme } } -bool Membership::m_isUnspoofableAddress(const NetworkConfig &nconf, const InetAddress &ip) const noexcept +bool Member::m_isUnspoofableAddress(const NetworkConfig &nconf, const InetAddress &ip) const noexcept { if ((ip.isV6())&&(nconf.ndpEmulation())) { const InetAddress sixpl(InetAddress::makeIpv66plane(nconf.networkId,nconf.issuedTo.toInt())); diff --git a/core/Membership.hpp b/core/Member.hpp similarity index 85% rename from core/Membership.hpp rename to core/Member.hpp index e878045c1..bb617f920 100644 --- a/core/Membership.hpp +++ b/core/Member.hpp @@ -17,10 +17,10 @@ #include "Constants.hpp" #include "Credential.hpp" #include "Containers.hpp" -#include "CertificateOfMembership.hpp" -#include "Capability.hpp" -#include "Tag.hpp" -#include "Revocation.hpp" +#include "MembershipCredential.hpp" +#include "CapabilityCredential.hpp" +#include "TagCredential.hpp" +#include "RevocationCredential.hpp" #include "NetworkConfig.hpp" namespace ZeroTier { @@ -35,7 +35,7 @@ class Network; * * This class is not thread safe. It must be locked externally. */ -class Membership +class Member { public: enum AddCredentialResult @@ -46,7 +46,7 @@ public: ADD_DEFERRED_FOR_WHOIS }; - Membership(); + Member(); /** * Send COM and other credentials to this peer @@ -71,10 +71,10 @@ public: * @param id Tag ID * @return Pointer to tag or NULL if not found */ - ZT_INLINE const Tag *getTag(const NetworkConfig &nconf,const uint32_t id) const noexcept + ZT_INLINE const TagCredential *getTag(const NetworkConfig &nconf, const uint32_t id) const noexcept { - const Tag *const t = m_remoteTags.get(id); - return (((t)&&(m_isCredentialTimestampValid(nconf, *t))) ? t : (Tag *)0); + const TagCredential *const t = m_remoteTags.get(id); + return (((t)&&(m_isCredentialTimestampValid(nconf, *t))) ? t : (TagCredential *)0); } /** @@ -103,7 +103,7 @@ public: { if (m_isUnspoofableAddress(nconf, r)) return true; - for(Map< uint32_t,CertificateOfOwnership >::const_iterator i(m_remoteCoos.begin());i != m_remoteCoos.end();++i) { + for(Map< uint32_t,OwnershipCredential >::const_iterator i(m_remoteCoos.begin()); i != m_remoteCoos.end(); ++i) { if (m_isCredentialTimestampValid(nconf, i->second) && (i->second.owns(r))) return true; } @@ -115,7 +115,7 @@ public: * * @param localCom */ - ZT_INLINE bool certificateOfMembershipAgress(const CertificateOfMembership &localCom,const Identity &remoteIdentity) + ZT_INLINE bool certificateOfMembershipAgress(const MembershipCredential &localCom, const Identity &remoteIdentity) { if ((m_comAgreementLocalTimestamp == localCom.timestamp()) && (m_comAgreementRemoteTimestamp == m_com.timestamp())) return true; @@ -146,11 +146,11 @@ public: return false; } - AddCredentialResult addCredential(const RuntimeEnvironment *RR,void *tPtr,const Identity &sourcePeerIdentity,const NetworkConfig &nconf,const CertificateOfMembership &com); - AddCredentialResult addCredential(const RuntimeEnvironment *RR,void *tPtr,const Identity &sourcePeerIdentity,const NetworkConfig &nconf,const Tag &tag); - AddCredentialResult addCredential(const RuntimeEnvironment *RR,void *tPtr,const Identity &sourcePeerIdentity,const NetworkConfig &nconf,const Capability &cap); - AddCredentialResult addCredential(const RuntimeEnvironment *RR,void *tPtr,const Identity &sourcePeerIdentity,const NetworkConfig &nconf,const CertificateOfOwnership &coo); - AddCredentialResult addCredential(const RuntimeEnvironment *RR,void *tPtr,const Identity &sourcePeerIdentity,const NetworkConfig &nconf,const Revocation &rev); + AddCredentialResult addCredential(const RuntimeEnvironment *RR,void *tPtr,const Identity &sourcePeerIdentity,const NetworkConfig &nconf,const MembershipCredential &com); + AddCredentialResult addCredential(const RuntimeEnvironment *RR,void *tPtr,const Identity &sourcePeerIdentity,const NetworkConfig &nconf,const TagCredential &tag); + AddCredentialResult addCredential(const RuntimeEnvironment *RR,void *tPtr,const Identity &sourcePeerIdentity,const NetworkConfig &nconf,const CapabilityCredential &cap); + AddCredentialResult addCredential(const RuntimeEnvironment *RR,void *tPtr,const Identity &sourcePeerIdentity,const NetworkConfig &nconf,const OwnershipCredential &coo); + AddCredentialResult addCredential(const RuntimeEnvironment *RR,void *tPtr,const Identity &sourcePeerIdentity,const NetworkConfig &nconf,const RevocationCredential &rev); private: // This returns true if a resource is an IPv6 NDP-emulated address. These embed the ZT @@ -192,31 +192,31 @@ private: int64_t m_comAgreementLocalTimestamp,m_comAgreementRemoteTimestamp; // Remote member's latest network COM - CertificateOfMembership m_com; + MembershipCredential m_com; // Revocations by credentialKey() Map m_revocations; // Remote credentials that we have received from this member (and that are valid) - Map m_remoteTags; - Map m_remoteCaps; - Map m_remoteCoos; + Map m_remoteTags; + Map m_remoteCaps; + Map m_remoteCoos; public: class CapabilityIterator { public: - ZT_INLINE CapabilityIterator(Membership &m,const NetworkConfig &nconf) noexcept : + ZT_INLINE CapabilityIterator(Member &m, const NetworkConfig &nconf) noexcept : m_hti(m.m_remoteCaps.begin()), m_parent(m), m_nconf(nconf) { } - ZT_INLINE Capability *next() noexcept + ZT_INLINE CapabilityCredential *next() noexcept { while (m_hti != m_parent.m_remoteCaps.end()) { - Map< uint32_t,Capability >::iterator i(m_hti++); // NOLINT(hicpp-use-auto,modernize-use-auto) + Map< uint32_t,CapabilityCredential >::iterator i(m_hti++); if (m_parent.m_isCredentialTimestampValid(m_nconf, i->second)) return &(i->second); } @@ -224,8 +224,8 @@ public: } private: - Map< uint32_t,Capability >::iterator m_hti; - Membership &m_parent; + Map< uint32_t,CapabilityCredential >::iterator m_hti; + Member &m_parent; const NetworkConfig &m_nconf; }; }; diff --git a/core/CertificateOfMembership.cpp b/core/MembershipCredential.cpp similarity index 92% rename from core/CertificateOfMembership.cpp rename to core/MembershipCredential.cpp index d09aa5cd8..4c4f47f9b 100644 --- a/core/CertificateOfMembership.cpp +++ b/core/MembershipCredential.cpp @@ -11,11 +11,11 @@ */ /****/ -#include "CertificateOfMembership.hpp" +#include "MembershipCredential.hpp" namespace ZeroTier { -CertificateOfMembership::CertificateOfMembership(const int64_t timestamp, const int64_t timestampMaxDelta, const uint64_t nwid, const Identity &issuedTo) noexcept: // NOLINT(cppcoreguidelines-pro-type-member-init,hicpp-member-init) +MembershipCredential::MembershipCredential(const int64_t timestamp, const int64_t timestampMaxDelta, const uint64_t nwid, const Identity &issuedTo) noexcept: // NOLINT(cppcoreguidelines-pro-type-member-init,hicpp-member-init) m_timestamp(timestamp), m_timestampMaxDelta(timestampMaxDelta), m_networkId(nwid), @@ -23,7 +23,7 @@ CertificateOfMembership::CertificateOfMembership(const int64_t timestamp, const m_signatureLength(0) {} -bool CertificateOfMembership::agreesWith(const CertificateOfMembership &other) const noexcept +bool MembershipCredential::agreesWith(const MembershipCredential &other) const noexcept { // NOTE: we always do explicit absolute value with an if() since llabs() can have overflow // conditions that could introduce a vulnerability. @@ -85,7 +85,7 @@ bool CertificateOfMembership::agreesWith(const CertificateOfMembership &other) c return (other.m_networkId == m_networkId) && (m_networkId != 0) && (other.m_issuedTo.address != m_issuedTo.address); } -bool CertificateOfMembership::sign(const Identity &with) noexcept +bool MembershipCredential::sign(const Identity &with) noexcept { m_signedBy = with.address(); uint64_t buf[ZT_CERTIFICATEOFMEMBERSHIP_MARSHAL_SIZE_MAX / 8]; @@ -94,7 +94,7 @@ bool CertificateOfMembership::sign(const Identity &with) noexcept return m_signatureLength > 0; } -int CertificateOfMembership::marshal(uint8_t data[ZT_CERTIFICATEOFMEMBERSHIP_MARSHAL_SIZE_MAX], const bool v2) const noexcept +int MembershipCredential::marshal(uint8_t data[ZT_CERTIFICATEOFMEMBERSHIP_MARSHAL_SIZE_MAX], const bool v2) const noexcept { data[0] = v2 ? 2 : 1; @@ -156,7 +156,7 @@ int CertificateOfMembership::marshal(uint8_t data[ZT_CERTIFICATEOFMEMBERSHIP_MAR return p; } -int CertificateOfMembership::unmarshal(const uint8_t *data, int len) noexcept +int MembershipCredential::unmarshal(const uint8_t *data, int len) noexcept { if (len < (1 + 2 + 72)) return -1; @@ -241,7 +241,7 @@ int CertificateOfMembership::unmarshal(const uint8_t *data, int len) noexcept return -1; } -unsigned int CertificateOfMembership::m_fillSigningBuf(uint64_t *buf) const noexcept +unsigned int MembershipCredential::m_fillSigningBuf(uint64_t *buf) const noexcept { const uint64_t informational = 0xffffffffffffffffULL; diff --git a/core/CertificateOfMembership.hpp b/core/MembershipCredential.hpp similarity index 94% rename from core/CertificateOfMembership.hpp rename to core/MembershipCredential.hpp index cf728271b..437174974 100644 --- a/core/CertificateOfMembership.hpp +++ b/core/MembershipCredential.hpp @@ -101,7 +101,7 @@ class RuntimeEnvironment; * order with the fingerprint hash being packed into tuple IDs 3-8 and this buffer is * then signed. */ -class CertificateOfMembership : public Credential +class MembershipCredential : public Credential { friend class Credential; @@ -111,7 +111,7 @@ public: /** * Create an empty certificate of membership */ - ZT_INLINE CertificateOfMembership() noexcept { memoryZero(this); } // NOLINT(cppcoreguidelines-pro-type-member-init,hicpp-member-init) + ZT_INLINE MembershipCredential() noexcept { memoryZero(this); } /** * Create from required fields common to all networks @@ -121,12 +121,12 @@ public: * @param nwid Network ID * @param issuedTo Certificate recipient */ - CertificateOfMembership(int64_t timestamp,int64_t timestampMaxDelta,uint64_t nwid,const Identity &issuedTo) noexcept; + MembershipCredential(int64_t timestamp, int64_t timestampMaxDelta, uint64_t nwid, const Identity &issuedTo) noexcept; /** * @return True if there's something here */ - ZT_INLINE operator bool() const noexcept { return (m_networkId != 0); } // NOLINT(google-explicit-constructor,hicpp-explicit-conversions) + ZT_INLINE operator bool() const noexcept { return (m_networkId != 0); } /** * @return Credential ID, always 0 for COMs @@ -166,7 +166,7 @@ public: * @param other Cert to compare with * @return True if certs agree and 'other' may be communicated with */ - bool agreesWith(const CertificateOfMembership &other) const noexcept; + bool agreesWith(const MembershipCredential &other) const noexcept; /** * Sign this certificate diff --git a/core/Network.cpp b/core/Network.cpp index cad32ec44..81ea00171 100644 --- a/core/Network.cpp +++ b/core/Network.cpp @@ -74,7 +74,7 @@ _doZtFilterResult _doZtFilter( const RuntimeEnvironment *RR, Trace::RuleResultLog &rrl, const NetworkConfig &nconf, - const Membership *membership, // can be NULL + const Member *membership, // can be NULL const bool inbound, const Address &ztSource, Address &ztDest, // MUTABLE -- is changed on REDIRECT actions @@ -420,9 +420,9 @@ _doZtFilterResult _doZtFilter( case ZT_NETWORK_RULE_MATCH_TAGS_BITWISE_OR: case ZT_NETWORK_RULE_MATCH_TAGS_BITWISE_XOR: case ZT_NETWORK_RULE_MATCH_TAGS_EQUAL: { - const Tag *const localTag = std::lower_bound(&(nconf.tags[0]),&(nconf.tags[nconf.tagCount]),rules[rn].v.tag.id,Tag::IdComparePredicate()); + const TagCredential *const localTag = std::lower_bound(&(nconf.tags[0]), &(nconf.tags[nconf.tagCount]), rules[rn].v.tag.id, TagCredential::IdComparePredicate()); if ((localTag != &(nconf.tags[nconf.tagCount]))&&(localTag->id() == rules[rn].v.tag.id)) { - const Tag *const remoteTag = ((membership) ? membership->getTag(nconf,rules[rn].v.tag.id) : (const Tag *)0); + const TagCredential *const remoteTag = ((membership) ? membership->getTag(nconf, rules[rn].v.tag.id) : (const TagCredential *)0); if (remoteTag) { const uint32_t ltv = localTag->value(); const uint32_t rtv = remoteTag->value(); @@ -461,7 +461,7 @@ _doZtFilterResult _doZtFilter( if (superAccept) { thisRuleMatches = 1; } else if ( ((rt == ZT_NETWORK_RULE_MATCH_TAG_SENDER)&&(inbound)) || ((rt == ZT_NETWORK_RULE_MATCH_TAG_RECEIVER)&&(!inbound)) ) { - const Tag *const remoteTag = ((membership) ? membership->getTag(nconf,rules[rn].v.tag.id) : (const Tag *)0); + const TagCredential *const remoteTag = ((membership) ? membership->getTag(nconf, rules[rn].v.tag.id) : (const TagCredential *)0); if (remoteTag) { thisRuleMatches = (uint8_t)(remoteTag->value() == rules[rn].v.tag.value); } else { @@ -474,7 +474,7 @@ _doZtFilterResult _doZtFilter( } } } else { // sender and outbound or receiver and inbound - const Tag *const localTag = std::lower_bound(&(nconf.tags[0]),&(nconf.tags[nconf.tagCount]),rules[rn].v.tag.id,Tag::IdComparePredicate()); + const TagCredential *const localTag = std::lower_bound(&(nconf.tags[0]), &(nconf.tags[nconf.tagCount]), rules[rn].v.tag.id, TagCredential::IdComparePredicate()); if ((localTag != &(nconf.tags[nconf.tagCount]))&&(localTag->id() == rules[rn].v.tag.id)) { thisRuleMatches = (uint8_t)(localTag->value() == rules[rn].v.tag.value); } else { @@ -626,7 +626,7 @@ bool Network::filterOutgoingPacket( Mutex::Lock l1(m_memberships_l); Mutex::Lock l2(m_config_l); - Membership *const membership = (ztDest) ? m_memberships.get(ztDest) : nullptr; + Member *const membership = (ztDest) ? m_memberships.get(ztDest) : nullptr; switch(_doZtFilter(RR, rrl, m_config, membership, false, ztSource, ztFinalDest, macSource, macDest, frameData, frameLen, etherType, vlanId, m_config.rules, m_config.ruleCount, cc, ccLength, ccWatch, qosBucket)) { @@ -719,7 +719,7 @@ bool Network::filterOutgoingPacket( } if (localCapabilityIndex >= 0) { - const Capability &cap = m_config.capabilities[localCapabilityIndex]; + const CapabilityCredential &cap = m_config.capabilities[localCapabilityIndex]; RR->t->networkFilter(tPtr, 0x56ff1a93, m_id, rrl.l, crrl.l, cap.id(), cap.timestamp(), ztSource, ztDest, macSource, macDest, (uint16_t)frameLen, frameData, (uint16_t)etherType, (uint16_t)vlanId, noTee, false, accept); } else { RR->t->networkFilter(tPtr, 0x112fbbab, m_id, rrl.l, nullptr, 0, 0, ztSource, ztDest, macSource, macDest, (uint16_t)frameLen, frameData, (uint16_t)etherType, (uint16_t)vlanId, noTee, false, accept); @@ -745,19 +745,19 @@ int Network::filterIncomingPacket( Address cc; unsigned int ccLength = 0; bool ccWatch = false; - const Capability *c = nullptr; + const CapabilityCredential *c = nullptr; uint8_t qosBucket = 255; // For incoming packets this is a dummy value Mutex::Lock l1(m_memberships_l); Mutex::Lock l2(m_config_l); - Membership &membership = m_memberships[sourcePeer->address()]; + Member &membership = m_memberships[sourcePeer->address()]; switch (_doZtFilter(RR, rrl, m_config, &membership, true, sourcePeer->address(), ztFinalDest, macSource, macDest, frameData, frameLen, etherType, vlanId, m_config.rules, m_config.ruleCount, cc, ccLength, ccWatch, qosBucket)) { case DOZTFILTER_NO_MATCH: { - Membership::CapabilityIterator mci(membership, m_config); + Member::CapabilityIterator mci(membership, m_config); while ((c = mci.next())) { ztFinalDest = ztDest; // sanity check, should be unmodified if there was no match Address cc2; @@ -1074,7 +1074,7 @@ bool Network::gate(void *tPtr,const SharedPtr &peer) noexcept try { Mutex::Lock l(m_memberships_l); - Membership *m = m_memberships.get(peer->address()); + Member *m = m_memberships.get(peer->address()); if (m) { // SECURITY: this method in CertificateOfMembership does a full fingerprint check as well as // checking certificate agreement. See Membership.hpp. @@ -1099,7 +1099,7 @@ void Network::doPeriodicTasks(void *tPtr,const int64_t now) { Mutex::Lock l1(m_memberships_l); - for(Map::iterator i(m_memberships.begin());i != m_memberships.end();++i) + for(Map::iterator i(m_memberships.begin()); i != m_memberships.end(); ++i) i->second.clean(now, m_config); { @@ -1150,41 +1150,41 @@ void Network::learnBridgeRoute(const MAC &mac,const Address &addr) } } -Membership::AddCredentialResult Network::addCredential(void *tPtr,const Identity &sourcePeerIdentity,const CertificateOfMembership &com) +Member::AddCredentialResult Network::addCredential(void *tPtr, const Identity &sourcePeerIdentity, const MembershipCredential &com) { if (com.networkId() != m_id) - return Membership::ADD_REJECTED; + return Member::ADD_REJECTED; Mutex::Lock _l(m_memberships_l); return m_memberships[com.issuedTo().address].addCredential(RR, tPtr, sourcePeerIdentity, m_config, com); } -Membership::AddCredentialResult Network::addCredential(void *tPtr,const Identity &sourcePeerIdentity,const Capability &cap) +Member::AddCredentialResult Network::addCredential(void *tPtr, const Identity &sourcePeerIdentity, const CapabilityCredential &cap) { if (cap.networkId() != m_id) - return Membership::ADD_REJECTED; + return Member::ADD_REJECTED; Mutex::Lock _l(m_memberships_l); return m_memberships[cap.issuedTo()].addCredential(RR, tPtr, sourcePeerIdentity, m_config, cap); } -Membership::AddCredentialResult Network::addCredential(void *tPtr,const Identity &sourcePeerIdentity,const Tag &tag) +Member::AddCredentialResult Network::addCredential(void *tPtr, const Identity &sourcePeerIdentity, const TagCredential &tag) { if (tag.networkId() != m_id) - return Membership::ADD_REJECTED; + return Member::ADD_REJECTED; Mutex::Lock _l(m_memberships_l); return m_memberships[tag.issuedTo()].addCredential(RR, tPtr, sourcePeerIdentity, m_config, tag); } -Membership::AddCredentialResult Network::addCredential(void *tPtr,const Identity &sourcePeerIdentity,const Revocation &rev) +Member::AddCredentialResult Network::addCredential(void *tPtr, const Identity &sourcePeerIdentity, const RevocationCredential &rev) { if (rev.networkId() != m_id) - return Membership::ADD_REJECTED; + return Member::ADD_REJECTED; Mutex::Lock l1(m_memberships_l); - Membership &m = m_memberships[rev.target()]; + Member &m = m_memberships[rev.target()]; - const Membership::AddCredentialResult result = m.addCredential(RR, tPtr, sourcePeerIdentity, m_config, rev); + const Member::AddCredentialResult result = m.addCredential(RR, tPtr, sourcePeerIdentity, m_config, rev); - if ((result == Membership::ADD_ACCEPTED_NEW)&&(rev.fastPropagate())) { + if ((result == Member::ADD_ACCEPTED_NEW) && (rev.fastPropagate())) { // TODO /* Address *a = nullptr; @@ -1208,10 +1208,10 @@ Membership::AddCredentialResult Network::addCredential(void *tPtr,const Identity return result; } -Membership::AddCredentialResult Network::addCredential(void *tPtr,const Identity &sourcePeerIdentity,const CertificateOfOwnership &coo) +Member::AddCredentialResult Network::addCredential(void *tPtr, const Identity &sourcePeerIdentity, const OwnershipCredential &coo) { if (coo.networkId() != m_id) - return Membership::ADD_REJECTED; + return Member::ADD_REJECTED; Mutex::Lock _l(m_memberships_l); return m_memberships[coo.issuedTo()].addCredential(RR, tPtr, sourcePeerIdentity, m_config, coo); } @@ -1220,7 +1220,7 @@ void Network::pushCredentials(void *tPtr,const SharedPtr &to,const int64_t { const int64_t tout = std::min(m_config.credentialTimeMaxDelta, m_config.com.timestampMaxDelta()); Mutex::Lock _l(m_memberships_l); - Membership &m = m_memberships[to->address()]; + Member &m = m_memberships[to->address()]; if (((now - m.lastPushedCredentials()) + 5000) >= tout) { m.pushCredentials(RR, tPtr, now, to, m_config); } diff --git a/core/Network.hpp b/core/Network.hpp index 5cc8a3e64..019f96b47 100644 --- a/core/Network.hpp +++ b/core/Network.hpp @@ -22,9 +22,9 @@ #include "MAC.hpp" #include "Buf.hpp" #include "Dictionary.hpp" -#include "Membership.hpp" +#include "Member.hpp" #include "NetworkConfig.hpp" -#include "CertificateOfMembership.hpp" +#include "MembershipCredential.hpp" #include "Containers.hpp" #define ZT_NETWORK_MAX_INCOMING_UPDATES 3 @@ -265,27 +265,27 @@ public: /** * Validate a credential and learn it if it passes certificate and other checks */ - Membership::AddCredentialResult addCredential(void *tPtr,const Identity &sourcePeerIdentity,const CertificateOfMembership &com); + Member::AddCredentialResult addCredential(void *tPtr, const Identity &sourcePeerIdentity, const MembershipCredential &com); /** * Validate a credential and learn it if it passes certificate and other checks */ - Membership::AddCredentialResult addCredential(void *tPtr,const Identity &sourcePeerIdentity,const Capability &cap); + Member::AddCredentialResult addCredential(void *tPtr, const Identity &sourcePeerIdentity, const CapabilityCredential &cap); /** * Validate a credential and learn it if it passes certificate and other checks */ - Membership::AddCredentialResult addCredential(void *tPtr,const Identity &sourcePeerIdentity,const Tag &tag); + Member::AddCredentialResult addCredential(void *tPtr, const Identity &sourcePeerIdentity, const TagCredential &tag); /** * Validate a credential and learn it if it passes certificate and other checks */ - Membership::AddCredentialResult addCredential(void *tPtr,const Identity &sourcePeerIdentity,const Revocation &rev); + Member::AddCredentialResult addCredential(void *tPtr, const Identity &sourcePeerIdentity, const RevocationCredential &rev); /** * Validate a credential and learn it if it passes certificate and other checks */ - Membership::AddCredentialResult addCredential(void *tPtr,const Identity &sourcePeerIdentity,const CertificateOfOwnership &coo); + Member::AddCredentialResult addCredential(void *tPtr, const Identity &sourcePeerIdentity, const OwnershipCredential &coo); /** * Push credentials to a peer if timeouts indicate that we should do so @@ -320,7 +320,7 @@ public: ZT_INLINE void eachMember(F f) { Mutex::Lock ml(m_memberships_l); - for(Map::iterator i(m_memberships.begin());i != m_memberships.end();++i) { // NOLINT(modernize-loop-convert,hicpp-use-auto,modernize-use-auto) + for(Map::iterator i(m_memberships.begin()); i != m_memberships.end(); ++i) { // NOLINT(modernize-loop-convert,hicpp-use-auto,modernize-use-auto) if (!f(i->first,i->second)) break; } @@ -361,7 +361,7 @@ private: NETCONF_FAILURE_INIT_FAILED } _netconfFailure; - Map m_memberships; + Map m_memberships; Mutex m_myMulticastGroups_l; Mutex m_remoteBridgeRoutes_l; diff --git a/core/NetworkConfig.cpp b/core/NetworkConfig.cpp index efa221255..18c097b2d 100644 --- a/core/NetworkConfig.cpp +++ b/core/NetworkConfig.cpp @@ -96,7 +96,7 @@ bool NetworkConfig::toDictionary(Dictionary &d) const blob = &(d[ZT_NETWORKCONFIG_DICT_KEY_RULES]); if (this->ruleCount) { blob->resize(ruleCount * ZT_VIRTUALNETWORKRULE_MARSHAL_SIZE_MAX); - int l = Capability::marshalVirtualNetworkRules(blob->data(),rules,ruleCount); + int l = CapabilityCredential::marshalVirtualNetworkRules(blob->data(), rules, ruleCount); if (l > 0) blob->resize(l); } @@ -154,7 +154,7 @@ bool NetworkConfig::fromDictionary(const Dictionary &d) try { unsigned int p = 0; while (p < blob->size()) { - Capability cap; + CapabilityCredential cap; int l = cap.unmarshal(blob->data() + p,(int)(blob->size() - p)); if (l < 0) return false; @@ -171,7 +171,7 @@ bool NetworkConfig::fromDictionary(const Dictionary &d) try { unsigned int p = 0; while (p < blob->size()) { - Tag tag; + TagCredential tag; int l = tag.unmarshal(blob->data() + p,(int)(blob->size() - p)); if (l < 0) return false; @@ -188,7 +188,7 @@ bool NetworkConfig::fromDictionary(const Dictionary &d) try { unsigned int p = 0; while (p < blob->size()) { - CertificateOfOwnership coo; + OwnershipCredential coo; int l = coo.unmarshal(blob->data() + p,(int)(blob->size() - p)); if (l < 0) return false; @@ -246,7 +246,7 @@ bool NetworkConfig::fromDictionary(const Dictionary &d) blob = &(d[ZT_NETWORKCONFIG_DICT_KEY_RULES]); if (!blob->empty()) { this->ruleCount = 0; - if (Capability::unmarshalVirtualNetworkRules(blob->data(),(int)blob->size(),this->rules,this->ruleCount,ZT_MAX_NETWORK_RULES) < 0) + if (CapabilityCredential::unmarshalVirtualNetworkRules(blob->data(), (int)blob->size(), this->rules, this->ruleCount, ZT_MAX_NETWORK_RULES) < 0) return false; } } diff --git a/core/NetworkConfig.hpp b/core/NetworkConfig.hpp index 68adb20e5..a46a34d23 100644 --- a/core/NetworkConfig.hpp +++ b/core/NetworkConfig.hpp @@ -18,10 +18,10 @@ #include "InetAddress.hpp" #include "MulticastGroup.hpp" #include "Address.hpp" -#include "CertificateOfMembership.hpp" -#include "CertificateOfOwnership.hpp" -#include "Capability.hpp" -#include "Tag.hpp" +#include "MembershipCredential.hpp" +#include "OwnershipCredential.hpp" +#include "CapabilityCredential.hpp" +#include "TagCredential.hpp" #include "Dictionary.hpp" #include "Identity.hpp" #include "Utils.hpp" @@ -222,7 +222,7 @@ struct NetworkConfig : TriviallyCopyable */ bool addSpecialist(const Address &a, uint64_t f) noexcept; - ZT_INLINE const Capability *capability(const uint32_t id) const + ZT_INLINE const CapabilityCredential *capability(const uint32_t id) const { for (unsigned int i = 0;i < capabilityCount;++i) { if (capabilities[i].id() == id) @@ -231,7 +231,7 @@ struct NetworkConfig : TriviallyCopyable return nullptr; } - ZT_INLINE const Tag *tag(const uint32_t id) const + ZT_INLINE const TagCredential *tag(const uint32_t id) const { for (unsigned int i = 0;i < tagCount;++i) { if (tags[i].id() == id) @@ -349,17 +349,17 @@ struct NetworkConfig : TriviallyCopyable /** * Capabilities for this node on this network, in ascending order of capability ID */ - Capability capabilities[ZT_MAX_NETWORK_CAPABILITIES]; + CapabilityCredential capabilities[ZT_MAX_NETWORK_CAPABILITIES]; /** * Tags for this node on this network, in ascending order of tag ID */ - Tag tags[ZT_MAX_NETWORK_TAGS]; + TagCredential tags[ZT_MAX_NETWORK_TAGS]; /** * Certificates of ownership for this network member */ - CertificateOfOwnership certificatesOfOwnership[ZT_MAX_CERTIFICATES_OF_OWNERSHIP]; + OwnershipCredential certificatesOfOwnership[ZT_MAX_CERTIFICATES_OF_OWNERSHIP]; /** * Network type (currently just public or private) @@ -374,7 +374,7 @@ struct NetworkConfig : TriviallyCopyable /** * Certificate of membership (for private networks) */ - CertificateOfMembership com; + MembershipCredential com; }; } // namespace ZeroTier diff --git a/core/NetworkController.hpp b/core/NetworkController.hpp index 64f0a4c21..24500b58f 100644 --- a/core/NetworkController.hpp +++ b/core/NetworkController.hpp @@ -17,7 +17,7 @@ #include "Constants.hpp" #include "Dictionary.hpp" #include "NetworkConfig.hpp" -#include "Revocation.hpp" +#include "RevocationCredential.hpp" #include "Address.hpp" namespace ZeroTier { @@ -62,7 +62,7 @@ public: * @param destination Destination node address * @param rev Revocation to send */ - virtual void ncSendRevocation(const Address &destination,const Revocation &rev) = 0; + virtual void ncSendRevocation(const Address &destination,const RevocationCredential &rev) = 0; /** * Send a network configuration request error diff --git a/core/Node.cpp b/core/Node.cpp index 26e46825a..9c1758e43 100644 --- a/core/Node.cpp +++ b/core/Node.cpp @@ -743,7 +743,7 @@ void Node::ncSendConfig(uint64_t nwid, uint64_t requestPacketId, const Address & } } -void Node::ncSendRevocation(const Address &destination, const Revocation &rev) +void Node::ncSendRevocation(const Address &destination, const RevocationCredential &rev) { if (destination == RR->identity.address()) { SharedPtr< Network > n(network(rev.networkId())); diff --git a/core/Node.hpp b/core/Node.hpp index f0361ed04..8b131d459 100644 --- a/core/Node.hpp +++ b/core/Node.hpp @@ -358,7 +358,7 @@ public: // Implementation of NetworkController::Sender interface virtual void ncSendConfig(uint64_t nwid, uint64_t requestPacketId, const Address &destination, const NetworkConfig &nc, bool sendLegacyFormatConfig); - virtual void ncSendRevocation(const Address &destination, const Revocation &rev); + virtual void ncSendRevocation(const Address &destination, const RevocationCredential &rev); virtual void ncSendError(uint64_t nwid, uint64_t requestPacketId, const Address &destination, NetworkController::ErrorCode errorCode); diff --git a/core/CertificateOfOwnership.cpp b/core/OwnershipCredential.cpp similarity index 89% rename from core/CertificateOfOwnership.cpp rename to core/OwnershipCredential.cpp index 71f7b94e7..57f41a3bb 100644 --- a/core/CertificateOfOwnership.cpp +++ b/core/OwnershipCredential.cpp @@ -11,11 +11,11 @@ */ /****/ -#include "CertificateOfOwnership.hpp" +#include "OwnershipCredential.hpp" namespace ZeroTier { -void CertificateOfOwnership::addThing(const InetAddress &ip) +void OwnershipCredential::addThing(const InetAddress &ip) { if (m_thingCount >= ZT_CERTIFICATEOFOWNERSHIP_MAX_THINGS) return; @@ -30,7 +30,7 @@ void CertificateOfOwnership::addThing(const InetAddress &ip) } } -void CertificateOfOwnership::addThing(const MAC &mac) +void OwnershipCredential::addThing(const MAC &mac) { if (m_thingCount >= ZT_CERTIFICATEOFOWNERSHIP_MAX_THINGS) return; @@ -39,7 +39,7 @@ void CertificateOfOwnership::addThing(const MAC &mac) ++m_thingCount; } -bool CertificateOfOwnership::sign(const Identity &signer) +bool OwnershipCredential::sign(const Identity &signer) { uint8_t buf[ZT_CERTIFICATEOFOWNERSHIP_MARSHAL_SIZE_MAX + 16]; if (signer.hasPrivate()) { @@ -50,7 +50,7 @@ bool CertificateOfOwnership::sign(const Identity &signer) return false; } -int CertificateOfOwnership::marshal(uint8_t data[ZT_CERTIFICATEOFOWNERSHIP_MARSHAL_SIZE_MAX], bool forSign) const noexcept +int OwnershipCredential::marshal(uint8_t data[ZT_CERTIFICATEOFOWNERSHIP_MARSHAL_SIZE_MAX], bool forSign) const noexcept { int p = 0; if (forSign) { @@ -88,7 +88,7 @@ int CertificateOfOwnership::marshal(uint8_t data[ZT_CERTIFICATEOFOWNERSHIP_MARSH return p; } -int CertificateOfOwnership::unmarshal(const uint8_t *data, int len) noexcept +int OwnershipCredential::unmarshal(const uint8_t *data, int len) noexcept { if (len < 30) return -1; diff --git a/core/CertificateOfOwnership.hpp b/core/OwnershipCredential.hpp similarity index 86% rename from core/CertificateOfOwnership.hpp rename to core/OwnershipCredential.hpp index 06c4bed6f..44d27d0dd 100644 --- a/core/CertificateOfOwnership.hpp +++ b/core/OwnershipCredential.hpp @@ -45,7 +45,7 @@ class RuntimeEnvironment; * These are used in conjunction with the rules engine to make IP addresses and * other identifiers un-spoofable. */ -class CertificateOfOwnership : public Credential +class OwnershipCredential : public Credential { friend class Credential; @@ -60,9 +60,9 @@ public: THING_IPV6_ADDRESS = 3 }; - ZT_INLINE CertificateOfOwnership() noexcept { memoryZero(this); } // NOLINT(cppcoreguidelines-pro-type-member-init,hicpp-member-init) + ZT_INLINE OwnershipCredential() noexcept { memoryZero(this); } - ZT_INLINE CertificateOfOwnership(const uint64_t nwid,const int64_t ts,const Address &issuedTo,const uint32_t id) noexcept // NOLINT(cppcoreguidelines-pro-type-member-init,hicpp-member-init) + ZT_INLINE OwnershipCredential(const uint64_t nwid, const int64_t ts, const Address &issuedTo, const uint32_t id) noexcept { memoryZero(this); m_networkId = nwid; @@ -139,10 +139,10 @@ public: int unmarshal(const uint8_t *data,int len) noexcept; // Provides natural sort order by ID - ZT_INLINE bool operator<(const CertificateOfOwnership &coo) const noexcept { return (m_id < coo.m_id); } + ZT_INLINE bool operator<(const OwnershipCredential &coo) const noexcept { return (m_id < coo.m_id); } - ZT_INLINE bool operator==(const CertificateOfOwnership &coo) const noexcept { return (memcmp(this,&coo,sizeof(CertificateOfOwnership)) == 0); } - ZT_INLINE bool operator!=(const CertificateOfOwnership &coo) const noexcept { return (memcmp(this,&coo,sizeof(CertificateOfOwnership)) != 0); } + ZT_INLINE bool operator==(const OwnershipCredential &coo) const noexcept { return (memcmp(this, &coo, sizeof(OwnershipCredential)) == 0); } + ZT_INLINE bool operator!=(const OwnershipCredential &coo) const noexcept { return (memcmp(this, &coo, sizeof(OwnershipCredential)) != 0); } private: ZT_INLINE bool _owns(const Thing &t,const void *v,unsigned int l) const noexcept diff --git a/core/Revocation.cpp b/core/RevocationCredential.cpp similarity index 89% rename from core/Revocation.cpp rename to core/RevocationCredential.cpp index 52e8f8da2..14d8d1a33 100644 --- a/core/Revocation.cpp +++ b/core/RevocationCredential.cpp @@ -11,11 +11,11 @@ */ /****/ -#include "Revocation.hpp" +#include "RevocationCredential.hpp" namespace ZeroTier { -bool Revocation::sign(const Identity &signer) noexcept +bool RevocationCredential::sign(const Identity &signer) noexcept { uint8_t buf[ZT_REVOCATION_MARSHAL_SIZE_MAX + 32]; if (signer.hasPrivate()) { @@ -26,7 +26,7 @@ bool Revocation::sign(const Identity &signer) noexcept return false; } -int Revocation::marshal(uint8_t data[ZT_REVOCATION_MARSHAL_SIZE_MAX], bool forSign) const noexcept +int RevocationCredential::marshal(uint8_t data[ZT_REVOCATION_MARSHAL_SIZE_MAX], bool forSign) const noexcept { int p = 0; if (forSign) { @@ -67,7 +67,7 @@ int Revocation::marshal(uint8_t data[ZT_REVOCATION_MARSHAL_SIZE_MAX], bool forSi return p; } -int Revocation::unmarshal(const uint8_t *restrict data, const int len) noexcept +int RevocationCredential::unmarshal(const uint8_t *restrict data, const int len) noexcept { if (len < 54) return -1; diff --git a/core/Revocation.hpp b/core/RevocationCredential.hpp similarity index 91% rename from core/Revocation.hpp rename to core/RevocationCredential.hpp index 1e745d7eb..b25a5f998 100644 --- a/core/Revocation.hpp +++ b/core/RevocationCredential.hpp @@ -35,7 +35,7 @@ class RuntimeEnvironment; /** * Revocation certificate to instantaneously revoke a COM, capability, or tag */ -class Revocation : public Credential +class RevocationCredential : public Credential { friend class Credential; @@ -43,7 +43,7 @@ public: static constexpr ZT_CredentialType credentialType() noexcept { return ZT_CREDENTIAL_TYPE_REVOCATION; } - ZT_INLINE Revocation() noexcept + ZT_INLINE RevocationCredential() noexcept { memoryZero(this); } // NOLINT(cppcoreguidelines-pro-type-member-init,hicpp-member-init) /** @@ -55,7 +55,7 @@ public: * @param tgt Target node whose credential(s) are being revoked * @param ct Credential type being revoked */ - ZT_INLINE Revocation(const uint32_t i, const uint64_t nwid, const uint32_t cid, const uint64_t thr, const uint64_t fl, const Address &tgt, const ZT_CredentialType ct) noexcept: // NOLINT(cppcoreguidelines-pro-type-member-init,hicpp-member-init) + ZT_INLINE RevocationCredential(const uint32_t i, const uint64_t nwid, const uint32_t cid, const uint64_t thr, const uint64_t fl, const Address &tgt, const ZT_CredentialType ct) noexcept: // NOLINT(cppcoreguidelines-pro-type-member-init,hicpp-member-init) m_id(i), m_credentialId(cid), m_networkId(nwid), diff --git a/core/Tag.cpp b/core/TagCredential.cpp similarity index 89% rename from core/Tag.cpp rename to core/TagCredential.cpp index a248939db..fdb18a4a2 100644 --- a/core/Tag.cpp +++ b/core/TagCredential.cpp @@ -11,11 +11,11 @@ */ /****/ -#include "Tag.hpp" +#include "TagCredential.hpp" namespace ZeroTier { -bool Tag::sign(const Identity &signer) noexcept +bool TagCredential::sign(const Identity &signer) noexcept { uint8_t buf[ZT_TAG_MARSHAL_SIZE_MAX]; if (signer.hasPrivate()) { @@ -26,7 +26,7 @@ bool Tag::sign(const Identity &signer) noexcept return false; } -int Tag::marshal(uint8_t data[ZT_TAG_MARSHAL_SIZE_MAX], bool forSign) const noexcept +int TagCredential::marshal(uint8_t data[ZT_TAG_MARSHAL_SIZE_MAX], bool forSign) const noexcept { int p = 0; if (forSign) { @@ -61,7 +61,7 @@ int Tag::marshal(uint8_t data[ZT_TAG_MARSHAL_SIZE_MAX], bool forSign) const noex return p; } -int Tag::unmarshal(const uint8_t *data, int len) noexcept +int TagCredential::unmarshal(const uint8_t *data, int len) noexcept { if (len < 37) return -1; diff --git a/core/Tag.hpp b/core/TagCredential.hpp similarity index 76% rename from core/Tag.hpp rename to core/TagCredential.hpp index ca0b06cf0..e97d3ef5f 100644 --- a/core/Tag.hpp +++ b/core/TagCredential.hpp @@ -43,7 +43,7 @@ class RuntimeEnvironment; * Unlike capabilities tags are signed only by the issuer and are never * transferable. */ -class Tag : public Credential +class TagCredential : public Credential { friend class Credential; @@ -51,7 +51,7 @@ public: static constexpr ZT_CredentialType credentialType() noexcept { return ZT_CREDENTIAL_TYPE_TAG; } - ZT_INLINE Tag() noexcept + ZT_INLINE TagCredential() noexcept { memoryZero(this); } /** @@ -61,7 +61,7 @@ public: * @param id Tag ID * @param value Tag value */ - ZT_INLINE Tag(const uint64_t nwid, const int64_t ts, const Address &issuedTo, const uint32_t id, const uint32_t value) noexcept: + ZT_INLINE TagCredential(const uint64_t nwid, const int64_t ts, const Address &issuedTo, const uint32_t id, const uint32_t value) noexcept: m_id(id), m_value(value), m_networkId(nwid), @@ -121,40 +121,40 @@ public: int unmarshal(const uint8_t *data, int len) noexcept; // Provides natural sort order by ID - ZT_INLINE bool operator<(const Tag &t) const noexcept + ZT_INLINE bool operator<(const TagCredential &t) const noexcept { return (m_id < t.m_id); } - ZT_INLINE bool operator==(const Tag &t) const noexcept - { return (memcmp(this, &t, sizeof(Tag)) == 0); } + ZT_INLINE bool operator==(const TagCredential &t) const noexcept + { return (memcmp(this, &t, sizeof(TagCredential)) == 0); } - ZT_INLINE bool operator!=(const Tag &t) const noexcept - { return (memcmp(this, &t, sizeof(Tag)) != 0); } + ZT_INLINE bool operator!=(const TagCredential &t) const noexcept + { return (memcmp(this, &t, sizeof(TagCredential)) != 0); } // For searching sorted arrays or lists of Tags by ID struct IdComparePredicate { - ZT_INLINE bool operator()(const Tag &a, const Tag &b) const noexcept + ZT_INLINE bool operator()(const TagCredential &a, const TagCredential &b) const noexcept { return (a.id() < b.id()); } - ZT_INLINE bool operator()(const uint32_t a, const Tag &b) const noexcept + ZT_INLINE bool operator()(const uint32_t a, const TagCredential &b) const noexcept { return (a < b.id()); } - ZT_INLINE bool operator()(const Tag &a, const uint32_t b) const noexcept + ZT_INLINE bool operator()(const TagCredential &a, const uint32_t b) const noexcept { return (a.id() < b); } - ZT_INLINE bool operator()(const Tag *a, const Tag *b) const noexcept + ZT_INLINE bool operator()(const TagCredential *a, const TagCredential *b) const noexcept { return (a->id() < b->id()); } - ZT_INLINE bool operator()(const Tag *a, const Tag &b) const noexcept + ZT_INLINE bool operator()(const TagCredential *a, const TagCredential &b) const noexcept { return (a->id() < b.id()); } - ZT_INLINE bool operator()(const Tag &a, const Tag *b) const noexcept + ZT_INLINE bool operator()(const TagCredential &a, const TagCredential *b) const noexcept { return (a.id() < b->id()); } - ZT_INLINE bool operator()(const uint32_t a, const Tag *b) const noexcept + ZT_INLINE bool operator()(const uint32_t a, const TagCredential *b) const noexcept { return (a < b->id()); } - ZT_INLINE bool operator()(const Tag *a, const uint32_t b) const noexcept + ZT_INLINE bool operator()(const TagCredential *a, const uint32_t b) const noexcept { return (a->id() < b); } ZT_INLINE bool operator()(const uint32_t a, const uint32_t b) const noexcept diff --git a/core/Tests.cpp b/core/Tests.cpp index 38f7a9f47..0d581b59c 100644 --- a/core/Tests.cpp +++ b/core/Tests.cpp @@ -29,11 +29,11 @@ #include "InetAddress.hpp" #include "Endpoint.hpp" #include "Locator.hpp" -#include "CertificateOfMembership.hpp" -#include "CertificateOfOwnership.hpp" -#include "Revocation.hpp" -#include "Tag.hpp" -#include "Capability.hpp" +#include "MembershipCredential.hpp" +#include "OwnershipCredential.hpp" +#include "RevocationCredential.hpp" +#include "TagCredential.hpp" +#include "CapabilityCredential.hpp" #include "NetworkConfig.hpp" #include "FCV.hpp" #include "SHA512.hpp" diff --git a/core/Topology.cpp b/core/Topology.cpp index b6587d9af..3a0d7e1cc 100644 --- a/core/Topology.cpp +++ b/core/Topology.cpp @@ -39,18 +39,6 @@ SharedPtr< Peer > Topology::add(void *tPtr, const SharedPtr< Peer > &peer) return peer; } -struct p_RootSortComparisonOperator -{ - ZT_INLINE bool operator()(const SharedPtr< Peer > &a, const SharedPtr< Peer > &b) const noexcept - { - // Sort in inverse order of latency with lowest latency first (and -1 last). - const int bb = b->latency(); - if (bb < 0) - return true; - return bb < a->latency(); - } -}; - SharedPtr< Peer > Topology::addRoot(void *const tPtr, const Identity &id) { if ((id != RR->identity) && id.locallyValidate()) { @@ -69,6 +57,10 @@ SharedPtr< Peer > Topology::addRoot(void *const tPtr, const Identity &id) return SharedPtr< Peer >(); } +ZT_CertificateError addRootSet(void *tPtr, const Certificate &cert) +{ +} + bool Topology::removeRoot(void *const tPtr, Address address) { RWMutex::Lock l1(m_peers_l); @@ -76,10 +68,22 @@ bool Topology::removeRoot(void *const tPtr, Address address) return true; } +struct p_RootRankingComparisonOperator +{ + ZT_INLINE bool operator()(const SharedPtr< Peer > &a, const SharedPtr< Peer > &b) const noexcept + { + // Sort in inverse order of latency with lowest latency first (and -1 last). + const int bb = b->latency(); + if (bb < 0) + return true; + return bb < a->latency(); + } +}; + void Topology::rankRoots() { RWMutex::Lock l1(m_peers_l); - std::sort(m_rootPeers.begin(), m_rootPeers.end(), p_RootSortComparisonOperator()); + std::sort(m_rootPeers.begin(), m_rootPeers.end(), p_RootRankingComparisonOperator()); } void Topology::doPeriodicTasks(void *tPtr, const int64_t now) diff --git a/core/Topology.hpp b/core/Topology.hpp index 24c11eb78..425fdb691 100644 --- a/core/Topology.hpp +++ b/core/Topology.hpp @@ -25,7 +25,7 @@ #include "ScopedPtr.hpp" #include "Fingerprint.hpp" #include "Blob.hpp" -#include "IdentificationCertificate.hpp" +#include "Certificate.hpp" #include "Containers.hpp" namespace ZeroTier { @@ -182,6 +182,20 @@ public: */ SharedPtr< Peer > addRoot(void *tPtr, const Identity &id); + /** + * Add or update a root set + * + * This does not check the certificate's validity. That must be done + * first. It may however return a certificate error if something is + * missing or wrong that prevents the certificate from being used + * as a root set. + * + * @param tPtr Thread pointer + * @param cert Certificate whose subject enumerates root identities + * @return Zero on success or an error code + */ + ZT_CertificateError addRootSet(void *tPtr, const Certificate &cert); + /** * Remove a root server's identity from the root server set * @@ -239,7 +253,8 @@ private: RWMutex m_peers_l; // locks m_peers, m_roots, and m_rootPeers Map< uint64_t, SharedPtr< Path > > m_paths; Map< Address, SharedPtr< Peer > > m_peers; - Map< Identity, Set< IdentificationCertificate > > m_roots; + Map< Identity, Set< Blob > > m_roots; + Map< String, Certificate > m_rootSets; Vector< SharedPtr< Peer > > m_rootPeers; }; diff --git a/core/Trace.hpp b/core/Trace.hpp index e653c9704..28f2f9728 100644 --- a/core/Trace.hpp +++ b/core/Trace.hpp @@ -35,11 +35,11 @@ class Identity; class Peer; class Path; class Network; -class CertificateOfMembership; -class CertificateOfOwnership; -class Revocation; -class Tag; -class Capability; +class MembershipCredential; +class OwnershipCredential; +class RevocationCredential; +class TagCredential; +class CapabilityCredential; struct NetworkConfig; /** diff --git a/core/VL1.cpp b/core/VL1.cpp index 607daef68..6fca9591f 100644 --- a/core/VL1.cpp +++ b/core/VL1.cpp @@ -32,9 +32,7 @@ namespace ZeroTier { namespace { ZT_INLINE const Identity &identityFromPeerPtr(const SharedPtr< Peer > &p) -{ - return (p) ? p->identity() : Identity::NIL; -} +{ return (p) ? p->identity() : Identity::NIL; } struct p_SalsaPolyCopyFunction { @@ -100,8 +98,7 @@ struct p_PolyCopyFunction VL1::VL1(const RuntimeEnvironment *renv) : RR(renv) -{ -} +{} void VL1::onRemotePacket(void *const tPtr, const int64_t localSocket, const InetAddress &fromAddr, SharedPtr< Buf > &data, const unsigned int len) noexcept { diff --git a/core/zerotier.h b/core/zerotier.h index e429e6a66..59db771db 100644 --- a/core/zerotier.h +++ b/core/zerotier.h @@ -294,40 +294,81 @@ typedef struct } ZT_Fingerprint; /** - * Maximum length of string fields in identification certificates + * Maximum length of string fields in certificates */ -#define ZT_IDENTIFICATION_CERTIFICATE_MAX_STRING_LENGTH 127 +#define ZT_CERTIFICATE_MAX_STRING_LENGTH 63 /** * Maximum length of a signature */ -#define ZT_IDENTIFICATION_CERTIFICATE_MAX_SIGNATURE_SIZE 256 +#define ZT_CERTIFICATE_MAX_SIGNATURE_SIZE 96 /** * Flag indicating that the nodes in the subject are a set of roots */ -#define ZT_IDENTIFICATION_CERTIFICATE_FLAG_ROOT_SET 0x0000000000000001ULL +#define ZT_CERTIFICATE_FLAG_CERTIFICATE_USE_ROOT_SET 0x0000000000000001ULL + +/** + * Errors returned by functions that verify or handle certificates. + */ +enum ZT_CertificateError +{ + /** + * No error (certificate is valid or operation was successful) + */ + ZT_CERTIFICATE_ERROR_NONE = 0, + + /** + * Certificate format is invalid or required fields are missing + */ + ZT_CERTIFICATE_ERROR_INVALID_FORMAT = 1, + + /** + * One or more identities in the certificate are invalid or fail consistency check + */ + ZT_CERTIFICATE_ERROR_INVALID_IDENTITY = 2, + + /** + * Certificate primary signature is invalid + */ + ZT_CERTIFICATE_ERROR_INVALID_PRIMARY_SIGNATURE = 3, + + /** + * Full chain validation of certificate failed + */ + ZT_CERTIFICATE_ERROR_INVALID_CHAIN = 4, + + /** + * One or more signed components (e.g. a Locator) has an invalid signature. + */ + ZT_CERTIFICATE_ERROR_INVALID_COMPONENT_SIGNATURE = 5, + + /** + * Certificate is not appropriate for this use + */ + ZT_CERTIFICATE_ERROR_INAPPROPRIATE_FOR_USE = 6 +}; /** * Information about a real world entity. */ typedef struct { - char country[ZT_IDENTIFICATION_CERTIFICATE_MAX_STRING_LENGTH + 1]; - char organization[ZT_IDENTIFICATION_CERTIFICATE_MAX_STRING_LENGTH + 1]; - char unit[ZT_IDENTIFICATION_CERTIFICATE_MAX_STRING_LENGTH + 1]; - char locality[ZT_IDENTIFICATION_CERTIFICATE_MAX_STRING_LENGTH + 1]; - char province[ZT_IDENTIFICATION_CERTIFICATE_MAX_STRING_LENGTH + 1]; - char streetAddress[ZT_IDENTIFICATION_CERTIFICATE_MAX_STRING_LENGTH + 1]; - char postalCode[ZT_IDENTIFICATION_CERTIFICATE_MAX_STRING_LENGTH + 1]; - char commonName[ZT_IDENTIFICATION_CERTIFICATE_MAX_STRING_LENGTH + 1]; - char serialNo[ZT_IDENTIFICATION_CERTIFICATE_MAX_STRING_LENGTH + 1]; - char email[ZT_IDENTIFICATION_CERTIFICATE_MAX_STRING_LENGTH + 1]; - char url[ZT_IDENTIFICATION_CERTIFICATE_MAX_STRING_LENGTH + 1]; -} ZT_IdentificationCertificate_Name; + char country[ZT_CERTIFICATE_MAX_STRING_LENGTH + 1]; + char organization[ZT_CERTIFICATE_MAX_STRING_LENGTH + 1]; + char unit[ZT_CERTIFICATE_MAX_STRING_LENGTH + 1]; + char locality[ZT_CERTIFICATE_MAX_STRING_LENGTH + 1]; + char province[ZT_CERTIFICATE_MAX_STRING_LENGTH + 1]; + char streetAddress[ZT_CERTIFICATE_MAX_STRING_LENGTH + 1]; + char postalCode[ZT_CERTIFICATE_MAX_STRING_LENGTH + 1]; + char commonName[ZT_CERTIFICATE_MAX_STRING_LENGTH + 1]; + char serialNo[ZT_CERTIFICATE_MAX_STRING_LENGTH + 1]; + char email[ZT_CERTIFICATE_MAX_STRING_LENGTH + 1]; + char url[ZT_CERTIFICATE_MAX_STRING_LENGTH + 1]; +} ZT_Certificate_Name; /** - * Identity and optional locator for a node + * Identity and optional locator to help find a node on physical networks. */ typedef struct { @@ -337,10 +378,10 @@ typedef struct const ZT_Identity *identity; /** - * Locator or NULL if not specified + * Locator, or NULL if none */ const ZT_Locator *locator; -} ZT_IdentificationCertificate_Node; +} ZT_Certificate_Identity; /** * ID and primary controller for a network @@ -356,7 +397,7 @@ typedef struct * Full fingerprint of primary controller */ ZT_Fingerprint controller; -} ZT_IdentificationCertificate_Network; +} ZT_Certificate_Network; /** * Identification certificate subject @@ -366,36 +407,48 @@ typedef struct /** * Identities and optional locators of nodes */ - ZT_IdentificationCertificate_Node *nodes; + ZT_Certificate_Identity *identities; /** * Networks owned by this entity */ - ZT_IdentificationCertificate_Network *networks; + ZT_Certificate_Network *networks; /** - * Number of nodes + * Serial numbers of other certificates being signed (each is 48 bytes / 384 bits) */ - unsigned int nodeCount; + const uint8_t *const *certificates; + + /** + * Number of identities + */ + unsigned int identityCount; /** * Number of networks */ unsigned int networkCount; + /** + * Number of certificates + */ + unsigned int certificateCount; + /** * Information about owner of items. */ - ZT_IdentificationCertificate_Name name; -} ZT_IdentificationCertificate_Subject; + ZT_Certificate_Name name; +} ZT_Certificate_Subject; /** - * Identification certificate + * Certificate * - * This is designed so it could be converted to/from an X509 format - * for interoperability with X509 systems. OCSP could be implemented - * too, though it would probably require the development of an OCSP - * proxy server that queried the issuer via the ZeroTier protocol. + * This is designed to be compatible with x509 certificate interfaces, + * presenting similar concepts and fields. + * + * It's not X509 because we want to keep ZeroTier clean, as simple as + * possible, small, and secure. X509 is both bloated and a security + * disaster as it's very hard to implement correctly. */ typedef struct { @@ -404,20 +457,6 @@ typedef struct */ uint8_t serialNo[48]; - /** - * Certificate version - */ - unsigned int version; - - /** - * Maximum path length from this certificate toward further certificates. - * - * Subjects may sign other certificates whose path lengths are less than - * this value. A value of zero indicates that no identification certificates - * may be signed (not a CA). - */ - unsigned int maxPathLength; - /** * Flags indicating certificate usage and any other attributes. */ @@ -434,7 +473,7 @@ typedef struct /** * Subject of certificate */ - ZT_IdentificationCertificate_Subject subject; + ZT_Certificate_Subject subject; /** * Issuer node identity and public key(s). @@ -444,7 +483,7 @@ typedef struct /** * Issuer information */ - ZT_IdentificationCertificate_Name issuerName; + ZT_Certificate_Name issuerName; /** * URLs that can be consulted for updates to this certificate. @@ -456,6 +495,15 @@ typedef struct */ unsigned int updateUrlCount; + /** + * Maximum path length from this certificate toward further certificates. + * + * Subjects may sign other certificates whose path lengths are less than + * this value. A value of zero indicates that no identification certificates + * may be signed (not a CA). + */ + unsigned int maxPathLength; + /** * Size of signature in bytes. */ @@ -464,8 +512,8 @@ typedef struct /** * Signature by issuer (algorithm determined by identity type). */ - uint8_t signature[ZT_IDENTIFICATION_CERTIFICATE_MAX_SIGNATURE_SIZE]; -} ZT_IdentificationCertificate; + uint8_t signature[ZT_CERTIFICATE_MAX_SIGNATURE_SIZE]; +} ZT_Certificate; /** * Credential type IDs