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:
Jonathan Hui
2016-06-28 09:05:12 -07:00
committed by GitHub
parent f8effdd181
commit 1b16222f3d
6 changed files with 43 additions and 153 deletions
+19 -20
View File
@@ -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;
}
+8 -60
View File
@@ -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)
+2 -40
View File
@@ -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
View File
@@ -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:
+2 -10
View File
@@ -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];
+4 -2
View File
@@ -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)
};
/**