mirror of
https://github.com/zerotier/ZeroTierOne.git
synced 2025-06-06 12:33:44 +02:00
Certificates, etc... work in progress.
This commit is contained in:
parent
808ab715d9
commit
f447608d6b
24 changed files with 1502 additions and 865 deletions
4
Makefile
4
Makefile
|
@ -25,7 +25,7 @@ central-controller-docker:
|
||||||
docker build -t registry.zerotier.com/zerotier-central/ztcentral-controller:${TIMESTAMP} -f controller/central-docker/Dockerfile .
|
docker build -t registry.zerotier.com/zerotier-central/ztcentral-controller:${TIMESTAMP} -f controller/central-docker/Dockerfile .
|
||||||
|
|
||||||
clean:
|
clean:
|
||||||
rm -rf ${BUILDDIR} cmake-build-*
|
rm -rf ${BUILDDIR}
|
||||||
|
|
||||||
distclean:
|
distclean:
|
||||||
rm -rf ${BUILDDIR} cmake-build-*
|
rm -rf ${BUILDDIR}
|
||||||
|
|
|
@ -34,7 +34,8 @@ Global Options:
|
||||||
Commands:
|
Commands:
|
||||||
help Show this help
|
help Show this help
|
||||||
version Print version
|
version Print version
|
||||||
service Start node (see below)
|
service [-options] Start node (see below)
|
||||||
|
-d Fork into background (Unix only)
|
||||||
status Show node status and configuration
|
status Show node status and configuration
|
||||||
join [-options] <network> Join a virtual network
|
join [-options] <network> Join a virtual network
|
||||||
-a <token> Token to submit to controller
|
-a <token> Token to submit to controller
|
||||||
|
@ -56,10 +57,8 @@ Commands:
|
||||||
locator <locator> Explicitly update peer locator
|
locator <locator> Explicitly update peer locator
|
||||||
roots List root peers
|
roots List root peers
|
||||||
root [command] - Root management commands
|
root [command] - Root management commands
|
||||||
add <identity> [endpoint] Designate a peer as a root
|
add <identity | url> [endpoint] Add a root or a root set
|
||||||
remove <address> Un-designate a peer as a root
|
remove <address | url | serial> Remove a root or root set
|
||||||
subscribe <url> [<key hash>] Subscribe to a set of roots
|
|
||||||
unsubscribe <url | key hash> Unsubscribe from a 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)
|
||||||
|
|
|
@ -15,8 +15,11 @@ package cli
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"io/ioutil"
|
||||||
"os"
|
"os"
|
||||||
"os/signal"
|
"os/signal"
|
||||||
|
"path"
|
||||||
|
"strconv"
|
||||||
"syscall"
|
"syscall"
|
||||||
|
|
||||||
"zerotier/pkg/zerotier"
|
"zerotier/pkg/zerotier"
|
||||||
|
@ -28,16 +31,20 @@ func Service(basePath, authToken string, args []string) {
|
||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pidPath := path.Join(basePath, "zerotier.pid")
|
||||||
|
_ = ioutil.WriteFile(pidPath, []byte(strconv.FormatInt(int64(os.Getpid()), 10)), 0644)
|
||||||
|
|
||||||
node, err := zerotier.NewNode(basePath)
|
node, err := zerotier.NewNode(basePath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Println("FATAL: error initializing node: " + err.Error())
|
fmt.Println("FATAL: error initializing node: " + err.Error())
|
||||||
os.Exit(1)
|
} else {
|
||||||
}
|
|
||||||
|
|
||||||
osSignalChannel := make(chan os.Signal, 2)
|
osSignalChannel := make(chan os.Signal, 2)
|
||||||
signal.Notify(osSignalChannel, syscall.SIGTERM, syscall.SIGQUIT, syscall.SIGINT, syscall.SIGBUS)
|
signal.Notify(osSignalChannel, syscall.SIGTERM, syscall.SIGQUIT, syscall.SIGINT, syscall.SIGSTOP)
|
||||||
signal.Ignore(syscall.SIGUSR1, syscall.SIGUSR2)
|
signal.Ignore(syscall.SIGUSR1, syscall.SIGUSR2, syscall.SIGPIPE, syscall.SIGHUP)
|
||||||
<-osSignalChannel
|
<-osSignalChannel
|
||||||
node.Close()
|
node.Close()
|
||||||
os.Exit(0)
|
}
|
||||||
|
|
||||||
|
_ = os.Remove(pidPath)
|
||||||
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
|
|
44
core/Blob.hpp
Normal file
44
core/Blob.hpp
Normal file
|
@ -0,0 +1,44 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c)2013-2020 ZeroTier, Inc.
|
||||||
|
*
|
||||||
|
* Use of this software is governed by the Business Source License included
|
||||||
|
* in the LICENSE.TXT file in the project's root directory.
|
||||||
|
*
|
||||||
|
* Change Date: 2024-01-01
|
||||||
|
*
|
||||||
|
* On the date above, in accordance with the Business Source License, use
|
||||||
|
* of this software will be governed by version 2.0 of the Apache License.
|
||||||
|
*/
|
||||||
|
/****/
|
||||||
|
|
||||||
|
#ifndef ZT_BLOB_HPP
|
||||||
|
#define ZT_BLOB_HPP
|
||||||
|
|
||||||
|
#include "Constants.hpp"
|
||||||
|
#include "Utils.hpp"
|
||||||
|
|
||||||
|
namespace ZeroTier {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Container for arbitrary bytes for use in collections
|
||||||
|
*
|
||||||
|
* @tparam S Size of container in bytes
|
||||||
|
*/
|
||||||
|
template<unsigned int S>
|
||||||
|
struct Blob
|
||||||
|
{
|
||||||
|
uint8_t data[S];
|
||||||
|
|
||||||
|
ZT_INLINE Blob() { Utils::zero<S>(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); }
|
||||||
|
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); }
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace ZeroTier
|
||||||
|
|
||||||
|
#endif
|
|
@ -9,6 +9,7 @@ configure_file(
|
||||||
set(core_headers
|
set(core_headers
|
||||||
zerotier.h
|
zerotier.h
|
||||||
Address.hpp
|
Address.hpp
|
||||||
|
Blob.hpp
|
||||||
Buf.hpp
|
Buf.hpp
|
||||||
C25519.hpp
|
C25519.hpp
|
||||||
Capability.hpp
|
Capability.hpp
|
||||||
|
@ -24,6 +25,7 @@ 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
|
||||||
|
@ -67,6 +69,7 @@ set(core_src
|
||||||
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
|
||||||
|
|
|
@ -12,24 +12,32 @@
|
||||||
/****/
|
/****/
|
||||||
|
|
||||||
#include "Dictionary.hpp"
|
#include "Dictionary.hpp"
|
||||||
#include "SHA512.hpp"
|
|
||||||
|
|
||||||
namespace ZeroTier {
|
namespace ZeroTier {
|
||||||
|
|
||||||
Dictionary::Dictionary()
|
Dictionary::Dictionary()
|
||||||
{
|
{}
|
||||||
}
|
|
||||||
|
Dictionary::~Dictionary()
|
||||||
|
{}
|
||||||
|
|
||||||
Vector< uint8_t > &Dictionary::operator[](const char *k)
|
Vector< uint8_t > &Dictionary::operator[](const char *k)
|
||||||
{
|
{
|
||||||
|
if (k)
|
||||||
return m_entries[s_key(k)];
|
return m_entries[s_key(k)];
|
||||||
|
else return m_entries[""];
|
||||||
}
|
}
|
||||||
|
|
||||||
const Vector< uint8_t > &Dictionary::operator[](const char *k) const
|
const Vector< uint8_t > &Dictionary::operator[](const char *k) const
|
||||||
{
|
{
|
||||||
static const Vector< uint8_t > s_emptyEntry;
|
static const Vector< uint8_t > s_emptyEntry;
|
||||||
|
if (k) {
|
||||||
SortedMap< String, Vector< uint8_t > >::const_iterator e(m_entries.find(s_key(k)));
|
SortedMap< String, Vector< uint8_t > >::const_iterator e(m_entries.find(s_key(k)));
|
||||||
return (e == m_entries.end()) ? s_emptyEntry : e->second;
|
return (e == m_entries.end()) ? s_emptyEntry : e->second;
|
||||||
|
} else {
|
||||||
|
SortedMap< String, Vector< uint8_t > >::const_iterator e(m_entries.find(""));
|
||||||
|
return (e == m_entries.end()) ? s_emptyEntry : e->second;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Dictionary::add(const char *k, bool v)
|
void Dictionary::add(const char *k, bool v)
|
||||||
|
@ -124,17 +132,15 @@ void Dictionary::clear()
|
||||||
m_entries.clear();
|
m_entries.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Dictionary::encode(Vector<uint8_t> &out, const bool omitSignatureFields) const
|
void Dictionary::encode(Vector< uint8_t > &out) const
|
||||||
{
|
{
|
||||||
out.clear();
|
out.clear();
|
||||||
for (SortedMap< String, Vector< uint8_t > >::const_iterator ti(m_entries.begin()); ti != m_entries.end(); ++ti) {
|
for (SortedMap< String, Vector< uint8_t > >::const_iterator ti(m_entries.begin()); ti != m_entries.end(); ++ti) {
|
||||||
if ((!omitSignatureFields) || ((ti->first != ZT_DICTIONARY_SIGNATURE_KEY))) {
|
|
||||||
s_appendKey(out, ti->first.data());
|
s_appendKey(out, ti->first.data());
|
||||||
for (Vector< uint8_t >::const_iterator i(ti->second.begin()); i != ti->second.end(); ++i)
|
for (Vector< uint8_t >::const_iterator i(ti->second.begin()); i != ti->second.end(); ++i)
|
||||||
s_appendValueByte(out, *i);
|
s_appendValueByte(out, *i);
|
||||||
out.push_back((uint8_t)'\n');
|
out.push_back((uint8_t)'\n');
|
||||||
}
|
}
|
||||||
}
|
|
||||||
out.push_back(0);
|
out.push_back(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -193,59 +199,4 @@ bool Dictionary::decode(const void *data, unsigned int len)
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Dictionary::sign(
|
|
||||||
const uint8_t c25519PrivateKey[ZT_C25519_COMBINED_PRIVATE_KEY_SIZE],
|
|
||||||
const uint8_t c25519PublicKey[ZT_C25519_COMBINED_PUBLIC_KEY_SIZE],
|
|
||||||
const uint8_t p384PrivateKey[ZT_ECC384_PRIVATE_KEY_SIZE],
|
|
||||||
const uint8_t p384PublicKey[ZT_ECC384_PUBLIC_KEY_SIZE])
|
|
||||||
{
|
|
||||||
Vector<uint8_t> buf;
|
|
||||||
encode(buf, true);
|
|
||||||
|
|
||||||
uint8_t c25519Signature[ZT_C25519_SIGNATURE_LEN];
|
|
||||||
C25519::sign(c25519PrivateKey, c25519PublicKey, buf.data(), (unsigned int)buf.size(), c25519Signature);
|
|
||||||
|
|
||||||
uint8_t hbuf[ZT_ECC384_SIGNATURE_HASH_SIZE];
|
|
||||||
static_assert(ZT_ECC384_SIGNATURE_HASH_SIZE == ZT_SHA384_DIGEST_SIZE,"size mismatch");
|
|
||||||
SHA384(hbuf, buf.data(), (unsigned int)buf.size());
|
|
||||||
uint8_t p384Signature[ZT_ECC384_SIGNATURE_SIZE];
|
|
||||||
ECC384ECDSASign(p384PrivateKey, hbuf, p384Signature);
|
|
||||||
|
|
||||||
SHA384(hbuf, c25519PublicKey, ZT_C25519_COMBINED_PUBLIC_KEY_SIZE, p384PublicKey, ZT_ECC384_PUBLIC_KEY_SIZE);
|
|
||||||
|
|
||||||
Dictionary signature;
|
|
||||||
signature["kh"].assign(hbuf, hbuf + ZT_SHA384_DIGEST_SIZE);
|
|
||||||
signature["ed25519"].assign(c25519Signature, c25519Signature + ZT_C25519_SIGNATURE_LEN);
|
|
||||||
signature["p384"].assign(p384Signature, p384Signature + ZT_ECC384_SIGNATURE_SIZE);
|
|
||||||
signature.encode((*this)[ZT_DICTIONARY_SIGNATURE_KEY], true);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Dictionary::verify(
|
|
||||||
const uint8_t c25519PublicKey[ZT_C25519_COMBINED_PUBLIC_KEY_SIZE],
|
|
||||||
const uint8_t p384PublicKey[ZT_ECC384_PUBLIC_KEY_SIZE]) const
|
|
||||||
{
|
|
||||||
try {
|
|
||||||
const Vector< uint8_t > &data = (*this)[ZT_DICTIONARY_SIGNATURE_KEY];
|
|
||||||
if (data.empty())
|
|
||||||
return false;
|
|
||||||
Dictionary signature;
|
|
||||||
if (!signature.decode(data.data(), (unsigned int)data.size()))
|
|
||||||
return false;
|
|
||||||
const Vector< uint8_t > &p384Signature = signature["p384"];
|
|
||||||
const Vector< uint8_t > &c25519Signature = signature["ed25519"];
|
|
||||||
if ((p384Signature.size() != ZT_ECC384_SIGNATURE_SIZE) || (c25519Signature.size() != ZT_C25519_SIGNATURE_LEN))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
Vector< uint8_t > buf;
|
|
||||||
encode(buf, true);
|
|
||||||
|
|
||||||
if (C25519::verify(c25519PublicKey, buf.data(), (unsigned int)buf.size(), c25519Signature.data(), (unsigned int)c25519Signature.size())) {
|
|
||||||
uint8_t hbuf[ZT_ECC384_SIGNATURE_HASH_SIZE];
|
|
||||||
SHA384(hbuf, buf.data(), (unsigned int)buf.size());
|
|
||||||
return ECC384ECDSAVerify(p384PublicKey, hbuf, p384Signature.data());
|
|
||||||
}
|
|
||||||
} catch ( ... ) {}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace ZeroTier
|
} // namespace ZeroTier
|
||||||
|
|
|
@ -19,10 +19,6 @@
|
||||||
#include "Address.hpp"
|
#include "Address.hpp"
|
||||||
#include "Buf.hpp"
|
#include "Buf.hpp"
|
||||||
#include "Containers.hpp"
|
#include "Containers.hpp"
|
||||||
#include "C25519.hpp"
|
|
||||||
#include "ECC384.hpp"
|
|
||||||
|
|
||||||
#define ZT_DICTIONARY_SIGNATURE_KEY "@S"
|
|
||||||
|
|
||||||
namespace ZeroTier {
|
namespace ZeroTier {
|
||||||
|
|
||||||
|
@ -46,10 +42,10 @@ class Identity;
|
||||||
class Dictionary
|
class Dictionary
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
typedef SortedMap< String, Vector < uint8_t > >
|
typedef SortedMap< String, Vector < uint8_t > >::const_iterator const_iterator;
|
||||||
::const_iterator const_iterator;
|
|
||||||
|
|
||||||
Dictionary();
|
Dictionary();
|
||||||
|
~Dictionary();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get a reference to a value
|
* Get a reference to a value
|
||||||
|
@ -90,12 +86,17 @@ public:
|
||||||
* @param k Key to set
|
* @param k Key to set
|
||||||
* @param v Integer to set, will be cast to uint64_t and stored as hex
|
* @param v Integer to set, will be cast to uint64_t and stored as hex
|
||||||
*/
|
*/
|
||||||
template< typename I >
|
ZT_INLINE void add(const char *const k, const uint64_t v)
|
||||||
ZT_INLINE void add(const char *const k, I v)
|
{ char buf[17]; add(k, Utils::hex((uint64_t)(v), buf)); }
|
||||||
{
|
|
||||||
char buf[17];
|
/**
|
||||||
add(k, Utils::hex((uint64_t)(v), buf));
|
* Add an integer as a hexadecimal string value
|
||||||
}
|
*
|
||||||
|
* @param k Key to set
|
||||||
|
* @param v Integer to set, will be cast to uint64_t and stored as hex
|
||||||
|
*/
|
||||||
|
ZT_INLINE void add(const char *const k, const int64_t v)
|
||||||
|
{ char buf[17]; add(k, Utils::hex((uint64_t)(v), buf)); }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Add an address in 10-digit hex string format
|
* Add an address in 10-digit hex string format
|
||||||
|
@ -145,6 +146,7 @@ public:
|
||||||
/**
|
/**
|
||||||
* Get an object supporting the marshal/unmarshal interface pattern
|
* Get an object supporting the marshal/unmarshal interface pattern
|
||||||
*
|
*
|
||||||
|
* @tparam T Object type (inferred)
|
||||||
* @param k Key to look up
|
* @param k Key to look up
|
||||||
* @param obj Object to unmarshal() into
|
* @param obj Object to unmarshal() into
|
||||||
* @return True if unmarshal was successful
|
* @return True if unmarshal was successful
|
||||||
|
@ -158,6 +160,27 @@ public:
|
||||||
return (obj.unmarshal(d.data(), (unsigned int)d.size()) > 0);
|
return (obj.unmarshal(d.data(), (unsigned int)d.size()) > 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add an object supporting the marshal/unmarshal interface pattern
|
||||||
|
*
|
||||||
|
* @tparam T Object type (inferred)
|
||||||
|
* @param k Key to add
|
||||||
|
* @param obj Object to marshal() into vector
|
||||||
|
* @return True if successful
|
||||||
|
*/
|
||||||
|
template< typename T >
|
||||||
|
ZT_INLINE bool addO(const char *k, T &obj)
|
||||||
|
{
|
||||||
|
uint8_t tmp[4096];
|
||||||
|
static_assert(sizeof(tmp) >= T::marshalSizeMax(),"buffer too small");
|
||||||
|
int l = obj.marshal(tmp);
|
||||||
|
if (l > 0) {
|
||||||
|
(*this)[k].assign(tmp, tmp + l);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Erase all entries in dictionary
|
* Erase all entries in dictionary
|
||||||
*/
|
*/
|
||||||
|
@ -179,9 +202,8 @@ public:
|
||||||
* Encode to a string in the supplied vector
|
* Encode to a string in the supplied vector
|
||||||
*
|
*
|
||||||
* @param out String encoded dictionary
|
* @param out String encoded dictionary
|
||||||
* @param omitSignatureFields If true omit the signature fields from encoding (default: false)
|
|
||||||
*/
|
*/
|
||||||
void encode(Vector <uint8_t> &out, bool omitSignatureFields = false) const;
|
void encode(Vector <uint8_t> &out) const;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Decode a string encoded dictionary
|
* Decode a string encoded dictionary
|
||||||
|
@ -195,34 +217,6 @@ public:
|
||||||
*/
|
*/
|
||||||
bool decode(const void *data, unsigned int len);
|
bool decode(const void *data, unsigned int len);
|
||||||
|
|
||||||
/**
|
|
||||||
* Sign this dictionary with both an Ed25519 key and a NIST P-384 key.
|
|
||||||
*
|
|
||||||
* This is currently used just for signing root sets for the root subscribe
|
|
||||||
* feature. It uses both key types for more crypto cowbell.
|
|
||||||
*
|
|
||||||
* @param c25519PrivateKey Curve25519 combined key (C25519 and ed25519), though only ed25519 part is used
|
|
||||||
* @param c25519PublicKey Public part of Curve25519 combined key
|
|
||||||
* @param p384PrivateKey NIST P-384 private key
|
|
||||||
* @param p384PublicKey NIST P-384 public key
|
|
||||||
*/
|
|
||||||
void sign(
|
|
||||||
const uint8_t c25519PrivateKey[ZT_C25519_COMBINED_PRIVATE_KEY_SIZE],
|
|
||||||
const uint8_t c25519PublicKey[ZT_C25519_COMBINED_PUBLIC_KEY_SIZE],
|
|
||||||
const uint8_t p384PrivateKey[ZT_ECC384_PRIVATE_KEY_SIZE],
|
|
||||||
const uint8_t p384PublicKey[ZT_ECC384_PUBLIC_KEY_SIZE]);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Verify this dictionary's signature
|
|
||||||
*
|
|
||||||
* @param c25519PublicKey Curve25519 public key
|
|
||||||
* @param p384PublicKey P-384 public key
|
|
||||||
* @return True if signatures are valid
|
|
||||||
*/
|
|
||||||
bool verify(
|
|
||||||
const uint8_t c25519PublicKey[ZT_C25519_COMBINED_PUBLIC_KEY_SIZE],
|
|
||||||
const uint8_t p384PublicKey[ZT_ECC384_PUBLIC_KEY_SIZE]) const;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Append a key=value pair to a buffer (vector or FCV)
|
* Append a key=value pair to a buffer (vector or FCV)
|
||||||
*
|
*
|
||||||
|
@ -376,6 +370,19 @@ public:
|
||||||
return mlen;
|
return mlen;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static ZT_INLINE char *arraySubscript(char buf[256],const char *name,const unsigned long sub) noexcept
|
||||||
|
{
|
||||||
|
for(unsigned int i=0;i<(256 - 17);++i) {
|
||||||
|
if ((buf[i] = name[i]) == 0) {
|
||||||
|
buf[i++] = '#';
|
||||||
|
Utils::hex(sub, buf + i);
|
||||||
|
return buf;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
buf[0] = 0;
|
||||||
|
return buf;
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
template< typename V >
|
template< typename V >
|
||||||
ZT_INLINE static void s_appendValueByte(V &out, const uint8_t c)
|
ZT_INLINE static void s_appendValueByte(V &out, const uint8_t c)
|
||||||
|
|
260
core/IdentificationCertificate.cpp
Normal file
260
core/IdentificationCertificate.cpp
Normal file
|
@ -0,0 +1,260 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c)2013-2020 ZeroTier, Inc.
|
||||||
|
*
|
||||||
|
* Use of this software is governed by the Business Source License included
|
||||||
|
* in the LICENSE.TXT file in the project's root directory.
|
||||||
|
*
|
||||||
|
* Change Date: 2024-01-01
|
||||||
|
*
|
||||||
|
* On the date above, in accordance with the Business Source License, use
|
||||||
|
* of this software will be governed by version 2.0 of the Apache License.
|
||||||
|
*/
|
||||||
|
/****/
|
||||||
|
|
||||||
|
#include "IdentificationCertificate.hpp"
|
||||||
|
#include "SHA512.hpp"
|
||||||
|
|
||||||
|
namespace ZeroTier {
|
||||||
|
|
||||||
|
IdentificationCertificate &IdentificationCertificate::operator=(const ZT_IdentificationCertificate &apiCert)
|
||||||
|
{
|
||||||
|
Utils::copy< sizeof(ZT_IdentificationCertificate) >((ZT_IdentificationCertificate *)this, &apiCert);
|
||||||
|
m_identities.clear();
|
||||||
|
m_locators.clear();
|
||||||
|
m_nodes.clear();
|
||||||
|
m_networks.clear();
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
IdentificationCertificate &IdentificationCertificate::operator=(const IdentificationCertificate &cert)
|
||||||
|
{
|
||||||
|
Utils::copy< sizeof(ZT_IdentificationCertificate) >((ZT_IdentificationCertificate *)this, (const ZT_IdentificationCertificate *)(&cert));
|
||||||
|
|
||||||
|
m_identities.clear();
|
||||||
|
m_locators.clear();
|
||||||
|
m_nodes.clear();
|
||||||
|
m_networks.clear();
|
||||||
|
|
||||||
|
this->subject.nodeCount = 0;
|
||||||
|
this->subject.networkCount = 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.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)
|
||||||
|
addSubjectNetwork(cert.subject.networks[i].id, cert.subject.networks[i].controller);
|
||||||
|
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
ZT_IdentificationCertificate_Node *IdentificationCertificate::addSubjectNode(const Identity &id)
|
||||||
|
{
|
||||||
|
m_nodes.resize(++this->subject.nodeCount);
|
||||||
|
this->subject.nodes = m_nodes.data();
|
||||||
|
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());
|
||||||
|
}
|
||||||
|
|
||||||
|
ZT_IdentificationCertificate_Node *IdentificationCertificate::addSubjectNode(const Identity &id, const Locator &loc)
|
||||||
|
{
|
||||||
|
ZT_IdentificationCertificate_Node *n = addSubjectNode(id);
|
||||||
|
m_locators.push_back(loc);
|
||||||
|
n->locator = reinterpret_cast<ZT_Locator *>(&(m_locators.back()));
|
||||||
|
return n;
|
||||||
|
}
|
||||||
|
|
||||||
|
ZT_IdentificationCertificate_Network *IdentificationCertificate::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());
|
||||||
|
}
|
||||||
|
|
||||||
|
Vector< uint8_t > IdentificationCertificate::encode(const bool omitSignature) const
|
||||||
|
{
|
||||||
|
char tmp[256];
|
||||||
|
Vector< uint8_t > enc;
|
||||||
|
Dictionary d;
|
||||||
|
|
||||||
|
d.add("v", (uint64_t)this->version);
|
||||||
|
d.add("mP", (uint64_t)this->maxPathLength);
|
||||||
|
d.add("f", this->flags);
|
||||||
|
d.add("v0", this->validity[0]);
|
||||||
|
d.add("v1", this->validity[1]);
|
||||||
|
|
||||||
|
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.nw[]", (uint64_t)this->subject.networkCount);
|
||||||
|
for (unsigned int i = 0; i < this->subject.networkCount; ++i) {
|
||||||
|
d.add(Dictionary::arraySubscript(tmp, "s.nw[].i", i), this->subject.networks[i].id);
|
||||||
|
Fingerprint fp(this->subject.networks[i].controller);
|
||||||
|
d.addO(Dictionary::arraySubscript(tmp, "s.nw[].c", i), fp);
|
||||||
|
}
|
||||||
|
|
||||||
|
d.add("s.n.c", this->subject.name.country);
|
||||||
|
d.add("s.n.o", this->subject.name.organization);
|
||||||
|
d.add("s.n.u", this->subject.name.unit);
|
||||||
|
d.add("s.n.l", this->subject.name.locality);
|
||||||
|
d.add("s.n.p", this->subject.name.province);
|
||||||
|
d.add("s.n.sA", this->subject.name.streetAddress);
|
||||||
|
d.add("s.n.pC", this->subject.name.postalCode);
|
||||||
|
d.add("s.n.cN", this->subject.name.commonName);
|
||||||
|
d.add("s.n.sN", this->subject.name.serialNo);
|
||||||
|
d.add("s.n.e", this->subject.name.email);
|
||||||
|
d.add("s.n.ur", this->subject.name.url);
|
||||||
|
|
||||||
|
if (this->issuer)
|
||||||
|
d.addO("i", *reinterpret_cast<const Identity *>(this->issuer));
|
||||||
|
|
||||||
|
d.add("iN.c", this->issuerName.country);
|
||||||
|
d.add("iN.o", this->issuerName.organization);
|
||||||
|
d.add("iN.u", this->issuerName.unit);
|
||||||
|
d.add("iN.l", this->issuerName.locality);
|
||||||
|
d.add("iN.p", this->issuerName.province);
|
||||||
|
d.add("iN.sA", this->issuerName.streetAddress);
|
||||||
|
d.add("iN.pC", this->issuerName.postalCode);
|
||||||
|
d.add("iN.cN", this->issuerName.commonName);
|
||||||
|
d.add("iN.sN", this->issuerName.serialNo);
|
||||||
|
d.add("iN.e", this->issuerName.email);
|
||||||
|
d.add("iN.ur", this->issuerName.url);
|
||||||
|
|
||||||
|
if ((!omitSignature) && (this->signatureSize > 0) && (this->signatureSize <= sizeof(this->signature)))
|
||||||
|
d["si"].assign(this->signature, this->signature + this->signatureSize);
|
||||||
|
|
||||||
|
d.encode(enc);
|
||||||
|
return enc;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool IdentificationCertificate::decode(const Vector< uint8_t > &data)
|
||||||
|
{
|
||||||
|
char tmp[256];
|
||||||
|
|
||||||
|
Utils::zero< sizeof(ZT_IdentificationCertificate) >((ZT_IdentificationCertificate *)this);
|
||||||
|
m_identities.clear();
|
||||||
|
m_locators.clear();
|
||||||
|
m_nodes.clear();
|
||||||
|
m_networks.clear();
|
||||||
|
|
||||||
|
Dictionary d;
|
||||||
|
if (!d.decode(data.data(), (unsigned int)data.size()))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
this->version = (unsigned int)d.getUI("v");
|
||||||
|
this->maxPathLength = (unsigned int)d.getUI("mP");
|
||||||
|
this->flags = d.getUI("f");
|
||||||
|
this->validity[0] = (int64_t)d.getUI("v0");
|
||||||
|
this->validity[1] = (int64_t)d.getUI("v1");
|
||||||
|
|
||||||
|
unsigned int cnt = (unsigned int)d.getUI("s.n[]");
|
||||||
|
for (unsigned int i = 0; i < cnt; ++i) {
|
||||||
|
const Vector< uint8_t > &identityData = d[Dictionary::arraySubscript(tmp, "s.n[].i", i)];
|
||||||
|
if (identityData.empty())
|
||||||
|
return false;
|
||||||
|
Identity id;
|
||||||
|
if (id.unmarshal(identityData.data(), (unsigned int)identityData.size()) <= 0)
|
||||||
|
return false;
|
||||||
|
const Vector< uint8_t > &locatorData = d[Dictionary::arraySubscript(tmp, "s.n[].l", i)];
|
||||||
|
if (!locatorData.empty()) {
|
||||||
|
Locator loc;
|
||||||
|
if (loc.unmarshal(locatorData.data(), (unsigned int)locatorData.size()) <= 0)
|
||||||
|
return false;
|
||||||
|
this->addSubjectNode(id, loc);
|
||||||
|
} else {
|
||||||
|
this->addSubjectNode(id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
cnt = (unsigned int)d.getUI("s.nw[]");
|
||||||
|
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())
|
||||||
|
return false;
|
||||||
|
Fingerprint fp;
|
||||||
|
if (fp.unmarshal(fingerprintData.data(), (unsigned int)fingerprintData.size()) <= 0)
|
||||||
|
return false;
|
||||||
|
this->addSubjectNetwork(nwid, fp);
|
||||||
|
}
|
||||||
|
|
||||||
|
d.getS("s.n.c", this->subject.name.country, sizeof(this->subject.name.country));
|
||||||
|
d.getS("s.n.o", this->subject.name.organization, sizeof(this->subject.name.organization));
|
||||||
|
d.getS("s.n.u", this->subject.name.unit, sizeof(this->subject.name.unit));
|
||||||
|
d.getS("s.n.l", this->subject.name.locality, sizeof(this->subject.name.locality));
|
||||||
|
d.getS("s.n.p", this->subject.name.province, sizeof(this->subject.name.province));
|
||||||
|
d.getS("s.n.sA", this->subject.name.streetAddress, sizeof(this->subject.name.streetAddress));
|
||||||
|
d.getS("s.n.pC", this->subject.name.postalCode, sizeof(this->subject.name.postalCode));
|
||||||
|
d.getS("s.n.cN", this->subject.name.commonName, sizeof(this->subject.name.commonName));
|
||||||
|
d.getS("s.n.sN", this->subject.name.serialNo, sizeof(this->subject.name.serialNo));
|
||||||
|
d.getS("s.n.e", this->subject.name.email, sizeof(this->subject.name.email));
|
||||||
|
d.getS("s.n.ur", this->subject.name.url, sizeof(this->subject.name.url));
|
||||||
|
|
||||||
|
const Vector< uint8_t > &issuerData = d["i"];
|
||||||
|
if (!issuerData.empty()) {
|
||||||
|
Identity id;
|
||||||
|
if (id.unmarshal(issuerData.data(), (int)issuerData.size()) > 0) {
|
||||||
|
m_identities.push_back(id);
|
||||||
|
this->issuer = reinterpret_cast<const Identity *>(&(m_identities.back()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
d.getS("iN.c", this->issuerName.country, sizeof(this->issuerName.country));
|
||||||
|
d.getS("iN.o", this->issuerName.organization, sizeof(this->issuerName.organization));
|
||||||
|
d.getS("iN.u", this->issuerName.unit, sizeof(this->issuerName.unit));
|
||||||
|
d.getS("iN.l", this->issuerName.locality, sizeof(this->issuerName.locality));
|
||||||
|
d.getS("iN.p", this->issuerName.province, sizeof(this->issuerName.province));
|
||||||
|
d.getS("iN.sA", this->issuerName.streetAddress, sizeof(this->issuerName.streetAddress));
|
||||||
|
d.getS("iN.pC", this->issuerName.postalCode, sizeof(this->issuerName.postalCode));
|
||||||
|
d.getS("iN.cN", this->issuerName.commonName, sizeof(this->issuerName.commonName));
|
||||||
|
d.getS("iN.sN", this->issuerName.serialNo, sizeof(this->issuerName.serialNo));
|
||||||
|
d.getS("iN.e", this->issuerName.email, sizeof(this->issuerName.email));
|
||||||
|
d.getS("iN.ur", this->issuerName.url, sizeof(this->issuerName.url));
|
||||||
|
|
||||||
|
const Vector< uint8_t > &sig = d["si"];
|
||||||
|
if (sig.size() > sizeof(this->signature))
|
||||||
|
return false;
|
||||||
|
Utils::copy(this->signature, sig.data(), (unsigned int)sig.size());
|
||||||
|
this->signatureSize = (unsigned int)sig.size();
|
||||||
|
|
||||||
|
Vector< uint8_t > enc(encode(true));
|
||||||
|
SHA384(this->serialNo, enc.data(), (unsigned int)enc.size());
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool IdentificationCertificate::sign(const Identity &issuer)
|
||||||
|
{
|
||||||
|
Vector< uint8_t > enc(encode(true));
|
||||||
|
SHA384(this->serialNo, enc.data(), (unsigned int)enc.size());
|
||||||
|
return (this->signatureSize = issuer.sign(enc.data(), (unsigned int)enc.size(), this->signature, sizeof(this->signature))) > 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool IdentificationCertificate::verify() const
|
||||||
|
{
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace ZeroTier
|
135
core/IdentificationCertificate.hpp
Normal file
135
core/IdentificationCertificate.hpp
Normal file
|
@ -0,0 +1,135 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c)2013-2020 ZeroTier, Inc.
|
||||||
|
*
|
||||||
|
* Use of this software is governed by the Business Source License included
|
||||||
|
* in the LICENSE.TXT file in the project's root directory.
|
||||||
|
*
|
||||||
|
* Change Date: 2024-01-01
|
||||||
|
*
|
||||||
|
* On the date above, in accordance with the Business Source License, use
|
||||||
|
* of this software will be governed by version 2.0 of the Apache License.
|
||||||
|
*/
|
||||||
|
/****/
|
||||||
|
|
||||||
|
#ifndef ZT_IDENTIFICATIONCERTIFICATE_HPP
|
||||||
|
#define ZT_IDENTIFICATIONCERTIFICATE_HPP
|
||||||
|
|
||||||
|
#include "Constants.hpp"
|
||||||
|
#include "SHA512.hpp"
|
||||||
|
#include "C25519.hpp"
|
||||||
|
#include "ECC384.hpp"
|
||||||
|
#include "SharedPtr.hpp"
|
||||||
|
#include "Identity.hpp"
|
||||||
|
#include "Locator.hpp"
|
||||||
|
#include "Dictionary.hpp"
|
||||||
|
#include "Utils.hpp"
|
||||||
|
#include "Containers.hpp"
|
||||||
|
|
||||||
|
namespace ZeroTier {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Certificate identifying the real world owner of an identity or network.
|
||||||
|
*
|
||||||
|
* This is a wrapper around the straight C ZT_IdentificationCertificate and
|
||||||
|
* handles allocating memory for objects and disposing of it on GC. If filling
|
||||||
|
* out a ZT_IdentificationCertificate structure, identities and other objects
|
||||||
|
* should be attached via the addXXX() methods rather than by directly setting
|
||||||
|
* the pointers in the C structure.
|
||||||
|
*
|
||||||
|
* If identities and similar objects are NOT added via the addXXX() methods,
|
||||||
|
* this will not take care of de-allocating them when destroyed.
|
||||||
|
*
|
||||||
|
* The serialNo field is filled in automatically by sign() and decode(), so
|
||||||
|
* it can be left undefined when building certificates.
|
||||||
|
*/
|
||||||
|
class IdentificationCertificate : public ZT_IdentificationCertificate
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
ZT_INLINE IdentificationCertificate() noexcept
|
||||||
|
{ Utils::zero< sizeof(ZT_IdentificationCertificate) >((ZT_IdentificationCertificate *)this); }
|
||||||
|
|
||||||
|
ZT_INLINE IdentificationCertificate(const ZT_IdentificationCertificate &apiCert)
|
||||||
|
{ Utils::copy< sizeof(ZT_IdentificationCertificate) >((ZT_IdentificationCertificate *)this, &apiCert); }
|
||||||
|
|
||||||
|
ZT_INLINE IdentificationCertificate(const IdentificationCertificate &cert)
|
||||||
|
{ *this = cert; }
|
||||||
|
|
||||||
|
IdentificationCertificate &operator=(const ZT_IdentificationCertificate &apiCert);
|
||||||
|
|
||||||
|
IdentificationCertificate &operator=(const IdentificationCertificate &cert);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add a subject node/identity without a locator
|
||||||
|
*
|
||||||
|
* @param id Identity
|
||||||
|
* @return Pointer to C struct
|
||||||
|
*/
|
||||||
|
ZT_IdentificationCertificate_Node *addSubjectNode(const Identity &id);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add a subject node/identity with a locator
|
||||||
|
*
|
||||||
|
* @param id Identity
|
||||||
|
* @param loc Locator signed by identity (signature is NOT checked here)
|
||||||
|
* @return Pointer to C struct
|
||||||
|
*/
|
||||||
|
ZT_IdentificationCertificate_Node *addSubjectNode(const Identity &id, const Locator &loc);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add a subject network
|
||||||
|
*
|
||||||
|
* @param id Network ID
|
||||||
|
* @param controller Network controller's full fingerprint
|
||||||
|
* @return Pointer to C struct
|
||||||
|
*/
|
||||||
|
ZT_IdentificationCertificate_Network *addSubjectNetwork(const uint64_t id, const ZT_Fingerprint &controller);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Marshal this certificate in binary form
|
||||||
|
*
|
||||||
|
* The internal encoding used here is Dictionary to permit easy
|
||||||
|
* extensibility.
|
||||||
|
*
|
||||||
|
* @param omitSignature If true omit the signature field (for signing and verification, default is false)
|
||||||
|
* @return Marshaled certificate
|
||||||
|
*/
|
||||||
|
Vector< uint8_t > encode(bool omitSignature = false) const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Decode this certificate from marshaled bytes.
|
||||||
|
*
|
||||||
|
* @param data Marshalled certificate
|
||||||
|
* @return True if input is valid and was unmarshalled (signature is NOT checked)
|
||||||
|
*/
|
||||||
|
bool decode(const Vector< uint8_t > &data);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sign this certificate (and also fill in serialNo).
|
||||||
|
*
|
||||||
|
* @param issuer Issuer identity (must have secret key)
|
||||||
|
* @return True on success
|
||||||
|
*/
|
||||||
|
bool sign(const Identity &issuer);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Verify certificate signature against the issuer contained therein
|
||||||
|
*
|
||||||
|
* @return True if certificate is signed and signature is valid
|
||||||
|
*/
|
||||||
|
bool verify() const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
// These hold any identity or locator objects that are owned by and should
|
||||||
|
// be deleted with this certificate. Lists are used so the pointers never
|
||||||
|
// change.
|
||||||
|
List< Identity > m_identities;
|
||||||
|
List< Locator > m_locators;
|
||||||
|
|
||||||
|
// 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;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace ZeroTier
|
||||||
|
|
||||||
|
#endif
|
|
@ -91,12 +91,14 @@ public:
|
||||||
/**
|
/**
|
||||||
* Set identity to NIL value (all zero)
|
* Set identity to NIL value (all zero)
|
||||||
*/
|
*/
|
||||||
ZT_INLINE void zero() noexcept { memoryZero(this); }
|
ZT_INLINE void zero() noexcept
|
||||||
|
{ memoryZero(this); }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return Identity type (undefined if identity is null or invalid)
|
* @return Identity type (undefined if identity is null or invalid)
|
||||||
*/
|
*/
|
||||||
ZT_INLINE Type type() const noexcept { return m_type; }
|
ZT_INLINE Type type() const noexcept
|
||||||
|
{ return m_type; }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Generate a new identity (address, key pair)
|
* Generate a new identity (address, key pair)
|
||||||
|
@ -122,17 +124,20 @@ public:
|
||||||
/**
|
/**
|
||||||
* @return True if this identity contains a private key
|
* @return True if this identity contains a private key
|
||||||
*/
|
*/
|
||||||
ZT_INLINE bool hasPrivate() const noexcept { return m_hasPrivate; }
|
ZT_INLINE bool hasPrivate() const noexcept
|
||||||
|
{ return m_hasPrivate; }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return This identity's address
|
* @return This identity's address
|
||||||
*/
|
*/
|
||||||
ZT_INLINE Address address() const noexcept { return Address(m_fp.address); }
|
ZT_INLINE Address address() const noexcept
|
||||||
|
{ return Address(m_fp.address); }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return Full fingerprint of this identity (address plus SHA384 of keys)
|
* @return Full fingerprint of this identity (address plus SHA384 of keys)
|
||||||
*/
|
*/
|
||||||
ZT_INLINE const Fingerprint &fingerprint() const noexcept { return m_fp; }
|
ZT_INLINE const Fingerprint &fingerprint() const noexcept
|
||||||
|
{ return m_fp; }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Compute a hash of this identity's public and private keys.
|
* Compute a hash of this identity's public and private keys.
|
||||||
|
@ -187,7 +192,13 @@ public:
|
||||||
* @return ASCII string representation of identity (pointer to buf)
|
* @return ASCII string representation of identity (pointer to buf)
|
||||||
*/
|
*/
|
||||||
char *toString(bool includePrivate, char buf[ZT_IDENTITY_STRING_BUFFER_LENGTH]) const;
|
char *toString(bool includePrivate, char buf[ZT_IDENTITY_STRING_BUFFER_LENGTH]) const;
|
||||||
ZT_INLINE String toString(const bool includePrivate = false) const { char buf[ZT_IDENTITY_STRING_BUFFER_LENGTH]; toString(includePrivate,buf); return String(buf); }
|
|
||||||
|
ZT_INLINE String toString(const bool includePrivate = false) const
|
||||||
|
{
|
||||||
|
char buf[ZT_IDENTITY_STRING_BUFFER_LENGTH];
|
||||||
|
toString(includePrivate, buf);
|
||||||
|
return String(buf);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Deserialize a human-friendly string
|
* Deserialize a human-friendly string
|
||||||
|
@ -203,19 +214,35 @@ public:
|
||||||
/**
|
/**
|
||||||
* @return True if this identity contains something
|
* @return True if this identity contains something
|
||||||
*/
|
*/
|
||||||
explicit ZT_INLINE operator bool() const noexcept { return (m_fp); }
|
explicit ZT_INLINE operator bool() const noexcept
|
||||||
|
{ return (m_fp); }
|
||||||
|
|
||||||
ZT_INLINE unsigned long hashCode() const noexcept { return m_fp.hashCode(); }
|
ZT_INLINE unsigned long hashCode() const noexcept
|
||||||
|
{ return m_fp.hashCode(); }
|
||||||
|
|
||||||
ZT_INLINE bool operator==(const Identity &id) const noexcept { 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 (m_fp == id.m_fp); }
|
||||||
ZT_INLINE bool operator<(const Identity &id) const noexcept { return (m_fp < id.m_fp); }
|
|
||||||
ZT_INLINE bool operator>(const Identity &id) const noexcept { return (id < *this); }
|
ZT_INLINE bool operator!=(const Identity &id) const noexcept
|
||||||
ZT_INLINE bool operator<=(const Identity &id) const noexcept { return !(id < *this); }
|
{ return !(*this == id); }
|
||||||
ZT_INLINE bool operator>=(const Identity &id) const noexcept { return !(*this < id); }
|
|
||||||
|
ZT_INLINE bool operator<(const Identity &id) const noexcept
|
||||||
|
{ return (m_fp < id.m_fp); }
|
||||||
|
|
||||||
|
ZT_INLINE bool operator>(const Identity &id) const noexcept
|
||||||
|
{ return (id < *this); }
|
||||||
|
|
||||||
|
ZT_INLINE bool operator<=(const Identity &id) const noexcept
|
||||||
|
{ return !(id < *this); }
|
||||||
|
|
||||||
|
ZT_INLINE bool operator>=(const Identity &id) const noexcept
|
||||||
|
{ return !(*this < id); }
|
||||||
|
|
||||||
|
static constexpr int marshalSizeMax() noexcept
|
||||||
|
{ return ZT_IDENTITY_MARSHAL_SIZE_MAX; }
|
||||||
|
|
||||||
static constexpr int marshalSizeMax() noexcept { return ZT_IDENTITY_MARSHAL_SIZE_MAX; }
|
|
||||||
int marshal(uint8_t data[ZT_IDENTITY_MARSHAL_SIZE_MAX], bool includePrivate = false) const noexcept;
|
int 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:
|
||||||
|
|
|
@ -119,9 +119,7 @@ Node::Node(
|
||||||
stateObjectPut(tPtr, ZT_STATE_OBJECT_IDENTITY_PUBLIC, idtmp, RR->publicIdentityStr, (unsigned int)strlen(RR->publicIdentityStr));
|
stateObjectPut(tPtr, ZT_STATE_OBJECT_IDENTITY_PUBLIC, idtmp, RR->publicIdentityStr, (unsigned int)strlen(RR->publicIdentityStr));
|
||||||
}
|
}
|
||||||
|
|
||||||
// 2X hash our identity private key(s) to obtain a symmetric key for encrypting
|
// Create a secret key for encrypting local data at rest.
|
||||||
// locally cached data at rest (as a defense in depth measure). This is not used
|
|
||||||
// for any network level encryption or authentication.
|
|
||||||
uint8_t tmph[ZT_SHA384_DIGEST_SIZE];
|
uint8_t tmph[ZT_SHA384_DIGEST_SIZE];
|
||||||
RR->identity.hashWithPrivate(tmph);
|
RR->identity.hashWithPrivate(tmph);
|
||||||
SHA384(tmph, tmph, ZT_SHA384_DIGEST_SIZE);
|
SHA384(tmph, tmph, ZT_SHA384_DIGEST_SIZE);
|
||||||
|
|
|
@ -194,7 +194,7 @@
|
||||||
#define ZT_PROTO_PACKET_FRAGMENT_PAYLOAD_START_AT ZT_PROTO_MIN_FRAGMENT_LENGTH
|
#define ZT_PROTO_PACKET_FRAGMENT_PAYLOAD_START_AT ZT_PROTO_MIN_FRAGMENT_LENGTH
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Header flag indicating that a packet is fragmented and more fragments should be expected
|
* Outer flag indicating that a packet is fragmented and this is just the head.
|
||||||
*/
|
*/
|
||||||
#define ZT_PROTO_FLAG_FRAGMENTED 0x40U
|
#define ZT_PROTO_FLAG_FRAGMENTED 0x40U
|
||||||
|
|
||||||
|
|
|
@ -145,7 +145,9 @@ static ZT_INLINE void p_salsaCrypt(p_SalsaState *const state, const uint8_t *m,
|
||||||
|
|
||||||
for (;;) {
|
for (;;) {
|
||||||
if (likely(bytes >= 64)) {
|
if (likely(bytes >= 64)) {
|
||||||
|
#ifdef ZT_SALSA20_SSE
|
||||||
_mm_prefetch(m + 128, _MM_HINT_T0);
|
_mm_prefetch(m + 128, _MM_HINT_T0);
|
||||||
|
#endif
|
||||||
} else {
|
} else {
|
||||||
for (unsigned int i = 0;i < bytes;++i)
|
for (unsigned int i = 0;i < bytes;++i)
|
||||||
tmp[i] = m[i];
|
tmp[i] = m[i];
|
||||||
|
|
|
@ -29,7 +29,6 @@ Topology::Topology(const RuntimeEnvironment *renv, void *tPtr) :
|
||||||
Identity id;
|
Identity id;
|
||||||
int l = id.unmarshal(dptr, drem);
|
int l = id.unmarshal(dptr, drem);
|
||||||
if ((l > 0) && (id)) {
|
if ((l > 0) && (id)) {
|
||||||
m_roots.insert(id);
|
|
||||||
ZT_SPEW("restored root %s", id.address().toString().c_str());
|
ZT_SPEW("restored root %s", id.address().toString().c_str());
|
||||||
if ((drem -= l) <= 0)
|
if ((drem -= l) <= 0)
|
||||||
break;
|
break;
|
||||||
|
@ -189,25 +188,25 @@ void Topology::m_updateRootPeers(void *tPtr)
|
||||||
{
|
{
|
||||||
// assumes m_peers_l is locked for write
|
// assumes m_peers_l is locked for write
|
||||||
Vector< SharedPtr< Peer > > rp;
|
Vector< SharedPtr< Peer > > rp;
|
||||||
for (Set< Identity >::iterator r(m_roots.begin()); r != m_roots.end(); ++r) {
|
for (Map< Identity, Set< SubscriptionKeyHash > >::iterator r(m_roots.begin()); r != m_roots.end(); ++r) {
|
||||||
Map< Address, SharedPtr< Peer > >::iterator pp(m_peers.find(r->address()));
|
Map< Address, SharedPtr< Peer > >::iterator pp(m_peers.find(r->first.address()));
|
||||||
SharedPtr< Peer > p;
|
SharedPtr< Peer > p;
|
||||||
if (pp != m_peers.end())
|
if (pp != m_peers.end())
|
||||||
p = pp->second;
|
p = pp->second;
|
||||||
|
|
||||||
if (!p)
|
if (!p)
|
||||||
m_loadCached(tPtr, r->address(), p);
|
m_loadCached(tPtr, r->first.address(), p);
|
||||||
|
|
||||||
if ((!p) || (p->identity() != *r)) {
|
if ((!p) || (p->identity() != r->first)) {
|
||||||
p.set(new Peer(RR));
|
p.set(new Peer(RR));
|
||||||
p->init(*r);
|
p->init(r->first);
|
||||||
m_peers[r->address()] = p;
|
m_peers[r->first.address()] = p;
|
||||||
}
|
}
|
||||||
|
|
||||||
rp.push_back(p);
|
rp.push_back(p);
|
||||||
}
|
}
|
||||||
|
std::sort(rp.begin(), rp.end(), p_RootSortComparisonOperator());
|
||||||
m_rootPeers.swap(rp);
|
m_rootPeers.swap(rp);
|
||||||
std::sort(m_rootPeers.begin(), m_rootPeers.end(), p_RootSortComparisonOperator());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace ZeroTier
|
} // namespace ZeroTier
|
||||||
|
|
|
@ -25,6 +25,7 @@
|
||||||
#include "ScopedPtr.hpp"
|
#include "ScopedPtr.hpp"
|
||||||
#include "Fingerprint.hpp"
|
#include "Fingerprint.hpp"
|
||||||
#include "Containers.hpp"
|
#include "Containers.hpp"
|
||||||
|
#include "Blob.hpp"
|
||||||
|
|
||||||
namespace ZeroTier {
|
namespace ZeroTier {
|
||||||
|
|
||||||
|
@ -36,6 +37,11 @@ class RuntimeEnvironment;
|
||||||
class Topology
|
class Topology
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
/**
|
||||||
|
* Hash of public keys for signing a root set definition
|
||||||
|
*/
|
||||||
|
typedef Blob<ZT_SHA384_DIGEST_SIZE> RootSetId;
|
||||||
|
|
||||||
Topology(const RuntimeEnvironment *renv, void *tPtr);
|
Topology(const RuntimeEnvironment *renv, void *tPtr);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -237,7 +243,7 @@ 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;
|
||||||
Set< Identity > m_roots;
|
Map< Identity, Set< SubscriptionKeyHash > > m_roots;
|
||||||
Vector< SharedPtr< Peer > > m_rootPeers;
|
Vector< SharedPtr< Peer > > m_rootPeers;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -132,14 +132,19 @@ char *decimal(unsigned long n, char s[24]) noexcept
|
||||||
|
|
||||||
char *hex(uint64_t i, char buf[17]) noexcept
|
char *hex(uint64_t i, char buf[17]) noexcept
|
||||||
{
|
{
|
||||||
if (i) {
|
if (i != 0) {
|
||||||
char *p = buf + 16;
|
char *p = nullptr;
|
||||||
*p = 0;
|
for (int b = 60; b >= 0; b -= 4) {
|
||||||
while (i) {
|
const unsigned int nyb = (unsigned int)(i >> (unsigned int)b) & 0xfU;
|
||||||
*(--p) = HEXCHARS[i & 0xfU];
|
if (p) {
|
||||||
i >>= 4;
|
*(p++) = HEXCHARS[nyb];
|
||||||
|
} else if (nyb != 0) {
|
||||||
|
p = buf;
|
||||||
|
*(p++) = HEXCHARS[nyb];
|
||||||
}
|
}
|
||||||
return p;
|
}
|
||||||
|
*p = 0;
|
||||||
|
return buf;
|
||||||
} else {
|
} else {
|
||||||
buf[0] = '0';
|
buf[0] = '0';
|
||||||
buf[1] = 0;
|
buf[1] = 0;
|
||||||
|
@ -267,20 +272,18 @@ void getSecureRandom(void *const buf, unsigned int bytes) noexcept
|
||||||
close(devURandomFd);
|
close(devURandomFd);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// Mix in additional entropy from time, the address of 'buf', CPU RDRAND if present, etc.
|
|
||||||
randomState[0] += (uint64_t)time(nullptr);
|
|
||||||
randomState[1] += (uint64_t)((uintptr_t)buf);
|
|
||||||
#ifdef __UNIX_LIKE__
|
#ifdef __UNIX_LIKE__
|
||||||
randomState[2] += (uint64_t)getpid();
|
randomState[0] += (uint64_t)getpid();
|
||||||
randomState[3] += (uint64_t)getppid();
|
randomState[1] += (uint64_t)getppid();
|
||||||
#endif
|
#endif
|
||||||
#ifdef ZT_ARCH_X64
|
#ifdef ZT_ARCH_X64
|
||||||
if (CPUID.rdrand) {
|
if (CPUID.rdrand) {
|
||||||
|
// RDRAND is very slow on some chips, so only sample it a little bit for extra entropy.
|
||||||
uint64_t tmp = 0;
|
uint64_t tmp = 0;
|
||||||
for (int k = 0; k < ZT_GETSECURERANDOM_STATE_SIZE; ++k) {
|
|
||||||
_rdrand64_step((unsigned long long *)&tmp);
|
_rdrand64_step((unsigned long long *)&tmp);
|
||||||
randomState[k] ^= tmp;
|
randomState[2] ^= tmp;
|
||||||
}
|
_rdrand64_step((unsigned long long *)&tmp);
|
||||||
|
randomState[3] ^= tmp;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
@ -289,6 +292,9 @@ void getSecureRandom(void *const buf, unsigned int bytes) noexcept
|
||||||
// replacing the first 64 bytes with this hash, and then re-initializing
|
// replacing the first 64 bytes with this hash, and then re-initializing
|
||||||
// AES with the first 32 bytes.
|
// AES with the first 32 bytes.
|
||||||
randomByteCounter = 0;
|
randomByteCounter = 0;
|
||||||
|
randomState[4] += (uint64_t)((uintptr_t)buf);
|
||||||
|
randomState[5] += (uint64_t)bytes;
|
||||||
|
randomState[6] += (uint64_t)time(nullptr);
|
||||||
SHA512(randomState, randomState, sizeof(randomState));
|
SHA512(randomState, randomState, sizeof(randomState));
|
||||||
randomGen.init(randomState);
|
randomGen.init(randomState);
|
||||||
}
|
}
|
||||||
|
|
|
@ -144,9 +144,6 @@ char *decimal(unsigned long n, char s[24]) noexcept;
|
||||||
/**
|
/**
|
||||||
* Convert an unsigned integer into hex
|
* Convert an unsigned integer into hex
|
||||||
*
|
*
|
||||||
* The returned pointer won't point to the start of 'buf', since
|
|
||||||
* hex writing is done in reverse order.
|
|
||||||
*
|
|
||||||
* @param i Any unsigned integer
|
* @param i Any unsigned integer
|
||||||
* @param s Buffer to receive hex, must be at least (2*sizeof(i))+1 in size or overflow will occur.
|
* @param s Buffer to receive hex, must be at least (2*sizeof(i))+1 in size or overflow will occur.
|
||||||
* @return Pointer to s containing hex string with trailing zero byte
|
* @return Pointer to s containing hex string with trailing zero byte
|
||||||
|
|
191
core/zerotier.h
191
core/zerotier.h
|
@ -276,6 +276,181 @@ typedef void ZT_Identity;
|
||||||
*/
|
*/
|
||||||
typedef void ZT_Locator;
|
typedef void ZT_Locator;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Full identity fingerprint with address and 384-bit hash of public key(s)
|
||||||
|
*/
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Short address (only least significant 40 bits are used)
|
||||||
|
*/
|
||||||
|
uint64_t address;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 384-bit hash of identity public key(s)
|
||||||
|
*/
|
||||||
|
uint8_t hash[48];
|
||||||
|
} ZT_Fingerprint;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Maximum length of string fields in identification certificates
|
||||||
|
*/
|
||||||
|
#define ZT_IDENTIFICATION_CERTIFICATE_MAX_STRING_LENGTH 127
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Maximum length of a signature
|
||||||
|
*/
|
||||||
|
#define ZT_IDENTIFICATION_CERTIFICATE_MAX_SIGNATURE_SIZE 256
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Information about a real world entity.
|
||||||
|
*/
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
char country[ZT_IDENTIFICATION_CERTIFICATE_MAX_STRING_LENGTH + 1];
|
||||||
|
char organization[ZT_IDENTIFICATION_CERTIFICATE_MAX_STRING_LENGTH + 1];
|
||||||
|
char unit[ZT_IDENTIFICATION_CERTIFICATE_MAX_STRING_LENGTH + 1];
|
||||||
|
char locality[ZT_IDENTIFICATION_CERTIFICATE_MAX_STRING_LENGTH + 1];
|
||||||
|
char province[ZT_IDENTIFICATION_CERTIFICATE_MAX_STRING_LENGTH + 1];
|
||||||
|
char streetAddress[ZT_IDENTIFICATION_CERTIFICATE_MAX_STRING_LENGTH + 1];
|
||||||
|
char postalCode[ZT_IDENTIFICATION_CERTIFICATE_MAX_STRING_LENGTH + 1];
|
||||||
|
char commonName[ZT_IDENTIFICATION_CERTIFICATE_MAX_STRING_LENGTH + 1];
|
||||||
|
char serialNo[ZT_IDENTIFICATION_CERTIFICATE_MAX_STRING_LENGTH + 1];
|
||||||
|
char email[ZT_IDENTIFICATION_CERTIFICATE_MAX_STRING_LENGTH + 1];
|
||||||
|
char url[ZT_IDENTIFICATION_CERTIFICATE_MAX_STRING_LENGTH + 1];
|
||||||
|
} ZT_IdentificationCertificate_Name;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Identity and optional locator for a node
|
||||||
|
*/
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Identity (never NULL)
|
||||||
|
*/
|
||||||
|
const ZT_Identity *identity;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Locator or NULL if not specified
|
||||||
|
*/
|
||||||
|
const ZT_Locator *locator;
|
||||||
|
} ZT_IdentificationCertificate_Node;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ID and primary controller for a network
|
||||||
|
*/
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Network ID
|
||||||
|
*/
|
||||||
|
uint64_t id;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Full fingerprint of primary controller
|
||||||
|
*/
|
||||||
|
ZT_Fingerprint controller;
|
||||||
|
} ZT_IdentificationCertificate_Network;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Identification certificate subject
|
||||||
|
*/
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Identities and optional locators of nodes
|
||||||
|
*/
|
||||||
|
ZT_IdentificationCertificate_Node *nodes;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Number of nodes
|
||||||
|
*/
|
||||||
|
unsigned int nodeCount;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Networks owned by this entity
|
||||||
|
*/
|
||||||
|
ZT_IdentificationCertificate_Network *networks;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Number of networks
|
||||||
|
*/
|
||||||
|
unsigned int networkCount;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Information about owner of items.
|
||||||
|
*/
|
||||||
|
ZT_IdentificationCertificate_Name name;
|
||||||
|
} ZT_IdentificationCertificate_Subject;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Identification 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.
|
||||||
|
*/
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Serial number, a SHA384 hash of this certificate.
|
||||||
|
*/
|
||||||
|
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 (for future use, currently zero).
|
||||||
|
*
|
||||||
|
* This could be used to implement key usage flags similar to X509 if
|
||||||
|
* these are needed.
|
||||||
|
*/
|
||||||
|
uint64_t flags;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Valid time range: not before, not after.
|
||||||
|
*/
|
||||||
|
int64_t validity[2];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Subject of certificate
|
||||||
|
*/
|
||||||
|
ZT_IdentificationCertificate_Subject subject;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Issuer node identity and public key(s).
|
||||||
|
*/
|
||||||
|
const ZT_Identity *issuer;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Issuer information
|
||||||
|
*/
|
||||||
|
ZT_IdentificationCertificate_Name issuerName;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Signature by issuer (algorithm determined by identity type).
|
||||||
|
*/
|
||||||
|
uint8_t signature[ZT_IDENTIFICATION_CERTIFICATE_MAX_SIGNATURE_SIZE];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Size of signature in bytes.
|
||||||
|
*/
|
||||||
|
unsigned int signatureSize;
|
||||||
|
} ZT_IdentificationCertificate;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Credential type IDs
|
* Credential type IDs
|
||||||
*/
|
*/
|
||||||
|
@ -308,22 +483,6 @@ enum ZT_EndpointType
|
||||||
ZT_ENDPOINT_TYPE_IP_HTTP = 8 // IP/HTTP encapsulation
|
ZT_ENDPOINT_TYPE_IP_HTTP = 8 // IP/HTTP encapsulation
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
|
||||||
* Full identity fingerprint with address and 384-bit hash of public key(s)
|
|
||||||
*/
|
|
||||||
typedef struct
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* Short address (only least significant 40 bits are used)
|
|
||||||
*/
|
|
||||||
uint64_t address;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 384-bit hash of identity public key(s)
|
|
||||||
*/
|
|
||||||
uint8_t hash[48];
|
|
||||||
} ZT_Fingerprint;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Flag indicating that VL1 tracing should be generated
|
* Flag indicating that VL1 tracing should be generated
|
||||||
*/
|
*/
|
||||||
|
|
36
main.cpp
36
main.cpp
|
@ -11,9 +11,41 @@
|
||||||
*/
|
*/
|
||||||
/****/
|
/****/
|
||||||
|
|
||||||
|
#if !defined(_WIN32) && !defined(_WIN64)
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
#include "zerotier_cgo.h"
|
#include "zerotier_cgo.h"
|
||||||
|
|
||||||
int main() {
|
int main(int argc,char **argv)
|
||||||
ZeroTierMain();
|
{
|
||||||
|
// Fork into background if run with 'service -d'. This is best done prior
|
||||||
|
// to launching the Go code, since Go likes to start thread pools and stuff
|
||||||
|
// that don't play nice with fork. This is obviously unsupported on Windows.
|
||||||
|
#if !defined(_WIN32) && !defined(_WIN64)
|
||||||
|
for(int i=1;i<argc;) {
|
||||||
|
if (strcmp(argv[i++], "service") == 0) {
|
||||||
|
for(;i<argc;) {
|
||||||
|
if (strcmp(argv[i++], "-d") == 0) {
|
||||||
|
long p = (long)fork();
|
||||||
|
if (p < 0) {
|
||||||
|
fprintf(stderr,"FATAL: fork() failed!\n");
|
||||||
|
return -1;
|
||||||
|
} else if (p > 0) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
ZeroTierMain();
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -47,7 +47,7 @@ var nullLogger = log.New(ioutil.Discard, "", 0)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
NetworkIDStringLength = 16
|
NetworkIDStringLength = 16
|
||||||
NEtworkIDLength = 8
|
NetworkIDLength = 8
|
||||||
AddressStringLength = 10
|
AddressStringLength = 10
|
||||||
AddressLength = 5
|
AddressLength = 5
|
||||||
|
|
||||||
|
@ -883,7 +883,7 @@ func goStateObjectGetFunc(gn unsafe.Pointer, objType C.int, id, dataP unsafe.Poi
|
||||||
*((*uintptr)(dataP)) = 0
|
*((*uintptr)(dataP)) = 0
|
||||||
tmp, found := node.stateObjectGet(int(objType), *((*[2]uint64)(id)))
|
tmp, found := node.stateObjectGet(int(objType), *((*[2]uint64)(id)))
|
||||||
if found && len(tmp) > 0 {
|
if found && len(tmp) > 0 {
|
||||||
cData := C.malloc(C.ulong(len(tmp))) // GoGlue sends free() to the core as the free function
|
cData := C.ZT_malloc(C.ulong(len(tmp))) // GoGlue sends free() to the core as the free function
|
||||||
if uintptr(cData) == 0 {
|
if uintptr(cData) == 0 {
|
||||||
return -1
|
return -1
|
||||||
}
|
}
|
||||||
|
|
|
@ -724,3 +724,6 @@ extern "C" int ZT_isTemporaryV6Address(const char *ifname, const struct sockaddr
|
||||||
return 0;
|
return 0;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
extern "C" void *ZT_malloc(unsigned long s)
|
||||||
|
{ return (void *)malloc((size_t)s); }
|
||||||
|
|
|
@ -50,6 +50,8 @@ void ZT_GoTap_setMtu(ZT_GoTap *tap,unsigned int mtu);
|
||||||
|
|
||||||
int ZT_isTemporaryV6Address(const char *ifname,const struct sockaddr_storage *a);
|
int ZT_isTemporaryV6Address(const char *ifname,const struct sockaddr_storage *a);
|
||||||
|
|
||||||
|
void *ZT_malloc(unsigned long s);
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
Loading…
Add table
Reference in a new issue