mirror of
https://github.com/espressif/openthread.git
synced 2026-08-01 08:37:47 +00:00
Do not blindly pass up unsecure frames from the link layer. (#68)
The following checks were added:
1) Any unsecure 6LoWPAN Mesh frames are dropped.
2) Any unsecure 6LoWPAN Fragment frames are only added to unsecure reassembly buffers.
3) Any unsecure MAC Data Poll frames are dropped.
4) Any unsecure IPv6 datagrams must have:
a) Destination with link-local scope,
b) Next Header set to UDP,
c) UDP Destination Port set to MLE,
d) Length long enough to carry IPv6 and UDP headers.
This commit is contained in:
@@ -97,6 +97,7 @@ typedef struct RadioPacket
|
||||
uint8_t mPsdu[kMaxPHYPacketSize]; ///< The PSDU.
|
||||
uint8_t mChannel; ///< Channel used to transmit/receive the frame.
|
||||
int8_t mPower; ///< Transmit/receive power in dBm.
|
||||
bool mSecurityValid; ///< Security Enabled flag is set and frame passes security checks.
|
||||
} RadioPacket;
|
||||
|
||||
/**
|
||||
|
||||
@@ -498,6 +498,16 @@ void Message::SetDirectTransmission(void)
|
||||
mInfo.mDirectTx = true;
|
||||
}
|
||||
|
||||
bool Message::GetSecurityValid(void) const
|
||||
{
|
||||
return mInfo.mSecurityValid;
|
||||
}
|
||||
|
||||
void Message::SetSecurityValid(bool aSecurityValid)
|
||||
{
|
||||
mInfo.mSecurityValid = aSecurityValid;
|
||||
}
|
||||
|
||||
uint16_t Message::UpdateChecksum(uint16_t aChecksum, uint16_t aOffset, uint16_t aLength) const
|
||||
{
|
||||
Buffer *curBuffer;
|
||||
|
||||
+29
-11
@@ -100,20 +100,21 @@ struct MessageInfo
|
||||
{
|
||||
enum
|
||||
{
|
||||
kListAll = 0, ///< Identifies the all messages list.
|
||||
kListInterface = 1, ///< Identifies the per-inteface message list.
|
||||
kListAll = 0, ///< Identifies the all messages list.
|
||||
kListInterface = 1, ///< Identifies the per-inteface message list.
|
||||
};
|
||||
MessageListEntry mList[2]; ///< Message lists.
|
||||
uint16_t mReserved; ///< Number of header bytes reserved for the message.
|
||||
uint16_t mLength; ///< Number of bytes within the message.
|
||||
uint16_t mOffset; ///< A byte offset within the message.
|
||||
uint16_t mDatagramTag; ///< The datagram tag used for 6LoWPAN fragmentation.
|
||||
uint8_t mTimeout; ///< Seconds remaining before dropping the message.
|
||||
MessageListEntry mList[2]; ///< Message lists.
|
||||
uint16_t mReserved; ///< Number of header bytes reserved for the message.
|
||||
uint16_t mLength; ///< Number of bytes within the message.
|
||||
uint16_t mOffset; ///< A byte offset within the message.
|
||||
uint16_t mDatagramTag; ///< The datagram tag used for 6LoWPAN fragmentation.
|
||||
uint8_t mTimeout; ///< Seconds remaining before dropping the message.
|
||||
|
||||
uint8_t mChildMask[8]; ///< A bit-vector to indicate which sleepy children need to receive this message.
|
||||
uint8_t mChildMask[8]; ///< A bit-vector to indicate which sleepy children need to receive this message.
|
||||
|
||||
uint8_t mType : 2; ///< Identifies the type of message.
|
||||
bool mDirectTx : 1; ///< Used to indicate whether a direct transmission is required.
|
||||
uint8_t mType : 2; ///< Identifies the type of message.
|
||||
bool mDirectTx : 1; ///< Used to indicate whether a direct transmission is required.
|
||||
bool mSecurityValid : 1; ///< Indicates whether received frames were secure and passed validation.
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -423,6 +424,23 @@ public:
|
||||
*/
|
||||
void SetDirectTransmission(void);
|
||||
|
||||
/**
|
||||
* This method indicates whether or not the message was secure and passed validation at the link layer.
|
||||
*
|
||||
* @retval TRUE If the message was secure and passed validation at the link layer.
|
||||
* @retval FALSE If the message was not secure or did not pass validation at the link layer.
|
||||
*
|
||||
*/
|
||||
bool GetSecurityValid(void) const;
|
||||
|
||||
/**
|
||||
* This method sets whether or not the message was secure and passed validation at the link layer.
|
||||
*
|
||||
* @param[in] aSecurityValid TRUE if the message was secure and passed link layer validation, FALSE otherwise.
|
||||
*
|
||||
*/
|
||||
void SetSecurityValid(bool aSecurityValid);
|
||||
|
||||
/**
|
||||
* This method is used to update a checksum value.
|
||||
*
|
||||
|
||||
@@ -672,6 +672,8 @@ ThreadError Mac::ProcessReceiveSecurity(const Address &aSrcAddr, Neighbor *aNeig
|
||||
const uint8_t *macKey;
|
||||
Crypto::AesCcm aesCcm;
|
||||
|
||||
mReceiveFrame.SetSecurityValid(false);
|
||||
|
||||
if (mReceiveFrame.GetSecurityEnabled() == false)
|
||||
{
|
||||
ExitNow();
|
||||
@@ -744,6 +746,8 @@ ThreadError Mac::ProcessReceiveSecurity(const Address &aSrcAddr, Neighbor *aNeig
|
||||
|
||||
aNeighbor->mValid.mLinkFrameCounter = frameCounter + 1;
|
||||
|
||||
mReceiveFrame.SetSecurityValid(true);
|
||||
|
||||
exit:
|
||||
return error;
|
||||
}
|
||||
|
||||
@@ -515,6 +515,23 @@ public:
|
||||
*/
|
||||
void SetPower(int8_t aPower) { mPower = aPower; }
|
||||
|
||||
/**
|
||||
* This method indicates whether or not frame security was enabled and passed security validation.
|
||||
*
|
||||
* @retval TRUE Frame security was enabled and passed security validation.
|
||||
* @retval FALSE Frame security was not enabled or did not pass security validation.
|
||||
*
|
||||
*/
|
||||
bool GetSecurityValid(void) const { return mSecurityValid; }
|
||||
|
||||
/**
|
||||
* This method sets the security valid attribute.
|
||||
*
|
||||
* @param[in] aSecurityValid TRUE if frame security was enabled and passed security validation, FALSE otherwise.
|
||||
*
|
||||
*/
|
||||
void SetSecurityValid(bool aSecurityValid) { mSecurityValid = aSecurityValid; }
|
||||
|
||||
/**
|
||||
* This method returns the IEEE 802.15.4 PSDU length.
|
||||
*
|
||||
|
||||
@@ -37,6 +37,7 @@
|
||||
#include <common/encoding.hpp>
|
||||
#include <common/message.hpp>
|
||||
#include <net/ip6.hpp>
|
||||
#include <net/udp6.hpp>
|
||||
#include <net/netif.hpp>
|
||||
#include <net/udp6.hpp>
|
||||
#include <platform/random.h>
|
||||
@@ -1014,6 +1015,7 @@ void MeshForwarder::HandleReceivedFrame(Mac::Frame &aFrame, ThreadError aError)
|
||||
|
||||
SuccessOrExit(aFrame.GetDstAddr(macDest));
|
||||
messageInfo.mLinkMargin = aFrame.GetPower() - -100;
|
||||
messageInfo.mSecurityValid = aFrame.GetSecurityValid();
|
||||
|
||||
payload = aFrame.GetPayload();
|
||||
payloadLength = aFrame.GetPayloadLength();
|
||||
@@ -1046,7 +1048,7 @@ void MeshForwarder::HandleReceivedFrame(Mac::Frame &aFrame, ThreadError aError)
|
||||
|
||||
if (commandId == Mac::Frame::kMacCmdDataRequest)
|
||||
{
|
||||
HandleDataRequest(macSource);
|
||||
HandleDataRequest(macSource, messageInfo);
|
||||
}
|
||||
|
||||
break;
|
||||
@@ -1064,7 +1066,8 @@ void MeshForwarder::HandleMesh(uint8_t *aFrame, uint8_t aFrameLength, const Thre
|
||||
Mac::Address meshSource;
|
||||
Lowpan::MeshHeader *meshHeader = reinterpret_cast<Lowpan::MeshHeader *>(aFrame);
|
||||
|
||||
VerifyOrExit(meshHeader->IsValid(), error = kThreadError_Drop);
|
||||
// Security Check: only process Mesh Header frames that had security enabled.
|
||||
VerifyOrExit(aMessageInfo.mSecurityValid && meshHeader->IsValid(), error = kThreadError_Drop);
|
||||
|
||||
meshSource.mLength = sizeof(meshSource.mShortAddress);
|
||||
meshSource.mShortAddress = meshHeader->GetSource();
|
||||
@@ -1098,6 +1101,7 @@ void MeshForwarder::HandleMesh(uint8_t *aFrame, uint8_t aFrameLength, const Thre
|
||||
VerifyOrExit((message = Message::New(Message::kType6lowpan, 0)) != NULL, error = kThreadError_Drop);
|
||||
SuccessOrExit(error = message->SetLength(aFrameLength));
|
||||
message->Write(0, aFrameLength, aFrame);
|
||||
message->SetSecurityValid(aMessageInfo.mSecurityValid);
|
||||
|
||||
SendMessage(*message);
|
||||
}
|
||||
@@ -1141,10 +1145,11 @@ void MeshForwarder::HandleFragment(uint8_t *aFrame, uint8_t aFrameLength,
|
||||
const Mac::Address &aMacSource, const Mac::Address &aMacDest,
|
||||
const ThreadMessageInfo &aMessageInfo)
|
||||
{
|
||||
ThreadError error = kThreadError_None;
|
||||
Lowpan::FragmentHeader *fragmentHeader = reinterpret_cast<Lowpan::FragmentHeader *>(aFrame);
|
||||
uint16_t datagramLength = fragmentHeader->GetDatagramSize();
|
||||
uint16_t datagramTag = fragmentHeader->GetDatagramTag();
|
||||
Message *message;
|
||||
Message *message = NULL;
|
||||
int headerLength;
|
||||
|
||||
if (fragmentHeader->GetDatagramOffset() == 0)
|
||||
@@ -1152,17 +1157,18 @@ void MeshForwarder::HandleFragment(uint8_t *aFrame, uint8_t aFrameLength,
|
||||
aFrame += fragmentHeader->GetHeaderLength();
|
||||
aFrameLength -= fragmentHeader->GetHeaderLength();
|
||||
|
||||
VerifyOrExit((message = Message::New(Message::kTypeIp6, 0)) != NULL, ;);
|
||||
VerifyOrExit((message = Message::New(Message::kTypeIp6, 0)) != NULL, error = kThreadError_NoBufs);
|
||||
headerLength = mLowpan.Decompress(*message, aMacSource, aMacDest, aFrame, aFrameLength, datagramLength);
|
||||
VerifyOrExit(headerLength > 0, Message::Free(*message));
|
||||
VerifyOrExit(headerLength > 0, error = kThreadError_NoBufs);
|
||||
aFrame += headerLength;
|
||||
aFrameLength -= headerLength;
|
||||
|
||||
VerifyOrExit(message->SetLength(datagramLength) == kThreadError_None, Message::Free(*message));
|
||||
VerifyOrExit(message->SetLength(datagramLength) == kThreadError_None, error = kThreadError_NoBufs);
|
||||
datagramLength = HostSwap16(datagramLength - sizeof(Ip6::Header));
|
||||
message->Write(Ip6::Header::GetPayloadLengthOffset(), sizeof(datagramLength), &datagramLength);
|
||||
message->SetDatagramTag(datagramTag);
|
||||
message->SetTimeout(kReassemblyTimeout);
|
||||
message->SetSecurityValid(aMessageInfo.mSecurityValid);
|
||||
|
||||
mReassemblyList.Enqueue(*message);
|
||||
|
||||
@@ -1178,9 +1184,11 @@ void MeshForwarder::HandleFragment(uint8_t *aFrame, uint8_t aFrameLength,
|
||||
|
||||
for (message = mReassemblyList.GetHead(); message; message = message->GetNext())
|
||||
{
|
||||
// Security Check: only consider reassembly buffers that had the same Security Enabled setting.
|
||||
if (message->GetLength() == datagramLength &&
|
||||
message->GetDatagramTag() == datagramTag &&
|
||||
message->GetOffset() == fragmentHeader->GetDatagramOffset())
|
||||
message->GetOffset() == fragmentHeader->GetDatagramOffset() &&
|
||||
message->GetSecurityValid() == aMessageInfo.mSecurityValid)
|
||||
{
|
||||
break;
|
||||
}
|
||||
@@ -1197,10 +1205,14 @@ void MeshForwarder::HandleFragment(uint8_t *aFrame, uint8_t aFrameLength,
|
||||
VerifyOrExit(message->GetOffset() >= message->GetLength(), ;);
|
||||
|
||||
mReassemblyList.Dequeue(*message);
|
||||
Ip6::Ip6::HandleDatagram(*message, &mNetif, mNetif.GetInterfaceId(), &aMessageInfo, false);
|
||||
SuccessOrExit(error = HandleDatagram(*message, aMessageInfo));
|
||||
|
||||
exit:
|
||||
{}
|
||||
|
||||
if (error != kThreadError_None && message != NULL)
|
||||
{
|
||||
Message::Free(*message);
|
||||
}
|
||||
}
|
||||
|
||||
void MeshForwarder::HandleReassemblyTimer(void *aContext)
|
||||
@@ -1258,25 +1270,57 @@ void MeshForwarder::HandleLowpanHC(uint8_t *aFrame, uint8_t aFrameLength,
|
||||
message->Write(Ip6::Header::GetPayloadLengthOffset(), sizeof(ip6PayloadLength), &ip6PayloadLength);
|
||||
|
||||
message->Write(message->GetOffset(), aFrameLength, aFrame);
|
||||
Ip6::Ip6::HandleDatagram(*message, &mNetif, mNetif.GetInterfaceId(), &aMessageInfo, false);
|
||||
message->SetSecurityValid(aMessageInfo.mSecurityValid);
|
||||
|
||||
SuccessOrExit(error = HandleDatagram(*message, aMessageInfo));
|
||||
|
||||
exit:
|
||||
|
||||
if (error != kThreadError_None)
|
||||
if (error != kThreadError_None && message != NULL)
|
||||
{
|
||||
Message::Free(*message);
|
||||
}
|
||||
}
|
||||
|
||||
ThreadError MeshForwarder::HandleDatagram(Message &aMessage, const ThreadMessageInfo &aMessageInfo)
|
||||
{
|
||||
ThreadError error = kThreadError_Drop;
|
||||
Ip6::Header ip6;
|
||||
Ip6::UdpHeader udp;
|
||||
|
||||
// Security Check: only pass up IPv6 datagrams that were received with Security Enabled or all of the following:
|
||||
// 1) Message contains IPv6 header
|
||||
// 2) IPv6 Destination has link-local scope
|
||||
// 3) IPv6 Next Header is UDP
|
||||
// 4) Message contains UDP header
|
||||
// 5) UDP Destination Port is the MLE port
|
||||
VerifyOrExit(aMessage.GetSecurityValid() ||
|
||||
(sizeof(ip6) == aMessage.Read(0, sizeof(ip6), &ip6) &&
|
||||
(ip6.GetDestination().IsLinkLocal() || ip6.GetDestination().IsLinkLocalMulticast()) &&
|
||||
ip6.GetNextHeader() == Ip6::kProtoUdp &&
|
||||
sizeof(udp) == aMessage.Read(sizeof(ip6), sizeof(udp), &udp) &&
|
||||
udp.GetDestinationPort() == Mle::kUdpPort),
|
||||
;);
|
||||
|
||||
Ip6::Ip6::HandleDatagram(aMessage, &mNetif, mNetif.GetInterfaceId(), &aMessageInfo, false);
|
||||
error = kThreadError_None;
|
||||
|
||||
exit:
|
||||
return error;
|
||||
}
|
||||
|
||||
void MeshForwarder::UpdateFramePending()
|
||||
{
|
||||
}
|
||||
|
||||
void MeshForwarder::HandleDataRequest(const Mac::Address &aMacSource)
|
||||
void MeshForwarder::HandleDataRequest(const Mac::Address &aMacSource, const ThreadMessageInfo &aMessageInfo)
|
||||
{
|
||||
Neighbor *neighbor;
|
||||
int childIndex;
|
||||
|
||||
// Security Check: only process secure Data Poll frames.
|
||||
VerifyOrExit(aMessageInfo.mSecurityValid, ;);
|
||||
|
||||
assert(mMle.GetDeviceState() != Mle::kDeviceStateDetached);
|
||||
|
||||
VerifyOrExit((neighbor = mMle.GetNeighbor(aMacSource)) != NULL, ;);
|
||||
|
||||
@@ -160,7 +160,7 @@ private:
|
||||
void HandleLowpanHC(uint8_t *aFrame, uint8_t aPayloadLength,
|
||||
const Mac::Address &aMacSource, const Mac::Address &aMacDest,
|
||||
const ThreadMessageInfo &aMessageInfo);
|
||||
void HandleDataRequest(const Mac::Address &aMacSource);
|
||||
void HandleDataRequest(const Mac::Address &aMacSource, const ThreadMessageInfo &aMessageInfo);
|
||||
void MoveToResolving(const Ip6::Address &aDestination);
|
||||
ThreadError SendPoll(Message &aMessage, Mac::Frame &aFrame);
|
||||
ThreadError SendMesh(Message &aMessage, Mac::Frame &aFrame);
|
||||
@@ -168,6 +168,7 @@ private:
|
||||
void UpdateFramePending(void);
|
||||
ThreadError UpdateIp6Route(Message &aMessage);
|
||||
ThreadError UpdateMeshRoute(Message &aMessage);
|
||||
ThreadError HandleDatagram(Message &aMessage, const ThreadMessageInfo &aMessageInfo);
|
||||
|
||||
static void HandleReceivedFrame(void *aContext, Mac::Frame &aFrame, ThreadError aError);
|
||||
void HandleReceivedFrame(Mac::Frame &aFrame, ThreadError aError);
|
||||
|
||||
@@ -215,7 +215,8 @@ private:
|
||||
*/
|
||||
struct ThreadMessageInfo
|
||||
{
|
||||
uint8_t mLinkMargin; ///< The Link Margin for a received message in dBm.
|
||||
uint8_t mLinkMargin; ///< The Link Margin for a received message in dBm.
|
||||
bool mSecurityValid; ///< Link security on all received frames was enabled and passed validation.
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
Reference in New Issue
Block a user