diff --git a/node/CMakeLists.txt b/node/CMakeLists.txt index 8e13b2436..0d1e59591 100644 --- a/node/CMakeLists.txt +++ b/node/CMakeLists.txt @@ -70,10 +70,12 @@ set(core_src Peer.cpp Poly1305.cpp Protocol.cpp + Revocation.cpp Salsa20.cpp SelfAwareness.cpp SHA512.cpp Switch.cpp + Tag.cpp Topology.cpp Trace.cpp Utils.cpp diff --git a/node/Capability.cpp b/node/Capability.cpp index 934c763de..e31fed949 100644 --- a/node/Capability.cpp +++ b/node/Capability.cpp @@ -122,7 +122,7 @@ int Capability::unmarshal(const uint8_t *data,int len) return p; } -int Capability::marshalVirtualNetworkRules(uint8_t data[ZT_VIRTUALNETWORKRULE_MARSHAL_SIZE_MAX],const ZT_VirtualNetworkRule *const rules,const unsigned int ruleCount) +int Capability::marshalVirtualNetworkRules(uint8_t *data,const ZT_VirtualNetworkRule *const rules,const unsigned int ruleCount) { int p = 0; for(unsigned int i=0;i > tmp(new Buffer()); + uint8_t tmp[16384]; + std::vector buf; char tmp2[128]; d.clear(); @@ -64,62 +65,90 @@ bool NetworkConfig::toDictionary(Dictionary &d,bool includeLegacy) const // Then add binary blobs if (this->com) { - tmp->clear(); - this->com.serialize(*tmp); - if (!d.add(ZT_NETWORKCONFIG_DICT_KEY_COM,*tmp)) return false; + if (!d.add(ZT_NETWORKCONFIG_DICT_KEY_COM,(const char *)tmp,this->com.marshal(tmp))) + return false; } - tmp->clear(); - for(unsigned int i=0;icapabilityCount;++i) - this->capabilities[i].serialize(*tmp); - if (tmp->size()) { - if (!d.add(ZT_NETWORKCONFIG_DICT_KEY_CAPABILITIES,*tmp)) return false; + buf.clear(); + for(unsigned int i=0;icapabilityCount;++i) { + int l = this->capabilities[i].marshal(tmp); + if (l < 0) + return false; + buf.insert(buf.end(),tmp,tmp + l); + } + if (!buf.empty()) { + if (!d.add(ZT_NETWORKCONFIG_DICT_KEY_CAPABILITIES,(const char *)buf.data(),(int)buf.size())) + return false; } - tmp->clear(); - for(unsigned int i=0;itagCount;++i) - this->tags[i].serialize(*tmp); - if (tmp->size()) { - if (!d.add(ZT_NETWORKCONFIG_DICT_KEY_TAGS,*tmp)) return false; + buf.clear(); + for(unsigned int i=0;itagCount;++i) { + int l = this->tags[i].marshal(tmp); + if (l < 0) + return false; + buf.insert(buf.end(),tmp,tmp + l); + } + if (!buf.empty()) { + if (!d.add(ZT_NETWORKCONFIG_DICT_KEY_TAGS,(const char *)buf.data(),(int)buf.size())) + return false; } - tmp->clear(); - for(unsigned int i=0;icertificateOfOwnershipCount;++i) - this->certificatesOfOwnership[i].serialize(*tmp); - if (tmp->size()) { - if (!d.add(ZT_NETWORKCONFIG_DICT_KEY_CERTIFICATES_OF_OWNERSHIP,*tmp)) return false; + buf.clear(); + for(unsigned int i=0;icertificateOfOwnershipCount;++i) { + int l = this->certificatesOfOwnership[i].marshal(tmp); + if (l < 0) + return false; + buf.insert(buf.end(),tmp,tmp + l); + } + if (!buf.empty()) { + if (!d.add(ZT_NETWORKCONFIG_DICT_KEY_CERTIFICATES_OF_OWNERSHIP,(const char *)buf.data(),(int)buf.size())) + return false; } - tmp->clear(); - for(unsigned int i=0;ispecialistCount;++i) - tmp->append((uint64_t)this->specialists[i]); - if (tmp->size()) { - if (!d.add(ZT_NETWORKCONFIG_DICT_KEY_SPECIALISTS,*tmp)) return false; + buf.clear(); + for(unsigned int i=0;ispecialistCount;++i) { + Utils::storeBigEndian(tmp,this->specialists[i]); + buf.insert(buf.end(),tmp,tmp + 8); + } + if (!buf.empty()) { + if (!d.add(ZT_NETWORKCONFIG_DICT_KEY_SPECIALISTS,(const char *)buf.data(),(int)buf.size())) + return false; } - tmp->clear(); + buf.clear(); for(unsigned int i=0;irouteCount;++i) { - reinterpret_cast(&(this->routes[i].target))->serialize(*tmp); - reinterpret_cast(&(this->routes[i].via))->serialize(*tmp); - tmp->append((uint16_t)this->routes[i].flags); - tmp->append((uint16_t)this->routes[i].metric); + int l = asInetAddress(this->routes[i].target).marshal(tmp); + if (l < 0) + return false; + buf.insert(buf.end(),tmp,tmp + l); + l = asInetAddress(this->routes[i].via).marshal(tmp); + if (l < 0) + return false; + buf.insert(buf.end(),tmp,tmp + l); } - if (tmp->size()) { - if (!d.add(ZT_NETWORKCONFIG_DICT_KEY_ROUTES,*tmp)) return false; + if (!buf.empty()) { + if (!d.add(ZT_NETWORKCONFIG_DICT_KEY_ROUTES,(const char *)buf.data(),(int)buf.size())) + return false; } - tmp->clear(); - for(unsigned int i=0;istaticIpCount;++i) - this->staticIps[i].serialize(*tmp); - if (tmp->size()) { - if (!d.add(ZT_NETWORKCONFIG_DICT_KEY_STATIC_IPS,*tmp)) return false; + buf.clear(); + for(unsigned int i=0;istaticIpCount;++i) { + int l = this->staticIps[i].marshal(tmp); + if (l < 0) + return false; + buf.insert(buf.end(),tmp,tmp + l); + } + if (!buf.empty()) { + if (!d.add(ZT_NETWORKCONFIG_DICT_KEY_STATIC_IPS,(const char *)buf.data(),(int)buf.size())) + return false; } if (this->ruleCount) { - tmp->clear(); - Capability::serializeRules(*tmp,rules,ruleCount); - if (tmp->size()) { - if (!d.add(ZT_NETWORKCONFIG_DICT_KEY_RULES,*tmp)) return false; + buf.resize(ruleCount * ZT_VIRTUALNETWORKRULE_MARSHAL_SIZE_MAX); + int l = Capability::marshalVirtualNetworkRules(buf.data(),rules,ruleCount); + if (l > 0) { + if (!d.add(ZT_NETWORKCONFIG_DICT_KEY_RULES,(const char *)buf.data(),l)) + return false; } } diff --git a/node/Protocol.cpp b/node/Protocol.cpp index 4b31e8bf4..c1f34262e 100644 --- a/node/Protocol.cpp +++ b/node/Protocol.cpp @@ -27,7 +27,7 @@ namespace Protocol { namespace { -const uint8_t ZEROES32[32] = { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 }; +const uint64_t ZEROES32[4] = { 0,0,0,0 }; /** * Deterministically mangle a 256-bit crypto key based on packet diff --git a/node/Revocation.cpp b/node/Revocation.cpp new file mode 100644 index 000000000..fb6692ea7 --- /dev/null +++ b/node/Revocation.cpp @@ -0,0 +1,89 @@ +/* + * Copyright (c)2013-2020 ZeroTier, Inc. + * + * Use of this software is governed by the Business Source License included + * in the LICENSE.TXT file in the project's root directory. + * + * Change Date: 2024-01-01 + * + * On the date above, in accordance with the Business Source License, use + * of this software will be governed by version 2.0 of the Apache License. + */ +/****/ + +#include "Revocation.hpp" + +namespace ZeroTier { + +bool Revocation::sign(const Identity &signer) +{ + uint8_t buf[ZT_REVOCATION_MARSHAL_SIZE_MAX+32]; + if (signer.hasPrivate()) { + _signedBy = signer.address(); + _signatureLength = signer.sign(buf,(unsigned int)marshal(buf,true),_signature,sizeof(_signature)); + return true; + } + return false; +} + +int Revocation::marshal(uint8_t data[ZT_REVOCATION_MARSHAL_SIZE_MAX],bool forSign) const +{ + int p = 0; + if (forSign) { + for(int k=0;k<8;++k) + data[p++] = 0x7f; + } + Utils::storeBigEndian(data + p,0); p += 4; + Utils::storeBigEndian(data + p,_id); p += 4; + Utils::storeBigEndian(data + p,_networkId); p += 8; + Utils::storeBigEndian(data + p,0); p += 4; + Utils::storeBigEndian(data + p,_credentialId); p += 4; + Utils::storeBigEndian(data + p,(uint64_t)_threshold); p += 8; + Utils::storeBigEndian(data + p,_flags); p += 8; + _target.copyTo(data + p); p += ZT_ADDRESS_LENGTH; + _signedBy.copyTo(data + p); p += ZT_ADDRESS_LENGTH; + data[p++] = (uint8_t)_type; + if (!forSign) { + data[p++] = 1; + Utils::storeBigEndian(data + p,(uint16_t)_signatureLength); + memcpy(data + p,_signature,_signatureLength); + p += (int)_signatureLength; + } + data[p++] = 0; + data[p++] = 0; + if (forSign) { + for(int k=0;k<8;++k) + data[p++] = 0x7f; + } + return p; +} + +int Revocation::unmarshal(const uint8_t *restrict data,const int len) +{ + if (len < 54) + return -1; + // 4 bytes reserved + _id = Utils::loadBigEndian(data + 4); + _networkId = Utils::loadBigEndian(data + 8); + // 4 bytes reserved + _credentialId = Utils::loadBigEndian(data + 20); + _threshold = (int64_t)Utils::loadBigEndian(data + 24); + _flags = Utils::loadBigEndian(data + 32); + _target.setTo(data + 40); + _signedBy.setTo(data + 45); + _type = (ZT_CredentialType)data[50]; + // 1 byte reserved + _signatureLength = Utils::loadBigEndian(data + 52); + int p = 54 + (int)_signatureLength; + if ((_signatureLength > ZT_SIGNATURE_BUFFER_SIZE)||(p > len)) + return -1; + memcpy(_signature,data + 54,_signatureLength); + if ((p + 2) > len) + return -1; + p += 2 + Utils::loadBigEndian(data + p); + if (p > len) + return -1; + return p; +} + +} // namespace ZeroTier diff --git a/node/Revocation.hpp b/node/Revocation.hpp index 132922c40..900a633fc 100644 --- a/node/Revocation.hpp +++ b/node/Revocation.hpp @@ -31,6 +31,8 @@ */ #define ZT_REVOCATION_FLAG_FAST_PROPAGATE 0x1ULL +#define ZT_REVOCATION_MARSHAL_SIZE_MAX (4 + 4 + 8 + 4 + 4 + 8 + 8 + 5 + 5 + 1 + 1 + 2 + ZT_SIGNATURE_BUFFER_SIZE + 2) + namespace ZeroTier { class RuntimeEnvironment; @@ -95,17 +97,7 @@ public: * @param signer Signing identity, must have private key * @return True if signature was successful */ - ZT_ALWAYS_INLINE bool 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; - } + bool sign(const Identity &signer); /** * Verify this revocation's signature @@ -115,67 +107,9 @@ public: */ ZT_ALWAYS_INLINE Credential::VerifyResult verify(const RuntimeEnvironment *RR,void *tPtr) const { return _verify(RR,tPtr,*this); } - template - inline void serialize(Buffer &b,const bool forSign = false) const - { - if (forSign) b.append((uint64_t)0x7f7f7f7f7f7f7f7fULL); - - b.append((uint32_t)0); // 4 unused bytes, currently set to 0 - b.append(_id); - b.append(_networkId); - b.append((uint32_t)0); // 4 unused bytes, currently set to 0 - b.append(_credentialId); - b.append(_threshold); - b.append(_flags); - _target.appendTo(b); - _signedBy.appendTo(b); - b.append((uint8_t)_type); - - if (!forSign) { - b.append((uint8_t)1); - b.append((uint16_t)_signatureLength); - b.append(_signature,_signatureLength); - } - - // This is the size of any additional fields, currently 0. - b.append((uint16_t)0); - - if (forSign) b.append((uint64_t)0x7f7f7f7f7f7f7f7fULL); - } - - template - inline unsigned int deserialize(const Buffer &b,unsigned int startAt = 0) - { - *this = Revocation(); - - unsigned int p = startAt; - - p += 4; // 4 bytes, currently unused - _id = b.template at(p); p += 4; - _networkId = b.template at(p); p += 8; - p += 4; // 4 bytes, currently unused - _credentialId = b.template at(p); p += 4; - _threshold = b.template at(p); p += 8; - _flags = b.template at(p); p += 8; - _target.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; - _type = (ZT_CredentialType)b[p++]; - - if (b[p++] == 1) { - _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); - } - - p += 2 + b.template at(p); - if (p > b.size()) - throw ZT_EXCEPTION_INVALID_SERIALIZED_DATA_OVERFLOW; - - return (p - startAt); - } + static ZT_ALWAYS_INLINE int marshalSizeMax() { return ZT_REVOCATION_MARSHAL_SIZE_MAX; } + int marshal(uint8_t data[ZT_REVOCATION_MARSHAL_SIZE_MAX],bool forSign = false) const; + int unmarshal(const uint8_t *restrict data,const int len); private: uint32_t _id; diff --git a/node/Tag.cpp b/node/Tag.cpp new file mode 100644 index 000000000..09a8643b6 --- /dev/null +++ b/node/Tag.cpp @@ -0,0 +1,81 @@ +/* + * Copyright (c)2013-2020 ZeroTier, Inc. + * + * Use of this software is governed by the Business Source License included + * in the LICENSE.TXT file in the project's root directory. + * + * Change Date: 2024-01-01 + * + * On the date above, in accordance with the Business Source License, use + * of this software will be governed by version 2.0 of the Apache License. + */ +/****/ + +#include "Tag.hpp" + +namespace ZeroTier { + +bool Tag::sign(const Identity &signer) +{ + uint8_t buf[ZT_TAG_MARSHAL_SIZE_MAX]; + if (signer.hasPrivate()) { + _signedBy = signer.address(); + _signatureLength = signer.sign(buf,(unsigned int)marshal(buf,true),_signature,sizeof(_signature)); + return true; + } + return false; +} + +int Tag::marshal(uint8_t data[ZT_TAG_MARSHAL_SIZE_MAX],bool forSign) const +{ + int p = 0; + if (forSign) { + for(int k=0;k<8;++k) + data[p++] = 0x7f; + } + Utils::storeBigEndian(data + p,_networkId); p += 8; + Utils::storeBigEndian(data + p,(uint64_t)_ts); p += 8; + Utils::storeBigEndian(data + p,_id); p += 4; + Utils::storeBigEndian(data + p,_value); p += 4; + _issuedTo.copyTo(data + p); p += ZT_ADDRESS_LENGTH; + _signedBy.copyTo(data + p); p += ZT_ADDRESS_LENGTH; + if (!forSign) { + data[p++] = 1; + Utils::storeBigEndian(data + p,(uint16_t)_signatureLength); p += 2; + memcpy(data + p,_signature,_signatureLength); + p += (int)_signatureLength; + } + data[p++] = 0; + data[p++] = 0; + if (forSign) { + for(int k=0;k<8;++k) + data[p++] = 0x7f; + } + return p; +} + +int Tag::unmarshal(const uint8_t *data,int len) +{ + if (len < 37) + return -1; + _networkId = Utils::loadBigEndian(data); + _ts = (int64_t)Utils::loadBigEndian(data + 8); + _id = Utils::loadBigEndian(data + 16); + _value = Utils::loadBigEndian(data + 20); + _issuedTo.setTo(data + 24); + _signedBy.setTo(data + 29); + // 1 byte reserved + _signatureLength = Utils::loadBigEndian(data + 35); + int p = 37 + (int)_signatureLength; + if ((_signatureLength > ZT_SIGNATURE_BUFFER_SIZE)||(p > len)) + return -1; + memcpy(_signature,data + p,_signatureLength); + if ((p + 2) > len) + return -1; + p += 2 + Utils::loadBigEndian(data + p); + if (p > len) + return -1; + return p; +} + +} // namespace ZeroTier diff --git a/node/Tag.hpp b/node/Tag.hpp index 731b55525..32e4c7e6e 100644 --- a/node/Tag.hpp +++ b/node/Tag.hpp @@ -25,6 +25,8 @@ #include "Address.hpp" #include "Identity.hpp" +#define ZT_TAG_MARSHAL_SIZE_MAX (8 + 8 + 4 + 4 + 5 + 5 + 1 + 2 + ZT_SIGNATURE_BUFFER_SIZE + 2) + namespace ZeroTier { class RuntimeEnvironment; @@ -95,17 +97,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); - _signatureLength = signer.sign(tmp.data(),tmp.size(),_signature,sizeof(_signature)); - return true; - } - return false; - } + bool sign(const Identity &signer); /** * Check this tag's signature @@ -115,60 +107,9 @@ public: */ ZT_ALWAYS_INLINE Credential::VerifyResult verify(const RuntimeEnvironment *RR,void *tPtr) const { return _verify(RR,tPtr,*this); } - template - inline void serialize(Buffer &b,const bool forSign = false) const - { - if (forSign) b.append((uint64_t)0x7f7f7f7f7f7f7f7fULL); - - b.append(_networkId); - b.append(_ts); - b.append(_id); - b.append(_value); - - _issuedTo.appendTo(b); - _signedBy.appendTo(b); - if (!forSign) { - 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 - - if (forSign) b.append((uint64_t)0x7f7f7f7f7f7f7f7fULL); - } - - template - inline unsigned int deserialize(const Buffer &b,unsigned int startAt = 0) - { - unsigned int p = startAt; - - *this = Tag(); - - _networkId = b.template at(p); p += 8; - _ts = b.template at(p); p += 8; - _id = b.template at(p); p += 4; - - _value = b.template at(p); p += 4; - - _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) { - _signatureLength = b.template at(p); - if (_signatureLength > sizeof(_signature)) - throw ZT_EXCEPTION_INVALID_SERIALIZED_DATA_INVALID_CRYPTOGRAPHIC_TOKEN; - p += 2; - memcpy(_signature,b.field(p,_signatureLength),_signatureLength); p += _signatureLength; - } else { - p += 2 + b.template at(p); - } - - p += 2 + b.template at(p); - if (p > b.size()) - throw ZT_EXCEPTION_INVALID_SERIALIZED_DATA_OVERFLOW; - - return (p - startAt); - } + static ZT_ALWAYS_INLINE int marshalSizeMax() { return ZT_TAG_MARSHAL_SIZE_MAX; } + int marshal(uint8_t data[ZT_TAG_MARSHAL_SIZE_MAX],bool forSign = false) const; + int unmarshal(const uint8_t *data,int len); // Provides natural sort order by ID ZT_ALWAYS_INLINE bool operator<(const Tag &t) const { return (_id < t._id); } diff --git a/node/Utils.hpp b/node/Utils.hpp index 2853d852c..31601d0b7 100644 --- a/node/Utils.hpp +++ b/node/Utils.hpp @@ -212,14 +212,14 @@ static ZT_ALWAYS_INLINE unsigned long hexStrToULong(const char *s) { return strt static ZT_ALWAYS_INLINE long hexStrToLong(const char *s) { return strtol(s,(char **)0,16); } #endif -static ZT_ALWAYS_INLINE unsigned int strToUInt(const char *s) { return (unsigned int)strtoul(s,(char **)0,10); } +static ZT_ALWAYS_INLINE unsigned int strToUInt(const char *s) { return (unsigned int)strtoul(s,nullptr,10); } static ZT_ALWAYS_INLINE unsigned long long strToU64(const char *s) { #ifdef __WINDOWS__ return (unsigned long long)_strtoui64(s,(char **)0,10); #else - return strtoull(s,(char **)0,10); + return strtoull(s,nullptr,10); #endif } @@ -228,16 +228,16 @@ static ZT_ALWAYS_INLINE long long hexStrTo64(const char *s) #ifdef __WINDOWS__ return (long long)_strtoi64(s,(char **)0,16); #else - return strtoll(s,(char **)0,16); + return strtoll(s,nullptr,16); #endif } static ZT_ALWAYS_INLINE unsigned long long hexStrToU64(const char *s) { #ifdef __WINDOWS__ - return (unsigned long long)_strtoui64(s,(char **)0,16); + return (unsigned long long)_strtoui64(s,nullptr,16); #else - return strtoull(s,(char **)0,16); + return strtoull(s,nullptr,16); #endif }