mirror of
https://github.com/zerotier/ZeroTierOne.git
synced 2025-06-06 20:43:44 +02:00
Merge branch 'edge' into cmake
This commit is contained in:
commit
8e04f83232
57 changed files with 3808 additions and 2318 deletions
158
attic/root.cpp
Normal file
158
attic/root.cpp
Normal 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;
|
||||
}
|
|
@ -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'.
|
||||
|
|
@ -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
|
|
@ -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.
|
@ -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};
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
362
node/AES.cpp
Normal 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
172
node/AES.hpp
Normal 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
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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];
|
||||
};
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
1363
node/ECC384.cpp
Normal file
File diff suppressed because it is too large
Load diff
108
node/ECC384.hpp
Normal file
108
node/ECC384.hpp
Normal 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
|
|
@ -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,25 +156,112 @@ 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;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
257
node/Locator.hpp
Normal 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
|
|
@ -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
|
||||
{
|
||||
|
|
|
@ -31,6 +31,7 @@
|
|||
|
||||
#include "MAC.hpp"
|
||||
#include "InetAddress.hpp"
|
||||
#include "Utils.hpp"
|
||||
|
||||
namespace ZeroTier {
|
||||
|
||||
|
|
|
@ -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)];
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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])];
|
||||
}
|
||||
}
|
||||
|
|
102
node/Node.cpp
102
node/Node.cpp
|
@ -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();
|
||||
|
|
|
@ -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; }
|
||||
|
||||
/**
|
||||
|
|
|
@ -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());
|
||||
|
|
|
@ -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)
|
||||
*
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
489
node/SHA512.cpp
489
node/SHA512.cpp
|
@ -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 inline void sha512_decode(uint64_t *output, uint8_t *input, uint32_t idx)
|
||||
{
|
||||
*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);
|
||||
}
|
||||
|
||||
static void store_bigendian(unsigned char *x,uint64 u)
|
||||
{
|
||||
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;
|
||||
}
|
||||
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;
|
||||
|
||||
#else // !ZT_NO_TYPE_PUNNING
|
||||
#define LSR(x,n) (x >> n)
|
||||
#define ROR(x,n) (LSR(x,n) | (x << (64 - n)))
|
||||
|
||||
#define load_bigendian(x) Utils::ntoh(*((const uint64_t *)(x)))
|
||||
#define store_bigendian(x,u) (*((uint64_t *)(x)) = Utils::hton((u)))
|
||||
#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))
|
||||
|
||||
#endif // ZT_NO_TYPE_PUNNING
|
||||
#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 SHR(x,c) ((x) >> (c))
|
||||
#define ROTR(x,c) (((x) >> (c)) | ((x) << (64 - (c))))
|
||||
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 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))
|
||||
|
||||
#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;
|
||||
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; }
|
||||
}
|
||||
|
||||
const unsigned char *in = (const unsigned char *)data;
|
||||
unsigned int inlen = len;
|
||||
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;
|
||||
}
|
||||
|
||||
for (i = 0;i < 64;++i) h[i] = iv[i];
|
||||
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;
|
||||
}
|
||||
|
||||
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);
|
||||
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]; }
|
||||
}
|
||||
|
||||
for (i = 0;i < 64;++i) ((unsigned char *)digest)[i] = h[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); }
|
||||
|
|
|
@ -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
158
node/Str.hpp
Normal 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
|
|
@ -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);
|
||||
|
|
14
node/Tag.cpp
14
node/Tag.cpp
|
@ -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;
|
||||
}
|
||||
|
|
34
node/Tag.hpp
34
node/Tag.hpp
|
@ -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
|
||||
|
|
|
@ -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,37 +156,38 @@ 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)
|
||||
|
|
|
@ -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
|
||||
|
|
165
node/Utils.cpp
165
node/Utils.cpp
|
@ -1,10 +1,10 @@
|
|||
/*
|
||||
* ZeroTier One - Network Virtualization Everywhere
|
||||
* Copyright (C) 2011-2019 ZeroTier, Inc. https://www.zerotier.com/
|
||||
* 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
|
||||
* 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,
|
||||
|
@ -13,7 +13,7 @@
|
|||
* 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/>.
|
||||
* along with this program. If not,see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* --
|
||||
*
|
||||
|
@ -69,7 +69,7 @@ static unsigned long _Utils_itoa(unsigned long n,char *s)
|
|||
if (n == 0)
|
||||
return 0;
|
||||
unsigned long pos = _Utils_itoa(n / 10,s);
|
||||
if (pos >= 22) // sanity check, should be impossible
|
||||
if (pos >= 22) // sanity check,should be impossible
|
||||
pos = 22;
|
||||
s[pos] = '0' + (char)(n % 10);
|
||||
return pos + 1;
|
||||
|
@ -99,7 +99,7 @@ void Utils::getSecureRandom(void *buf,unsigned int bytes)
|
|||
* CSPRNG we use. There have been several bugs at the OS or OS distribution
|
||||
* level in the past that resulted in systematically weak or predictable
|
||||
* keys due to random seeding problems. This mitigates that by grabbing
|
||||
* a bit of extra entropy and further randomizing the result, and comes
|
||||
* a bit of extra entropy and further randomizing the result,and comes
|
||||
* at almost no cost and with no real downside if the random source is
|
||||
* good. */
|
||||
if (!s20Initialized) {
|
||||
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
*
|
||||
|
|
284
node/World.hpp
284
node/World.hpp
|
@ -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
|
|
@ -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
177
one.cpp
|
@ -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;
|
||||
|
|
|
@ -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)
|
||||
|
|
136
selftest.cpp
136
selftest.cpp
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Add table
Reference in a new issue