Browse Source

Add skeleton of certificate-based private network authentication. Also remove some old code.

Adam Ierymenko 12 years ago
parent
commit
7a17f6ca80
8 changed files with 40 additions and 399 deletions
  1. 0 94
      node/BlobArray.hpp
  2. 14 1
      node/Network.hpp
  3. 0 1
      node/Node.cpp
  4. 0 159
      node/Pack.cpp
  5. 0 141
      node/Pack.hpp
  6. 3 0
      node/Packet.cpp
  7. 23 2
      node/Packet.hpp
  8. 0 1
      objects.mk

+ 0 - 94
node/BlobArray.hpp

@@ -1,94 +0,0 @@
-/*
- * ZeroTier One - Global Peer to Peer Ethernet
- * Copyright (C) 2012-2013  ZeroTier Networks LLC
- *
- * 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/>.
- *
- * --
- *
- * ZeroTier may be used and distributed under the terms of the GPLv3, which
- * are available at: http://www.gnu.org/licenses/gpl-3.0.html
- *
- * If you would like to embed ZeroTier into a commercial application or
- * redistribute it in a modified binary form, please contact ZeroTier Networks
- * LLC. Start here: http://www.zerotier.com/
- */
-
-#ifndef _ZT_BLOBARRAY_HPP
-#define _ZT_BLOBARRAY_HPP
-
-#include <vector>
-#include <string>
-#include <algorithm>
-
-namespace ZeroTier {
-
-/**
- * A vector of binary strings serializable in a packed format
- *
- * The format uses variable-length integers to indicate the length of each
- * field. Each byte of the length has another byte with seven more significant
- * bits if its 8th bit is set. Fields can be up to 2^28 in length.
- */
-class BlobArray : public std::vector<std::string>
-{
-public:
-	inline std::string serialize() const
-	{
-		std::string r;
-		for(BlobArray::const_iterator i=begin();i!=end();++i) {
-			unsigned int flen = (unsigned int)i->length();
-			do {
-				unsigned char flenb = (unsigned char)(flen & 0x7f);
-				flen >>= 7;
-				flenb |= (flen) ? 0x80 : 0;
-				r.push_back((char)flenb);
-			} while (flen);
-			r.append(*i);
-		}
-		return r;
-	}
-
-	/**
-	 * Deserialize, replacing the current contents of this array
-	 *
-	 * @param data Serialized binary data
-	 * @param len Length of serialized data
-	 */
-	inline void deserialize(const void *data,unsigned int len)
-	{
-		clear();
-		for(unsigned int i=0;i<len;) {
-			unsigned int flen = 0;
-			unsigned int chunk = 0;
-			while (i < len) {
-				flen |= ((unsigned int)(((const unsigned char *)data)[i] & 0x7f)) << (7 * chunk++);
-				if (!(((const unsigned char *)data)[i++] & 0x80))
-					break;
-			}
-			flen = std::min(flen,len - i);
-			push_back(std::string(((const char *)data) + i,flen));
-			i += flen;
-		}
-	}
-	inline void deserialize(const std::string &data)
-	{
-		deserialize(data.data(),(unsigned int)data.length());
-	}
-};
-
-} // namespace ZeroTier
-
-#endif
-

+ 14 - 1
node/Network.hpp

