mirror of
https://github.com/zerotier/ZeroTierOne.git
synced 2025-04-18 16:07:28 +00:00
Add skeleton of certificate-based private network authentication. Also remove some old code.
This commit is contained in:
parent
d35d322890
commit
7a17f6ca80
@ -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
|
||||
|
@ -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
|
||||
{
|
||||
|
@ -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"
|
||||
|
159
node/Pack.cpp
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
|
141
node/Pack.hpp
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
|
@ -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)";
|
||||
}
|
||||
|
@ -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
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -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 \
|
||||
|
Loading…
x
Reference in New Issue
Block a user