Merge branch 'edge' into cmake

This commit is contained in:
Grant Limberg 2019-08-12 12:24:25 -07:00
commit 8e04f83232
57 changed files with 3808 additions and 2318 deletions

158
attic/root.cpp Normal file
View file

@ -0,0 +1,158 @@
/*
* ZeroTier One - Network Virtualization Everywhere
* Copyright (C) 2011-2019 ZeroTier, Inc. https://www.zerotier.com/
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* --
*
* You can be released from the requirements of the license by purchasing
* a commercial license. Buying such a license is mandatory as soon as you
* develop commercial closed-source software that incorporates or links
* directly against ZeroTier software without disclosing the source code
* of your own application.
*/
#include "node/Constants.hpp"
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <fcntl.h>
#include <signal.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/select.h>
#include <sys/time.h>
#include <sys/un.h>
#include <sys/ioctl.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <netinet/ip6.h>
#include <netinet/tcp.h>
#include <string>
#include <thread>
#include <map>
#include <vector>
#include <iostream>
#include "include/ZeroTierOne.h"
static int bindSocket(struct sockaddr *bindAddr)
{
int s = socket(bindAddr->sa_family,SOCK_DGRAM,0);
if (s < 0) {
close(s);
return -1;
}
int f = 131072;
setsockopt(s,SOL_SOCKET,SO_RCVBUF,(const char *)&f,sizeof(f));
f = 131072;
setsockopt(s,SOL_SOCKET,SO_SNDBUF,(const char *)&f,sizeof(f));
if (bindAddr->sa_family == AF_INET6) {
f = 1; setsockopt(s,IPPROTO_IPV6,IPV6_V6ONLY,(void *)&f,sizeof(f));
#ifdef IPV6_MTU_DISCOVER
f = 0; setsockopt(s,IPPROTO_IPV6,IPV6_MTU_DISCOVER,&f,sizeof(f));
#endif
#ifdef IPV6_DONTFRAG
f = 0; setsockopt(s,IPPROTO_IPV6,IPV6_DONTFRAG,&f,sizeof(f));
#endif
}
f = 1; setsockopt(s,SOL_SOCKET,SO_REUSEADDR,(void *)&f,sizeof(f));
f = 1; setsockopt(s,SOL_SOCKET,SO_REUSEPORT,(void *)&f,sizeof(f));
f = 1; setsockopt(s,SOL_SOCKET,SO_BROADCAST,(void *)&f,sizeof(f));
#ifdef IP_DONTFRAG
f = 0; setsockopt(s,IPPROTO_IP,IP_DONTFRAG,&f,sizeof(f));
#endif
#ifdef IP_MTU_DISCOVER
f = IP_PMTUDISC_DONT; setsockopt(s,IPPROTO_IP,IP_MTU_DISCOVER,&f,sizeof(f));
#endif
#ifdef SO_NO_CHECK
if (bindAddr->sa_family == AF_INET) {
f = 1; setsockopt(s,SOL_SOCKET,SO_NO_CHECK,(void *)&f,sizeof(f));
}
#endif
if (bind(s,bindAddr,(bindAddr->sa_family == AF_INET) ? sizeof(struct sockaddr_in) : sizeof(struct sockaddr_in6))) {
close(s);
return -1;
}
return s;
}
int main(int argc,char **argv)
{
unsigned int ncores = std::thread::hardware_concurrency();
if (ncores == 0) ncores = 1;
std::vector<int> sockets;
std::vector<std::thread> threads;
for(unsigned int tn=0;tn<ncores;++tn) {
struct sockaddr_in6 in6;
memset(&in6,0,sizeof(in6));
in6.sin6_family = AF_INET6;
in6.sin6_port = htons(ZT_DEFAULT_PORT);
const int s6 = bindSocket((struct sockaddr *)&in6);
if (s6 < 0) {
std::cout << "ERROR: unable to bind to port " << ZT_DEFAULT_PORT << ZT_EOL_S;
exit(1);
}
struct sockaddr_in in4;
memset(&in4,0,sizeof(in4));
in4.sin_family = AF_INET;
in4.sin_port = htons(ZT_DEFAULT_PORT);
const int s4 = bindSocket((struct sockaddr *)&in4);
if (s4 < 0) {
std::cout << "ERROR: unable to bind to port " << ZT_DEFAULT_PORT << ZT_EOL_S;
exit(1);
}
sockets.push_back(s6);
sockets.push_back(s4);
threads.push_back(std::thread([s6]() {
struct sockaddr_in6 in6;
char buf[10000];
memset(&in6,0,sizeof(in6));
for(;;) {
socklen_t sl = sizeof(in6);
const int pl = (int)recvfrom(s6,buf,sizeof(buf),0,(struct sockaddr *)&in6,&sl);
if (pl > 0) {
} else break;
}
}));
threads.push_back(std::thread([s4]() {
struct sockaddr_in in4;
char buf[10000];
memset(&in4,0,sizeof(in4));
for(;;) {
socklen_t sl = sizeof(in4);
const int pl = (int)recvfrom(s4,buf,sizeof(buf),0,(struct sockaddr *)&in4,&sl);
if (pl > 0) {
} else break;
}
}));
}
return 0;
}

View file

@ -1,7 +0,0 @@
World Definitions and Generator Code
======
This little bit of code is used to generate world updates. Ordinary users probably will never need this unless they want to test or experiment.
See mkworld.cpp for documentation. To build from this directory use 'source ./build.sh'.

View file

@ -1,3 +0,0 @@
#!/bin/bash
c++ -std=c++11 -I../.. -I.. -O -o mkworld ../../node/C25519.cpp ../../node/Salsa20.cpp ../../node/SHA512.cpp ../../node/Identity.cpp ../../node/Utils.cpp ../../node/InetAddress.cpp ../../osdep/OSUtils.cpp mkworld.cpp -lm

View file

@ -1,154 +0,0 @@
/*
* ZeroTier One - Network Virtualization Everywhere
* Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/*
* This utility makes the World from the configuration specified below.
* It probably won't be much use to anyone outside ZeroTier, Inc. except
* for testing and experimentation purposes.
*
* If you want to make your own World you must edit this file.
*
* When run, it expects two files in the current directory:
*
* previous.c25519 - key pair to sign this world (key from previous world)
* current.c25519 - key pair whose public key should be embedded in this world
*
* If these files do not exist, they are both created with the same key pair
* and a self-signed initial World is born.
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdint.h>
#include <string>
#include <vector>
#include <algorithm>
#include <node/Constants.hpp>
#include <node/World.hpp>
#include <node/C25519.hpp>
#include <node/Identity.hpp>
#include <node/InetAddress.hpp>
#include <osdep/OSUtils.hpp>
using namespace ZeroTier;
int main(int argc,char **argv)
{
std::string previous,current;
if ((!OSUtils::readFile("previous.c25519",previous))||(!OSUtils::readFile("current.c25519",current))) {
C25519::Pair np(C25519::generate());
previous = std::string();
previous.append((const char *)np.pub.data,ZT_C25519_PUBLIC_KEY_LEN);
previous.append((const char *)np.priv.data,ZT_C25519_PRIVATE_KEY_LEN);
current = previous;
OSUtils::writeFile("previous.c25519",previous);
OSUtils::writeFile("current.c25519",current);
fprintf(stderr,"INFO: created initial world keys: previous.c25519 and current.c25519 (both initially the same)" ZT_EOL_S);
}
if ((previous.length() != (ZT_C25519_PUBLIC_KEY_LEN + ZT_C25519_PRIVATE_KEY_LEN))||(current.length() != (ZT_C25519_PUBLIC_KEY_LEN + ZT_C25519_PRIVATE_KEY_LEN))) {
fprintf(stderr,"FATAL: previous.c25519 or current.c25519 empty or invalid" ZT_EOL_S);
return 1;
}
C25519::Pair previousKP;
memcpy(previousKP.pub.data,previous.data(),ZT_C25519_PUBLIC_KEY_LEN);
memcpy(previousKP.priv.data,previous.data() + ZT_C25519_PUBLIC_KEY_LEN,ZT_C25519_PRIVATE_KEY_LEN);
C25519::Pair currentKP;
memcpy(currentKP.pub.data,current.data(),ZT_C25519_PUBLIC_KEY_LEN);
memcpy(currentKP.priv.data,current.data() + ZT_C25519_PUBLIC_KEY_LEN,ZT_C25519_PRIVATE_KEY_LEN);
// =========================================================================
// EDIT BELOW HERE
std::vector<World::Root> roots;
const uint64_t id = ZT_WORLD_ID_EARTH;
const uint64_t ts = 1562631342273ULL; // July 8th, 2019
roots.push_back(World::Root());
roots.back().identity = Identity("3a46f1bf30:0:76e66fab33e28549a62ee2064d1843273c2c300ba45c3f20bef02dbad225723bb59a9bb4b13535730961aeecf5a163ace477cceb0727025b99ac14a5166a09a3");
roots.back().stableEndpoints.push_back(InetAddress("185.180.13.82/9993"));
roots.back().stableEndpoints.push_back(InetAddress("2a02:6ea0:c815::/9993"));
// Alice
roots.push_back(World::Root());
roots.back().identity = Identity("9d219039f3:0:01f0922a98e3b34ebcbff333269dc265d7a020aab69d72be4d4acc9c8c9294785771256cd1d942a90d1bd1d2dca3ea84ef7d85afe6611fb43ff0b74126d90a6e");
roots.back().stableEndpoints.push_back(InetAddress("188.166.94.177/9993")); // Amsterdam
roots.back().stableEndpoints.push_back(InetAddress("2a03:b0c0:2:d0::7d:1/9993")); // Amsterdam
roots.back().stableEndpoints.push_back(InetAddress("154.66.197.33/9993")); // Johannesburg
roots.back().stableEndpoints.push_back(InetAddress("2c0f:f850:154:197::33/9993")); // Johannesburg
roots.back().stableEndpoints.push_back(InetAddress("159.203.97.171/9993")); // New York
roots.back().stableEndpoints.push_back(InetAddress("2604:a880:800:a1::54:6001/9993")); // New York
roots.back().stableEndpoints.push_back(InetAddress("131.255.6.16/9993")); // Buenos Aires
roots.back().stableEndpoints.push_back(InetAddress("2803:eb80:0:e::2/9993")); // Buenos Aires
roots.back().stableEndpoints.push_back(InetAddress("107.170.197.14/9993")); // San Francisco
roots.back().stableEndpoints.push_back(InetAddress("2604:a880:1:20::200:e001/9993")); // San Francisco
roots.back().stableEndpoints.push_back(InetAddress("128.199.197.217/9993")); // Singapore
roots.back().stableEndpoints.push_back(InetAddress("2400:6180:0:d0::b7:4001/9993")); // Singapore
// Bob
roots.push_back(World::Root());
roots.back().identity = Identity("8841408a2e:0:bb1d31f2c323e264e9e64172c1a74f77899555ed10751cd56e86405cde118d02dffe555d462ccf6a85b5631c12350c8d5dc409ba10b9025d0f445cf449d92b1c");
roots.back().stableEndpoints.push_back(InetAddress("45.32.198.130/9993")); // Dallas
roots.back().stableEndpoints.push_back(InetAddress("2001:19f0:6400:81c3:5400:00ff:fe18:1d61/9993")); // Dallas
roots.back().stableEndpoints.push_back(InetAddress("46.101.160.249/9993")); // Frankfurt
roots.back().stableEndpoints.push_back(InetAddress("2a03:b0c0:3:d0::6a:3001/9993")); // Frankfurt
roots.back().stableEndpoints.push_back(InetAddress("107.191.46.210/9993")); // Paris
roots.back().stableEndpoints.push_back(InetAddress("2001:19f0:6800:83a4::64/9993")); // Paris
roots.back().stableEndpoints.push_back(InetAddress("45.32.246.179/9993")); // Sydney
roots.back().stableEndpoints.push_back(InetAddress("2001:19f0:5800:8bf8:5400:ff:fe15:b39a/9993")); // Sydney
roots.back().stableEndpoints.push_back(InetAddress("45.32.248.87/9993")); // Tokyo
roots.back().stableEndpoints.push_back(InetAddress("2001:19f0:7000:9bc9:5400:00ff:fe15:c4f5/9993")); // Tokyo
roots.back().stableEndpoints.push_back(InetAddress("159.203.2.154/9993")); // Toronto
roots.back().stableEndpoints.push_back(InetAddress("2604:a880:cad:d0::26:7001/9993")); // Toronto
// END WORLD DEFINITION
// =========================================================================
fprintf(stderr,"INFO: generating and signing id==%llu ts==%llu" ZT_EOL_S,(unsigned long long)id,(unsigned long long)ts);
World nw = World::make(World::TYPE_PLANET,id,ts,currentKP.pub,roots,previousKP);
Buffer<ZT_WORLD_MAX_SERIALIZED_LENGTH> outtmp;
nw.serialize(outtmp,false);
World testw;
testw.deserialize(outtmp,0);
if (testw != nw) {
fprintf(stderr,"FATAL: serialization test failed!" ZT_EOL_S);
return 1;
}
OSUtils::writeFile("world.bin",std::string((const char *)outtmp.data(),outtmp.size()));
fprintf(stderr,"INFO: world.bin written with %u bytes of binary world data." ZT_EOL_S,outtmp.size());
fprintf(stdout,ZT_EOL_S);
fprintf(stdout,"#define ZT_DEFAULT_WORLD_LENGTH %u" ZT_EOL_S,outtmp.size());
fprintf(stdout,"static const unsigned char ZT_DEFAULT_WORLD[ZT_DEFAULT_WORLD_LENGTH] = {");
for(unsigned int i=0;i<outtmp.size();++i) {
const unsigned char *d = (const unsigned char *)outtmp.data();
if (i > 0)
fprintf(stdout,",");
fprintf(stdout,"0x%.2x",(unsigned int)d[i]);
}
fprintf(stdout,"};" ZT_EOL_S);
return 0;
}

Binary file not shown.

View file

@ -1,3 +0,0 @@
#define ZT_DEFAULT_WORLD_LENGTH 732
static const unsigned char ZT_DEFAULT_WORLD[ZT_DEFAULT_WORLD_LENGTH] = {0x01,0x00,0x00,0x00,0x00,0x08,0xea,0xc9,0x0a,0x00,0x00,0x01,0x6b,0xd4,0x16,0x08,0xc1,0xb8,0xb3,0x88,0xa4,0x69,0x22,0x14,0x91,0xaa,0x9a,0xcd,0x66,0xcc,0x76,0x4c,0xde,0xfd,0x56,0x03,0x9f,0x10,0x67,0xae,0x15,0xe6,0x9c,0x6f,0xb4,0x2d,0x7b,0x55,0x33,0x0e,0x3f,0xda,0xac,0x52,0x9c,0x07,0x92,0xfd,0x73,0x40,0xa6,0xaa,0x21,0xab,0xa8,0xa4,0x89,0xfd,0xae,0xa4,0x4a,0x39,0xbf,0x2d,0x00,0x65,0x9a,0xc9,0xc8,0x18,0xeb,0x16,0x93,0xf4,0xe5,0xbd,0x20,0xda,0x10,0xad,0xc7,0x05,0xf4,0x99,0xfe,0x04,0x08,0x9b,0xe0,0x9e,0x77,0x1d,0x9f,0x47,0x16,0xaa,0x92,0x4f,0x10,0x16,0x3d,0xc7,0xec,0xd3,0x90,0x9e,0xd1,0x74,0xfc,0xb3,0xb5,0x07,0x9c,0x4d,0x95,0xc5,0x17,0x8b,0x3d,0x0b,0x60,0x76,0xe8,0x51,0xbb,0xb6,0x3d,0x74,0xb5,0x21,0x83,0x7b,0x95,0x1d,0x02,0x9b,0xcd,0xaf,0x5c,0x3e,0x96,0xdf,0x37,0x2c,0x56,0x6d,0xfa,0x75,0x0f,0xda,0x55,0x85,0x13,0xf4,0x76,0x1a,0x66,0x4d,0x3b,0x8d,0xcf,0x12,0xc9,0x34,0xb9,0x0d,0x61,0x03,0x3a,0x46,0xf1,0xbf,0x30,0x00,0x76,0xe6,0x6f,0xab,0x33,0xe2,0x85,0x49,0xa6,0x2e,0xe2,0x06,0x4d,0x18,0x43,0x27,0x3c,0x2c,0x30,0x0b,0xa4,0x5c,0x3f,0x20,0xbe,0xf0,0x2d,0xba,0xd2,0x25,0x72,0x3b,0xb5,0x9a,0x9b,0xb4,0xb1,0x35,0x35,0x73,0x09,0x61,0xae,0xec,0xf5,0xa1,0x63,0xac,0xe4,0x77,0xcc,0xeb,0x07,0x27,0x02,0x5b,0x99,0xac,0x14,0xa5,0x16,0x6a,0x09,0xa3,0x00,0x02,0x04,0xb9,0xb4,0x0d,0x52,0x27,0x09,0x06,0x2a,0x02,0x6e,0xa0,0xc8,0x15,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x27,0x09,0x9d,0x21,0x90,0x39,0xf3,0x00,0x01,0xf0,0x92,0x2a,0x98,0xe3,0xb3,0x4e,0xbc,0xbf,0xf3,0x33,0x26,0x9d,0xc2,0x65,0xd7,0xa0,0x20,0xaa,0xb6,0x9d,0x72,0xbe,0x4d,0x4a,0xcc,0x9c,0x8c,0x92,0x94,0x78,0x57,0x71,0x25,0x6c,0xd1,0xd9,0x42,0xa9,0x0d,0x1b,0xd1,0xd2,0xdc,0xa3,0xea,0x84,0xef,0x7d,0x85,0xaf,0xe6,0x61,0x1f,0xb4,0x3f,0xf0,0xb7,0x41,0x26,0xd9,0x0a,0x6e,0x00,0x0c,0x04,0xbc,0xa6,0x5e,0xb1,0x27,0x09,0x06,0x2a,0x03,0xb0,0xc0,0x00,0x02,0x00,0xd0,0x00,0x00,0x00,0x00,0x00,0x7d,0x00,0x01,0x27,0x09,0x04,0x9a,0x42,0xc5,0x21,0x27,0x09,0x06,0x2c,0x0f,0xf8,0x50,0x01,0x54,0x01,0x97,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x33,0x27,0x09,0x04,0x9f,0xcb,0x61,0xab,0x27,0x09,0x06,0x26,0x04,0xa8,0x80,0x08,0x00,0x00,0xa1,0x00,0x00,0x00,0x00,0x00,0x54,0x60,0x01,0x27,0x09,0x04,0x83,0xff,0x06,0x10,0x27,0x09,0x06,0x28,0x03,0xeb,0x80,0x00,0x00,0x00,0x0e,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x27,0x09,0x04,0x6b,0xaa,0xc5,0x0e,0x27,0x09,0x06,0x26,0x04,0xa8,0x80,0x00,0x01,0x00,0x20,0x00,0x00,0x00,0x00,0x02,0x00,0xe0,0x01,0x27,0x09,0x04,0x80,0xc7,0xc5,0xd9,0x27,0x09,0x06,0x24,0x00,0x61,0x80,0x00,0x00,0x00,0xd0,0x00,0x00,0x00,0x00,0x00,0xb7,0x40,0x01,0x27,0x09,0x88,0x41,0x40,0x8a,0x2e,0x00,0xbb,0x1d,0x31,0xf2,0xc3,0x23,0xe2,0x64,0xe9,0xe6,0x41,0x72,0xc1,0xa7,0x4f,0x77,0x89,0x95,0x55,0xed,0x10,0x75,0x1c,0xd5,0x6e,0x86,0x40,0x5c,0xde,0x11,0x8d,0x02,0xdf,0xfe,0x55,0x5d,0x46,0x2c,0xcf,0x6a,0x85,0xb5,0x63,0x1c,0x12,0x35,0x0c,0x8d,0x5d,0xc4,0x09,0xba,0x10,0xb9,0x02,0x5d,0x0f,0x44,0x5c,0xf4,0x49,0xd9,0x2b,0x1c,0x00,0x0c,0x04,0x2d,0x20,0xc6,0x82,0x27,0x09,0x06,0x20,0x01,0x19,0xf0,0x64,0x00,0x81,0xc3,0x54,0x00,0x00,0xff,0xfe,0x18,0x1d,0x61,0x27,0x09,0x04,0x2e,0x65,0xa0,0xf9,0x27,0x09,0x06,0x2a,0x03,0xb0,0xc0,0x00,0x03,0x00,0xd0,0x00,0x00,0x00,0x00,0x00,0x6a,0x30,0x01,0x27,0x09,0x04,0x6b,0xbf,0x2e,0xd2,0x27,0x09,0x06,0x20,0x01,0x19,0xf0,0x68,0x00,0x83,0xa4,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x64,0x27,0x09,0x04,0x2d,0x20,0xf6,0xb3,0x27,0x09,0x06,0x20,0x01,0x19,0xf0,0x58,0x00,0x8b,0xf8,0x54,0x00,0x00,0xff,0xfe,0x15,0xb3,0x9a,0x27,0x09,0x04,0x2d,0x20,0xf8,0x57,0x27,0x09,0x06,0x20,0x01,0x19,0xf0,0x70,0x00,0x9b,0xc9,0x54,0x00,0x00,0xff,0xfe,0x15,0xc4,0xf5,0x27,0x09,0x04,0x9f,0xcb,0x02,0x9a,0x27,0x09,0x06,0x26,0x04,0xa8,0x80,0x0c,0xad,0x00,0xd0,0x00,0x00,0x00,0x00,0x00,0x26,0x70,0x01,0x27,0x09};

View file

@ -64,6 +64,7 @@ class EmbeddedNetworkController : public NetworkController,public DB::ChangeList
public:
/**
* @param node Parent node
* @param ztPath ZeroTier base path
* @param dbPath Database path (file path or database credentials)
*/
EmbeddedNetworkController(Node *node,const char *ztPath,const char *dbPath, int listenPort, MQConfig *mqc = NULL);

View file

