fix KEYS_UPDATE to properly be two-phased so the packet buffer works properly;

pull/121/merge
Bryan Biedenkapp 6 days ago
parent 7d5db97449
commit 67ec2b5f6d

@ -904,51 +904,104 @@ void MetadataNetwork::taskNetworkRx(NetPacketRequest* req)
} }
} }
// keys inventory operates differently from the rest of the network opcodes...and does not require // keys update operates differently from the rest of the network opcodes...and does not require
// an established connection to the master, so we will not validate the peer connection state here // an established connection to the master, so we will not validate the peer connection state here.
// update is a two-phase flow: (1) auth request frame (80 bytes), then (2) chunked PacketBuffer frames.
if (peerId > 0 && !peerEntry.peerDefault()) { if (peerId > 0 && !peerEntry.peerDefault()) {
// scope intentional if (mdNetwork->m_peerKeyUpdatePkt.find(peerId) == mdNetwork->m_peerKeyUpdatePkt.end()) {
{ if (req->length < 80) {
// get the peer password hash from the frame message LogError(LOG_MASTER, "PEER %u requested enc. key update, but payload length was invalid (%u bytes), no response", peerId, req->length);
DECLARE_UINT8_ARRAY(peerHash, 32U); break;
::memcpy(peerHash, req->buffer + 8U, 32U); }
uint8_t peerSalt[4U]; // scope intentional
::memset(peerSalt, 0x00U, 4U); {
::memcpy(peerSalt, req->buffer + 40U, 4U); // get the peer password hash from the frame message
DECLARE_UINT8_ARRAY(peerHash, 32U);
::memcpy(peerHash, req->buffer + 8U, 32U);
std::string passwordForPeer = network->m_password; uint8_t peerSalt[4U];
::memset(peerSalt, 0x00U, 4U);
::memcpy(peerSalt, req->buffer + 40U, 4U);
// check if the peer is in the peer ACL list std::string passwordForPeer = network->m_password;
bool validAcl = true;
if (network->m_peerListLookup->getACL()) { // check if the peer is in the peer ACL list
if (!network->m_peerListLookup->isPeerAllowed(peerId) && !network->m_peerListLookup->isPeerListEmpty()) { bool validAcl = true;
LogWarning(LOG_MASTER, "PEER %u RPTK, failed peer ACL check", peerId); if (network->m_peerListLookup->getACL()) {
validAcl = false; if (!network->m_peerListLookup->isPeerAllowed(peerId) && !network->m_peerListLookup->isPeerListEmpty()) {
} else { LogWarning(LOG_MASTER, "PEER %u RPTK, failed peer ACL check", peerId);
lookups::PeerId peerEntry = network->m_peerListLookup->find(peerId); validAcl = false;
if (peerEntry.peerDefault()) {
validAcl = false; // default peer IDs are a no-no as they have no data thus fail ACL check
} else { } else {
passwordForPeer = peerEntry.peerPassword(); lookups::PeerId peerEntry = network->m_peerListLookup->find(peerId);
if (passwordForPeer.length() == 0) { if (peerEntry.peerDefault()) {
passwordForPeer = network->m_password; validAcl = false; // default peer IDs are a no-no as they have no data thus fail ACL check
} else {
passwordForPeer = peerEntry.peerPassword();
if (passwordForPeer.length() == 0) {
passwordForPeer = network->m_password;
}
} }
} }
if (network->m_peerListLookup->isPeerListEmpty()) {
LogWarning(LOG_MASTER, "Peer List ACL enabled, but we have an empty peer list? Passing all peers.");
validAcl = true;
}
} }
if (network->m_peerListLookup->isPeerListEmpty()) { if (validAcl) {
LogWarning(LOG_MASTER, "Peer List ACL enabled, but we have an empty peer list? Passing all peers."); size_t size = passwordForPeer.size();
validAcl = true; uint8_t* in = new uint8_t[size + sizeof(uint32_t)];
::memcpy(in, peerSalt, sizeof(uint32_t));
for (size_t i = 0U; i < size; i++)
in[i + sizeof(uint32_t)] = passwordForPeer.at(i);
uint8_t out[32U];
edac::SHA256 sha256;
sha256.buffer(in, (uint32_t)(size + sizeof(uint32_t)), out);
delete[] in;
// validate hash
bool validHash = false;
if (req->length >= 80) {
validHash = true;
for (uint8_t i = 0; i < 32U; i++) {
if (peerHash[i] != out[i]) {
validHash = false;
break;
}
}
}
if (!validHash) {
LogError(LOG_MASTER, "PEER %u requested enc. key update, but had invalid authentication, no response", peerId);
break;
}
} else {
LogError(LOG_MASTER, "PEER %u requested enc. key update, but had invalid ACL, no response", peerId);
break;
} }
} }
if (validAcl) { // scope intentional
size_t size = passwordForPeer.size(); {
// get remote access password hash from the frame message
DECLARE_UINT8_ARRAY(remoteAccessHash, 32U);
::memcpy(remoteAccessHash, req->buffer + 44U, 32U);
uint8_t remoteSalt[4U];
::memset(remoteSalt, 0x00U, 4U);
::memcpy(remoteSalt, req->buffer + 76U, 4U);
std::string remoteAccessPassword = network->m_host->m_cryptoLookup->getRemotePassword();
size_t size = remoteAccessPassword.size();
uint8_t* in = new uint8_t[size + sizeof(uint32_t)]; uint8_t* in = new uint8_t[size + sizeof(uint32_t)];
::memcpy(in, peerSalt, sizeof(uint32_t)); ::memcpy(in, remoteSalt, sizeof(uint32_t));
for (size_t i = 0U; i < size; i++) for (size_t i = 0U; i < size; i++)
in[i + sizeof(uint32_t)] = passwordForPeer.at(i); in[i + sizeof(uint32_t)] = remoteAccessPassword.at(i);
uint8_t out[32U]; uint8_t out[32U];
edac::SHA256 sha256; edac::SHA256 sha256;
@ -958,10 +1011,10 @@ void MetadataNetwork::taskNetworkRx(NetPacketRequest* req)
// validate hash // validate hash
bool validHash = false; bool validHash = false;
if (req->length - 8U == 32U) { if (req->length >= 80) {
validHash = true; validHash = true;
for (uint8_t i = 0; i < 32U; i++) { for (uint8_t i = 0; i < 32U; i++) {
if (peerHash[i] != out[i]) { if (remoteAccessHash[i] != out[i]) {
validHash = false; validHash = false;
break; break;
} }
@ -969,55 +1022,20 @@ void MetadataNetwork::taskNetworkRx(NetPacketRequest* req)
} }
if (!validHash) { if (!validHash) {
LogError(LOG_MASTER, "PEER %u requested enc. key update, but had invalid authentication, no response", peerId); LogError(LOG_MASTER, "PEER %u requested enc. key update, but had invalid access authentication, no response", peerId);
break; break;
} }
} else {
LogError(LOG_MASTER, "PEER %u requested enc. key update, but had invalid ACL, no response", peerId);
break;
} }
}
// scope intentional mdNetwork->m_peerKeyUpdatePkt.insert(peerId, MetadataNetwork::PacketBufferEntry());
{ MetadataNetwork::PacketBufferEntry& pkt = mdNetwork->m_peerKeyUpdatePkt[peerId];
// get remote access password hash from the frame message pkt.buffer = new PacketBuffer(true, "Remote EKC, Key Update");
DECLARE_UINT8_ARRAY(remoteAccessHash, 32U); pkt.streamId = streamId;
::memcpy(remoteAccessHash, req->buffer + 44U, 32U); pkt.locked = false;
pkt.timeout = 0U;
uint8_t remoteSalt[4U];
::memset(remoteSalt, 0x00U, 4U);
::memcpy(remoteSalt, req->buffer + 76U, 4U);
std::string remoteAccessPassword = network->m_host->m_cryptoLookup->getRemotePassword();
size_t size = remoteAccessPassword.size();
uint8_t* in = new uint8_t[size + sizeof(uint32_t)];
::memcpy(in, remoteSalt, sizeof(uint32_t));
for (size_t i = 0U; i < size; i++)
in[i + sizeof(uint32_t)] = remoteAccessPassword.at(i);
uint8_t out[32U];
edac::SHA256 sha256;
sha256.buffer(in, (uint32_t)(size + sizeof(uint32_t)), out);
delete[] in;
// validate hash
bool validHash = false;
if (req->length - 8U == 32U) {
validHash = true;
for (uint8_t i = 0; i < 32U; i++) {
if (remoteAccessHash[i] != out[i]) {
validHash = false;
break;
}
}
}
if (!validHash) { LogInfoEx(LOG_REPL, "PEER %u Remote EKC, Key Update, authenticated transfer streamId = %u", peerId, streamId);
LogError(LOG_MASTER, "PEER %u requested enc. key update, but had invalid access authentication, no response", peerId); break;
break;
}
} }
// scope intentional // scope intentional
@ -1027,29 +1045,21 @@ void MetadataNetwork::taskNetworkRx(NetPacketRequest* req)
// Utils::dump(1U, "MetadataNetwork::taskNetworkRx(), KEYS_UPDATE, Raw Payload", rawPayload, req->length); // Utils::dump(1U, "MetadataNetwork::taskNetworkRx(), KEYS_UPDATE, Raw Payload", rawPayload, req->length);
if (mdNetwork->m_peerKeyUpdatePkt.find(peerId) == mdNetwork->m_peerKeyUpdatePkt.end()) { MetadataNetwork::PacketBufferEntry& pkt = mdNetwork->m_peerKeyUpdatePkt[peerId];
mdNetwork->m_peerKeyUpdatePkt.insert(peerId, MetadataNetwork::PacketBufferEntry()); if (!pkt.locked && pkt.streamId != streamId) {
LogError(LOG_REPL, "PEER %u Remote EKC, Key Update, stream ID mismatch, expected %u, got %u", peerId, pkt.streamId, streamId);
MetadataNetwork::PacketBufferEntry& pkt = mdNetwork->m_peerKeyUpdatePkt[peerId]; pkt.buffer->clear();
pkt.buffer = new PacketBuffer(true, "Remote EKC, Key Update"); delete pkt.buffer;
pkt.streamId = streamId; pkt.streamId = 0U;
mdNetwork->m_peerKeyUpdatePkt.erase(peerId);
pkt.locked = false; break;
} else { }
MetadataNetwork::PacketBufferEntry& pkt = mdNetwork->m_peerKeyUpdatePkt[peerId];
if (!pkt.locked && pkt.streamId != streamId) {
LogError(LOG_REPL, "PEER %u Remote EKC, Key Update, stream ID mismatch, expected %u, got %u", peerId, pkt.streamId, streamId);
pkt.buffer->clear();
pkt.streamId = streamId;
}
if (pkt.streamId != streamId) { if (pkt.streamId != streamId) {
// otherwise drop the packet // otherwise drop the packet
break; break;
}
} }
MetadataNetwork::PacketBufferEntry& pkt = mdNetwork->m_peerKeyUpdatePkt[peerId];
if (pkt.locked) { if (pkt.locked) {
while (pkt.locked && pkt.timeout < TIMEOUT_MAX_REPL) { while (pkt.locked && pkt.timeout < TIMEOUT_MAX_REPL) {
pkt.timeout++; pkt.timeout++;
@ -1059,6 +1069,7 @@ void MetadataNetwork::taskNetworkRx(NetPacketRequest* req)
if (pkt.timeout >= TIMEOUT_MAX_REPL) { if (pkt.timeout >= TIMEOUT_MAX_REPL) {
LogError(LOG_STP, "PEER %u Remote EKC, Key Update, timeout waiting for packet buffer to unlock", peerId); LogError(LOG_STP, "PEER %u Remote EKC, Key Update, timeout waiting for packet buffer to unlock", peerId);
pkt.buffer->clear(); pkt.buffer->clear();
delete pkt.buffer;
pkt.streamId = 0U; pkt.streamId = 0U;
mdNetwork->m_peerKeyUpdatePkt.erase(peerId); mdNetwork->m_peerKeyUpdatePkt.erase(peerId);
break; break;
@ -1073,7 +1084,6 @@ void MetadataNetwork::taskNetworkRx(NetPacketRequest* req)
if (pkt.buffer->decode(rawPayload, &decompressed, &decompressedLen)) { if (pkt.buffer->decode(rawPayload, &decompressed, &decompressedLen)) {
mdNetwork->m_peerKeyUpdatePkt.lock(); mdNetwork->m_peerKeyUpdatePkt.lock();
// randomize filename
std::ostringstream s; std::ostringstream s;
s << network->m_cryptoLookup->filename(); s << network->m_cryptoLookup->filename();

Loading…
Cancel
Save

Powered by TurnKey Linux.