summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAdam Ierymenko <adam.ierymenko@gmail.com>2017-02-04 13:17:00 -0800
committerAdam Ierymenko <adam.ierymenko@gmail.com>2017-02-04 13:17:00 -0800
commit3587aa1ea7573198168422be55511b16470fb33f (patch)
tree645853d1cd6cd9d98218d28455efa981d5f6ccf5
parentbeb642faa58bb3c2c283a068e6de942bfad2c314 (diff)
downloadinfinitytier-3587aa1ea7573198168422be55511b16470fb33f.tar.gz
infinitytier-3587aa1ea7573198168422be55511b16470fb33f.zip
Add and send certificates of representation to tell people what our valid upstreams are. These are not used yet but will be needed for future privacy modes, etc. Also some cleanup.
-rw-r--r--node/Capability.hpp9
-rw-r--r--node/CertificateOfRepresentation.hpp161
-rw-r--r--node/Constants.hpp5
-rw-r--r--node/IncomingPacket.cpp9
-rw-r--r--node/Packet.hpp32
-rw-r--r--node/Peer.cpp7
-rw-r--r--node/Peer.hpp11
-rw-r--r--node/Revocation.hpp2
-rw-r--r--node/Tag.hpp14
-rw-r--r--node/Topology.cpp11
-rw-r--r--node/Topology.hpp21
11 files changed, 247 insertions, 35 deletions
diff --git a/node/Capability.hpp b/node/Capability.hpp
index 2c829ee5..ddbfd9ee 100644
--- a/node/Capability.hpp
+++ b/node/Capability.hpp
@@ -414,7 +414,14 @@ public:
throw std::runtime_error("unterminated custody chain");
_custody[i].to = to;
_custody[i].from.setTo(b.field(p,ZT_ADDRESS_LENGTH),ZT_ADDRESS_LENGTH); p += ZT_ADDRESS_LENGTH;
- memcpy(_custody[i].signature.data,b.field(p,ZT_C25519_SIGNATURE_LEN),ZT_C25519_SIGNATURE_LEN); p += ZT_C25519_SIGNATURE_LEN;
+ if (b[p++] == 1) {
+ if (b.template at<uint16_t>(p) != ZT_C25519_SIGNATURE_LEN)
+ throw std::runtime_error("invalid signature");
+ p += 2;
+ memcpy(_custody[i].signature.data,b.field(p,ZT_C25519_SIGNATURE_LEN),ZT_C25519_SIGNATURE_LEN); p += ZT_C25519_SIGNATURE_LEN;
+ } else {
+ p += 2 + b.template at<uint16_t>(p);
+ }
}
p += 2 + b.template at<uint16_t>(p);
diff --git a/node/CertificateOfRepresentation.hpp b/node/CertificateOfRepresentation.hpp
new file mode 100644
index 00000000..7c239a96
--- /dev/null
+++ b/node/CertificateOfRepresentation.hpp
@@ -0,0 +1,161 @@
+/*
+ * ZeroTier One - Network Virtualization Everywhere
+ * Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef ZT_CERTIFICATEOFREPRESENTATION_HPP
+#define ZT_CERTIFICATEOFREPRESENTATION_HPP
+
+#include "Constants.hpp"
+#include "Address.hpp"
+#include "C25519.hpp"
+#include "Identity.hpp"
+#include "Buffer.hpp"
+
+/**
+ * Maximum number of addresses allowed in a COR
+ */
+#define ZT_CERTIFICATEOFREPRESENTATION_MAX_ADDRESSES ZT_MAX_UPSTREAMS
+
+namespace ZeroTier {
+
+class CertificateOfRepresentation
+{
+public:
+ CertificateOfRepresentation()
+ {
+ memset(this,0,sizeof(CertificateOfRepresentation));
+ }
+
+ inline uint64_t timestamp() const { return _timestamp; }
+ inline const Address &representative(const unsigned int i) const { return _reps[i]; }
+ inline unsigned int repCount() const { return _repCount; }
+
+ inline void clear()
+ {
+ memset(this,0,sizeof(CertificateOfRepresentation));
+ }
+
+ /**
+ * Add a representative if space remains
+ *
+ * @param r Representative to add
+ * @return True if representative was added
+ */
+ inline bool addRepresentative(const Address &r)
+ {
+ if (_repCount < ZT_CERTIFICATEOFREPRESENTATION_MAX_ADDRESSES) {
+ _reps[_repCount++] = r;
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * Sign this COR with my identity
+ *
+ * @param myIdentity This node's identity
+ * @param ts COR timestamp for establishing new vs. old
+ */
+ inline void sign(const Identity &myIdentity,const uint64_t ts)
+ {
+ _timestamp = ts;
+ Buffer<sizeof(CertificateOfRepresentation) + 32> tmp;
+ this->serialize(tmp,true);
+ _signature = myIdentity.sign(tmp.data(),tmp.size());
+ }
+
+ /**
+ * Verify this COR's signature
+ *
+ * @param senderIdentity Identity of sender of COR
+ * @return True if COR is valid
+ */
+ inline bool verify(const Identity &senderIdentity)
+ {
+ try {
+ Buffer<sizeof(CertificateOfRepresentation) + 32> tmp;
+ this->serialize(tmp,true);
+ return senderIdentity.verify(tmp.data(),tmp.size(),_signature.data,ZT_C25519_SIGNATURE_LEN);
+ } catch ( ... ) {
+ return false;
+ }
+ }
+
+ template<unsigned int C>
+ inline void serialize(Buffer<C> &b,const bool forSign = false) const
+ {
+ if (forSign) b.append((uint64_t)0x7f7f7f7f7f7f7f7fULL);
+
+ b.append((uint64_t)_timestamp);
+ b.append((uint16_t)_repCount);
+ for(unsigned int i=0;i<_repCount;++i)
+ _reps[i].appendTo(b);
+
+ 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((uint16_t)0); // size of any additional fields, currently 0
+
+ if (forSign) b.append((uint64_t)0x7f7f7f7f7f7f7f7fULL);
+ }
+
+ template<unsigned int C>
+ inline unsigned int deserialize(const Buffer<C> &b,unsigned int startAt = 0)
+ {
+ clear();
+
+ unsigned int p = startAt;
+
+ _timestamp = b.template at<uint64_t>(p); p += 8;
+ const unsigned int rc = b.template at<uint16_t>(p); p += 2;
+ for(unsigned int i=0;i<rc;++i) {
+ if (i < ZT_CERTIFICATEOFREPRESENTATION_MAX_ADDRESSES)
+ _reps[i].setTo(b.field(p,ZT_ADDRESS_LENGTH),ZT_ADDRESS_LENGTH);
+ p += ZT_ADDRESS_LENGTH;
+ }
+ _repCount = (rc > ZT_CERTIFICATEOFREPRESENTATION_MAX_ADDRESSES) ? ZT_CERTIFICATEOFREPRESENTATION_MAX_ADDRESSES : rc;
+
+ if (b[p++] == 1) {
+ if (b.template at<uint16_t>(p) == ZT_C25519_SIGNATURE_LEN) {
+ p += 2;
+ memcpy(_signature.data,b.field(p,ZT_C25519_SIGNATURE_LEN),ZT_C25519_SIGNATURE_LEN);
+ p += ZT_C25519_SIGNATURE_LEN;
+ } else throw std::runtime_error("invalid signature");
+ } else {
+ p += 2 + b.template at<uint16_t>(p);
+ }
+
+ p += 2 + b.template at<uint16_t>(p);
+ if (p > b.size())
+ throw std::runtime_error("extended field overflow");
+
+ return (p - startAt);
+ }
+
+private:
+ uint64_t _timestamp;
+ Address _reps[ZT_CERTIFICATEOFREPRESENTATION_MAX_ADDRESSES];
+ unsigned int _repCount;
+ C25519::Signature _signature;
+};
+
+} // namespace ZeroTier
+
+#endif
diff --git a/node/Constants.hpp b/node/Constants.hpp
index ab6dfb32..be4eb475 100644
--- a/node/Constants.hpp
+++ b/node/Constants.hpp
@@ -227,6 +227,11 @@
#define ZT_RELAY_MAX_HOPS 3
/**
+ * Maximum number of upstreams to use (far more than we should ever need)
+ */
+#define ZT_MAX_UPSTREAMS 64
+
+/**
* Expire time for multicast 'likes' and indirect multicast memberships in ms
*/
#define ZT_MULTICAST_LIKE_EXPIRE 600000
diff --git a/node/IncomingPacket.cpp b/node/IncomingPacket.cpp
index cecbe2fa..6b38c4ec 100644
--- a/node/IncomingPacket.cpp
+++ b/node/IncomingPacket.cpp
@@ -37,6 +37,7 @@
#include "Cluster.hpp"
#include "Node.hpp"
#include "CertificateOfMembership.hpp"
+#include "CertificateOfRepresentation.hpp"
#include "Capability.hpp"
#include "Tag.hpp"
#include "Revocation.hpp"
@@ -445,6 +446,14 @@ bool IncomingPacket::_doOK(const RuntimeEnvironment *RR,const SharedPtr<Peer> &p
}
}
+ // Handle COR if present (older versions don't send this)
+ if ((ptr + 2) <= size()) {
+ //const unsigned int corSize = at<uint16_t>(ptr); ptr += 2;
+ ptr += 2;
+ CertificateOfRepresentation cor;
+ ptr += cor.deserialize(*this,ptr);
+ }
+
TRACE("%s(%s): OK(HELLO), version %u.%u.%u, latency %u, reported external address %s",source().toString().c_str(),_path->address().toString().c_str(),vMajor,vMinor,vRevision,latency,((externalSurfaceAddress) ? externalSurfaceAddress.toString().c_str() : "(none)"));
if (!hops())
diff --git a/node/Packet.hpp b/node/Packet.hpp
index a5831c8d..7d404b25 100644
--- a/node/Packet.hpp
+++ b/node/Packet.hpp
@@ -531,7 +531,7 @@ public:
VERB_NOP = 0x00,
/**
- * Announcement of a node's existence:
+ * Announcement of a node's existence and vitals:
* <[1] protocol version>
* <[1] software major version>
* <[1] software minor version>
@@ -547,10 +547,12 @@ public:
* [<[8] 64-bit world ID of moon>]
* [<[8] 64-bit timestamp of moon>]
* [... additional moons ...]
+ * <[2] 16-bit length of certificate of representation>
+ * [... certificate of representation ...]
*
- * Important security note: this message is sent in the clear as it
- * contains the initial identity for key agreement. It can therefore
- * contain no secrets or sensitive information.
+ * HELLO is sent in the clear, and therefore cannot contain anything
+ * secret or highly confidential. It should contain nothing that is
+ * not either public or easy to obtain via other means.
*
* The destination address is the wire address to which this packet is
* being sent, and in OK is *also* the destination address of the OK
@@ -1059,27 +1061,7 @@ public:
* ZeroTier, Inc. itself. We recommend making up random ones for your own
* implementations.
*/
- VERB_USER_MESSAGE = 0x14,
-
- /**
- * Announce that we can reach a particular address:
- * <[1] protocol version>
- * <[1] software major version>
- * <[1] software minor version>
- * <[2] software revision>
- * <[...] binary serialized identity (see Identity)>
- * <[1] 8-bit number of direct addresses where peer is reachable (if any)>
- * [... serialized direct addresses ...]
- *
- * This message can be sent upstream to announce that we can reach a
- * particular address. It can optionally report physical paths upstream
- * to allow upstream peers to send RENDEZVOUS, but this may be omitted
- * if it is not known or if endpoint address privacy is desired.
- *
- * The receiving peer should confirm this message by sending a message
- * downstream and waiting for a reply.
- */
- VERB_CAN_REACH = 0x15
+ VERB_USER_MESSAGE = 0x14
};
/**
diff --git a/node/Peer.cpp b/node/Peer.cpp
index 129c2437..bb6b945d 100644
--- a/node/Peer.cpp
+++ b/node/Peer.cpp
@@ -38,6 +38,7 @@
namespace ZeroTier {
Peer::Peer(const RuntimeEnvironment *renv,const Identity &myIdentity,const Identity &peerIdentity) :
+ RR(renv),
_lastReceive(0),
_lastNontrivialReceive(0),
_lastTriedMemorizedPath(0),
@@ -50,7 +51,6 @@ Peer::Peer(const RuntimeEnvironment *renv,const Identity &myIdentity,const Ident
_lastComRequestSent(0),
_lastCredentialsReceived(0),
_lastTrustEstablishedPacketReceived(0),
- RR(renv),
_remoteClusterOptimal4(0),
_vProto(0),
_vMajor(0),
@@ -365,6 +365,11 @@ void Peer::sendHELLO(const InetAddress &localAddr,const InetAddress &atAddress,u
outp.append((uint64_t)m->timestamp());
}
+ const unsigned int corSizeAt = outp.size();
+ outp.addSize(2);
+ RR->topology->appendCertificateOfRepresentation(outp);
+ outp.setAt(corSizeAt,(uint16_t)((outp.size() - corSizeAt) - 2));
+
RR->node->expectReplyTo(outp.packetId());
if (atAddress) {
diff --git a/node/Peer.hpp b/node/Peer.hpp
index bbe13a2e..e79739a3 100644
--- a/node/Peer.hpp
+++ b/node/Peer.hpp
@@ -439,7 +439,9 @@ private:
}
uint8_t _key[ZT_PEER_SECRET_KEY_LENGTH];
- uint8_t _remoteClusterOptimal6[16];
+
+ const RuntimeEnvironment *RR;
+
uint64_t _lastReceive; // direct or indirect
uint64_t _lastNontrivialReceive; // frames, things like netconf, etc.
uint64_t _lastTriedMemorizedPath;
@@ -452,13 +454,17 @@ private:
uint64_t _lastComRequestSent;
uint64_t _lastCredentialsReceived;
uint64_t _lastTrustEstablishedPacketReceived;
- const RuntimeEnvironment *RR;
+
+ uint8_t _remoteClusterOptimal6[16];
uint32_t _remoteClusterOptimal4;
+
uint16_t _vProto;
uint16_t _vMajor;
uint16_t _vMinor;
uint16_t _vRevision;
+
Identity _id;
+
struct {
uint64_t lastReceive;
SharedPtr<Path> path;
@@ -467,6 +473,7 @@ private:
#endif
} _paths[ZT_MAX_PEER_NETWORK_PATHS];
Mutex _paths_m;
+
unsigned int _numPaths;
unsigned int _latency;
unsigned int _directPathPushCutoffCount;
diff --git a/node/Revocation.hpp b/node/Revocation.hpp
index 18916985..bc290e75 100644
--- a/node/Revocation.hpp
+++ b/node/Revocation.hpp
@@ -152,6 +152,8 @@ public:
memcpy(_signature.data,b.field(p,ZT_C25519_SIGNATURE_LEN),ZT_C25519_SIGNATURE_LEN);
p += ZT_C25519_SIGNATURE_LEN;
} else throw std::runtime_error("invalid signature");
+ } else {
+ p += 2 + b.template at<uint16_t>(p);
}
p += 2 + b.template at<uint16_t>(p);
diff --git a/node/Tag.hpp b/node/Tag.hpp
index 97228157..65348200 100644
--- a/node/Tag.hpp
+++ b/node/Tag.hpp
@@ -148,12 +148,14 @@ 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)
- throw std::runtime_error("unrecognized signature type");
- if (b.template at<uint16_t>(p) != ZT_C25519_SIGNATURE_LEN)
- throw std::runtime_error("invalid signature length");
- p += 2;
- memcpy(_signature.data,b.field(p,ZT_C25519_SIGNATURE_LEN),ZT_C25519_SIGNATURE_LEN); p += ZT_C25519_SIGNATURE_LEN;
+ if (b[p++] == 1) {
+ if (b.template at<uint16_t>(p) != ZT_C25519_SIGNATURE_LEN)
+ throw std::runtime_error("invalid signature length");
+ p += 2;
+ memcpy(_signature.data,b.field(p,ZT_C25519_SIGNATURE_LEN),ZT_C25519_SIGNATURE_LEN); p += ZT_C25519_SIGNATURE_LEN;
+ } else {
+ p += 2 + b.template at<uint16_t>(p);
+ }
p += 2 + b.template at<uint16_t>(p);
if (p > b.size())
diff --git a/node/Topology.cpp b/node/Topology.cpp
index 0cd3db9e..f19d8656 100644
--- a/node/Topology.cpp
+++ b/node/Topology.cpp
@@ -417,6 +417,7 @@ void Topology::_memoizeUpstreams()
// assumes _upstreams_m and _peers_m are locked
_upstreamAddresses.clear();
_amRoot = false;
+
for(std::vector<World::Root>::const_iterator i(_planet.roots().begin());i!=_planet.roots().end();++i) {
if (i->identity == RR->identity) {
_amRoot = true;
@@ -429,6 +430,7 @@ void Topology::_memoizeUpstreams()
}
}
}
+
for(std::vector<World>::const_iterator m(_moons.begin());m!=_moons.end();++m) {
for(std::vector<World::Root>::const_iterator i(m->roots().begin());i!=m->roots().end();++i) {
if (i->identity == RR->identity) {
@@ -443,6 +445,15 @@ void Topology::_memoizeUpstreams()
}
}
}
+
+ std::sort(_upstreamAddresses.begin(),_upstreamAddresses.end());
+
+ _cor.clear();
+ for(std::vector<Address>::const_iterator a(_upstreamAddresses.begin());a!=_upstreamAddresses.end();++a) {
+ if (!_cor.addRepresentative(*a))
+ break;
+ }
+ _cor.sign(RR->identity,RR->node->now());
}
} // namespace ZeroTier
diff --git a/node/Topology.hpp b/node/Topology.hpp
index 78dc0fe8..dca35789 100644
--- a/node/Topology.hpp
+++ b/node/Topology.hpp
@@ -38,6 +38,7 @@
#include "InetAddress.hpp"
#include "Hashtable.hpp"
#include "World.hpp"
+#include "CertificateOfRepresentation.hpp"
namespace ZeroTier {
@@ -383,6 +384,25 @@ public:
_trustedPathCount = count;
}
+ /**
+ * @return Current certificate of representation (copy)
+ */
+ inline CertificateOfRepresentation certificateOfRepresentation() const
+ {
+ Mutex::Lock _l(_upstreams_m);
+ return _cor;
+ }
+
+ /**
+ * @param buf Buffer to receive COR
+ */
+ template<unsigned int C>
+ void appendCertificateOfRepresentation(Buffer<C> &buf)
+ {
+ Mutex::Lock _l(_upstreams_m);
+ _cor.serialize(buf);
+ }
+
private:
Identity _getIdentity(const Address &zta);
void _memoizeUpstreams();
@@ -404,6 +424,7 @@ private:
std::vector<World> _moons;
std::vector<Address> _contactingMoons;
std::vector<Address> _upstreamAddresses;
+ CertificateOfRepresentation _cor;
bool _amRoot;
Mutex _upstreams_m; // locks worlds, upstream info, moon info, etc.
};