From 3d9c844dca41d464920077cd73d46a374175f0b5 Mon Sep 17 00:00:00 2001 From: orignal Date: Tue, 28 Apr 2020 22:03:13 -0400 Subject: [PATCH] handle out of order NSR --- libi2pd/ECIESX25519AEADRatchetSession.cpp | 52 ++++++++++++++++------- 1 file changed, 36 insertions(+), 16 deletions(-) diff --git a/libi2pd/ECIESX25519AEADRatchetSession.cpp b/libi2pd/ECIESX25519AEADRatchetSession.cpp index 43049d56..025340c8 100644 --- a/libi2pd/ECIESX25519AEADRatchetSession.cpp +++ b/libi2pd/ECIESX25519AEADRatchetSession.cpp @@ -482,13 +482,18 @@ namespace garlic } buf += 32; len -= 32; // KDF for Reply Key Section + uint8_t h[32]; memcpy (h, m_H, 32); // save m_H MixHash (tag, 8); // h = SHA256(h || tag) MixHash (bepk, 32); // h = SHA256(h || bepk) uint8_t sharedSecret[32]; - m_EphemeralKeys.Agree (bepk, sharedSecret); // sharedSecret = x25519(aesk, bepk) - i2p::crypto::HKDF (m_CK, sharedSecret, 32, "", m_CK, 32); // chainKey = HKDF(chainKey, sharedSecret, "", 32) - GetOwner ()->Decrypt (bepk, sharedSecret, nullptr, i2p::data::CRYPTO_KEY_TYPE_ECIES_X25519_AEAD_RATCHET); // x25519 (ask, bepk) - i2p::crypto::HKDF (m_CK, sharedSecret, 32, "", m_CK); // [chainKey, key] = HKDF(chainKey, sharedSecret, "", 64) + if (m_State == eSessionStateNewSessionSent) + { + // only fist time, we assume ephemeral keys the same + m_EphemeralKeys.Agree (bepk, sharedSecret); // sharedSecret = x25519(aesk, bepk) + i2p::crypto::HKDF (m_CK, sharedSecret, 32, "", m_CK, 32); // chainKey = HKDF(chainKey, sharedSecret, "", 32) + GetOwner ()->Decrypt (bepk, sharedSecret, nullptr, i2p::data::CRYPTO_KEY_TYPE_ECIES_X25519_AEAD_RATCHET); // x25519 (ask, bepk) + i2p::crypto::HKDF (m_CK, sharedSecret, 32, "", m_CK); // [chainKey, key] = HKDF(chainKey, sharedSecret, "", 64) + } uint8_t nonce[12]; CreateNonce (0, nonce); // calulate hash for zero length @@ -502,14 +507,17 @@ namespace garlic // KDF for payload uint8_t keydata[64]; i2p::crypto::HKDF (m_CK, nullptr, 0, "", keydata); // keydata = HKDF(chainKey, ZEROLEN, "", 64) - // k_ab = keydata[0:31], k_ba = keydata[32:63] - m_SendTagset = std::make_shared(shared_from_this ()); - m_SendTagset->DHInitialize (m_CK, keydata); // tagset_ab = DH_INITIALIZE(chainKey, k_ab) - m_SendTagset->NextSessionTagRatchet (); - auto receiveTagset = std::make_shared(shared_from_this ()); - receiveTagset->DHInitialize (m_CK, keydata + 32); // tagset_ba = DH_INITIALIZE(chainKey, k_ba) - receiveTagset->NextSessionTagRatchet (); - GenerateMoreReceiveTags (receiveTagset, ECIESX25519_MIN_NUM_GENERATED_TAGS); + if (m_State == eSessionStateNewSessionSent) + { + // k_ab = keydata[0:31], k_ba = keydata[32:63] + m_SendTagset = std::make_shared(shared_from_this ()); + m_SendTagset->DHInitialize (m_CK, keydata); // tagset_ab = DH_INITIALIZE(chainKey, k_ab) + m_SendTagset->NextSessionTagRatchet (); + auto receiveTagset = std::make_shared(shared_from_this ()); + receiveTagset->DHInitialize (m_CK, keydata + 32); // tagset_ba = DH_INITIALIZE(chainKey, k_ba) + receiveTagset->NextSessionTagRatchet (); + GenerateMoreReceiveTags (receiveTagset, ECIESX25519_MIN_NUM_GENERATED_TAGS); + } i2p::crypto::HKDF (keydata + 32, nullptr, 0, "AttachPayloadKDF", keydata, 32); // k = HKDF(k_ba, ZEROLEN, "AttachPayloadKDF", 32) // decrypt payload std::vector payload (len - 16); @@ -518,9 +526,13 @@ namespace garlic LogPrint (eLogWarning, "Garlic: Payload section AEAD decryption failed"); return false; } - - m_State = eSessionStateEstablished; - GetOwner ()->AddECIESx25519Session (m_RemoteStaticKey, shared_from_this ()); + + if (m_State == eSessionStateNewSessionSent) + { + m_State = eSessionStateEstablished; + GetOwner ()->AddECIESx25519Session (m_RemoteStaticKey, shared_from_this ()); + } + memcpy (m_H, h, 32); // restore m_H HandlePayload (payload.data (), len - 16, nullptr, 0); // we have received reply to NS with LeaseSet in it @@ -587,7 +599,15 @@ namespace garlic [[fallthrough]]; #endif case eSessionStateEstablished: - return HandleExistingSessionMessage (buf, len, receiveTagset, index); + if (HandleExistingSessionMessage (buf, len, receiveTagset, index)) return true; + if (index < ECIESX25519_NSR_NUM_GENERATED_TAGS) + { + // check NSR just in case + LogPrint (eLogDebug, "Garlic: check for out of order NSR with index ", index); + return HandleNewOutgoingSessionReply (buf, len); + } + else + return false; case eSessionStateNew: return HandleNewIncomingSession (buf, len); case eSessionStateNewSessionSent: