diff options
author | Adam Ierymenko <adam.ierymenko@gmail.com> | 2013-07-18 11:43:46 -0400 |
---|---|---|
committer | Adam Ierymenko <adam.ierymenko@gmail.com> | 2013-07-18 11:43:46 -0400 |
commit | a677597b44ff94bf1f642f7ef81f926e09439ffd (patch) | |
tree | 3169ed1a90cce09ddfae89b23f1a5cfa17990448 /node/NodeConfig.cpp | |
parent | 1fce55fab10260ae942cc46c6fee15d71a1403c2 (diff) | |
download | infinitytier-a677597b44ff94bf1f642f7ef81f926e09439ffd.tar.gz infinitytier-a677597b44ff94bf1f642f7ef81f926e09439ffd.zip |
Better encode/decode code for control bus.
Diffstat (limited to 'node/NodeConfig.cpp')
-rw-r--r-- | node/NodeConfig.cpp | 129 |
1 files changed, 72 insertions, 57 deletions
diff --git a/node/NodeConfig.cpp b/node/NodeConfig.cpp index 0daa9ebe..fca53942 100644 --- a/node/NodeConfig.cpp +++ b/node/NodeConfig.cpp @@ -52,19 +52,12 @@ namespace ZeroTier { NodeConfig::NodeConfig(const RuntimeEnvironment *renv,const char *authToken) throw(std::runtime_error) : _r(renv), - _authToken(authToken), _controlSocket(true,ZT_CONTROL_UDP_PORT,false,&_CBcontrolPacketHandler,this) { SHA256_CTX sha; - - SHA256_Init(&sha); - SHA256_Update(&sha,_authToken.data(),_authToken.length()); - SHA256_Final(_keys,&sha); // first 32 bytes of keys[]: Salsa20 key - SHA256_Init(&sha); - SHA256_Update(&sha,_keys,32); - SHA256_Update(&sha,_authToken.data(),_authToken.length()); - SHA256_Final(_keys + 32,&sha); // second 32 bytes of keys[]: HMAC key + SHA256_Update(&sha,authToken,strlen(authToken)); + SHA256_Final(_controlSocketKey,&sha); } NodeConfig::~NodeConfig() @@ -146,64 +139,86 @@ std::vector<std::string> NodeConfig::execute(const char *command) return r; } -void NodeConfig::_CBcontrolPacketHandler(UdpSocket *sock,void *arg,const InetAddress &remoteAddr,const void *data,unsigned int len) +std::vector< Buffer<ZT_NODECONFIG_MAX_PACKET_SIZE> > NodeConfig::encodeControlMessage(const void *key,unsigned long conversationId,const std::vector<std::string> &payload) + throw(std::out_of_range) { - char hmacKey[32]; char hmac[32]; - char buf[131072]; - NodeConfig *nc = (NodeConfig *)arg; - const RuntimeEnvironment *_r = nc->_r; + char keytmp[32]; + std::vector< Buffer<ZT_NODECONFIG_MAX_PACKET_SIZE> > packets; + Buffer<ZT_NODECONFIG_MAX_PACKET_SIZE> packet; - try { - // Minimum length - if (len < 28) - return; - if (len >= sizeof(buf)) // only up to len - 28 bytes are used on receive/decrypt - return; - - // Compare first 16 bytes of HMAC, which is after IV in packet - memcpy(hmacKey,nc->_keys + 32,32); - *((uint64_t *)hmacKey) ^= *((const uint64_t *)data); // include IV in HMAC - HMAC::sha256(hmacKey,32,((const unsigned char *)data) + 28,len - 28,hmac); - if (memcmp(hmac,((const unsigned char *)data) + 8,16)) - return; - - // Decrypt payload if we passed HMAC - Salsa20 s20(nc->_keys,256,data); // first 64 bits of data are IV - s20.decrypt(((const unsigned char *)data) + 28,buf,len - 28); - - // Null-terminate string for execute() - buf[len - 28] = (char)0; - - // Execute command - std::vector<std::string> r(nc->execute(buf)); - - // Result packet contains a series of null-terminated results - unsigned int resultLen = 28; - for(std::vector<std::string>::iterator i(r.begin());i!=r.end();++i) { - if ((resultLen + i->length() + 1) >= sizeof(buf)) - return; // result too long - memcpy(buf + resultLen,i->c_str(),i->length() + 1); - resultLen += i->length() + 1; + packet.setSize(16); // HMAC and IV + packet.append((uint32_t)(conversationId & 0xffffffff)); + for(unsigned int i=0;i<payload.size();++i) { + packet.append(payload[i]); // will throw if too big + packet.append((unsigned char)0); + + if (((i + 1) >= payload.size())||((packet.size() + payload[i + 1].length() + 1) >= packet.capacity())) { + Utils::getSecureRandom(packet.field(8,8),8); + + memcpy(keytmp,key,32); + for(unsigned int i=0;i<32;++i) + keytmp[i] ^= 0x77; // use a different permutation of key for HMAC than for Salsa20 + HMAC::sha256(keytmp,32,packet.field(16,packet.size() - 16),packet.size() - 16,hmac); + memcpy(packet.field(0,8),hmac,8); + + Salsa20 s20(key,256,packet.field(8,8)); + s20.encrypt(packet.field(16,packet.size() - 16),packet.field(16,packet.size() - 16),packet.size() - 16); + + packets.push_back(packet); + + packet.setSize(16); // HMAC and IV + packet.append((uint32_t)(conversationId & 0xffffffff)); } + } - // Generate result packet IV - Utils::getSecureRandom(buf,8); + return packets; +} - // Generate result packet HMAC - memcpy(hmacKey,nc->_keys + 32,32); - *((uint64_t *)hmacKey) ^= *((const uint64_t *)buf); // include IV in HMAC - HMAC::sha256(hmacKey,32,((const unsigned char *)buf) + 28,resultLen - 28,hmac); - memcpy(buf + 8,hmac,16); +bool NodeConfig::decodeControlMessagePacket(const void *key,const void *data,unsigned int len,unsigned long &conversationId,std::vector<std::string> &payload) +{ + char hmac[32]; + char keytmp[32]; - // Copy arbitrary tag from original packet - memcpy(buf + 24,((const unsigned char *)data) + 24,4); + try { + if (len < 20) + return false; + + Buffer<ZT_NODECONFIG_MAX_PACKET_SIZE> packet(data,len); + + memcpy(keytmp,key,32); + for(unsigned int i=0;i<32;++i) + keytmp[i] ^= 0x77; // use a different permutation of key for HMAC than for Salsa20 + HMAC::sha256(keytmp,32,packet.field(16,packet.size() - 16),packet.size() - 16,hmac); + if (memcmp(packet.field(0,8),hmac,8)) + return false; + + Salsa20 s20(key,256,packet.field(8,8)); + s20.decrypt(packet.field(16,packet.size() - 16),packet.field(16,packet.size() - 16),packet.size() - 16); + + conversationId = packet.at<uint32_t>(16); + + const char *pl = ((const char *)packet.data()) + 20; + unsigned int pll = packet.size() - 20; + payload.clear(); + for(unsigned int i=0;i<pll;) { + unsigned int eos = i; + while ((eos < pll)&&(pl[eos])) + ++eos; + if (eos > i) { + payload.push_back(std::string(pl + i,eos - i)); + i = eos + 1; + } else break; + } - // Send encrypted result back to requester - sock->send(remoteAddr,buf,resultLen,-1); + return true; } catch ( ... ) { - TRACE("unexpected exception parsing control packet or generating response"); + return false; } } +void NodeConfig::_CBcontrolPacketHandler(UdpSocket *sock,void *arg,const InetAddress &remoteAddr,const void *data,unsigned int len) +{ +} + } // namespace ZeroTier |