From fe2215df00832fe1054b990ccedaab54c37cd65f Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Wed, 17 Jul 2019 10:52:08 -0500 Subject: [PATCH] TON of refactoring, moon/planet is DEAD, ECC P-384 is integrated (but not enabled), and multicast work and cleanup. Whew. --- attic/MTUDPSocket.hpp | 162 ----------------- attic/world/README.md | 7 - attic/world/build.sh | 3 - attic/world/mkworld.cpp | 154 ---------------- attic/world/world.bin | Bin 732 -> 0 bytes attic/world/world.c | 3 - include/ZeroTierOne.h | 44 ----- node/C25519.hpp | 2 - node/Capability.cpp | 19 +- node/Capability.hpp | 31 +--- node/CertificateOfMembership.cpp | 13 +- node/CertificateOfMembership.hpp | 30 +++- node/CertificateOfOwnership.cpp | 28 ++- node/CertificateOfOwnership.hpp | 40 ++--- node/Constants.hpp | 5 + node/ECC384.hpp | 34 ++++ node/Identity.cpp | 180 +++++++++++++------ node/Identity.hpp | 291 ++++++++++++++++++++----------- node/IncomingPacket.cpp | 72 +------- node/Node.cpp | 93 +++------- node/Node.hpp | 7 - node/Packet.cpp | 10 -- node/Packet.hpp | 38 +--- node/Peer.cpp | 21 --- node/Revocation.cpp | 14 +- node/Revocation.hpp | 38 ++-- node/Switch.cpp | 7 - node/Tag.cpp | 14 +- node/Tag.hpp | 34 ++-- node/Topology.cpp | 277 +---------------------------- node/Topology.hpp | 122 +------------ node/Utils.hpp | 4 +- node/World.hpp | 284 ------------------------------ one.cpp | 177 +------------------ selftest.cpp | 20 +-- service/OneService.cpp | 122 +------------ 36 files changed, 556 insertions(+), 1844 deletions(-) delete mode 100644 attic/MTUDPSocket.hpp delete mode 100644 attic/world/README.md delete mode 100755 attic/world/build.sh delete mode 100644 attic/world/mkworld.cpp delete mode 100644 attic/world/world.bin delete mode 100644 attic/world/world.c delete mode 100644 node/World.hpp diff --git a/attic/MTUDPSocket.hpp b/attic/MTUDPSocket.hpp deleted file mode 100644 index 365bbf9cd..000000000 --- a/attic/MTUDPSocket.hpp +++ /dev/null @@ -1,162 +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 . - * - * -- - * - * 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_MTUDPSOCKET_HPP -#define ZT_MTUDPSOCKET_HPP - -#ifndef __WINDOWS__ - -#include "../node/Constants.hpp" -#include "../include/ZeroTierOne.h" -#include "../osdep/OSUtils.hpp" -#include "../osdep/Thread.hpp" - -#include -#include -#include -#include - -namespace ZeroTier { - -/** - * MTUDPSocket is a multithreaded UDP socket using multiple binds and SO_REUSEPORT - * - * On Mac and Linux this is the most efficient way to implement a multithreaded UDP - * I/O path. On Windows it's probably not necessary to optimize this much. If it ever - * is, we will have to implement a version of this the Windows way. - */ -class MTUDPSocket -{ -public: - inline MTUDPSocket(ZT_Node *n,volatile int64_t *dptr,const struct sockaddr *bindAddr) - { - const int ncores = std::max(1,(int)sysconf(_SC_NPROCESSORS_CONF)); - for(int t=0;tsa_family,SOCK_DGRAM,0); - if (s < 0) { - for(auto i=_sockets.begin();i!=_sockets.end();++i) - close(*i); - throw std::runtime_error("unable to allocate socket"); - } - - 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 = 0; 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))) { - for(auto i=_sockets.begin();i!=_sockets.end();++i) - close(*i); - throw std::runtime_error("unable to bind to address"); - } - - _sockets.push_back(s); - } - - for(auto s=_sockets.begin();s!=_sockets.end();++s) { - try { - new MTUDPThread(n,dptr,*s); - } catch ( ... ) { - for(auto i=_sockets.begin();i!=_sockets.end();++i) - close(*i); - throw; - } - } - } - - inline ~MTUDPSocket() - { - for(auto i=_sockets.begin();i!=_sockets.end();++i) - close(*i); - } - -private: - class MTUDPThread - { - public: - inline MTUDPThread(ZT_Node *n,volatile int64_t *dptr,int s) : - node(n), - deadlinePtr(dptr), - sock(s), - thread(Thread::start(this)) - { - } - - inline void threadMain() - { - struct sockaddr_storage from; - for(;;) { - socklen_t fromLen = sizeof(from); - const int nr = recvfrom(this->sock,this->buf,sizeof(this->buf),0,(struct sockaddr *)&from,&fromLen); - if (nr > 0) { - ZT_Node_processWirePacket(this->node,nullptr,OSUtils::now(),(int64_t)this->sock,&from,this->buf,(unsigned int)nr,this->deadlinePtr); - } else { - close(this->sock); - break; - } - } - delete this; // closing the socket causes this to exit and delete itself - } - - ZT_Node *const node; - volatile int64_t *const deadlinePtr; - const int sock; - Thread thread; - char buf[10000]; - }; - - std::vector _sockets; -}; - -} // namespace ZeroTier - -#endif // !__WINDOWS__ - -#endif diff --git a/attic/world/README.md b/attic/world/README.md deleted file mode 100644 index dda4920ae..000000000 --- a/attic/world/README.md +++ /dev/null @@ -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'. - diff --git a/attic/world/build.sh b/attic/world/build.sh deleted file mode 100755 index aeb3b87fa..000000000 --- a/attic/world/build.sh +++ /dev/null @@ -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 diff --git a/attic/world/mkworld.cpp b/attic/world/mkworld.cpp deleted file mode 100644 index b8cb027b4..000000000 --- a/attic/world/mkworld.cpp +++ /dev/null @@ -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 . - */ - -/* - * 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 -#include -#include -#include - -#include -#include -#include - -#include -#include -#include -#include -#include -#include - -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 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 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 0) - fprintf(stdout,","); - fprintf(stdout,"0x%.2x",(unsigned int)d[i]); - } - fprintf(stdout,"};" ZT_EOL_S); - - return 0; -} diff --git a/attic/world/world.bin b/attic/world/world.bin deleted file mode 100644 index fff7e2a99462f929185788f1e74875c6c83b7b91..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 732 zcmZQ%00NFzC%G6H7_+a4aU9&SxnoJDlE}nWv(BcSDf7AaH;j3{K>9k-XLItm=vIds z^V#286Euf?(%)i-WvdiduUOLgcij>%%l*0xsk2U=ka#UN`ODM23bzE-9%ubB^B)Vx z><9D8W#_w#t(xR7AZB~~&E*O6E|&b+yp?^9@6@B>-L~8bWiJAEZ?i4gs@PmTRhDV? z+4V7Y)9#z=gysG!<-Zl$D*UBPD$Uor_q@-^?EgMZui#Ze5z4^K@dCimZGq2gznWAT|5m_ph z#krV)iDl;&-XL{OHZ7*S1t&y7!2kj3oO2Z?Sbk<;{4hyt#^cR?d-i`eR-1b$_4)#Z zRomtk?eq0IGpA?Ll#1{|)trkromTQnU%Yf@@vD~iwXN%)CCYEH|FGRr?Iu?q0}sod zWpNupHZX5Ez`(?C0c?IP1EV@8%Pgm(ia;41{vQF1A&k?ZRvQCl=ATYn4U|!1S<%43 zz_1W36OsVZ)BK-J04Sru{JH@s$_LfM1eD2Mb(9aPhk=nn0VKo3@BpNz;rP*;Kp7Q= z#0H=s#0A?OfHED94qbW-yJZbO9aesn^75Hu(ZS{Z<(*SQ-wKqx n&9lHVKf<9h1q`!KLS&A71+~c4l$m!P/planet - * Persistence: recommended - */ - ZT_STATE_OBJECT_PLANET = 3, - - /** - * A moon (federated root set) - * - * Object ID: world ID of moon - * Canonical path: /moons.d/.moon (16-digit hex ID) - * Persistence: required if moon memberships should persist - */ - ZT_STATE_OBJECT_MOON = 4, - /** * Peer and related state * @@ -1847,32 +1829,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 * diff --git a/node/C25519.hpp b/node/C25519.hpp index c87df9c20..d4a2c9349 100644 --- a/node/C25519.hpp +++ b/node/C25519.hpp @@ -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,7 +119,6 @@ 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 diff --git a/node/Capability.cpp b/node/Capability.cpp index fdf98baec..3ed7f0b19 100644 --- a/node/Capability.cpp +++ b/node/Capability.cpp @@ -34,6 +34,23 @@ namespace ZeroTier { +bool Capability::sign(const Identity &from,const Address &to) +{ + try { + for(unsigned int i=0;((i<_maxCustodyChainLength)&&(i 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); diff --git a/node/Capability.hpp b/node/Capability.hpp index 0704c5139..35fe17bac 100644 --- a/node/Capability.hpp +++ b/node/Capability.hpp @@ -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 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(p) != ZT_C25519_SIGNATURE_LEN) + _custody[i].signatureLength = b.template at(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(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]; }; diff --git a/node/CertificateOfMembership.cpp b/node/CertificateOfMembership.cpp index 614c68871..0ec7abfaf 100644 --- a/node/CertificateOfMembership.cpp +++ b/node/CertificateOfMembership.cpp @@ -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 diff --git a/node/CertificateOfMembership.hpp b/node/CertificateOfMembership.hpp index b2c63f9d0..b4aa51727 100644 --- a/node/CertificateOfMembership.hpp +++ b/node/CertificateOfMembership.hpp @@ -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 @@ -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 diff --git a/node/CertificateOfOwnership.cpp b/node/CertificateOfOwnership.cpp index d7266cd29..5a17026ce 100644 --- a/node/CertificateOfOwnership.cpp +++ b/node/CertificateOfOwnership.cpp @@ -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(&ip)->sin_addr.s_addr),4); + ++_thingCount; + } else if (ip.ss_family == AF_INET6) { + _thingTypes[_thingCount] = THING_IPV6_ADDRESS; + memcpy(_thingValues[_thingCount],reinterpret_cast(&ip)->sin6_addr.s6_addr,16); + ++_thingCount; + } +} + +bool CertificateOfOwnership::sign(const Identity &signer) +{ + if (signer.hasPrivate()) { + Buffer 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; } diff --git a/node/CertificateOfOwnership.hpp b/node/CertificateOfOwnership.hpp index fdffec3b8..cf984ad8e 100644 --- a/node/CertificateOfOwnership.hpp +++ b/node/CertificateOfOwnership.hpp @@ -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(&ip)->sin_addr.s_addr),4); - ++_thingCount; - } else if (ip.ss_family == AF_INET6) { - _thingTypes[_thingCount] = THING_IPV6_ADDRESS; - memcpy(_thingValues[_thingCount],reinterpret_cast(&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 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(p) != ZT_C25519_SIGNATURE_LEN) + _signatureLength = b.template at(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(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 diff --git a/node/Constants.hpp b/node/Constants.hpp index 98df998d8..3c155b206 100644 --- a/node/Constants.hpp +++ b/node/Constants.hpp @@ -613,6 +613,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) */ diff --git a/node/ECC384.hpp b/node/ECC384.hpp index 40ce3a145..5097a6030 100644 --- a/node/ECC384.hpp +++ b/node/ECC384.hpp @@ -61,12 +61,46 @@ 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 diff --git a/node/Identity.cpp b/node/Identity.cpp index e914b2701..e23de277a 100644 --- a/node/Identity.cpp +++ b/node/Identity.cpp @@ -35,14 +35,16 @@ #include "Salsa20.hpp" #include "Utils.hpp" +namespace ZeroTier { + +////////////////////////////////////////////////////////////////////////////// +// This is the memory-hard hash used for type 0 identities' addresses + // 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) { @@ -94,23 +96,39 @@ struct _Identity_generate_cond char *genmem; }; -void Identity::generate() +////////////////////////////////////////////////////////////////////////////// + +void Identity::generate(const Type t) { - unsigned char digest[64]; - char *genmem = new char[ZT_IDENTITY_GEN_MEMORY]; + uint8_t digest[64]; + switch(t) { + case C25519: { + char *genmem = new char[ZT_IDENTITY_GEN_MEMORY]; - 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()); + 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; + + delete [] genmem; + } break; - delete [] genmem; + case P384: { + do { + ECC384GenerateKey(_k.t1.pub,_k.t1.priv); + SHA512::hash(digest,_k.t1.pub,ZT_ECC384_PUBLIC_KEY_SIZE); + _address.setTo(digest + 59,ZT_ADDRESS_LENGTH); + } while (_address.isReserved()); + _type = P384; + _hasPrivate = true; + } break; + } } bool Identity::locallyValidate() const @@ -118,40 +136,70 @@ 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); - delete [] genmem; + switch(_type) { + case C25519: { + unsigned char digest[64]; + char *genmem = new char[ZT_IDENTITY_GEN_MEMORY]; + _computeMemoryHardHash(_k.t0.pub.data,ZT_C25519_PUBLIC_KEY_LEN,digest,genmem); + 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])&& + (digest[60] == addrb[1])&& + (digest[61] == addrb[2])&& + (digest[62] == addrb[3])&& + (digest[63] == addrb[4])); + } break; - unsigned char addrb[5]; - _address.copyTo(addrb,5); + case P384: { + return true; + } break; + } - return ( - (digest[0] < ZT_IDENTITY_GEN_HASHCASH_FIRST_BYTE_LESS_THAN)&& - (digest[59] == addrb[0])&& - (digest[60] == addrb[1])&& - (digest[61] == addrb[2])&& - (digest[62] == addrb[3])&& - (digest[63] == addrb[4])); + return false; } char *Identity::toString(bool includePrivate,char buf[ZT_IDENTITY_STRING_BUFFER_LENGTH]) const { - char *p = buf; - Utils::hex10(_address.toInt(),p); - p += 10; - *(p++) = ':'; - *(p++) = '0'; - *(p++) = ':'; - Utils::hex(_publicKey.data,ZT_C25519_PUBLIC_KEY_LEN,p); - p += ZT_C25519_PUBLIC_KEY_LEN * 2; - if ((_privateKey)&&(includePrivate)) { - *(p++) = ':'; - Utils::hex(_privateKey->data,ZT_C25519_PRIVATE_KEY_LEN,p); - p += ZT_C25519_PRIVATE_KEY_LEN * 2; + switch(_type) { + case C25519: { + char *p = buf; + Utils::hex10(_address.toInt(),p); + p += 10; + *(p++) = ':'; + *(p++) = '0'; + *(p++) = ':'; + Utils::hex(_k.t0.pub.data,ZT_C25519_PUBLIC_KEY_LEN,p); + p += ZT_C25519_PUBLIC_KEY_LEN * 2; + if ((_hasPrivate)&&(includePrivate)) { + *(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; } - *p = (char)0; - return buf; } bool Identity::fromString(const char *str) @@ -166,8 +214,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,22 +228,49 @@ 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) { - _address.zero(); - return false; + 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 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: - _privateKey = new C25519::Private(); - if (Utils::unhex(f,_privateKey->data,ZT_C25519_PRIVATE_KEY_LEN) != ZT_C25519_PRIVATE_KEY_LEN) { - _address.zero(); - return false; + 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: diff --git a/node/Identity.hpp b/node/Identity.hpp index ee55028cf..4b5396d9b 100644 --- a/node/Identity.hpp +++ b/node/Identity.hpp @@ -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,45 @@ namespace ZeroTier { class Identity { public: - Identity() : - _privateKey((C25519::Private *)0) + enum Type { - } + C25519 = 0, // Curve25519 and Ed25519 + P384 = 1 // NIST P-384 ECDH and ECDSA + }; - 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(this),0,sizeof(Identity)); } + Identity(const Identity &id) { memcpy(reinterpret_cast(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 - Identity(const Buffer &b,unsigned int startAt = 0) : - _privateKey((C25519::Private *)0) - { - deserialize(b,startAt); - } + Identity(const Buffer &b,unsigned int startAt = 0) { deserialize(b,startAt); } - ~Identity() - { - if (_privateKey) { - Utils::burn(_privateKey,sizeof(C25519::Private)); - delete _privateKey; - } - } + ~Identity() { Utils::burn(reinterpret_cast(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(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 +105,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 +115,15 @@ public: */ inline bool sha512PrivateKey(void *sha) const { - if (_privateKey) { - SHA512::hash(sha,_privateKey->data,ZT_C25519_PRIVATE_KEY_LEN); - return true; + if (_hasPrivate) { + switch(_type) { + case C25519: + SHA512::hash(sha,_k.t0.priv.data,ZT_C25519_PRIVATE_KEY_LEN); + return true; + case P384: + SHA512::hash(sha,_k.t1.priv,ZT_ECC384_PRIVATE_KEY_SIZE); + return true; + } } return false; } @@ -140,14 +131,34 @@ 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 + inline unsigned int sign(const void *data,unsigned int len,void *sig,unsigned int siglen) const { - if (_privateKey) - return C25519::sign(*_privateKey,_publicKey,data,len); - throw ZT_EXCEPTION_PRIVATE_KEY_REQUIRED; + uint8_t h[64]; + 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; + SHA512::hash(h,data,len); + ECC384ECDSASign(_k.t1.priv,h,(uint8_t *)sig); + return ZT_ECC384_SIGNATURE_SIZE; + } + return 0; } /** @@ -159,17 +170,20 @@ 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 { return C25519::verify(_publicKey,data,len,signature,siglen); } - - /** - * 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); } + inline bool verify(const void *data,unsigned int len,const void *sig,unsigned int siglen) const + { + uint8_t h[64]; + switch(_type) { + case C25519: + return C25519::verify(_k.t0.pub,data,len,sig,siglen); + case P384: + if (siglen != ZT_ECC384_SIGNATURE_SIZE) + return false; + SHA512::hash(h,data,len); + return ECC384ECDSAVerify(_k.t1.pub,h,(const uint8_t *)sig); + } + return false; + } /** * Shortcut method to perform key agreement with another identity @@ -183,9 +197,26 @@ public: */ inline bool agree(const Identity &id,void *key,unsigned int klen) const { - if (_privateKey) { - C25519::agree(*_privateKey,id._publicKey,key,klen); - return true; + uint8_t ecc384RawSecret[ZT_ECC384_SHARED_SECRET_SIZE]; + uint8_t h[64]; + 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); + SHA512::hash(h,ecc384RawSecret,sizeof(ecc384RawSecret)); + unsigned int hi = 0; + for(unsigned int i=0;i &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; + } } /** @@ -229,27 +276,47 @@ public: template inline unsigned int deserialize(const Buffer &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) - 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; + _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; } return (p - startAt); @@ -275,40 +342,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 diff --git a/node/IncomingPacket.cpp b/node/IncomingPacket.cpp index bc2c6a7f2..197bfe225 100644 --- a/node/IncomingPacket.cpp +++ b/node/IncomingPacket.cpp @@ -43,7 +43,6 @@ #include "SelfAwareness.hpp" #include "Salsa20.hpp" #include "SHA512.hpp" -#include "World.hpp" #include "Node.hpp" #include "CertificateOfMembership.hpp" #include "Capability.hpp" @@ -368,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(ptr); ptr += 8; - planetWorldTimestamp = at(ptr); ptr += 8; - } - - std::vector< std::pair > 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(ptr); ptr += 2; - for(unsigned int i=0;i(at(ptr),at(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. @@ -435,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 moons(RR->topology->moons()); - for(std::vector::const_iterator m(moons.begin());m!=moons.end();++m) { - for(std::vector< std::pair >::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(worldUpdateSizeAt,(uint16_t)(outp.size() - (worldUpdateSizeAt + 2))); - outp.armor(peer->key(),true); _path->send(RR,tPtr,outp.data(),outp.size(),now); @@ -489,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(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()); } @@ -575,8 +515,9 @@ bool IncomingPacket::_doOK(const RuntimeEnvironment *RR,void *tPtr,const SharedP bool IncomingPacket::_doWHOIS(const RuntimeEnvironment *RR,void *tPtr,const SharedPtr &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); @@ -772,8 +713,8 @@ bool IncomingPacket::_doMULTICAST_LIKE(const RuntimeEnvironment *RR,void *tPtr,c SharedPtr 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(ptr + 14)),peer->address()); @@ -982,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()); diff --git a/node/Node.cpp b/node/Node.cpp index e71e898bd..609795ebb 100644 --- a/node/Node.cpp +++ b/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 > &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 *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 > &_alwaysContact; const int64_t _now; const SharedPtr _bestCurrentUpstream; + + bool online; }; ZT_ResultCode Node::processBackgroundTasks(void *tptr,int64_t now,volatile int64_t *nextBackgroundTaskDeadline) @@ -265,38 +268,25 @@ ZT_ResultCode Node::processBackgroundTasks(void *tptr,int64_t now,volatile int64 try { _lastPingCheck = now; - // Get designated VL1 upstreams - Hashtable< Address,std::vector > alwaysContact; - RR->topology->getUpstreamsToContact(alwaysContact); - - // Check last receive time on designated upstreams to see if we seem to be online - int64_t lastReceivedFromUpstream = 0; - { - Hashtable< Address,std::vector >::Iterator i(alwaysContact); - Address *upstreamAddress = (Address *)0; - std::vector *upstreamStableEndpoints = (std::vector *)0; - while (i.next(upstreamAddress,upstreamStableEndpoints)) { - SharedPtr 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 > alwaysContact; + RR->topology->getUpstreamsToContact(alwaysContact); std::vector< std::pair< SharedPtr,bool > > networkConfigNeeded; { Mutex::Lock l(_networks_m); @@ -331,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 ( ... ) { @@ -425,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(); @@ -635,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 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(); @@ -682,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(outp.data()) + sigStart,outp.size() - sigStart)); + uint8_t sig[256]; + const unsigned int siglen = RR->identity.sign(reinterpret_cast(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); @@ -879,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(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(node)->deorbit(tptr,moonWorldId); - } catch ( ... ) { - return ZT_RESULT_FATAL_ERROR_INTERNAL; - } -} - uint64_t ZT_Node_address(ZT_Node *node) { return reinterpret_cast(node)->address(); diff --git a/node/Node.hpp b/node/Node.hpp index a6f92eb11..e751b36bf 100644 --- a/node/Node.hpp +++ b/node/Node.hpp @@ -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 moons() const; - inline const Identity &identity() const { return _RR.identity; } /** diff --git a/node/Packet.cpp b/node/Packet.cpp index 5d0885d37..1c2ac86a7 100644 --- a/node/Packet.cpp +++ b/node/Packet.cpp @@ -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(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(unsafeData()); diff --git a/node/Packet.hpp b/node/Packet.hpp index f35714cc0..426274d77 100644 --- a/node/Packet.hpp +++ b/node/Packet.hpp @@ -71,6 +71,7 @@ * 10 - 1.4.0 ... CURRENT * + Multipath capability and load balancing * + Peer-to-peer multicast replication (optional) + * + Old planet/moon stuff is DEAD! */ #define ZT_PROTO_VERSION 10 @@ -532,22 +533,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. @@ -559,15 +547,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, @@ -1268,21 +1251,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) * diff --git a/node/Peer.cpp b/node/Peer.cpp index 5f5d1462b..4ef481c08 100644 --- a/node/Peer.cpp +++ b/node/Peer.cpp @@ -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 moons(RR->topology->moons()); - std::vector moonsWanted(RR->topology->moonsWanted()); - outp.append((uint16_t)(moons.size() + moonsWanted.size())); - for(std::vector::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::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) { diff --git a/node/Revocation.cpp b/node/Revocation.cpp index 043425690..75b71e9c5 100644 --- a/node/Revocation.cpp +++ b/node/Revocation.cpp @@ -34,6 +34,18 @@ namespace ZeroTier { +bool Revocation::sign(const Identity &signer) +{ + if (signer.hasPrivate()) { + Buffer 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 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; } diff --git a/node/Revocation.hpp b/node/Revocation.hpp index 1d001a405..94ba64596 100644 --- a/node/Revocation.hpp +++ b/node/Revocation.hpp @@ -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 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(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(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(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 diff --git a/node/Switch.cpp b/node/Switch.cpp index a6852d9f4..66d5da6d3 100644 --- a/node/Switch.cpp +++ b/node/Switch.cpp @@ -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 relayTo = RR->topology->getPeer(tPtr,destination); diff --git a/node/Tag.cpp b/node/Tag.cpp index 6c78f3e48..3ae29319e 100644 --- a/node/Tag.cpp +++ b/node/Tag.cpp @@ -34,6 +34,18 @@ namespace ZeroTier { +bool Tag::sign(const Identity &signer) +{ + if (signer.hasPrivate()) { + Buffer 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; } diff --git a/node/Tag.hpp b/node/Tag.hpp index 3f888ba91..e5ac891bd 100644 --- a/node/Tag.hpp +++ b/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 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(p) != ZT_C25519_SIGNATURE_LEN) + _signatureLength = b.template at(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(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 diff --git a/node/Topology.cpp b/node/Topology.cpp index 6d6beda33..985dd5d80 100644 --- a/node/Topology.cpp +++ b/node/Topology.cpp @@ -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(tmp,(unsigned int)n),0); - addWorld(tPtr,cachedPlanet,false); - } catch ( ... ) {} // ignore invalid cached planets - } - - World defaultPlanet; - { - Buffer 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 Topology::getUpstreamPeer() { - const int64_t now = RR->node->now(); - unsigned int bestq = ~((unsigned int)0); - const SharedPtr *best = (const SharedPtr *)0; - - Mutex::Lock _l2(_peers_m); - Mutex::Lock _l1(_upstreams_m); - - for(std::vector
::const_iterator a(_upstreamAddresses.begin());a!=_upstreamAddresses.end();++a) { - const SharedPtr *p = _peers.get(*a); - if (p) { - const unsigned int q = (*p)->relayQuality(now); - if (q <= bestq) { - bestq = q; - best = p; - } - } - } - - if (!best) - return SharedPtr(); - return *best; + return SharedPtr(); } 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::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::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::const_iterator e(r->stableEndpoints.begin());e!=r->stableEndpoints.end();++e) { - if (ipaddr.ipsEqual(*e)) - return false; - } - } - } - for(std::vector::const_iterator m(_moons.begin());m!=_moons.end();++m) { - for(std::vector::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::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 >::iterator m(_moonSeeds.begin());m!=_moonSeeds.end();++m) { - if (m->first == newWorld.id()) { - for(std::vector::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 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(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(id,seed)) == _moonSeeds.end()) - _moonSeeds.push_back(std::pair(id,seed)); - } -} - -void Topology::removeMoon(void *tPtr,const uint64_t id) -{ - Mutex::Lock _l2(_peers_m); - Mutex::Lock _l1(_upstreams_m); - - std::vector nm; - for(std::vector::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 > cm; - for(std::vector< std::pair >::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 >::Iterator i(_peers); Address *a = (Address *)0; SharedPtr *p = (SharedPtr *)0; while (i.next(a,p)) { - if ( (!(*p)->isAlive(now)) && (std::find(_upstreamAddresses.begin(),_upstreamAddresses.end(),*a) == _upstreamAddresses.end()) ) { + if (!(*p)->isAlive(now)) { _savePeer(tPtr,*p); _peers.erase(*a); } @@ -394,39 +156,6 @@ void Topology::doPeriodicTasks(void *tPtr,int64_t now) } } -void Topology::_memoizeUpstreams(void *tPtr) -{ - // assumes _upstreams_m and _peers_m are locked - _upstreamAddresses.clear(); - _amUpstream = false; - - for(std::vector::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 &hp = _peers[i->identity.address()]; - if (!hp) - hp = new Peer(RR,RR->identity,i->identity); - } - } - - for(std::vector::const_iterator m(_moons.begin());m!=_moons.end();++m) { - for(std::vector::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 &hp = _peers[i->identity.address()]; - if (!hp) - hp = new Peer(RR,RR->identity,i->identity); - } - } - } - - std::sort(_upstreamAddresses.begin(),_upstreamAddresses.end()); -} - void Topology::_savePeer(void *tPtr,const SharedPtr &peer) { try { diff --git a/node/Topology.hpp b/node/Topology.hpp index b6690f580..35c4e7ab3 100644 --- a/node/Topology.hpp +++ b/node/Topology.hpp @@ -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 > &eps) const { - Mutex::Lock _l(_upstreams_m); - for(std::vector::const_iterator i(_planet.roots().begin());i!=_planet.roots().end();++i) { - if (i->identity != RR->identity) { - std::vector &ips = eps[i->identity.address()]; - for(std::vector::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::const_iterator m(_moons.begin());m!=_moons.end();++m) { - for(std::vector::const_iterator i(m->roots().begin());i!=m->roots().end();++i) { - if (i->identity != RR->identity) { - std::vector &ips = eps[i->identity.address()]; - for(std::vector::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 >::const_iterator m(_moonSeeds.begin());m!=_moonSeeds.end();++m) - eps[m->second]; } /** @@ -201,87 +171,9 @@ public: */ inline std::vector
upstreamAddresses() const { - Mutex::Lock _l(_upstreams_m); - return _upstreamAddresses; + return std::vector
(); } - /** - * @return Current moons - */ - inline std::vector moons() const - { - Mutex::Lock _l(_upstreams_m); - return _moons; - } - - /** - * @return Moon IDs we are waiting for from seeds - */ - inline std::vector moonsWanted() const - { - Mutex::Lock _l(_upstreams_m); - std::vector mw; - for(std::vector< std::pair >::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 +225,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 * @@ -455,13 +342,6 @@ private: Hashtable< Path::HashKey,SharedPtr > _paths; Mutex _paths_m; - - World _planet; - std::vector _moons; - std::vector< std::pair > _moonSeeds; - std::vector
_upstreamAddresses; - bool _amUpstream; - Mutex _upstreams_m; // locks worlds, upstream info, moon info, etc. }; } // namespace ZeroTier diff --git a/node/Utils.hpp b/node/Utils.hpp index 009866d48..c5fa8756a 100644 --- a/node/Utils.hpp +++ b/node/Utils.hpp @@ -453,7 +453,7 @@ public: out[6] = BASE32CHARS[(in[3] & 0x03) << 3 | (in[4] & 0xe0) >> 5]; out[7] = BASE32CHARS[(in[4] & 0x1f)]; } - + static inline void base328to5(const char *const in,uint8_t *const out) { out[0] = ((BASE32BITS[(unsigned int)in[0]]) << 3) | (BASE32BITS[(unsigned int)in[1]] & 0x1C) >> 2; @@ -462,7 +462,7 @@ public: out[3] = ((BASE32BITS[(unsigned int)in[4]] & 0x01) << 7) | (BASE32BITS[(unsigned int)in[5]]) << 2 | (BASE32BITS[(unsigned int)in[6]] & 0x18) >> 3; out[4] = ((BASE32BITS[(unsigned int)in[6]] & 0x07) << 5) | (BASE32BITS[(unsigned int)in[7]]); } - + /** * Hexadecimal characters 0-f */ diff --git a/node/World.hpp b/node/World.hpp deleted file mode 100644 index 823d304d8..000000000 --- a/node/World.hpp +++ /dev/null @@ -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 . - * - * -- - * - * 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 -#include - -#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 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 &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 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 - inline void serialize(Buffer &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::const_iterator r(_roots.begin());r!=_roots.end();++r) { - r->identity.serialize(b); - b.append((uint8_t)r->stableEndpoints.size()); - for(std::vector::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 - inline unsigned int deserialize(const Buffer &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(p); p += 8; - _ts = b.template at(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 ZT_WORLD_MAX_STABLE_ENDPOINTS_PER_ROOT) - throw ZT_EXCEPTION_INVALID_SERIALIZED_DATA_OVERFLOW; - for(unsigned int kk=0;kk(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 &roots,const C25519::Pair &signWith) - { - World w; - w._id = id; - w._ts = ts; - w._type = t; - w._updatesMustBeSignedBy = sk; - w._roots = roots; - - Buffer 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 _roots; -}; - -} // namespace ZeroTier - -#endif diff --git a/one.cpp b/one.cpp index 89acaace5..5a148e7ed 100644 --- a/one.cpp +++ b/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 - Leave a network" ZT_EOL_S); fprintf(out," set - Set a network setting" ZT_EOL_S); fprintf(out," get - Get a network setting" ZT_EOL_S); - fprintf(out," listmoons - List moons (federated root sets)" ZT_EOL_S); - fprintf(out," orbit - Join a moon via any member root" ZT_EOL_S); - fprintf(out," deorbit - 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 " ZT_EOL_S); fprintf(out," sign " ZT_EOL_S); fprintf(out," verify " ZT_EOL_S); - fprintf(out," initmoon " ZT_EOL_S); - fprintf(out," genmoon " 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 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 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; diff --git a/selftest.cpp b/selftest.cpp index 9ddd6953b..4e46ab8fd 100644 --- a/selftest.cpp +++ b/selftest.cpp @@ -367,8 +367,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; @@ -398,9 +398,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; @@ -420,7 +420,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; @@ -508,7 +508,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: "; @@ -581,13 +581,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..."; diff --git a/service/OneService.cpp b/service/OneService.cpp index 53b3e606f..9dfa8b0f5 100644 --- a/service/OneService.cpp +++ b/service/OneService.cpp @@ -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" @@ -346,28 +345,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::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::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); @@ -780,16 +757,6 @@ public: } } - // Orbit existing moons in moons.d - { - std::vector moonsDotD(OSUtils::listDirectory((_homePath + ZT_PATH_SEPARATOR_S "moons.d").c_str())); - for(std::vector::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(); @@ -1287,37 +1254,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 moons(_node->moons()); - if (ps.size() == 1) { - // Return [array] of all moons - - res = json::array(); - for(std::vector::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::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) { @@ -1390,44 +1328,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 moons(_node->moons()); - const uint64_t id = Utils::hexStrToU64(ps[1].c_str()); - for(std::vector::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()); @@ -1474,13 +1375,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) { @@ -2370,13 +2265,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]); @@ -2522,12 +2410,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;