diff --git a/include/platform/radio.h b/include/platform/radio.h index 540ad5379..cff96d58a 100644 --- a/include/platform/radio.h +++ b/include/platform/radio.h @@ -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; /** diff --git a/src/core/common/message.cpp b/src/core/common/message.cpp index 515e2299f..a96b48538 100644 --- a/src/core/common/message.cpp +++ b/src/core/common/message.cpp @@ -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; diff --git a/src/core/common/message.hpp b/src/core/common/message.hpp index ce3f81c43..af6d58fa4 100644 --- a/src/core/common/message.hpp +++ b/src/core/common/message.hpp @@ -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. * diff --git a/src/core/mac/mac.cpp b/src/core/mac/mac.cpp index 9c6626454..cb278e663 100644 --- a/src/core/mac/mac.cpp +++ b/src/core/mac/mac.cpp @@ -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; } diff --git a/src/core/mac/mac_frame.hpp b/src/core/mac/mac_frame.hpp index a88c5f656..9e7858463 100644 --- a/src/core/mac/mac_frame.hpp +++ b/src/core/mac/mac_frame.hpp @@ -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. * diff --git a/src/core/thread/mesh_forwarder.cpp b/src/core/thread/mesh_forwarder.cpp index 31edc196b..2cbc54aa6 100644 --- a/src/core/thread/mesh_forwarder.cpp +++ b/src/core/thread/mesh_forwarder.cpp @@ -37,6 +37,7 @@ #include #include #include +#include #include #include #include @@ -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(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(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, ;); diff --git a/src/core/thread/mesh_forwarder.hpp b/src/core/thread/mesh_forwarder.hpp index 682b119af..e59d05164 100644 --- a/src/core/thread/mesh_forwarder.hpp +++ b/src/core/thread/mesh_forwarder.hpp @@ -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); diff --git a/src/core/thread/thread_netif.hpp b/src/core/thread/thread_netif.hpp index 1e7c8dbe5..79c49512d 100644 --- a/src/core/thread/thread_netif.hpp +++ b/src/core/thread/thread_netif.hpp @@ -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. }; /**