浏览代码

A whole bunch of minor refactoring, and rename a bunch of classes to be more canonical. A credential really is not a certficiate, so just call IdentificationCertificate Certificate and call the network auth stuff credentials.

Adam Ierymenko 5 年之前
父节点
当前提交
cfc2a43f51

+ 22 - 5
CMakeLists.txt

@@ -30,8 +30,6 @@ if(WIN32)
 	set(CMAKE_SYSTEM_VERSION "7" CACHE STRING INTERNAL FORCE)
 	set(CMAKE_SYSTEM_VERSION "7" CACHE STRING INTERNAL FORCE)
 endif(WIN32)
 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)
 if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES)
 	message(STATUS "Setting build type to '${default_build_type}' as none was specified.")
 	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)
 	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)
 if(WIN32)
 
 
 	message("++ Setting Windows Compiler Flags ${CMAKE_BUILD_TYPE}")
 	message("++ Setting Windows Compiler Flags ${CMAKE_BUILD_TYPE}")
+
 	add_definitions(-DNOMINMAX)
 	add_definitions(-DNOMINMAX)
+	add_compile_options(
+		-Wall
+		-Wno-deprecated
+		-Wno-unused-function
+		-Wno-format
+		$<$<CONFIG:DEBUG>:-g>
+		$<$<CONFIG:DEBUG>:-O0>
+		$<$<CONFIG:RELEASE>:-O3>
+		$<$<CONFIG:RELEASE>:-ffast-math>
+		$<$<CONFIG:RELWITHDEBINFO>:-O3>
+		$<$<CONFIG:RELWITHDEBINFO>:-g>
+	)
 
 
 	set(GOFLAGS
 	set(GOFLAGS
+		-a
 		-trimpath
 		-trimpath
+		-ldflags '-w'
 	)
 	)
 
 
 else(WIN32)
 else(WIN32)
@@ -77,6 +90,8 @@ else(WIN32)
 		-buildmode=pie
 		-buildmode=pie
 	)
 	)
 
 
+	set(MACOS_VERSION_MIN "10.12")
+
 	if(APPLE)
 	if(APPLE)
 
 
 		message("++ Setting MacOS Compiler Flags ${CMAKE_BUILD_TYPE}")
 		message("++ Setting MacOS Compiler Flags ${CMAKE_BUILD_TYPE}")
@@ -85,7 +100,7 @@ else(WIN32)
 			-Wall
 			-Wall
 			-Wno-deprecated
 			-Wno-deprecated
 			-Wno-unused-function
 			-Wno-unused-function
-			-mmacosx-version-min=10.12
+			-mmacosx-version-min=${MACOS_VERSION_MIN}
 			$<$<CONFIG:DEBUG>:-g>
 			$<$<CONFIG:DEBUG>:-g>
 			$<$<CONFIG:DEBUG>:-O0>
 			$<$<CONFIG:DEBUG>:-O0>
 			$<$<CONFIG:RELEASE>:-Ofast>
 			$<$<CONFIG:RELEASE>:-Ofast>
@@ -98,7 +113,7 @@ else(WIN32)
 		)
 		)
 
 
 		add_link_options(
 		add_link_options(
-			-mmacosx-version-min=10.12
+			-mmacosx-version-min=${MACOS_VERSION_MIN}
 			$<$<CONFIG:RELEASE>:-flto>
 			$<$<CONFIG:RELEASE>:-flto>
 		)
 		)
 
 
@@ -111,6 +126,7 @@ else(WIN32)
 	else(APPLE)
 	else(APPLE)
 
 
 		message("++ Setting Linux/BSD/Posix Compiler Flags (${CMAKE_BUILD_TYPE})")
 		message("++ Setting Linux/BSD/Posix Compiler Flags (${CMAKE_BUILD_TYPE})")