@ -33,13 +33,11 @@ FileDB::FileDB(const char *path) :
DB(),
_path(path),
_networksPath(_path + ZT_PATH_SEPARATOR_S + "network"),
_tracePath(_path + ZT_PATH_SEPARATOR_S + "trace"),
_running(true)
{
OSUtils::mkdir(_path.c_str());
OSUtils::lockDownFile(_path.c_str(),true);
OSUtils::mkdir(_networksPath.c_str());
OSUtils::mkdir(_tracePath.c_str());
std::vector<std::string> networks(OSUtils::listDirectory(_networksPath.c_str(),false));
std::string buf;

View file

@ -48,7 +48,6 @@ public:
protected:
std::string _path;
std::string _networksPath;
std::string _tracePath;
std::thread _onlineUpdateThread;
std::map< uint64_t,std::map<uint64_t,std::map<int64_t,InetAddress> > > _online;
std::mutex _online_l;

View file

@ -1390,24 +1390,6 @@ enum ZT_StateObjectType
*/
ZT_STATE_OBJECT_IDENTITY_SECRET = 2,
/**
* The planet (there is only one per... well... planet!)
*
* Object ID: world ID of planet, or 0 if unknown (first query)
* Canonical path: <HOME>/planet
* Persistence: recommended
*/
ZT_STATE_OBJECT_PLANET = 3,
/**
* A moon (federated root set)
*
* Object ID: world ID of moon
* Canonical path: <HOME>/moons.d/<ID>.moon (16-digit hex ID)
* Persistence: required if moon memberships should persist
*/
ZT_STATE_OBJECT_MOON = 4,
/**
* Peer and related state
*
@ -1844,32 +1826,6 @@ ZT_SDK_API enum ZT_ResultCode ZT_Node_multicastSubscribe(ZT_Node *node,void *tpt
*/
ZT_SDK_API enum ZT_ResultCode ZT_Node_multicastUnsubscribe(ZT_Node *node,uint64_t nwid,uint64_t multicastGroup,unsigned long multicastAdi);
/**
* Add or update a moon
*
* Moons are persisted in the data store in moons.d/, so this can persist
* across invocations if the contents of moon.d are scanned and orbit is
* called for each on startup.
*
* @param node Node instance
* @param tptr Thread pointer to pass to functions/callbacks resulting from this call
* @param moonWorldId Moon's world ID
* @param moonSeed If non-zero, the ZeroTier address of any member of the moon to query for moon definition
* @param len Length of moonWorld in bytes
* @return Error if moon was invalid or failed to be added
*/
ZT_SDK_API enum ZT_ResultCode ZT_Node_orbit(ZT_Node *node,void *tptr,uint64_t moonWorldId,uint64_t moonSeed);
/**
* Remove a moon (does nothing if not present)
*
* @param node Node instance
* @param tptr Thread pointer to pass to functions/callbacks resulting from this call
* @param moonWorldId World ID of moon to remove
* @return Error if anything bad happened
*/
ZT_SDK_API enum ZT_ResultCode ZT_Node_deorbit(ZT_Node *node,void *tptr,uint64_t moonWorldId);
/**
* Get this node's 40-bit ZeroTier address
*

362
node/AES.cpp Normal file
View file

@ -0,0 +1,362 @@
/*
* ZeroTier One - Network Virtualization Everywhere
* Copyright (C) 2011-2019 ZeroTier, Inc. https://www.zerotier.com/
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* --
*
* You can be released from the requirements of the license by purchasing
* a commercial license. Buying such a license is mandatory as soon as you
* develop commercial closed-source software that incorporates or links
* directly against ZeroTier software without disclosing the source code
* of your own application.
*/
#include "AES.hpp"
namespace ZeroTier {
#if (defined(__amd64) || defined(__amd64__) || defined(__x86_64) || defined(__x86_64__) || defined(__AMD64) || defined(__AMD64__) || defined(_M_X64))
#include <wmmintrin.h>
#include <emmintrin.h>
#include <smmintrin.h>
static inline bool _zt_aesni_supported()
{
uint32_t eax,ebx,ecx,edx;
__asm__ __volatile__ (
"cpuid"
: "=a"(eax), "=b"(ebx), "=c"(ecx), "=d"(edx)
: "a"(1), "c"(0)
);
return ((ecx & (1 << 25)) != 0);
}
const bool AES::HW_ACCEL = _zt_aesni_supported();
#else
const bool AES::HW_ACCEL = false;
#endif
namespace {
#ifdef ZT_NO_TYPE_PUNNING
static inline uint32_t GETU32(const void *in)
{
uint32_t v = ((const uint8_t *)in)[0];
v <<= 8;
v |= ((const uint8_t *)in)[1];
v <<= 8;
v |= ((const uint8_t *)in)[2];
v <<= 8;
v |= ((const uint8_t *)in)[3];
return v;
}
static inline void PUTU32(void *out,const uint32_t v)
{
((uint8_t *)out)[0] = (uint8_t)(v >> 24);
((uint8_t *)out)[1] = (uint8_t)(v >> 16);
((uint8_t *)out)[2] = (uint8_t)(v >> 8);
((uint8_t *)out)[3] = (uint8_t)v;
}
#else
#define GETU32(i) (Utils::ntoh(*((const uint32_t *)(i))))
#define PUTU32(o,v) (*((uint32_t *)(o)) = Utils::hton(v))
#endif
static const uint32_t Te0[256] = {
0xc66363a5,0xf87c7c84,0xee777799,0xf67b7b8d,0xfff2f20d,
0xd66b6bbd,0xde6f6fb1,0x91c5c554,0x60303050,0x02010103,
0xce6767a9,0x562b2b7d,0xe7fefe19,0xb5d7d762,0x4dababe6,
0xec76769a,0x8fcaca45,0x1f82829d,0x89c9c940,0xfa7d7d87,
0xeffafa15,0xb25959eb,0x8e4747c9,0xfbf0f00b,0x41adadec,
0xb3d4d467,0x5fa2a2fd,0x45afafea,0x239c9cbf,0x53a4a4f7,
0xe4727296,0x9bc0c05b,0x75b7b7c2,0xe1fdfd1c,0x3d9393ae,
0x4c26266a,0x6c36365a,0x7e3f3f41,0xf5f7f702,0x83cccc4f,
0x6834345c,0x51a5a5f4,0xd1e5e534,0xf9f1f108,0xe2717193,
0xabd8d873,0x62313153,0x2a15153f,0x0804040c,0x95c7c752,
0x46232365,0x9dc3c35e,0x30181828,0x379696a1,0x0a05050f,
0x2f9a9ab5,0x0e070709,0x24121236,0x1b80809b,0xdfe2e23d,
0xcdebeb26,0x4e272769,0x7fb2b2cd,0xea75759f,0x1209091b,
0x1d83839e,0x582c2c74,0x341a1a2e,0x361b1b2d,0xdc6e6eb2,
0xb45a5aee,0x5ba0a0fb,0xa45252f6,0x763b3b4d,0xb7d6d661,
0x7db3b3ce,0x5229297b,0xdde3e33e,0x5e2f2f71,0x13848497,
0xa65353f5,0xb9d1d168,0x00000000,0xc1eded2c,0x40202060,
0xe3fcfc1f,0x79b1b1c8,0xb65b5bed,0xd46a6abe,0x8dcbcb46,
0x67bebed9,0x7239394b,0x944a4ade,0x984c4cd4,0xb05858e8,
0x85cfcf4a,0xbbd0d06b,0xc5efef2a,0x4faaaae5,0xedfbfb16,
0x864343c5,0x9a4d4dd7,0x66333355,0x11858594,0x8a4545cf,
0xe9f9f910,0x04020206,0xfe7f7f81,0xa05050f0,0x783c3c44,
0x259f9fba,0x4ba8a8e3,0xa25151f3,0x5da3a3fe,0x804040c0,
0x058f8f8a,0x3f9292ad,0x219d9dbc,0x70383848,0xf1f5f504,
0x63bcbcdf,0x77b6b6c1,0xafdada75,0x42212163,0x20101030,
0xe5ffff1a,0xfdf3f30e,0xbfd2d26d,0x81cdcd4c,0x180c0c14,
0x26131335,0xc3ecec2f,0xbe5f5fe1,0x359797a2,0x884444cc,
0x2e171739,0x93c4c457,0x55a7a7f2,0xfc7e7e82,0x7a3d3d47,
0xc86464ac,0xba5d5de7,0x3219192b,0xe6737395,0xc06060a0,
0x19818198,0x9e4f4fd1,0xa3dcdc7f,0x44222266,0x542a2a7e,
0x3b9090ab,0x0b888883,0x8c4646ca,0xc7eeee29,0x6bb8b8d3,
0x2814143c,0xa7dede79,0xbc5e5ee2,0x160b0b1d,0xaddbdb76,
0xdbe0e03b,0x64323256,0x743a3a4e,0x140a0a1e,0x924949db,
0x0c06060a,0x4824246c,0xb85c5ce4,0x9fc2c25d,0xbdd3d36e,
0x43acacef,0xc46262a6,0x399191a8,0x319595a4,0xd3e4e437,
0xf279798b,0xd5e7e732,0x8bc8c843,0x6e373759,0xda6d6db7,
0x018d8d8c,0xb1d5d564,0x9c4e4ed2,0x49a9a9e0,0xd86c6cb4,
0xac5656fa,0xf3f4f407,0xcfeaea25,0xca6565af,0xf47a7a8e,
0x47aeaee9,0x10080818,0x6fbabad5,0xf0787888,0x4a25256f,
0x5c2e2e72,0x381c1c24,0x57a6a6f1,0x73b4b4c7,0x97c6c651,
0xcbe8e823,0xa1dddd7c,0xe874749c,0x3e1f1f21,0x964b4bdd,
0x61bdbddc,0x0d8b8b86,0x0f8a8a85,0xe0707090,0x7c3e3e42,
0x71b5b5c4,0xcc6666aa,0x904848d8,0x06030305,0xf7f6f601,
0x1c0e0e12,0xc26161a3,0x6a35355f,0xae5757f9,0x69b9b9d0,
0x17868691,0x99c1c158,0x3a1d1d27,0x279e9eb9,0xd9e1e138,
0xebf8f813,0x2b9898b3,0x22111133,0xd26969bb,0xa9d9d970,
0x078e8e89,0x339494a7,0x2d9b9bb6,0x3c1e1e22,0x15878792,
0xc9e9e920,0x87cece49,0xaa5555ff,0x50282878,0xa5dfdf7a,
0x038c8c8f,0x59a1a1f8,0x09898980,0x1a0d0d17,0x65bfbfda,
0xd7e6e631,0x844242c6,0xd06868b8,0x824141c3,0x299999b0,
0x5a2d2d77,0x1e0f0f11,0x7bb0b0cb,0xa85454fc,0x6dbbbbd6,
0x2c16163a
};
static const uint32_t Te1[256] = {
0xa5c66363,0x84f87c7c,0x99ee7777,0x8df67b7b,0x0dfff2f2,
0xbdd66b6b,0xb1de6f6f,0x5491c5c5,0x50603030,0x03020101,
0xa9ce6767,0x7d562b2b,0x19e7fefe,0x62b5d7d7,0xe64dabab,
0x9aec7676,0x458fcaca,0x9d1f8282,0x4089c9c9,0x87fa7d7d,
0x15effafa,0xebb25959,0xc98e4747,0x0bfbf0f0,0xec41adad,
0x67b3d4d4,0xfd5fa2a2,0xea45afaf,0xbf239c9c,0xf753a4a4,
0x96e47272,0x5b9bc0c0,0xc275b7b7,0x1ce1fdfd,0xae3d9393,
0x6a4c2626,0x5a6c3636,0x417e3f3f,0x02f5f7f7,0x4f83cccc,
0x5c683434,0xf451a5a5,0x34d1e5e5,0x08f9f1f1,0x93e27171,
0x73abd8d8,0x53623131,0x3f2a1515,0x0c080404,0x5295c7c7,
0x65462323,0x5e9dc3c3,0x28301818,0xa1379696,0x0f0a0505,
0xb52f9a9a,0x090e0707,0x36241212,0x9b1b8080,0x3ddfe2e2,
0x26cdebeb,0x694e2727,0xcd7fb2b2,0x9fea7575,0x1b120909,
0x9e1d8383,0x74582c2c,0x2e341a1a,0x2d361b1b,0xb2dc6e6e,
0xeeb45a5a,0xfb5ba0a0,0xf6a45252,0x4d763b3b,0x61b7d6d6,
0xce7db3b3,0x7b522929,0x3edde3e3,0x715e2f2f,0x97138484,
0xf5a65353,0x68b9d1d1,0x00000000,0x2cc1eded,0x60402020,
0x1fe3fcfc,0xc879b1b1,0xedb65b5b,0xbed46a6a,0x468dcbcb,
0xd967bebe,0x4b723939,0xde944a4a,0xd4984c4c,0xe8b05858,
0x4a85cfcf,0x6bbbd0d0,0x2ac5efef,0xe54faaaa,0x16edfbfb,
0xc5864343,0xd79a4d4d,0x55663333,0x94118585,0xcf8a4545,
0x10e9f9f9,0x06040202,0x81fe7f7f,0xf0a05050,0x44783c3c,
0xba259f9f,0xe34ba8a8,0xf3a25151,0xfe5da3a3,0xc0804040,
0x8a058f8f,0xad3f9292,0xbc219d9d,0x48703838,0x04f1f5f5,
0xdf63bcbc,0xc177b6b6,0x75afdada,0x63422121,0x30201010,
0x1ae5ffff,0x0efdf3f3,0x6dbfd2d2,0x4c81cdcd,0x14180c0c,
0x35261313,0x2fc3ecec,0xe1be5f5f,0xa2359797,0xcc884444,
0x392e1717,0x5793c4c4,0xf255a7a7,0x82fc7e7e,0x477a3d3d,
0xacc86464,0xe7ba5d5d,0x2b321919,0x95e67373,0xa0c06060,
0x98198181,0xd19e4f4f,0x7fa3dcdc,0x66442222,0x7e542a2a,
0xab3b9090,0x830b8888,0xca8c4646,0x29c7eeee,0xd36bb8b8,
0x3c281414,0x79a7dede,0xe2bc5e5e,0x1d160b0b,0x76addbdb,
0x3bdbe0e0,0x56643232,0x4e743a3a,0x1e140a0a,0xdb924949,
0x0a0c0606,0x6c482424,0xe4b85c5c,0x5d9fc2c2,0x6ebdd3d3,
0xef43acac,0xa6c46262,0xa8399191,0xa4319595,0x37d3e4e4,
0x8bf27979,0x32d5e7e7,0x438bc8c8,0x596e3737,0xb7da6d6d,
0x8c018d8d,0x64b1d5d5,0xd29c4e4e,0xe049a9a9,0xb4d86c6c,
0xfaac5656,0x07f3f4f4,0x25cfeaea,0xafca6565,0x8ef47a7a,
0xe947aeae,0x18100808,0xd56fbaba,0x88f07878,0x6f4a2525,
0x725c2e2e,0x24381c1c,0xf157a6a6,0xc773b4b4,0x5197c6c6,
0x23cbe8e8,0x7ca1dddd,0x9ce87474,0x213e1f1f,0xdd964b4b,
0xdc61bdbd,0x860d8b8b,0x850f8a8a,0x90e07070,0x427c3e3e,
0xc471b5b5,0xaacc6666,0xd8904848,0x05060303,0x01f7f6f6,
0x121c0e0e,0xa3c26161,0x5f6a3535,0xf9ae5757,0xd069b9b9,
0x91178686,0x5899c1c1,0x273a1d1d,0xb9279e9e,0x38d9e1e1,
0x13ebf8f8,0xb32b9898,0x33221111,0xbbd26969,0x70a9d9d9,
0x89078e8e,0xa7339494,0xb62d9b9b,0x223c1e1e,0x92158787,
0x20c9e9e9,0x4987cece,0xffaa5555,0x78502828,0x7aa5dfdf,
0x8f038c8c,0xf859a1a1,0x80098989,0x171a0d0d,0xda65bfbf,
0x31d7e6e6,0xc6844242,0xb8d06868,0xc3824141,0xb0299999,
0x775a2d2d,0x111e0f0f,0xcb7bb0b0,0xfca85454,0xd66dbbbb,
0x3a2c1616
};
static const uint32_t Te2[256] = {
0x63a5c663,0x7c84f87c,0x7799ee77,0x7b8df67b,0xf20dfff2,
0x6bbdd66b,0x6fb1de6f,0xc55491c5,0x30506030,0x01030201,
0x67a9ce67,0x2b7d562b,0xfe19e7fe,0xd762b5d7,0xabe64dab,
0x769aec76,0xca458fca,0x829d1f82,0xc94089c9,0x7d87fa7d,
0xfa15effa,0x59ebb259,0x47c98e47,0xf00bfbf0,0xadec41ad,
0xd467b3d4,0xa2fd5fa2,0xafea45af,0x9cbf239c,0xa4f753a4,
0x7296e472,0xc05b9bc0,0xb7c275b7,0xfd1ce1fd,0x93ae3d93,
0x266a4c26,0x365a6c36,0x3f417e3f,0xf702f5f7,0xcc4f83cc,
0x345c6834,0xa5f451a5,0xe534d1e5,0xf108f9f1,0x7193e271,
0xd873abd8,0x31536231,0x153f2a15,0x040c0804,0xc75295c7,
0x23654623,0xc35e9dc3,0x18283018,0x96a13796,0x050f0a05,
0x9ab52f9a,0x07090e07,0x12362412,0x809b1b80,0xe23ddfe2,
0xeb26cdeb,0x27694e27,0xb2cd7fb2,0x759fea75,0x091b1209,
0x839e1d83,0x2c74582c,0x1a2e341a,0x1b2d361b,0x6eb2dc6e,
0x5aeeb45a,0xa0fb5ba0,0x52f6a452,0x3b4d763b,0xd661b7d6,
0xb3ce7db3,0x297b5229,0xe33edde3,0x2f715e2f,0x84971384,
0x53f5a653,0xd168b9d1,0x00000000,0xed2cc1ed,0x20604020,
0xfc1fe3fc,0xb1c879b1,0x5bedb65b,0x6abed46a,0xcb468dcb,
0xbed967be,0x394b7239,0x4ade944a,0x4cd4984c,0x58e8b058,
0xcf4a85cf,0xd06bbbd0,0xef2ac5ef,0xaae54faa,0xfb16edfb,
0x43c58643,0x4dd79a4d,0x33556633,0x85941185,0x45cf8a45,
0xf910e9f9,0x02060402,0x7f81fe7f,0x50f0a050,0x3c44783c,
0x9fba259f,0xa8e34ba8,0x51f3a251,0xa3fe5da3,0x40c08040,
0x8f8a058f,0x92ad3f92,0x9dbc219d,0x38487038,0xf504f1f5,
0xbcdf63bc,0xb6c177b6,0xda75afda,0x21634221,0x10302010,
0xff1ae5ff,0xf30efdf3,0xd26dbfd2,0xcd4c81cd,0x0c14180c,
0x13352613,0xec2fc3ec,0x5fe1be5f,0x97a23597,0x44cc8844,
0x17392e17,0xc45793c4,0xa7f255a7,0x7e82fc7e,0x3d477a3d,
0x64acc864,0x5de7ba5d,0x192b3219,0x7395e673,0x60a0c060,
0x81981981,0x4fd19e4f,0xdc7fa3dc,0x22664422,0x2a7e542a,
0x90ab3b90,0x88830b88,0x46ca8c46,0xee29c7ee,0xb8d36bb8,
0x143c2814,0xde79a7de,0x5ee2bc5e,0x0b1d160b,0xdb76addb,
0xe03bdbe0,0x32566432,0x3a4e743a,0x0a1e140a,0x49db9249,
0x060a0c06,0x246c4824,0x5ce4b85c,0xc25d9fc2,0xd36ebdd3,
0xacef43ac,0x62a6c462,0x91a83991,0x95a43195,0xe437d3e4,
0x798bf279,0xe732d5e7,0xc8438bc8,0x37596e37,0x6db7da6d,
0x8d8c018d,0xd564b1d5,0x4ed29c4e,0xa9e049a9,0x6cb4d86c,
0x56faac56,0xf407f3f4,0xea25cfea,0x65afca65,0x7a8ef47a,
0xaee947ae,0x08181008,0xbad56fba,0x7888f078,0x256f4a25,
0x2e725c2e,0x1c24381c,0xa6f157a6,0xb4c773b4,0xc65197c6,
0xe823cbe8,0xdd7ca1dd,0x749ce874,0x1f213e1f,0x4bdd964b,
0xbddc61bd,0x8b860d8b,0x8a850f8a,0x7090e070,0x3e427c3e,
0xb5c471b5,0x66aacc66,0x48d89048,0x03050603,0xf601f7f6,
0x0e121c0e,0x61a3c261,0x355f6a35,0x57f9ae57,0xb9d069b9,
0x86911786,0xc15899c1,0x1d273a1d,0x9eb9279e,0xe138d9e1,
0xf813ebf8,0x98b32b98,0x11332211,0x69bbd269,0xd970a9d9,
0x8e89078e,0x94a73394,0x9bb62d9b,0x1e223c1e,0x87921587,
0xe920c9e9,0xce4987ce,0x55ffaa55,0x28785028,0xdf7aa5df,
0x8c8f038c,0xa1f859a1,0x89800989,0x0d171a0d,0xbfda65bf,
0xe631d7e6,0x42c68442,0x68b8d068,0x41c38241,0x99b02999,
0x2d775a2d,0x0f111e0f,0xb0cb7bb0,0x54fca854,0xbbd66dbb,
0x163a2c16
};
static const uint32_t Te3[256] = {
0x6363a5c6,0x7c7c84f8,0x777799ee,0x7b7b8df6,0xf2f20dff,
0x6b6bbdd6,0x6f6fb1de,0xc5c55491,0x30305060,0x01010302,
0x6767a9ce,0x2b2b7d56,0xfefe19e7,0xd7d762b5,0xababe64d,
0x76769aec,0xcaca458f,0x82829d1f,0xc9c94089,0x7d7d87fa,
0xfafa15ef,0x5959ebb2,0x4747c98e,0xf0f00bfb,0xadadec41,
0xd4d467b3,0xa2a2fd5f,0xafafea45,0x9c9cbf23,0xa4a4f753,
0x727296e4,0xc0c05b9b,0xb7b7c275,0xfdfd1ce1,0x9393ae3d,
0x26266a4c,0x36365a6c,0x3f3f417e,0xf7f702f5,0xcccc4f83,
0x34345c68,0xa5a5f451,0xe5e534d1,0xf1f108f9,0x717193e2,
0xd8d873ab,0x31315362,0x15153f2a,0x04040c08,0xc7c75295,
0x23236546,0xc3c35e9d,0x18182830,0x9696a137,0x05050f0a,
0x9a9ab52f,0x0707090e,0x12123624,0x80809b1b,0xe2e23ddf,
0xebeb26cd,0x2727694e,0xb2b2cd7f,0x75759fea,0x09091b12,
0x83839e1d,0x2c2c7458,0x1a1a2e34,0x1b1b2d36,0x6e6eb2dc,
0x5a5aeeb4,0xa0a0fb5b,0x5252f6a4,0x3b3b4d76,0xd6d661b7,
0xb3b3ce7d,0x29297b52,0xe3e33edd,0x2f2f715e,0x84849713,
0x5353f5a6,0xd1d168b9,0x00000000,0xeded2cc1,0x20206040,
0xfcfc1fe3,0xb1b1c879,0x5b5bedb6,0x6a6abed4,0xcbcb468d,
0xbebed967,0x39394b72,0x4a4ade94,0x4c4cd498,0x5858e8b0,
0xcfcf4a85,0xd0d06bbb,0xefef2ac5,0xaaaae54f,0xfbfb16ed,
0x4343c586,0x4d4dd79a,0x33335566,0x85859411,0x4545cf8a,
0xf9f910e9,0x02020604,0x7f7f81fe,0x5050f0a0,0x3c3c4478,
0x9f9fba25,0xa8a8e34b,0x5151f3a2,0xa3a3fe5d,0x4040c080,
0x8f8f8a05,0x9292ad3f,0x9d9dbc21,0x38384870,0xf5f504f1,
0xbcbcdf63,0xb6b6c177,0xdada75af,0x21216342,0x10103020,
0xffff1ae5,0xf3f30efd,0xd2d26dbf,0xcdcd4c81,0x0c0c1418,
0x13133526,0xecec2fc3,0x5f5fe1be,0x9797a235,0x4444cc88,
0x1717392e,0xc4c45793,0xa7a7f255,0x7e7e82fc,0x3d3d477a,
0x6464acc8,0x5d5de7ba,0x19192b32,0x737395e6,0x6060a0c0,
0x81819819,0x4f4fd19e,0xdcdc7fa3,0x22226644,0x2a2a7e54,
0x9090ab3b,0x8888830b,0x4646ca8c,0xeeee29c7,0xb8b8d36b,
0x14143c28,0xdede79a7,0x5e5ee2bc,0x0b0b1d16,0xdbdb76ad,
0xe0e03bdb,0x32325664,0x3a3a4e74,0x0a0a1e14,0x4949db92,
0x06060a0c,0x24246c48,0x5c5ce4b8,0xc2c25d9f,0xd3d36ebd,
0xacacef43,0x6262a6c4,0x9191a839,0x9595a431,0xe4e437d3,
0x79798bf2,0xe7e732d5,0xc8c8438b,0x3737596e,0x6d6db7da,
0x8d8d8c01,0xd5d564b1,0x4e4ed29c,0xa9a9e049,0x6c6cb4d8,
0x5656faac,0xf4f407f3,0xeaea25cf,0x6565afca,0x7a7a8ef4,
0xaeaee947,0x08081810,0xbabad56f,0x787888f0,0x25256f4a,
0x2e2e725c,0x1c1c2438,0xa6a6f157,0xb4b4c773,0xc6c65197,
0xe8e823cb,0xdddd7ca1,0x74749ce8,0x1f1f213e,0x4b4bdd96,
0xbdbddc61,0x8b8b860d,0x8a8a850f,0x707090e0,0x3e3e427c,
0xb5b5c471,0x6666aacc,0x4848d890,0x03030506,0xf6f601f7,
0x0e0e121c,0x6161a3c2,0x35355f6a,0x5757f9ae,0xb9b9d069,
0x86869117,0xc1c15899,0x1d1d273a,0x9e9eb927,0xe1e138d9,
0xf8f813eb,0x9898b32b,0x11113322,0x6969bbd2,0xd9d970a9,
0x8e8e8907,0x9494a733,0x9b9bb62d,0x1e1e223c,0x87879215,
0xe9e920c9,0xcece4987,0x5555ffaa,0x28287850,0xdfdf7aa5,
0x8c8c8f03,0xa1a1f859,0x89898009,0x0d0d171a,0xbfbfda65,
0xe6e631d7,0x4242c684,0x6868b8d0,0x4141c382,0x9999b029,
0x2d2d775a,0x0f0f111e,0xb0b0cb7b,0x5454fca8,0xbbbbd66d,
0x16163a2c
};
static const uint32_t rcon[] = {
0x01000000, 0x02000000, 0x04000000, 0x08000000, 0x10000000,
0x20000000, 0x40000000, 0x80000000, 0x1B000000, 0x36000000,
};
} // anonymous namespace
void AES::_initSW(const uint8_t key[32])
{
uint32_t *rk = _k.sw;
rk[0] = GETU32(key);
rk[1] = GETU32(key + 4);
rk[2] = GETU32(key + 8);
rk[3] = GETU32(key + 12);
rk[4] = GETU32(key + 16);
rk[5] = GETU32(key + 20);
rk[6] = GETU32(key + 24);
rk[7] = GETU32(key + 28);
for(int i=0;;) {
uint32_t temp = rk[7];
rk[8] = rk[0] ^ (Te2[(temp >> 16) & 0xff] & 0xff000000) ^ (Te3[(temp >> 8) & 0xff] & 0x00ff0000) ^ (Te0[(temp) & 0xff] & 0x0000ff00) ^ (Te1[(temp >> 24)] & 0x000000ff) ^ rcon[i];
rk[9] = rk[1] ^ rk[8];
rk[10] = rk[2] ^ rk[9];
rk[11] = rk[3] ^ rk[10];
if (++i == 7)
break;
temp = rk[11];
rk[12] = rk[4] ^ (Te2[(temp >> 24)] & 0xff000000) ^ (Te3[(temp >> 16) & 0xff] & 0x00ff0000) ^ (Te0[(temp >> 8) & 0xff] & 0x0000ff00) ^ (Te1[(temp) & 0xff] & 0x000000ff);
rk[13] = rk[5] ^ rk[12];
rk[14] = rk[6] ^ rk[13];
rk[15] = rk[7] ^ rk[14];
rk += 8;
}
}
void AES::_encryptSW(const uint8_t in[16],uint8_t out[16]) const
{
const uint32_t *rk = _k.sw;
uint32_t s0, s1, s2, s3, t0, t1, t2, t3;
s0 = GETU32(in) ^ rk[0];
s1 = GETU32(in + 4) ^ rk[1];
s2 = GETU32(in + 8) ^ rk[2];
s3 = GETU32(in + 12) ^ rk[3];
for (int r=(14>>1);;) {
t0 = Te0[(s0 >> 24)] ^ Te1[(s1 >> 16) & 0xff] ^ Te2[(s2 >> 8) & 0xff] ^ Te3[(s3) & 0xff] ^ rk[4];
t1 = Te0[(s1 >> 24)] ^ Te1[(s2 >> 16) & 0xff] ^ Te2[(s3 >> 8) & 0xff] ^ Te3[(s0) & 0xff] ^ rk[5];
t2 = Te0[(s2 >> 24)] ^ Te1[(s3 >> 16) & 0xff] ^ Te2[(s0 >> 8) & 0xff] ^ Te3[(s1) & 0xff] ^ rk[6];
t3 = Te0[(s3 >> 24)] ^ Te1[(s0 >> 16) & 0xff] ^ Te2[(s1 >> 8) & 0xff] ^ Te3[(s2) & 0xff] ^ rk[7];
rk += 8;
if (--r == 0)
break;
s0 = Te0[(t0 >> 24)] ^ Te1[(t1 >> 16) & 0xff] ^ Te2[(t2 >> 8) & 0xff] ^ Te3[(t3) & 0xff] ^ rk[0];
s1 = Te0[(t1 >> 24)] ^ Te1[(t2 >> 16) & 0xff] ^ Te2[(t3 >> 8) & 0xff] ^ Te3[(t0) & 0xff] ^ rk[1];
s2 = Te0[(t2 >> 24)] ^ Te1[(t3 >> 16) & 0xff] ^ Te2[(t0 >> 8) & 0xff] ^ Te3[(t1) & 0xff] ^ rk[2];
s3 = Te0[(t3 >> 24)] ^ Te1[(t0 >> 16) & 0xff] ^ Te2[(t1 >> 8) & 0xff] ^ Te3[(t2) & 0xff] ^ rk[3];
}
s0 = (Te2[(t0 >> 24)] & 0xff000000) ^ (Te3[(t1 >> 16) & 0xff] & 0x00ff0000) ^ (Te0[(t2 >> 8) & 0xff] & 0x0000ff00) ^ (Te1[(t3) & 0xff] & 0x000000ff) ^ rk[0];
PUTU32(out, s0);
s1 = (Te2[(t1 >> 24)] & 0xff000000) ^ (Te3[(t2 >> 16) & 0xff] & 0x00ff0000) ^ (Te0[(t3 >> 8) & 0xff] & 0x0000ff00) ^ (Te1[(t0) & 0xff] & 0x000000ff) ^ rk[1];
PUTU32(out + 4, s1);
s2 = (Te2[(t2 >> 24)] & 0xff000000) ^ (Te3[(t3 >> 16) & 0xff] & 0x00ff0000) ^ (Te0[(t0 >> 8) & 0xff] & 0x0000ff00) ^ (Te1[(t1) & 0xff] & 0x000000ff) ^ rk[2];
PUTU32(out + 8, s2);
s3 = (Te2[(t3 >> 24)] & 0xff000000) ^ (Te3[(t0 >> 16) & 0xff] & 0x00ff0000) ^ (Te0[(t1 >> 8) & 0xff] & 0x0000ff00) ^ (Te1[(t2) & 0xff] & 0x000000ff) ^ rk[3];
PUTU32(out + 12, s3);
}
} // namespace ZeroTier

172
node/AES.hpp Normal file
View file

@ -0,0 +1,172 @@
/*
* ZeroTier One - Network Virtualization Everywhere
* Copyright (C) 2011-2019 ZeroTier, Inc. https://www.zerotier.com/
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* --
*
* You can be released from the requirements of the license by purchasing
* a commercial license. Buying such a license is mandatory as soon as you
* develop commercial closed-source software that incorporates or links
* directly against ZeroTier software without disclosing the source code
* of your own application.
*/
#ifndef ZT_AES_HPP
#define ZT_AES_HPP
#include "Constants.hpp"
#include "Utils.hpp"
#if (defined(__amd64) || defined(__amd64__) || defined(__x86_64) || defined(__x86_64__) || defined(__AMD64) || defined(__AMD64__) || defined(_M_X64))
#include <wmmintrin.h>
#include <emmintrin.h>
#include <smmintrin.h>
#define ZT_AES_AESNI 1
#endif
namespace ZeroTier {
/**
* AES-256 and GCM AEAD
*
* AES with 128-bit or 192-bit key sizes isn't supported here. This also only
* supports the encrypt operation since we use AES in GCM mode. For HW acceleration
* the code is inlined for maximum performance.
*/
class AES
{
public:
/**
* This will be true if your platform's type of AES acceleration is supported on this machine
*/
static const bool HW_ACCEL;
inline AES() {}
inline AES(const uint8_t key[32]) { this->init(key); }
inline ~AES()
{
Utils::burn(&_k,sizeof(_k)); // ensure that expanded key memory is zeroed on object destruction
}
inline void init(const uint8_t key[32])
{
if (HW_ACCEL) {
#ifdef ZT_AES_AESNI
_init_aesni(key);
#endif
} else {
_initSW(key);
}
}
inline void encrypt(const uint8_t in[16],uint8_t out[16]) const
{
if (HW_ACCEL) {
#ifdef ZT_AES_AESNI
_encrypt_aesni(in,out);
#endif
} else {
_encryptSW(in,out);
}
}
// These are public so the software mode can always be tested in self-test.
// Normally init(), encrypt(), etc. should be used.
void _initSW(const uint8_t key[32]);
void _encryptSW(const uint8_t in[16],uint8_t out[16]) const;
private:
#ifdef ZT_AES_AESNI
static inline __m128i _init256_1(__m128i a,__m128i b)
{
__m128i x,y;
b = _mm_shuffle_epi32(b,0xff);
y = _mm_slli_si128(a,0x04);
x = _mm_xor_si128(a,y);
y = _mm_slli_si128(y,0x04);
x = _mm_xor_si128(x,y);
y = _mm_slli_si128(y,0x04);
x = _mm_xor_si128(x,y);
x = _mm_xor_si128(x,b);
return x;
}
static inline __m128i _init256_2(__m128i a,__m128i b)
{
__m128i x,y,z;
y = _mm_aeskeygenassist_si128(a,0x00);
z = _mm_shuffle_epi32(y,0xaa);
y = _mm_slli_si128(b,0x04);
x = _mm_xor_si128(b,y);
y = _mm_slli_si128(y,0x04);
x = _mm_xor_si128(x,y);
y = _mm_slli_si128(y,0x04);
x = _mm_xor_si128(x,y);
x = _mm_xor_si128(x,z);
return x;
}
inline void _init_aesni(const uint8_t key[32])
{
__m128i t1,t2;
_k.ni[0] = t1 = _mm_loadu_si128((const __m128i *)key);
_k.ni[1] = t2 = _mm_loadu_si128((const __m128i *)(key+16));
_k.ni[2] = t1 = _init256_1(t1,_mm_aeskeygenassist_si128(t2,0x01));
_k.ni[3] = t2 = _init256_2(t1,t2);
_k.ni[4] = t1 = _init256_1(t1,_mm_aeskeygenassist_si128(t2,0x02));
_k.ni[5] = t2 = _init256_2(t1,t2);
_k.ni[6] = t1 = _init256_1(t1,_mm_aeskeygenassist_si128(t2,0x04));
_k.ni[7] = t2 = _init256_2(t1,t2);
_k.ni[8] = t1 = _init256_1(t1,_mm_aeskeygenassist_si128(t2,0x08));
_k.ni[9] = t2 = _init256_2(t1,t2);
_k.ni[10] = t1 = _init256_1(t1,_mm_aeskeygenassist_si128(t2,0x10));
_k.ni[11] = t2 = _init256_2(t1,t2);
_k.ni[12] = t1 = _init256_1(t1,_mm_aeskeygenassist_si128(t2,0x20));
_k.ni[13] = t2 = _init256_2(t1,t2);
_k.ni[14] = _init256_1(t1,_mm_aeskeygenassist_si128(t2,0x40));
}
inline void _encrypt_aesni(const void *in,void *out) const
{
__m128i tmp;
tmp = _mm_loadu_si128((const __m128i *)in);
tmp = _mm_xor_si128(tmp,_k.ni[0]);
tmp = _mm_aesenc_si128(tmp,_k.ni[1]);
tmp = _mm_aesenc_si128(tmp,_k.ni[2]);
tmp = _mm_aesenc_si128(tmp,_k.ni[3]);
tmp = _mm_aesenc_si128(tmp,_k.ni[4]);
tmp = _mm_aesenc_si128(tmp,_k.ni[5]);
tmp = _mm_aesenc_si128(tmp,_k.ni[6]);
tmp = _mm_aesenc_si128(tmp,_k.ni[7]);
tmp = _mm_aesenc_si128(tmp,_k.ni[8]);
tmp = _mm_aesenc_si128(tmp,_k.ni[9]);
tmp = _mm_aesenc_si128(tmp,_k.ni[10]);
tmp = _mm_aesenc_si128(tmp,_k.ni[11]);
tmp = _mm_aesenc_si128(tmp,_k.ni[12]);
tmp = _mm_aesenc_si128(tmp,_k.ni[13]);
_mm_storeu_si128((__m128i *)out,_mm_aesenclast_si128(tmp,_k.ni[14]));
}
#endif
union {
#ifdef ZT_AES_AESNI
__m128i ni[15]; // AES-NI expanded key
#endif
uint32_t sw[60]; // software mode expanded key
} _k;
};
} // namespace ZeroTier
#endif

View file

@ -2439,7 +2439,7 @@ static inline void get_hram(unsigned char *hram, const unsigned char *sm, const
for (i = 32;i < 64;++i) playground[i] = pk[i-32];
for (i = 64;i < smlen;++i) playground[i] = sm[i];
ZeroTier::SHA512::hash(hram,playground,(unsigned int)smlen);
ZeroTier::SHA512(hram,playground,(unsigned int)smlen);
}
//////////////////////////////////////////////////////////////////////////////
@ -2459,11 +2459,11 @@ void C25519::agree(const C25519::Private &mine,const C25519::Public &their,void
unsigned char digest[64];
crypto_scalarmult(rawkey,mine.data,their.data);
SHA512::hash(digest,rawkey,32);
SHA512(digest,rawkey,32);
for(unsigned int i=0,k=0;i<keylen;) {
if (k == 64) {
k = 0;
SHA512::hash(digest,digest,64);
SHA512(digest,digest,64);
}
((unsigned char *)keybuf)[i++] = digest[k++];
}
@ -2472,7 +2472,7 @@ void C25519::agree(const C25519::Private &mine,const C25519::Public &their,void
void C25519::sign(const C25519::Private &myPrivate,const C25519::Public &myPublic,const void *msg,unsigned int len,void *signature)
{
unsigned char digest[64]; // we sign the first 32 bytes of SHA-512(msg)
SHA512::hash(digest,msg,len);
SHA512(digest,msg,len);
#ifdef ZT_USE_FAST_X64_ED25519
ed25519_amd64_asm_sign(myPrivate.data + 32,myPublic.data + 32,digest,(unsigned char *)signature);
@ -2486,7 +2486,7 @@ void C25519::sign(const C25519::Private &myPrivate,const C25519::Public &myPubli
unsigned char hram[crypto_hash_sha512_BYTES];
unsigned char *sig = (unsigned char *)signature;
SHA512::hash(extsk,myPrivate.data + 32,32);
SHA512(extsk,myPrivate.data + 32,32);
extsk[0] &= 248;
extsk[31] &= 127;
extsk[31] |= 64;
@ -2496,7 +2496,7 @@ void C25519::sign(const C25519::Private &myPrivate,const C25519::Public &myPubli
for(unsigned int i=0;i<32;i++)
sig[64 + i] = digest[i];
SHA512::hash(hmg,sig + 32,64);
SHA512(hmg,sig + 32,64);
/* Computation of R */
sc25519_from64bytes(&sck, hmg);
@ -2521,13 +2521,22 @@ void C25519::sign(const C25519::Private &myPrivate,const C25519::Public &myPubli
#endif
}
bool C25519::verify(const C25519::Public &their,const void *msg,unsigned int len,const void *signature)
bool C25519::verify(const C25519::Public &their,const void *msg,unsigned int len,const void *signature,const unsigned int siglen)
{
const unsigned char *const sig = (const unsigned char *)signature;
if (siglen < 64) return false;
const unsigned char *sig = (const unsigned char *)signature;
unsigned char digest[64]; // we sign the first 32 bytes of SHA-512(msg)
SHA512::hash(digest,msg,len);
if (!Utils::secureEq(sig + 64,digest,32))
unsigned char sigtmp[96];
SHA512(digest,msg,len);
if ((siglen == 96)&&(!Utils::secureEq(sig+64,digest,32))) {
return false;
} else if (siglen == 64) {
memcpy(sigtmp,sig,64);
memcpy(sigtmp+64,digest,32);
sig = sigtmp;
}
unsigned char t2[32];
ge25519 get1, get2;
@ -2565,7 +2574,7 @@ void C25519::_calcPubED(C25519::Pair &kp)
// Second 32 bytes of pub and priv are the keys for ed25519
// signing and verification.
SHA512::hash(extsk,kp.priv.data + 32,32);
SHA512(extsk,kp.priv.data + 32,32);
extsk[0] &= 248;
extsk[31] &= 127;
extsk[31] |= 64;

View file

@ -98,7 +98,6 @@ public:
* @param keylen Number of key bytes to generate
*/
static void agree(const Private &mine,const Public &their,void *keybuf,unsigned int keylen);
static inline void agree(const Pair &mine,const Public &their,void *keybuf,unsigned int keylen) { agree(mine.priv,their,keybuf,keylen); }
/**
* Sign a message with a sender's key pair
@ -120,11 +119,15 @@ public:
* @param signature Buffer to fill with signature -- MUST be 96 bytes in length
*/
static void sign(const Private &myPrivate,const Public &myPublic,const void *msg,unsigned int len,void *signature);
static inline void sign(const Pair &mine,const void *msg,unsigned int len,void *signature) { sign(mine.priv,mine.pub,msg,len,signature); }
/**
* Sign a message with a sender's key pair
*
* Note that this generates a 96-byte signature that contains an extra 32 bytes
* of hash data. This data is included for historical reasons and is optional. The
* verify function here will take the first 64 bytes only (normal ed25519 signature)
* or a 96-byte length signature with the extra input hash data.
*
* @param myPrivate My private key
* @param myPublic My public key
* @param msg Message to sign
@ -150,10 +153,11 @@ public:
* @param their Public key to verify against
* @param msg Message to verify signature integrity against
* @param len Length of message in bytes
* @param signature 96-byte signature
* @param signature Signature bytes
* @param siglen Length of signature in bytes
* @return True if signature is valid and the message is authentic and unmodified
*/
static bool verify(const Public &their,const void *msg,unsigned int len,const void *signature);
static bool verify(const Public &their,const void *msg,unsigned int len,const void *signature,const unsigned int siglen);
/**
* Verify a message's signature
@ -164,10 +168,7 @@ public:
* @param signature 96-byte signature
* @return True if signature is valid and the message is authentic and unmodified
*/
static inline bool verify(const Public &their,const void *msg,unsigned int len,const Signature &signature)
{
return verify(their,msg,len,signature.data);
}
static inline bool verify(const Public &their,const void *msg,unsigned int len,const Signature &signature) { return verify(their,msg,len,signature.data,96); }
private:
// derive first 32 bytes of kp.pub from first 32 bytes of kp.priv

View file

@ -34,6 +34,23 @@
namespace ZeroTier {
bool Capability::sign(const Identity &from,const Address &to)
{
try {
for(unsigned int i=0;((i<_maxCustodyChainLength)&&(i<ZT_MAX_CAPABILITY_CUSTODY_CHAIN_LENGTH));++i) {
if (!(_custody[i].to)) {
Buffer<(sizeof(Capability) * 2)> tmp;
this->serialize(tmp,true);
_custody[i].to = to;
_custody[i].from = from.address();
_custody[i].signatureLength = from.sign(tmp.data(),tmp.size(),_custody[i].signature,sizeof(_custody[i].signature));
return true;
}
}
} catch ( ... ) {}
return false;
}
int Capability::verify(const RuntimeEnvironment *RR,void *tPtr) const
{
try {
@ -57,7 +74,7 @@ int Capability::verify(const RuntimeEnvironment *RR,void *tPtr) const
const Identity id(RR->topology->getIdentity(tPtr,_custody[c].from));
if (id) {
if (!id.verify(tmp.data(),tmp.size(),_custody[c].signature))
if (!id.verify(tmp.data(),tmp.size(),_custody[c].signature,_custody[c].signatureLength))
return -1;
} else {
RR->sw->requestWhois(tPtr,RR->node->now(),_custody[c].from);

View file

@ -154,22 +154,7 @@ public:
* @param to Recipient of this signature
* @return True if signature successful and chain of custody appended
*/
inline bool sign(const Identity &from,const Address &to)
{
try {
for(unsigned int i=0;((i<_maxCustodyChainLength)&&(i<ZT_MAX_CAPABILITY_CUSTODY_CHAIN_LENGTH));++i) {
if (!(_custody[i].to)) {
Buffer<(sizeof(Capability) * 2)> tmp;
this->serialize(tmp,true);
_custody[i].to = to;
_custody[i].from = from.address();
_custody[i].signature = from.sign(tmp.data(),tmp.size());
return true;
}
}
} catch ( ... ) {}
return false;
}
bool sign(const Identity &from,const Address &to);
/**
* Verify this capability's chain of custody and signatures
@ -409,9 +394,9 @@ public:
if ((i < _maxCustodyChainLength)&&(i < ZT_MAX_CAPABILITY_CUSTODY_CHAIN_LENGTH)&&(_custody[i].to)) {
_custody[i].to.appendTo(b);
_custody[i].from.appendTo(b);
b.append((uint8_t)1); // 1 == Ed25519 signature
b.append((uint16_t)ZT_C25519_SIGNATURE_LEN); // length of signature
b.append(_custody[i].signature.data,ZT_C25519_SIGNATURE_LEN);
b.append((uint8_t)1);
b.append((uint16_t)_custody[i].signatureLength);
b.append(_custody[i].signature,_custody[i].signatureLength);
} else {
b.append((unsigned char)0,ZT_ADDRESS_LENGTH); // zero 'to' terminates chain
break;
@ -454,10 +439,11 @@ public:
_custody[i].to = to;
_custody[i].from.setTo(b.field(p,ZT_ADDRESS_LENGTH),ZT_ADDRESS_LENGTH); p += ZT_ADDRESS_LENGTH;
if (b[p++] == 1) {
if (b.template at<uint16_t>(p) != ZT_C25519_SIGNATURE_LEN)
_custody[i].signatureLength = b.template at<uint16_t>(p);
if (_custody[i].signatureLength > sizeof(_custody[i].signature))
throw ZT_EXCEPTION_INVALID_SERIALIZED_DATA_INVALID_CRYPTOGRAPHIC_TOKEN;
p += 2;
memcpy(_custody[i].signature.data,b.field(p,ZT_C25519_SIGNATURE_LEN),ZT_C25519_SIGNATURE_LEN); p += ZT_C25519_SIGNATURE_LEN;
memcpy(_custody[i].signature,b.field(p,_custody[i].signatureLength),_custody[i].signatureLength); p += _custody[i].signatureLength;
} else {
p += 2 + b.template at<uint16_t>(p);
}
@ -489,7 +475,8 @@ private:
struct {
Address to;
Address from;
C25519::Signature signature;
unsigned int signatureLength;
uint8_t signature[ZT_SIGNATURE_BUFFER_SIZE];
} _custody[ZT_MAX_CAPABILITY_CUSTODY_CHAIN_LENGTH];
};

View file

@ -84,7 +84,7 @@ std::string CertificateOfMembership::toString() const
if (_signedBy) {
s.push_back(':');
s.append(Utils::hex(_signature.data,ZT_C25519_SIGNATURE_LEN,tmp));
s.append(Utils::hex(_signature,_signatureLength,tmp));
}
return s;
@ -92,9 +92,9 @@ std::string CertificateOfMembership::toString() const
void CertificateOfMembership::fromString(const char *s)
{
_qualifierCount = 0;
_signedBy.zero();
memset(_signature.data,0,ZT_C25519_SIGNATURE_LEN);
_qualifierCount = 0;
_signatureLength = 0;
if (!*s)
return;
@ -145,8 +145,7 @@ void CertificateOfMembership::fromString(const char *s)
colonAt = 0;
while ((s[colonAt])&&(s[colonAt] != ':')) ++colonAt;
if (colonAt) {
if (Utils::unhex(s,colonAt,_signature.data,ZT_C25519_SIGNATURE_LEN) != ZT_C25519_SIGNATURE_LEN)
_signedBy.zero();
_signatureLength = Utils::unhex(s,colonAt,_signature,sizeof(_signature));
} else {
_signedBy.zero();
}
@ -208,7 +207,7 @@ bool CertificateOfMembership::sign(const Identity &with)
}
try {
_signature = with.sign(buf,ptr * sizeof(uint64_t));
_signatureLength = with.sign(buf,ptr * sizeof(uint64_t),_signature,sizeof(_signature));
_signedBy = with.address();
return true;
} catch ( ... ) {
@ -235,7 +234,7 @@ int CertificateOfMembership::verify(const RuntimeEnvironment *RR,void *tPtr) con
buf[ptr++] = Utils::hton(_qualifiers[i].value);
buf[ptr++] = Utils::hton(_qualifiers[i].maxDelta);
}
return (id.verify(buf,ptr * sizeof(uint64_t),_signature) ? 0 : -1);
return (id.verify(buf,ptr * sizeof(uint64_t),_signature,_signatureLength) ? 0 : -1);
}
} // namespace ZeroTier

View file

@ -113,7 +113,8 @@ public:
* Create an empty certificate of membership
*/
CertificateOfMembership() :
_qualifierCount(0) {}
_qualifierCount(0),
_signatureLength(0) {}
/**
* Create from required fields common to all networks
@ -135,7 +136,7 @@ public:
_qualifiers[2].value = issuedTo.toInt();
_qualifiers[2].maxDelta = 0xffffffffffffffffULL;
_qualifierCount = 3;
memset(_signature.data,0,ZT_C25519_SIGNATURE_LEN);
_signatureLength = 0;
}
/**
@ -279,8 +280,13 @@ public:
b.append(_qualifiers[i].maxDelta);
}
_signedBy.appendTo(b);
if (_signedBy)
b.append(_signature.data,ZT_C25519_SIGNATURE_LEN);
if ((_signedBy)&&(_signatureLength == 96)) {
// UGLY: Ed25519 signatures in ZT are 96 bytes (64 + 32 bytes of hash).
// P-384 signatures are also 96 bytes, praise the horned one. That means
// we don't need to include a length. If we ever do we will need a new
// serialized object version, but only for those with length != 96.
b.append(_signature,96);
}
}
template<unsigned int C>
@ -288,8 +294,9 @@ public:
{
unsigned int p = startAt;
_qualifierCount = 0;
_signedBy.zero();
_qualifierCount = 0;
_signatureLength = 0;
if (b[p++] != 1)
throw ZT_EXCEPTION_INVALID_SERIALIZED_DATA_INVALID_TYPE;
@ -316,8 +323,10 @@ public:
p += ZT_ADDRESS_LENGTH;
if (_signedBy) {
memcpy(_signature.data,b.field(p,ZT_C25519_SIGNATURE_LEN),ZT_C25519_SIGNATURE_LEN);
p += ZT_C25519_SIGNATURE_LEN;
// See "UGLY" comment in serialize()...
_signatureLength = 96;
memcpy(_signature,b.field(p,96),96);
p += 96;
}
return (p - startAt);
@ -329,13 +338,15 @@ public:
return false;
if (_qualifierCount != c._qualifierCount)
return false;
if (_signatureLength != c._signatureLength)
return false;
for(unsigned int i=0;i<_qualifierCount;++i) {
const _Qualifier &a = _qualifiers[i];
const _Qualifier &b = c._qualifiers[i];
if ((a.id != b.id)||(a.value != b.value)||(a.maxDelta != b.maxDelta))
return false;
}
return (memcmp(_signature.data,c._signature.data,ZT_C25519_SIGNATURE_LEN) == 0);
return (memcmp(_signature,c._signature,_signatureLength) == 0);
}
inline bool operator!=(const CertificateOfMembership &c) const { return (!(*this == c)); }
@ -352,7 +363,8 @@ private:
Address _signedBy;
_Qualifier _qualifiers[ZT_NETWORK_COM_MAX_QUALIFIERS];
unsigned int _qualifierCount;
C25519::Signature _signature;
unsigned int _signatureLength;
uint8_t _signature[ZT_SIGNATURE_BUFFER_SIZE];
};
} // namespace ZeroTier

View file

@ -34,6 +34,32 @@
namespace ZeroTier {
void CertificateOfOwnership::addThing(const InetAddress &ip)
{
if (_thingCount >= ZT_CERTIFICATEOFOWNERSHIP_MAX_THINGS) return;
if (ip.ss_family == AF_INET) {
_thingTypes[_thingCount] = THING_IPV4_ADDRESS;
memcpy(_thingValues[_thingCount],&(reinterpret_cast<const struct sockaddr_in *>(&ip)->sin_addr.s_addr),4);
++_thingCount;
} else if (ip.ss_family == AF_INET6) {
_thingTypes[_thingCount] = THING_IPV6_ADDRESS;
memcpy(_thingValues[_thingCount],reinterpret_cast<const struct sockaddr_in6 *>(&ip)->sin6_addr.s6_addr,16);
++_thingCount;
}
}
bool CertificateOfOwnership::sign(const Identity &signer)
{
if (signer.hasPrivate()) {
Buffer<sizeof(CertificateOfOwnership) + 64> tmp;
_signedBy = signer.address();
this->serialize(tmp,true);
_signatureLength = signer.sign(tmp.data(),tmp.size(),_signature,sizeof(_signature));
return true;
}
return false;
}
int CertificateOfOwnership::verify(const RuntimeEnvironment *RR,void *tPtr) const
{
if ((!_signedBy)||(_signedBy != Network::controllerFor(_networkId)))
@ -46,7 +72,7 @@ int CertificateOfOwnership::verify(const RuntimeEnvironment *RR,void *tPtr) cons
try {
Buffer<(sizeof(CertificateOfOwnership) + 64)> tmp;
this->serialize(tmp,true);
return (id.verify(tmp.data(),tmp.size(),_signature) ? 0 : -1);
return (id.verify(tmp.data(),tmp.size(),_signature,_signatureLength) ? 0 : -1);
} catch ( ... ) {
return -1;
}

View file

@ -107,19 +107,7 @@ public:
return this->_owns(THING_MAC_ADDRESS,tmp,6);
}
inline void addThing(const InetAddress &ip)
{
if (_thingCount >= ZT_CERTIFICATEOFOWNERSHIP_MAX_THINGS) return;
if (ip.ss_family == AF_INET) {
_thingTypes[_thingCount] = THING_IPV4_ADDRESS;
memcpy(_thingValues[_thingCount],&(reinterpret_cast<const struct sockaddr_in *>(&ip)->sin_addr.s_addr),4);
++_thingCount;
} else if (ip.ss_family == AF_INET6) {
_thingTypes[_thingCount] = THING_IPV6_ADDRESS;
memcpy(_thingValues[_thingCount],reinterpret_cast<const struct sockaddr_in6 *>(&ip)->sin6_addr.s6_addr,16);
++_thingCount;
}
}
void addThing(const InetAddress &ip);
inline void addThing(const MAC &mac)
{
@ -133,17 +121,7 @@ public:
* @param signer Signing identity, must have private key
* @return True if signature was successful
*/
inline bool sign(const Identity &signer)
{
if (signer.hasPrivate()) {
Buffer<sizeof(CertificateOfOwnership) + 64> tmp;
_signedBy = signer.address();
this->serialize(tmp,true);
_signature = signer.sign(tmp.data(),tmp.size());
return true;
}
return false;
}
bool sign(const Identity &signer);
/**
* @param RR Runtime environment to allow identity lookup for signedBy
@ -170,9 +148,9 @@ public:
_issuedTo.appendTo(b);
_signedBy.appendTo(b);
if (!forSign) {
b.append((uint8_t)1); // 1 == Ed25519
b.append((uint16_t)ZT_C25519_SIGNATURE_LEN); // length of signature
b.append(_signature.data,ZT_C25519_SIGNATURE_LEN);
b.append((uint8_t)1);
b.append((uint16_t)_signatureLength); // length of signature
b.append(_signature,_signatureLength);
}
b.append((uint16_t)0); // length of additional fields, currently 0
@ -203,10 +181,11 @@ public:
_issuedTo.setTo(b.field(p,ZT_ADDRESS_LENGTH),ZT_ADDRESS_LENGTH); p += ZT_ADDRESS_LENGTH;
_signedBy.setTo(b.field(p,ZT_ADDRESS_LENGTH),ZT_ADDRESS_LENGTH); p += ZT_ADDRESS_LENGTH;
if (b[p++] == 1) {
if (b.template at<uint16_t>(p) != ZT_C25519_SIGNATURE_LEN)
_signatureLength = b.template at<uint16_t>(p);
if (_signatureLength > sizeof(_signature))
throw ZT_EXCEPTION_INVALID_SERIALIZED_DATA_INVALID_CRYPTOGRAPHIC_TOKEN;
p += 2;
memcpy(_signature.data,b.field(p,ZT_C25519_SIGNATURE_LEN),ZT_C25519_SIGNATURE_LEN); p += ZT_C25519_SIGNATURE_LEN;
memcpy(_signature,b.field(p,_signatureLength),_signatureLength); p += _signatureLength;
} else {
p += 2 + b.template at<uint16_t>(p);
}
@ -236,7 +215,8 @@ private:
uint8_t _thingValues[ZT_CERTIFICATEOFOWNERSHIP_MAX_THINGS][ZT_CERTIFICATEOFOWNERSHIP_MAX_THING_VALUE_SIZE];
Address _issuedTo;
Address _signedBy;
C25519::Signature _signature;
unsigned int _signatureLength;
uint8_t _signature[ZT_SIGNATURE_BUFFER_SIZE];
};
} // namespace ZeroTier

View file

@ -60,8 +60,6 @@
#endif
#ifdef __APPLE__
#define likely(x) __builtin_expect((x),1)
#define unlikely(x) __builtin_expect((x),0)
#include <TargetConditionals.h>
#ifndef __UNIX_LIKE__
#define __UNIX_LIKE__
@ -79,7 +77,7 @@
#ifndef __BSD__
#define __BSD__
#endif
#include <machine/endian.h>
#include <sys/endian.h>
#ifndef __BYTE_ORDER
#define __BYTE_ORDER _BYTE_ORDER
#define __LITTLE_ENDIAN _LITTLE_ENDIAN
@ -109,14 +107,14 @@
#endif
#endif
// Define ZT_NO_TYPE_PUNNING to disable reckless casts on anything other than x86/x64.
// Define ZT_NO_TYPE_PUNNING to disable reckless casts on anything other than x86 and x86_64.
#if (!(defined(__amd64__) || defined(__amd64) || defined(__x86_64__) || defined(__x86_64) || defined(_M_AMD64) || defined(_M_X64) || defined(i386) || defined(__i386) || defined(__i386__) || defined(__i486__) || defined(__i586__) || defined(__i686__) || defined(_M_IX86) || defined(__X86__) || defined(_X86_) || defined(__I86__) || defined(__INTEL__) || defined(__386)))
#ifndef ZT_NO_TYPE_PUNNING
#define ZT_NO_TYPE_PUNNING
#endif
#endif
// Assume little endian if not defined
// Assume little endian if not defined on Mac and Windows as these don't run on any BE architectures.
#if (defined(__APPLE__) || defined(__WINDOWS__)) && (!defined(__BYTE_ORDER))
#undef __BYTE_ORDER
#undef __LITTLE_ENDIAN
@ -156,7 +154,7 @@
#endif
#endif
#ifdef __WINDOWS__
#if defined(__WINDOWS__) && !defined(__GNUC__) && !defined (__clang__) && !defined(__INTEL_COMPILER)
#define ZT_PACKED_STRUCT(D) __pragma(pack(push,1)) D __pragma(pack(pop))
#else
#define ZT_PACKED_STRUCT(D) D __attribute__((packed))
@ -178,7 +176,7 @@
#define ZT_ADDRESS_RESERVED_PREFIX 0xff
/**
* Default MTU used for Ethernet tap device
* Default virtual network MTU (not physical)
*/
#define ZT_DEFAULT_MTU 2800
@ -188,17 +186,17 @@
#define ZT_MAX_PACKET_FRAGMENTS 7
/**
* Size of RX queue
* Size of RX queue in packets
*/
#define ZT_RX_QUEUE_SIZE 32
/**
* Size of TX queue
* Size of TX queue in packets
*/
#define ZT_TX_QUEUE_SIZE 32
/**
* Length of secret key in bytes -- 256-bit -- do not change
* Length of peer shared secrets (256-bit, do not change)
*/
#define ZT_PEER_SECRET_KEY_LENGTH 32
@ -232,7 +230,7 @@
*
* The protocol allows up to 7, but we limit it to something smaller.
*/
#define ZT_RELAY_MAX_HOPS 3
#define ZT_RELAY_MAX_HOPS 4
/**
* Expire time for multicast 'likes' and indirect multicast memberships in ms
@ -261,11 +259,6 @@
*/
#define ZT_PING_CHECK_INVERVAL 5000
/**
* How often the local.conf file is checked for changes (service, should be moved there)
*/
#define ZT_LOCAL_CONF_FILE_CHECK_INTERVAL 10000
/**
* How frequently to check for changes to the system's network interfaces. When
* the service decides to use this constant it's because we want to react more
@ -615,6 +608,11 @@
*/
#define ZT_SUPPORT_OLD_STYLE_NETCONF 1
/**
* Size of a buffer to store either a C25519 or an ECC P-384 signature
*/
#define ZT_SIGNATURE_BUFFER_SIZE 96
/**
* Desired buffer size for UDP sockets (used in service and osdep but defined here)
*/
@ -629,6 +627,9 @@
*/
#define ZT_THREAD_MIN_STACK_SIZE 1048576
#define ZT_CRYPTO_ALG_C25519 0
#define ZT_CRYPTO_ALG_P384 1
// Exceptions thrown in core ZT code
#define ZT_EXCEPTION_OUT_OF_BOUNDS 100
#define ZT_EXCEPTION_OUT_OF_MEMORY 101

1363
node/ECC384.cpp Normal file

File diff suppressed because it is too large Load diff

108
node/ECC384.hpp Normal file
View file

@ -0,0 +1,108 @@
/*
* ZeroTier One - Network Virtualization Everywhere
* Copyright (C) 2011-2019 ZeroTier, Inc. https://www.zerotier.com/
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* --
*
* You can be released from the requirements of the license by purchasing
* a commercial license. Buying such a license is mandatory as soon as you
* develop commercial closed-source software that incorporates or links
* directly against ZeroTier software without disclosing the source code
* of your own application.
*/
// This is glue code to ease the use of the NIST P-384 elliptic curve.
// Note that most of the code inside ECC384.cpp is third party code and
// is under the BSD 2-clause license rather than ZeroTier's license.
#ifndef ZT_ECC384_HPP
#define ZT_ECC384_HPP
#include "Constants.hpp"
/**
* Size of a (point compressed) P-384 public key
*/
#define ZT_ECC384_PUBLIC_KEY_SIZE 49
/**
* Size of a P-384 private key
*/
#define ZT_ECC384_PRIVATE_KEY_SIZE 48
/**
* Size of the hash that should be signed using P-384
*/
#define ZT_ECC384_SIGNATURE_HASH_SIZE 48
/**
* Size of a P-384 signature
*/
#define ZT_ECC384_SIGNATURE_SIZE 96
/**
* Size of raw shared secret generated by ECDH key agreement
*/
#define ZT_ECC384_SHARED_SECRET_SIZE 48
namespace ZeroTier {
/**
* Generate a NIST P-384 key pair
*
* @param pub Buffer to receive point compressed public key
* @param priv Buffer to receiver private key
*/
void ECC384GenerateKey(uint8_t pub[ZT_ECC384_PUBLIC_KEY_SIZE],uint8_t priv[ZT_ECC384_PRIVATE_KEY_SIZE]);
/**
* Sign a hash with a NIST P-384 private key
*
* The hash must be 48 bytes in size and is typically the first 48 bytes
* of a SHA512 hash or something similar. Extra bytes of course are ignored.
*
* @param priv Private key
* @param hash 48-byte hash
* @param sig Buffer to receive signature
*/
void ECC384ECDSASign(const uint8_t priv[ZT_ECC384_PRIVATE_KEY_SIZE],const uint8_t hash[ZT_ECC384_SIGNATURE_HASH_SIZE],uint8_t sig[ZT_ECC384_SIGNATURE_SIZE]);
/**
* Verify a signature
*
* @param pub Public key
* @param hash 48-byte hash (usually first 48 bytes of SHA512(msg))
* @param sig Signature to check
* @return True if signature is valid
*/
bool ECC384ECDSAVerify(const uint8_t pub[ZT_ECC384_PUBLIC_KEY_SIZE],const uint8_t hash[ZT_ECC384_SIGNATURE_HASH_SIZE],const uint8_t sig[ZT_ECC384_SIGNATURE_SIZE]);
/**
* Perform ECDH key agreement
*
* The secret generated here is the raw 48-byte result of ECDH.
* It's typically hashed prior to use.
*
* @param theirPub Remote public key
* @param ourPriv Local private key
* @param secret Buffer to receive 48-byte secret
*/
bool ECC384ECDH(const uint8_t theirPub[ZT_ECC384_PUBLIC_KEY_SIZE],const uint8_t ourPriv[ZT_ECC384_PRIVATE_KEY_SIZE],uint8_t secret[ZT_ECC384_SHARED_SECRET_SIZE]);
} // namespace ZeroTier
#endif

View file

@ -35,19 +35,20 @@
#include "Salsa20.hpp"
#include "Utils.hpp"
namespace ZeroTier {
namespace {
// These can't be changed without a new identity type. They define the
// parameters of the hashcash hashing/searching algorithm.
#define ZT_IDENTITY_GEN_HASHCASH_FIRST_BYTE_LESS_THAN 17
#define ZT_IDENTITY_GEN_MEMORY 2097152
namespace ZeroTier {
// A memory-hard composition of SHA-512 and Salsa20 for hashcash hashing
static inline void _computeMemoryHardHash(const void *publicKey,unsigned int publicKeyBytes,void *digest,void *genmem)
static void _computeMemoryHardHash(const void *publicKey,unsigned int publicKeyBytes,void *digest,void *genmem)
{
// Digest publicKey[] to obtain initial digest
SHA512::hash(digest,publicKey,publicKeyBytes);
SHA512(digest,publicKey,publicKeyBytes);
// Initialize genmem[] using Salsa20 in a CBC-like configuration since
// ordinary Salsa20 is randomly seek-able. This is good for a cipher
@ -94,22 +95,36 @@ struct _Identity_generate_cond
char *genmem;
};
void Identity::generate()
{
unsigned char digest[64];
char *genmem = new char[ZT_IDENTITY_GEN_MEMORY];
} // anonymous namespace
void Identity::generate(const Type t)
{
uint8_t digest[64];
char *const genmem = new char[ZT_IDENTITY_GEN_MEMORY];
switch(t) {
case C25519: {
C25519::Pair kp;
do {
kp = C25519::generateSatisfying(_Identity_generate_cond(digest,genmem));
_address.setTo(digest + 59,ZT_ADDRESS_LENGTH); // last 5 bytes are address
} while (_address.isReserved());
_publicKey = kp.pub;
if (!_privateKey)
_privateKey = new C25519::Private();
*_privateKey = kp.priv;
memcpy(_k.t0.pub.data,kp.pub.data,ZT_C25519_PUBLIC_KEY_LEN);
memcpy(_k.t0.priv.data,kp.priv.data,ZT_C25519_PRIVATE_KEY_LEN);
_type = C25519;
_hasPrivate = true;
} break;
case P384: {
do {
ECC384GenerateKey(_k.t1.pub,_k.t1.priv);
_computeMemoryHardHash(_k.t1.pub,ZT_ECC384_PUBLIC_KEY_SIZE,digest,genmem);
if (digest[0] >= ZT_IDENTITY_GEN_HASHCASH_FIRST_BYTE_LESS_THAN)
continue;
_address.setTo(digest + 59,ZT_ADDRESS_LENGTH);
} while (_address.isReserved());
_type = P384;
_hasPrivate = true;
} break;
}
delete [] genmem;
}
@ -117,15 +132,23 @@ bool Identity::locallyValidate() const
{
if (_address.isReserved())
return false;
unsigned char digest[64];
char *genmem = new char[ZT_IDENTITY_GEN_MEMORY];
_computeMemoryHardHash(_publicKey.data,ZT_C25519_PUBLIC_KEY_LEN,digest,genmem);
uint8_t digest[64];
char *genmem = nullptr;
try {
genmem = new char[ZT_IDENTITY_GEN_MEMORY];
switch(_type) {
case C25519:
_computeMemoryHardHash(_k.t0.pub.data,ZT_C25519_PUBLIC_KEY_LEN,digest,genmem);
break;
case P384:
_computeMemoryHardHash(_k.t1.pub,ZT_ECC384_PUBLIC_KEY_SIZE,digest,genmem);
break;
default:
return false;
}
delete [] genmem;
unsigned char addrb[5];
_address.copyTo(addrb,5);
return (
(digest[0] < ZT_IDENTITY_GEN_HASHCASH_FIRST_BYTE_LESS_THAN)&&
(digest[59] == addrb[0])&&
@ -133,26 +156,113 @@ bool Identity::locallyValidate() const
(digest[61] == addrb[2])&&
(digest[62] == addrb[3])&&
(digest[63] == addrb[4]));
} catch ( ... ) {
if (genmem) delete [] genmem;
return false;
}
}
unsigned int Identity::sign(const void *data,unsigned int len,void *sig,unsigned int siglen) const
{
uint8_t h[48];
if (!_hasPrivate)
return 0;
switch(_type) {
case C25519:
if (siglen < ZT_C25519_SIGNATURE_LEN)
return 0;
C25519::sign(_k.t0.priv,_k.t0.pub,data,len,sig);
return ZT_C25519_SIGNATURE_LEN;
case P384:
if (siglen < ZT_ECC384_SIGNATURE_SIZE)
return 0;
SHA384(h,data,len);
ECC384ECDSASign(_k.t1.priv,h,(uint8_t *)sig);
return ZT_ECC384_SIGNATURE_SIZE;
}
return 0;
}
bool Identity::verify(const void *data,unsigned int len,const void *sig,unsigned int siglen) const
{
switch(_type) {
case C25519:
return C25519::verify(_k.t0.pub,data,len,sig,siglen);
case P384:
if (siglen == ZT_ECC384_SIGNATURE_SIZE) {
uint8_t h[48];
SHA384(h,data,len);
return ECC384ECDSAVerify(_k.t1.pub,h,(const uint8_t *)sig);
}
break;
}
return false;
}
bool Identity::agree(const Identity &id,void *key,unsigned int klen) const
{
uint8_t ecc384RawSecret[ZT_ECC384_SHARED_SECRET_SIZE];
uint8_t h[48];
if (_hasPrivate) {
switch(_type) {
case C25519:
C25519::agree(_k.t0.priv,id._k.t0.pub,key,klen);
return true;
case P384:
ECC384ECDH(id._k.t1.pub,_k.t1.priv,ecc384RawSecret);
SHA384(h,ecc384RawSecret,sizeof(ecc384RawSecret));
for(unsigned int i=0,hi=0;i<klen;++i) {
if (hi == 48) {
hi = 0;
SHA384(h,h,48);
}
((uint8_t *)key)[i] = h[hi++];
}
return true;
}
}
return false;
}
char *Identity::toString(bool includePrivate,char buf[ZT_IDENTITY_STRING_BUFFER_LENGTH]) const
{
switch(_type) {
case C25519: {
char *p = buf;
Utils::hex10(_address.toInt(),p);
p += 10;
*(p++) = ':';
*(p++) = '0';
*(p++) = ':';
Utils::hex(_publicKey.data,ZT_C25519_PUBLIC_KEY_LEN,p);
Utils::hex(_k.t0.pub.data,ZT_C25519_PUBLIC_KEY_LEN,p);
p += ZT_C25519_PUBLIC_KEY_LEN * 2;
if ((_privateKey)&&(includePrivate)) {
if ((_hasPrivate)&&(includePrivate)) {
*(p++) = ':';
Utils::hex(_privateKey->data,ZT_C25519_PRIVATE_KEY_LEN,p);
Utils::hex(_k.t0.priv.data,ZT_C25519_PRIVATE_KEY_LEN,p);
p += ZT_C25519_PRIVATE_KEY_LEN * 2;
}
*p = (char)0;
return buf;
}
case P384: {
char *p = buf;
Utils::hex10(_address.toInt(),p);
p += 10;
*(p++) = ':';
*(p++) = '1';
*(p++) = ':';
Utils::hex(_k.t1.pub,ZT_ECC384_PUBLIC_KEY_SIZE,p);
p += ZT_ECC384_PUBLIC_KEY_SIZE * 2;
if ((_hasPrivate)&&(includePrivate)) {
*(p++) = ':';
Utils::hex(_k.t1.priv,ZT_ECC384_PRIVATE_KEY_SIZE,p);
p += ZT_ECC384_PRIVATE_KEY_SIZE * 2;
}
*p = (char)0;
return buf;
} break;
}
}
bool Identity::fromString(const char *str)
{
@ -166,8 +276,7 @@ bool Identity::fromString(const char *str)
return false;
}
delete _privateKey;
_privateKey = (C25519::Private *)0;
_hasPrivate = false;
int fno = 0;
char *saveptr = (char *)0;
@ -181,24 +290,51 @@ bool Identity::fromString(const char *str)
}
break;
case 1:
if ((f[0] != '0')||(f[1])) {
if ((f[0] == '0')&&(!f[1])) {
_type = C25519;
} else if ((f[0] == '1')&&(!f[1])) {
_type = P384;
} else {
_address.zero();
return false;
}
break;
case 2:
if (Utils::unhex(f,_publicKey.data,ZT_C25519_PUBLIC_KEY_LEN) != ZT_C25519_PUBLIC_KEY_LEN) {
switch(_type) {
case C25519:
if (Utils::unhex(f,_k.t0.pub.data,ZT_C25519_PUBLIC_KEY_LEN) != ZT_C25519_PUBLIC_KEY_LEN) {
_address.zero();
return false;
}
break;
case 3:
_privateKey = new C25519::Private();
if (Utils::unhex(f,_privateKey->data,ZT_C25519_PRIVATE_KEY_LEN) != ZT_C25519_PRIVATE_KEY_LEN) {
case P384:
if (Utils::unhex(f,_k.t1.pub,ZT_ECC384_PUBLIC_KEY_SIZE) != ZT_ECC384_PUBLIC_KEY_SIZE) {
_address.zero();
return false;
}
break;
}
break;
case 3:
switch(_type) {
case C25519:
if (Utils::unhex(f,_k.t0.priv.data,ZT_C25519_PRIVATE_KEY_LEN) != ZT_C25519_PRIVATE_KEY_LEN) {
_address.zero();
return false;
} else {
_hasPrivate = true;
}
break;
case P384:
if (Utils::unhex(f,_k.t1.priv,ZT_ECC384_PRIVATE_KEY_SIZE) != ZT_ECC384_PRIVATE_KEY_SIZE) {
_address.zero();
return false;
} else {
_hasPrivate = true;
}
break;
}
break;
default:
_address.zero();
return false;

View file

@ -36,6 +36,7 @@
#include "C25519.hpp"
#include "Buffer.hpp"
#include "SHA512.hpp"
#include "ECC384.hpp"
#define ZT_IDENTITY_STRING_BUFFER_LENGTH 384
@ -54,61 +55,50 @@ namespace ZeroTier {
class Identity
{
public:
Identity() :
_privateKey((C25519::Private *)0)
/**
* Identity type -- numeric values of these enums are protocol constants
*/
enum Type
{
}
C25519 = ZT_CRYPTO_ALG_C25519, // Type 0 -- Curve25519 and Ed25519 (1.0 and 2.0, default)
P384 = ZT_CRYPTO_ALG_P384 // Type 1 -- NIST P-384 ECDH and ECDSA (2.0+ only)
};
Identity(const Identity &id) :
_address(id._address),
_publicKey(id._publicKey),
_privateKey((id._privateKey) ? new C25519::Private(*(id._privateKey)) : (C25519::Private *)0)
{
}
Identity() { memset(reinterpret_cast<void *>(this),0,sizeof(Identity)); }
Identity(const Identity &id) { memcpy(reinterpret_cast<void *>(this),&id,sizeof(Identity)); }
Identity(const char *str) :
_privateKey((C25519::Private *)0)
Identity(const char *str)
{
if (!fromString(str))
throw ZT_EXCEPTION_INVALID_SERIALIZED_DATA_INVALID_TYPE;
}
template<unsigned int C>
Identity(const Buffer<C> &b,unsigned int startAt = 0) :
_privateKey((C25519::Private *)0)
{
deserialize(b,startAt);
}
Identity(const Buffer<C> &b,unsigned int startAt = 0) { deserialize(b,startAt); }
~Identity()
{
if (_privateKey) {
Utils::burn(_privateKey,sizeof(C25519::Private));
delete _privateKey;
}
}
~Identity() { Utils::burn(reinterpret_cast<void *>(this),sizeof(Identity)); }
inline void zero() { Utils::burn(reinterpret_cast<void *>(this),sizeof(Identity)); }
inline Identity &operator=(const Identity &id)
{
_address = id._address;
_publicKey = id._publicKey;
if (id._privateKey) {
if (!_privateKey)
_privateKey = new C25519::Private();
*_privateKey = *(id._privateKey);
} else {
delete _privateKey;
_privateKey = (C25519::Private *)0;
}
memcpy(reinterpret_cast<void *>(this),&id,sizeof(Identity));
return *this;
}
/**
* @return Identity type
*/
inline Type type() const { return _type; }
/**
* Generate a new identity (address, key pair)
*
* This is a time consuming operation.
*
* @param t Type of identity to generate
*/
void generate();
void generate(const Type t);
/**
* Check the validity of this identity's pairing of key to address
@ -120,7 +110,7 @@ public:
/**
* @return True if this identity contains a private key
*/
inline bool hasPrivate() const { return (_privateKey != (C25519::Private *)0); }
inline bool hasPrivate() const { return _hasPrivate; }
/**
* Compute the SHA512 hash of our private key (if we have one)
@ -130,9 +120,36 @@ public:
*/
inline bool sha512PrivateKey(void *sha) const
{
if (_privateKey) {
SHA512::hash(sha,_privateKey->data,ZT_C25519_PRIVATE_KEY_LEN);
if (_hasPrivate) {
switch(_type) {
case C25519:
SHA512(sha,_k.t0.priv.data,ZT_C25519_PRIVATE_KEY_LEN);
return true;
case P384:
SHA512(sha,_k.t1.priv,ZT_ECC384_PRIVATE_KEY_SIZE);
return true;
}
}
return false;
}
/**
* Compute the SHA512 hash of our public key
*
* @param sha Buffer to receive hash bytes
* @return True on success, false if identity is empty or invalid
*/
inline bool sha512PublicKey(void *sha) const
{
if (_hasPrivate) {
switch(_type) {
case C25519:
SHA512(sha,_k.t0.pub.data,ZT_C25519_PUBLIC_KEY_LEN);
return true;
case P384:
SHA512(sha,_k.t1.pub,ZT_ECC384_PUBLIC_KEY_SIZE);
return true;
}
}
return false;
}
@ -140,15 +157,16 @@ public:
/**
* Sign a message with this identity (private key required)
*
* The signature buffer should be large enough for the largest
* signature, which is currently 96 bytes.
*
* @param data Data to sign
* @param len Length of data
* @param sig Buffer to receive signature
* @param siglen Length of buffer
* @return Number of bytes actually written to sig or 0 on error
*/
inline C25519::Signature sign(const void *data,unsigned int len) const
{
if (_privateKey)
return C25519::sign(*_privateKey,_publicKey,data,len);
throw ZT_EXCEPTION_PRIVATE_KEY_REQUIRED;
}
unsigned int sign(const void *data,unsigned int len,void *sig,unsigned int siglen) const;
/**
* Verify a message signature against this identity
@ -159,25 +177,7 @@ public:
* @param siglen Length of signature in bytes
* @return True if signature validates and data integrity checks
*/
inline bool verify(const void *data,unsigned int len,const void *signature,unsigned int siglen) const
{
if (siglen != ZT_C25519_SIGNATURE_LEN)
return false;
return C25519::verify(_publicKey,data,len,signature);
}
/**
* Verify a message signature against this identity
*
* @param data Data to check
* @param len Length of data
* @param signature Signature
* @return True if signature validates and data integrity checks
*/
inline bool verify(const void *data,unsigned int len,const C25519::Signature &signature) const
{
return C25519::verify(_publicKey,data,len,signature);
}
bool verify(const void *data,unsigned int len,const void *sig,unsigned int siglen) const;
/**
* Shortcut method to perform key agreement with another identity
@ -189,14 +189,7 @@ public:
* @param klen Length of key in bytes
* @return Was agreement successful?
*/
inline bool agree(const Identity &id,void *key,unsigned int klen) const
{
if (_privateKey) {
C25519::agree(*_privateKey,id._publicKey,key,klen);
return true;
}
return false;
}
bool agree(const Identity &id,void *key,unsigned int klen) const;
/**
* @return This identity's address
@ -214,12 +207,31 @@ public:
inline void serialize(Buffer<C> &b,bool includePrivate = false) const
{
_address.appendTo(b);
b.append((uint8_t)0); // C25519/Ed25519 identity type
b.append(_publicKey.data,ZT_C25519_PUBLIC_KEY_LEN);
if ((_privateKey)&&(includePrivate)) {
b.append((unsigned char)ZT_C25519_PRIVATE_KEY_LEN);
b.append(_privateKey->data,ZT_C25519_PRIVATE_KEY_LEN);
} else b.append((unsigned char)0);
switch(_type) {
case C25519:
b.append((uint8_t)C25519);
b.append(_k.t0.pub.data,ZT_C25519_PUBLIC_KEY_LEN);
if ((_hasPrivate)&&(includePrivate)) {
b.append((uint8_t)ZT_C25519_PRIVATE_KEY_LEN);
b.append(_k.t0.priv.data,ZT_C25519_PRIVATE_KEY_LEN);
} else {
b.append((uint8_t)0);
}
break;
case P384:
b.append((uint8_t)P384);
b.append(_k.t1.pub,ZT_ECC384_PUBLIC_KEY_SIZE);
if ((_hasPrivate)&&(includePrivate)) {
b.append((uint8_t)ZT_ECC384_PRIVATE_KEY_SIZE);
b.append(_k.t1.priv,ZT_ECC384_PRIVATE_KEY_SIZE);
} else {
b.append((uint8_t)0);
}
break;
}
}
/**
@ -237,27 +249,51 @@ public:
template<unsigned int C>
inline unsigned int deserialize(const Buffer<C> &b,unsigned int startAt = 0)
{
delete _privateKey;
_privateKey = (C25519::Private *)0;
_hasPrivate = false;
unsigned int p = startAt;
unsigned int pkl;
_address.setTo(b.field(p,ZT_ADDRESS_LENGTH),ZT_ADDRESS_LENGTH);
p += ZT_ADDRESS_LENGTH;
if (b[p++] != 0)
_type = (Type)b[p++];
switch(_type) {
case C25519:
memcpy(_k.t0.pub.data,b.field(p,ZT_C25519_PUBLIC_KEY_LEN),ZT_C25519_PUBLIC_KEY_LEN);
p += ZT_C25519_PUBLIC_KEY_LEN;
pkl = (unsigned int)b[p++];
if (pkl) {
if (pkl != ZT_C25519_PRIVATE_KEY_LEN)
throw ZT_EXCEPTION_INVALID_SERIALIZED_DATA_INVALID_CRYPTOGRAPHIC_TOKEN;
_hasPrivate = true;
memcpy(_k.t0.priv.data,b.field(p,ZT_C25519_PRIVATE_KEY_LEN),ZT_C25519_PRIVATE_KEY_LEN);
p += ZT_C25519_PRIVATE_KEY_LEN;
} else {
memset(_k.t0.priv.data,0,ZT_C25519_PRIVATE_KEY_LEN);
_hasPrivate = false;
}
break;
case P384:
memcpy(_k.t0.pub.data,b.field(p,ZT_ECC384_PUBLIC_KEY_SIZE),ZT_ECC384_PUBLIC_KEY_SIZE);
p += ZT_ECC384_PUBLIC_KEY_SIZE;
pkl = (unsigned int)b[p++];
if (pkl) {
if (pkl != ZT_ECC384_PRIVATE_KEY_SIZE)
throw ZT_EXCEPTION_INVALID_SERIALIZED_DATA_INVALID_CRYPTOGRAPHIC_TOKEN;
_hasPrivate = true;
memcpy(_k.t1.priv,b.field(p,ZT_ECC384_PRIVATE_KEY_SIZE),ZT_ECC384_PRIVATE_KEY_SIZE);
p += ZT_ECC384_PRIVATE_KEY_SIZE;
} else {
memset(_k.t1.priv,0,ZT_ECC384_PRIVATE_KEY_SIZE);
_hasPrivate = false;
}
break;
default:
throw ZT_EXCEPTION_INVALID_SERIALIZED_DATA_INVALID_TYPE;
memcpy(_publicKey.data,b.field(p,ZT_C25519_PUBLIC_KEY_LEN),ZT_C25519_PUBLIC_KEY_LEN);
p += ZT_C25519_PUBLIC_KEY_LEN;
unsigned int privateKeyLength = (unsigned int)b[p++];
if (privateKeyLength) {
if (privateKeyLength != ZT_C25519_PRIVATE_KEY_LEN)
throw ZT_EXCEPTION_INVALID_SERIALIZED_DATA_INVALID_CRYPTOGRAPHIC_TOKEN;
_privateKey = new C25519::Private();
memcpy(_privateKey->data,b.field(p,ZT_C25519_PRIVATE_KEY_LEN),ZT_C25519_PRIVATE_KEY_LEN);
p += ZT_C25519_PRIVATE_KEY_LEN;
}
return (p - startAt);
@ -283,40 +319,64 @@ public:
*/
bool fromString(const char *str);
/**
* @return C25519 public key
*/
inline const C25519::Public &publicKey() const { return _publicKey; }
/**
* @return C25519 key pair (only returns valid pair if private key is present in this Identity object)
*/
inline const C25519::Pair privateKeyPair() const
{
C25519::Pair pair;
pair.pub = _publicKey;
if (_privateKey)
pair.priv = *_privateKey;
else memset(pair.priv.data,0,ZT_C25519_PRIVATE_KEY_LEN);
return pair;
}
/**
* @return True if this identity contains something
*/
inline operator bool() const { return (_address); }
inline bool operator==(const Identity &id) const { return ((_address == id._address)&&(memcmp(_publicKey.data,id._publicKey.data,ZT_C25519_PUBLIC_KEY_LEN) == 0)); }
inline bool operator<(const Identity &id) const { return ((_address < id._address)||((_address == id._address)&&(memcmp(_publicKey.data,id._publicKey.data,ZT_C25519_PUBLIC_KEY_LEN) < 0))); }
inline bool operator==(const Identity &id) const
{
if ((_address == id._address)&&(_type == id._type)) {
switch(_type) {
case C25519:
return (memcmp(_k.t0.pub.data,id._k.t0.pub.data,ZT_C25519_PUBLIC_KEY_LEN) == 0);
case P384:
return (memcmp(_k.t1.pub,id._k.t1.pub,ZT_ECC384_PUBLIC_KEY_SIZE) == 0);
default:
return false;
}
}
return false;
}
inline bool operator<(const Identity &id) const
{
if (_address < id._address)
return true;
if (_address == id._address) {
if ((int)_type < (int)id._type)
return true;
if (_type == id._type) {
switch(_type) {
case C25519:
return (memcmp(_k.t0.pub.data,id._k.t0.pub.data,ZT_C25519_PUBLIC_KEY_LEN) < 0);
case P384:
return (memcmp(_k.t1.pub,id._k.t1.pub,ZT_ECC384_PUBLIC_KEY_SIZE) < 0);
}
}
}
return false;
}
inline bool operator!=(const Identity &id) const { return !(*this == id); }
inline bool operator>(const Identity &id) const { return (id < *this); }
inline bool operator<=(const Identity &id) const { return !(id < *this); }
inline bool operator>=(const Identity &id) const { return !(*this < id); }
inline unsigned long hashCode() const { return (unsigned long)_address.toInt(); }
private:
Address _address;
C25519::Public _publicKey;
C25519::Private *_privateKey;
union {
struct {
C25519::Public pub;
C25519::Private priv;
} t0;
struct {
uint8_t pub[ZT_ECC384_PUBLIC_KEY_SIZE];
uint8_t priv[ZT_ECC384_PRIVATE_KEY_SIZE];
} t1;
} _k;
Type _type;
bool _hasPrivate;
};
} // namespace ZeroTier

View file

@ -28,6 +28,8 @@
#include <string.h>
#include <stdlib.h>
#include <list>
#include "../version.h"
#include "../include/ZeroTierOne.h"
@ -41,7 +43,6 @@
#include "SelfAwareness.hpp"
#include "Salsa20.hpp"
#include "SHA512.hpp"
#include "World.hpp"
#include "Node.hpp"
#include "CertificateOfMembership.hpp"
#include "Capability.hpp"
@ -168,13 +169,14 @@ bool IncomingPacket::_doERROR(const RuntimeEnvironment *RR,void *tPtr,const Shar
break;
case Packet::ERROR_IDENTITY_COLLISION:
// FIXME: for federation this will need a payload with a signature or something.
// This is a trusted upstream telling us our 5-digit ID is taken. This
// causes the node to generate another.
if (RR->topology->isUpstream(peer->identity()))
RR->node->postEvent(tPtr,ZT_EVENT_FATAL_ERROR_IDENTITY_COLLISION);
break;
case Packet::ERROR_NEED_MEMBERSHIP_CERTIFICATE: {
// Peers can send this in response to frames if they do not have a recent enough COM from us
// Peers can send this to ask for a cert for a network.
networkId = at<uint64_t>(ZT_PROTO_VERB_ERROR_IDX_PAYLOAD);
const SharedPtr<Network> network(RR->node->network(networkId));
const int64_t now = RR->node->now();
@ -365,30 +367,6 @@ bool IncomingPacket::_doHELLO(const RuntimeEnvironment *RR,void *tPtr,const bool
RR->sa->iam(tPtr,id.address(),_path->localSocket(),_path->address(),externalSurfaceAddress,RR->topology->isUpstream(id),now);
}
// Get primary planet world ID and world timestamp if present
uint64_t planetWorldId = 0;
uint64_t planetWorldTimestamp = 0;
if ((ptr + 16) <= size()) {
planetWorldId = at<uint64_t>(ptr); ptr += 8;
planetWorldTimestamp = at<uint64_t>(ptr); ptr += 8;
}
std::vector< std::pair<uint64_t,uint64_t> > moonIdsAndTimestamps;
if (ptr < size()) {
// Remainder of packet, if present, is encrypted
cryptField(peer->key(),ptr,size() - ptr);
// Get moon IDs and timestamps if present
if ((ptr + 2) <= size()) {
const unsigned int numMoons = at<uint16_t>(ptr); ptr += 2;
for(unsigned int i=0;i<numMoons;++i) {
if ((World::Type)(*this)[ptr++] == World::TYPE_MOON)
moonIdsAndTimestamps.push_back(std::pair<uint64_t,uint64_t>(at<uint64_t>(ptr),at<uint64_t>(ptr + 8)));
ptr += 16;
}
}
}
// Send OK(HELLO) with an echo of the packet's timestamp and some of the same
// information about us: version, sent-to address, etc.
@ -432,25 +410,6 @@ bool IncomingPacket::_doHELLO(const RuntimeEnvironment *RR,void *tPtr,const bool
tmpa.serialize(outp);
}
const unsigned int worldUpdateSizeAt = outp.size();
outp.addSize(2); // make room for 16-bit size field
if ((planetWorldId)&&(RR->topology->planetWorldTimestamp() > planetWorldTimestamp)&&(planetWorldId == RR->topology->planetWorldId())) {
RR->topology->planet().serialize(outp,false);
}
if (moonIdsAndTimestamps.size() > 0) {
std::vector<World> moons(RR->topology->moons());
for(std::vector<World>::const_iterator m(moons.begin());m!=moons.end();++m) {
for(std::vector< std::pair<uint64_t,uint64_t> >::const_iterator i(moonIdsAndTimestamps.begin());i!=moonIdsAndTimestamps.end();++i) {
if (i->first == m->id()) {
if (m->timestamp() > i->second)
m->serialize(outp,false);
break;
}
}
}
}
outp.setAt<uint16_t>(worldUpdateSizeAt,(uint16_t)(outp.size() - (worldUpdateSizeAt + 2)));
outp.armor(peer->key(),true);
_path->send(RR,tPtr,outp.data(),outp.size(),now);
@ -486,22 +445,6 @@ bool IncomingPacket::_doOK(const RuntimeEnvironment *RR,void *tPtr,const SharedP
// Get reported external surface address if present
if (ptr < size())
ptr += externalSurfaceAddress.deserialize(*this,ptr);
// Handle planet or moon updates if present
if ((ptr + 2) <= size()) {
const unsigned int worldsLen = at<uint16_t>(ptr); ptr += 2;
if (RR->topology->shouldAcceptWorldUpdateFrom(peer->address())) {
const unsigned int endOfWorlds = ptr + worldsLen;
while (ptr < endOfWorlds) {
World w;
ptr += w.deserialize(*this,ptr);
RR->topology->addWorld(tPtr,w,false);
}
} else {
ptr += worldsLen;
}
}
if (!hops()) {
_path->updateLatency((unsigned int)latency,RR->node->now());
}
@ -572,8 +515,9 @@ bool IncomingPacket::_doOK(const RuntimeEnvironment *RR,void *tPtr,const SharedP
bool IncomingPacket::_doWHOIS(const RuntimeEnvironment *RR,void *tPtr,const SharedPtr<Peer> &peer)
{
if ((!RR->topology->amUpstream())&&(!peer->rateGateInboundWhoisRequest(RR->node->now())))
return true;
// TODO
//if ((!RR->topology->amUpstream())&&(!peer->rateGateInboundWhoisRequest(RR->node->now())))
// return true;
Packet outp(peer->address(),RR->identity.address(),Packet::VERB_OK);
outp.append((unsigned char)Packet::VERB_WHOIS);
@ -769,8 +713,8 @@ bool IncomingPacket::_doMULTICAST_LIKE(const RuntimeEnvironment *RR,void *tPtr,c
SharedPtr<Network> network(RR->node->network(nwid));
if (network)
authorized = network->gate(tPtr,peer);
if (!authorized)
authorized = ((RR->topology->amUpstream())||(RR->node->localControllerHasAuthorized(now,nwid,peer->address())));
//if (!authorized)
// authorized = ((RR->topology->amUpstream())||(RR->node->localControllerHasAuthorized(now,nwid,peer->address())));
}
if (authorized)
RR->mc->add(tPtr,now,nwid,MulticastGroup(MAC(field(ptr + 8,6),6),at<uint32_t>(ptr + 14)),peer->address());
@ -979,7 +923,8 @@ bool IncomingPacket::_doMULTICAST_GATHER(const RuntimeEnvironment *RR,void *tPtr
}
const int64_t now = RR->node->now();
if ((gatherLimit > 0)&&((trustEstablished)||(RR->topology->amUpstream())||(RR->node->localControllerHasAuthorized(now,nwid,peer->address())))) {
//if ((gatherLimit > 0)&&((trustEstablished)||(RR->topology->amUpstream())||(RR->node->localControllerHasAuthorized(now,nwid,peer->address())))) {
if (gatherLimit) {
Packet outp(peer->address(),RR->identity.address(),Packet::VERB_OK);
outp.append((unsigned char)Packet::VERB_MULTICAST_GATHER);
outp.append(packetId());
@ -1000,18 +945,16 @@ bool IncomingPacket::_doMULTICAST_GATHER(const RuntimeEnvironment *RR,void *tPtr
bool IncomingPacket::_doMULTICAST_FRAME(const RuntimeEnvironment *RR,void *tPtr,const SharedPtr<Peer> &peer)
{
const uint64_t nwid = at<uint64_t>(ZT_PROTO_VERB_MULTICAST_FRAME_IDX_NETWORK_ID);
const unsigned int flags = (*this)[ZT_PROTO_VERB_MULTICAST_FRAME_IDX_FLAGS];
unsigned int offset = ZT_PACKET_IDX_PAYLOAD;
const uint64_t nwid = at<uint64_t>(offset); offset += 8;
const unsigned int flags = (*this)[offset]; ++offset;
const SharedPtr<Network> network(RR->node->network(nwid));
if (network) {
// Offset -- size of optional fields added to position of later fields
unsigned int offset = 0;
if ((flags & 0x01) != 0) {
// This is deprecated but may still be sent by old peers
CertificateOfMembership com;
offset += com.deserialize(*this,ZT_PROTO_VERB_MULTICAST_FRAME_IDX_COM);
offset += com.deserialize(*this,offset);
if (com)
network->addCredential(tPtr,com);
}
@ -1023,60 +966,87 @@ bool IncomingPacket::_doMULTICAST_FRAME(const RuntimeEnvironment *RR,void *tPtr,
unsigned int gatherLimit = 0;
if ((flags & 0x02) != 0) {
gatherLimit = at<uint32_t>(offset + ZT_PROTO_VERB_MULTICAST_FRAME_IDX_GATHER_LIMIT);
offset += 4;
gatherLimit = at<uint32_t>(offset); offset += 4;
}
MAC from;
if ((flags & 0x04) != 0) {
from.setTo(field(offset + ZT_PROTO_VERB_MULTICAST_FRAME_IDX_SOURCE_MAC,6),6);
offset += 6;
from.setTo(field(offset,6),6); offset += 6;
} else {
from.fromAddress(peer->address(),nwid);
}
const MulticastGroup to(MAC(field(offset + ZT_PROTO_VERB_MULTICAST_FRAME_IDX_DEST_MAC,6),6),at<uint32_t>(offset + ZT_PROTO_VERB_MULTICAST_FRAME_IDX_DEST_ADI));
const unsigned int etherType = at<uint16_t>(offset + ZT_PROTO_VERB_MULTICAST_FRAME_IDX_ETHERTYPE);
const unsigned int frameLen = size() - (offset + ZT_PROTO_VERB_MULTICAST_FRAME_IDX_FRAME);
const unsigned int recipientsOffset = offset;
std::list<Address> recipients;
if ((flags & 0x08) != 0) {
const unsigned int rc = at<uint16_t>(offset); offset += 2;
for(unsigned int i=0;i<rc;++i) {
const Address a(field(offset,5),5);
if ((a != peer->address())&&(a != RR->identity.address())) {
recipients.push_back(a);
}
offset += 5;
}
}
const unsigned int afterRecipientsOffset = offset;
const MulticastGroup to(MAC(field(offset,6),6),at<uint32_t>(offset + 6)); offset += 10;
const unsigned int etherType = at<uint16_t>(offset); offset += 2;
const unsigned int frameLen = size() - offset;
if (network->config().multicastLimit == 0) {
RR->t->incomingNetworkFrameDropped(tPtr,network,_path,packetId(),size(),peer->address(),Packet::VERB_MULTICAST_FRAME,from,to.mac(),"multicast disabled");
peer->received(tPtr,_path,hops(),packetId(),payloadLength(),Packet::VERB_MULTICAST_FRAME,0,Packet::VERB_NOP,false,nwid);
peer->received(tPtr,_path,hops(),packetId(),payloadLength(),Packet::VERB_MULTICAST_FRAME,0,Packet::VERB_NOP,true,nwid);
return true;
}
if ((frameLen > 0)&&(frameLen <= ZT_MAX_MTU)) {
if (!to.mac().isMulticast()) {
RR->t->incomingPacketInvalid(tPtr,_path,packetId(),source(),hops(),Packet::VERB_MULTICAST_FRAME,"destination not multicast");
peer->received(tPtr,_path,hops(),packetId(),payloadLength(),Packet::VERB_MULTICAST_FRAME,0,Packet::VERB_NOP,true,nwid); // trustEstablished because COM is okay
peer->received(tPtr,_path,hops(),packetId(),payloadLength(),Packet::VERB_MULTICAST_FRAME,0,Packet::VERB_NOP,true,nwid);
return true;
}
if ((!from)||(from.isMulticast())||(from == network->mac())) {
RR->t->incomingPacketInvalid(tPtr,_path,packetId(),source(),hops(),Packet::VERB_MULTICAST_FRAME,"invalid source MAC");
peer->received(tPtr,_path,hops(),packetId(),payloadLength(),Packet::VERB_MULTICAST_FRAME,0,Packet::VERB_NOP,true,nwid); // trustEstablished because COM is okay
peer->received(tPtr,_path,hops(),packetId(),payloadLength(),Packet::VERB_MULTICAST_FRAME,0,Packet::VERB_NOP,true,nwid);
return true;
}
const uint8_t *const frameData = (const uint8_t *)field(offset + ZT_PROTO_VERB_MULTICAST_FRAME_IDX_FRAME,frameLen);
if ((flags & 0x08)&&(network->config().isMulticastReplicator(RR->identity.address())))
RR->mc->send(tPtr,RR->node->now(),network,peer->address(),to,from,etherType,frameData,frameLen);
if (from != MAC(peer->address(),nwid)) {
if (network->config().permitsBridging(peer->address())) {
network->learnBridgeRoute(from,peer->address());
} else {
RR->t->incomingNetworkFrameDropped(tPtr,network,_path,packetId(),size(),peer->address(),Packet::VERB_MULTICAST_FRAME,from,to.mac(),"bridging not allowed (remote)");
peer->received(tPtr,_path,hops(),packetId(),payloadLength(),Packet::VERB_MULTICAST_FRAME,0,Packet::VERB_NOP,true,nwid); // trustEstablished because COM is okay
return true;
}
}
if (network->filterIncomingPacket(tPtr,peer,RR->identity.address(),from,to.mac(),frameData,frameLen,etherType,0) > 0)
if ((frameLen > 0)&&(frameLen <= ZT_MAX_MTU)) {
const uint8_t *const frameData = ((const uint8_t *)unsafeData()) + offset;
if (network->filterIncomingPacket(tPtr,peer,RR->identity.address(),from,to.mac(),frameData,frameLen,etherType,0) > 0) {
RR->node->putFrame(tPtr,nwid,network->userPtr(),from,to.mac(),etherType,0,(const void *)frameData,frameLen);
}
}
if (gatherLimit) {
if (!recipients.empty()) {
const std::vector<Address> anchors = network->config().anchors();
const bool amAnchor = (std::find(anchors.begin(),anchors.end(),RR->identity.address()) != anchors.end());
for(std::list<Address>::iterator ra(recipients.begin());ra!=recipients.end();) {
SharedPtr<Peer> recipient(RR->topology->getPeer(tPtr,*ra));
if ((recipient)&&((recipient->remoteVersionProtocol() < 10)||(amAnchor))) {
Packet outp(*ra,RR->identity.address(),Packet::VERB_MULTICAST_FRAME);
outp.append(field(ZT_PACKET_IDX_PAYLOAD,recipientsOffset - ZT_PACKET_IDX_PAYLOAD),recipientsOffset - ZT_PACKET_IDX_PAYLOAD);
outp.append(field(afterRecipientsOffset,size() - afterRecipientsOffset),size() - afterRecipientsOffset);
RR->sw->send(tPtr,outp,true);
recipients.erase(ra++);
} else ++ra;
}
if (!recipients.empty()) {
Packet outp(recipients.front(),RR->identity.address(),Packet::VERB_MULTICAST_FRAME);
recipients.pop_front();
outp.append(field(ZT_PACKET_IDX_PAYLOAD,recipientsOffset - ZT_PACKET_IDX_PAYLOAD),recipientsOffset - ZT_PACKET_IDX_PAYLOAD);
if (!recipients.empty()) {
outp.append((uint16_t)recipients.size());
for(std::list<Address>::iterator ra(recipients.begin());ra!=recipients.end();++ra)
ra->appendTo(outp);
}
outp.append(field(afterRecipientsOffset,size() - afterRecipientsOffset),size() - afterRecipientsOffset);
RR->sw->send(tPtr,outp,true);
}
}
if (gatherLimit) { // DEPRECATED but still supported
Packet outp(source(),RR->identity.address(),Packet::VERB_OK);
outp.append((unsigned char)Packet::VERB_MULTICAST_FRAME);
outp.append(packetId());
@ -1091,12 +1061,11 @@ bool IncomingPacket::_doMULTICAST_FRAME(const RuntimeEnvironment *RR,void *tPtr,
}
peer->received(tPtr,_path,hops(),packetId(),payloadLength(),Packet::VERB_MULTICAST_FRAME,0,Packet::VERB_NOP,true,nwid);
return true;
} else {
_sendErrorNeedCredentials(RR,tPtr,peer,nwid);
return false;
}
return true;
}
bool IncomingPacket::_doPUSH_DIRECT_PATHS(const RuntimeEnvironment *RR,void *tPtr,const SharedPtr<Peer> &peer)

257
node/Locator.hpp Normal file
View file

@ -0,0 +1,257 @@
/*
* ZeroTier One - Network Virtualization Everywhere
* Copyright (C) 2011-2019 ZeroTier, Inc. https://www.zerotier.com/
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* --
*
* You can be released from the requirements of the license by purchasing
* a commercial license. Buying such a license is mandatory as soon as you
* develop commercial closed-source software that incorporates or links
* directly against ZeroTier software without disclosing the source code
* of your own application.
*/
#ifndef ZT_LOCATOR_HPP
#define ZT_LOCATOR_HPP
#include "Constants.hpp"
#include "Identity.hpp"
#include "InetAddress.hpp"
#include "Utils.hpp"
#include "Buffer.hpp"
#include "SHA512.hpp"
#include "Str.hpp"
#include <algorithm>
#include <vector>
#define ZT_LOCATOR_MAX_PHYSICAL_ADDRESSES 255
#define ZT_LOCATOR_MAX_VIRTUAL_ADDRESSES 255
namespace ZeroTier {
/**
* Signed information about a node's location on the network
*
* A locator can be stored in DNS as a series of TXT records with a DNS name
* that includes a public key that can be used to validate the locator's
* signature. That way DNS records can't be spoofed even if no DNSSEC or
* anything else is present to secure DNS.
*/
class Locator
{
public:
Locator() : _signatureLength(0) {}
inline const std::vector<InetAddress> &phy() const { return _physical; }
inline const std::vector<Identity> &virt() const { return _virtual; }
inline void add(const InetAddress &ip)
{
if (_physical.size() < ZT_LOCATOR_MAX_PHYSICAL_ADDRESSES)
_physical.push_back(ip);
}
inline void add(const Identity &zt)
{
if (_virtual.size() < ZT_LOCATOR_MAX_VIRTUAL_ADDRESSES)
_virtual.push_back(zt);
}
inline void finish(const Identity &id,const int64_t ts)
{
_ts = ts;
_id = id;
std::sort(_physical.begin(),_physical.end());
_physical.erase(std::unique(_physical.begin(),_physical.end()),_physical.end());
std::sort(_virtual.begin(),_virtual.end());
_virtual.erase(std::unique(_virtual.begin(),_virtual.end()),_virtual.end());
}
inline bool sign(const Identity &signingId)
{
if (!signingId.hasPrivate())
return false;
if (signingId == _id) {
_signedBy.zero();
} else {
_signedBy = signingId;
}
Buffer<65536> *tmp = new Buffer<65536>();
try {
serialize(*tmp,true);
_signatureLength = signingId.sign(tmp->data(),tmp->size(),_signature,ZT_SIGNATURE_BUFFER_SIZE);
delete tmp;
return (_signatureLength > 0);
} catch ( ... ) {
delete tmp;
return false;
}
}
inline bool verify() const
{
if ((_signatureLength == 0)||(_signatureLength > sizeof(_signature)))
return false;
Buffer<65536> *tmp = nullptr;
try {
tmp = new Buffer<65536>();
serialize(*tmp,true);
const bool ok = (_signedBy) ? _signedBy.verify(tmp->data(),tmp->size(),_signature,_signatureLength) : _id.verify(tmp->data(),tmp->size(),_signature,_signatureLength);
delete tmp;
return ok;
} catch ( ... ) {
if (tmp) delete tmp;
return false;
}
}
inline std::vector<Str> makeTxtRecords(const uint8_t p384SigningKeyPublic[ZT_ECC384_PUBLIC_KEY_SIZE],const uint8_t p384SigningKeyPrivate[ZT_ECC384_PUBLIC_KEY_SIZE])
{
uint8_t s384[48],dnsSig[ZT_ECC384_SIGNATURE_SIZE];
char enc[256];
Buffer<65536> *const tmp = new Buffer<65536>();
serialize(*tmp,false);
SHA384(s384,tmp->data(),tmp->size());
ECC384ECDSASign(p384SigningKeyPrivate,s384,dnsSig);
tmp->append(dnsSig,ZT_ECC384_SIGNATURE_SIZE);
// Blob must be broken into multiple TXT records that must remain sortable so they are prefixed by a hex value.
// 186-byte chunks yield 248-byte base64 chunks which leaves some margin below the limit of 255.
std::vector<Str> txtRecords;
for(unsigned int p=0;p<tmp->size();p+=186) {
unsigned int rem = tmp->size() - p;
if (rem > 186) rem = 186;
Utils::b64e(((const uint8_t *)tmp->data()) + p,rem,enc,sizeof(enc));
txtRecords.push_back(Str());
txtRecords.back() << Utils::HEXCHARS[(p >> 4) & 0xf] << Utils::HEXCHARS[p & 0xf] << enc;
}
delete tmp;
return txtRecords;
}
template<typename I>
inline bool decodeTxtRecords(I start,I end,const uint8_t p384SigningKeyPublic[ZT_ECC384_PUBLIC_KEY_SIZE])
{
uint8_t dec[256],s384[48];
Buffer<65536> *tmp = nullptr;
try {
tmp = new Buffer<65536>();
while (start != end) {
tmp->append(dec,Utils::b64d(start->c_str(),dec,sizeof(dec)));
++start;
}
if (tmp->size() <= ZT_ECC384_SIGNATURE_SIZE) {
delete tmp;
return false;
}
SHA384(s384,tmp->data(),tmp->size() - ZT_ECC384_SIGNATURE_SIZE);
if (!ECC384ECDSAVerify(p384SigningKeyPublic,s384,((const uint8_t *)tmp->data()) + (tmp->size() - ZT_ECC384_SIGNATURE_SIZE))) {
delete tmp;
return false;
}
deserialize(*tmp,0);
delete tmp;
return verify();
} catch ( ... ) {
if (tmp) delete tmp;
return false;
}
}
template<unsigned int C>
inline void serialize(Buffer<C> &b,const bool forSign = false) const
{
if (forSign) b.append((uint64_t)0x7f7f7f7f7f7f7f7fULL);
b.append((uint8_t)0); // version/flags, currently 0
b.append((uint64_t)_ts);
_id.serialise(b,false);
if (_signedBy) {
b.append((uint8_t)1); // number of signers, current max is 1
_signedBy.serialize(b,false);
} else {
b.append((uint8_t)0); // signer is _id
}
b.append((uint8_t)_physical.size());
for(std::vector<InetAddress>::const_iterator i(_physical.begin());i!=_physical.end();++i)
i->serialize(b);
b.append((uint8_t)_virtual.size());
for(std::vector<Identity>::const_iterator i(_virtual.begin());i!=_virtual.end();++i)
i->serialize(b,false);
if (!forSign) {
b.append((uint16_t)_signatureLength);
b.append(_signature,_signatureLength);
}
b.append((uint16_t)0); // length of additional fields, currently 0
if (forSign) b.append((uint64_t)0x7f7f7f7f7f7f7f7fULL);
}
template<unsigned int C>
inline unsigned int deserialize(const Buffer<C> &b,unsigned int startAt = 0)
{
unsigned int p = startAt;
if (b[p++] != 0)
throw ZT_EXCEPTION_INVALID_SERIALIZED_DATA_INVALID_TYPE;
_ts = (int64_t)b.template at<uint64_t>(p); p += 8;
p += _id.deserialize(b,p);
const unsigned int signerCount = b[p++];
if (signerCount > 1)
throw ZT_EXCEPTION_INVALID_SERIALIZED_DATA_OVERFLOW;
if (signerCount == 1) {
p += _signedBy.deserialize(b,p);
} else {
_signedBy.zero();
}
const unsigned int physicalCount = b[p++];
_physical.resize(physicalCount);
for(unsigned int i=0;i<physicalCount;++i)
p += _physical[i].deserialize(b,p);
const unsigned int virtualCount = b[p++];
_virtual.resize(virtualCount);
for(unsigned int i=0;i<virtualCount;++i)
p += _virtual[i].deserialize(b,p);
_signatureLen = b.template at<uint16_t>(p); p += 2;
if (_signatureLength > ZT_SIGNATURE_BUFFER_SIZE)
throw ZT_EXCEPTION_INVALID_SERIALIZED_DATA_OVERFLOW;
memcpy(_signature,b.field(p,_signatureLength),_signatureLength);
p += _signatureLength;
p += b.template at<uint16_t>(p); p += 2;
if (p > b.size())
throw ZT_EXCEPTION_INVALID_SERIALIZED_DATA_OVERFLOW;
return (p - startAt);
}
private:
int64_t _ts;
Identity _id;
Identity _signedBy; // signed by _id if nil/zero
std::vector<InetAddress> _physical;
std::vector<Identity> _virtual;
unsigned int _signatureLength;
uint8_t _signature[ZT_SIGNATURE_BUFFER_SIZE];
};
} // namespace ZeroTier
#endif

View file

@ -108,9 +108,9 @@ public:
*/
inline bool isAllowedOnNetwork(const NetworkConfig &nconf) const
{
if (nconf.isPublic()) return true;
if (_com.timestamp() <= _comRevocationThreshold) return false;
return nconf.com.agreesWith(_com);
if (nconf.isPublic()) return true; // public network
if (_com.timestamp() <= _comRevocationThreshold) return false; // COM has been revoked
return nconf.com.agreesWith(_com); // check timestamp agreement window
}
inline bool recentlyAssociated(const int64_t now) const
@ -119,7 +119,7 @@ public:
}
/**
* Check whether the peer represented by this Membership owns a given resource
* Check whether the peer represented by this Membership owns a given address
*
* @tparam Type of resource: InetAddress or MAC
* @param nconf Our network config
@ -127,8 +127,10 @@ public:
* @return True if this peer has a certificate of ownership for the given resource
*/
template<typename T>
inline bool hasCertificateOfOwnershipFor(const NetworkConfig &nconf,const T &r) const
inline bool peerOwnsAddress(const NetworkConfig &nconf,const T &r) const
{
if (_isUnspoofableAddress(nconf,r))
return true;
uint32_t *k = (uint32_t *)0;
CertificateOfOwnership *v = (CertificateOfOwnership *)0;
Hashtable< uint32_t,CertificateOfOwnership >::Iterator i(*(const_cast< Hashtable< uint32_t,CertificateOfOwnership> *>(&_remoteCoos)));
@ -136,7 +138,7 @@ public:
if (_isCredentialTimestampValid(nconf,*v)&&(v->owns(r)))
return true;
}
return _isV6NDPEmulated(nconf,r);
return false;
}
/**
@ -152,29 +154,10 @@ public:
return (((t)&&(_isCredentialTimestampValid(nconf,*t))) ? t : (Tag *)0);
}
/**
* Validate and add a credential if signature is okay and it's otherwise good
*/
AddCredentialResult addCredential(const RuntimeEnvironment *RR,void *tPtr,const NetworkConfig &nconf,const CertificateOfMembership &com);
/**
* Validate and add a credential if signature is okay and it's otherwise good
*/
AddCredentialResult addCredential(const RuntimeEnvironment *RR,void *tPtr,const NetworkConfig &nconf,const Tag &tag);
/**
* Validate and add a credential if signature is okay and it's otherwise good
*/
AddCredentialResult addCredential(const RuntimeEnvironment *RR,void *tPtr,const NetworkConfig &nconf,const Capability &cap);
/**
* Validate and add a credential if signature is okay and it's otherwise good
*/
AddCredentialResult addCredential(const RuntimeEnvironment *RR,void *tPtr,const NetworkConfig &nconf,const CertificateOfOwnership &coo);
/**
* Validate and add a credential if signature is okay and it's otherwise good
*/
AddCredentialResult addCredential(const RuntimeEnvironment *RR,void *tPtr,const NetworkConfig &nconf,const Revocation &rev);
/**
@ -186,20 +169,29 @@ public:
void clean(const int64_t now,const NetworkConfig &nconf);
/**
* Generates a key for the internal use in indexing credentials by type and credential ID
* Generates a key for internal use in indexing credentials by type and credential ID
*/
static uint64_t credentialKey(const Credential::Type &t,const uint32_t i) { return (((uint64_t)t << 32) | (uint64_t)i); }
private:
inline bool _isV6NDPEmulated(const NetworkConfig &nconf,const MAC &m) const { return false; }
inline bool _isV6NDPEmulated(const NetworkConfig &nconf,const InetAddress &ip) const
// This returns true if a resource is an IPv6 NDP-emulated address. These embed the ZT
// address of the peer and therefore cannot be spoofed, causing peerOwnsAddress() to
// always return true for them. A certificate is not required for these.
inline bool _isUnspoofableAddress(const NetworkConfig &nconf,const MAC &m) const { return false; }
inline bool _isUnspoofableAddress(const NetworkConfig &nconf,const InetAddress &ip) const
{
if ((ip.isV6())&&(nconf.ndpEmulation())&&((InetAddress::makeIpv66plane(nconf.networkId,nconf.issuedTo.toInt()).ipsEqual(ip))||(InetAddress::makeIpv6rfc4193(nconf.networkId,nconf.issuedTo.toInt()).ipsEqual(ip)))) {
return true;
}
return false;
return (
(ip.ss_family == AF_INET6)&&
(nconf.ndpEmulation())&&
(
(InetAddress::makeIpv66plane(nconf.networkId,nconf.issuedTo.toInt()).ipsEqual(ip))||
(InetAddress::makeIpv6rfc4193(nconf.networkId,nconf.issuedTo.toInt()).ipsEqual(ip))
)
);
}
// This compares the remote credential's timestamp to the timestamp in our network config
// plus or minus the permitted maximum timestamp delta.
template<typename C>
inline bool _isCredentialTimestampValid(const NetworkConfig &nconf,const C &remoteCredential) const
{

View file

@ -31,6 +31,7 @@
#include "MAC.hpp"
#include "InetAddress.hpp"
#include "Utils.hpp"
namespace ZeroTier {

View file

@ -170,51 +170,6 @@ void Multicaster::send(
unsigned long idxbuf[4096];
unsigned long *indexes = idxbuf;
// If we're in hub-and-spoke designated multicast replication mode, see if we
// have a multicast replicator active. If so, pick the best and send it
// there. If we are a multicast replicator or if none are alive, fall back
// to sender replication. Note that bridges do not do this since this would
// break bridge route learning. This is sort of an edge case limitation of
// the current protocol and could be fixed, but fixing it would add more
// complexity than the fix is probably worth. Bridges are generally high
// bandwidth nodes.
if (!network->config().isActiveBridge(RR->identity.address())) {
Address multicastReplicators[ZT_MAX_NETWORK_SPECIALISTS];
const unsigned int multicastReplicatorCount = network->config().multicastReplicators(multicastReplicators);
if (multicastReplicatorCount) {
if (std::find(multicastReplicators,multicastReplicators + multicastReplicatorCount,RR->identity.address()) == (multicastReplicators + multicastReplicatorCount)) {
SharedPtr<Peer> bestMulticastReplicator;
SharedPtr<Path> bestMulticastReplicatorPath;
unsigned int bestMulticastReplicatorLatency = 0xffff;
for(unsigned int i=0;i<multicastReplicatorCount;++i) {
const SharedPtr<Peer> p(RR->topology->getPeerNoCache(multicastReplicators[i]));
if ((p)&&(p->isAlive(now))) {
const SharedPtr<Path> pp(p->getAppropriatePath(now,false));
if ((pp)&&(pp->latency() < bestMulticastReplicatorLatency)) {
bestMulticastReplicatorLatency = pp->latency();
bestMulticastReplicatorPath = pp;
bestMulticastReplicator = p;
}
}
}
if (bestMulticastReplicator) {
Packet outp(bestMulticastReplicator->address(),RR->identity.address(),Packet::VERB_MULTICAST_FRAME);
outp.append((uint64_t)network->id());
outp.append((uint8_t)0x0c); // includes source MAC | please replicate
((src) ? src : MAC(RR->identity.address(),network->id())).appendTo(outp);
mg.mac().appendTo(outp);
outp.append((uint32_t)mg.adi());
outp.append((uint16_t)etherType);
outp.append(data,len);
if (!network->config().disableCompression()) outp.compress();
outp.armor(bestMulticastReplicator->key(),true);
bestMulticastReplicatorPath->send(RR,tPtr,outp.data(),outp.size(),now);
return;
}
}
}
}
try {
Mutex::Lock _l(_groups_m);
MulticastGroupStatus &gs = _groups[Multicaster::Key(network->id(),mg)];

View file

@ -399,9 +399,9 @@ static _doZtFilterResult _doZtFilter(
}
if (inbound) {
if (membership) {
if ((src)&&(membership->hasCertificateOfOwnershipFor<InetAddress>(nconf,src)))
if ((src)&&(membership->peerOwnsAddress<InetAddress>(nconf,src)))
ownershipVerificationMask |= ZT_RULE_PACKET_CHARACTERISTICS_SENDER_IP_AUTHENTICATED;
if (membership->hasCertificateOfOwnershipFor<MAC>(nconf,macSource))
if (membership->peerOwnsAddress<MAC>(nconf,macSource))
ownershipVerificationMask |= ZT_RULE_PACKET_CHARACTERISTICS_SENDER_MAC_AUTHENTICATED;
}
} else {
@ -1467,23 +1467,9 @@ void Network::_sendUpdatesToMembers(void *tPtr,const MulticastGroup *const newMu
}
std::sort(alwaysAnnounceTo.begin(),alwaysAnnounceTo.end());
for(std::vector<Address>::const_iterator a(alwaysAnnounceTo.begin());a!=alwaysAnnounceTo.end();++a) {
/*
// push COM to non-members so they can do multicast request auth
if ( (_config.com) && (!_memberships.contains(*a)) && (*a != RR->identity.address()) ) {
Packet outp(*a,RR->identity.address(),Packet::VERB_NETWORK_CREDENTIALS);
_config.com.serialize(outp);
outp.append((uint8_t)0x00);
outp.append((uint16_t)0); // no capabilities
outp.append((uint16_t)0); // no tags
outp.append((uint16_t)0); // no revocations
outp.append((uint16_t)0); // no certificates of ownership
RR->sw->send(tPtr,outp,true);
}
*/
for(std::vector<Address>::const_iterator a(alwaysAnnounceTo.begin());a!=alwaysAnnounceTo.end();++a)
_announceMulticastGroupsTo(tPtr,*a,groups);
}
}
{
Address *a = (Address *)0;

View file

@ -98,11 +98,6 @@
*/
#define ZT_NETWORKCONFIG_SPECIALIST_TYPE_ANCHOR 0x0000040000000000ULL
/**
* Designated multicast replicators replicate multicast in place of sender-side replication
*/
#define ZT_NETWORKCONFIG_SPECIALIST_TYPE_MULTICAST_REPLICATOR 0x0000080000000000ULL
namespace ZeroTier {
// Dictionary capacity needed for max size network config
@ -339,40 +334,11 @@ public:
return r;
}
inline std::vector<Address> multicastReplicators() const
{
std::vector<Address> r;
for(unsigned int i=0;i<specialistCount;++i) {
if ((specialists[i] & ZT_NETWORKCONFIG_SPECIALIST_TYPE_MULTICAST_REPLICATOR) != 0)
r.push_back(Address(specialists[i]));
}
return r;
}
inline unsigned int multicastReplicators(Address mr[ZT_MAX_NETWORK_SPECIALISTS]) const
{
unsigned int c = 0;
for(unsigned int i=0;i<specialistCount;++i) {
if ((specialists[i] & ZT_NETWORKCONFIG_SPECIALIST_TYPE_MULTICAST_REPLICATOR) != 0)
mr[c++] = specialists[i];
}
return c;
}
inline bool isMulticastReplicator(const Address &a) const
{
for(unsigned int i=0;i<specialistCount;++i) {
if (((specialists[i] & ZT_NETWORKCONFIG_SPECIALIST_TYPE_MULTICAST_REPLICATOR) != 0)&&(a == specialists[i]))
return true;
}
return false;
}
inline std::vector<Address> alwaysContactAddresses() const
{
std::vector<Address> r;
for(unsigned int i=0;i<specialistCount;++i) {
if ((specialists[i] & (ZT_NETWORKCONFIG_SPECIALIST_TYPE_ANCHOR | ZT_NETWORKCONFIG_SPECIALIST_TYPE_MULTICAST_REPLICATOR)) != 0)
if ((specialists[i] & ZT_NETWORKCONFIG_SPECIALIST_TYPE_ANCHOR) != 0)
r.push_back(Address(specialists[i]));
}
return r;
@ -382,7 +348,7 @@ public:
{
unsigned int c = 0;
for(unsigned int i=0;i<specialistCount;++i) {
if ((specialists[i] & (ZT_NETWORKCONFIG_SPECIALIST_TYPE_ANCHOR | ZT_NETWORKCONFIG_SPECIALIST_TYPE_MULTICAST_REPLICATOR)) != 0)
if ((specialists[i] & ZT_NETWORKCONFIG_SPECIALIST_TYPE_ANCHOR) != 0)
ac[c++] = specialists[i];
}
return c;
@ -391,7 +357,7 @@ public:
inline void alwaysContactAddresses(Hashtable< Address,std::vector<InetAddress> > &a) const
{
for(unsigned int i=0;i<specialistCount;++i) {
if ((specialists[i] & (ZT_NETWORKCONFIG_SPECIALIST_TYPE_ANCHOR | ZT_NETWORKCONFIG_SPECIALIST_TYPE_MULTICAST_REPLICATOR)) != 0) {
if ((specialists[i] & ZT_NETWORKCONFIG_SPECIALIST_TYPE_ANCHOR) != 0) {
a[Address(specialists[i])];
}
}

View file

@ -93,7 +93,7 @@ Node::Node(void *uptr,void *tptr,const struct ZT_Node_Callbacks *callbacks,int64
}
if (n <= 0) {
RR->identity.generate();
RR->identity.generate(Identity::C25519);
RR->identity.toString(false,RR->publicIdentityStr);
RR->identity.toString(true,RR->secretIdentityStr);
idtmp[0] = RR->identity.address().toInt(); idtmp[1] = 0;
@ -192,16 +192,17 @@ ZT_ResultCode Node::processVirtualNetworkFrame(
} else return ZT_RESULT_ERROR_NETWORK_NOT_FOUND;
}
// Closure used to ping upstream and active/online peers
class _PingPeersThatNeedPing
// Function object used to traverse the peer list, check peer status, and ping
// those that need pinging.
struct _PingPeersThatNeedPing
{
public:
_PingPeersThatNeedPing(const RuntimeEnvironment *renv,void *tPtr,Hashtable< Address,std::vector<InetAddress> > &alwaysContact,int64_t now) :
RR(renv),
_tPtr(tPtr),
_alwaysContact(alwaysContact),
_now(now),
_bestCurrentUpstream(RR->topology->getUpstreamPeer())
_bestCurrentUpstream(RR->topology->getUpstreamPeer()),
online(false)
{
}
@ -209,6 +210,7 @@ public:
{
const std::vector<InetAddress> *const alwaysContactEndpoints = _alwaysContact.get(p->address());
if (alwaysContactEndpoints) {
online |= p->isAlive(_now);
const unsigned int sent = p->doPingAndKeepalive(_tPtr,_now);
bool contacted = (sent != 0);
@ -246,12 +248,13 @@ public:
}
}
private:
const RuntimeEnvironment *RR;
void *_tPtr;
Hashtable< Address,std::vector<InetAddress> > &_alwaysContact;
const int64_t _now;
const SharedPtr<Peer> _bestCurrentUpstream;
bool online;
};
ZT_ResultCode Node::processBackgroundTasks(void *tptr,int64_t now,volatile int64_t *nextBackgroundTaskDeadline)
@ -265,47 +268,25 @@ ZT_ResultCode Node::processBackgroundTasks(void *tptr,int64_t now,volatile int64
try {
_lastPingCheck = now;
// Get designated VL1 upstreams
Hashtable< Address,std::vector<InetAddress> > alwaysContact;
RR->topology->getUpstreamsToContact(alwaysContact);
// Uncomment to dump stats
/*
for(unsigned int i=0;i<32;i++) {
if (_stats.inVerbCounts[i] > 0)
printf("%.2x\t%12lld %lld\n",i,(unsigned long long)_stats.inVerbCounts[i],(unsigned long long)_stats.inVerbBytes[i]);
}
printf("\n");
*/
// Check last receive time on designated upstreams to see if we seem to be online
int64_t lastReceivedFromUpstream = 0;
{
Hashtable< Address,std::vector<InetAddress> >::Iterator i(alwaysContact);
Address *upstreamAddress = (Address *)0;
std::vector<InetAddress> *upstreamStableEndpoints = (std::vector<InetAddress> *)0;
while (i.next(upstreamAddress,upstreamStableEndpoints)) {
SharedPtr<Peer> p(RR->topology->getPeerNoCache(*upstreamAddress));
if (p)
lastReceivedFromUpstream = std::max(p->lastReceive(),lastReceivedFromUpstream);
}
}
// Clean up any old local controller auth memorizations.
// Clean up any old local controller auth memoizations. This is an
// optimization for network controllers to know whether to accept
// or trust nodes without doing an extra cert check.
{
_localControllerAuthorizations_m.lock();
Hashtable< _LocalControllerAuth,int64_t >::Iterator i(_localControllerAuthorizations);
_LocalControllerAuth *k = (_LocalControllerAuth *)0;
int64_t *v = (int64_t *)0;
while (i.next(k,v)) {
if ((*v - now) > (ZT_NETWORK_AUTOCONF_DELAY * 3))
if ((*v - now) > (ZT_NETWORK_AUTOCONF_DELAY * 3)) {
_localControllerAuthorizations.erase(*k);
}
}
_localControllerAuthorizations_m.unlock();
}
// Get peers we should stay connected to according to network configs
// Also get networks and whether they need config so we only have to do one pass over networks
// (1) Get peers we should remain connected to and (2) get networks that need config.
Hashtable< Address,std::vector<InetAddress> > alwaysContact;
RR->topology->getUpstreamsToContact(alwaysContact);
std::vector< std::pair< SharedPtr<Network>,bool > > networkConfigNeeded;
{
Mutex::Lock l(_networks_m);
@ -340,7 +321,7 @@ ZT_ResultCode Node::processBackgroundTasks(void *tptr,int64_t now,volatile int64
// Update online status, post status change as event
const bool oldOnline = _online;
_online = (((now - lastReceivedFromUpstream) < ZT_PEER_ACTIVITY_TIMEOUT)||(RR->topology->amUpstream()));
_online = pfunc.online;
if (oldOnline != _online)
postEvent(tptr,_online ? ZT_EVENT_ONLINE : ZT_EVENT_OFFLINE);
} catch ( ... ) {
@ -434,18 +415,6 @@ ZT_ResultCode Node::multicastUnsubscribe(uint64_t nwid,uint64_t multicastGroup,u
} else return ZT_RESULT_ERROR_NETWORK_NOT_FOUND;
}
ZT_ResultCode Node::orbit(void *tptr,uint64_t moonWorldId,uint64_t moonSeed)
{
RR->topology->addMoon(tptr,moonWorldId,Address(moonSeed));
return ZT_RESULT_OK;
}
ZT_ResultCode Node::deorbit(void *tptr,uint64_t moonWorldId)
{
RR->topology->removeMoon(tptr,moonWorldId);
return ZT_RESULT_OK;
}
uint64_t Node::address() const
{
return RR->identity.address().toInt();
@ -644,16 +613,6 @@ ZT_ResultCode Node::setPhysicalPathConfiguration(const struct sockaddr_storage *
return ZT_RESULT_OK;
}
World Node::planet() const
{
return RR->topology->planet();
}
std::vector<World> Node::moons() const
{
return RR->topology->moons();
}
void Node::ncSendConfig(uint64_t nwid,uint64_t requestPacketId,const Address &destination,const NetworkConfig &nc,bool sendLegacyFormatConfig)
{
_localControllerAuthorizations_m.lock();
@ -691,10 +650,11 @@ void Node::ncSendConfig(uint64_t nwid,uint64_t requestPacketId,const Address &de
outp.append((uint32_t)totalSize);
outp.append((uint32_t)chunkIndex);
C25519::Signature sig(RR->identity.sign(reinterpret_cast<const uint8_t *>(outp.data()) + sigStart,outp.size() - sigStart));
uint8_t sig[256];
const unsigned int siglen = RR->identity.sign(reinterpret_cast<const uint8_t *>(outp.data()) + sigStart,outp.size() - sigStart,sig,sizeof(sig));
outp.append((uint8_t)1);
outp.append((uint16_t)ZT_C25519_SIGNATURE_LEN);
outp.append(sig.data,ZT_C25519_SIGNATURE_LEN);
outp.append((uint16_t)siglen);
outp.append(sig,siglen);
outp.compress();
RR->sw->send((void *)0,outp,true);
@ -888,24 +848,6 @@ enum ZT_ResultCode ZT_Node_multicastUnsubscribe(ZT_Node *node,uint64_t nwid,uint
}
}
enum ZT_ResultCode ZT_Node_orbit(ZT_Node *node,void *tptr,uint64_t moonWorldId,uint64_t moonSeed)
{
try {
return reinterpret_cast<ZeroTier::Node *>(node)->orbit(tptr,moonWorldId,moonSeed);
} catch ( ... ) {
return ZT_RESULT_FATAL_ERROR_INTERNAL;
}
}
enum ZT_ResultCode ZT_Node_deorbit(ZT_Node *node,void *tptr,uint64_t moonWorldId)
{
try {
return reinterpret_cast<ZeroTier::Node *>(node)->deorbit(tptr,moonWorldId);
} catch ( ... ) {
return ZT_RESULT_FATAL_ERROR_INTERNAL;
}
}
uint64_t ZT_Node_address(ZT_Node *node)
{
return reinterpret_cast<ZeroTier::Node *>(node)->address();

View file

@ -54,8 +54,6 @@
namespace ZeroTier {
class World;
/**
* Implementation of Node object as defined in CAPI
*
@ -99,8 +97,6 @@ public:
ZT_ResultCode leave(uint64_t nwid,void **uptr,void *tptr);
ZT_ResultCode multicastSubscribe(void *tptr,uint64_t nwid,uint64_t multicastGroup,unsigned long multicastAdi);
ZT_ResultCode multicastUnsubscribe(uint64_t nwid,uint64_t multicastGroup,unsigned long multicastAdi);
ZT_ResultCode orbit(void *tptr,uint64_t moonWorldId,uint64_t moonSeed);
ZT_ResultCode deorbit(void *tptr,uint64_t moonWorldId);
uint64_t address() const;
void status(ZT_NodeStatus *status) const;
ZT_PeerList *peers() const;
@ -194,9 +190,6 @@ public:
uint64_t prng();
ZT_ResultCode setPhysicalPathConfiguration(const struct sockaddr_storage *pathNetwork,const ZT_PhysicalPathConfiguration *pathConfig);
World planet() const;
std::vector<World> moons() const;
inline const Identity &identity() const { return _RR.identity; }
/**

View file

@ -972,16 +972,6 @@ bool Packet::dearmor(const void *key)
}
}
void Packet::cryptField(const void *key,unsigned int start,unsigned int len)
{
uint8_t *const data = reinterpret_cast<uint8_t *>(unsafeData());
uint8_t iv[8];
for(int i=0;i<8;++i) iv[i] = data[i];
iv[7] &= 0xf8; // mask off least significant 3 bits of packet ID / IV since this is unset when this function gets called
Salsa20 s20(key,iv);
s20.crypt12(data + start,data + start,len);
}
bool Packet::compress()
{
char *const data = reinterpret_cast<char *>(unsafeData());

View file

@ -68,10 +68,13 @@
* + Tags and Capabilities
* + Inline push of CertificateOfMembership deprecated
* 9 - 1.2.0 ... 1.2.14
* 10 - 1.4.0 ... CURRENT
* 10 - 1.4.0 ... 1.6.0
* + Multipath capability and load balancing
* 11 - 1.6.0 ... CURRENT
* + Peer-to-peer multicast replication (optional)
* + Old planet/moon stuff is DEAD!
*/
#define ZT_PROTO_VERSION 10
#define ZT_PROTO_VERSION 11
/**
* Minimum supported protocol version
@ -309,17 +312,6 @@
#define ZT_PROTO_VERB_MULTICAST_GATHER_IDX_GATHER_LIMIT (ZT_PROTO_VERB_MULTICAST_GATHER_IDX_ADI + 4)
#define ZT_PROTO_VERB_MULTICAST_GATHER_IDX_COM (ZT_PROTO_VERB_MULTICAST_GATHER_IDX_GATHER_LIMIT + 4)
// Note: COM, GATHER_LIMIT, and SOURCE_MAC are optional, and so are specified without size
#define ZT_PROTO_VERB_MULTICAST_FRAME_IDX_NETWORK_ID (ZT_PACKET_IDX_PAYLOAD)
#define ZT_PROTO_VERB_MULTICAST_FRAME_IDX_FLAGS (ZT_PROTO_VERB_MULTICAST_FRAME_IDX_NETWORK_ID + 8)
#define ZT_PROTO_VERB_MULTICAST_FRAME_IDX_COM (ZT_PROTO_VERB_MULTICAST_FRAME_IDX_FLAGS + 1)
#define ZT_PROTO_VERB_MULTICAST_FRAME_IDX_GATHER_LIMIT (ZT_PROTO_VERB_MULTICAST_FRAME_IDX_FLAGS + 1)
#define ZT_PROTO_VERB_MULTICAST_FRAME_IDX_SOURCE_MAC (ZT_PROTO_VERB_MULTICAST_FRAME_IDX_FLAGS + 1)
#define ZT_PROTO_VERB_MULTICAST_FRAME_IDX_DEST_MAC (ZT_PROTO_VERB_MULTICAST_FRAME_IDX_FLAGS + 1)
#define ZT_PROTO_VERB_MULTICAST_FRAME_IDX_DEST_ADI (ZT_PROTO_VERB_MULTICAST_FRAME_IDX_DEST_MAC + 6)
#define ZT_PROTO_VERB_MULTICAST_FRAME_IDX_ETHERTYPE (ZT_PROTO_VERB_MULTICAST_FRAME_IDX_DEST_ADI + 4)
#define ZT_PROTO_VERB_MULTICAST_FRAME_IDX_FRAME (ZT_PROTO_VERB_MULTICAST_FRAME_IDX_ETHERTYPE + 2)
#define ZT_PROTO_VERB_HELLO__OK__IDX_TIMESTAMP (ZT_PROTO_VERB_OK_IDX_PAYLOAD)
#define ZT_PROTO_VERB_HELLO__OK__IDX_PROTOCOL_VERSION (ZT_PROTO_VERB_HELLO__OK__IDX_TIMESTAMP + 8)
#define ZT_PROTO_VERB_HELLO__OK__IDX_MAJOR_VERSION (ZT_PROTO_VERB_HELLO__OK__IDX_PROTOCOL_VERSION + 1)
@ -542,22 +534,9 @@ public:
* <[8] timestamp for determining latency>
* <[...] binary serialized identity (see Identity)>
* <[...] physical destination address of packet>
* <[8] 64-bit world ID of current planet>
* <[8] 64-bit timestamp of current planet>
* [... remainder if packet is encrypted using cryptField() ...]
* <[2] 16-bit number of moons>
* [<[1] 8-bit type ID of moon>]
* [<[8] 64-bit world ID of moon>]
* [<[8] 64-bit timestamp of moon>]
* [... additional moon type/ID/timestamp tuples ...]
*
* HELLO is sent in the clear as it is how peers share their identity
* public keys. A few additional fields are sent in the clear too, but
* these are things that are public info or are easy to determine. As
* of 1.2.0 we have added a few more fields, but since these could have
* the potential to be sensitive we introduced the encryption of the
* remainder of the packet. See cryptField(). Packet MAC is still
* performed of course, so authentication occurs as normal.
* public keys.
*
* Destination address is the actual wire address to which the packet
* was sent. See InetAddress::serialize() for format.
@ -569,15 +548,10 @@ public:
* <[1] software minor version>
* <[2] software revision>
* <[...] physical destination address of packet>
* <[2] 16-bit length of world update(s) or 0 if none>
* [[...] updates to planets and/or moons]
*
* With the exception of the timestamp, the other fields pertain to the
* respondent who is sending OK and are not echoes.
*
* Note that OK is fully encrypted so no selective cryptField() of
* potentially sensitive fields is needed.
*
* ERROR has no payload.
*/
VERB_HELLO = 0x01,
@ -710,10 +684,6 @@ public:
* controllers and root servers. In the current network, root servers
* will provide the service of final multicast cache.
*
* VERB_NETWORK_CREDENTIALS should be pushed along with this, especially
* if using upstream (e.g. root) nodes as multicast databases. This allows
* GATHERs to be authenticated.
*
* OK/ERROR are not generated.
*/
VERB_MULTICAST_LIKE = 0x09,
@ -832,19 +802,11 @@ public:
* [<[...] network certificate of membership>]
*
* Flags:
* 0x01 - COM is attached
*
* This message asks a peer for additional known endpoints that have
* LIKEd a given multicast group. It's sent when the sender wishes
* to send multicast but does not have the desired number of recipient
* peers.
* 0x01 - COM is attached (DEPRECATED)
*
* More than one OK response can occur if the response is broken up across
* multiple packets or if querying a clustered node.
*
* The COM should be included so that upstream nodes that are not
* members of our network can validate our request.
*
* OK response payload:
* <[8] 64-bit network ID>
* <[6] MAC address of multicast group being queried>
@ -864,6 +826,8 @@ public:
* <[1] flags>
* [<[4] 32-bit implicit gather limit>]
* [<[6] source MAC>]
* [<[2] number of explicitly specified recipients>]
* [<[...] series of 5-byte explicitly specified recipients>]
* <[6] destination MAC (multicast address)>
* <[4] 32-bit multicast ADI (multicast address extension)>
* <[2] 16-bit ethertype>
@ -871,15 +835,12 @@ public:
*
* Flags:
* 0x01 - Network certificate of membership attached (DEPRECATED)
* 0x02 - Implicit gather limit field is present
* 0x02 - Implicit gather limit field is present (DEPRECATED)
* 0x04 - Source MAC is specified -- otherwise it's computed from sender
* 0x08 - Please replicate (sent to multicast replicators)
* 0x08 - Explicit recipient list included for P2P/HS replication
*
* OK and ERROR responses are optional. OK may be generated if there are
* implicit gather results or if the recipient wants to send its own
* updated certificate of network membership to the sender. ERROR may be
* generated if a certificate is needed or if multicasts to this group
* are no longer wanted (multicast unsubscribe).
* Explicit recipient lists are used for peer to peer or hub and spoke
* replication.
*
* OK response payload:
* <[8] 64-bit network ID>
@ -1004,10 +965,6 @@ public:
* be sent to observers configured at the network level for those that
* pertain directly to activity on a network, or to global observers if
* locally configured.
*
* The instance ID is a random 64-bit value generated by each ZeroTier
* node on startup. This is helpful in identifying traces from different
* members of a cluster.
*/
VERB_REMOTE_TRACE = 0x15
};
@ -1295,21 +1252,6 @@ public:
*/
bool dearmor(const void *key);
/**
* Encrypt/decrypt a separately armored portion of a packet
*
* This is currently only used to mask portions of HELLO as an extra
* security precaution since most of that message is sent in the clear.
*
* This must NEVER be used more than once in the same packet, as doing
* so will result in re-use of the same key stream.
*
* @param key 32-byte key
* @param start Start of encrypted portion
* @param len Length of encrypted portion
*/
void cryptField(const void *key,unsigned int start,unsigned int len);
/**
* Attempt to compress payload if not already (must be unencrypted)
*

View file

@ -711,27 +711,6 @@ void Peer::sendHELLO(void *tPtr,const int64_t localSocket,const InetAddress &atA
RR->identity.serialize(outp,false);
atAddress.serialize(outp);
outp.append((uint64_t)RR->topology->planetWorldId());
outp.append((uint64_t)RR->topology->planetWorldTimestamp());
const unsigned int startCryptedPortionAt = outp.size();
std::vector<World> moons(RR->topology->moons());
std::vector<uint64_t> moonsWanted(RR->topology->moonsWanted());
outp.append((uint16_t)(moons.size() + moonsWanted.size()));
for(std::vector<World>::const_iterator m(moons.begin());m!=moons.end();++m) {
outp.append((uint8_t)m->type());
outp.append((uint64_t)m->id());
outp.append((uint64_t)m->timestamp());
}
for(std::vector<uint64_t>::const_iterator m(moonsWanted.begin());m!=moonsWanted.end();++m) {
outp.append((uint8_t)World::TYPE_MOON);
outp.append(*m);
outp.append((uint64_t)0);
}
outp.cryptField(_key,startCryptedPortionAt,outp.size() - startCryptedPortionAt);
RR->node->expectReplyTo(outp.packetId());
if (atAddress) {

View file

@ -540,7 +540,8 @@ public:
/**
* @return Whether this peer is reachable via an aggregate link
*/
inline bool hasAggregateLink() {
inline bool hasAggregateLink()
{
return _localMultipathSupported && _remoteMultipathSupported && _remotePeerMultipathEnabled;
}

View file

@ -34,6 +34,18 @@
namespace ZeroTier {
bool Revocation::sign(const Identity &signer)
{
if (signer.hasPrivate()) {
Buffer<sizeof(Revocation) + 64> tmp;
_signedBy = signer.address();
this->serialize(tmp,true);
_signatureLength = signer.sign(tmp.data(),tmp.size(),_signature,sizeof(_signature));
return true;
}
return false;
}
int Revocation::verify(const RuntimeEnvironment *RR,void *tPtr) const
{
if ((!_signedBy)||(_signedBy != Network::controllerFor(_networkId)))
@ -46,7 +58,7 @@ int Revocation::verify(const RuntimeEnvironment *RR,void *tPtr) const
try {
Buffer<sizeof(Revocation) + 64> tmp;
this->serialize(tmp,true);
return (id.verify(tmp.data(),tmp.size(),_signature) ? 0 : -1);
return (id.verify(tmp.data(),tmp.size(),_signature,_signatureLength) ? 0 : -1);
} catch ( ... ) {
return -1;
}

View file

@ -66,9 +66,9 @@ public:
_flags(0),
_target(),
_signedBy(),
_type(Credential::CREDENTIAL_TYPE_NULL)
_type(Credential::CREDENTIAL_TYPE_NULL),
_signatureLength(0)
{
memset(_signature.data,0,sizeof(_signature.data));
}
/**
@ -88,9 +88,9 @@ public:
_flags(fl),
_target(tgt),
_signedBy(),
_type(ct)
_type(ct),
_signatureLength(0)
{
memset(_signature.data,0,sizeof(_signature.data));
}
inline uint32_t id() const { return _id; }
@ -107,17 +107,7 @@ public:
* @param signer Signing identity, must have private key
* @return True if signature was successful
*/
inline bool sign(const Identity &signer)
{
if (signer.hasPrivate()) {
Buffer<sizeof(Revocation) + 64> tmp;
_signedBy = signer.address();
this->serialize(tmp,true);
_signature = signer.sign(tmp.data(),tmp.size());
return true;
}
return false;
}
bool sign(const Identity &signer);
/**
* Verify this revocation's signature
@ -145,9 +135,9 @@ public:
b.append((uint8_t)_type);
if (!forSign) {
b.append((uint8_t)1); // 1 == Ed25519 signature
b.append((uint16_t)ZT_C25519_SIGNATURE_LEN);
b.append(_signature.data,ZT_C25519_SIGNATURE_LEN);
b.append((uint8_t)1);
b.append((uint16_t)_signatureLength);
b.append(_signature,_signatureLength);
}
// This is the size of any additional fields, currently 0.
@ -175,11 +165,10 @@ public:
_type = (Credential::Type)b[p++];
if (b[p++] == 1) {
if (b.template at<uint16_t>(p) == ZT_C25519_SIGNATURE_LEN) {
p += 2;
memcpy(_signature.data,b.field(p,ZT_C25519_SIGNATURE_LEN),ZT_C25519_SIGNATURE_LEN);
p += ZT_C25519_SIGNATURE_LEN;
} else throw ZT_EXCEPTION_INVALID_SERIALIZED_DATA_INVALID_CRYPTOGRAPHIC_TOKEN;
_signatureLength = b.template at<uint16_t>(p);
if (_signatureLength > sizeof(_signature))
throw ZT_EXCEPTION_INVALID_SERIALIZED_DATA_INVALID_CRYPTOGRAPHIC_TOKEN;
memcpy(_signature,b.field(p,_signatureLength),_signatureLength);
} else {
p += 2 + b.template at<uint16_t>(p);
}
@ -200,7 +189,8 @@ private:
Address _target;
Address _signedBy;
Credential::Type _type;
C25519::Signature _signature;
unsigned int _signatureLength;
uint8_t _signature[ZT_SIGNATURE_BUFFER_SIZE];
};
} // namespace ZeroTier

View file

@ -18,13 +18,20 @@ Public domain.
#include <CommonCrypto/CommonDigest.h>
#define ZT_HAVE_NATIVE_SHA512
namespace ZeroTier {
void SHA512::hash(void *digest,const void *data,unsigned int len)
void SHA512(void *digest,const void *data,unsigned int len)
{
CC_SHA512_CTX ctx;
CC_SHA512_Init(&ctx);
CC_SHA512_Update(&ctx,data,len);
CC_SHA512_Final(reinterpret_cast<unsigned char *>(digest),&ctx);
}
void SHA384(void *digest,const void *data,unsigned int len)
{
CC_SHA512_CTX ctx;
CC_SHA384_Init(&ctx);
CC_SHA384_Update(&ctx,data,len);
CC_SHA384_Final(reinterpret_cast<unsigned char *>(digest),&ctx);
}
}
#endif
@ -32,336 +39,222 @@ void SHA512::hash(void *digest,const void *data,unsigned int len)
#include <openssl/sha.h>
#define ZT_HAVE_NATIVE_SHA512
namespace ZeroTier {
void SHA512::hash(void *digest,const void *data,unsigned int len)
void SHA512(void *digest,const void *data,unsigned int len)
{
SHA512_CTX ctx;
SHA512_Init(&ctx);
SHA512_Update(&ctx,data,len);
SHA512_Final(reinterpret_cast<unsigned char *>(digest),&ctx);
}
void SHA384(void *digest,const void *data,unsigned int len)
{
SHA512_CTX ctx;
SHA384_Init(&ctx);
SHA384_Update(&ctx,data,len);
SHA384_Final(reinterpret_cast<unsigned char *>(digest),&ctx);
}
}
#endif
// If a platform-native SHA512 isn't available we use this 64-bit C version.
#ifndef ZT_HAVE_NATIVE_SHA512
namespace ZeroTier {
#define uint64 uint64_t
namespace {
#ifdef ZT_NO_TYPE_PUNNING
static uint64 load_bigendian(const unsigned char *x)
static inline void sha512_encode(uint64_t input, uint8_t *output, uint32_t idx)
{
return
(uint64) (x[7]) \
| (((uint64) (x[6])) << 8) \
| (((uint64) (x[5])) << 16) \
| (((uint64) (x[4])) << 24) \
| (((uint64) (x[3])) << 32) \
| (((uint64) (x[2])) << 40) \
| (((uint64) (x[1])) << 48) \
| (((uint64) (x[0])) << 56)
;
output[idx + 0] = (uint8_t)(input >> 56);
output[idx + 1] = (uint8_t)(input >> 48);
output[idx + 2] = (uint8_t)(input >> 40);
output[idx + 3] = (uint8_t)(input >> 32);
output[idx + 4] = (uint8_t)(input >> 24);
output[idx + 5] = (uint8_t)(input >> 16);
output[idx + 6] = (uint8_t)(input >> 8);
output[idx + 7] = (uint8_t)(input >> 0);
}
static void store_bigendian(unsigned char *x,uint64 u)
static inline void sha512_decode(uint64_t *output, uint8_t *input, uint32_t idx)
{
x[7] = u; u >>= 8;
x[6] = u; u >>= 8;
x[5] = u; u >>= 8;
x[4] = u; u >>= 8;
x[3] = u; u >>= 8;
x[2] = u; u >>= 8;
x[1] = u; u >>= 8;
x[0] = u;
*output = ((uint64_t)input[idx + 0] << 56)
| ((uint64_t)input[idx + 1] << 48)
| ((uint64_t)input[idx + 2] << 40)
| ((uint64_t)input[idx + 3] << 32)
| ((uint64_t)input[idx + 4] << 24)
| ((uint64_t)input[idx + 5] << 16)
| ((uint64_t)input[idx + 6] << 8)
| ((uint64_t)input[idx + 7] << 0);
}
#else // !ZT_NO_TYPE_PUNNING
typedef struct sha512_ctx_tag {
uint32_t is_sha384;
uint8_t block[128];
uint64_t len[2];
uint64_t val[8];
uint8_t *payload_addr;
uint64_t payload_len;
} sha512_ctx_t;
#define load_bigendian(x) Utils::ntoh(*((const uint64_t *)(x)))
#define store_bigendian(x,u) (*((uint64_t *)(x)) = Utils::hton((u)))
#define LSR(x,n) (x >> n)
#define ROR(x,n) (LSR(x,n) | (x << (64 - n)))
#endif // ZT_NO_TYPE_PUNNING
#define MA(x,y,z) ((x & y) | (z & (x | y)))
#define CH(x,y,z) (z ^ (x & (y ^ z)))
#define GAMMA0(x) (ROR(x, 1) ^ ROR(x, 8) ^ LSR(x, 7))
#define GAMMA1(x) (ROR(x,19) ^ ROR(x,61) ^ LSR(x, 6))
#define SIGMA0(x) (ROR(x,28) ^ ROR(x,34) ^ ROR(x,39))
#define SIGMA1(x) (ROR(x,14) ^ ROR(x,18) ^ ROR(x,41))
#define SHR(x,c) ((x) >> (c))
#define ROTR(x,c) (((x) >> (c)) | ((x) << (64 - (c))))
#define INIT_COMPRESSOR() uint64_t tmp0 = 0, tmp1 = 0
#define COMPRESS( a, b, c, d, e, f, g, h, x, k) \
tmp0 = h + SIGMA1(e) + CH(e,f,g) + k + x; \
tmp1 = SIGMA0(a) + MA(a,b,c); d += tmp0; h = tmp0 + tmp1;
#define Ch(x,y,z) ((x & y) ^ (~x & z))
#define Maj(x,y,z) ((x & y) ^ (x & z) ^ (y & z))
#define Sigma0(x) (ROTR(x,28) ^ ROTR(x,34) ^ ROTR(x,39))
#define Sigma1(x) (ROTR(x,14) ^ ROTR(x,18) ^ ROTR(x,41))
#define sigma0(x) (ROTR(x, 1) ^ ROTR(x, 8) ^ SHR(x,7))
#define sigma1(x) (ROTR(x,19) ^ ROTR(x,61) ^ SHR(x,6))
static const uint8_t sha512_padding[128] = { 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
#define M(w0,w14,w9,w1) w0 = sigma1(w14) + w9 + sigma0(w1) + w0;
#define EXPAND \
M(w0 ,w14,w9 ,w1 ) \
M(w1 ,w15,w10,w2 ) \
M(w2 ,w0 ,w11,w3 ) \
M(w3 ,w1 ,w12,w4 ) \
M(w4 ,w2 ,w13,w5 ) \
M(w5 ,w3 ,w14,w6 ) \
M(w6 ,w4 ,w15,w7 ) \
M(w7 ,w5 ,w0 ,w8 ) \
M(w8 ,w6 ,w1 ,w9 ) \
M(w9 ,w7 ,w2 ,w10) \
M(w10,w8 ,w3 ,w11) \
M(w11,w9 ,w4 ,w12) \
M(w12,w10,w5 ,w13) \
M(w13,w11,w6 ,w14) \
M(w14,w12,w7 ,w15) \
M(w15,w13,w8 ,w0 )
#define F(w,k) \
T1 = h + Sigma1(e) + Ch(e,f,g) + k + w; \
T2 = Sigma0(a) + Maj(a,b,c); \
h = g; \
g = f; \
f = e; \
e = d + T1; \
d = c; \
c = b; \
b = a; \
a = T1 + T2;
static inline int crypto_hashblocks(unsigned char *statebytes,const unsigned char *in,unsigned long long inlen)
{
uint64 state[8];
uint64 a;
uint64 b;
uint64 c;
uint64 d;
uint64 e;
uint64 f;
uint64 g;
uint64 h;
uint64 T1;
uint64 T2;
a = load_bigendian(statebytes + 0); state[0] = a;
b = load_bigendian(statebytes + 8); state[1] = b;
c = load_bigendian(statebytes + 16); state[2] = c;
d = load_bigendian(statebytes + 24); state[3] = d;
e = load_bigendian(statebytes + 32); state[4] = e;
f = load_bigendian(statebytes + 40); state[5] = f;
g = load_bigendian(statebytes + 48); state[6] = g;
h = load_bigendian(statebytes + 56); state[7] = h;
while (inlen >= 128) {
uint64 w0 = load_bigendian(in + 0);
uint64 w1 = load_bigendian(in + 8);
uint64 w2 = load_bigendian(in + 16);
uint64 w3 = load_bigendian(in + 24);
uint64 w4 = load_bigendian(in + 32);
uint64 w5 = load_bigendian(in + 40);
uint64 w6 = load_bigendian(in + 48);
uint64 w7 = load_bigendian(in + 56);
uint64 w8 = load_bigendian(in + 64);
uint64 w9 = load_bigendian(in + 72);
uint64 w10 = load_bigendian(in + 80);
uint64 w11 = load_bigendian(in + 88);
uint64 w12 = load_bigendian(in + 96);
uint64 w13 = load_bigendian(in + 104);
uint64 w14 = load_bigendian(in + 112);
uint64 w15 = load_bigendian(in + 120);
F(w0 ,0x428a2f98d728ae22ULL)
F(w1 ,0x7137449123ef65cdULL)
F(w2 ,0xb5c0fbcfec4d3b2fULL)
F(w3 ,0xe9b5dba58189dbbcULL)
F(w4 ,0x3956c25bf348b538ULL)
F(w5 ,0x59f111f1b605d019ULL)
F(w6 ,0x923f82a4af194f9bULL)
F(w7 ,0xab1c5ed5da6d8118ULL)
F(w8 ,0xd807aa98a3030242ULL)
F(w9 ,0x12835b0145706fbeULL)
F(w10,0x243185be4ee4b28cULL)
F(w11,0x550c7dc3d5ffb4e2ULL)
F(w12,0x72be5d74f27b896fULL)
F(w13,0x80deb1fe3b1696b1ULL)
F(w14,0x9bdc06a725c71235ULL)
F(w15,0xc19bf174cf692694ULL)
EXPAND
F(w0 ,0xe49b69c19ef14ad2ULL)
F(w1 ,0xefbe4786384f25e3ULL)
F(w2 ,0x0fc19dc68b8cd5b5ULL)
F(w3 ,0x240ca1cc77ac9c65ULL)
F(w4 ,0x2de92c6f592b0275ULL)
F(w5 ,0x4a7484aa6ea6e483ULL)
F(w6 ,0x5cb0a9dcbd41fbd4ULL)
F(w7 ,0x76f988da831153b5ULL)
F(w8 ,0x983e5152ee66dfabULL)
F(w9 ,0xa831c66d2db43210ULL)
F(w10,0xb00327c898fb213fULL)
F(w11,0xbf597fc7beef0ee4ULL)
F(w12,0xc6e00bf33da88fc2ULL)
F(w13,0xd5a79147930aa725ULL)
F(w14,0x06ca6351e003826fULL)
F(w15,0x142929670a0e6e70ULL)
EXPAND
F(w0 ,0x27b70a8546d22ffcULL)
F(w1 ,0x2e1b21385c26c926ULL)
F(w2 ,0x4d2c6dfc5ac42aedULL)
F(w3 ,0x53380d139d95b3dfULL)
F(w4 ,0x650a73548baf63deULL)
F(w5 ,0x766a0abb3c77b2a8ULL)
F(w6 ,0x81c2c92e47edaee6ULL)
F(w7 ,0x92722c851482353bULL)
F(w8 ,0xa2bfe8a14cf10364ULL)
F(w9 ,0xa81a664bbc423001ULL)
F(w10,0xc24b8b70d0f89791ULL)
F(w11,0xc76c51a30654be30ULL)
F(w12,0xd192e819d6ef5218ULL)
F(w13,0xd69906245565a910ULL)
F(w14,0xf40e35855771202aULL)
F(w15,0x106aa07032bbd1b8ULL)
EXPAND
F(w0 ,0x19a4c116b8d2d0c8ULL)
F(w1 ,0x1e376c085141ab53ULL)
F(w2 ,0x2748774cdf8eeb99ULL)
F(w3 ,0x34b0bcb5e19b48a8ULL)
F(w4 ,0x391c0cb3c5c95a63ULL)
F(w5 ,0x4ed8aa4ae3418acbULL)
F(w6 ,0x5b9cca4f7763e373ULL)
F(w7 ,0x682e6ff3d6b2b8a3ULL)
F(w8 ,0x748f82ee5defb2fcULL)
F(w9 ,0x78a5636f43172f60ULL)
F(w10,0x84c87814a1f0ab72ULL)
F(w11,0x8cc702081a6439ecULL)
F(w12,0x90befffa23631e28ULL)
F(w13,0xa4506cebde82bde9ULL)
F(w14,0xbef9a3f7b2c67915ULL)
F(w15,0xc67178f2e372532bULL)
EXPAND
F(w0 ,0xca273eceea26619cULL)
F(w1 ,0xd186b8c721c0c207ULL)
F(w2 ,0xeada7dd6cde0eb1eULL)
F(w3 ,0xf57d4f7fee6ed178ULL)
F(w4 ,0x06f067aa72176fbaULL)
F(w5 ,0x0a637dc5a2c898a6ULL)
F(w6 ,0x113f9804bef90daeULL)
F(w7 ,0x1b710b35131c471bULL)
F(w8 ,0x28db77f523047d84ULL)
F(w9 ,0x32caab7b40c72493ULL)
F(w10,0x3c9ebe0a15c9bebcULL)
F(w11,0x431d67c49c100d4cULL)
F(w12,0x4cc5d4becb3e42b6ULL)
F(w13,0x597f299cfc657e2aULL)
F(w14,0x5fcb6fab3ad6faecULL)
F(w15,0x6c44198c4a475817ULL)
a += state[0];
b += state[1];
c += state[2];
d += state[3];
e += state[4];
f += state[5];
g += state[6];
h += state[7];
state[0] = a;
state[1] = b;
state[2] = c;
state[3] = d;
state[4] = e;
state[5] = f;
state[6] = g;
state[7] = h;
in += 128;
inlen -= 128;
}
store_bigendian(statebytes + 0,state[0]);
store_bigendian(statebytes + 8,state[1]);
store_bigendian(statebytes + 16,state[2]);
store_bigendian(statebytes + 24,state[3]);
store_bigendian(statebytes + 32,state[4]);
store_bigendian(statebytes + 40,state[5]);
store_bigendian(statebytes + 48,state[6]);
store_bigendian(statebytes + 56,state[7]);
return 0;
}
#define blocks crypto_hashblocks
static const unsigned char iv[64] = {
0x6a,0x09,0xe6,0x67,0xf3,0xbc,0xc9,0x08,
0xbb,0x67,0xae,0x85,0x84,0xca,0xa7,0x3b,
0x3c,0x6e,0xf3,0x72,0xfe,0x94,0xf8,0x2b,
0xa5,0x4f,0xf5,0x3a,0x5f,0x1d,0x36,0xf1,
0x51,0x0e,0x52,0x7f,0xad,0xe6,0x82,0xd1,
0x9b,0x05,0x68,0x8c,0x2b,0x3e,0x6c,0x1f,
0x1f,0x83,0xd9,0xab,0xfb,0x41,0xbd,0x6b,
0x5b,0xe0,0xcd,0x19,0x13,0x7e,0x21,0x79
static const uint64_t K[80] = {
0x428A2F98D728AE22ULL, 0x7137449123EF65CDULL, 0xB5C0FBCFEC4D3B2FULL, 0xE9B5DBA58189DBBCULL,
0x3956C25BF348B538ULL, 0x59F111F1B605D019ULL, 0x923F82A4AF194F9BULL, 0xAB1C5ED5DA6D8118ULL,
0xD807AA98A3030242ULL, 0x12835B0145706FBEULL, 0x243185BE4EE4B28CULL, 0x550C7DC3D5FFB4E2ULL,
0x72BE5D74F27B896FULL, 0x80DEB1FE3B1696B1ULL, 0x9BDC06A725C71235ULL, 0xC19BF174CF692694ULL,
0xE49B69C19EF14AD2ULL, 0xEFBE4786384F25E3ULL, 0x0FC19DC68B8CD5B5ULL, 0x240CA1CC77AC9C65ULL,
0x2DE92C6F592B0275ULL, 0x4A7484AA6EA6E483ULL, 0x5CB0A9DCBD41FBD4ULL, 0x76F988DA831153B5ULL,
0x983E5152EE66DFABULL, 0xA831C66D2DB43210ULL, 0xB00327C898FB213FULL, 0xBF597FC7BEEF0EE4ULL,
0xC6E00BF33DA88FC2ULL, 0xD5A79147930AA725ULL, 0x06CA6351E003826FULL, 0x142929670A0E6E70ULL,
0x27B70A8546D22FFCULL, 0x2E1B21385C26C926ULL, 0x4D2C6DFC5AC42AEDULL, 0x53380D139D95B3DFULL,
0x650A73548BAF63DEULL, 0x766A0ABB3C77B2A8ULL, 0x81C2C92E47EDAEE6ULL, 0x92722C851482353BULL,
0xA2BFE8A14CF10364ULL, 0xA81A664BBC423001ULL, 0xC24B8B70D0F89791ULL, 0xC76C51A30654BE30ULL,
0xD192E819D6EF5218ULL, 0xD69906245565A910ULL, 0xF40E35855771202AULL, 0x106AA07032BBD1B8ULL,
0x19A4C116B8D2D0C8ULL, 0x1E376C085141AB53ULL, 0x2748774CDF8EEB99ULL, 0x34B0BCB5E19B48A8ULL,
0x391C0CB3C5C95A63ULL, 0x4ED8AA4AE3418ACBULL, 0x5B9CCA4F7763E373ULL, 0x682E6FF3D6B2B8A3ULL,
0x748F82EE5DEFB2FCULL, 0x78A5636F43172F60ULL, 0x84C87814A1F0AB72ULL, 0x8CC702081A6439ECULL,
0x90BEFFFA23631E28ULL, 0xA4506CEBDE82BDE9ULL, 0xBEF9A3F7B2C67915ULL, 0xC67178F2E372532BULL,
0xCA273ECEEA26619CULL, 0xD186B8C721C0C207ULL, 0xEADA7DD6CDE0EB1EULL, 0xF57D4F7FEE6ED178ULL,
0x06F067AA72176FBAULL, 0x0A637DC5A2C898A6ULL, 0x113F9804BEF90DAEULL, 0x1B710B35131C471BULL,
0x28DB77F523047D84ULL, 0x32CAAB7B40C72493ULL, 0x3C9EBE0A15C9BEBCULL, 0x431D67C49C100D4CULL,
0x4CC5D4BECB3E42B6ULL, 0x597F299CFC657E2AULL, 0x5FCB6FAB3AD6FAECULL, 0x6C44198C4A475817ULL
};
void SHA512::hash(void *digest,const void *data,unsigned int len)
static inline void sha512_memcpy(uint8_t *src, uint8_t *dst, uint32_t size)
{
unsigned char h[64];
unsigned char padded[256];
int i;
uint64_t bytes = len;
const unsigned char *in = (const unsigned char *)data;
unsigned int inlen = len;
for (i = 0;i < 64;++i) h[i] = iv[i];
blocks(h,in,inlen);
in += inlen;
inlen &= 127;
in -= inlen;
for (i = 0;i < (int)inlen;++i) padded[i] = in[i];
padded[inlen] = 0x80;
if (inlen < 112) {
for (i = inlen + 1;i < 119;++i) padded[i] = 0;
padded[119] = (unsigned char)((bytes >> 61) & 0xff);
padded[120] = (unsigned char)((bytes >> 53) & 0xff);
padded[121] = (unsigned char)((bytes >> 45) & 0xff);
padded[122] = (unsigned char)((bytes >> 37) & 0xff);
padded[123] = (unsigned char)((bytes >> 29) & 0xff);
padded[124] = (unsigned char)((bytes >> 21) & 0xff);
padded[125] = (unsigned char)((bytes >> 13) & 0xff);
padded[126] = (unsigned char)((bytes >> 5) & 0xff);
padded[127] = (unsigned char)((bytes << 3) & 0xff);
blocks(h,padded,128);
} else {
for (i = inlen + 1;i < 247;++i) padded[i] = 0;
padded[247] = (unsigned char)((bytes >> 61) & 0xff);
padded[248] = (unsigned char)((bytes >> 53) & 0xff);
padded[249] = (unsigned char)((bytes >> 45) & 0xff);
padded[250] = (unsigned char)((bytes >> 37) & 0xff);
padded[251] = (unsigned char)((bytes >> 29) & 0xff);
padded[252] = (unsigned char)((bytes >> 21) & 0xff);
padded[253] = (unsigned char)((bytes >> 13) & 0xff);
padded[254] = (unsigned char)((bytes >> 5) & 0xff);
padded[255] = (unsigned char)((bytes << 3) & 0xff);
blocks(h,padded,256);
uint32_t i = 0;
for (;i < size;i++) { *dst++ = *src++; }
}
static inline void sha512_memclr(uint8_t *dst, uint32_t size)
{
uint32_t i = 0;
for (;i < size;i++) { *dst++ = 0; }
}
for (i = 0;i < 64;++i) ((unsigned char *)digest)[i] = h[i];
static inline void sha512_init_512(sha512_ctx_t *sha512_ctx, uint8_t *payload_addr, uint64_t payload_len)
{
sha512_memclr((uint8_t *)sha512_ctx,sizeof(sha512_ctx_t));
sha512_ctx->val[0] = 0x6A09E667F3BCC908ULL;
sha512_ctx->val[1] = 0xBB67AE8584CAA73BULL;
sha512_ctx->val[2] = 0x3C6EF372FE94F82BULL;
sha512_ctx->val[3] = 0xA54FF53A5F1D36F1ULL;
sha512_ctx->val[4] = 0x510E527FADE682D1ULL;
sha512_ctx->val[5] = 0x9B05688C2B3E6C1FULL;
sha512_ctx->val[6] = 0x1F83D9ABFB41BD6BULL;
sha512_ctx->val[7] = 0x5BE0CD19137E2179ULL;
sha512_ctx->is_sha384 = 0;
sha512_ctx->payload_addr = payload_addr;
sha512_ctx->payload_len = (uint64_t)payload_len;
sha512_ctx->len[0] = payload_len << 3;
sha512_ctx->len[1] = payload_len >> 61;
}
static inline void sha512_init_384(sha512_ctx_t *sha512_ctx, uint8_t *payload_addr, uint64_t payload_len)
{
sha512_memclr((uint8_t *)sha512_ctx,sizeof(sha512_ctx_t));
sha512_ctx->val[0] = 0xCBBB9D5DC1059ED8ULL;
sha512_ctx->val[1] = 0x629A292A367CD507ULL;
sha512_ctx->val[2] = 0x9159015A3070DD17ULL;
sha512_ctx->val[3] = 0x152FECD8F70E5939ULL;
sha512_ctx->val[4] = 0x67332667FFC00B31ULL;
sha512_ctx->val[5] = 0x8EB44A8768581511ULL;
sha512_ctx->val[6] = 0xDB0C2E0D64F98FA7ULL;
sha512_ctx->val[7] = 0x47B5481DBEFA4FA4ULL;
sha512_ctx->is_sha384 = 1;
sha512_ctx->payload_addr = payload_addr;
sha512_ctx->payload_len = (uint64_t)payload_len;
sha512_ctx->len[0] = payload_len << 3;
sha512_ctx->len[1] = payload_len >> 61;
}
static inline void sha512_hash_factory(sha512_ctx_t *ctx, uint8_t data[128])
{
uint32_t i = 0;
uint64_t W[80];
uint64_t v[8];
INIT_COMPRESSOR();
for(i = 0; i < 16; i++) { sha512_decode(&W[i], data, i << 3 ); }
for(; i < 80; i++) { W[i] = GAMMA1(W[i - 2]) + W[i - 7] + GAMMA0(W[i - 15]) + W[i - 16]; }
for (i = 0;i < 8; i++) { v[i] = ctx->val[i]; }
for(i = 0; i < 80;) {
COMPRESS(v[0], v[1], v[2], v[3], v[4], v[5], v[6], v[7], W[i], K[i] ); i++;
COMPRESS(v[7], v[0], v[1], v[2], v[3], v[4], v[5], v[6], W[i], K[i] ); i++;
COMPRESS(v[6], v[7], v[0], v[1], v[2], v[3], v[4], v[5], W[i], K[i] ); i++;
COMPRESS(v[5], v[6], v[7], v[0], v[1], v[2], v[3], v[4], W[i], K[i] ); i++;
COMPRESS(v[4], v[5], v[6], v[7], v[0], v[1], v[2], v[3], W[i], K[i] ); i++;
COMPRESS(v[3], v[4], v[5], v[6], v[7], v[0], v[1], v[2], W[i], K[i] ); i++;
COMPRESS(v[2], v[3], v[4], v[5], v[6], v[7], v[0], v[1], W[i], K[i] ); i++;
COMPRESS(v[1], v[2], v[3], v[4], v[5], v[6], v[7], v[0], W[i], K[i] ); i++;
}
for (i = 0; i < 8; i++) { ctx->val[i] += v[i]; }
}
static inline void sha512_stage1(sha512_ctx_t *sha512_ctx)
{
while (sha512_ctx->payload_len >= 128) {
sha512_hash_factory(sha512_ctx, sha512_ctx->payload_addr);
sha512_ctx->payload_addr += 128;
sha512_ctx->payload_len -= 128;
}
}
static inline void sha512_stage2(sha512_ctx_t *sha512_ctx, uint8_t output[64])
{
uint32_t block_pos = sha512_ctx->payload_len;
uint32_t padding_bytes = 0;
uint8_t temp_data[128] = {0};
uint8_t *temp_data_p = (uint8_t *)&temp_data[0];
uint8_t len_be[16] = {0};
uint8_t i = 0;
sha512_memcpy(sha512_ctx->payload_addr, temp_data_p, sha512_ctx->payload_len);
padding_bytes = 112 - block_pos;
temp_data_p += block_pos;
sha512_memcpy((uint8_t *)sha512_padding, temp_data_p, padding_bytes);
temp_data_p += padding_bytes;
sha512_encode(sha512_ctx->len[1], len_be, 0);
sha512_encode(sha512_ctx->len[0], len_be, 8);
sha512_memcpy(len_be, temp_data_p, 16);
sha512_hash_factory(sha512_ctx, temp_data);
for (i = 0; i < 6; i++) { sha512_encode(sha512_ctx->val[i], output, i * 8); }
for ( ;(i < 8) && (sha512_ctx->is_sha384 == 0); i++) { sha512_encode(sha512_ctx->val[i], output, i * 8); }
}
} // anonymous namespace
void SHA512(void *digest,const void *data,unsigned int len)
{
sha512_ctx_t h;
sha512_init_512(&h,(uint8_t *)data,len);
sha512_stage1(&h);
sha512_stage2(&h,(uint8_t *)digest);
}
void SHA384(void *digest,const void *data,unsigned int len)
{
sha512_ctx_t h;
sha512_init_384(&h,(uint8_t *)data,len);
sha512_stage1(&h);
sha512_stage2(&h,(uint8_t *)digest);
}
} // namespace ZeroTier
#endif // !ZT_HAVE_NATIVE_SHA512
// Internally re-export to included C code, which includes some fast crypto code ported in on some platforms.
// This eliminates the need to link against a third party SHA512() from this code
extern "C" void ZT_sha512internal(void *digest,const void *data,unsigned int len)
{
ZeroTier::SHA512::hash(digest,data,len);
}
extern "C" void ZT_sha512internal(void *digest,const void *data,unsigned int len) { ZeroTier::SHA512(digest,data,len); }
extern "C" void ZT_sha384internal(void *digest,const void *data,unsigned int len) { ZeroTier::SHA384(digest,data,len); }

View file

@ -31,14 +31,9 @@
namespace ZeroTier {
/**
* SHA-512 digest algorithm
*/
class SHA512
{
public:
static void hash(void *digest,const void *data,unsigned int len);
};
void SHA512(void *digest,const void *data,unsigned int len);
void SHA384(void *digest,const void *data,unsigned int len);
} // namespace ZeroTier

158
node/Str.hpp Normal file
View file

@ -0,0 +1,158 @@
/*
* ZeroTier One - Network Virtualization Everywhere
* Copyright (C) 2011-2019 ZeroTier, Inc. https://www.zerotier.com/
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* --
*
* You can be released from the requirements of the license by purchasing
* a commercial license. Buying such a license is mandatory as soon as you
* develop commercial closed-source software that incorporates or links
* directly against ZeroTier software without disclosing the source code
* of your own application.
*/
#ifndef ZT_STR_HPP
#define ZT_STR_HPP
#include "Constants.hpp"
#include "Utils.hpp"
#include "Address.hpp"
#include "MAC.hpp"
#include "InetAddress.hpp"
#define ZT_STR_CAPACITY 254
namespace ZeroTier {
class Str
{
public:
Str() { _l = 0; _s[0] = 0; }
Str(const Str &s)
{
_l = s._l;
memcpy(_s,s._s,_l+1);
}
Str(const char *s)
{
_l = 0;
_s[0] = 0;
(*this) << s;
}
inline Str &operator=(const Str &s)
{
_l = s._l;
memcpy(_s,s._s,_l+1);
return *this;
}
inline Str &operator=(const char *s)
{
_l = 0;
_s[0] = 0;
return ((*this) << s);
}
inline char operator[](const unsigned int i) const
{
if (unlikely(i >= (unsigned int)_l))
throw ZT_EXCEPTION_OUT_OF_BOUNDS;
return _s[i];
}
inline void clear() { _l = 0; _s[0] = 0; }
inline const char *c_str() const { return _s; }
inline unsigned int length() const { return _l; }
inline Str &operator<<(const char *s)
{
if (likely(s != (const char *)0)) {
unsigned long l = _l;
while (*s) {
if (unlikely(l >= ZT_STR_CAPACITY)) {
_s[l] = 0;
_l = (uint8_t)l;
throw ZT_EXCEPTION_OUT_OF_BOUNDS;
}
_s[l++] = *s;
}
_s[l] = 0;
_l = (uint8_t)l;
}
return *this;
}
inline Str &operator<<(const Str &s) { return ((*this) << s._s); }
inline Str &operator<<(const char c)
{
if (likely(c != 0)) {
if (unlikely(_l >= ZT_STR_CAPACITY)) {
_s[_l] = 0;
throw ZT_EXCEPTION_OUT_OF_BOUNDS;
}
_s[_l++] = c;
_s[_l] = 0;
}
}
inline Str &operator<<(const unsigned long n)
{
char tmp[32];
Utils::decimal(n,tmp);
return ((*this) << tmp);
}
inline Str &operator<<(const unsigned int n)
{
char tmp[32];
Utils::decimal((unsigned long)n,tmp);
return ((*this) << tmp);
}
inline Str &operator<<(const Address &a)
{
char tmp[32];
return ((*this) << a.toString(tmp));
}
inline Str &operator<<(const InetAddress &a)
{
char tmp[128];
return ((*this) << a.toString(tmp));
}
inline Str &operator<<(const MAC &a)
{
char tmp[64];
return ((*this) << a.toString(tmp));
}
inline bool operator==(const Str &s) const { return ((_l == s._l)&&(strcmp(_s,s._s) == 0)); }
inline bool operator!=(const Str &s) const { return ((_l != s._l)||(strcmp(_s,s._s) != 0)); }
inline bool operator<(const Str &s) const { return ((_l < s._l)&&(strcmp(_s,s._s) < 0)); }
inline bool operator>(const Str &s) const { return ((_l > s._l)&&(strcmp(_s,s._s) > 0)); }
inline bool operator<=(const Str &s) const { return ((_l <= s._l)&&(strcmp(_s,s._s) <= 0)); }
inline bool operator>=(const Str &s) const { return ((_l >= s._l)&&(strcmp(_s,s._s) >= 0)); }
inline bool operator==(const char *s) const { return (strcmp(_s,s) == 0); }
inline bool operator!=(const char *s) const { return (strcmp(_s,s) != 0); }
inline bool operator<(const char *s) const { return (strcmp(_s,s) < 0); }
inline bool operator>(const char *s) const { return (strcmp(_s,s) > 0); }
inline bool operator<=(const char *s) const { return (strcmp(_s,s) <= 0); }
inline bool operator>=(const char *s) const { return (strcmp(_s,s) >= 0); }
private:
uint8_t _l;
char _s[ZT_STR_CAPACITY+1];
};
} // namespace ZeroTier
#endif

View file

@ -92,9 +92,6 @@ void Switch::onRemotePacket(void *tPtr,const int64_t localSocket,const InetAddre
const Address destination(fragment.destination());
if (destination != RR->identity.address()) {
if ( (!RR->topology->amUpstream()) && (!path->trustEstablished(now)) )
return;
if (fragment.hops() < ZT_RELAY_MAX_HOPS) {
fragment.incrementHops();
@ -164,11 +161,7 @@ void Switch::onRemotePacket(void *tPtr,const int64_t localSocket,const InetAddre
return;
if (destination != RR->identity.address()) {
if ( (!RR->topology->amUpstream()) && (!path->trustEstablished(now)) && (source != RR->identity.address()) )
return;
Packet packet(data,len);
if (packet.hops() < ZT_RELAY_MAX_HOPS) {
packet.incrementHops();
SharedPtr<Peer> relayTo = RR->topology->getPeer(tPtr,destination);

View file

@ -34,6 +34,18 @@
namespace ZeroTier {
bool Tag::sign(const Identity &signer)
{
if (signer.hasPrivate()) {
Buffer<sizeof(Tag) + 64> tmp;
_signedBy = signer.address();
this->serialize(tmp,true);
_signatureLength = signer.sign(tmp.data(),tmp.size(),_signature,sizeof(_signature));
return true;
}
return false;
}
int Tag::verify(const RuntimeEnvironment *RR,void *tPtr) const
{
if ((!_signedBy)||(_signedBy != Network::controllerFor(_networkId)))
@ -46,7 +58,7 @@ int Tag::verify(const RuntimeEnvironment *RR,void *tPtr) const
try {
Buffer<(sizeof(Tag) * 2)> tmp;
this->serialize(tmp,true);
return (id.verify(tmp.data(),tmp.size(),_signature) ? 0 : -1);
return (id.verify(tmp.data(),tmp.size(),_signature,_signatureLength) ? 0 : -1);
} catch ( ... ) {
return -1;
}

View file

@ -69,9 +69,9 @@ public:
_id(0),
_value(0),
_networkId(0),
_ts(0)
_ts(0),
_signatureLength(0)
{
memset(_signature.data,0,sizeof(_signature.data));
}
/**
@ -87,9 +87,9 @@ public:
_networkId(nwid),
_ts(ts),
_issuedTo(issuedTo),
_signedBy()
_signedBy(),
_signatureLength(0)
{
memset(_signature.data,0,sizeof(_signature.data));
}
inline uint32_t id() const { return _id; }
@ -105,17 +105,7 @@ public:
* @param signer Signing identity, must have private key
* @return True if signature was successful
*/
inline bool sign(const Identity &signer)
{
if (signer.hasPrivate()) {
Buffer<sizeof(Tag) + 64> tmp;
_signedBy = signer.address();
this->serialize(tmp,true);
_signature = signer.sign(tmp.data(),tmp.size());
return true;
}
return false;
}
bool sign(const Identity &signer);
/**
* Check this tag's signature
@ -139,9 +129,9 @@ public:
_issuedTo.appendTo(b);
_signedBy.appendTo(b);
if (!forSign) {
b.append((uint8_t)1); // 1 == Ed25519
b.append((uint16_t)ZT_C25519_SIGNATURE_LEN); // length of signature
b.append(_signature.data,ZT_C25519_SIGNATURE_LEN);
b.append((uint8_t)1);
b.append((uint16_t)_signatureLength);
b.append(_signature,_signatureLength);
}
b.append((uint16_t)0); // length of additional fields, currently 0
@ -165,10 +155,11 @@ public:
_issuedTo.setTo(b.field(p,ZT_ADDRESS_LENGTH),ZT_ADDRESS_LENGTH); p += ZT_ADDRESS_LENGTH;
_signedBy.setTo(b.field(p,ZT_ADDRESS_LENGTH),ZT_ADDRESS_LENGTH); p += ZT_ADDRESS_LENGTH;
if (b[p++] == 1) {
if (b.template at<uint16_t>(p) != ZT_C25519_SIGNATURE_LEN)
_signatureLength = b.template at<uint16_t>(p);
if (_signatureLength > sizeof(_signature))
throw ZT_EXCEPTION_INVALID_SERIALIZED_DATA_INVALID_CRYPTOGRAPHIC_TOKEN;
p += 2;
memcpy(_signature.data,b.field(p,ZT_C25519_SIGNATURE_LEN),ZT_C25519_SIGNATURE_LEN); p += ZT_C25519_SIGNATURE_LEN;
memcpy(_signature,b.field(p,_signatureLength),_signatureLength); p += _signatureLength;
} else {
p += 2 + b.template at<uint16_t>(p);
}
@ -207,7 +198,8 @@ private:
int64_t _ts;
Address _issuedTo;
Address _signedBy;
C25519::Signature _signature;
unsigned int _signatureLength;
uint8_t _signature[ZT_SIGNATURE_BUFFER_SIZE];
};
} // namespace ZeroTier

View file

@ -35,57 +35,10 @@
namespace ZeroTier {
/*
* 2018-07-26 ZeroTier planet definition for the third planet of Sol:
*
* There are two roots, each of which is a cluster spread across multiple
* continents and providers. They are named Alice and Bob after the
* canonical example names used in cryptography.
*
* Alice:
*
* root-alice-ams-01: Amsterdam, Netherlands
* root-alice-joh-01: Johannesburg, South Africa
* root-alice-nyc-01: New York, New York, USA
* root-alice-arg-01: Buenos Aires, Argentina
* root-alice-sfo-01: San Francisco, California, USA
* root-alice-sgp-01: Singapore
*
* Bob:
*
* root-bob-dfw-01: Dallas, Texas, USA
* root-bob-fra-01: Frankfurt, Germany
* root-bob-par-01: Paris, France
* root-bob-syd-01: Sydney, Australia
* root-bob-tok-01: Tokyo, Japan
* root-bob-tor-01: Toronto, Canada
*/
#define ZT_DEFAULT_WORLD_LENGTH 634
static const unsigned char ZT_DEFAULT_WORLD[ZT_DEFAULT_WORLD_LENGTH] = {0x01,0x00,0x00,0x00,0x00,0x08,0xea,0xc9,0x0a,0x00,0x00,0x01,0x64,0xd3,0x71,0xf0,0x58,0xb8,0xb3,0x88,0xa4,0x69,0x22,0x14,0x91,0xaa,0x9a,0xcd,0x66,0xcc,0x76,0x4c,0xde,0xfd,0x56,0x03,0x9f,0x10,0x67,0xae,0x15,0xe6,0x9c,0x6f,0xb4,0x2d,0x7b,0x55,0x33,0x0e,0x3f,0xda,0xac,0x52,0x9c,0x07,0x92,0xfd,0x73,0x40,0xa6,0xaa,0x21,0xab,0xa8,0xa4,0x89,0xfd,0xae,0xa4,0x4a,0x39,0xbf,0x2d,0x00,0x65,0x9a,0xc9,0xc8,0x18,0xeb,0xbf,0xfd,0xd5,0x32,0xf7,0x15,0x6e,0x02,0x6f,0xb9,0x01,0x0d,0xb5,0x7b,0x04,0xd8,0x3a,0xc5,0x17,0x39,0x04,0x36,0xfd,0x9d,0xc6,0x3d,0xa8,0xf3,0x8e,0x79,0xe7,0xc8,0x77,0x8d,0xcc,0x79,0xb8,0xab,0xc6,0x98,0x7c,0x9f,0x34,0x25,0x14,0xe1,0x2f,0xd7,0x97,0x11,0xec,0x34,0x4c,0x9f,0x0f,0xb4,0x85,0x0d,0x9b,0x11,0xd1,0xc2,0xce,0x00,0xc4,0x0a,0x13,0x4b,0xcb,0xc3,0xae,0x2e,0x16,0x00,0x4b,0xdc,0x90,0x5e,0x7e,0x9b,0x44,0x07,0x15,0x36,0x61,0x3c,0x64,0xaa,0xe9,0x46,0x78,0x3c,0xa7,0x18,0xc8,0xd8,0x02,0x9d,0x21,0x90,0x39,0xf3,0x00,0x01,0xf0,0x92,0x2a,0x98,0xe3,0xb3,0x4e,0xbc,0xbf,0xf3,0x33,0x26,0x9d,0xc2,0x65,0xd7,0xa0,0x20,0xaa,0xb6,0x9d,0x72,0xbe,0x4d,0x4a,0xcc,0x9c,0x8c,0x92,0x94,0x78,0x57,0x71,0x25,0x6c,0xd1,0xd9,0x42,0xa9,0x0d,0x1b,0xd1,0xd2,0xdc,0xa3,0xea,0x84,0xef,0x7d,0x85,0xaf,0xe6,0x61,0x1f,0xb4,0x3f,0xf0,0xb7,0x41,0x26,0xd9,0x0a,0x6e,0x00,0x0c,0x04,0xbc,0xa6,0x5e,0xb1,0x27,0x09,0x06,0x2a,0x03,0xb0,0xc0,0x00,0x02,0x00,0xd0,0x00,0x7d,0x00,0x01,0x00,0x00,0x00,0x00,0x27,0x09,0x04,0x9a,0x42,0xc5,0x21,0x27,0x09,0x06,0x2c,0x0f,0xf8,0x50,0x01,0x54,0x01,0x97,0x00,0x33,0xcc,0x08,0xf8,0xfa,0xcc,0x08,0x27,0x09,0x04,0x9f,0xcb,0x61,0xab,0x27,0x09,0x06,0x26,0x04,0xa8,0x80,0x08,0x00,0x00,0xa1,0x00,0x54,0x60,0x01,0x00,0xfc,0xcc,0x08,0x27,0x09,0x04,0x83,0xff,0x06,0x10,0x27,0x09,0x06,0x28,0x03,0xeb,0x80,0x00,0x00,0x00,0x0e,0x00,0x02,0x60,0x01,0x00,0xfc,0xcc,0x08,0x27,0x09,0x04,0x6b,0xaa,0xc5,0x0e,0x27,0x09,0x06,0x26,0x04,0xa8,0x80,0x00,0x01,0x00,0x20,0x02,0x00,0xe0,0x01,0x08,0xfe,0xcc,0x08,0x27,0x09,0x04,0x80,0xc7,0xc5,0xd9,0x27,0x09,0x06,0x24,0x00,0x61,0x80,0x00,0x00,0x00,0xd0,0x00,0xb7,0x40,0x01,0x08,0xfe,0xcc,0x08,0x27,0x09,0x88,0x41,0x40,0x8a,0x2e,0x00,0xbb,0x1d,0x31,0xf2,0xc3,0x23,0xe2,0x64,0xe9,0xe6,0x41,0x72,0xc1,0xa7,0x4f,0x77,0x89,0x95,0x55,0xed,0x10,0x75,0x1c,0xd5,0x6e,0x86,0x40,0x5c,0xde,0x11,0x8d,0x02,0xdf,0xfe,0x55,0x5d,0x46,0x2c,0xcf,0x6a,0x85,0xb5,0x63,0x1c,0x12,0x35,0x0c,0x8d,0x5d,0xc4,0x09,0xba,0x10,0xb9,0x02,0x5d,0x0f,0x44,0x5c,0xf4,0x49,0xd9,0x2b,0x1c,0x00,0x0c,0x04,0x2d,0x20,0xc6,0x82,0x27,0x09,0x06,0x20,0x01,0x19,0xf0,0x64,0x00,0x81,0xc3,0x54,0x00,0x00,0xff,0xfe,0x18,0x1d,0x61,0x27,0x09,0x04,0x2e,0x65,0xa0,0xf9,0x27,0x09,0x06,0x2a,0x03,0xb0,0xc0,0x00,0x03,0x00,0xd0,0x00,0x6a,0x30,0x01,0x78,0x00,0xcd,0x08,0x27,0x09,0x04,0x6b,0xbf,0x2e,0xd2,0x27,0x09,0x06,0x20,0x01,0x19,0xf0,0x68,0x00,0x83,0xa4,0x00,0x64,0xcd,0x08,0x80,0x01,0xcd,0x08,0x27,0x09,0x04,0x2d,0x20,0xf6,0xb3,0x27,0x09,0x06,0x20,0x01,0x19,0xf0,0x58,0x00,0x8b,0xf8,0x54,0x00,0x00,0xff,0xfe,0x15,0xb3,0x9a,0x27,0x09,0x04,0x2d,0x20,0xf8,0x57,0x27,0x09,0x06,0x20,0x01,0x19,0xf0,0x70,0x00,0x9b,0xc9,0x54,0x00,0x00,0xff,0xfe,0x15,0xc4,0xf5,0x27,0x09,0x04,0x9f,0xcb,0x02,0x9a,0x27,0x09,0x06,0x26,0x04,0xa8,0x80,0x0c,0xad,0x00,0xd0,0x00,0x26,0x70,0x01,0xfe,0x15,0xc4,0xf5,0x27,0x09};
Topology::Topology(const RuntimeEnvironment *renv,void *tPtr) :
RR(renv),
_numConfiguredPhysicalPaths(0),
_amUpstream(false)
_numConfiguredPhysicalPaths(0)
{
uint8_t tmp[ZT_WORLD_MAX_SERIALIZED_LENGTH];
uint64_t idtmp[2];
idtmp[0] = 0; idtmp[1] = 0;
int n = RR->node->stateObjectGet(tPtr,ZT_STATE_OBJECT_PLANET,idtmp,tmp,sizeof(tmp));
if (n > 0) {
try {
World cachedPlanet;
cachedPlanet.deserialize(Buffer<ZT_WORLD_MAX_SERIALIZED_LENGTH>(tmp,(unsigned int)n),0);
addWorld(tPtr,cachedPlanet,false);
} catch ( ... ) {} // ignore invalid cached planets
}
World defaultPlanet;
{
Buffer<ZT_DEFAULT_WORLD_LENGTH> wtmp(ZT_DEFAULT_WORLD,ZT_DEFAULT_WORLD_LENGTH);
defaultPlanet.deserialize(wtmp,0); // throws on error, which would indicate a bad static variable up top
}
addWorld(tPtr,defaultPlanet,false);
}
Topology::~Topology()
@ -158,224 +111,33 @@ Identity Topology::getIdentity(void *tPtr,const Address &zta)
SharedPtr<Peer> Topology::getUpstreamPeer()
{
const int64_t now = RR->node->now();
unsigned int bestq = ~((unsigned int)0);
const SharedPtr<Peer> *best = (const SharedPtr<Peer> *)0;
Mutex::Lock _l2(_peers_m);
Mutex::Lock _l1(_upstreams_m);
for(std::vector<Address>::const_iterator a(_upstreamAddresses.begin());a!=_upstreamAddresses.end();++a) {
const SharedPtr<Peer> *p = _peers.get(*a);
if (p) {
const unsigned int q = (*p)->relayQuality(now);
if (q <= bestq) {
bestq = q;
best = p;
}
}
}
if (!best)
return SharedPtr<Peer>();
return *best;
}
bool Topology::isUpstream(const Identity &id) const
{
Mutex::Lock _l(_upstreams_m);
return (std::find(_upstreamAddresses.begin(),_upstreamAddresses.end(),id.address()) != _upstreamAddresses.end());
}
bool Topology::shouldAcceptWorldUpdateFrom(const Address &addr) const
{
Mutex::Lock _l(_upstreams_m);
if (std::find(_upstreamAddresses.begin(),_upstreamAddresses.end(),addr) != _upstreamAddresses.end())
return true;
for(std::vector< std::pair< uint64_t,Address> >::const_iterator s(_moonSeeds.begin());s!=_moonSeeds.end();++s) {
if (s->second == addr)
return true;
}
return false;
}
ZT_PeerRole Topology::role(const Address &ztaddr) const
{
Mutex::Lock _l(_upstreams_m);
if (std::find(_upstreamAddresses.begin(),_upstreamAddresses.end(),ztaddr) != _upstreamAddresses.end()) {
for(std::vector<World::Root>::const_iterator i(_planet.roots().begin());i!=_planet.roots().end();++i) {
if (i->identity.address() == ztaddr)
return ZT_PEER_ROLE_PLANET;
}
return ZT_PEER_ROLE_MOON;
}
return ZT_PEER_ROLE_LEAF;
}
bool Topology::isProhibitedEndpoint(const Address &ztaddr,const InetAddress &ipaddr) const
{
Mutex::Lock _l(_upstreams_m);
// For roots the only permitted addresses are those defined. This adds just a little
// bit of extra security against spoofing, replaying, etc.
if (std::find(_upstreamAddresses.begin(),_upstreamAddresses.end(),ztaddr) != _upstreamAddresses.end()) {
for(std::vector<World::Root>::const_iterator r(_planet.roots().begin());r!=_planet.roots().end();++r) {
if (r->identity.address() == ztaddr) {
if (r->stableEndpoints.size() == 0)
return false; // no stable endpoints specified, so allow dynamic paths
for(std::vector<InetAddress>::const_iterator e(r->stableEndpoints.begin());e!=r->stableEndpoints.end();++e) {
if (ipaddr.ipsEqual(*e))
return false;
}
}
}
for(std::vector<World>::const_iterator m(_moons.begin());m!=_moons.end();++m) {
for(std::vector<World::Root>::const_iterator r(m->roots().begin());r!=m->roots().end();++r) {
if (r->identity.address() == ztaddr) {
if (r->stableEndpoints.size() == 0)
return false; // no stable endpoints specified, so allow dynamic paths
for(std::vector<InetAddress>::const_iterator e(r->stableEndpoints.begin());e!=r->stableEndpoints.end();++e) {
if (ipaddr.ipsEqual(*e))
return false;
}
}
}
}
return true;
}
return false;
}
bool Topology::addWorld(void *tPtr,const World &newWorld,bool alwaysAcceptNew)
{
if ((newWorld.type() != World::TYPE_PLANET)&&(newWorld.type() != World::TYPE_MOON))
return false;
Mutex::Lock _l2(_peers_m);
Mutex::Lock _l1(_upstreams_m);
World *existing = (World *)0;
switch(newWorld.type()) {
case World::TYPE_PLANET:
existing = &_planet;
break;
case World::TYPE_MOON:
for(std::vector< World >::iterator m(_moons.begin());m!=_moons.end();++m) {
if (m->id() == newWorld.id()) {
existing = &(*m);
break;
}
}
break;
default:
return false;
}
if (existing) {
if (existing->shouldBeReplacedBy(newWorld))
*existing = newWorld;
else return false;
} else if (newWorld.type() == World::TYPE_MOON) {
if (alwaysAcceptNew) {
_moons.push_back(newWorld);
existing = &(_moons.back());
} else {
for(std::vector< std::pair<uint64_t,Address> >::iterator m(_moonSeeds.begin());m!=_moonSeeds.end();++m) {
if (m->first == newWorld.id()) {
for(std::vector<World::Root>::const_iterator r(newWorld.roots().begin());r!=newWorld.roots().end();++r) {
if (r->identity.address() == m->second) {
_moonSeeds.erase(m);
_moons.push_back(newWorld);
existing = &(_moons.back());
break;
}
}
if (existing)
break;
}
}
}
if (!existing)
return false;
} else {
return false;
}
try {
Buffer<ZT_WORLD_MAX_SERIALIZED_LENGTH> sbuf;
existing->serialize(sbuf,false);
uint64_t idtmp[2];
idtmp[0] = existing->id(); idtmp[1] = 0;
RR->node->stateObjectPut(tPtr,(existing->type() == World::TYPE_PLANET) ? ZT_STATE_OBJECT_PLANET : ZT_STATE_OBJECT_MOON,idtmp,sbuf.data(),sbuf.size());
} catch ( ... ) {}
_memoizeUpstreams(tPtr);
return true;
}
void Topology::addMoon(void *tPtr,const uint64_t id,const Address &seed)
{
char tmp[ZT_WORLD_MAX_SERIALIZED_LENGTH];
uint64_t idtmp[2];
idtmp[0] = id; idtmp[1] = 0;
int n = RR->node->stateObjectGet(tPtr,ZT_STATE_OBJECT_MOON,idtmp,tmp,sizeof(tmp));
if (n > 0) {
try {
World w;
w.deserialize(Buffer<ZT_WORLD_MAX_SERIALIZED_LENGTH>(tmp,(unsigned int)n));
if ((w.type() == World::TYPE_MOON)&&(w.id() == id)) {
addWorld(tPtr,w,true);
return;
}
} catch ( ... ) {}
}
if (seed) {
Mutex::Lock _l(_upstreams_m);
if (std::find(_moonSeeds.begin(),_moonSeeds.end(),std::pair<uint64_t,Address>(id,seed)) == _moonSeeds.end())
_moonSeeds.push_back(std::pair<uint64_t,Address>(id,seed));
}
}
void Topology::removeMoon(void *tPtr,const uint64_t id)
{
Mutex::Lock _l2(_peers_m);
Mutex::Lock _l1(_upstreams_m);
std::vector<World> nm;
for(std::vector<World>::const_iterator m(_moons.begin());m!=_moons.end();++m) {
if (m->id() != id) {
nm.push_back(*m);
} else {
uint64_t idtmp[2];
idtmp[0] = id; idtmp[1] = 0;
RR->node->stateObjectDelete(tPtr,ZT_STATE_OBJECT_MOON,idtmp);
}
}
_moons.swap(nm);
std::vector< std::pair<uint64_t,Address> > cm;
for(std::vector< std::pair<uint64_t,Address> >::const_iterator m(_moonSeeds.begin());m!=_moonSeeds.end();++m) {
if (m->first != id)
cm.push_back(*m);
}
_moonSeeds.swap(cm);
_memoizeUpstreams(tPtr);
}
void Topology::doPeriodicTasks(void *tPtr,int64_t now)
{
{
Mutex::Lock _l1(_peers_m);
Mutex::Lock _l2(_upstreams_m);
Hashtable< Address,SharedPtr<Peer> >::Iterator i(_peers);
Address *a = (Address *)0;
SharedPtr<Peer> *p = (SharedPtr<Peer> *)0;
while (i.next(a,p)) {
if ( (!(*p)->isAlive(now)) && (std::find(_upstreamAddresses.begin(),_upstreamAddresses.end(),*a) == _upstreamAddresses.end()) ) {
if (!(*p)->isAlive(now)) {
_savePeer(tPtr,*p);
_peers.erase(*a);
}
@ -394,39 +156,40 @@ void Topology::doPeriodicTasks(void *tPtr,int64_t now)
}
}
void Topology::_memoizeUpstreams(void *tPtr)
void Topology::setPhysicalPathConfiguration(const struct sockaddr_storage *pathNetwork,const ZT_PhysicalPathConfiguration *pathConfig)
{
// assumes _upstreams_m and _peers_m are locked
_upstreamAddresses.clear();
_amUpstream = false;
if (!pathNetwork) {
_numConfiguredPhysicalPaths = 0;
} else {
std::map<InetAddress,ZT_PhysicalPathConfiguration> cpaths;
for(unsigned int i=0,j=_numConfiguredPhysicalPaths;i<j;++i)
cpaths[_physicalPathConfig[i].first] = _physicalPathConfig[i].second;
for(std::vector<World::Root>::const_iterator i(_planet.roots().begin());i!=_planet.roots().end();++i) {
if (i->identity == RR->identity) {
_amUpstream = true;
} else if (std::find(_upstreamAddresses.begin(),_upstreamAddresses.end(),i->identity.address()) == _upstreamAddresses.end()) {
_upstreamAddresses.push_back(i->identity.address());
SharedPtr<Peer> &hp = _peers[i->identity.address()];
if (!hp)
hp = new Peer(RR,RR->identity,i->identity);
}
if (pathConfig) {
ZT_PhysicalPathConfiguration pc(*pathConfig);
if (pc.mtu <= 0)
pc.mtu = ZT_DEFAULT_PHYSMTU;
else if (pc.mtu < ZT_MIN_PHYSMTU)
pc.mtu = ZT_MIN_PHYSMTU;
else if (pc.mtu > ZT_MAX_PHYSMTU)
pc.mtu = ZT_MAX_PHYSMTU;
cpaths[*(reinterpret_cast<const InetAddress *>(pathNetwork))] = pc;
} else {
cpaths.erase(*(reinterpret_cast<const InetAddress *>(pathNetwork)));
}
for(std::vector<World>::const_iterator m(_moons.begin());m!=_moons.end();++m) {
for(std::vector<World::Root>::const_iterator i(m->roots().begin());i!=m->roots().end();++i) {
if (i->identity == RR->identity) {
_amUpstream = true;
} else if (std::find(_upstreamAddresses.begin(),_upstreamAddresses.end(),i->identity.address()) == _upstreamAddresses.end()) {
_upstreamAddresses.push_back(i->identity.address());
SharedPtr<Peer> &hp = _peers[i->identity.address()];
if (!hp)
hp = new Peer(RR,RR->identity,i->identity);
unsigned int cnt = 0;
for(std::map<InetAddress,ZT_PhysicalPathConfiguration>::const_iterator i(cpaths.begin());((i!=cpaths.end())&&(cnt<ZT_MAX_CONFIGURABLE_PATHS));++i) {
_physicalPathConfig[cnt].first = i->first;
_physicalPathConfig[cnt].second = i->second;
++cnt;
}
_numConfiguredPhysicalPaths = cnt;
}
}
std::sort(_upstreamAddresses.begin(),_upstreamAddresses.end());
}
void Topology::_savePeer(void *tPtr,const SharedPtr<Peer> &peer)
{
try {

View file

@ -45,7 +45,6 @@
#include "Mutex.hpp"
#include "InetAddress.hpp"
#include "Hashtable.hpp"
#include "World.hpp"
namespace ZeroTier {
@ -136,12 +135,6 @@ public:
*/
bool isUpstream(const Identity &id) const;
/**
* @param addr Address to check
* @return True if we should accept a world update from this address
*/
bool shouldAcceptWorldUpdateFrom(const Address &addr) const;
/**
* @param ztaddr ZeroTier address
* @return Peer role for this device
@ -171,29 +164,6 @@ public:
*/
inline void getUpstreamsToContact(Hashtable< Address,std::vector<InetAddress> > &eps) const
{
Mutex::Lock _l(_upstreams_m);
for(std::vector<World::Root>::const_iterator i(_planet.roots().begin());i!=_planet.roots().end();++i) {
if (i->identity != RR->identity) {
std::vector<InetAddress> &ips = eps[i->identity.address()];
for(std::vector<InetAddress>::const_iterator j(i->stableEndpoints.begin());j!=i->stableEndpoints.end();++j) {
if (std::find(ips.begin(),ips.end(),*j) == ips.end())
ips.push_back(*j);
}
}
}
for(std::vector<World>::const_iterator m(_moons.begin());m!=_moons.end();++m) {
for(std::vector<World::Root>::const_iterator i(m->roots().begin());i!=m->roots().end();++i) {
if (i->identity != RR->identity) {
std::vector<InetAddress> &ips = eps[i->identity.address()];
for(std::vector<InetAddress>::const_iterator j(i->stableEndpoints.begin());j!=i->stableEndpoints.end();++j) {
if (std::find(ips.begin(),ips.end(),*j) == ips.end())
ips.push_back(*j);
}
}
}
}
for(std::vector< std::pair<uint64_t,Address> >::const_iterator m(_moonSeeds.begin());m!=_moonSeeds.end();++m)
eps[m->second];
}
/**
@ -201,87 +171,10 @@ public:
*/
inline std::vector<Address> upstreamAddresses() const
{
Mutex::Lock _l(_upstreams_m);
return _upstreamAddresses;
// TODO
return std::vector<Address>();
}
/**
* @return Current moons
*/
inline std::vector<World> moons() const
{
Mutex::Lock _l(_upstreams_m);
return _moons;
}
/**
* @return Moon IDs we are waiting for from seeds
*/
inline std::vector<uint64_t> moonsWanted() const
{
Mutex::Lock _l(_upstreams_m);
std::vector<uint64_t> mw;
for(std::vector< std::pair<uint64_t,Address> >::const_iterator s(_moonSeeds.begin());s!=_moonSeeds.end();++s) {
if (std::find(mw.begin(),mw.end(),s->first) == mw.end())
mw.push_back(s->first);
}
return mw;
}
/**
* @return Current planet
*/
inline World planet() const
{
Mutex::Lock _l(_upstreams_m);
return _planet;
}
/**
* @return Current planet's world ID
*/
inline uint64_t planetWorldId() const
{
return _planet.id(); // safe to read without lock, and used from within eachPeer() so don't lock
}
/**
* @return Current planet's world timestamp
*/
inline uint64_t planetWorldTimestamp() const
{
return _planet.timestamp(); // safe to read without lock, and used from within eachPeer() so don't lock
}
/**
* Validate new world and update if newer and signature is okay
*
* @param tPtr Thread pointer to be handed through to any callbacks called as a result of this call
* @param newWorld A new or updated planet or moon to learn
* @param alwaysAcceptNew If true, always accept new moons even if we're not waiting for one
* @return True if it was valid and newer than current (or totally new for moons)
*/
bool addWorld(void *tPtr,const World &newWorld,bool alwaysAcceptNew);
/**
* Add a moon
*
* This loads it from moons.d if present, and if not adds it to
* a list of moons that we want to contact.
*
* @param id Moon ID
* @param seed If non-NULL, an address of any member of the moon to contact
*/
void addMoon(void *tPtr,const uint64_t id,const Address &seed);
/**
* Remove a moon
*
* @param tPtr Thread pointer to be handed through to any callbacks called as a result of this call
* @param id Moon's world ID
*/
void removeMoon(void *tPtr,const uint64_t id);
/**
* Clean and flush database
*/
@ -333,11 +226,6 @@ public:
return _peers.entries();
}
/**
* @return True if I am a root server in a planet or moon
*/
inline bool amUpstream() const { return _amUpstream; }
/**
* Get info about a path
*
@ -406,39 +294,7 @@ public:
/**
* Set or clear physical path configuration (called via Node::setPhysicalPathConfiguration)
*/
inline void setPhysicalPathConfiguration(const struct sockaddr_storage *pathNetwork,const ZT_PhysicalPathConfiguration *pathConfig)
{
if (!pathNetwork) {
_numConfiguredPhysicalPaths = 0;
} else {
std::map<InetAddress,ZT_PhysicalPathConfiguration> cpaths;
for(unsigned int i=0,j=_numConfiguredPhysicalPaths;i<j;++i)
cpaths[_physicalPathConfig[i].first] = _physicalPathConfig[i].second;
if (pathConfig) {
ZT_PhysicalPathConfiguration pc(*pathConfig);
if (pc.mtu <= 0)
pc.mtu = ZT_DEFAULT_PHYSMTU;
else if (pc.mtu < ZT_MIN_PHYSMTU)
pc.mtu = ZT_MIN_PHYSMTU;
else if (pc.mtu > ZT_MAX_PHYSMTU)
pc.mtu = ZT_MAX_PHYSMTU;
cpaths[*(reinterpret_cast<const InetAddress *>(pathNetwork))] = pc;
} else {
cpaths.erase(*(reinterpret_cast<const InetAddress *>(pathNetwork)));
}
unsigned int cnt = 0;
for(std::map<InetAddress,ZT_PhysicalPathConfiguration>::const_iterator i(cpaths.begin());((i!=cpaths.end())&&(cnt<ZT_MAX_CONFIGURABLE_PATHS));++i) {
_physicalPathConfig[cnt].first = i->first;
_physicalPathConfig[cnt].second = i->second;
++cnt;
}
_numConfiguredPhysicalPaths = cnt;
}
}
void setPhysicalPathConfiguration(const struct sockaddr_storage *pathNetwork,const ZT_PhysicalPathConfiguration *pathConfig);
private:
Identity _getIdentity(void *tPtr,const Address &zta);
@ -448,20 +304,13 @@ private:
const RuntimeEnvironment *const RR;
std::pair<InetAddress,ZT_PhysicalPathConfiguration> _physicalPathConfig[ZT_MAX_CONFIGURABLE_PATHS];
volatile unsigned int _numConfiguredPhysicalPaths;
unsigned int _numConfiguredPhysicalPaths;
Hashtable< Address,SharedPtr<Peer> > _peers;
Mutex _peers_m;
Hashtable< Path::HashKey,SharedPtr<Path> > _paths;
Mutex _paths_m;
World _planet;
std::vector<World> _moons;
std::vector< std::pair<uint64_t,Address> > _moonSeeds;
std::vector<Address> _upstreamAddresses;
bool _amUpstream;
Mutex _upstreams_m; // locks worlds, upstream info, moon info, etc.
};
} // namespace ZeroTier

View file

@ -171,4 +171,159 @@ void Utils::getSecureRandom(void *buf,unsigned int bytes)
#endif // __WINDOWS__ or not
}
int Utils::b32d(const char *encoded,uint8_t *result,int bufSize)
{
int buffer = 0;
int bitsLeft = 0;
int count = 0;
for (const uint8_t *ptr = (const uint8_t *)encoded;count<bufSize && *ptr; ++ptr) {
uint8_t ch = *ptr;
if (ch == ' ' || ch == '\t' || ch == '\r' || ch == '\n' || ch == '-' || ch == '.') {
continue;
}
buffer <<= 5;
if (ch == '0') {
ch = 'O';
} else if (ch == '1') {
ch = 'L';
} else if (ch == '8') {
ch = 'B';
}
if ((ch >= 'A' && ch <= 'Z') || (ch >= 'a' && ch <= 'z')) {
ch = (ch & 0x1F) - 1;
} else if (ch >= '2' && ch <= '7') {
ch -= '2' - 26;
} else {
return -1;
}
buffer |= ch;
bitsLeft += 5;
if (bitsLeft >= 8) {
result[count++] = buffer >> (bitsLeft - 8);
bitsLeft -= 8;
}
}
if (count < bufSize)
result[count] = (uint8_t)0;
return count;
}
int Utils::b32e(const uint8_t *data,int length,char *result,int bufSize)
{
if (length < 0 || length > (1 << 28)) {
result[0] = (char)0;
return -1;
}
int count = 0;
if (length > 0) {
int buffer = data[0];
int next = 1;
int bitsLeft = 8;
while (count < bufSize && (bitsLeft > 0 || next < length)) {
if (bitsLeft < 5) {
if (next < length) {
buffer <<= 8;
buffer |= data[next++] & 0xFF;
bitsLeft += 8;
} else {
int pad = 5 - bitsLeft;
buffer <<= pad;
bitsLeft += pad;
}
}
int index = 0x1F & (buffer >> (bitsLeft - 5));
bitsLeft -= 5;
result[count++] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567"[index];
}
}
if (count < bufSize) {
result[count] = (char)0;
return count;
}
result[0] = (char)0;
return -1;
}
unsigned int Utils::b64e(const uint8_t *in,unsigned int inlen,char *out,unsigned int outlen)
{
static const char base64en[64] = { 'A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z','a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v','w','x','y','z','0','1','2','3','4','5','6','7','8','9','+','/' };
unsigned int i = 0,j = 0;
uint8_t l = 0;
int s = 0;
for (;i<inlen;++i) {
uint8_t c = in[i];
switch (s) {
case 0:
s = 1;
if (j >= outlen) return 0;
out[j++] = base64en[(c >> 2) & 0x3f];
break;
case 1:
s = 2;
if (j >= outlen) return 0;
out[j++] = base64en[((l & 0x3) << 4) | ((c >> 4) & 0xf)];
break;
case 2:
s = 0;
if (j >= outlen) return 0;
out[j++] = base64en[((l & 0xf) << 2) | ((c >> 6) & 0x3)];
if (j >= outlen) return 0;
out[j++] = base64en[c & 0x3f];
break;
}
l = c;
}
switch (s) {
case 1:
if (j >= outlen) return 0;
out[j++] = base64en[(l & 0x3) << 4];
//out[j++] = '=';
//out[j++] = '=';
break;
case 2:
if (j >= outlen) return 0;
out[j++] = base64en[(l & 0xf) << 2];
//out[j++] = '=';
break;
}
if (j >= outlen) return 0;
out[j] = 0;
return j;
}
unsigned int Utils::b64d(const char *in,unsigned char *out,unsigned int outlen)
{
static const uint8_t base64de[256] = { 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,62,255,255,255,63,52,53,54,55,56,57,58,59,60,61,255,255,255,255,255,255,255,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,255,255,255,255,255,255,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,255,255,255,255,255 };
unsigned int i = 0;
unsigned int j = 0;
while ((in[i] != '=')&&(in[i] != 0)) {
if (j >= outlen)
break;
uint8_t c = base64de[(unsigned char)in[i]];
if (c != 255) {
switch (i & 0x3) {
case 0:
out[j] = (c << 2) & 0xff;
break;
case 1:
out[j++] |= (c >> 4) & 0x3;
out[j] = (c & 0xf) << 4;
break;
case 2:
out[j++] |= (c >> 2) & 0xf;
out[j] = (c & 0x3) << 6;
break;
case 3:
out[j++] |= c;
break;
}
}
++i;
}
return j;
}
} // namespace ZeroTier

View file

@ -38,10 +38,6 @@
#include <vector>
#include <map>
#if defined(__FreeBSD__)
#include <sys/endian.h>
#endif
#include "Constants.hpp"
namespace ZeroTier {
@ -246,6 +242,13 @@ public:
*/
static void getSecureRandom(void *buf,unsigned int bytes);
static int b32d(const char *encoded, uint8_t *result, int bufSize);
static int b32e(const uint8_t *data,int length,char *result,int bufSize);
static inline unsigned int b64MaxEncodedSize(const unsigned int s) { return ((((s + 2) / 3) * 4) + 1); }
static unsigned int b64e(const uint8_t *in,unsigned int inlen,char *out,unsigned int outlen);
static unsigned int b64d(const char *in,uint8_t *out,unsigned int outlen);
/**
* Tokenize a string (alias for strtok_r or strtok_s depending on platform)
*

View file

@ -1,284 +0,0 @@
/*
* ZeroTier One - Network Virtualization Everywhere
* Copyright (C) 2011-2019 ZeroTier, Inc. https://www.zerotier.com/
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* --
*
* You can be released from the requirements of the license by purchasing
* a commercial license. Buying such a license is mandatory as soon as you
* develop commercial closed-source software that incorporates or links
* directly against ZeroTier software without disclosing the source code
* of your own application.
*/
#ifndef ZT_WORLD_HPP
#define ZT_WORLD_HPP
#include <vector>
#include <string>
#include "Constants.hpp"
#include "InetAddress.hpp"
#include "Identity.hpp"
#include "Buffer.hpp"
#include "C25519.hpp"
/**
* Maximum number of roots (sanity limit, okay to increase)
*
* A given root can (through multi-homing) be distributed across any number of
* physical endpoints, but having more than one is good to permit total failure
* of one root or its withdrawal due to compromise without taking the whole net
* down.
*/
#define ZT_WORLD_MAX_ROOTS 4
/**
* Maximum number of stable endpoints per root (sanity limit, okay to increase)
*/
#define ZT_WORLD_MAX_STABLE_ENDPOINTS_PER_ROOT 32
/**
* The (more than) maximum length of a serialized World
*/
#define ZT_WORLD_MAX_SERIALIZED_LENGTH (((1024 + (32 * ZT_WORLD_MAX_STABLE_ENDPOINTS_PER_ROOT)) * ZT_WORLD_MAX_ROOTS) + ZT_C25519_PUBLIC_KEY_LEN + ZT_C25519_SIGNATURE_LEN + 128)
/**
* World ID for Earth
*
* This is the ID for the ZeroTier World used on planet Earth. It is unrelated
* to the public network 8056c2e21c000001 of the same name. It was chosen
* from Earth's approximate distance from the sun in kilometers.
*/
#define ZT_WORLD_ID_EARTH 149604618
/**
* World ID for Mars -- for future use by SpaceX or others
*/
#define ZT_WORLD_ID_MARS 227883110
namespace ZeroTier {
/**
* A world definition (formerly known as a root topology)
*
* Think of a World as a single data center. Within this data center a set
* of distributed fault tolerant root servers provide stable anchor points
* for a peer to peer network that provides VLAN service. Updates to a world
* definition can be published by signing them with the previous revision's
* signing key, and should be very infrequent.
*
* The maximum data center size is approximately 2.5 cubic light seconds,
* since many protocols have issues with >5s RTT latencies.
*
* ZeroTier operates a World for Earth capable of encompassing the planet, its
* orbits, the Moon (about 1.3 light seconds), and nearby Lagrange points. A
* world ID for Mars and nearby space is defined but not yet used, and a test
* world ID is provided for testing purposes.
*/
class World
{
public:
/**
* World type -- do not change IDs
*/
enum Type
{
TYPE_NULL = 0,
TYPE_PLANET = 1, // Planets, of which there is currently one (Earth)
TYPE_MOON = 127 // Moons, which are user-created and many
};
/**
* Upstream server definition in world/moon
*/
struct Root
{
Identity identity;
std::vector<InetAddress> stableEndpoints;
inline bool operator==(const Root &r) const { return ((identity == r.identity)&&(stableEndpoints == r.stableEndpoints)); }
inline bool operator!=(const Root &r) const { return (!(*this == r)); }
inline bool operator<(const Root &r) const { return (identity < r.identity); } // for sorting
};
/**
* Construct an empty / null World
*/
World() :
_id(0),
_ts(0),
_type(TYPE_NULL) {}
/**
* @return Root servers for this world and their stable endpoints
*/
inline const std::vector<World::Root> &roots() const { return _roots; }
/**
* @return World type: planet or moon
*/
inline Type type() const { return _type; }
/**
* @return World unique identifier
*/
inline uint64_t id() const { return _id; }
/**
* @return World definition timestamp
*/
inline uint64_t timestamp() const { return _ts; }
/**
* @return C25519 signature
*/
inline const C25519::Signature &signature() const { return _signature; }
/**
* @return Public key that must sign next update
*/
inline const C25519::Public &updatesMustBeSignedBy() const { return _updatesMustBeSignedBy; }
/**
* Check whether a world update should replace this one
*
* @param update Candidate update
* @return True if update is newer than current, matches its ID and type, and is properly signed (or if current is NULL)
*/
inline bool shouldBeReplacedBy(const World &update)
{
if ((_id == 0)||(_type == TYPE_NULL))
return true;
if ((_id == update._id)&&(_ts < update._ts)&&(_type == update._type)) {
Buffer<ZT_WORLD_MAX_SERIALIZED_LENGTH> tmp;
update.serialize(tmp,true);
return C25519::verify(_updatesMustBeSignedBy,tmp.data(),tmp.size(),update._signature);
}
return false;
}
/**
* @return True if this World is non-empty
*/
inline operator bool() const { return (_type != TYPE_NULL); }
template<unsigned int C>
inline void serialize(Buffer<C> &b,bool forSign = false) const
{
if (forSign) b.append((uint64_t)0x7f7f7f7f7f7f7f7fULL);
b.append((uint8_t)_type);
b.append((uint64_t)_id);
b.append((uint64_t)_ts);
b.append(_updatesMustBeSignedBy.data,ZT_C25519_PUBLIC_KEY_LEN);
if (!forSign)
b.append(_signature.data,ZT_C25519_SIGNATURE_LEN);
b.append((uint8_t)_roots.size());
for(std::vector<Root>::const_iterator r(_roots.begin());r!=_roots.end();++r) {
r->identity.serialize(b);
b.append((uint8_t)r->stableEndpoints.size());
for(std::vector<InetAddress>::const_iterator ep(r->stableEndpoints.begin());ep!=r->stableEndpoints.end();++ep)
ep->serialize(b);
}
if (_type == TYPE_MOON)
b.append((uint16_t)0); // no attached dictionary (for future use)
if (forSign) b.append((uint64_t)0xf7f7f7f7f7f7f7f7ULL);
}
template<unsigned int C>
inline unsigned int deserialize(const Buffer<C> &b,unsigned int startAt = 0)
{
unsigned int p = startAt;
_roots.clear();
switch((Type)b[p++]) {
case TYPE_NULL: _type = TYPE_NULL; break; // shouldn't ever really happen in serialized data but it's not invalid
case TYPE_PLANET: _type = TYPE_PLANET; break;
case TYPE_MOON: _type = TYPE_MOON; break;
default:
throw ZT_EXCEPTION_INVALID_SERIALIZED_DATA_INVALID_TYPE;
}
_id = b.template at<uint64_t>(p); p += 8;
_ts = b.template at<uint64_t>(p); p += 8;
memcpy(_updatesMustBeSignedBy.data,b.field(p,ZT_C25519_PUBLIC_KEY_LEN),ZT_C25519_PUBLIC_KEY_LEN); p += ZT_C25519_PUBLIC_KEY_LEN;
memcpy(_signature.data,b.field(p,ZT_C25519_SIGNATURE_LEN),ZT_C25519_SIGNATURE_LEN); p += ZT_C25519_SIGNATURE_LEN;
const unsigned int numRoots = (unsigned int)b[p++];
if (numRoots > ZT_WORLD_MAX_ROOTS)
throw ZT_EXCEPTION_INVALID_SERIALIZED_DATA_OVERFLOW;
for(unsigned int k=0;k<numRoots;++k) {
_roots.push_back(Root());
Root &r = _roots.back();
p += r.identity.deserialize(b,p);
unsigned int numStableEndpoints = b[p++];
if (numStableEndpoints > ZT_WORLD_MAX_STABLE_ENDPOINTS_PER_ROOT)
throw ZT_EXCEPTION_INVALID_SERIALIZED_DATA_OVERFLOW;
for(unsigned int kk=0;kk<numStableEndpoints;++kk) {
r.stableEndpoints.push_back(InetAddress());
p += r.stableEndpoints.back().deserialize(b,p);
}
}
if (_type == TYPE_MOON)
p += b.template at<uint16_t>(p) + 2;
return (p - startAt);
}
inline bool operator==(const World &w) const { return ((_id == w._id)&&(_ts == w._ts)&&(memcmp(_updatesMustBeSignedBy.data,w._updatesMustBeSignedBy.data,ZT_C25519_PUBLIC_KEY_LEN) == 0)&&(memcmp(_signature.data,w._signature.data,ZT_C25519_SIGNATURE_LEN) == 0)&&(_roots == w._roots)&&(_type == w._type)); }
inline bool operator!=(const World &w) const { return (!(*this == w)); }
/**
* Create a World object signed with a key pair
*
* @param t World type
* @param id World ID
* @param ts World timestamp / revision
* @param sk Key that must be used to sign the next future update to this world
* @param roots Roots and their stable endpoints
* @param signWith Key to sign this World with (can have the same public as the next-update signing key, but doesn't have to)
* @return Signed World object
*/
static inline World make(World::Type t,uint64_t id,uint64_t ts,const C25519::Public &sk,const std::vector<World::Root> &roots,const C25519::Pair &signWith)
{
World w;
w._id = id;
w._ts = ts;
w._type = t;
w._updatesMustBeSignedBy = sk;
w._roots = roots;
Buffer<ZT_WORLD_MAX_SERIALIZED_LENGTH> tmp;
w.serialize(tmp,true);
w._signature = C25519::sign(signWith,tmp.data(),tmp.size());
return w;
}
protected:
uint64_t _id;
uint64_t _ts;
Type _type;
C25519::Public _updatesMustBeSignedBy;
C25519::Signature _signature;
std::vector<Root> _roots;
};
} // namespace ZeroTier
#endif

View file

@ -3,6 +3,7 @@ CORE_OBJS=\
node/Capability.o \
node/CertificateOfMembership.o \
node/CertificateOfOwnership.o \
node/ECC384.o \
node/Identity.o \
node/IncomingPacket.o \
node/InetAddress.o \

177
one.cpp
View file

@ -79,7 +79,6 @@
#include "node/Utils.hpp"
#include "node/NetworkController.hpp"
#include "node/Buffer.hpp"
#include "node/World.hpp"
#include "osdep/OSUtils.hpp"
#include "osdep/Http.hpp"
@ -136,9 +135,6 @@ static void cliPrintHelp(const char *pn,FILE *out)
fprintf(out," leave <network> - Leave a network" ZT_EOL_S);
fprintf(out," set <network> <setting> - Set a network setting" ZT_EOL_S);
fprintf(out," get <network> <setting> - Get a network setting" ZT_EOL_S);
fprintf(out," listmoons - List moons (federated root sets)" ZT_EOL_S);
fprintf(out," orbit <world ID> <seed> - Join a moon via any member root" ZT_EOL_S);
fprintf(out," deorbit <world ID> - Leave a moon" ZT_EOL_S);
fprintf(out,ZT_EOL_S"Available settings:" ZT_EOL_S);
fprintf(out," Settings to use with [get/set] may include property names from " ZT_EOL_S);
fprintf(out," the JSON output of \"zerotier-cli -j listnetworks\". Additionally, " ZT_EOL_S);
@ -593,80 +589,6 @@ static int cli(int argc,char **argv)
printf("%u %s %s" ZT_EOL_S,scode,command.c_str(),responseBody.c_str());
return 1;
}
} else if (command == "listmoons") {
const unsigned int scode = Http::GET(1024 * 1024 * 16,60000,(const struct sockaddr *)&addr,"/moon",requestHeaders,responseHeaders,responseBody);
if (scode == 0) {
printf("Error connecting to the ZeroTier service: %s\n\nPlease check that the service is running and that TCP port 9993 can be contacted via 127.0.0.1." ZT_EOL_S, responseBody.c_str());
return 1;
}
nlohmann::json j;
try {
j = OSUtils::jsonParse(responseBody);
} catch (std::exception &exc) {
printf("%u %s invalid JSON response (%s)" ZT_EOL_S,scode,command.c_str(),exc.what());
return 1;
} catch ( ... ) {
printf("%u %s invalid JSON response (unknown exception)" ZT_EOL_S,scode,command.c_str());
return 1;
}
if (scode == 200) {
printf("%s" ZT_EOL_S,OSUtils::jsonDump(j).c_str());
return 0;
} else {
printf("%u %s %s" ZT_EOL_S,scode,command.c_str(),responseBody.c_str());
return 1;
}
} else if (command == "orbit") {
const uint64_t worldId = Utils::hexStrToU64(arg1.c_str());
const uint64_t seed = Utils::hexStrToU64(arg2.c_str());
if ((worldId)&&(seed)) {
char jsons[1024];
OSUtils::ztsnprintf(jsons,sizeof(jsons),"{\"seed\":\"%s\"}",arg2.c_str());
char cl[128];
OSUtils::ztsnprintf(cl,sizeof(cl),"%u",(unsigned int)strlen(jsons));
requestHeaders["Content-Type"] = "application/json";
requestHeaders["Content-Length"] = cl;
unsigned int scode = Http::POST(
1024 * 1024 * 16,
60000,
(const struct sockaddr *)&addr,
(std::string("/moon/") + arg1).c_str(),
requestHeaders,
jsons,
(unsigned long)strlen(jsons),
responseHeaders,
responseBody);
if (scode == 200) {
printf("200 orbit OK" ZT_EOL_S);
return 0;
} else {
printf("%u %s %s" ZT_EOL_S,scode,command.c_str(),responseBody.c_str());
return 1;
}
}
} else if (command == "deorbit") {
unsigned int scode = Http::DEL(
1024 * 1024 * 16,
60000,
(const struct sockaddr *)&addr,
(std::string("/moon/") + arg1).c_str(),
requestHeaders,
responseHeaders,
responseBody);
if (scode == 200) {
if (json) {
printf("%s",cliFixJsonCRs(responseBody).c_str());
} else {
printf("200 deorbit OK" ZT_EOL_S);
}
return 0;
} else {
printf("%u %s %s" ZT_EOL_S,scode,command.c_str(),responseBody.c_str());
return 1;
}
} else if (command == "set") {
if (arg1.length() != 16) {
fprintf(stderr,"invalid format: must be a 16-digit (network) ID\n");
@ -829,8 +751,6 @@ static void idtoolPrintHelp(FILE *out,const char *pn)
fprintf(out," getpublic <identity.secret>" ZT_EOL_S);
fprintf(out," sign <identity.secret> <file>" ZT_EOL_S);
fprintf(out," verify <identity.secret/public> <file> <signature>" ZT_EOL_S);
fprintf(out," initmoon <identity.public of first seed>" ZT_EOL_S);
fprintf(out," genmoon <moon json>" ZT_EOL_S);
}
static Identity getIdFromArg(char *arg)
@ -872,7 +792,7 @@ static int idtool(int argc,char **argv)
Identity id;
for(;;) {
id.generate();
id.generate(Identity::C25519);
if ((id.address().toInt() >> (40 - vanityBits)) == vanity) {
if (vanityBits > 0) {
fprintf(stderr,"vanity address: found %.10llx !\n",(unsigned long long)id.address().toInt());
@ -950,9 +870,10 @@ static int idtool(int argc,char **argv)
fprintf(stderr,"%s is not readable" ZT_EOL_S,argv[3]);
return 1;
}
C25519::Signature signature = id.sign(inf.data(),(unsigned int)inf.length());
char hexbuf[1024];
printf("%s",Utils::hex(signature.data,ZT_C25519_SIGNATURE_LEN,hexbuf));
uint8_t signature[ZT_SIGNATURE_BUFFER_SIZE];
const unsigned int siglen = id.sign(inf.data(),(unsigned int)inf.length(),signature,sizeof(signature));
char hexbuf[256];
printf("%s",Utils::hex(signature,siglen,hexbuf));
} else if (!strcmp(argv[1],"verify")) {
if (argc < 5) {
idtoolPrintHelp(stdout,argv[0]);
@ -990,94 +911,6 @@ static int idtool(int argc,char **argv)
return 1;
}
}
} else if (!strcmp(argv[1],"initmoon")) {
if (argc < 3) {
idtoolPrintHelp(stdout,argv[0]);
} else {
const Identity id = getIdFromArg(argv[2]);
if (!id) {
fprintf(stderr,"%s is not a valid identity" ZT_EOL_S,argv[2]);
return 1;
}
C25519::Pair kp(C25519::generate());
char idtmp[4096];
nlohmann::json mj;
mj["objtype"] = "world";
mj["worldType"] = "moon";
mj["updatesMustBeSignedBy"] = mj["signingKey"] = Utils::hex(kp.pub.data,ZT_C25519_PUBLIC_KEY_LEN,idtmp);
mj["signingKey_SECRET"] = Utils::hex(kp.priv.data,ZT_C25519_PRIVATE_KEY_LEN,idtmp);
mj["id"] = id.address().toString(idtmp);
nlohmann::json seedj;
seedj["identity"] = id.toString(false,idtmp);
seedj["stableEndpoints"] = nlohmann::json::array();
(mj["roots"] = nlohmann::json::array()).push_back(seedj);
std::string mjd(OSUtils::jsonDump(mj));
printf("%s" ZT_EOL_S,mjd.c_str());
}
} else if (!strcmp(argv[1],"genmoon")) {
if (argc < 3) {
idtoolPrintHelp(stdout,argv[0]);
} else {
std::string buf;
if (!OSUtils::readFile(argv[2],buf)) {
fprintf(stderr,"cannot read %s" ZT_EOL_S,argv[2]);
return 1;
}
nlohmann::json mj(OSUtils::jsonParse(buf));
const uint64_t id = Utils::hexStrToU64(OSUtils::jsonString(mj["id"],"0").c_str());
if (!id) {
fprintf(stderr,"ID in %s is invalid" ZT_EOL_S,argv[2]);
return 1;
}
World::Type t;
if (mj["worldType"] == "moon") {
t = World::TYPE_MOON;
} else if (mj["worldType"] == "planet") {
t = World::TYPE_PLANET;
} else {
fprintf(stderr,"invalid worldType" ZT_EOL_S);
return 1;
}
C25519::Pair signingKey;
C25519::Public updatesMustBeSignedBy;
Utils::unhex(OSUtils::jsonString(mj["signingKey"],"").c_str(),signingKey.pub.data,ZT_C25519_PUBLIC_KEY_LEN);
Utils::unhex(OSUtils::jsonString(mj["signingKey_SECRET"],"").c_str(),signingKey.priv.data,ZT_C25519_PRIVATE_KEY_LEN);
Utils::unhex(OSUtils::jsonString(mj["updatesMustBeSignedBy"],"").c_str(),updatesMustBeSignedBy.data,ZT_C25519_PUBLIC_KEY_LEN);
std::vector<World::Root> roots;
nlohmann::json &rootsj = mj["roots"];
if (rootsj.is_array()) {
for(unsigned long i=0;i<(unsigned long)rootsj.size();++i) {
nlohmann::json &r = rootsj[i];
if (r.is_object()) {
roots.push_back(World::Root());
roots.back().identity = Identity(OSUtils::jsonString(r["identity"],"").c_str());
nlohmann::json &stableEndpointsj = r["stableEndpoints"];
if (stableEndpointsj.is_array()) {
for(unsigned long k=0;k<(unsigned long)stableEndpointsj.size();++k)
roots.back().stableEndpoints.push_back(InetAddress(OSUtils::jsonString(stableEndpointsj[k],"").c_str()));
std::sort(roots.back().stableEndpoints.begin(),roots.back().stableEndpoints.end());
}
}
}
}
std::sort(roots.begin(),roots.end());
const int64_t now = OSUtils::now();
World w(World::make(t,id,now,updatesMustBeSignedBy,roots,signingKey));
Buffer<ZT_WORLD_MAX_SERIALIZED_LENGTH> wbuf;
w.serialize(wbuf);
char fn[128];
OSUtils::ztsnprintf(fn,sizeof(fn),"%.16llx.moon",w.id());
OSUtils::writeFile(fn,wbuf.data(),wbuf.size());
printf("wrote %s (signed world with timestamp %llu)" ZT_EOL_S,fn,(unsigned long long)now);
}
} else {
idtoolPrintHelp(stdout,argv[0]);
return 1;

View file

@ -61,6 +61,7 @@
#include <sys/un.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <netinet/ip6.h>
#include <netinet/tcp.h>
#if defined(__linux__) || defined(linux) || defined(__LINUX__) || defined(__linux)

View file

@ -50,6 +50,7 @@
#include "node/Dictionary.hpp"
#include "node/SHA512.hpp"
#include "node/C25519.hpp"
#include "node/ECC384.hpp"
#include "node/Poly1305.hpp"
#include "node/CertificateOfMembership.hpp"
#include "node/Node.hpp"
@ -78,6 +79,14 @@ using namespace ZeroTier;
#define KNOWN_GOOD_IDENTITY "8e4df28b72:0:ac3d46abe0c21f3cfe7a6c8d6a85cfcffcb82fbd55af6a4d6350657c68200843fa2e16f9418bbd9702cae365f2af5fb4c420908b803a681d4daef6114d78a2d7:bd8dd6e4ce7022d2f812797a80c6ee8ad180dc4ebf301dec8b06d1be08832bddd63a2f1cfa7b2c504474c75bdc8898ba476ef92e8e2d0509f8441985171ff16e"
#define KNOWN_BAD_IDENTITY "9e4df28b72:0:ac3d46abe0c21f3cfe7a6c8d6a85cfcffcb82fbd55af6a4d6350657c68200843fa2e16f9418bbd9702cae365f2af5fb4c420908b803a681d4daef6114d78a2d7:bd8dd6e4ce7022d2f812797a80c6ee8ad180dc4ebf301dec8b06d1be08832bddd63a2f1cfa7b2c504474c75bdc8898ba476ef92e8e2d0509f8441985171ff16e"
// These were generated with some Go code using the NIST P-384 elliptic curve. There
// are official P-384 test vectors but the format of these is funny and converting is
// a pain, so this is easier. We assume the Go runtime's P-384 implementation is correct.
#define ECC384_TEST_PUBLIC "02edbcbb1f239bbd9d3d7cef6b37a32669e94df42664fbac7640c22221a6a3df8c9681760f0e67abd45158b31563fb4971"
#define ECC384_TEST_PRIVATE "62939b4a293cc68698c3d07fb7ff97a2fbc9368a1da5408e4913d41546cbb408fa8cb27fcc3f72f80d167bf0a4c329d3"
#define ECC384_TEST_DH_SELF_AGREE "f696bd1bda5e528c1d56a36ed9bad784dd201b50c9d868b9529327ab17edc6ae895e7fd9461587f4c8472ef786f5870b"
#define ECC384_TEST_SIG "98935f0a052cba3ad7d208de64e7772cbde6d91611d2ef03ba129f1498498c2d3650d9cfbb2beacb28e70b90439e018b52db46ecc7f6a95688003cdb4ffe04a1c74c3ffcb8c8704212f437facdb9172f608cb605c6ce37d6c9f00b233910290d"
static const unsigned char s20TV0Key[32] = { 0x0f,0x62,0xb5,0x08,0x5b,0xae,0x01,0x54,0xa7,0xfa,0x4d,0xa0,0xf3,0x46,0x99,0xec,0x3f,0x92,0xe5,0x38,0x8b,0xde,0x31,0x84,0xd7,0x2a,0x7d,0xd0,0x23,0x76,0xc9,0x1c };
static const unsigned char s20TV0Iv[8] = { 0x28,0x8f,0xf6,0x5d,0xc4,0x2b,0x92,0xf9 };
static const unsigned char s20TV0Ks[64] = { 0x5e,0x5e,0x71,0xf9,0x01,0x99,0x34,0x03,0x04,0xab,0xb2,0x2a,0x37,0xb6,0x62,0x5b,0xf8,0x83,0xfb,0x89,0xce,0x3b,0x21,0xf5,0x4a,0x10,0xb8,0x10,0x66,0xef,0x87,0xda,0x30,0xb7,0x76,0x99,0xaa,0x73,0x79,0xda,0x59,0x5c,0x77,0xdd,0x59,0x54,0x2d,0xa2,0x08,0xe5,0x95,0x4f,0x89,0xe4,0x0e,0xb7,0xaa,0x80,0xa8,0x4a,0x61,0x76,0x66,0x3f };
@ -96,6 +105,7 @@ static const unsigned char poly1305TV1Tag[16] = { 0xa6,0xf7,0x45,0x00,0x8f,0x81,
static const char *sha512TV0Input = "supercalifragilisticexpealidocious";
static const unsigned char sha512TV0Digest[64] = { 0x18,0x2a,0x85,0x59,0x69,0xe5,0xd3,0xe6,0xcb,0xf6,0x05,0x24,0xad,0xf2,0x88,0xd1,0xbb,0xf2,0x52,0x92,0x81,0x24,0x31,0xf6,0xd2,0x52,0xf1,0xdb,0xc1,0xcb,0x44,0xdf,0x21,0x57,0x3d,0xe1,0xb0,0x6b,0x68,0x75,0x95,0x9f,0x3b,0x6f,0x87,0xb1,0x13,0x81,0xd0,0xbc,0x79,0x2c,0x43,0x3a,0x13,0x55,0x3c,0xe0,0x84,0xc2,0x92,0x55,0x31,0x1c };
static const unsigned char sha384TV0Digest[48] = { 0x71,0xe7,0x71,0x79,0xae,0xc3,0xf3,0x5f,0x93,0xea,0xe2,0x1d,0xe3,0x3f,0x24,0x6d,0xed,0x2a,0x59,0xae,0x22,0x45,0x27,0x6c,0x12,0x57,0xf3,0xbe,0xe6,0xce,0xe2,0x73,0xd8,0xad,0xaa,0x9b,0x99,0xa4,0x8a,0x1b,0x7a,0xb9,0x5d,0xfb,0x9c,0x1a,0x1c,0xf6 };
struct C25519TestVector
{
@ -211,7 +221,7 @@ static int testCrypto()
bytes += 1234567.0;
}
uint64_t end = OSUtils::now();
SHA512::hash(buf1,bb,1234567);
SHA512(buf1,bb,1234567);
std::cout << ((bytes / 1048576.0) / ((long double)(end - start) / 1024.0)) << " MiB/second (" << Utils::hex(buf1,16,hexbuf) << ')' << std::endl;
::free((void *)bb);
}
@ -263,18 +273,25 @@ static int testCrypto()
bytes += 1234567.0;
}
uint64_t end = OSUtils::now();
SHA512::hash(buf1,bb,1234567);
SHA512(buf1,bb,1234567);
std::cout << ((bytes / 1048576.0) / ((long double)(end - start) / 1024.0)) << " MiB/second (" << Utils::hex(buf1,16,hexbuf) << ')' << std::endl;
::free((void *)bb);
}
std::cout << "[crypto] Testing SHA-512... "; std::cout.flush();
SHA512::hash(buf1,sha512TV0Input,(unsigned int)strlen(sha512TV0Input));
SHA512(buf1,sha512TV0Input,(unsigned int)strlen(sha512TV0Input));
if (memcmp(buf1,sha512TV0Digest,64)) {
std::cout << "FAIL" << std::endl;
return -1;
}
std::cout << "PASS" << std::endl;
std::cout << "[crypto] Testing SHA-384... "; std::cout.flush();
SHA384(buf1,sha512TV0Input,(unsigned int)strlen(sha512TV0Input));
if (memcmp(buf1,sha384TV0Digest,48)) {
std::cout << "FAIL" << std::endl;
return -1;
}
std::cout << "PASS" << std::endl;
std::cout << "[crypto] Testing Poly1305... "; std::cout.flush();
Poly1305::compute(buf1,poly1305TV0Input,sizeof(poly1305TV0Input),poly1305TV0Key);
@ -305,18 +322,51 @@ static int testCrypto()
::free((void *)bb);
}
/*
for(unsigned int d=8;d<=10;++d) {
for(int k=0;k<8;++k) {
std::cout << "[crypto] computeSalsa2012Sha512ProofOfWork(" << d << ",\"foobarbaz\",9) == "; std::cout.flush();
unsigned char result[16];
uint64_t start = OSUtils::now();
IncomingPacket::computeSalsa2012Sha512ProofOfWork(d,"foobarbaz",9,result);
uint64_t end = OSUtils::now();
std::cout << Utils::hex(result,16) << " -- valid: " << IncomingPacket::testSalsa2012Sha512ProofOfWorkResult(d,"foobarbaz",9,result) << ", " << (end - start) << "ms" << std::endl;
std::cout << "[crypto] Testing ECC384 (NIST P-384)..." << std::endl;
{
uint8_t p384pub[ZT_ECC384_PUBLIC_KEY_SIZE],p384priv[ZT_ECC384_PRIVATE_KEY_SIZE],p384sig[ZT_ECC384_SIGNATURE_SIZE],p384hash[ZT_ECC384_SIGNATURE_HASH_SIZE];
char p384hex[256];
ECC384GenerateKey(p384pub,p384priv);
std::cout << "[crypto] Public Key: " << Utils::hex(p384pub,sizeof(p384pub),p384hex) << std::endl;
Utils::getSecureRandom(p384hash,sizeof(p384hash));
ECC384ECDSASign(p384priv,p384hash,p384sig);
if (!ECC384ECDSAVerify(p384pub,p384hash,p384sig)) {
std::cout << "[crypto] ECDSA Signature: FAILED (verify good signature)" << std::endl;
return -1;
}
++p384sig[0];
if (ECC384ECDSAVerify(p384pub,p384hash,p384sig)) {
std::cout << "[crypto] ECDSA Signature: FAILED (verify bad signature)" << std::endl;
return -1;
}
--p384sig[0];
std::cout << "[crypto] ECDSA Signature: " << Utils::hex(p384sig,sizeof(p384sig),p384hex) << std::endl;
uint8_t p384pub2[ZT_ECC384_PUBLIC_KEY_SIZE],p384priv2[ZT_ECC384_PRIVATE_KEY_SIZE],p384sec[ZT_ECC384_SHARED_SECRET_SIZE],p384sec2[ZT_ECC384_SHARED_SECRET_SIZE];
ECC384GenerateKey(p384pub2,p384priv2);
ECC384ECDH(p384pub,p384priv2,p384sec);
ECC384ECDH(p384pub2,p384priv,p384sec2);
if (memcmp(p384sec,p384sec2,ZT_ECC384_SHARED_SECRET_SIZE)) {
std::cout << "[crypto] ECDH Agree: FAILED (secrets do not match)" << std::endl;
return -1;
}
std::cout << "[crypto] ECDH Agree: " << Utils::hex(p384sec,sizeof(p384sec),p384hex) << std::endl;
Utils::unhex(ECC384_TEST_PUBLIC,p384pub,sizeof(p384pub));
Utils::unhex(ECC384_TEST_PRIVATE,p384priv,sizeof(p384priv));
ECC384ECDH(p384pub,p384priv,p384sec);
Utils::unhex(ECC384_TEST_DH_SELF_AGREE,p384sec2,sizeof(p384sec2));
if (memcmp(p384sec,p384sec2,ZT_ECC384_SHARED_SECRET_SIZE)) {
std::cout << "[crypto] ECDH Test Vector: FAILED (secrets do not match)" << std::endl;
return -1;
}
std::cout << "[crypto] ECDH Test Vector: PASS" << std::endl;
Utils::unhex(ECC384_TEST_SIG,p384sig,sizeof(p384sig));
if (!ECC384ECDSAVerify(p384pub,p384pub,p384sig)) {
std::cout << "[crypto] ECDSA Test Vector: FAILED (verify failed)" << std::endl;
return -1;
}
std::cout << "[crypto] ECDSA Test Vector: PASS" << std::endl;
}
*/
std::cout << "[crypto] Testing C25519 and Ed25519 against test vectors... "; std::cout.flush();
for(int k=0;k<ZT_NUM_C25519_TEST_VECTORS;++k) {
@ -325,8 +375,8 @@ static int testCrypto()
memcpy(p1.priv.data,C25519_TEST_VECTORS[k].priv1,ZT_C25519_PRIVATE_KEY_LEN);
memcpy(p2.pub.data,C25519_TEST_VECTORS[k].pub2,ZT_C25519_PUBLIC_KEY_LEN);
memcpy(p2.priv.data,C25519_TEST_VECTORS[k].priv2,ZT_C25519_PRIVATE_KEY_LEN);
C25519::agree(p1,p2.pub,buf1,64);
C25519::agree(p2,p1.pub,buf2,64);
C25519::agree(p1.priv,p2.pub,buf1,64);
C25519::agree(p2.priv,p1.pub,buf2,64);
if (memcmp(buf1,buf2,64)) {
std::cout << "FAIL (1)" << std::endl;
return -1;
@ -356,9 +406,9 @@ static int testCrypto()
C25519::Pair p1 = C25519::generate();
C25519::Pair p2 = C25519::generate();
C25519::Pair p3 = C25519::generate();
C25519::agree(p1,p2.pub,buf1,64);
C25519::agree(p2,p1.pub,buf2,64);
C25519::agree(p3,p1.pub,buf3,64);
C25519::agree(p1.priv,p2.pub,buf1,64);
C25519::agree(p2.priv,p1.pub,buf2,64);
C25519::agree(p3.priv,p1.pub,buf3,64);
// p1<>p2 should equal p1<>p2
if (memcmp(buf1,buf2,64)) {
std::cout << "FAIL (1)" << std::endl;
@ -378,7 +428,7 @@ static int testCrypto()
bp[k] = C25519::generate();
uint64_t st = OSUtils::now();
for(unsigned int k=0;k<50;++k) {
C25519::agree(bp[~k & 7],bp[k & 7].pub,buf1,64);
C25519::agree(bp[~k & 7].priv,bp[k & 7].pub,buf1,64);
}
uint64_t et = OSUtils::now();
std::cout << ((double)(et - st) / 50.0) << "ms per agreement." << std::endl;
@ -466,7 +516,7 @@ static int testIdentity()
for(unsigned int k=0;k<4;++k) {
std::cout << "[identity] Generate identity... "; std::cout.flush();
uint64_t genstart = OSUtils::now();
id.generate();
id.generate(Identity::C25519);
uint64_t genend = OSUtils::now();
std::cout << "(took " << (genend - genstart) << "ms): " << id.toString(true,buf2) << std::endl;
std::cout << "[identity] Locally validate identity: ";
@ -539,13 +589,13 @@ static int testCertificate()
Identity authority;
std::cout << "[certificate] Generating identity to act as authority... "; std::cout.flush();
authority.generate();
authority.generate(Identity::C25519);
std::cout << authority.address().toString(buf) << std::endl;
Identity idA,idB;
std::cout << "[certificate] Generating identities A and B... "; std::cout.flush();
idA.generate();
idB.generate();
idA.generate(Identity::C25519);
idB.generate(Identity::C25519);
std::cout << idA.address().toString(buf) << ", " << idB.address().toString(buf) << std::endl;
std::cout << "[certificate] Generating certificates A and B...";
@ -662,6 +712,46 @@ static int testOther()
return -1;
}
std::cout << "[other] Testing base32... "; std::cout.flush();
for(unsigned int i=1;i<1024;++i) {
Utils::getSecureRandom(buf,(unsigned int)sizeof(buf));
int l = Utils::b32e((const uint8_t *)buf,i,buf2,sizeof(buf2));
if (l <= 0) {
std::cout << "FAIL (encode returned 0)" << std::endl;
return -1;
}
int l2 = Utils::b32d(buf2,(uint8_t *)buf3,sizeof(buf3));
if (l2 != (int)i) {
std::cout << "FAIL (decode returned wrong count)" << std::endl;
return -1;
}
if (memcmp(buf,buf3,i) != 0) {
std::cout << "FAIL (decode result incorrect)" << std::endl;
return -1;
}
}
std::cout << "PASS" << std::endl;
std::cout << "[other] Testing base64... "; std::cout.flush();
for(unsigned int i=1;i<1024;++i) {
Utils::getSecureRandom(buf,(unsigned int)sizeof(buf));
unsigned int l = Utils::b64e((const uint8_t *)buf,i,buf2,sizeof(buf2));
if (l == 0) {
std::cout << "FAIL (encode returned 0)" << std::endl;
return -1;
}
unsigned int l2 = Utils::b64d(buf2,(uint8_t *)buf3,sizeof(buf3));
if (l2 != i) {
std::cout << "FAIL (decode returned wrong count)" << std::endl;
return -1;
}
if (memcmp(buf,buf3,i) != 0) {
std::cout << "FAIL (decode result incorrect)" << std::endl;
return -1;
}
}
std::cout << "PASS" << std::endl;
std::cout << "[other] Testing InetAddress encode/decode..."; std::cout.flush();
std::cout << " " << InetAddress("127.0.0.1/9993").toString(buf);
std::cout << " " << InetAddress("feed:dead:babe:dead:beef:f00d:1234:5678/12345").toString(buf);

View file

@ -48,7 +48,6 @@
#include "../node/InetAddress.hpp"
#include "../node/MAC.hpp"
#include "../node/Identity.hpp"
#include "../node/World.hpp"
#include "../node/Salsa20.hpp"
#include "../node/Poly1305.hpp"
#include "../node/SHA512.hpp"
@ -140,6 +139,9 @@ using json = nlohmann::json;
// TCP activity timeout
#define ZT_TCP_ACTIVITY_TIMEOUT 60000
// How often local.conf is checked for changes
#define ZT_LOCAL_CONF_FILE_CHECK_INTERVAL 10000
#if ZT_VAULT_SUPPORT
size_t curlResponseWrite(void *ptr, size_t size, size_t nmemb, std::string *data)
{
@ -313,28 +315,6 @@ static void _peerAggregateLinkToJson(nlohmann::json &pj,const ZT_Peer *peer)
pj["paths"] = pa;
}
static void _moonToJson(nlohmann::json &mj,const World &world)
{
char tmp[4096];
OSUtils::ztsnprintf(tmp,sizeof(tmp),"%.16llx",world.id());
mj["id"] = tmp;
mj["timestamp"] = world.timestamp();
mj["signature"] = Utils::hex(world.signature().data,ZT_C25519_SIGNATURE_LEN,tmp);
mj["updatesMustBeSignedBy"] = Utils::hex(world.updatesMustBeSignedBy().data,ZT_C25519_PUBLIC_KEY_LEN,tmp);
nlohmann::json ra = nlohmann::json::array();
for(std::vector<World::Root>::const_iterator r(world.roots().begin());r!=world.roots().end();++r) {
nlohmann::json rj;
rj["identity"] = r->identity.toString(false,tmp);
nlohmann::json eps = nlohmann::json::array();
for(std::vector<InetAddress>::const_iterator a(r->stableEndpoints.begin());a!=r->stableEndpoints.end();++a)
eps.push_back(a->toString(tmp));
rj["stableEndpoints"] = eps;
ra.push_back(rj);
}
mj["roots"] = ra;
mj["waiting"] = false;
}
class OneServiceImpl;
static int SnodeVirtualNetworkConfigFunction(ZT_Node *node,void *uptr,void *tptr,uint64_t nwid,void **nuptr,enum ZT_VirtualNetworkConfigOperation op,const ZT_VirtualNetworkConfig *nwconf);
@ -747,16 +727,6 @@ public:
}
}
// Orbit existing moons in moons.d
{
std::vector<std::string> moonsDotD(OSUtils::listDirectory((_homePath + ZT_PATH_SEPARATOR_S "moons.d").c_str()));
for(std::vector<std::string>::iterator f(moonsDotD.begin());f!=moonsDotD.end();++f) {
std::size_t dot = f->find_last_of('.');
if ((dot == 16)&&(f->substr(16) == ".moon"))
_node->orbit((void *)0,Utils::hexStrToU64(f->substr(0,dot).c_str()),0);
}
}
// Main I/O loop
_nextBackgroundTaskDeadline = 0;
int64_t clockShouldBe = OSUtils::now();
@ -1254,37 +1224,8 @@ public:
settings["softwareUpdate"] = OSUtils::jsonString(settings["softwareUpdate"],ZT_SOFTWARE_UPDATE_DEFAULT);
settings["softwareUpdateChannel"] = OSUtils::jsonString(settings["softwareUpdateChannel"],ZT_SOFTWARE_UPDATE_DEFAULT_CHANNEL);
#endif
const World planet(_node->planet());
res["planetWorldId"] = planet.id();
res["planetWorldTimestamp"] = planet.timestamp();
scode = 200;
} else if (ps[0] == "moon") {
std::vector<World> moons(_node->moons());
if (ps.size() == 1) {
// Return [array] of all moons
res = json::array();
for(std::vector<World>::const_iterator m(moons.begin());m!=moons.end();++m) {
json mj;
_moonToJson(mj,*m);
res.push_back(mj);
}
scode = 200;
} else {
// Return a single moon by ID
const uint64_t id = Utils::hexStrToU64(ps[1].c_str());
for(std::vector<World>::const_iterator m(moons.begin());m!=moons.end();++m) {
if (m->id() == id) {
_moonToJson(res,*m);
scode = 200;
break;
}
}
}
} else if (ps[0] == "network") {
ZT_VirtualNetworkList *nws = _node->networks();
if (nws) {
@ -1357,44 +1298,7 @@ public:
} else if ((httpMethod == HTTP_POST)||(httpMethod == HTTP_PUT)) {
if (isAuth) {
if (ps[0] == "moon") {
if (ps.size() == 2) {
uint64_t seed = 0;
try {
json j(OSUtils::jsonParse(body));
if (j.is_object()) {
seed = Utils::hexStrToU64(OSUtils::jsonString(j["seed"],"0").c_str());
}
} catch ( ... ) {
// discard invalid JSON
}
std::vector<World> moons(_node->moons());
const uint64_t id = Utils::hexStrToU64(ps[1].c_str());
for(std::vector<World>::const_iterator m(moons.begin());m!=moons.end();++m) {
if (m->id() == id) {
_moonToJson(res,*m);
scode = 200;
break;
}
}
if ((scode != 200)&&(seed != 0)) {
char tmp[64];
OSUtils::ztsnprintf(tmp,sizeof(tmp),"%.16llx",id);
res["id"] = tmp;
res["roots"] = json::array();
res["timestamp"] = 0;
res["signature"] = json();
res["updatesMustBeSignedBy"] = json();
res["waiting"] = true;
_node->orbit((void *)0,id,seed);
scode = 200;
}
} else scode = 404;
} else if (ps[0] == "network") {
if (ps[0] == "network") {
if (ps.size() == 2) {
uint64_t wantnw = Utils::hexStrToU64(ps[1].c_str());
@ -1441,13 +1345,7 @@ public:
} else if (httpMethod == HTTP_DELETE) {
if (isAuth) {
if (ps[0] == "moon") {
if (ps.size() == 2) {
_node->deorbit((void *)0,Utils::hexStrToU64(ps[1].c_str()));
res["result"] = true;
scode = 200;
} // else 404
} else if (ps[0] == "network") {
if (ps[0] == "network") {
ZT_VirtualNetworkList *nws = _node->networks();
if (nws) {
if (ps.size() == 2) {
@ -2234,9 +2132,7 @@ public:
} break;
case ZT_EVENT_REMOTE_TRACE: {
const ZT_RemoteTrace *rt = reinterpret_cast<const ZT_RemoteTrace *>(metaData);
if ((rt)&&(rt->len > 0)&&(rt->len <= ZT_MAX_REMOTE_TRACE_SIZE)&&(rt->data))
_controller->handleRemoteTrace(*rt);
// TODO
}
default:
@ -2340,13 +2236,6 @@ public:
OSUtils::ztsnprintf(p,sizeof(p),"%s" ZT_PATH_SEPARATOR_S "identity.secret",_homePath.c_str());
secure = true;
break;
case ZT_STATE_OBJECT_PLANET:
OSUtils::ztsnprintf(p,sizeof(p),"%s" ZT_PATH_SEPARATOR_S "planet",_homePath.c_str());
break;
case ZT_STATE_OBJECT_MOON:
OSUtils::ztsnprintf(dirname,sizeof(dirname),"%s" ZT_PATH_SEPARATOR_S "moons.d",_homePath.c_str());
OSUtils::ztsnprintf(p,sizeof(p),"%s" ZT_PATH_SEPARATOR_S "%.16llx.moon",dirname,(unsigned long long)id[0]);
break;
case ZT_STATE_OBJECT_NETWORK_CONFIG:
OSUtils::ztsnprintf(dirname,sizeof(dirname),"%s" ZT_PATH_SEPARATOR_S "networks.d",_homePath.c_str());
OSUtils::ztsnprintf(p,sizeof(p),"%s" ZT_PATH_SEPARATOR_S "%.16llx.conf",dirname,(unsigned long long)id[0]);
@ -2492,12 +2381,6 @@ public:
case ZT_STATE_OBJECT_IDENTITY_SECRET:
OSUtils::ztsnprintf(p,sizeof(p),"%s" ZT_PATH_SEPARATOR_S "identity.secret",_homePath.c_str());
break;
case ZT_STATE_OBJECT_PLANET:
OSUtils::ztsnprintf(p,sizeof(p),"%s" ZT_PATH_SEPARATOR_S "planet",_homePath.c_str());
break;
case ZT_STATE_OBJECT_MOON:
OSUtils::ztsnprintf(p,sizeof(p),"%s" ZT_PATH_SEPARATOR_S "moons.d" ZT_PATH_SEPARATOR_S "%.16llx.moon",_homePath.c_str(),(unsigned long long)id[0]);
break;
case ZT_STATE_OBJECT_NETWORK_CONFIG:
OSUtils::ztsnprintf(p,sizeof(p),"%s" ZT_PATH_SEPARATOR_S "networks.d" ZT_PATH_SEPARATOR_S "%.16llx.conf",_homePath.c_str(),(unsigned long long)id[0]);
break;

View file

@ -127,7 +127,7 @@ void SoftwareUpdater::setUpdateDistribution(bool distribute)
const std::string metaHash(OSUtils::jsonBinFromHex(d.meta[ZT_SOFTWARE_UPDATE_JSON_UPDATE_HASH]));
if ((metaHash.length() == ZT_SHA512_DIGEST_LEN)&&(OSUtils::readFile(binPath.c_str(),d.bin))) {
std::array<uint8_t,ZT_SHA512_DIGEST_LEN> sha512;
SHA512::hash(sha512.data(),d.bin.data(),(unsigned int)d.bin.length());
SHA512(sha512.data(),d.bin.data(),(unsigned int)d.bin.length());
if (!memcmp(sha512.data(),metaHash.data(),ZT_SHA512_DIGEST_LEN)) { // double check that hash in JSON is correct
d.meta[ZT_SOFTWARE_UPDATE_JSON_UPDATE_SIZE] = d.bin.length(); // override with correct value -- setting this in meta json is optional
std::array<uint8_t,16> shakey;
@ -347,7 +347,7 @@ bool SoftwareUpdater::check(const int64_t now)
try {
// (1) Check the hash itself to make sure the image is basically okay
uint8_t sha512[ZT_SHA512_DIGEST_LEN];
SHA512::hash(sha512,_download.data(),(unsigned int)_download.length());
SHA512(sha512,_download.data(),(unsigned int)_download.length());
char hexbuf[(ZT_SHA512_DIGEST_LEN * 2) + 2];
if (OSUtils::jsonString(_latestMeta[ZT_SOFTWARE_UPDATE_JSON_UPDATE_HASH],"") == Utils::hex(sha512,ZT_SHA512_DIGEST_LEN,hexbuf)) {
// (2) Check signature by signing authority