mirror of
https://github.com/espressif/openthread.git
synced 2026-09-11 11:40:06 +00:00
Fix replay protection. (#218)
* Store key sequence value for each neighbor. * Dynamically generate previous key material on demand to reduce memory overhead. * Reset neighbor frame counters when advancing key sequence for a neighbor.
This commit is contained in:
+19
-20
@@ -723,17 +723,12 @@ ThreadError Mac::ProcessReceiveSecurity(Frame &aFrame, const Address &aSrcAddr,
|
||||
// same key index
|
||||
keySequence = mKeyManager.GetCurrentKeySequence();
|
||||
macKey = mKeyManager.GetCurrentMacKey();
|
||||
VerifyOrExit(aNeighbor->mPreviousKey == true || frameCounter >= aNeighbor->mValid.mLinkFrameCounter,
|
||||
error = kThreadError_Security);
|
||||
}
|
||||
else if (aNeighbor->mPreviousKey &&
|
||||
mKeyManager.IsPreviousKeyValid() &&
|
||||
keyid == (mKeyManager.GetPreviousKeySequence() & 0x7f))
|
||||
else if (keyid == ((mKeyManager.GetCurrentKeySequence() - 1) & 0x7f))
|
||||
{
|
||||
// previous key index
|
||||
keySequence = mKeyManager.GetPreviousKeySequence();
|
||||
macKey = mKeyManager.GetPreviousMacKey();
|
||||
VerifyOrExit(frameCounter >= aNeighbor->mValid.mLinkFrameCounter, error = kThreadError_Security);
|
||||
keySequence = mKeyManager.GetCurrentKeySequence() - 1;
|
||||
macKey = mKeyManager.GetTemporaryMacKey(keySequence);
|
||||
}
|
||||
else if (keyid == ((mKeyManager.GetCurrentKeySequence() + 1) & 0x7f))
|
||||
{
|
||||
@@ -743,14 +738,13 @@ ThreadError Mac::ProcessReceiveSecurity(Frame &aFrame, const Address &aSrcAddr,
|
||||
}
|
||||
else
|
||||
{
|
||||
for (Receiver *receiver = mReceiveHead; receiver; receiver = receiver->mNext)
|
||||
{
|
||||
receiver->HandleReceivedFrame(aFrame, kThreadError_Security);
|
||||
}
|
||||
|
||||
ExitNow(error = kThreadError_Security);
|
||||
}
|
||||
|
||||
VerifyOrExit(keySequence > aNeighbor->mKeySequence ||
|
||||
(keySequence == aNeighbor->mKeySequence) && (frameCounter >= aNeighbor->mValid.mLinkFrameCounter),
|
||||
error = kThreadError_Security);
|
||||
|
||||
aesCcm.SetKey(macKey, 16);
|
||||
aesCcm.Init(aFrame.GetHeaderLength(), aFrame.GetPayloadLength(), tagLength, nonce, sizeof(nonce));
|
||||
aesCcm.Header(aFrame.GetHeader(), aFrame.GetHeaderLength());
|
||||
@@ -759,14 +753,10 @@ ThreadError Mac::ProcessReceiveSecurity(Frame &aFrame, const Address &aSrcAddr,
|
||||
|
||||
VerifyOrExit(memcmp(tag, aFrame.GetFooter(), tagLength) == 0, error = kThreadError_Security);
|
||||
|
||||
if (keySequence > mKeyManager.GetCurrentKeySequence())
|
||||
if (aNeighbor->mKeySequence != keySequence)
|
||||
{
|
||||
mKeyManager.SetCurrentKeySequence(keySequence);
|
||||
}
|
||||
|
||||
if (keySequence == mKeyManager.GetCurrentKeySequence())
|
||||
{
|
||||
aNeighbor->mPreviousKey = false;
|
||||
aNeighbor->mKeySequence = keySequence;
|
||||
aNeighbor->mValid.mMleFrameCounter = 0;
|
||||
}
|
||||
|
||||
aNeighbor->mValid.mLinkFrameCounter = frameCounter + 1;
|
||||
@@ -774,6 +764,15 @@ ThreadError Mac::ProcessReceiveSecurity(Frame &aFrame, const Address &aSrcAddr,
|
||||
aFrame.SetSecurityValid(true);
|
||||
|
||||
exit:
|
||||
|
||||
if (error != kThreadError_None)
|
||||
{
|
||||
for (Receiver *receiver = mReceiveHead; receiver; receiver = receiver->mNext)
|
||||
{
|
||||
receiver->HandleReceivedFrame(aFrame, kThreadError_Security);
|
||||
}
|
||||
}
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
|
||||
@@ -47,12 +47,10 @@ static const uint8_t kThreadString[] =
|
||||
KeyManager::KeyManager(ThreadNetif &aThreadNetif):
|
||||
mNetif(aThreadNetif)
|
||||
{
|
||||
mPreviousKeyValid = false;
|
||||
mMasterKeyLength = 0;
|
||||
mKeySequence = 0;
|
||||
mMacFrameCounter = 0;
|
||||
mMleFrameCounter = 0;
|
||||
mCurrentKeySequence = 0;
|
||||
mPreviousKeySequence = 0;
|
||||
}
|
||||
|
||||
const uint8_t *KeyManager::GetMasterKey(uint8_t *aKeyLength) const
|
||||
@@ -72,8 +70,8 @@ ThreadError KeyManager::SetMasterKey(const void *aKey, uint8_t aKeyLength)
|
||||
VerifyOrExit(aKeyLength <= sizeof(mMasterKey), error = kThreadError_InvalidArgs);
|
||||
memcpy(mMasterKey, aKey, aKeyLength);
|
||||
mMasterKeyLength = aKeyLength;
|
||||
mCurrentKeySequence = 0;
|
||||
ComputeKey(mCurrentKeySequence, mCurrentKey);
|
||||
mKeySequence = 0;
|
||||
ComputeKey(mKeySequence, mKey);
|
||||
|
||||
mNetif.SetStateChangedFlags(OT_NET_KEY_SEQUENCE);
|
||||
|
||||
@@ -101,78 +99,28 @@ ThreadError KeyManager::ComputeKey(uint32_t aKeySequence, uint8_t *aKey)
|
||||
|
||||
uint32_t KeyManager::GetCurrentKeySequence() const
|
||||
{
|
||||
return mCurrentKeySequence;
|
||||
}
|
||||
|
||||
void KeyManager::UpdateNeighbors()
|
||||
{
|
||||
uint8_t numNeighbors;
|
||||
Router *routers;
|
||||
Child *children;
|
||||
|
||||
routers = mNetif.GetMle().GetParent();
|
||||
routers->mPreviousKey = true;
|
||||
|
||||
routers = mNetif.GetMle().GetRouters(&numNeighbors);
|
||||
|
||||
for (int i = 0; i < numNeighbors; i++)
|
||||
{
|
||||
routers[i].mPreviousKey = true;
|
||||
}
|
||||
|
||||
children = mNetif.GetMle().GetChildren(&numNeighbors);
|
||||
|
||||
for (int i = 0; i < numNeighbors; i++)
|
||||
{
|
||||
children[i].mPreviousKey = true;
|
||||
}
|
||||
return mKeySequence;
|
||||
}
|
||||
|
||||
void KeyManager::SetCurrentKeySequence(uint32_t aKeySequence)
|
||||
{
|
||||
mPreviousKeyValid = true;
|
||||
mPreviousKeySequence = mCurrentKeySequence;
|
||||
memcpy(mPreviousKey, mCurrentKey, sizeof(mPreviousKey));
|
||||
|
||||
mCurrentKeySequence = aKeySequence;
|
||||
ComputeKey(mCurrentKeySequence, mCurrentKey);
|
||||
mKeySequence = aKeySequence;
|
||||
ComputeKey(mKeySequence, mKey);
|
||||
|
||||
mMacFrameCounter = 0;
|
||||
mMleFrameCounter = 0;
|
||||
|
||||
UpdateNeighbors();
|
||||
|
||||
mNetif.SetStateChangedFlags(OT_NET_KEY_SEQUENCE);
|
||||
}
|
||||
|
||||
const uint8_t *KeyManager::GetCurrentMacKey() const
|
||||
{
|
||||
return mCurrentKey + 16;
|
||||
return mKey + 16;
|
||||
}
|
||||
|
||||
const uint8_t *KeyManager::GetCurrentMleKey() const
|
||||
{
|
||||
return mCurrentKey;
|
||||
}
|
||||
|
||||
bool KeyManager::IsPreviousKeyValid() const
|
||||
{
|
||||
return mPreviousKeyValid;
|
||||
}
|
||||
|
||||
uint32_t KeyManager::GetPreviousKeySequence() const
|
||||
{
|
||||
return mPreviousKeySequence;
|
||||
}
|
||||
|
||||
const uint8_t *KeyManager::GetPreviousMacKey() const
|
||||
{
|
||||
return mPreviousKey + 16;
|
||||
}
|
||||
|
||||
const uint8_t *KeyManager::GetPreviousMleKey() const
|
||||
{
|
||||
return mPreviousKey;
|
||||
return mKey;
|
||||
}
|
||||
|
||||
const uint8_t *KeyManager::GetTemporaryMacKey(uint32_t aKeySequence)
|
||||
|
||||
@@ -117,39 +117,6 @@ public:
|
||||
*/
|
||||
const uint8_t *GetCurrentMleKey() const;
|
||||
|
||||
/**
|
||||
* This method indicates whether the previous key is valid.
|
||||
*
|
||||
* @retval TRUE If the previous key is valid.
|
||||
* @retval FALSE If the previous key is not valid.
|
||||
*
|
||||
*/
|
||||
bool IsPreviousKeyValid() const;
|
||||
|
||||
/**
|
||||
* This method returns the previous key sequence value.
|
||||
*
|
||||
* @returns The previous key sequence value.
|
||||
*
|
||||
*/
|
||||
uint32_t GetPreviousKeySequence() const;
|
||||
|
||||
/**
|
||||
* This method returns a pointer to the previous MAC key.
|
||||
*
|
||||
* @returns A pointer to the previous MAC key.
|
||||
*
|
||||
*/
|
||||
const uint8_t *GetPreviousMacKey() const;
|
||||
|
||||
/**
|
||||
* This method returns a pointer to the previous MLE key.
|
||||
*
|
||||
* @returns A pointer to the previous MLE key.
|
||||
*
|
||||
*/
|
||||
const uint8_t *GetPreviousMleKey() const;
|
||||
|
||||
/**
|
||||
* This method returns a pointer to a temporary MAC key computed from the given key sequence.
|
||||
*
|
||||
@@ -209,17 +176,12 @@ private:
|
||||
};
|
||||
|
||||
ThreadError ComputeKey(uint32_t aKeySequence, uint8_t *aKey);
|
||||
void UpdateNeighbors();
|
||||
|
||||
uint8_t mMasterKey[kMaxKeyLength];
|
||||
uint8_t mMasterKeyLength;
|
||||
|
||||
uint32_t mPreviousKeySequence;
|
||||
uint8_t mPreviousKey[otCryptoSha256Size];
|
||||
bool mPreviousKeyValid;
|
||||
|
||||
uint32_t mCurrentKeySequence;
|
||||
uint8_t mCurrentKey[otCryptoSha256Size];
|
||||
uint32_t mKeySequence;
|
||||
uint8_t mKey[otCryptoSha256Size];
|
||||
|
||||
uint8_t mTemporaryKey[otCryptoSha256Size];
|
||||
|
||||
|
||||
+8
-21
@@ -1219,12 +1219,6 @@ void Mle::HandleUdpReceive(Message &aMessage, const Ip6::MessageInfo &aMessageIn
|
||||
keySequence = mKeyManager.GetCurrentKeySequence();
|
||||
mleKey = mKeyManager.GetCurrentMleKey();
|
||||
}
|
||||
else if (mKeyManager.IsPreviousKeyValid() &&
|
||||
keyid == (mKeyManager.GetPreviousKeySequence() & 0x7f))
|
||||
{
|
||||
keySequence = mKeyManager.GetPreviousKeySequence();
|
||||
mleKey = mKeyManager.GetPreviousMleKey();
|
||||
}
|
||||
else
|
||||
{
|
||||
keySequence = (mKeyManager.GetCurrentKeySequence() & ~0x7f) | keyid;
|
||||
@@ -1245,11 +1239,6 @@ void Mle::HandleUdpReceive(Message &aMessage, const Ip6::MessageInfo &aMessageIn
|
||||
{
|
||||
mleKey = mKeyManager.GetCurrentMleKey();
|
||||
}
|
||||
else if (mKeyManager.IsPreviousKeyValid() &&
|
||||
keySequence == mKeyManager.GetPreviousKeySequence())
|
||||
{
|
||||
mleKey = mKeyManager.GetPreviousMleKey();
|
||||
}
|
||||
else
|
||||
{
|
||||
mleKey = mKeyManager.GetTemporaryMleKey(keySequence);
|
||||
@@ -1325,15 +1314,15 @@ void Mle::HandleUdpReceive(Message &aMessage, const Ip6::MessageInfo &aMessageIn
|
||||
|
||||
if (neighbor != NULL && neighbor->mState == Neighbor::kStateValid)
|
||||
{
|
||||
if (keySequence == mKeyManager.GetCurrentKeySequence())
|
||||
VerifyOrExit(neighbor->mPreviousKey == true || frameCounter >= neighbor->mValid.mMleFrameCounter,
|
||||
otLogDebgMle("mle frame counter reject 1\n"));
|
||||
else if (keySequence == mKeyManager.GetPreviousKeySequence())
|
||||
VerifyOrExit(neighbor->mPreviousKey == true && frameCounter >= neighbor->mValid.mMleFrameCounter,
|
||||
otLogDebgMle("mle frame counter reject 2\n"));
|
||||
if (keySequence == neighbor->mKeySequence)
|
||||
{
|
||||
VerifyOrExit(frameCounter >= neighbor->mValid.mMleFrameCounter, otLogDebgMle("mle frame reject 1\n"));
|
||||
}
|
||||
else
|
||||
{
|
||||
assert(false);
|
||||
VerifyOrExit(keySequence > neighbor->mKeySequence, otLogDebgMle("mle frame reject 2\n"));
|
||||
neighbor->mKeySequence = keySequence;
|
||||
neighbor->mValid.mLinkFrameCounter = 0;
|
||||
}
|
||||
|
||||
neighbor->mValid.mMleFrameCounter = frameCounter + 1;
|
||||
@@ -1692,9 +1681,7 @@ ThreadError Mle::HandleParentResponse(const Message &aMessage, const Ip6::Messag
|
||||
mParent.mLinkInfo.Clear();
|
||||
mParent.mLinkInfo.AddRss(threadMessageInfo->mRss);
|
||||
mParent.mState = Neighbor::kStateValid;
|
||||
assert(aKeySequence == mKeyManager.GetCurrentKeySequence() ||
|
||||
aKeySequence == mKeyManager.GetPreviousKeySequence());
|
||||
mParent.mPreviousKey = aKeySequence == mKeyManager.GetPreviousKeySequence();
|
||||
mParent.mKeySequence = aKeySequence;
|
||||
mParentConnectivity = connectivity_metric;
|
||||
|
||||
exit:
|
||||
|
||||
@@ -903,9 +903,7 @@ ThreadError MleRouter::HandleLinkAccept(const Message &aMessage, const Ip6::Mess
|
||||
neighbor->mLinkInfo.Clear();
|
||||
neighbor->mLinkInfo.AddRss(threadMessageInfo->mRss);
|
||||
neighbor->mState = Neighbor::kStateValid;
|
||||
assert(aKeySequence == mKeyManager.GetCurrentKeySequence() ||
|
||||
aKeySequence == mKeyManager.GetPreviousKeySequence());
|
||||
neighbor->mPreviousKey = aKeySequence == mKeyManager.GetPreviousKeySequence();
|
||||
neighbor->mKeySequence = aKeySequence;
|
||||
|
||||
if (aRequest)
|
||||
{
|
||||
@@ -1181,7 +1179,6 @@ ThreadError MleRouter::HandleAdvertisement(const Message &aMessage, const Ip6::M
|
||||
router->mLinkInfo.Clear();
|
||||
router->mLinkInfo.AddRss(threadMessageInfo->mRss);
|
||||
router->mState = Neighbor::kStateLinkRequest;
|
||||
router->mPreviousKey = false;
|
||||
SendLinkRequest(router);
|
||||
ExitNow(error = kThreadError_NoRoute);
|
||||
}
|
||||
@@ -1209,7 +1206,6 @@ ThreadError MleRouter::HandleAdvertisement(const Message &aMessage, const Ip6::M
|
||||
router->mLinkInfo.AddRss(threadMessageInfo->mRss);
|
||||
router->mState = Neighbor::kStateLinkRequest;
|
||||
router->mDataRequest = false;
|
||||
router->mPreviousKey = false;
|
||||
SendLinkRequest(router);
|
||||
ExitNow(error = kThreadError_NoRoute);
|
||||
}
|
||||
@@ -1414,7 +1410,6 @@ ThreadError MleRouter::HandleParentRequest(const Message &aMessage, const Ip6::M
|
||||
child->mLinkInfo.AddRss(threadMessageInfo->mRss);
|
||||
child->mState = Neighbor::kStateParentRequest;
|
||||
child->mDataRequest = false;
|
||||
child->mPreviousKey = false;
|
||||
|
||||
child->mTimeout = Timer::SecToMsec(2 * kParentRequestChildTimeout);
|
||||
SuccessOrExit(error = SendParentResponse(child, challenge));
|
||||
@@ -1674,6 +1669,7 @@ ThreadError MleRouter::HandleChildIdRequest(const Message &aMessage, const Ip6::
|
||||
child->mLastHeard = Timer::GetNow();
|
||||
child->mValid.mLinkFrameCounter = linkFrameCounter.GetFrameCounter();
|
||||
child->mValid.mMleFrameCounter = mleFrameCounter.GetFrameCounter();
|
||||
child->mKeySequence = aKeySequence;
|
||||
child->mMode = mode.GetMode();
|
||||
child->mLinkInfo.AddRss(threadMessageInfo->mRss);
|
||||
child->mTimeout = timeout.GetTimeout();
|
||||
@@ -1689,10 +1685,6 @@ ThreadError MleRouter::HandleChildIdRequest(const Message &aMessage, const Ip6::
|
||||
|
||||
UpdateChildAddresses(address, *child);
|
||||
|
||||
assert(aKeySequence == mKeyManager.GetCurrentKeySequence() ||
|
||||
aKeySequence == mKeyManager.GetPreviousKeySequence());
|
||||
child->mPreviousKey = aKeySequence == mKeyManager.GetPreviousKeySequence();
|
||||
|
||||
for (uint8_t i = 0; i < tlvRequest.GetLength(); i++)
|
||||
{
|
||||
child->mRequestTlvs[i] = tlvRequest.GetTlvs()[i];
|
||||
|
||||
@@ -66,6 +66,8 @@ public:
|
||||
} mPending;
|
||||
};
|
||||
|
||||
uint32_t mKeySequence; ///< Current key sequence
|
||||
|
||||
/**
|
||||
* Neighbor link states.
|
||||
*
|
||||
@@ -78,11 +80,11 @@ public:
|
||||
kStateLinkRequest, ///< Sent a MLE Link Request message
|
||||
kStateValid, ///< Link is valid
|
||||
};
|
||||
|
||||
State mState : 3; ///< The link state
|
||||
uint8_t mMode : 4; ///< The MLE device mode
|
||||
bool mPreviousKey : 1; ///< Indicates whether or not the neighbor is still using a previous key
|
||||
bool mDataRequest : 1; ///< Indicates whether or not a Data Poll was received
|
||||
LinkQualityInfo mLinkInfo; ///< Link quality info (contains average RSS, link margin and link quality).
|
||||
LinkQualityInfo mLinkInfo; ///< Link quality info (contains average RSS, link margin and link quality)
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
Reference in New Issue
Block a user