+
 		add_compile_options(
 		add_compile_options(
 			-Wall
 			-Wall
 			-Wno-deprecated
 			-Wno-deprecated
@@ -186,7 +202,8 @@ add_subdirectory(serviceiocore)
 file(GLOB go_src 
 file(GLOB go_src 
 	${CMAKE_SOURCE_DIR}/cmd/*.go
 	${CMAKE_SOURCE_DIR}/cmd/*.go
 	${CMAKE_SOURCE_DIR}/cmd/cmd/*.go
 	${CMAKE_SOURCE_DIR}/cmd/cmd/*.go
-	${CMAKE_SOURCE_DIR}/pkg/zerotier/*.go)
+	${CMAKE_SOURCE_DIR}/pkg/zerotier/*.go
+)
 
 
 if(WIN32)
 if(WIN32)
 	set(GO_EXE_NAME "zerotier.exe")
 	set(GO_EXE_NAME "zerotier.exe")

+ 2 - 2
attic/java/jni/Android.mk

@@ -17,8 +17,8 @@ LOCAL_CFLAGS := -DZT_USE_MINIUPNPC
 LOCAL_SRC_FILES := \
 LOCAL_SRC_FILES := \
     $(ZT1)/node/C25519.cpp \
     $(ZT1)/node/C25519.cpp \
 	$(ZT1)/node/Capability.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/Identity.cpp \
 	$(ZT1)/node/IncomingPacket.cpp \
 	$(ZT1)/node/IncomingPacket.cpp \
 	$(ZT1)/node/InetAddress.cpp \
 	$(ZT1)/node/InetAddress.cpp \

+ 1 - 0
build.bat

@@ -3,3 +3,4 @@ mkdir build
 cd build
 cd build
 cmake .. -G "MinGW Makefiles"
 cmake .. -G "MinGW Makefiles"
 make -j4
 make -j4
+cd ..

+ 5 - 5
cmd/zerotier/cli/help.go

@@ -54,17 +54,16 @@ Commands:
   peer <address> [command] [option]    - Peer management commands
   peer <address> [command] [option]    - Peer management commands
     show                                 Show peer details (default)
     show                                 Show peer details (default)
     try <endpoint> [...]                 Try peer at explicit endpoint
     try <endpoint> [...]                 Try peer at explicit endpoint
-    locator <locator>                    Explicitly update peer locator
-  roots                                  List root peers
-  root [command]                       - Root management commands
-    add <identity | url> [endpoint]      Add a root or a set of roots
-    remove <address | url | serial>      Remove a root or set of roots
   set [option] [value]                 - Get or set a core config option
   set [option] [value]                 - Get or set a core config option
     port <port>                          Primary P2P port
     port <port>                          Primary P2P port
     secondaryport <port/0>               Secondary P2P port (0 to disable)
     secondaryport <port/0>               Secondary P2P port (0 to disable)
     blacklist cidr <IP/bits> <boolean>   Toggle physical path blacklisting
     blacklist cidr <IP/bits> <boolean>   Toggle physical path blacklisting
     blacklist if <prefix> <boolean>      Toggle interface prefix blacklisting
     blacklist if <prefix> <boolean>      Toggle interface prefix blacklisting
     portmap <boolean>                    Toggle use of uPnP or NAT-PMP
     portmap <boolean>                    Toggle use of uPnP or NAT-PMP
+  roots                                  List root peers
+  root [command]                       - Root management commands
+    trust <identity | url> [endpoint]    Add a root or a set of roots
+    remove <address | url | serial>      Remove a root or set of roots
   controller <command> [option]        - Local controller management commands
   controller <command> [option]        - Local controller management commands
     networks                             List networks run by local controller
     networks                             List networks run by local controller
     new                                  Create a new network
     new                                  Create a new network
@@ -80,6 +79,7 @@ Commands:
     validate <identity>                  Locally validate an identity
     validate <identity>                  Locally validate an identity
     sign <identity> <file>               Sign a file with an identity's key
     sign <identity> <file>               Sign a file with an identity's key
     verify <identity> <file> <sig>       Verify a signature
     verify <identity> <file> <sig>       Verify a signature
+  certificate <command> [args]         - Certificate commands
 
 
 An <address> may be specified as a 10-digit short ZeroTier address, a
 An <address> may be specified as a 10-digit short ZeroTier address, a
 fingerprint containing both an address and a SHA384 hash, or an identity.
 fingerprint containing both an address and a SHA384 hash, or an identity.

+ 1 - 1
cmd/zerotier/cli/service.go

@@ -25,7 +25,7 @@ import (
 	"zerotier/pkg/zerotier"
 	"zerotier/pkg/zerotier"
 )
 )
 
 
-func Service(basePath, authToken string, args []string) {
+func Service(basePath string, args []string) {
 	if len(args) > 0 {
 	if len(args) > 0 {
 		Help()
 		Help()
 		os.Exit(1)
 		os.Exit(1)

+ 46 - 64
cmd/zerotier/zerotier.go

@@ -43,12 +43,40 @@ func getAuthTokenPaths(basePath string) (p []string) {
 	return p
 	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 {
 	if len(authToken) == 0 {
 		fmt.Println("FATAL: unable to read API authorization token from command line or any filesystem location.")
 		fmt.Println("FATAL: unable to read API authorization token from command line or any filesystem location.")
 		os.Exit(1)
 		os.Exit(1)
-
 	}
 	}
+	return authToken
 }
 }
 
 
 func main() {
 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
 	// 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.
 	// in pushing a lot of packets around. If that ever changes this should be adjusted.
 	runtime.GOMAXPROCS(1)
 	runtime.GOMAXPROCS(1)
-	debug.SetGCPercent(20)
+	debug.SetGCPercent(15)
 
 
 	globalOpts := flag.NewFlagSet("global", flag.ContinueOnError)
 	globalOpts := flag.NewFlagSet("global", flag.ContinueOnError)
 	hflag := globalOpts.Bool("h", false, "") // support -h to be canonical with other Unix utilities
 	hflag := globalOpts.Bool("h", false, "") // support -h to be canonical with other Unix utilities
@@ -80,89 +108,43 @@ func main() {
 	if len(args) > 1 {
 	if len(args) > 1 {
 		cmdArgs = args[1:]
 		cmdArgs = args[1:]
 	}
 	}
-
 	basePath := zerotier.PlatformDefaultHomePath
 	basePath := zerotier.PlatformDefaultHomePath
 	if len(*pflag) > 0 {
 	if len(*pflag) > 0 {
 		basePath = *pflag
 		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] {
 	switch args[0] {
-	case "help":
+	default:
+	//case "help":
 		cli.Help()
 		cli.Help()
-		os.Exit(0)
 	case "version":
 	case "version":
 		fmt.Printf("%d.%d.%d\n", zerotier.CoreVersionMajor, zerotier.CoreVersionMinor, zerotier.CoreVersionRevision)
 		fmt.Printf("%d.%d.%d\n", zerotier.CoreVersionMajor, zerotier.CoreVersionMinor, zerotier.CoreVersionRevision)
-		os.Exit(0)
 	case "service":
 	case "service":
-		cli.Service(basePath, authToken, cmdArgs)
+		cli.Service(basePath, cmdArgs)
 	case "status", "info":
 	case "status", "info":
-		authTokenRequired(authToken)
-		cli.Status(basePath, authToken, cmdArgs, *jflag)
+		cli.Status(basePath, authTokenRequired(basePath, *tflag, *tTflag), cmdArgs, *jflag)
 	case "join":
 	case "join":
-		authTokenRequired(authToken)
-		cli.Join(basePath, authToken, cmdArgs)
+		cli.Join(basePath, authTokenRequired(basePath, *tflag, *tTflag), cmdArgs)
 	case "leave":
 	case "leave":
-		authTokenRequired(authToken)
-		cli.Leave(basePath, authToken, cmdArgs)
+		cli.Leave(basePath, authTokenRequired(basePath, *tflag, *tTflag), cmdArgs)
 	case "networks", "listnetworks":
 	case "networks", "listnetworks":
-		authTokenRequired(authToken)
-		cli.Networks(basePath, authToken, cmdArgs, *jflag)
+		cli.Networks(basePath, authTokenRequired(basePath, *tflag, *tTflag), cmdArgs, *jflag)
 	case "network":
 	case "network":
-		authTokenRequired(authToken)
-		cli.Network(basePath, authToken, cmdArgs, *jflag)
+		cli.Network(basePath, authTokenRequired(basePath, *tflag, *tTflag), cmdArgs, *jflag)
 	case "peers", "listpeers", "lspeers":
 	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":
 	case "peer":
-		authTokenRequired(authToken)
+		authTokenRequired(basePath, *tflag, *tTflag)
 	case "roots":
 	case "roots":
-		authTokenRequired(authToken)
-		cli.Peers(basePath, authToken, cmdArgs, *jflag, true)
+		cli.Peers(basePath, authTokenRequired(basePath, *tflag, *tTflag), cmdArgs, *jflag, true)
 	case "root":
 	case "root":
-		authTokenRequired(authToken)
-		cli.Root(basePath, authToken, cmdArgs, *jflag)
+		cli.Root(basePath, authTokenRequired(basePath, *tflag, *tTflag), cmdArgs, *jflag)
 	case "set":
 	case "set":
-		authTokenRequired(authToken)
-		cli.Set(basePath, authToken, cmdArgs)
+		cli.Set(basePath, authTokenRequired(basePath, *tflag, *tTflag), cmdArgs)
 	case "controller":
 	case "controller":
-		authTokenRequired(authToken)
-		cli.Controller(basePath, authToken, cmdArgs, *jflag)
+		cli.Controller(basePath, authTokenRequired(basePath, *tflag, *tTflag), cmdArgs, *jflag)
 	case "identity":
 	case "identity":
 		cli.Identity(cmdArgs)
 		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)
 }
 }

+ 6 - 6
controller/EmbeddedNetworkController.cpp

@@ -23,7 +23,7 @@
 
 
 #include "../core/Constants.hpp"
 #include "../core/Constants.hpp"
 #include "../core/Node.hpp"
 #include "../core/Node.hpp"
-#include "../core/CertificateOfMembership.hpp"
+#include "../core/MembershipCredential.hpp"
 #include "../core/NetworkConfig.hpp"
 #include "../core/NetworkConfig.hpp"
 #include "../core/Dictionary.hpp"
 #include "../core/Dictionary.hpp"
 #include "../core/MAC.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)
 void EmbeddedNetworkController::onNetworkMemberDeauthorize(const void *db,uint64_t networkId,uint64_t memberId)
 {
 {
 	const int64_t now = OSUtils::now();
 	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);
 	rev.sign(_signingId);
 	{
 	{
 		std::lock_guard<std::mutex> l(_memberStatus_l);
 		std::lock_guard<std::mutex> l(_memberStatus_l);
@@ -1370,7 +1370,7 @@ void EmbeddedNetworkController::_request(
 								++caprc;
 								++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()))
 					if (nc->capabilities[nc->capabilityCount].sign(_signingId,identity.address()))
 						++nc->capabilityCount;
 						++nc->capabilityCount;
 					if (nc->capabilityCount >= ZT_MAX_NETWORK_CAPABILITIES)
 					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) {
 		for(std::map< uint32_t,uint32_t >::const_iterator t(memberTagsById.begin());t!=memberTagsById.end();++t) {
 			if (nc->tagCount >= ZT_MAX_NETWORK_TAGS)
 			if (nc->tagCount >= ZT_MAX_NETWORK_TAGS)
 				break;
 				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))
 			if (nc->tags[nc->tagCount].sign(_signingId))
 				++nc->tagCount;
 				++nc->tagCount;
 		}
 		}
@@ -1609,14 +1609,14 @@ void EmbeddedNetworkController::_request(
 
 
 	// Issue a certificate of ownership for all static IPs
 	// Issue a certificate of ownership for all static IPs
 	if (nc->staticIpCount) {
 	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;i<nc->staticIpCount;++i)
 		for(unsigned int i=0;i<nc->staticIpCount;++i)
 			nc->certificatesOfOwnership[0].addThing(nc->staticIps[i]);
 			nc->certificatesOfOwnership[0].addThing(nc->staticIps[i]);
 		nc->certificatesOfOwnership[0].sign(_signingId);
 		nc->certificatesOfOwnership[0].sign(_signingId);
 		nc->certificateOfOwnershipCount = 1;
 		nc->certificateOfOwnershipCount = 1;
 	}
 	}
 
 
-	CertificateOfMembership com(now,credentialtmd,nwid,identity);
+	MembershipCredential com(now, credentialtmd, nwid, identity);
 	if (com.sign(_signingId)) {
 	if (com.sign(_signingId)) {
 		nc->com = com;
 		nc->com = com;
 	} else {
 	} else {

+ 0 - 11
core/Address.hpp

@@ -136,37 +136,26 @@ public:
 
 
 	ZT_INLINE bool operator==(const Address &a) const noexcept
 	ZT_INLINE bool operator==(const Address &a) const noexcept
 	{ return _a == a._a; }
 	{ return _a == a._a; }
-
 	ZT_INLINE bool operator!=(const Address &a) const noexcept
 	ZT_INLINE bool operator!=(const Address &a) const noexcept
 	{ return _a != a._a; }
 	{ return _a != a._a; }
-
 	ZT_INLINE bool operator>(const Address &a) const noexcept
 	ZT_INLINE bool operator>(const Address &a) const noexcept
 	{ return _a > a._a; }
 	{ return _a > a._a; }
-
 	ZT_INLINE bool operator<(const Address &a) const noexcept
 	ZT_INLINE bool operator<(const Address &a) const noexcept
 	{ return _a < a._a; }
 	{ return _a < a._a; }
-
 	ZT_INLINE bool operator>=(const Address &a) const noexcept
 	ZT_INLINE bool operator>=(const Address &a) const noexcept
 	{ return _a >= a._a; }
 	{ return _a >= a._a; }
-
 	ZT_INLINE bool operator<=(const Address &a) const noexcept
 	ZT_INLINE bool operator<=(const Address &a) const noexcept
 	{ return _a <= a._a; }
 	{ return _a <= a._a; }
-
 	ZT_INLINE bool operator==(const uint64_t a) const noexcept
 	ZT_INLINE bool operator==(const uint64_t a) const noexcept
 	{ return _a == a; }
 	{ return _a == a; }
-
 	ZT_INLINE bool operator!=(const uint64_t a) const noexcept
 	ZT_INLINE bool operator!=(const uint64_t a) const noexcept
 	{ return _a != a; }
 	{ return _a != a; }
-
 	ZT_INLINE bool operator>(const uint64_t a) const noexcept
 	ZT_INLINE bool operator>(const uint64_t a) const noexcept
 	{ return _a > a; }
 	{ return _a > a; }
-
 	ZT_INLINE bool operator<(const uint64_t a) const noexcept
 	ZT_INLINE bool operator<(const uint64_t a) const noexcept
 	{ return _a < a; }
 	{ return _a < a; }
-
 	ZT_INLINE bool operator>=(const uint64_t a) const noexcept
 	ZT_INLINE bool operator>=(const uint64_t a) const noexcept
 	{ return _a >= a; }
 	{ return _a >= a; }
-
 	ZT_INLINE bool operator<=(const uint64_t a) const noexcept
 	ZT_INLINE bool operator<=(const uint64_t a) const noexcept
 	{ return _a <= a; }
 	{ return _a <= a; }
 
 

+ 4 - 1
core/Blob.hpp

@@ -29,7 +29,10 @@ struct Blob
 {
 {
 	uint8_t data[S];
 	uint8_t data[S];
 
 
-	ZT_INLINE Blob() { Utils::zero<S>(data); }
+	ZT_INLINE Blob() noexcept { Utils::zero<S>(data); }
+	explicit ZT_INLINE Blob(const void *const d) noexcept { Utils::copy<S>(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); }
 	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); }

+ 13 - 13
core/CMakeLists.txt

@@ -12,9 +12,10 @@ set(core_headers
 	Blob.hpp
 	Blob.hpp
 	Buf.hpp
 	Buf.hpp
 	C25519.hpp
 	C25519.hpp
-	Capability.hpp
-	CertificateOfMembership.hpp
-	CertificateOfOwnership.hpp
+	CapabilityCredential.hpp
+	Certificate.hpp
+	MembershipCredential.hpp
+	OwnershipCredential.hpp
 	Constants.hpp
 	Constants.hpp
 	Containers.hpp
 	Containers.hpp
 	Credential.hpp
 	Credential.hpp
@@ -25,13 +26,12 @@ set(core_headers
 	Expect.hpp
 	Expect.hpp
 	FCV.hpp
 	FCV.hpp
 	Fingerprint.hpp
 	Fingerprint.hpp
-	IdentificationCertificate.hpp
 	Identity.hpp
 	Identity.hpp
 	InetAddress.hpp
 	InetAddress.hpp
 	Locator.hpp
 	Locator.hpp
 	LZ4.hpp
 	LZ4.hpp
 	MAC.hpp
 	MAC.hpp
-	Membership.hpp
+	Member.hpp
 	MulticastGroup.hpp
 	MulticastGroup.hpp
 	Mutex.hpp
 	Mutex.hpp
 	Network.hpp
 	Network.hpp
@@ -49,7 +49,7 @@ set(core_headers
 	SHA512.hpp
 	SHA512.hpp
 	SharedPtr.hpp
 	SharedPtr.hpp
 	SymmetricKey.hpp
 	SymmetricKey.hpp
-	Tag.hpp
+	TagCredential.hpp
 	Topology.hpp
 	Topology.hpp
 	Trace.hpp
 	Trace.hpp
 	TriviallyCopyable.hpp
 	TriviallyCopyable.hpp
@@ -62,30 +62,30 @@ set(core_src
 	AES.cpp
 	AES.cpp
 	Buf.cpp
 	Buf.cpp
 	C25519.cpp
 	C25519.cpp
-	Capability.cpp
-	CertificateOfMembership.cpp
-	CertificateOfOwnership.cpp
+	CapabilityCredential.cpp
+	Certificate.cpp
+	MembershipCredential.cpp
+	OwnershipCredential.cpp
 	Credential.cpp
 	Credential.cpp
 	Dictionary.cpp
 	Dictionary.cpp
 	ECC384.cpp
 	ECC384.cpp
 	Endpoint.cpp
 	Endpoint.cpp
-	IdentificationCertificate.cpp
 	Identity.cpp
 	Identity.cpp
 	InetAddress.cpp
 	InetAddress.cpp
 	Locator.cpp
 	Locator.cpp
 	LZ4.cpp
 	LZ4.cpp
-	Membership.cpp
+	Member.cpp
 	Network.cpp
 	Network.cpp
 	NetworkConfig.cpp
 	NetworkConfig.cpp
 	Node.cpp
 	Node.cpp
 	Path.cpp
 	Path.cpp
 	Peer.cpp
 	Peer.cpp
 	Poly1305.cpp
 	Poly1305.cpp
-	Revocation.cpp
+	RevocationCredential.cpp
 	Salsa20.cpp
 	Salsa20.cpp
 	SelfAwareness.cpp
 	SelfAwareness.cpp
 	SHA512.cpp
 	SHA512.cpp
-	Tag.cpp
+	TagCredential.cpp
 	Topology.cpp
 	Topology.cpp
 	Trace.cpp
 	Trace.cpp
 	Utils.cpp
 	Utils.cpp

+ 7 - 7
core/Capability.cpp → core/CapabilityCredential.cpp

@@ -11,14 +11,14 @@
  */
  */
 /****/
 /****/
 
 
-#include "Capability.hpp"
+#include "CapabilityCredential.hpp"
 #include "Utils.hpp"
 #include "Utils.hpp"
 #include "Constants.hpp"
 #include "Constants.hpp"
 #include "MAC.hpp"
 #include "MAC.hpp"
 
 
 namespace ZeroTier {
 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];
 	uint8_t buf[ZT_CAPABILITY_MARSHAL_SIZE_MAX + 16];
 	m_issuedTo = to;
 	m_issuedTo = to;
@@ -27,7 +27,7 @@ bool Capability::sign(const Identity &from, const Address &to) noexcept
 	return m_signatureLength > 0;
 	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;
 	int p = 0;
 
 
@@ -45,7 +45,7 @@ int Capability::marshal(uint8_t data[ZT_CAPABILITY_MARSHAL_SIZE_MAX], const bool
 
 
 	Utils::storeBigEndian<uint16_t>(data + p, (uint16_t) m_ruleCount);
 	Utils::storeBigEndian<uint16_t>(data + p, (uint16_t) m_ruleCount);
 	p += 2;
 	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
 	// 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.
 	// 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;
 	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)
 	if (len < 22)
 		return -1;
 		return -1;
@@ -138,7 +138,7 @@ int Capability::unmarshal(const uint8_t *data, int len) noexcept
 	return p;
 	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;
 	int p = 0;
 	for (unsigned int i = 0;i < ruleCount;++i) {
 	for (unsigned int i = 0;i < ruleCount;++i) {
@@ -273,7 +273,7 @@ int Capability::marshalVirtualNetworkRules(uint8_t *data, const ZT_VirtualNetwor
 	return p;
 	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;
 	int p = 0;
 	unsigned int rc = 0;
 	unsigned int rc = 0;

+ 6 - 6
core/Capability.hpp → core/CapabilityCredential.hpp

@@ -50,14 +50,14 @@ class RuntimeEnvironment;
  * Note that this is after evaluation of network scope rules and only if
  * Note that this is after evaluation of network scope rules and only if
  * network scope rules do not deliver an explicit match.
  * network scope rules do not deliver an explicit match.
  */
  */
-class Capability : public Credential
+class CapabilityCredential : public Credential
 {
 {
 	friend class Credential;
 	friend class Credential;
 
 
 public:
 public:
 	static constexpr ZT_CredentialType credentialType() noexcept { return ZT_CREDENTIAL_TYPE_CAPABILITY; }
 	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
 	 * @param id Capability ID
@@ -67,7 +67,7 @@ public:
 	 * @param rules Network flow rules for this capability
 	 * @param rules Network flow rules for this capability
 	 * @param ruleCount Number of flow rules
 	 * @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_nwid(nwid),
 		m_ts(ts),
 		m_ts(ts),
 		m_id(id),
 		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;
 	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
 	// 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:
 private:
 	uint64_t m_nwid;
 	uint64_t m_nwid;

+ 137 - 71
core/IdentificationCertificate.cpp → core/Certificate.cpp

@@ -11,118 +11,177 @@
  */
  */
 /****/
 /****/
 
 
-#include "IdentificationCertificate.hpp"
+#include "Certificate.hpp"
 #include "SHA512.hpp"
 #include "SHA512.hpp"
 
 
 namespace ZeroTier {
 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_identities.clear();
 	m_locators.clear();
 	m_locators.clear();
 	m_strings.clear();
 	m_strings.clear();
-	m_nodes.clear();
-	m_networks.clear();
+	m_serials.clear();
+
+	m_subjectIdentities.clear();
+	m_subjectNetworks.clear();
 	m_updateUrls.clear();
 	m_updateUrls.clear();
+	m_subjectCertificates.clear();
 }
 }
 
 
-IdentificationCertificate &IdentificationCertificate::operator=(const ZT_IdentificationCertificate &apiCert)
+Certificate &Certificate::operator=(const ZT_Certificate &apiCert)
 {
 {
 	clear();
 	clear();
-	Utils::copy< sizeof(ZT_IdentificationCertificate) >((ZT_IdentificationCertificate *)this, &apiCert);
+	Utils::copy< sizeof(ZT_Certificate) >((ZT_Certificate *)this, &apiCert);
 	return *this;
 	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.networkCount = 0;
+	this->subject.certificateCount = 0;
 
 
-	if (cert.issuer) {
-		m_identities.push_back(*reinterpret_cast<const Identity *>(cert.issuer));
-		this->issuer = reinterpret_cast<ZT_Identity *>(&(m_identities.back()));
+	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<const Identity *>(cert.subject.identities[i].identity), *reinterpret_cast<const Locator *>(cert.subject.identities[i].locator));
+			else addSubjectNode(*reinterpret_cast<const Identity *>(cert.subject.identities[i].identity));
+		}
 	}
 	}
 
 
-	for (unsigned int i = 0; i < cert.subject.nodeCount; ++i) {
-		if (cert.subject.nodes[i].locator)
-			addSubjectNode(*reinterpret_cast<const Identity *>(cert.subject.nodes[i].identity), *reinterpret_cast<const Locator *>(cert.subject.nodes[i].locator));
-		else if (cert.subject.nodes[i].identity)
-			addSubjectNode(*reinterpret_cast<const Identity *>(cert.subject.nodes[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.networkCount; ++i)
-		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<const Identity *>(cert.issuer));
+		this->issuer = reinterpret_cast<ZT_Identity *>(&(m_identities.back()));
+	}
 
 
 	if (cert.updateUrls) {
 	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;
 	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_identities.push_back(id);
-	m_nodes.back().identity = reinterpret_cast<ZT_Identity *>(&(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<ZT_Identity *>(&(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);
 	m_locators.push_back(loc);
+
+	// Set pointer to stored local copy of locator.
 	n->locator = reinterpret_cast<ZT_Locator *>(&(m_locators.back()));
 	n->locator = reinterpret_cast<ZT_Locator *>(&(m_locators.back()));
+
 	return n;
 	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 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 IdentificationCertificate::addUpdateUrl(const char *url)
+void Certificate::addUpdateUrl(const char *url)
 {
 {
+	// Store local copy of URL.
 	m_strings.push_back(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());
 	m_updateUrls.push_back(m_strings.back().c_str());
 	this->updateUrls = m_updateUrls.data();
 	this->updateUrls = m_updateUrls.data();
 	this->updateUrlCount = (unsigned int)m_updateUrls.size();
 	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];
 	char tmp[256];
 	Vector< uint8_t > enc;
 	Vector< uint8_t > enc;
 	Dictionary d;
 	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("f", this->flags);
 	d.add("v0", this->validity[0]);
 	d.add("v0", this->validity[0]);
 	d.add("v1", this->validity[1]);
 	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<const Identity *>(this->subject.nodes[i].identity));
-		if (this->subject.nodes[i].locator)
-			d.addO(Dictionary::arraySubscript(tmp, "s.n[].l", i), *reinterpret_cast<const Locator *>(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<const Identity *>(this->subject.identities[i].identity));
+		if (this->subject.identities[i].locator)
+			d.addO(Dictionary::arraySubscript(tmp, "s.i$.l", i), *reinterpret_cast<const Locator *>(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) {
 	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);
 		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);
 	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.e", this->issuerName.email);
 	d.add("iN.ur", this->issuerName.url);
 	d.add("iN.ur", this->issuerName.url);
 
 
-	d.add("uU[]", (uint64_t)this->updateUrlCount);
+	d.add("u$", (uint64_t)this->updateUrlCount);
 	if (this->updateUrls) {
 	if (this->updateUrls) {
 		for (unsigned int i = 0; i < this->updateUrlCount; ++i)
 		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)))
 	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;
 	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();
 	clear();
 
 
@@ -175,21 +234,20 @@ bool IdentificationCertificate::decode(const Vector< uint8_t > &data)
 	if (!d.decode(data.data(), (unsigned int)data.size()))
 	if (!d.decode(data.data(), (unsigned int)data.size()))
 		return false;
 		return false;
 
 
-	this->version = (unsigned int)d.getUI("v");
-	this->maxPathLength = (unsigned int)d.getUI("mP");
 	this->flags = d.getUI("f");
 	this->flags = d.getUI("f");
 	this->validity[0] = (int64_t)d.getUI("v0");
 	this->validity[0] = (int64_t)d.getUI("v0");
 	this->validity[1] = (int64_t)d.getUI("v1");
 	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) {
 	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())
 		if (identityData.empty())
 			return false;
 			return false;
 		Identity id;
 		Identity id;
 		if (id.unmarshal(identityData.data(), (unsigned int)identityData.size()) <= 0)
 		if (id.unmarshal(identityData.data(), (unsigned int)identityData.size()) <= 0)
 			return false;
 			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()) {
 		if (!locatorData.empty()) {
 			Locator loc;
 			Locator loc;
 			if (loc.unmarshal(locatorData.data(), (unsigned int)locatorData.size()) <= 0)
 			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) {
 	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;
 			return false;
 		Fingerprint fp;
 		Fingerprint fp;
 		if (fp.unmarshal(fingerprintData.data(), (unsigned int)fingerprintData.size()) <= 0)
 		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);
 		this->addSubjectNetwork(nwid, fp);
 	}
 	}
 
 
+	cnt = (unsigned int)d.getUI("s.c$");
+	for (unsigned int i=0;i<cnt;++i) {
+		const Vector< uint8_t > &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.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.o", this->subject.name.organization, sizeof(this->subject.name.organization));
 	d.getS("s.n.u", this->subject.name.unit, sizeof(this->subject.name.unit));
 	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.e", this->issuerName.email, sizeof(this->issuerName.email));
 	d.getS("iN.ur", this->issuerName.url, sizeof(this->issuerName.url));
 	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) {
 	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)
 		if (url)
 			addUpdateUrl(tmp2);
 			addUpdateUrl(tmp2);
 		else return false;
 		else return false;
@@ -267,19 +331,21 @@ bool IdentificationCertificate::decode(const Vector< uint8_t > &data)
 	return true;
 	return true;
 }
 }
 
 
-bool IdentificationCertificate::sign(const Identity &issuer)
+bool Certificate::sign(const Identity &issuer)
 {
 {
 	Vector< uint8_t > enc(encode(true));
 	Vector< uint8_t > enc(encode(true));
 	SHA384(this->serialNo, enc.data(), (unsigned int)enc.size());
 	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;
 	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<const Identity *>(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<const Identity *>(this->issuer)->verify(enc.data(), (unsigned int)enc.size(), this->signature, this->signatureSize);
+		}
+	} catch ( ... ) {}
 	return false;
 	return false;
 }
 }
 
 

+ 30 - 20
core/IdentificationCertificate.hpp → 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 "Constants.hpp"
 #include "SHA512.hpp"
 #include "SHA512.hpp"
@@ -23,12 +23,13 @@
 #include "Locator.hpp"
 #include "Locator.hpp"
 #include "Dictionary.hpp"
 #include "Dictionary.hpp"
 #include "Utils.hpp"
 #include "Utils.hpp"
+#include "Blob.hpp"
 #include "Containers.hpp"
 #include "Containers.hpp"
 
 
 namespace ZeroTier {
 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
  * This is a wrapper around the straight C ZT_IdentificationCertificate and
  * handles allocating memory for objects added via addXXX() and disposing of
  * 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
  * field, so these will not work correctly before sign() or decode() is
  * called.
  * called.
  */
  */
-class IdentificationCertificate : public ZT_IdentificationCertificate
+class Certificate : public ZT_Certificate
 {
 {
 public:
 public:
-	ZT_INLINE IdentificationCertificate() noexcept
+	ZT_INLINE Certificate() noexcept
 	{ this->clear(); }
 	{ this->clear(); }
 
 
-	ZT_INLINE IdentificationCertificate(const ZT_IdentificationCertificate &apiCert)
+	ZT_INLINE Certificate(const ZT_Certificate &apiCert)
 	{ *this = apiCert; }
 	{ *this = apiCert; }
 
 
-	ZT_INLINE IdentificationCertificate(const IdentificationCertificate &cert)
+	ZT_INLINE Certificate(const Certificate &cert)
 	{ *this = cert; }
 	{ *this = cert; }
 
 
 	/**
 	/**
@@ -61,9 +62,9 @@ public:
 	 */
 	 */
 	void clear();
 	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
 	 * Add a subject node/identity without a locator
@@ -71,7 +72,7 @@ public:
 	 * @param id Identity
 	 * @param id Identity
 	 * @return Pointer to C struct
 	 * @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
 	 * Add a subject node/identity with a locator
@@ -80,7 +81,7 @@ public:
 	 * @param loc Locator signed by identity (signature is NOT checked here)
 	 * @param loc Locator signed by identity (signature is NOT checked here)
 	 * @return Pointer to C struct
 	 * @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
 	 * Add a subject network
@@ -89,7 +90,14 @@ public:
 	 * @param controller Network controller's full fingerprint
 	 * @param controller Network controller's full fingerprint
 	 * @return Pointer to C struct
 	 * @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
 	 * Add an update URL to the updateUrls list
@@ -135,22 +143,22 @@ public:
 	ZT_INLINE unsigned long hashCode() const noexcept
 	ZT_INLINE unsigned long hashCode() const noexcept
 	{ return (unsigned long)Utils::loadAsIsEndian< uint32_t >(this->serialNo); }
 	{ 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; }
 	{ 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; }
 	{ 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; }
 	{ 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; }
 	{ 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; }
 	{ 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; }
 	{ return memcmp(this->serialNo, c.serialNo, ZT_SHA384_DIGEST_SIZE) >= 0; }
 
 
 private:
 private:
@@ -160,10 +168,12 @@ private:
 	List< Identity > m_identities;
 	List< Identity > m_identities;
 	List< Locator > m_locators;
 	List< Locator > m_locators;
 	List< String > m_strings;
 	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.
 	// 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;
 	Vector< const char * > m_updateUrls;
 };
 };
 
 

+ 50 - 110
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. */
 /* This defines a Map, SortedMap, Vector, etc. based on STL templates. */
 
 
@@ -40,51 +40,40 @@ struct intl_MapHasher
 	template< typename O >
 	template< typename O >
 	std::size_t operator()(const O &obj) const noexcept
 	std::size_t operator()(const O &obj) const noexcept
 	{ return (std::size_t)obj.hashCode(); }
 	{ return (std::size_t)obj.hashCode(); }
-
 	std::size_t operator()(const uint64_t i) const noexcept
 	std::size_t operator()(const uint64_t i) const noexcept
 	{ return (std::size_t)Utils::hash64(i + Utils::s_mapNonce); }
 	{ return (std::size_t)Utils::hash64(i + Utils::s_mapNonce); }
-
 	std::size_t operator()(const int64_t i) const noexcept
 	std::size_t operator()(const int64_t i) const noexcept
 	{ return (std::size_t)Utils::hash64((uint64_t)i + Utils::s_mapNonce); }
 	{ return (std::size_t)Utils::hash64((uint64_t)i + Utils::s_mapNonce); }
-
 	std::size_t operator()(const uint32_t i) const noexcept
 	std::size_t operator()(const uint32_t i) const noexcept
 	{ return (std::size_t)Utils::hash32(i + (uint32_t)Utils::s_mapNonce); }
 	{ return (std::size_t)Utils::hash32(i + (uint32_t)Utils::s_mapNonce); }
-
 	std::size_t operator()(const int32_t i) const noexcept
 	std::size_t operator()(const int32_t i) const noexcept
 	{ return (std::size_t)Utils::hash32((uint32_t)i + (uint32_t)Utils::s_mapNonce); }
 	{ return (std::size_t)Utils::hash32((uint32_t)i + (uint32_t)Utils::s_mapNonce); }
 };
 };
 
 
 template< typename K, typename V >
 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 > >
-
-> {
-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
+class Map : public std::unordered_map< K, V, intl_MapHasher, std::equal_to< K >, Utils::Mallocator < std::pair< const K, V > > >
 {
 {
-	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); }
+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); }
 };
 };
 
 
 template< typename K, typename V >
 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
 #else
 
 
@@ -120,103 +109,54 @@ class MultiMap : public std::multimap< K,V,std::less<K>,Utils::Mallocator< std::
 #endif
 #endif
 
 
 template< typename K, typename V >
 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:
 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 >
 template< typename V >
-class Vector : public std::vector< V, Utils::Mallocator < V >
-
->
+class Vector : public std::vector< V, Utils::Mallocator < V > >
 {
 {
 public:
 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 >
 template< typename V >
-class List : public std::list< V, Utils::Mallocator < V >
-
->
+class List : public std::list< V, Utils::Mallocator < V > >
 {
 {
 };
 };
 
 
 template< typename 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:
 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
 } // ZeroTier

+ 10 - 10
core/Credential.cpp

@@ -14,11 +14,11 @@
 #include "Constants.hpp"
 #include "Constants.hpp"
 #include "RuntimeEnvironment.hpp"
 #include "RuntimeEnvironment.hpp"
 #include "Credential.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 "Network.hpp"
 #include "Topology.hpp"
 #include "Topology.hpp"
 
 
@@ -66,12 +66,12 @@ static ZT_INLINE Credential::VerifyResult _credVerify(const RuntimeEnvironment *
 	return Credential::VERIFY_BAD_SIGNATURE;
 	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.
 	// Sanity check network ID.
 	if ((!credential.m_signedBy) || (credential.m_signedBy != Network::controllerFor(credential.m_networkId)))
 	if ((!credential.m_signedBy) || (credential.m_signedBy != Network::controllerFor(credential.m_networkId)))

+ 10 - 10
core/Credential.hpp

@@ -23,11 +23,11 @@
 
 
 namespace ZeroTier {
 namespace ZeroTier {
 
 
-class Capability;
-class Revocation;
-class Tag;
-class CertificateOfMembership;
-class CertificateOfOwnership;
+class CapabilityCredential;
+class RevocationCredential;
+class TagCredential;
+class MembershipCredential;
+class OwnershipCredential;
 class RuntimeEnvironment;
 class RuntimeEnvironment;
 
 
 /**
 /**
@@ -52,11 +52,11 @@ public:
 	};
 	};
 
 
 protected:
 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
 } // namespace ZeroTier

+ 4 - 1
core/Dictionary.hpp

@@ -431,7 +431,10 @@ private:
 		return buf;
 		return buf;
 	}
 	}
 
 
-	SortedMap <String, Vector< uint8_t >> 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
 } // namespace ZeroTier

+ 2 - 6
core/Expect.hpp

@@ -49,9 +49,7 @@ public:
 	 * @param now Current time
 	 * @param now Current time
 	 */
 	 */
 	ZT_INLINE void sending(const uint64_t packetId, const int64_t now) noexcept
 	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.
 	 * 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)
 	 * @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
 	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:
 private:
 	// Each bucket contains a timestamp in units of the max expect duration.
 	// Each bucket contains a timestamp in units of the max expect duration.

+ 0 - 7
core/Identity.hpp

@@ -222,27 +222,20 @@ public:
 
 
 	ZT_INLINE bool operator==(const Identity &id) const noexcept
 	ZT_INLINE bool operator==(const Identity &id) const noexcept
 	{ return (m_fp == id.m_fp); }
 	{ return (m_fp == id.m_fp); }
-
 	ZT_INLINE bool operator!=(const Identity &id) const noexcept
 	ZT_INLINE bool operator!=(const Identity &id) const noexcept
 	{ return !(*this == id); }
 	{ return !(*this == id); }
-
 	ZT_INLINE bool operator<(const Identity &id) const noexcept
 	ZT_INLINE bool operator<(const Identity &id) const noexcept
 	{ return (m_fp < id.m_fp); }
 	{ return (m_fp < id.m_fp); }
-
 	ZT_INLINE bool operator>(const Identity &id) const noexcept
 	ZT_INLINE bool operator>(const Identity &id) const noexcept
 	{ return (id < *this); }
 	{ return (id < *this); }
-
 	ZT_INLINE bool operator<=(const Identity &id) const noexcept
 	ZT_INLINE bool operator<=(const Identity &id) const noexcept
 	{ return !(id < *this); }
 	{ return !(id < *this); }
-
 	ZT_INLINE bool operator>=(const Identity &id) const noexcept
 	ZT_INLINE bool operator>=(const Identity &id) const noexcept
 	{ return !(*this < id); }
 	{ return !(*this < id); }
 
 
 	static constexpr int marshalSizeMax() noexcept
 	static constexpr int marshalSizeMax() noexcept
 	{ return ZT_IDENTITY_MARSHAL_SIZE_MAX; }
 	{ return ZT_IDENTITY_MARSHAL_SIZE_MAX; }
-
 	int marshal(uint8_t data[ZT_IDENTITY_MARSHAL_SIZE_MAX], bool includePrivate = false) const noexcept;
 	int marshal(uint8_t data[ZT_IDENTITY_MARSHAL_SIZE_MAX], bool includePrivate = false) const noexcept;
-
 	int unmarshal(const uint8_t *data, int len) noexcept;
 	int unmarshal(const uint8_t *data, int len) noexcept;
 
 
 private:
 private:

+ 2 - 18
core/MAC.hpp

@@ -62,9 +62,7 @@ public:
 	 * @param len Length, must be >= 6 or result is zero
 	 * @param len Length, must be >= 6 or result is zero
 	 */
 	 */
 	ZT_INLINE void setTo(const uint8_t b[6]) noexcept
 	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
 	 * @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
 	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
 	ZT_INLINE bool operator==(const MAC &m) const noexcept
 	{ return (m_mac == m.m_mac); }
 	{ return (m_mac == m.m_mac); }
-
 	ZT_INLINE bool operator!=(const MAC &m) const noexcept
 	ZT_INLINE bool operator!=(const MAC &m) const noexcept
 	{ return (m_mac != m.m_mac); }
 	{ return (m_mac != m.m_mac); }
-
 	ZT_INLINE bool operator<(const MAC &m) const noexcept
 	ZT_INLINE bool operator<(const MAC &m) const noexcept
 	{ return (m_mac < m.m_mac); }
 	{ return (m_mac < m.m_mac); }
-
 	ZT_INLINE bool operator<=(const MAC &m) const noexcept
 	ZT_INLINE bool operator<=(const MAC &m) const noexcept
 	{ return (m_mac <= m.m_mac); }
 	{ return (m_mac <= m.m_mac); }
-
 	ZT_INLINE bool operator>(const MAC &m) const noexcept
 	ZT_INLINE bool operator>(const MAC &m) const noexcept
 	{ return (m_mac > m.m_mac); }
 	{ return (m_mac > m.m_mac); }
-
 	ZT_INLINE bool operator>=(const MAC &m) const noexcept
 	ZT_INLINE bool operator>=(const MAC &m) const noexcept
 	{ return (m_mac >= m.m_mac); }
 	{ return (m_mac >= m.m_mac); }
-
 	ZT_INLINE bool operator==(const uint64_t m) const noexcept
 	ZT_INLINE bool operator==(const uint64_t m) const noexcept
 	{ return (m_mac == m); }
 	{ return (m_mac == m); }
-
 	ZT_INLINE bool operator!=(const uint64_t m) const noexcept
 	ZT_INLINE bool operator!=(const uint64_t m) const noexcept
 	{ return (m_mac != m); }
 	{ return (m_mac != m); }
-
 	ZT_INLINE bool operator<(const uint64_t m) const noexcept
 	ZT_INLINE bool operator<(const uint64_t m) const noexcept
 	{ return (m_mac < m); }
 	{ return (m_mac < m); }
-
 	ZT_INLINE bool operator<=(const uint64_t m) const noexcept
 	ZT_INLINE bool operator<=(const uint64_t m) const noexcept
 	{ return (m_mac <= m); }
 	{ return (m_mac <= m); }
-
 	ZT_INLINE bool operator>(const uint64_t m) const noexcept
 	ZT_INLINE bool operator>(const uint64_t m) const noexcept
 	{ return (m_mac > m); }
 	{ return (m_mac > m); }
-
 	ZT_INLINE bool operator>=(const uint64_t m) const noexcept
 	ZT_INLINE bool operator>=(const uint64_t m) const noexcept
 	{ return (m_mac >= m); }
 	{ return (m_mac >= m); }
 
 

+ 23 - 23
core/Membership.cpp → core/Member.cpp

@@ -13,14 +13,14 @@
 
 
 #include <algorithm>
 #include <algorithm>
 
 
-#include "Membership.hpp"
+#include "Member.hpp"
 #include "RuntimeEnvironment.hpp"
 #include "RuntimeEnvironment.hpp"
 #include "Peer.hpp"
 #include "Peer.hpp"
 #include "Topology.hpp"
 #include "Topology.hpp"
 
 
 namespace ZeroTier {
 namespace ZeroTier {
 
 
-Membership::Membership() :
+Member::Member() :
 	m_comRevocationThreshold(0),
 	m_comRevocationThreshold(0),
 	m_lastPushedCredentials(0),
 	m_lastPushedCredentials(0),
 	m_comAgreementLocalTimestamp(0),
 	m_comAgreementLocalTimestamp(0),
@@ -28,14 +28,14 @@ Membership::Membership() :
 {
 {
 }
 }
 
 
-void Membership::pushCredentials(const RuntimeEnvironment *RR,void *tPtr,const int64_t now,const SharedPtr<Peer> &to,const NetworkConfig &nconf)
+void Member::pushCredentials(const RuntimeEnvironment *RR, void *tPtr, const int64_t now, const SharedPtr<Peer> &to, const NetworkConfig &nconf)
 {
 {
 	if (!nconf.com) // sanity check
 	if (!nconf.com) // sanity check
 		return;
 		return;
 
 
 #if 0
 #if 0
 	SharedPtr<Buf> outp(new Buf());
 	SharedPtr<Buf> outp(new Buf());
-	Protocol::Header &ph = outp->as<Protocol::Header>(); // NOLINT(hicpp-use-auto,modernize-use-auto)
+	Protocol::Header &ph = outp->as<Protocol::Header>();
 
 
 	unsigned int capPtr = 0,tagPtr = 0,cooPtr = 0;
 	unsigned int capPtr = 0,tagPtr = 0,cooPtr = 0;
 	bool sendCom = true;
 	bool sendCom = true;
@@ -115,14 +115,14 @@ void Membership::pushCredentials(const RuntimeEnvironment *RR,void *tPtr,const i
 	m_lastPushedCredentials = now;
 	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<Tag>(nconf, m_remoteTags);
-	m_cleanCredImpl<Capability>(nconf, m_remoteCaps);
-	m_cleanCredImpl<CertificateOfOwnership>(nconf, m_remoteCoos);
+	m_cleanCredImpl<TagCredential>(nconf, m_remoteTags);
+	m_cleanCredImpl<CapabilityCredential>(nconf, m_remoteCaps);
+	m_cleanCredImpl<OwnershipCredential>(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();
 	const int64_t newts = com.timestamp();
 	if (newts <= m_comRevocationThreshold) {
 	if (newts <= m_comRevocationThreshold) {
@@ -141,7 +141,7 @@ Membership::AddCredentialResult Membership::addCredential(const RuntimeEnvironme
 	switch(com.verify(RR,tPtr)) {
 	switch(com.verify(RR,tPtr)) {
 		default:
 		default:
 			RR->t->credentialRejected(tPtr,0x0f198241,com.networkId(),sourcePeerIdentity,com.id(),com.timestamp(),ZT_CREDENTIAL_TYPE_COM,ZT_TRACE_CREDENTIAL_REJECTION_REASON_INVALID);
 			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:
 		case Credential::VERIFY_OK:
 			m_com = com;
 			m_com = com;
 			return ADD_ACCEPTED_NEW;
 			return ADD_ACCEPTED_NEW;
@@ -155,7 +155,7 @@ Membership::AddCredentialResult Membership::addCredential(const RuntimeEnvironme
 
 
 // 3/5 of the credential types have identical addCredential() code
 // 3/5 of the credential types have identical addCredential() code
 template<typename C>
 template<typename C>
-static ZT_INLINE Membership::AddCredentialResult _addCredImpl(
+static ZT_INLINE Member::AddCredentialResult _addCredImpl(
 	Map<uint32_t,C> &remoteCreds,
 	Map<uint32_t,C> &remoteCreds,
 	const Map<uint64_t,int64_t> &revocations,
 	const Map<uint64_t,int64_t> &revocations,
 	const RuntimeEnvironment *const RR,
 	const RuntimeEnvironment *const RR,
@@ -168,36 +168,36 @@ static ZT_INLINE Membership::AddCredentialResult _addCredImpl(
 	if (rc) {
 	if (rc) {
 		if (rc->timestamp() > cred.timestamp()) {
 		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);
 			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)
 		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())) {
 	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);
 		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)) {
 	switch(cred.verify(RR,tPtr)) {
 		default:
 		default:
 			RR->t->credentialRejected(tPtr,0x01feba012,nconf.networkId,sourcePeerIdentity,cred.id(),cred.timestamp(),C::credentialType(),ZT_TRACE_CREDENTIAL_REJECTION_REASON_INVALID);
 			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:
 		case 0:
 			if (!rc)
 			if (!rc)
 				rc = &(remoteCreds[cred.id()]);
 				rc = &(remoteCreds[cred.id()]);
 			*rc = cred;
 			*rc = cred;
-			return Membership::ADD_ACCEPTED_NEW;
+			return Member::ADD_ACCEPTED_NEW;
 		case 1:
 		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<Tag>(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<Capability>(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<CertificateOfOwnership>(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<TagCredential>(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<CapabilityCredential>(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<OwnershipCredential>(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;
 	int64_t *rt;
 	switch(rev.verify(RR,tPtr)) {
 	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())) {
 	if ((ip.isV6())&&(nconf.ndpEmulation())) {
 		const InetAddress sixpl(InetAddress::makeIpv66plane(nconf.networkId,nconf.issuedTo.toInt()));
 		const InetAddress sixpl(InetAddress::makeIpv66plane(nconf.networkId,nconf.issuedTo.toInt()));

+ 25 - 25
core/Membership.hpp → core/Member.hpp

@@ -17,10 +17,10 @@
 #include "Constants.hpp"
 #include "Constants.hpp"
 #include "Credential.hpp"
 #include "Credential.hpp"
 #include "Containers.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"
 #include "NetworkConfig.hpp"
 
 
 namespace ZeroTier {
 namespace ZeroTier {
@@ -35,7 +35,7 @@ class Network;
  *
  *
  * This class is not thread safe. It must be locked externally.
  * This class is not thread safe. It must be locked externally.
  */
  */
-class Membership
+class Member
 {
 {
 public:
 public:
 	enum AddCredentialResult
 	enum AddCredentialResult
@@ -46,7 +46,7 @@ public:
 		ADD_DEFERRED_FOR_WHOIS
 		ADD_DEFERRED_FOR_WHOIS
 	};
 	};
 
 
-	Membership();
+	Member();
 
 
 	/**
 	/**
 	 * Send COM and other credentials to this peer
 	 * Send COM and other credentials to this peer
@@ -71,10 +71,10 @@ public:
 	 * @param id Tag ID
 	 * @param id Tag ID
 	 * @return Pointer to tag or NULL if not found
 	 * @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))
 		if (m_isUnspoofableAddress(nconf, r))
 			return true;
 			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)))
 			if (m_isCredentialTimestampValid(nconf, i->second) && (i->second.owns(r)))
 				return true;
 				return true;
 		}
 		}
@@ -115,7 +115,7 @@ public:
 	 *
 	 *
 	 * @param localCom
 	 * @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()))
 		if ((m_comAgreementLocalTimestamp == localCom.timestamp()) && (m_comAgreementRemoteTimestamp == m_com.timestamp()))
 			return true;
 			return true;
@@ -146,11 +146,11 @@ public:
 		return false;
 		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:
 private:
 	// This returns true if a resource is an IPv6 NDP-emulated address. These embed the ZT
 	// 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;
 	int64_t m_comAgreementLocalTimestamp,m_comAgreementRemoteTimestamp;
 
 
 	// Remote member's latest network COM
 	// Remote member's latest network COM
-	CertificateOfMembership m_com;
+	MembershipCredential m_com;
 
 
 	// Revocations by credentialKey()
 	// Revocations by credentialKey()
 	Map<uint64_t,int64_t> m_revocations;
 	Map<uint64_t,int64_t> m_revocations;
 
 
 	// Remote credentials that we have received from this member (and that are valid)
 	// Remote credentials that we have received from this member (and that are valid)
-	Map<uint32_t,Tag> m_remoteTags;
-	Map<uint32_t,Capability> m_remoteCaps;
-	Map<uint32_t,CertificateOfOwnership> m_remoteCoos;
+	Map<uint32_t,TagCredential> m_remoteTags;
+	Map<uint32_t,CapabilityCredential> m_remoteCaps;
+	Map<uint32_t,OwnershipCredential> m_remoteCoos;
 
 
 public:
 public:
 	class CapabilityIterator
 	class CapabilityIterator
 	{
 	{
 	public:
 	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_hti(m.m_remoteCaps.begin()),
 			m_parent(m),
 			m_parent(m),
 			m_nconf(nconf)
 			m_nconf(nconf)
 		{
 		{
 		}
 		}
 
 
-		ZT_INLINE Capability *next() noexcept
+		ZT_INLINE CapabilityCredential *next() noexcept
 		{
 		{
 			while (m_hti != m_parent.m_remoteCaps.end()) {
 			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))
 				if (m_parent.m_isCredentialTimestampValid(m_nconf, i->second))
 					return &(i->second);
 					return &(i->second);
 			}
 			}
@@ -224,8 +224,8 @@ public:
 		}
 		}
 
 
 	private:
 	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;
 		const NetworkConfig &m_nconf;
 	};
 	};
 };
 };

+ 7 - 7
core/CertificateOfMembership.cpp → core/MembershipCredential.cpp

@@ -11,11 +11,11 @@
  */
  */
 /****/
 /****/
 
 
-#include "CertificateOfMembership.hpp"
+#include "MembershipCredential.hpp"
 
 
 namespace ZeroTier {
 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_timestamp(timestamp),
 	m_timestampMaxDelta(timestampMaxDelta),
 	m_timestampMaxDelta(timestampMaxDelta),
 	m_networkId(nwid),
 	m_networkId(nwid),
@@ -23,7 +23,7 @@ CertificateOfMembership::CertificateOfMembership(const int64_t timestamp, const
 	m_signatureLength(0)
 	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
 	// NOTE: we always do explicit absolute value with an if() since llabs() can have overflow
 	// conditions that could introduce a vulnerability.
 	// 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);
 	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();
 	m_signedBy = with.address();
 	uint64_t buf[ZT_CERTIFICATEOFMEMBERSHIP_MARSHAL_SIZE_MAX / 8];
 	uint64_t buf[ZT_CERTIFICATEOFMEMBERSHIP_MARSHAL_SIZE_MAX / 8];
@@ -94,7 +94,7 @@ bool CertificateOfMembership::sign(const Identity &with) noexcept
 	return m_signatureLength > 0;
 	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;
 	data[0] = v2 ? 2 : 1;
 
 
@@ -156,7 +156,7 @@ int CertificateOfMembership::marshal(uint8_t data[ZT_CERTIFICATEOFMEMBERSHIP_MAR
 	return p;
 	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))
 	if (len < (1 + 2 + 72))
 		return -1;
 		return -1;
@@ -241,7 +241,7 @@ int CertificateOfMembership::unmarshal(const uint8_t *data, int len) noexcept
 	return -1;
 	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;
 	const uint64_t informational = 0xffffffffffffffffULL;
 
 

+ 5 - 5
core/CertificateOfMembership.hpp → 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
  * order with the fingerprint hash being packed into tuple IDs 3-8 and this buffer is
  * then signed.
  * then signed.
  */
  */
-class CertificateOfMembership : public Credential
+class MembershipCredential : public Credential
 {
 {
 	friend class Credential;
 	friend class Credential;
 
 
@@ -111,7 +111,7 @@ public:
 	/**
 	/**
 	 * Create an empty certificate of membership
 	 * 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
 	 * Create from required fields common to all networks
@@ -121,12 +121,12 @@ public:
 	 * @param nwid Network ID
 	 * @param nwid Network ID
 	 * @param issuedTo Certificate recipient
 	 * @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
 	 * @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
 	 * @return Credential ID, always 0 for COMs
@@ -166,7 +166,7 @@ public:
 	 * @param other Cert to compare with
 	 * @param other Cert to compare with
 	 * @return True if certs agree and 'other' may be communicated 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
 	 * Sign this certificate

+ 26 - 26
core/Network.cpp

@@ -74,7 +74,7 @@ _doZtFilterResult _doZtFilter(
 	const RuntimeEnvironment *RR,
 	const RuntimeEnvironment *RR,
 	Trace::RuleResultLog &rrl,
 	Trace::RuleResultLog &rrl,
 	const NetworkConfig &nconf,
 	const NetworkConfig &nconf,
-	const Membership *membership,       // can be NULL
+	const Member *membership,       // can be NULL
 	const bool inbound,
 	const bool inbound,
 	const Address &ztSource,
 	const Address &ztSource,
 	Address &ztDest,                    // MUTABLE -- is changed on REDIRECT actions
 	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_OR:
 			case ZT_NETWORK_RULE_MATCH_TAGS_BITWISE_XOR:
 			case ZT_NETWORK_RULE_MATCH_TAGS_BITWISE_XOR:
 			case ZT_NETWORK_RULE_MATCH_TAGS_EQUAL: {
 			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)) {
 				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) {
 					if (remoteTag) {
 						const uint32_t ltv = localTag->value();
 						const uint32_t ltv = localTag->value();
 						const uint32_t rtv = remoteTag->value();
 						const uint32_t rtv = remoteTag->value();
@@ -461,7 +461,7 @@ _doZtFilterResult _doZtFilter(
 				if (superAccept) {
 				if (superAccept) {
 					thisRuleMatches = 1;
 					thisRuleMatches = 1;
 				} else if ( ((rt == ZT_NETWORK_RULE_MATCH_TAG_SENDER)&&(inbound)) || ((rt == ZT_NETWORK_RULE_MATCH_TAG_RECEIVER)&&(!inbound)) ) {
 				} 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) {
 					if (remoteTag) {
 						thisRuleMatches = (uint8_t)(remoteTag->value() == rules[rn].v.tag.value);
 						thisRuleMatches = (uint8_t)(remoteTag->value() == rules[rn].v.tag.value);
 					} else {
 					} else {
@@ -474,7 +474,7 @@ _doZtFilterResult _doZtFilter(
 						}
 						}
 					}
 					}
 				} else { // sender and outbound or receiver and inbound
 				} 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)) {
 					if ((localTag != &(nconf.tags[nconf.tagCount]))&&(localTag->id() == rules[rn].v.tag.id)) {
 						thisRuleMatches = (uint8_t)(localTag->value() == rules[rn].v.tag.value);
 						thisRuleMatches = (uint8_t)(localTag->value() == rules[rn].v.tag.value);
 					} else {
 					} else {
@@ -626,7 +626,7 @@ bool Network::filterOutgoingPacket(
 	Mutex::Lock l1(m_memberships_l);
 	Mutex::Lock l1(m_memberships_l);
 	Mutex::Lock l2(m_config_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)) {
 	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) {
 	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);
 		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 {
 	} 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);
 		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;
 	Address cc;
 	unsigned int ccLength = 0;
 	unsigned int ccLength = 0;
 	bool ccWatch = false;
 	bool ccWatch = false;
-	const Capability *c = nullptr;
+	const CapabilityCredential *c = nullptr;
 
 
 	uint8_t qosBucket = 255; // For incoming packets this is a dummy value
 	uint8_t qosBucket = 255; // For incoming packets this is a dummy value
 
 
 	Mutex::Lock l1(m_memberships_l);
 	Mutex::Lock l1(m_memberships_l);
 	Mutex::Lock l2(m_config_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)) {
 	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: {
 		case DOZTFILTER_NO_MATCH: {
-			Membership::CapabilityIterator mci(membership, m_config);
+			Member::CapabilityIterator mci(membership, m_config);
 			while ((c = mci.next())) {
 			while ((c = mci.next())) {
 				ztFinalDest = ztDest; // sanity check, should be unmodified if there was no match
 				ztFinalDest = ztDest; // sanity check, should be unmodified if there was no match
 				Address cc2;
 				Address cc2;
@@ -1074,7 +1074,7 @@ bool Network::gate(void *tPtr,const SharedPtr<Peer> &peer) noexcept
 
 
 	try {
 	try {
 		Mutex::Lock l(m_memberships_l);
 		Mutex::Lock l(m_memberships_l);
-		Membership *m = m_memberships.get(peer->address());
+		Member *m = m_memberships.get(peer->address());
 		if (m) {
 		if (m) {
 			// SECURITY: this method in CertificateOfMembership does a full fingerprint check as well as
 			// SECURITY: this method in CertificateOfMembership does a full fingerprint check as well as
 			// checking certificate agreement. See Membership.hpp.
 			// 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);
 		Mutex::Lock l1(m_memberships_l);
 
 
-		for(Map<Address,Membership>::iterator i(m_memberships.begin());i != m_memberships.end();++i)
+		for(Map<Address,Member>::iterator i(m_memberships.begin()); i != m_memberships.end(); ++i)
 			i->second.clean(now, m_config);
 			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)
 	if (com.networkId() != m_id)
-		return Membership::ADD_REJECTED;
+		return Member::ADD_REJECTED;
 	Mutex::Lock _l(m_memberships_l);
 	Mutex::Lock _l(m_memberships_l);
 	return m_memberships[com.issuedTo().address].addCredential(RR, tPtr, sourcePeerIdentity, m_config, com);
 	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)
 	if (cap.networkId() != m_id)
-		return Membership::ADD_REJECTED;
+		return Member::ADD_REJECTED;
 	Mutex::Lock _l(m_memberships_l);
 	Mutex::Lock _l(m_memberships_l);
 	return m_memberships[cap.issuedTo()].addCredential(RR, tPtr, sourcePeerIdentity, m_config, cap);
 	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)
 	if (tag.networkId() != m_id)
-		return Membership::ADD_REJECTED;
+		return Member::ADD_REJECTED;
 	Mutex::Lock _l(m_memberships_l);
 	Mutex::Lock _l(m_memberships_l);
 	return m_memberships[tag.issuedTo()].addCredential(RR, tPtr, sourcePeerIdentity, m_config, tag);
 	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)
 	if (rev.networkId() != m_id)
-		return Membership::ADD_REJECTED;
+		return Member::ADD_REJECTED;
 
 
 	Mutex::Lock l1(m_memberships_l);
 	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
 		// TODO
 		/*
 		/*
 			Address *a = nullptr;
 			Address *a = nullptr;
@@ -1208,10 +1208,10 @@ Membership::AddCredentialResult Network::addCredential(void *tPtr,const Identity
 	return result;
 	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)
 	if (coo.networkId() != m_id)
-		return Membership::ADD_REJECTED;
+		return Member::ADD_REJECTED;
 	Mutex::Lock _l(m_memberships_l);
 	Mutex::Lock _l(m_memberships_l);
 	return m_memberships[coo.issuedTo()].addCredential(RR, tPtr, sourcePeerIdentity, m_config, coo);
 	return m_memberships[coo.issuedTo()].addCredential(RR, tPtr, sourcePeerIdentity, m_config, coo);
 }
 }
@@ -1220,7 +1220,7 @@ void Network::pushCredentials(void *tPtr,const SharedPtr<Peer> &to,const int64_t
 {
 {
 	const int64_t tout = std::min(m_config.credentialTimeMaxDelta, m_config.com.timestampMaxDelta());
 	const int64_t tout = std::min(m_config.credentialTimeMaxDelta, m_config.com.timestampMaxDelta());
 	Mutex::Lock _l(m_memberships_l);
 	Mutex::Lock _l(m_memberships_l);
-	Membership &m = m_memberships[to->address()];
+	Member &m = m_memberships[to->address()];
 	if (((now - m.lastPushedCredentials()) + 5000) >= tout) {
 	if (((now - m.lastPushedCredentials()) + 5000) >= tout) {
 		m.pushCredentials(RR, tPtr, now, to, m_config);
 		m.pushCredentials(RR, tPtr, now, to, m_config);
 	}
 	}

+ 9 - 9
core/Network.hpp

@@ -22,9 +22,9 @@
 #include "MAC.hpp"
 #include "MAC.hpp"
 #include "Buf.hpp"
 #include "Buf.hpp"
 #include "Dictionary.hpp"
 #include "Dictionary.hpp"
-#include "Membership.hpp"
+#include "Member.hpp"
 #include "NetworkConfig.hpp"
 #include "NetworkConfig.hpp"
-#include "CertificateOfMembership.hpp"
+#include "MembershipCredential.hpp"
 #include "Containers.hpp"
 #include "Containers.hpp"
 
 
 #define ZT_NETWORK_MAX_INCOMING_UPDATES 3
 #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
 	 * 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
 	 * 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
 	 * 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
 	 * 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
 	 * 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
 	 * Push credentials to a peer if timeouts indicate that we should do so
@@ -320,7 +320,7 @@ public:
 	ZT_INLINE void eachMember(F f)
 	ZT_INLINE void eachMember(F f)
 	{
 	{
 		Mutex::Lock ml(m_memberships_l);
 		Mutex::Lock ml(m_memberships_l);
-		for(Map<Address,Membership>::iterator i(m_memberships.begin());i != m_memberships.end();++i) { // NOLINT(modernize-loop-convert,hicpp-use-auto,modernize-use-auto)
+		for(Map<Address,Member>::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))
 			if (!f(i->first,i->second))
 				break;
 				break;
 		}
 		}
@@ -361,7 +361,7 @@ private:
 		NETCONF_FAILURE_INIT_FAILED
 		NETCONF_FAILURE_INIT_FAILED
 	} _netconfFailure;
 	} _netconfFailure;
 
 
-	Map<Address,Membership> m_memberships;
+	Map<Address,Member> m_memberships;
 
 
 	Mutex m_myMulticastGroups_l;
 	Mutex m_myMulticastGroups_l;
 	Mutex m_remoteBridgeRoutes_l;
 	Mutex m_remoteBridgeRoutes_l;

+ 5 - 5
core/NetworkConfig.cpp

@@ -96,7 +96,7 @@ bool NetworkConfig::toDictionary(Dictionary &d) const
 		blob = &(d[ZT_NETWORKCONFIG_DICT_KEY_RULES]);
 		blob = &(d[ZT_NETWORKCONFIG_DICT_KEY_RULES]);
 		if (this->ruleCount) {
 		if (this->ruleCount) {
 			blob->resize(ruleCount * ZT_VIRTUALNETWORKRULE_MARSHAL_SIZE_MAX);
 			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)
 			if (l > 0)
 				blob->resize(l);
 				blob->resize(l);
 		}
 		}
@@ -154,7 +154,7 @@ bool NetworkConfig::fromDictionary(const Dictionary &d)
 				try {
 				try {
 					unsigned int p = 0;
 					unsigned int p = 0;
 					while (p < blob->size()) {
 					while (p < blob->size()) {
-						Capability cap;
+						CapabilityCredential cap;
 						int l = cap.unmarshal(blob->data() + p,(int)(blob->size() - p));
 						int l = cap.unmarshal(blob->data() + p,(int)(blob->size() - p));
 						if (l < 0)
 						if (l < 0)
 							return false;
 							return false;
@@ -171,7 +171,7 @@ bool NetworkConfig::fromDictionary(const Dictionary &d)
 				try {
 				try {
 					unsigned int p = 0;
 					unsigned int p = 0;
 					while (p < blob->size()) {
 					while (p < blob->size()) {
-						Tag tag;
+						TagCredential tag;
 						int l = tag.unmarshal(blob->data() + p,(int)(blob->size() - p));
 						int l = tag.unmarshal(blob->data() + p,(int)(blob->size() - p));
 						if (l < 0)
 						if (l < 0)
 							return false;
 							return false;
@@ -188,7 +188,7 @@ bool NetworkConfig::fromDictionary(const Dictionary &d)
 				try {
 				try {
 					unsigned int p = 0;
 					unsigned int p = 0;
 					while (p < blob->size()) {
 					while (p < blob->size()) {
-						CertificateOfOwnership coo;
+						OwnershipCredential coo;
 						int l = coo.unmarshal(blob->data() + p,(int)(blob->size() - p));
 						int l = coo.unmarshal(blob->data() + p,(int)(blob->size() - p));
 						if (l < 0)
 						if (l < 0)
 							return false;
 							return false;
@@ -246,7 +246,7 @@ bool NetworkConfig::fromDictionary(const Dictionary &d)
 			blob = &(d[ZT_NETWORKCONFIG_DICT_KEY_RULES]);
 			blob = &(d[ZT_NETWORKCONFIG_DICT_KEY_RULES]);
 			if (!blob->empty()) {
 			if (!blob->empty()) {
 				this->ruleCount = 0;
 				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;
 					return false;
 			}
 			}
 		}
 		}

+ 10 - 10
core/NetworkConfig.hpp

@@ -18,10 +18,10 @@
 #include "InetAddress.hpp"
 #include "InetAddress.hpp"
 #include "MulticastGroup.hpp"
 #include "MulticastGroup.hpp"
 #include "Address.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 "Dictionary.hpp"
 #include "Identity.hpp"
 #include "Identity.hpp"
 #include "Utils.hpp"
 #include "Utils.hpp"
@@ -222,7 +222,7 @@ struct NetworkConfig : TriviallyCopyable
 	 */
 	 */
 	bool addSpecialist(const Address &a, uint64_t f) noexcept;
 	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) {
 		for (unsigned int i = 0;i < capabilityCount;++i) {
 			if (capabilities[i].id() == id)
 			if (capabilities[i].id() == id)
@@ -231,7 +231,7 @@ struct NetworkConfig : TriviallyCopyable
 		return nullptr;
 		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) {
 		for (unsigned int i = 0;i < tagCount;++i) {
 			if (tags[i].id() == id)
 			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
 	 * 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
 	 * 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
 	 * 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)
 	 * Network type (currently just public or private)
@@ -374,7 +374,7 @@ struct NetworkConfig : TriviallyCopyable
 	/**
 	/**
 	 * Certificate of membership (for private networks)
 	 * Certificate of membership (for private networks)
 	 */
 	 */
-	CertificateOfMembership com;
+	MembershipCredential com;
 };
 };
 
 
 } // namespace ZeroTier
 } // namespace ZeroTier

+ 2 - 2
core/NetworkController.hpp

@@ -17,7 +17,7 @@
 #include "Constants.hpp"
 #include "Constants.hpp"
 #include "Dictionary.hpp"
 #include "Dictionary.hpp"
 #include "NetworkConfig.hpp"
 #include "NetworkConfig.hpp"
-#include "Revocation.hpp"
+#include "RevocationCredential.hpp"
 #include "Address.hpp"
 #include "Address.hpp"
 
 
 namespace ZeroTier {
 namespace ZeroTier {
@@ -62,7 +62,7 @@ public:
 		 * @param destination Destination node address
 		 * @param destination Destination node address
 		 * @param rev Revocation to send
 		 * @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
 		 * Send a network configuration request error

+ 1 - 1
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()) {
 	if (destination == RR->identity.address()) {
 		SharedPtr< Network > n(network(rev.networkId()));
 		SharedPtr< Network > n(network(rev.networkId()));

+ 1 - 1
core/Node.hpp

@@ -358,7 +358,7 @@ public:
 	// Implementation of NetworkController::Sender interface
 	// Implementation of NetworkController::Sender interface
 	virtual void ncSendConfig(uint64_t nwid, uint64_t requestPacketId, const Address &destination, const NetworkConfig &nc, bool sendLegacyFormatConfig);
 	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);
 	virtual void ncSendError(uint64_t nwid, uint64_t requestPacketId, const Address &destination, NetworkController::ErrorCode errorCode);
 
 

+ 6 - 6
core/CertificateOfOwnership.cpp → core/OwnershipCredential.cpp

@@ -11,11 +11,11 @@
  */
  */
 /****/
 /****/
 
 
-#include "CertificateOfOwnership.hpp"
+#include "OwnershipCredential.hpp"
 
 
 namespace ZeroTier {
 namespace ZeroTier {
 
 
-void CertificateOfOwnership::addThing(const InetAddress &ip)
+void OwnershipCredential::addThing(const InetAddress &ip)
 {
 {
 	if (m_thingCount >= ZT_CERTIFICATEOFOWNERSHIP_MAX_THINGS)
 	if (m_thingCount >= ZT_CERTIFICATEOFOWNERSHIP_MAX_THINGS)
 		return;
 		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)
 	if (m_thingCount >= ZT_CERTIFICATEOFOWNERSHIP_MAX_THINGS)
 		return;
 		return;
@@ -39,7 +39,7 @@ void CertificateOfOwnership::addThing(const MAC &mac)
 	++m_thingCount;
 	++m_thingCount;
 }
 }
 
 
-bool CertificateOfOwnership::sign(const Identity &signer)
+bool OwnershipCredential::sign(const Identity &signer)
 {
 {
 	uint8_t buf[ZT_CERTIFICATEOFOWNERSHIP_MARSHAL_SIZE_MAX + 16];
 	uint8_t buf[ZT_CERTIFICATEOFOWNERSHIP_MARSHAL_SIZE_MAX + 16];
 	if (signer.hasPrivate()) {
 	if (signer.hasPrivate()) {
@@ -50,7 +50,7 @@ bool CertificateOfOwnership::sign(const Identity &signer)
 	return false;
 	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;
 	int p = 0;
 	if (forSign) {
 	if (forSign) {
@@ -88,7 +88,7 @@ int CertificateOfOwnership::marshal(uint8_t data[ZT_CERTIFICATEOFOWNERSHIP_MARSH
 	return p;
 	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)
 	if (len < 30)
 		return -1;
 		return -1;

+ 6 - 6
core/CertificateOfOwnership.hpp → core/OwnershipCredential.hpp

@@ -45,7 +45,7 @@ class RuntimeEnvironment;
  * These are used in conjunction with the rules engine to make IP addresses and
  * These are used in conjunction with the rules engine to make IP addresses and
  * other identifiers un-spoofable.
  * other identifiers un-spoofable.
  */
  */
-class CertificateOfOwnership : public Credential
+class OwnershipCredential : public Credential
 {
 {
 	friend class Credential;
 	friend class Credential;
 
 
@@ -60,9 +60,9 @@ public:
 		THING_IPV6_ADDRESS = 3
 		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);
 		memoryZero(this);
 		m_networkId = nwid;
 		m_networkId = nwid;
@@ -139,10 +139,10 @@ public:
 	int unmarshal(const uint8_t *data,int len) noexcept;
 	int unmarshal(const uint8_t *data,int len) noexcept;
 
 
 	// Provides natural sort order by ID
 	// 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:
 private:
 	ZT_INLINE bool _owns(const Thing &t,const void *v,unsigned int l) const noexcept
 	ZT_INLINE bool _owns(const Thing &t,const void *v,unsigned int l) const noexcept

+ 4 - 4
core/Revocation.cpp → core/RevocationCredential.cpp

@@ -11,11 +11,11 @@
  */
  */
 /****/
 /****/
 
 
-#include "Revocation.hpp"
+#include "RevocationCredential.hpp"
 
 
 namespace ZeroTier {
 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];
 	uint8_t buf[ZT_REVOCATION_MARSHAL_SIZE_MAX + 32];
 	if (signer.hasPrivate()) {
 	if (signer.hasPrivate()) {
@@ -26,7 +26,7 @@ bool Revocation::sign(const Identity &signer) noexcept
 	return false;
 	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;
 	int p = 0;
 	if (forSign) {
 	if (forSign) {
@@ -67,7 +67,7 @@ int Revocation::marshal(uint8_t data[ZT_REVOCATION_MARSHAL_SIZE_MAX], bool forSi
 	return p;
 	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)
 	if (len < 54)
 		return -1;
 		return -1;

+ 3 - 3
core/Revocation.hpp → core/RevocationCredential.hpp

@@ -35,7 +35,7 @@ class RuntimeEnvironment;
 /**
 /**
  * Revocation certificate to instantaneously revoke a COM, capability, or tag
  * Revocation certificate to instantaneously revoke a COM, capability, or tag
  */
  */
-class Revocation : public Credential
+class RevocationCredential : public Credential
 {
 {
 	friend class Credential;
 	friend class Credential;
 
 
@@ -43,7 +43,7 @@ public:
 	static constexpr ZT_CredentialType credentialType() noexcept
 	static constexpr ZT_CredentialType credentialType() noexcept
 	{ return ZT_CREDENTIAL_TYPE_REVOCATION; }
 	{ return ZT_CREDENTIAL_TYPE_REVOCATION; }
 
 
-	ZT_INLINE Revocation() noexcept
+	ZT_INLINE RevocationCredential() noexcept
 	{ memoryZero(this); } // NOLINT(cppcoreguidelines-pro-type-member-init,hicpp-member-init)
 	{ 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 tgt Target node whose credential(s) are being revoked
 	 * @param ct Credential type 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_id(i),
 		m_credentialId(cid),
 		m_credentialId(cid),
 		m_networkId(nwid),
 		m_networkId(nwid),

+ 4 - 4
core/Tag.cpp → core/TagCredential.cpp

@@ -11,11 +11,11 @@
  */
  */
 /****/
 /****/
 
 
-#include "Tag.hpp"
+#include "TagCredential.hpp"
 
 
 namespace ZeroTier {
 namespace ZeroTier {
 
 
-bool Tag::sign(const Identity &signer) noexcept
+bool TagCredential::sign(const Identity &signer) noexcept
 {
 {
 	uint8_t buf[ZT_TAG_MARSHAL_SIZE_MAX];
 	uint8_t buf[ZT_TAG_MARSHAL_SIZE_MAX];
 	if (signer.hasPrivate()) {
 	if (signer.hasPrivate()) {
@@ -26,7 +26,7 @@ bool Tag::sign(const Identity &signer) noexcept
 	return false;
 	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;
 	int p = 0;
 	if (forSign) {
 	if (forSign) {
@@ -61,7 +61,7 @@ int Tag::marshal(uint8_t data[ZT_TAG_MARSHAL_SIZE_MAX], bool forSign) const noex
 	return p;
 	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)
 	if (len < 37)
 		return -1;
 		return -1;

+ 16 - 16
core/Tag.hpp → core/TagCredential.hpp

@@ -43,7 +43,7 @@ class RuntimeEnvironment;
  * Unlike capabilities tags are signed only by the issuer and are never
  * Unlike capabilities tags are signed only by the issuer and are never
  * transferable.
  * transferable.
  */
  */
-class Tag : public Credential
+class TagCredential : public Credential
 {
 {
 	friend class Credential;
 	friend class Credential;
 
 
@@ -51,7 +51,7 @@ public:
 	static constexpr ZT_CredentialType credentialType() noexcept
 	static constexpr ZT_CredentialType credentialType() noexcept
 	{ return ZT_CREDENTIAL_TYPE_TAG; }
 	{ return ZT_CREDENTIAL_TYPE_TAG; }
 
 
-	ZT_INLINE Tag() noexcept
+	ZT_INLINE TagCredential() noexcept
 	{ memoryZero(this); }
 	{ memoryZero(this); }
 
 
 	/**
 	/**
@@ -61,7 +61,7 @@ public:
 	 * @param id Tag ID
 	 * @param id Tag ID
 	 * @param value Tag value
 	 * @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_id(id),
 		m_value(value),
 		m_value(value),
 		m_networkId(nwid),
 		m_networkId(nwid),
@@ -121,40 +121,40 @@ public:
 	int unmarshal(const uint8_t *data, int len) noexcept;
 	int unmarshal(const uint8_t *data, int len) noexcept;
 
 
 	// Provides natural sort order by ID
 	// 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); }
 	{ 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
 	// For searching sorted arrays or lists of Tags by ID
 	struct IdComparePredicate
 	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()); }
 		{ 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()); }
 		{ 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); }
 		{ 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()); }
 		{ 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()); }
 		{ 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()); }
 		{ 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()); }
 		{ 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); }
 		{ return (a->id() < b); }
 
 
 		ZT_INLINE bool operator()(const uint32_t a, const uint32_t b) const noexcept
 		ZT_INLINE bool operator()(const uint32_t a, const uint32_t b) const noexcept

+ 5 - 5
core/Tests.cpp

@@ -29,11 +29,11 @@
 #include "InetAddress.hpp"
 #include "InetAddress.hpp"
 #include "Endpoint.hpp"
 #include "Endpoint.hpp"
 #include "Locator.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 "NetworkConfig.hpp"
 #include "FCV.hpp"
 #include "FCV.hpp"
 #include "SHA512.hpp"
 #include "SHA512.hpp"

+ 17 - 13
core/Topology.cpp

@@ -39,18 +39,6 @@ SharedPtr< Peer > Topology::add(void *tPtr, const SharedPtr< Peer > &peer)
 	return 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)
 SharedPtr< Peer > Topology::addRoot(void *const tPtr, const Identity &id)
 {
 {
 	if ((id != RR->identity) && id.locallyValidate()) {
 	if ((id != RR->identity) && id.locallyValidate()) {
@@ -69,6 +57,10 @@ SharedPtr< Peer > Topology::addRoot(void *const tPtr, const Identity &id)
 	return SharedPtr< Peer >();
 	return SharedPtr< Peer >();
 }
 }
 
 
+ZT_CertificateError addRootSet(void *tPtr, const Certificate &cert)
+{
+}
+
 bool Topology::removeRoot(void *const tPtr, Address address)
 bool Topology::removeRoot(void *const tPtr, Address address)
 {
 {
 	RWMutex::Lock l1(m_peers_l);
 	RWMutex::Lock l1(m_peers_l);
@@ -76,10 +68,22 @@ bool Topology::removeRoot(void *const tPtr, Address address)
 	return true;
 	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()
 void Topology::rankRoots()
 {
 {
 	RWMutex::Lock l1(m_peers_l);
 	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)
 void Topology::doPeriodicTasks(void *tPtr, const int64_t now)

+ 17 - 2
core/Topology.hpp

@@ -25,7 +25,7 @@
 #include "ScopedPtr.hpp"
 #include "ScopedPtr.hpp"
 #include "Fingerprint.hpp"
 #include "Fingerprint.hpp"
 #include "Blob.hpp"
 #include "Blob.hpp"
-#include "IdentificationCertificate.hpp"
+#include "Certificate.hpp"
 #include "Containers.hpp"
 #include "Containers.hpp"
 
 
 namespace ZeroTier {
 namespace ZeroTier {
@@ -182,6 +182,20 @@ public:
 	 */
 	 */
 	SharedPtr< Peer > addRoot(void *tPtr, const Identity &id);
 	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
 	 * 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
 	RWMutex m_peers_l; // locks m_peers, m_roots, and m_rootPeers
 	Map< uint64_t, SharedPtr< Path > > m_paths;
 	Map< uint64_t, SharedPtr< Path > > m_paths;
 	Map< Address, SharedPtr< Peer > > m_peers;
 	Map< Address, SharedPtr< Peer > > m_peers;
-	Map< Identity, Set< IdentificationCertificate > > m_roots;
+	Map< Identity, Set< Blob<ZT_SHA384_DIGEST_SIZE> > > m_roots;
+	Map< String, Certificate > m_rootSets;
 	Vector< SharedPtr< Peer > > m_rootPeers;
 	Vector< SharedPtr< Peer > > m_rootPeers;
 };
 };
 
 

+ 5 - 5
core/Trace.hpp

@@ -35,11 +35,11 @@ class Identity;
 class Peer;
 class Peer;
 class Path;
 class Path;
 class Network;
 class Network;
-class CertificateOfMembership;
-class CertificateOfOwnership;
-class Revocation;
-class Tag;
-class Capability;
+class MembershipCredential;
+class OwnershipCredential;
+class RevocationCredential;
+class TagCredential;
+class CapabilityCredential;
 struct NetworkConfig;
 struct NetworkConfig;
 
 
 /**
 /**

+ 2 - 5
core/VL1.cpp

@@ -32,9 +32,7 @@ namespace ZeroTier {
 namespace {
 namespace {
 
 
 ZT_INLINE const Identity &identityFromPeerPtr(const SharedPtr< Peer > &p)
 ZT_INLINE const Identity &identityFromPeerPtr(const SharedPtr< Peer > &p)
-{
-	return (p) ? p->identity() : Identity::NIL;
-}
+{ return (p) ? p->identity() : Identity::NIL; }
 
 
 struct p_SalsaPolyCopyFunction
 struct p_SalsaPolyCopyFunction
 {
 {
@@ -100,8 +98,7 @@ struct p_PolyCopyFunction
 
 
 VL1::VL1(const RuntimeEnvironment *renv) :
 VL1::VL1(const RuntimeEnvironment *renv) :
 	RR(renv)
 	RR(renv)
-{
-}
+{}
 
 
 void VL1::onRemotePacket(void *const tPtr, const int64_t localSocket, const InetAddress &fromAddr, SharedPtr< Buf > &data, const unsigned int len) noexcept
 void VL1::onRemotePacket(void *const tPtr, const int64_t localSocket, const InetAddress &fromAddr, SharedPtr< Buf > &data, const unsigned int len) noexcept
 {
 {

+ 99 - 51
core/zerotier.h

@@ -294,40 +294,81 @@ typedef struct
 } ZT_Fingerprint;
 } 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
  * 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
  * 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.
  * Information about a real world entity.
  */
  */
 typedef struct
 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;
-
-/**
- * Identity and optional locator for a node
+	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 to help find a node on physical networks.
  */
  */
 typedef struct
 typedef struct
 {
 {
@@ -337,10 +378,10 @@ typedef struct
 	const ZT_Identity *identity;
 	const ZT_Identity *identity;
 
 
 	/**
 	/**
-	 * Locator or NULL if not specified
+	 * Locator, or NULL if none
 	 */
 	 */
 	const ZT_Locator *locator;
 	const ZT_Locator *locator;
-} ZT_IdentificationCertificate_Node;
+} ZT_Certificate_Identity;
 
 
 /**
 /**
  * ID and primary controller for a network
  * ID and primary controller for a network
@@ -356,7 +397,7 @@ typedef struct
 	 * Full fingerprint of primary controller
 	 * Full fingerprint of primary controller
 	 */
 	 */
 	ZT_Fingerprint controller;
 	ZT_Fingerprint controller;
-} ZT_IdentificationCertificate_Network;
+} ZT_Certificate_Network;
 
 
 /**
 /**
  * Identification certificate subject
  * Identification certificate subject
@@ -366,36 +407,48 @@ typedef struct
 	/**
 	/**
 	 * Identities and optional locators of nodes
 	 * Identities and optional locators of nodes
 	 */
 	 */
-	ZT_IdentificationCertificate_Node *nodes;
+	ZT_Certificate_Identity *identities;
 
 
 	/**
 	/**
 	 * Networks owned by this entity
 	 * 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
 	 * Number of networks
 	 */
 	 */
 	unsigned int networkCount;
 	unsigned int networkCount;
 
 
+	/**
+	 * Number of certificates
+	 */
+	unsigned int certificateCount;
+
 	/**
 	/**
 	 * Information about owner of items.
 	 * 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
 typedef struct
 {
 {
@@ -404,20 +457,6 @@ typedef struct
 	 */
 	 */
 	uint8_t serialNo[48];
 	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.
 	 * Flags indicating certificate usage and any other attributes.
 	 */
 	 */
@@ -434,7 +473,7 @@ typedef struct
 	/**
 	/**
 	 * Subject of certificate
 	 * Subject of certificate
 	 */
 	 */
-	ZT_IdentificationCertificate_Subject subject;
+	ZT_Certificate_Subject subject;
 
 
 	/**
 	/**
 	 * Issuer node identity and public key(s).
 	 * Issuer node identity and public key(s).
@@ -444,7 +483,7 @@ typedef struct
 	/**
 	/**
 	 * Issuer information
 	 * Issuer information
 	 */
 	 */
-	ZT_IdentificationCertificate_Name issuerName;
+	ZT_Certificate_Name issuerName;
 
 
 	/**
 	/**
 	 * URLs that can be consulted for updates to this certificate.
 	 * URLs that can be consulted for updates to this certificate.
@@ -456,6 +495,15 @@ typedef struct
 	 */
 	 */
 	unsigned int updateUrlCount;
 	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.
 	 * Size of signature in bytes.
 	 */
 	 */
@@ -464,8 +512,8 @@ typedef struct
 	/**
 	/**
 	 * Signature by issuer (algorithm determined by identity type).
 	 * 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
  * Credential type IDs