From e6b4006c701f0ca5d79f99d09883e480ca6b0020 Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Wed, 14 Aug 2019 14:55:37 -0700 Subject: [PATCH] Refactoring to eliminate duplicated code --- node/AtomicCounter.hpp | 2 +- node/CMakeLists.txt | 6 +- node/Capability.cpp | 17 --- node/Capability.hpp | 23 ++- node/CertificateOfMembership.cpp | 240 ------------------------------- node/CertificateOfMembership.hpp | 101 +++++++++---- node/CertificateOfOwnership.cpp | 98 ------------- node/CertificateOfOwnership.hpp | 59 ++++++-- node/Credential.cpp | 88 ++++++++++++ node/Credential.hpp | 23 +++ node/Membership.cpp | 10 +- node/Revocation.cpp | 67 --------- node/Revocation.hpp | 19 ++- node/Tag.cpp | 67 --------- node/Tag.hpp | 23 ++- objects.mk | 5 +- 16 files changed, 298 insertions(+), 550 deletions(-) delete mode 100644 node/CertificateOfMembership.cpp delete mode 100644 node/CertificateOfOwnership.cpp create mode 100644 node/Credential.cpp delete mode 100644 node/Revocation.cpp delete mode 100644 node/Tag.cpp diff --git a/node/AtomicCounter.hpp b/node/AtomicCounter.hpp index 4eba043bc..0b06bedfc 100644 --- a/node/AtomicCounter.hpp +++ b/node/AtomicCounter.hpp @@ -72,7 +72,7 @@ public: private: inline AtomicCounter(const AtomicCounter &) {} - const AtomicCounter &operator=(const AtomicCounter &) { return *this; } + inline const AtomicCounter &operator=(const AtomicCounter &) { return *this; } #ifdef __GNUC__ int _v; diff --git a/node/CMakeLists.txt b/node/CMakeLists.txt index add93405b..eb45b6df8 100644 --- a/node/CMakeLists.txt +++ b/node/CMakeLists.txt @@ -52,8 +52,7 @@ set(core_src AES.cpp C25519.cpp Capability.cpp - CertificateOfMembership.cpp - CertificateOfOwnership.cpp + Credential.cpp ECC384.cpp Identity.cpp IncomingPacket.cpp @@ -68,13 +67,10 @@ set(core_src Path.cpp Peer.cpp Poly1305.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 3ed7f0b19..f10d385aa 100644 --- a/node/Capability.cpp +++ b/node/Capability.cpp @@ -34,23 +34,6 @@ 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 { diff --git a/node/Capability.hpp b/node/Capability.hpp index 809b18c6f..7334ad1df 100644 --- a/node/Capability.hpp +++ b/node/Capability.hpp @@ -69,6 +69,8 @@ class RuntimeEnvironment; */ class Capability : public Credential { + friend class Credential; + public: static inline Credential::Type credentialType() { return Credential::CREDENTIAL_TYPE_CAPABILITY; } @@ -154,8 +156,23 @@ public: * @param to Recipient of this signature * @return True if signature successful and chain of custody appended */ - bool sign(const Identity &from,const Address &to); - + 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].signatureLength = from.sign(tmp.data(),tmp.size(),_custody[i].signature,sizeof(_custody[i].signature)); + return true; + } + } + } catch ( ... ) {} + return false; + } + /** * Verify this capability's chain of custody and signatures * @@ -163,7 +180,7 @@ public: * @return 0 == OK, 1 == waiting for WHOIS, -1 == BAD signature or chain */ int verify(const RuntimeEnvironment *RR,void *tPtr) const; - + template static inline void serializeRules(Buffer &b,const ZT_VirtualNetworkRule *rules,unsigned int ruleCount) { diff --git a/node/CertificateOfMembership.cpp b/node/CertificateOfMembership.cpp deleted file mode 100644 index 0ec7abfaf..000000000 --- a/node/CertificateOfMembership.cpp +++ /dev/null @@ -1,240 +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. - */ - -#include "CertificateOfMembership.hpp" -#include "RuntimeEnvironment.hpp" -#include "Topology.hpp" -#include "Switch.hpp" -#include "Network.hpp" -#include "Node.hpp" - -namespace ZeroTier { - -void CertificateOfMembership::setQualifier(uint64_t id,uint64_t value,uint64_t maxDelta) -{ - _signedBy.zero(); - - for(unsigned int i=0;i<_qualifierCount;++i) { - if (_qualifiers[i].id == id) { - _qualifiers[i].value = value; - _qualifiers[i].maxDelta = maxDelta; - return; - } - } - - if (_qualifierCount < ZT_NETWORK_COM_MAX_QUALIFIERS) { - _qualifiers[_qualifierCount].id = id; - _qualifiers[_qualifierCount].value = value; - _qualifiers[_qualifierCount].maxDelta = maxDelta; - ++_qualifierCount; - std::sort(&(_qualifiers[0]),&(_qualifiers[_qualifierCount])); - } -} - -#ifdef ZT_SUPPORT_OLD_STYLE_NETCONF - -std::string CertificateOfMembership::toString() const -{ - char tmp[ZT_NETWORK_COM_MAX_QUALIFIERS * 32]; - std::string s; - - s.append("1:"); // COM_UINT64_ED25519 - - uint64_t *const buf = new uint64_t[_qualifierCount * 3]; - try { - unsigned int ptr = 0; - for(unsigned int i=0;i<_qualifierCount;++i) { - buf[ptr++] = Utils::hton(_qualifiers[i].id); - buf[ptr++] = Utils::hton(_qualifiers[i].value); - buf[ptr++] = Utils::hton(_qualifiers[i].maxDelta); - } - s.append(Utils::hex(buf,ptr * sizeof(uint64_t),tmp)); - delete [] buf; - } catch ( ... ) { - delete [] buf; - throw; - } - - s.push_back(':'); - - s.append(_signedBy.toString(tmp)); - - if (_signedBy) { - s.push_back(':'); - s.append(Utils::hex(_signature,_signatureLength,tmp)); - } - - return s; -} - -void CertificateOfMembership::fromString(const char *s) -{ - _signedBy.zero(); - _qualifierCount = 0; - _signatureLength = 0; - - if (!*s) - return; - - unsigned int colonAt = 0; - while ((s[colonAt])&&(s[colonAt] != ':')) ++colonAt; - - if (!((colonAt == 1)&&(s[0] == '1'))) // COM_UINT64_ED25519? - return; - - s += colonAt + 1; - colonAt = 0; - while ((s[colonAt])&&(s[colonAt] != ':')) ++colonAt; - - if (colonAt) { - const unsigned int buflen = colonAt / 2; - char *const buf = new char[buflen]; - unsigned int bufactual = Utils::unhex(s,colonAt,buf,buflen); - char *bufptr = buf; - try { - while (bufactual >= 24) { - if (_qualifierCount < ZT_NETWORK_COM_MAX_QUALIFIERS) { - _qualifiers[_qualifierCount].id = Utils::ntoh(*((uint64_t *)bufptr)); bufptr += 8; - _qualifiers[_qualifierCount].value = Utils::ntoh(*((uint64_t *)bufptr)); bufptr += 8; - _qualifiers[_qualifierCount].maxDelta = Utils::ntoh(*((uint64_t *)bufptr)); bufptr += 8; - ++_qualifierCount; - } else { - bufptr += 24; - } - bufactual -= 24; - } - } catch ( ... ) {} - delete [] buf; - } - - if (s[colonAt]) { - s += colonAt + 1; - colonAt = 0; - while ((s[colonAt])&&(s[colonAt] != ':')) ++colonAt; - - if (colonAt) { - char addrbuf[ZT_ADDRESS_LENGTH]; - if (Utils::unhex(s,colonAt,addrbuf,sizeof(addrbuf)) == ZT_ADDRESS_LENGTH) - _signedBy.setTo(addrbuf,ZT_ADDRESS_LENGTH); - - if ((_signedBy)&&(s[colonAt])) { - s += colonAt + 1; - colonAt = 0; - while ((s[colonAt])&&(s[colonAt] != ':')) ++colonAt; - if (colonAt) { - _signatureLength = Utils::unhex(s,colonAt,_signature,sizeof(_signature)); - } else { - _signedBy.zero(); - } - } else { - _signedBy.zero(); - } - } - } - - std::sort(&(_qualifiers[0]),&(_qualifiers[_qualifierCount])); -} - -#endif // ZT_SUPPORT_OLD_STYLE_NETCONF - -bool CertificateOfMembership::agreesWith(const CertificateOfMembership &other) const -{ - unsigned int myidx = 0; - unsigned int otheridx = 0; - - if ((_qualifierCount == 0)||(other._qualifierCount == 0)) - return false; - - while (myidx < _qualifierCount) { - // Fail if we're at the end of other, since this means the field is - // missing. - if (otheridx >= other._qualifierCount) - return false; - - // Seek to corresponding tuple in other, ignoring tuples that - // we may not have. If we run off the end of other, the tuple is - // missing. This works because tuples are sorted by ID. - while (other._qualifiers[otheridx].id != _qualifiers[myidx].id) { - ++otheridx; - if (otheridx >= other._qualifierCount) - return false; - } - - // Compare to determine if the absolute value of the difference - // between these two parameters is within our maxDelta. - const uint64_t a = _qualifiers[myidx].value; - const uint64_t b = other._qualifiers[myidx].value; - if (((a >= b) ? (a - b) : (b - a)) > _qualifiers[myidx].maxDelta) - return false; - - ++myidx; - } - - return true; -} - -bool CertificateOfMembership::sign(const Identity &with) -{ - uint64_t buf[ZT_NETWORK_COM_MAX_QUALIFIERS * 3]; - unsigned int ptr = 0; - for(unsigned int i=0;i<_qualifierCount;++i) { - buf[ptr++] = Utils::hton(_qualifiers[i].id); - buf[ptr++] = Utils::hton(_qualifiers[i].value); - buf[ptr++] = Utils::hton(_qualifiers[i].maxDelta); - } - - try { - _signatureLength = with.sign(buf,ptr * sizeof(uint64_t),_signature,sizeof(_signature)); - _signedBy = with.address(); - return true; - } catch ( ... ) { - _signedBy.zero(); - return false; - } -} - -int CertificateOfMembership::verify(const RuntimeEnvironment *RR,void *tPtr) const -{ - if ((!_signedBy)||(_signedBy != Network::controllerFor(networkId()))||(_qualifierCount > ZT_NETWORK_COM_MAX_QUALIFIERS)) - return -1; - - const Identity id(RR->topology->getIdentity(tPtr,_signedBy)); - if (!id) { - RR->sw->requestWhois(tPtr,RR->node->now(),_signedBy); - return 1; - } - - uint64_t buf[ZT_NETWORK_COM_MAX_QUALIFIERS * 3]; - unsigned int ptr = 0; - for(unsigned int i=0;i<_qualifierCount;++i) { - buf[ptr++] = Utils::hton(_qualifiers[i].id); - buf[ptr++] = Utils::hton(_qualifiers[i].value); - buf[ptr++] = Utils::hton(_qualifiers[i].maxDelta); - } - 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 72dadd2cf..dcb2a0537 100644 --- a/node/CertificateOfMembership.hpp +++ b/node/CertificateOfMembership.hpp @@ -79,6 +79,8 @@ class RuntimeEnvironment; */ class CertificateOfMembership : public Credential { + friend class Credential; + public: static inline Credential::Type credentialType() { return Credential::CREDENTIAL_TYPE_COM; } @@ -168,7 +170,7 @@ public: { for(unsigned int i=0;i<_qualifierCount;++i) { if (_qualifiers[i].id == COM_RESERVED_ID_TIMESTAMP) - return _qualifiers[i].value; + return (int64_t)_qualifiers[i].value; } return 0; } @@ -206,27 +208,27 @@ public: * @param value Qualifier value * @param maxDelta Qualifier maximum allowed difference (absolute value of difference) */ - void setQualifier(uint64_t id,uint64_t value,uint64_t maxDelta); + inline void setQualifier(uint64_t id,uint64_t value,uint64_t maxDelta) + { + _signedBy.zero(); + for(unsigned int i=0;i<_qualifierCount;++i) { + if (_qualifiers[i].id == id) { + _qualifiers[i].value = value; + _qualifiers[i].maxDelta = maxDelta; + return; + } + } + if (_qualifierCount < ZT_NETWORK_COM_MAX_QUALIFIERS) { + _qualifiers[_qualifierCount].id = id; + _qualifiers[_qualifierCount].value = value; + _qualifiers[_qualifierCount].maxDelta = maxDelta; + ++_qualifierCount; + std::sort(&(_qualifiers[0]),&(_qualifiers[_qualifierCount])); + } + } + inline void setQualifier(ReservedId id,uint64_t value,uint64_t maxDelta) { setQualifier((uint64_t)id,value,maxDelta); } -#ifdef ZT_SUPPORT_OLD_STYLE_NETCONF - /** - * @return String-serialized representation of this certificate - */ - std::string toString() const; - - /** - * Set this certificate equal to the hex-serialized string - * - * Invalid strings will result in invalid or undefined certificate - * contents. These will subsequently fail validation and comparison. - * Empty strings will result in an empty certificate. - * - * @param s String to deserialize - */ - void fromString(const char *s); -#endif // ZT_SUPPORT_OLD_STYLE_NETCONF - /** * Compare two certificates for parameter agreement * @@ -240,7 +242,41 @@ public: * @param other Cert to compare with * @return True if certs agree and 'other' may be communicated with */ - bool agreesWith(const CertificateOfMembership &other) const; + inline bool agreesWith(const CertificateOfMembership &other) const + { + unsigned int myidx = 0; + unsigned int otheridx = 0; + + if ((_qualifierCount == 0)||(other._qualifierCount == 0)) + return false; + + while (myidx < _qualifierCount) { + // Fail if we're at the end of other, since this means the field is + // missing. + if (otheridx >= other._qualifierCount) + return false; + + // Seek to corresponding tuple in other, ignoring tuples that + // we may not have. If we run off the end of other, the tuple is + // missing. This works because tuples are sorted by ID. + while (other._qualifiers[otheridx].id != _qualifiers[myidx].id) { + ++otheridx; + if (otheridx >= other._qualifierCount) + return false; + } + + // Compare to determine if the absolute value of the difference + // between these two parameters is within our maxDelta. + const uint64_t a = _qualifiers[myidx].value; + const uint64_t b = other._qualifiers[myidx].value; + if (((a >= b) ? (a - b) : (b - a)) > _qualifiers[myidx].maxDelta) + return false; + + ++myidx; + } + + return true; + } /** * Sign this certificate @@ -248,16 +284,33 @@ public: * @param with Identity to sign with, must include private key * @return True if signature was successful */ - bool sign(const Identity &with); + inline bool sign(const Identity &with) + { + uint64_t buf[ZT_NETWORK_COM_MAX_QUALIFIERS * 3]; + unsigned int ptr = 0; + for(unsigned int i=0;i<_qualifierCount;++i) { + buf[ptr++] = Utils::hton(_qualifiers[i].id); + buf[ptr++] = Utils::hton(_qualifiers[i].value); + buf[ptr++] = Utils::hton(_qualifiers[i].maxDelta); + } + + try { + _signatureLength = with.sign(buf,ptr * sizeof(uint64_t),_signature,sizeof(_signature)); + _signedBy = with.address(); + return true; + } catch ( ... ) { + _signedBy.zero(); + return false; + } + } /** * Verify this COM and its signature * * @param RR Runtime environment for looking up peers * @param tPtr Thread pointer to be handed through to any callbacks called as a result of this call - * @return 0 == OK, 1 == waiting for WHOIS, -1 == BAD signature or credential */ - int verify(const RuntimeEnvironment *RR,void *tPtr) const; + inline Credential::VerifyResult verify(const RuntimeEnvironment *RR,void *tPtr) const { return _verify(RR,tPtr,*this); } /** * @return True if signed diff --git a/node/CertificateOfOwnership.cpp b/node/CertificateOfOwnership.cpp deleted file mode 100644 index 5a17026ce..000000000 --- a/node/CertificateOfOwnership.cpp +++ /dev/null @@ -1,98 +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. - */ - -#include "CertificateOfOwnership.hpp" -#include "RuntimeEnvironment.hpp" -#include "Identity.hpp" -#include "Topology.hpp" -#include "Switch.hpp" -#include "Network.hpp" -#include "Node.hpp" - -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))) - return -1; - const Identity id(RR->topology->getIdentity(tPtr,_signedBy)); - if (!id) { - RR->sw->requestWhois(tPtr,RR->node->now(),_signedBy); - return 1; - } - try { - Buffer<(sizeof(CertificateOfOwnership) + 64)> tmp; - this->serialize(tmp,true); - return (id.verify(tmp.data(),tmp.size(),_signature,_signatureLength) ? 0 : -1); - } catch ( ... ) { - return -1; - } -} - -bool CertificateOfOwnership::_owns(const CertificateOfOwnership::Thing &t,const void *v,unsigned int l) const -{ - for(unsigned int i=0,j=_thingCount;i(v)[k] != _thingValues[i][k]) - break; - ++k; - } - if (k == l) - return true; - } - } - return false; -} - -} // namespace ZeroTier diff --git a/node/CertificateOfOwnership.hpp b/node/CertificateOfOwnership.hpp index 3463d861b..6c7802f24 100644 --- a/node/CertificateOfOwnership.hpp +++ b/node/CertificateOfOwnership.hpp @@ -56,6 +56,8 @@ class RuntimeEnvironment; */ class CertificateOfOwnership : public Credential { + friend class Credential; + public: static inline Credential::Type credentialType() { return Credential::CREDENTIAL_TYPE_COO; } @@ -85,6 +87,9 @@ public: inline int64_t timestamp() const { return _ts; } inline uint32_t id() const { return _id; } inline unsigned int thingCount() const { return (unsigned int)_thingCount; } + inline const Address &signer() const { return _signedBy; } + inline const uint8_t *signature() const { return _signature; } + inline unsigned int signatureLength() const { return _signatureLength; } inline Thing thingType(const unsigned int i) const { return (Thing)_thingTypes[i]; } inline const uint8_t *thingValue(const unsigned int i) const { return _thingValues[i]; } @@ -107,8 +112,20 @@ public: return this->_owns(THING_MAC_ADDRESS,tmp,6); } - void addThing(const InetAddress &ip); - + 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; + } + } + inline void addThing(const MAC &mac) { if (_thingCount >= ZT_CERTIFICATEOFOWNERSHIP_MAX_THINGS) return; @@ -121,14 +138,19 @@ public: * @param signer Signing identity, must have private key * @return True if signature was successful */ - bool sign(const Identity &signer); + 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; + } - /** - * @param RR Runtime environment to allow identity lookup for signedBy - * @param tPtr Thread pointer to be handed through to any callbacks called as a result of this call - * @return 0 == OK, 1 == waiting for WHOIS, -1 == BAD signature - */ - int verify(const RuntimeEnvironment *RR,void *tPtr) const; + 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 @@ -204,8 +226,23 @@ public: inline bool operator!=(const CertificateOfOwnership &coo) const { return (memcmp(this,&coo,sizeof(CertificateOfOwnership)) != 0); } private: - bool _owns(const Thing &t,const void *v,unsigned int l) const; - + inline bool _owns(const Thing &t,const void *v,unsigned int l) const + { + for(unsigned int i=0,j=_thingCount;i(v)[k] != _thingValues[i][k]) + break; + ++k; + } + if (k == l) + return true; + } + } + return false; + } + uint64_t _networkId; int64_t _ts; uint64_t _flags; diff --git a/node/Credential.cpp b/node/Credential.cpp new file mode 100644 index 000000000..4df96bf87 --- /dev/null +++ b/node/Credential.cpp @@ -0,0 +1,88 @@ +/* + * 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. + */ + +#include "Constants.hpp" +#include "RuntimeEnvironment.hpp" +#include "Credential.hpp" +#include "Capability.hpp" +#include "Tag.hpp" +#include "CertificateOfMembership.hpp" +#include "CertificateOfOwnership.hpp" +#include "Revocation.hpp" +#include "Switch.hpp" +#include "Network.hpp" + +namespace ZeroTier { + +template +static inline Credential::VerifyResult _credVerify(const RuntimeEnvironment *const RR,void *tPtr,CRED credential) +{ + const Address signedBy(credential.signer()); + const uint64_t networkId = credential.networkId(); + if ((!signedBy)||(signedBy != Network::controllerFor(networkId))) + return Credential::VERIFY_BAD_SIGNATURE; + const Identity id(RR->topology->getIdentity(tPtr,signedBy)); + if (!id) { + RR->sw->requestWhois(tPtr,RR->node->now(),signedBy); + return Credential::VERIFY_NEED_IDENTITY; + } + try { + Buffer<(sizeof(CRED) + 64)> *const tmp = new Buffer<(sizeof(CRED) + 64)>(); + credential.serialize(*tmp,true); + const Credential::VerifyResult result = (id.verify(tmp->data(),tmp->size(),credential.signature(),credential.signatureLength()) ? Credential::VERIFY_OK : Credential::VERIFY_BAD_SIGNATURE); + delete tmp; + return result; + } catch ( ... ) {} + return Credential::VERIFY_BAD_SIGNATURE; +} + +Credential::VerifyResult Credential::_verify(const RuntimeEnvironment *const RR,void *tPtr,const Revocation &credential) const { return _credVerify(RR,tPtr,credential); } +Credential::VerifyResult Credential::_verify(const RuntimeEnvironment *const RR,void *tPtr,const Tag &credential) const { return _credVerify(RR,tPtr,credential); } +Credential::VerifyResult Credential::_verify(const RuntimeEnvironment *const RR,void *tPtr,const CertificateOfOwnership &credential) const { return _credVerify(RR,tPtr,credential); } + +Credential::VerifyResult Credential::_verify(const RuntimeEnvironment *const RR,void *tPtr,const CertificateOfMembership &credential) const +{ + if ((!credential._signedBy)||(credential._signedBy != Network::controllerFor(credential.networkId()))||(credential._qualifierCount > ZT_NETWORK_COM_MAX_QUALIFIERS)) + return Credential::VERIFY_BAD_SIGNATURE; + + const Identity id(RR->topology->getIdentity(tPtr,credential._signedBy)); + if (!id) { + RR->sw->requestWhois(tPtr,RR->node->now(),credential._signedBy); + return Credential::VERIFY_NEED_IDENTITY; + } + + uint64_t buf[ZT_NETWORK_COM_MAX_QUALIFIERS * 3]; + unsigned int ptr = 0; + for(unsigned int i=0;it->credentialRejected(tPtr,com,"invalid"); - return ADD_REJECTED; - case 0: + case Credential::VERIFY_OK: _com = com; return ADD_ACCEPTED_NEW; - case 1: + case Credential::VERIFY_BAD_SIGNATURE: + RR->t->credentialRejected(tPtr,com,"invalid"); + return ADD_REJECTED; + case Credential::VERIFY_NEED_IDENTITY: return ADD_DEFERRED_FOR_WHOIS; } } diff --git a/node/Revocation.cpp b/node/Revocation.cpp deleted file mode 100644 index 75b71e9c5..000000000 --- a/node/Revocation.cpp +++ /dev/null @@ -1,67 +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. - */ - -#include "Revocation.hpp" -#include "RuntimeEnvironment.hpp" -#include "Identity.hpp" -#include "Topology.hpp" -#include "Switch.hpp" -#include "Network.hpp" -#include "Node.hpp" - -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))) - return -1; - const Identity id(RR->topology->getIdentity(tPtr,_signedBy)); - if (!id) { - RR->sw->requestWhois(tPtr,RR->node->now(),_signedBy); - return 1; - } - try { - Buffer tmp; - this->serialize(tmp,true); - return (id.verify(tmp.data(),tmp.size(),_signature,_signatureLength) ? 0 : -1); - } catch ( ... ) { - return -1; - } -} - -} // namespace ZeroTier diff --git a/node/Revocation.hpp b/node/Revocation.hpp index 5c126e9b3..e3540f645 100644 --- a/node/Revocation.hpp +++ b/node/Revocation.hpp @@ -55,6 +55,8 @@ class RuntimeEnvironment; */ class Revocation : public Credential { + friend class Credential; + public: static inline Credential::Type credentialType() { return Credential::CREDENTIAL_TYPE_REVOCATION; } @@ -100,6 +102,8 @@ public: inline const Address &target() const { return _target; } inline const Address &signer() const { return _signedBy; } inline Credential::Type type() const { return _type; } + inline const uint8_t *signature() const { return _signature; } + inline unsigned int signatureLength() const { return _signatureLength; } inline bool fastPropagate() const { return ((_flags & ZT_REVOCATION_FLAG_FAST_PROPAGATE) != 0); } @@ -107,16 +111,25 @@ public: * @param signer Signing identity, must have private key * @return True if signature was successful */ - bool sign(const Identity &signer); + 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; + } /** * Verify this revocation's signature * * @param RR Runtime environment to provide for peer lookup, etc. * @param tPtr Thread pointer to be handed through to any callbacks called as a result of this call - * @return 0 == OK, 1 == waiting for WHOIS, -1 == BAD signature or chain */ - int verify(const RuntimeEnvironment *RR,void *tPtr) const; + 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 diff --git a/node/Tag.cpp b/node/Tag.cpp deleted file mode 100644 index 3ae29319e..000000000 --- a/node/Tag.cpp +++ /dev/null @@ -1,67 +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. - */ - -#include "Tag.hpp" -#include "RuntimeEnvironment.hpp" -#include "Identity.hpp" -#include "Topology.hpp" -#include "Switch.hpp" -#include "Network.hpp" -#include "Node.hpp" - -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))) - return -1; - const Identity id(RR->topology->getIdentity(tPtr,_signedBy)); - if (!id) { - RR->sw->requestWhois(tPtr,RR->node->now(),_signedBy); - return 1; - } - try { - Buffer<(sizeof(Tag) * 2)> tmp; - this->serialize(tmp,true); - return (id.verify(tmp.data(),tmp.size(),_signature,_signatureLength) ? 0 : -1); - } catch ( ... ) { - return -1; - } -} - -} // namespace ZeroTier diff --git a/node/Tag.hpp b/node/Tag.hpp index dcb548eb1..fccbae575 100644 --- a/node/Tag.hpp +++ b/node/Tag.hpp @@ -62,6 +62,8 @@ class RuntimeEnvironment; */ class Tag : public Credential { + friend class Credential; + public: static inline Credential::Type credentialType() { return Credential::CREDENTIAL_TYPE_TAG; } @@ -97,7 +99,9 @@ public: inline uint64_t networkId() const { return _networkId; } inline int64_t timestamp() const { return _ts; } inline const Address &issuedTo() const { return _issuedTo; } - inline const Address &signedBy() const { return _signedBy; } + inline const Address &signer() const { return _signedBy; } + inline const uint8_t *signature() const { return _signature; } + inline unsigned int signatureLength() const { return _signatureLength; } /** * Sign this tag @@ -105,16 +109,25 @@ public: * @param signer Signing identity, must have private key * @return True if signature was successful */ - bool sign(const Identity &signer); - + 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; + } + /** * Check this tag's signature * * @param RR Runtime environment to allow identity lookup for signedBy * @param tPtr Thread pointer to be handed through to any callbacks called as a result of this call - * @return 0 == OK, 1 == waiting for WHOIS, -1 == BAD signature or tag */ - int verify(const RuntimeEnvironment *RR,void *tPtr) const; + 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 diff --git a/objects.mk b/objects.mk index 0796a0b07..fe6aefe65 100644 --- a/objects.mk +++ b/objects.mk @@ -2,8 +2,7 @@ CORE_OBJS=\ node/AES.o \ node/C25519.o \ node/Capability.o \ - node/CertificateOfMembership.o \ - node/CertificateOfOwnership.o \ + node/Credential.o \ node/ECC384.o \ node/Identity.o \ node/IncomingPacket.o \ @@ -18,12 +17,10 @@ CORE_OBJS=\ node/Path.o \ node/Peer.o \ node/Poly1305.o \ - node/Revocation.o \ node/Salsa20.o \ node/SelfAwareness.o \ node/SHA512.o \ node/Switch.o \ - node/Tag.o \ node/Trace.o \ node/Utils.o