@@ -49,7 +49,20 @@ namespace ZeroTier {
 class NodeConfig;
 
 /**
- * Local membership to a network
+ * A virtual LAN
+ *
+ * Networks can be open or closed.
+ *
+ * Open networks do not track membership. Anyone is allowed to communicate
+ * over them.
+ *
+ * Closed networks track membership by way of timestamped signatures. When
+ * the network requests its configuration, one of the fields returned is
+ * a signature for the identity of the peer on the network. This signature
+ * includes a timestamp. When a peer communicates with other peers on a
+ * closed network, it periodically (and pre-emptively) propagates this
+ * signature to the peers with which it is communicating. Peers reject
+ * packets with an error if no recent signature is on file.
  */
 class Network : NonCopyable
 {

+ 0 - 1
node/Node.cpp

@@ -56,7 +56,6 @@
 #include "Logger.hpp"
 #include "Constants.hpp"
 #include "InetAddress.hpp"
-#include "Pack.hpp"
 #include "Salsa20.hpp"
 #include "HMAC.hpp"
 #include "RuntimeEnvironment.hpp"

+ 0 - 159
node/Pack.cpp

@@ -1,159 +0,0 @@
-/*
- * ZeroTier One - Global Peer to Peer Ethernet
- * Copyright (C) 2012-2013  ZeroTier Networks LLC
- *
- * 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/>.
- *
- * --
- *
- * ZeroTier may be used and distributed under the terms of the GPLv3, which
- * are available at: http://www.gnu.org/licenses/gpl-3.0.html
- *
- * If you would like to embed ZeroTier into a commercial application or
- * redistribute it in a modified binary form, please contact ZeroTier Networks
- * LLC. Start here: http://www.zerotier.com/
- */
-
-#include <iostream>
-#include <string.h>
-#include <stdlib.h>
-#include "Pack.hpp"
-#include "BlobArray.hpp"
-#include "Utils.hpp"
-
-#include <openssl/sha.h>
-
-namespace ZeroTier {
-
-std::vector<const Pack::Entry *> Pack::getAll() const
-{
-	std::vector<const Entry *> v;
-	for(std::map<std::string,Entry>::const_iterator e=_entries.begin();e!=_entries.end();++e)
-		v.push_back(&(e->second));
-	return v;
-}
-
-const Pack::Entry *Pack::get(const std::string &name) const
-{
-	std::map<std::string,Entry>::const_iterator e(_entries.find(name));
-	return ((e == _entries.end()) ? (const Entry *)0 : &(e->second));
-}
-
-const Pack::Entry *Pack::put(const std::string &name,const std::string &content)
-{
-	SHA256_CTX sha;
-
-	Pack::Entry &e = _entries[name];
-	e.name = name;
-	e.content = content;
-
-	SHA256_Init(&sha);
-	SHA256_Update(&sha,content.data(),content.length());
-	SHA256_Final(e.sha256,&sha);
-
-	e.signedBy = 0;
-	e.signature.assign((const char *)0,0);
-
-	return &e;
-}
-
-void Pack::clear()
-{
-	_entries.clear();
-}
-
-std::string Pack::serialize() const
-{
-	BlobArray archive;
-	for(std::map<std::string,Entry>::const_iterator e=_entries.begin();e!=_entries.end();++e) {
-		BlobArray entry;
-		entry.push_back(e->second.name);
-		entry.push_back(e->second.content);
-		entry.push_back(std::string((const char *)e->second.sha256,sizeof(e->second.sha256)));
-		entry.push_back(e->second.signedBy.toBinaryString());
-		entry.push_back(e->second.signature);
-		archive.push_back(entry.serialize());
-	}
-
-	std::string ser(archive.serialize());
-	std::string comp;
-	Utils::compress(ser.begin(),ser.end(),Utils::StringAppendOutput(comp));
-	return comp;
-}
-
-bool Pack::deserialize(const void *sd,unsigned int sdlen)
-{
-	unsigned char dig[32];
-	SHA256_CTX sha;
-
-	std::string decomp;
-	if (!Utils::decompress(((const char *)sd),((const char *)sd) + sdlen,Utils::StringAppendOutput(decomp)))
-		return false;
-
-	BlobArray archive;
-	archive.deserialize(decomp.data(),decomp.length());
-	clear();
-	for(BlobArray::const_iterator i=archive.begin();i!=archive.end();++i) {
-		BlobArray entry;
-		entry.deserialize(i->data(),i->length());
-
-		if (entry.size() != 5) return false;
-		if (entry[2].length() != 32) return false; // SHA-256
-		if (entry[3].length() != ZT_ADDRESS_LENGTH) return false; // Address
-
-		Pack::Entry &e = _entries[entry[0]];
-		e.name = entry[0];
-		e.content = entry[1];
-
-		SHA256_Init(&sha);
-		SHA256_Update(&sha,e.content.data(),e.content.length());
-		SHA256_Final(dig,&sha);
-		if (memcmp(dig,entry[2].data(),32)) return false; // integrity check failed
-		memcpy(e.sha256,dig,32);
-
-		if (entry[3].length() == ZT_ADDRESS_LENGTH)
-			e.signedBy.setTo(entry[3].data());
-		else e.signedBy = 0;
-		e.signature = entry[4];
-	}
-	return true;
-}
-
-bool Pack::signAll(const Identity &id)
-{
-	for(std::map<std::string,Entry>::iterator e=_entries.begin();e!=_entries.end();++e) {
-		e->second.signedBy = id.address();
-		e->second.signature = id.sign(e->second.sha256);
-		if (!e->second.signature.length())
-			return false;
-	}
-	return true;
-}
-
-std::vector<const Pack::Entry *> Pack::verifyAll(const Identity &id,bool mandatory) const
-{
-	std::vector<const Entry *> bad;
-	for(std::map<std::string,Entry>::const_iterator e=_entries.begin();e!=_entries.end();++e) {
-		if ((e->second.signedBy)&&(e->second.signature.length())) {
-			if (id.address() != e->second.signedBy)
-				bad.push_back(&(e->second));
-			else if (!id.verifySignature(e->second.sha256,e->second.signature.data(),e->second.signature.length()))
-				bad.push_back(&(e->second));
-		} else if (mandatory)
-			bad.push_back(&(e->second));
-	}
-	return bad;
-}
-
-} // namespace ZeroTier

+ 0 - 141
node/Pack.hpp

@@ -1,141 +0,0 @@
-/*
- * ZeroTier One - Global Peer to Peer Ethernet
- * Copyright (C) 2012-2013  ZeroTier Networks LLC
- *
- * 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/>.
- *
- * --
- *
- * ZeroTier may be used and distributed under the terms of the GPLv3, which
- * are available at: http://www.gnu.org/licenses/gpl-3.0.html
- *
- * If you would like to embed ZeroTier into a commercial application or
- * redistribute it in a modified binary form, please contact ZeroTier Networks
- * LLC. Start here: http://www.zerotier.com/
- */
-
-#ifndef _ZT_PACK_HPP
-#define _ZT_PACK_HPP
-
-#include <string>
-#include <map>
-#include <list>
-#include <stdexcept>
-#include "Address.hpp"
-#include "Identity.hpp"
-
-namespace ZeroTier {
-
-/**
- * A very simple archive format for distributing packs of files or resources
- * 
- * This is used for things like the auto-updater. It's not suitable for huge
- * files, since at present it must work in memory. Packs support signing with
- * identities and signature verification.
- */
-class Pack
-{
-public:
-	/**
-	 * Pack entry structure for looking up deserialized entries
-	 */
-	struct Entry
-	{
-		std::string name;
-		std::string content;
-		unsigned char sha256[32];
-		Address signedBy;
-		std::string signature;
-	};
-
-	Pack() {}
-	~Pack() {}
-
-	/**
-	 * @return Vector of all entries
-	 */
-	std::vector<const Entry *> getAll() const;
-
-	/**
-	 * Look up an entry
-	 * 
-	 * @param name Name to look up
-	 * @return Pointer to entry if it exists or NULL if not found
-	 */
-	const Entry *get(const std::string &name) const;
-
-	/**
-	 * Add an entry to this pack
-	 * 
-	 * @param name Entry to add
-	 * @param content Entry's contents
-	 * @return The new entry
-	 */
-	const Entry *put(const std::string &name,const std::string &content);
-
-	/**
-	 * Remove all entries
-	 */
-	void clear();
-
-	/**
-	 * @return Number of entries in pack
-	 */
-	inline unsigned int numEntries() const { return (unsigned int)_entries.size(); }
-
-	/**
-	 * Serialize this pack
-	 * 
-	 * @return Serialized form (compressed with LZ4)
-	 */
-	std::string serialize() const;
-
-	/**
-	 * Deserialize this pack
-	 * 
-	 * Any current contents are lost. This does not verify signatures,
-	 * but does check SHA256 hashes for entry integrity. If the return
-	 * value is false, the pack's contents are undefined.
-	 * 
-	 * @param sd Serialized data
-	 * @param sdlen Length of serialized data
-	 * @return True on success, false on deserialization error
-	 */
-	bool deserialize(const void *sd,unsigned int sdlen);
-	inline bool deserialize(const std::string &sd) { return deserialize(sd.data(),sd.length()); }
-
-	/**
-	 * Sign all entries in this pack with a given identity
-	 * 
-	 * @param id Identity to sign with
-	 * @return True on signature success, false if error
-	 */
-	bool signAll(const Identity &id);
-
-	/**
-	 * Verify all signed entries
-	 * 
-	 * @param id Identity to verify against
-	 * @param mandatory If true, require that all entries be signed and fail if no signature
-	 * @return Vector of entries that failed verification or empty vector if all passed
-	 */
-	std::vector<const Entry *> verifyAll(const Identity &id,bool mandatory) const;
-
-private:
-	std::map<std::string,Entry> _entries;
-};
-
-} // namespace ZeroTier
-
-#endif

+ 3 - 0
node/Packet.cpp

@@ -42,6 +42,7 @@ const char *Packet::verbString(Verb v)
 		case VERB_FRAME: return "FRAME";
 		case VERB_MULTICAST_FRAME: return "MULTICAST_FRAME";
 		case VERB_MULTICAST_LIKE: return "MULTICAST_LIKE";
+		case VERB_NETWORK_PERMISSION_CERTIFICATE: return "NETWORK_PERMISSION_CERTIFICATE";
 	}
 	return "(unknown)";
 }
