mirror of
https://github.com/zerotier/ZeroTierOne.git
synced 2025-06-06 12:33:44 +02:00
Network constructor deuglification, remove unused old encrypt/decrypt methods from Identity.
This commit is contained in:
parent
28a73b620e
commit
b342f56bec
5 changed files with 70 additions and 167 deletions
|
@ -225,81 +225,5 @@ Address Identity::deriveAddress(const void *keyBytes,unsigned int keyLen)
|
||||||
return Address(dig,ZT_ADDRESS_LENGTH); // first 5 bytes of dig[]
|
return Address(dig,ZT_ADDRESS_LENGTH); // first 5 bytes of dig[]
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string Identity::encrypt(const Identity &to,const void *data,unsigned int len) const
|
|
||||||
{
|
|
||||||
unsigned char key[64];
|
|
||||||
unsigned char mac[32];
|
|
||||||
unsigned char iv[8];
|
|
||||||
|
|
||||||
if (!agree(to,key,sizeof(key)))
|
|
||||||
return std::string();
|
|
||||||
Utils::getSecureRandom(iv,8);
|
|
||||||
for(int i=0;i<8;++i)
|
|
||||||
key[i + 32] ^= iv[i]; // perturb HMAC key with IV so IV is effectively included in HMAC
|
|
||||||
Salsa20 s20(key,256,iv);
|
|
||||||
|
|
||||||
std::string compressed;
|
|
||||||
compressed.reserve(len);
|
|
||||||
Utils::compress((const char *)data,(const char *)data + len,Utils::StringAppendOutput(compressed));
|
|
||||||
if (!compressed.length())
|
|
||||||
return std::string();
|
|
||||||
|
|
||||||
char *encrypted = new char[compressed.length() + 16];
|
|
||||||
try {
|
|
||||||
s20.encrypt(compressed.data(),encrypted + 16,(unsigned int)compressed.length());
|
|
||||||
HMAC::sha256(key + 32,32,encrypted + 16,(unsigned int)compressed.length(),mac);
|
|
||||||
for(int i=0;i<8;++i)
|
|
||||||
encrypted[i] = iv[i];
|
|
||||||
for(int i=0;i<8;++i)
|
|
||||||
encrypted[i + 8] = mac[i];
|
|
||||||
|
|
||||||
std::string s(encrypted,compressed.length() + 16);
|
|
||||||
delete [] encrypted;
|
|
||||||
return s;
|
|
||||||
} catch ( ... ) {
|
|
||||||
delete [] encrypted;
|
|
||||||
return std::string();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string Identity::decrypt(const Identity &from,const void *cdata,unsigned int len) const
|
|
||||||
{
|
|
||||||
unsigned char key[64];
|
|
||||||
unsigned char mac[32];
|
|
||||||
|
|
||||||
if (len < 16)
|
|
||||||
return std::string();
|
|
||||||
|
|
||||||
if (!agree(from,key,sizeof(key)))
|
|
||||||
return std::string();
|
|
||||||
|
|
||||||
for(int i=0;i<8;++i)
|
|
||||||
key[i + 32] ^= ((const unsigned char *)cdata)[i]; // apply IV to HMAC key
|
|
||||||
HMAC::sha256(key + 32,32,((const char *)cdata) + 16,(unsigned int)(len - 16),mac);
|
|
||||||
for(int i=0;i<8;++i) {
|
|
||||||
if (((const unsigned char *)cdata)[i + 8] != mac[i])
|
|
||||||
return std::string();
|
|
||||||
}
|
|
||||||
|
|
||||||
char *decbuf = new char[len - 16];
|
|
||||||
try {
|
|
||||||
Salsa20 s20(key,256,cdata); // first 8 bytes are IV
|
|
||||||
len -= 16;
|
|
||||||
s20.decrypt((const char *)cdata + 16,decbuf,len);
|
|
||||||
|
|
||||||
std::string decompressed;
|
|
||||||
if (Utils::decompress((const char *)decbuf,(const char *)decbuf + len,Utils::StringAppendOutput(decompressed))) {
|
|
||||||
delete [] decbuf;
|
|
||||||
return decompressed;
|
|
||||||
} else {
|
|
||||||
delete [] decbuf;
|
|
||||||
return std::string();
|
|
||||||
}
|
|
||||||
} catch ( ... ) {
|
|
||||||
delete [] decbuf;
|
|
||||||
return std::string();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace ZeroTier
|
} // namespace ZeroTier
|
||||||
|
|
||||||
|
|
|
@ -175,40 +175,6 @@ public:
|
||||||
*/
|
*/
|
||||||
inline bool hasPrivate() const throw() { return (_keyPair); }
|
inline bool hasPrivate() const throw() { return (_keyPair); }
|
||||||
|
|
||||||
/**
|
|
||||||
* Encrypt a block of data to send to another identity
|
|
||||||
*
|
|
||||||
* This identity must have a secret key.
|
|
||||||
*
|
|
||||||
* The encrypted data format is:
|
|
||||||
* <[8] Salsa20 initialization vector>
|
|
||||||
* <[8] first 8 bytes of HMAC-SHA-256 of ciphertext>
|
|
||||||
* <[...] encrypted compressed data>
|
|
||||||
*
|
|
||||||
* Keying is accomplished using agree() (KDF function is in the
|
|
||||||
* EllipticCurveKeyPair.cpp source) to generate 64 bytes of key. The first
|
|
||||||
* 32 bytes are used as the Salsa20 key, and the last 32 bytes are used
|
|
||||||
* as the HMAC key.
|
|
||||||
*
|
|
||||||
* @param to Identity of recipient of encrypted message
|
|
||||||
* @param data Data to encrypt
|
|
||||||
* @param len Length of data
|
|
||||||
* @return Encrypted data or empty string on failure
|
|
||||||
*/
|
|
||||||
std::string encrypt(const Identity &to,const void *data,unsigned int len) const;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Decrypt a message encrypted with encrypt()
|
|
||||||
*
|
|
||||||
* This identity must have a secret key.
|
|
||||||
*
|
|
||||||
* @param from Identity of sender of encrypted message
|
|
||||||
* @param cdata Encrypted message
|
|
||||||
* @param len Length of encrypted message
|
|
||||||
* @return Decrypted data or empty string on failure
|
|
||||||
*/
|
|
||||||
std::string decrypt(const Identity &from,const void *cdata,unsigned int len) const;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Shortcut method to perform key agreement with another identity
|
* Shortcut method to perform key agreement with another identity
|
||||||
*
|
*
|
||||||
|
|
|
@ -104,20 +104,10 @@ bool Network::Certificate::qualifyMembership(const Network::Certificate &mc) con
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
Network::Network(const RuntimeEnvironment *renv,uint64_t id)
|
|
||||||
throw(std::runtime_error) :
|
|
||||||
_r(renv),
|
|
||||||
_tap(renv,renv->identity.address().toMAC(),ZT_IF_MTU,&_CBhandleTapData,this),
|
|
||||||
_id(id),
|
|
||||||
_lastConfigUpdate(0),
|
|
||||||
_destroyOnDelete(false)
|
|
||||||
{
|
|
||||||
if (controller() == _r->identity.address())
|
|
||||||
throw std::runtime_error("cannot add a network for which I am the netconf master");
|
|
||||||
}
|
|
||||||
|
|
||||||
Network::~Network()
|
Network::~Network()
|
||||||
{
|
{
|
||||||
|
delete _tap;
|
||||||
|
|
||||||
if (_destroyOnDelete) {
|
if (_destroyOnDelete) {
|
||||||
std::string confPath(_r->homePath + ZT_PATH_SEPARATOR_S + "networks.d" + ZT_PATH_SEPARATOR_S + toString() + ".conf");
|
std::string confPath(_r->homePath + ZT_PATH_SEPARATOR_S + "networks.d" + ZT_PATH_SEPARATOR_S + toString() + ".conf");
|
||||||
std::string mcdbPath(_r->homePath + ZT_PATH_SEPARATOR_S + "networks.d" + ZT_PATH_SEPARATOR_S + toString() + ".mcerts");
|
std::string mcdbPath(_r->homePath + ZT_PATH_SEPARATOR_S + "networks.d" + ZT_PATH_SEPARATOR_S + toString() + ".mcerts");
|
||||||
|
@ -129,26 +119,25 @@ Network::~Network()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Network::restoreState()
|
SharedPtr<Network> Network::newInstance(const RuntimeEnvironment *renv,uint64_t id)
|
||||||
|
throw(std::runtime_error)
|
||||||
{
|
{
|
||||||
std::string confPath(_r->homePath + ZT_PATH_SEPARATOR_S + "networks.d" + ZT_PATH_SEPARATOR_S + toString() + ".conf");
|
// We construct Network via a static method to ensure that it is immediately
|
||||||
std::string confs;
|
// wrapped in a SharedPtr<>. Otherwise if there is traffic on the Ethernet
|
||||||
if (Utils::readFile(confPath.c_str(),confs)) {
|
// tap device, a SharedPtr<> wrap can occur in the Ethernet frame handler
|
||||||
try {
|
// that then causes the Network instance to be deleted before it is finished
|
||||||
if (confs.length()) {
|
// being constructed. C++ edge cases, how I love thee.
|
||||||
Config conf(confs);
|
SharedPtr<Network> nw(new Network());
|
||||||
if (conf.containsAllFields())
|
nw->_r = renv;
|
||||||
setConfiguration(conf);
|
nw->_tap = new EthernetTap(renv,renv->identity.address().toMAC(),ZT_IF_MTU,&_CBhandleTapData,nw.ptr());
|
||||||
}
|
nw->_id = id;
|
||||||
} catch ( ... ) {} // ignore invalid config on disk, we will re-request
|
nw->_lastConfigUpdate = 0;
|
||||||
} else {
|
nw->_destroyOnDelete = false;
|
||||||
// If the conf file isn't present, "touch" it so we'll remember
|
if (nw->controller() == renv->identity.address()) // sanity check, this isn't supported for now
|
||||||
// the existence of this network.
|
throw std::runtime_error("cannot add a network for which I am the netconf master");
|
||||||
FILE *tmp = fopen(confPath.c_str(),"w");
|
nw->_restoreState();
|
||||||
if (tmp)
|
nw->requestConfiguration();
|
||||||
fclose(tmp);
|
return nw;
|
||||||
}
|
|
||||||
// TODO: restore membership certs
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Network::setConfiguration(const Network::Config &conf)
|
void Network::setConfiguration(const Network::Config &conf)
|
||||||
|
@ -160,7 +149,7 @@ void Network::setConfiguration(const Network::Config &conf)
|
||||||
_myCertificate = conf.certificateOfMembership();
|
_myCertificate = conf.certificateOfMembership();
|
||||||
_lastConfigUpdate = Utils::now();
|
_lastConfigUpdate = Utils::now();
|
||||||
|
|
||||||
_tap.setIps(conf.staticAddresses());
|
_tap->setIps(conf.staticAddresses());
|
||||||
|
|
||||||
std::string confPath(_r->homePath + ZT_PATH_SEPARATOR_S + "networks.d" + ZT_PATH_SEPARATOR_S + toString() + ".conf");
|
std::string confPath(_r->homePath + ZT_PATH_SEPARATOR_S + "networks.d" + ZT_PATH_SEPARATOR_S + toString() + ".conf");
|
||||||
if (!Utils::writeFile(confPath.c_str(),conf.toString())) {
|
if (!Utils::writeFile(confPath.c_str(),conf.toString())) {
|
||||||
|
@ -210,11 +199,13 @@ bool Network::isAllowed(const Address &peer) const
|
||||||
|
|
||||||
void Network::clean()
|
void Network::clean()
|
||||||
{
|
{
|
||||||
Mutex::Lock _l(_lock);
|
|
||||||
if (_configuration.isOpen())
|
|
||||||
_membershipCertificates.clear();
|
|
||||||
else {
|
|
||||||
std::string mcdbPath(_r->homePath + ZT_PATH_SEPARATOR_S + "networks.d" + ZT_PATH_SEPARATOR_S + toString() + ".mcerts");
|
std::string mcdbPath(_r->homePath + ZT_PATH_SEPARATOR_S + "networks.d" + ZT_PATH_SEPARATOR_S + toString() + ".mcerts");
|
||||||
|
|
||||||
|
Mutex::Lock _l(_lock);
|
||||||
|
if (_configuration.isOpen()) {
|
||||||
|
_membershipCertificates.clear();
|
||||||
|
unlink(mcdbPath.c_str());
|
||||||
|
} else {
|
||||||
FILE *mcdb = fopen(mcdbPath.c_str(),"wb");
|
FILE *mcdb = fopen(mcdbPath.c_str(),"wb");
|
||||||
bool writeError = false;
|
bool writeError = false;
|
||||||
if (!mcdb) {
|
if (!mcdb) {
|
||||||
|
@ -263,4 +254,26 @@ void Network::_CBhandleTapData(void *arg,const MAC &from,const MAC &to,unsigned
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Network::_restoreState()
|
||||||
|
{
|
||||||
|
std::string confPath(_r->homePath + ZT_PATH_SEPARATOR_S + "networks.d" + ZT_PATH_SEPARATOR_S + toString() + ".conf");
|
||||||
|
std::string confs;
|
||||||
|
if (Utils::readFile(confPath.c_str(),confs)) {
|
||||||
|
try {
|
||||||
|
if (confs.length()) {
|
||||||
|
Config conf(confs);
|
||||||
|
if (conf.containsAllFields())
|
||||||
|
setConfiguration(conf);
|
||||||
|
}
|
||||||
|
} catch ( ... ) {} // ignore invalid config on disk, we will re-request
|
||||||
|
} else {
|
||||||
|
// If the conf file isn't present, "touch" it so we'll remember
|
||||||
|
// the existence of this network.
|
||||||
|
FILE *tmp = fopen(confPath.c_str(),"w");
|
||||||
|
if (tmp)
|
||||||
|
fclose(tmp);
|
||||||
|
}
|
||||||
|
// TODO: restore membership certs
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace ZeroTier
|
} // namespace ZeroTier
|
||||||
|
|
|
@ -267,26 +267,29 @@ public:
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// Only NodeConfig can create, only SharedPtr can delete
|
// Only NodeConfig can create, only SharedPtr can delete
|
||||||
Network(const RuntimeEnvironment *renv,uint64_t id)
|
|
||||||
throw(std::runtime_error);
|
// Actual construction happens in newInstance()
|
||||||
|
Network()
|
||||||
|
throw() :
|
||||||
|
_tap((EthernetTap *)0)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
~Network();
|
~Network();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Called by NodeConfig after create
|
* Create a new Network instance and restore any saved state
|
||||||
*
|
*
|
||||||
* This is called separately to avoid a rather evil race condition.
|
* If there is no saved state, a dummy .conf is created on disk to remember
|
||||||
* If config is restored in the constructor, then it's possible that
|
* this network across restarts.
|
||||||
* the tap will be assigned an IP and will start getting packets
|
|
||||||
* before SharedPtr<Network> has gotten the pointer from the initial
|
|
||||||
* object construct. That causes SharedPtr<Network> in the static
|
|
||||||
* method that handles tap traffic to delete the object, resulting
|
|
||||||
* in all sorts of utter madness. C++ is crazy like that.
|
|
||||||
*
|
*
|
||||||
* Actually the way we're using SharedPtr<Network> is hacky and
|
* @param renv Runtime environment
|
||||||
* ugly, so it's our fault sorta.
|
* @param id Network ID
|
||||||
|
* @return Reference counted pointer to new network
|
||||||
|
* @throws std::runtime_error Unable to create tap device or other fatal error
|
||||||
*/
|
*/
|
||||||
void restoreState();
|
static SharedPtr<Network> newInstance(const RuntimeEnvironment *renv,uint64_t id)
|
||||||
|
throw(std::runtime_error);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Causes all persistent disk presence to be erased on delete
|
* Causes all persistent disk presence to be erased on delete
|
||||||
|
@ -305,7 +308,7 @@ public:
|
||||||
/**
|
/**
|
||||||
* @return Ethernet tap
|
* @return Ethernet tap
|
||||||
*/
|
*/
|
||||||
inline EthernetTap &tap() throw() { return _tap; }
|
inline EthernetTap &tap() throw() { return *_tap; }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return Address of network's controlling node
|
* @return Address of network's controlling node
|
||||||
|
@ -344,7 +347,7 @@ public:
|
||||||
inline bool updateMulticastGroups()
|
inline bool updateMulticastGroups()
|
||||||
{
|
{
|
||||||
Mutex::Lock _l(_lock);
|
Mutex::Lock _l(_lock);
|
||||||
return _tap.updateMulticastGroups(_multicastGroups);
|
return _tap->updateMulticastGroups(_multicastGroups);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -403,11 +406,12 @@ public:
|
||||||
|
|
||||||
private:
|
private:
|
||||||
static void _CBhandleTapData(void *arg,const MAC &from,const MAC &to,unsigned int etherType,const Buffer<4096> &data);
|
static void _CBhandleTapData(void *arg,const MAC &from,const MAC &to,unsigned int etherType,const Buffer<4096> &data);
|
||||||
|
void _restoreState();
|
||||||
|
|
||||||
const RuntimeEnvironment *_r;
|
const RuntimeEnvironment *_r;
|
||||||
|
|
||||||
// Tap and tap multicast memberships
|
// Tap and tap multicast memberships
|
||||||
EthernetTap _tap;
|
EthernetTap *_tap;
|
||||||
std::set<MulticastGroup> _multicastGroups;
|
std::set<MulticastGroup> _multicastGroups;
|
||||||
|
|
||||||
// Membership certificates supplied by peers
|
// Membership certificates supplied by peers
|
||||||
|
|
|
@ -76,10 +76,8 @@ NodeConfig::NodeConfig(const RuntimeEnvironment *renv,const char *authToken)
|
||||||
|
|
||||||
for(std::set<uint64_t>::iterator nwid(nwids.begin());nwid!=nwids.end();++nwid) {
|
for(std::set<uint64_t>::iterator nwid(nwids.begin());nwid!=nwids.end();++nwid) {
|
||||||
try {
|
try {
|
||||||
SharedPtr<Network> nw(new Network(_r,*nwid));
|
SharedPtr<Network> nw(Network::newInstance(_r,*nwid));
|
||||||
_networks[*nwid] = nw;
|
_networks[*nwid] = nw;
|
||||||
nw->restoreState();
|
|
||||||
nw->requestConfiguration();
|
|
||||||
} catch (std::exception &exc) {
|
} catch (std::exception &exc) {
|
||||||
LOG("unable to create network %.16llx: %s",(unsigned long long)*nwid,exc.what());
|
LOG("unable to create network %.16llx: %s",(unsigned long long)*nwid,exc.what());
|
||||||
} catch ( ... ) {
|
} catch ( ... ) {
|
||||||
|
@ -181,10 +179,8 @@ std::vector<std::string> NodeConfig::execute(const char *command)
|
||||||
_P("400 already a member of %.16llx",(unsigned long long)nwid);
|
_P("400 already a member of %.16llx",(unsigned long long)nwid);
|
||||||
} else {
|
} else {
|
||||||
try {
|
try {
|
||||||
SharedPtr<Network> nw(new Network(_r,nwid));
|
SharedPtr<Network> nw(Network::newInstance(_r,nwid));
|
||||||
_networks[nwid] = nw;
|
_networks[nwid] = nw;
|
||||||
nw->restoreState();
|
|
||||||
nw->requestConfiguration();
|
|
||||||
_P("200 join %.16llx OK",(unsigned long long)nwid);
|
_P("200 join %.16llx OK",(unsigned long long)nwid);
|
||||||
} catch (std::exception &exc) {
|
} catch (std::exception &exc) {
|
||||||
_P("500 join %.16llx ERROR: %s",(unsigned long long)nwid,exc.what());
|
_P("500 join %.16llx ERROR: %s",(unsigned long long)nwid,exc.what());
|
||||||
|
|
Loading…
Add table
Reference in a new issue