@@ -57,6 +58,8 @@ const char *Packet::errorString(ErrorCode e)
 		case ERROR_IDENTITY_COLLISION: return "IDENTITY_COLLISION";
 		case ERROR_IDENTITY_INVALID: return "IDENTITY_INVALID";
 		case ERROR_UNSUPPORTED_OPERATION: return "UNSUPPORTED_OPERATION";
+		case ERROR_NO_NETWORK_CERTIFICATE_ON_FILE: return "NO_NETWORK_CERTIFICATE_ON_FILE";
+		case ERROR_OBJECT_EXPIRED: return "OBJECT_EXPIRED";
 	}
 	return "(unknown)";
 }

+ 23 - 2
node/Packet.hpp

@@ -463,7 +463,22 @@ public:
 		 *
 		 * No OK or ERROR is generated.
 		 */
-		VERB_MULTICAST_FRAME = 9
+		VERB_MULTICAST_FRAME = 9,
+
+		/* Network permission certificate:
+		 *   <[8] 64-bit network ID>
+		 *   <[1] flags (currently unused, must be 0)>
+		 *   <[8] certificate timestamp>
+		 *   <[8] 16-bit length of signature>
+		 *   <[...] ECDSA signature of my binary serialized identity and timestamp>
+		 *
+		 * This message is used to send ahead of time a certificate proving
+		 * this node has permission to communicate on a private network.
+		 *
+		 * OK is generated on acceptance. ERROR is returned on failure. In both
+		 * cases the payload is the network ID.
+		 */
+		VERB_NETWORK_PERMISSION_CERTIFICATE = 10
 	};
 
 	/**
@@ -490,7 +505,13 @@ public:
 		ERROR_IDENTITY_INVALID = 5,
 
 		/* Verb or use case not supported/enabled by this node */
-		ERROR_UNSUPPORTED_OPERATION = 6
+		ERROR_UNSUPPORTED_OPERATION = 6,
+
+		/* Message to private network rejected -- no unexpired certificate on file */
+		ERROR_NO_NETWORK_CERTIFICATE_ON_FILE = 7,
+
+		/* Object is expired (e.g. network certificate) */
+		ERROR_OBJECT_EXPIRED = 8
 	};
 
 	/**

+ 0 - 1
objects.mk

@@ -18,7 +18,6 @@ OBJS=\
 	node/NodeConfig.o \
 	node/Packet.o \
 	node/PacketDecoder.o \
-	node/Pack.o \
 	node/Peer.o \
 	node/Salsa20.o \
 	node/Switch.o \