[mle] simplify security header processing (#7615)

This commit simplifies the MLE header processing. It defines
the `SecurityHeader` to represent the aux security header used
by MLE messages (when security suite is set to `k154Security`).
With this change the initial `SecuitySuite` and the MLE `Command`
fields are parsed and appended separately.
This commit is contained in:
Abtin Keshavarzian
2022-04-22 14:14:47 -07:00
committed by GitHub
parent f9e8b266f7
commit 8069b958d9
2 changed files with 88 additions and 139 deletions
+74 -65
View File
@@ -1048,23 +1048,34 @@ exit:
Error Mle::AppendHeader(Message &aMessage, Command aCommand)
{
Error error = kErrorNone;
Header header;
Error error = kErrorNone;
uint8_t securitySuite = k154Security;
header.Init();
switch (aCommand)
{
case kCommandDiscoveryRequest:
case kCommandDiscoveryResponse:
securitySuite = kNoSecurity;
break;
if (aCommand == kCommandDiscoveryRequest || aCommand == kCommandDiscoveryResponse)
{
header.SetSecuritySuite(Header::kNoSecurity);
}
else
{
header.SetKeyIdMode2();
default:
break;
}
header.SetCommand(aCommand);
SuccessOrExit(error = aMessage.Append(securitySuite));
SuccessOrExit(error = aMessage.AppendBytes(&header, header.GetLength()));
if (securitySuite == k154Security)
{
SecurityHeader securityHeader;
// The other fields in security header are updated in the
// message in `SendMessage()` before message is sent.
securityHeader.InitSecurityControl();
SuccessOrExit(error = aMessage.Append(securityHeader));
}
error = aMessage.Append<uint8_t>(aCommand);
exit:
return error;
@@ -2676,41 +2687,42 @@ exit:
Error Mle::SendMessage(Message &aMessage, const Ip6::Address &aDestination)
{
Error error = kErrorNone;
Header header;
Error error = kErrorNone;
uint16_t offset = 0;
uint8_t securitySuite;
Ip6::MessageInfo messageInfo;
IgnoreError(aMessage.Read(0, header));
IgnoreError(aMessage.Read(offset, securitySuite));
offset += sizeof(securitySuite);
if (header.GetSecuritySuite() == Header::k154Security)
if (securitySuite == k154Security)
{
uint32_t keySequence;
SecurityHeader header;
uint8_t nonce[Crypto::AesCcm::kNonceSize];
uint8_t tag[kMleSecurityTagSize];
Crypto::AesCcm aesCcm;
IgnoreError(aMessage.Read(offset, header));
header.SetFrameCounter(Get<KeyManager>().GetMleFrameCounter());
header.SetKeyId(Get<KeyManager>().GetCurrentKeySequence());
keySequence = Get<KeyManager>().GetCurrentKeySequence();
header.SetKeyId(keySequence);
aMessage.WriteBytes(0, &header, header.GetLength());
aMessage.Write(offset, header);
offset += sizeof(SecurityHeader);
Crypto::AesCcm::GenerateNonce(Get<Mac::Mac>().GetExtAddress(), Get<KeyManager>().GetMleFrameCounter(),
Mac::Frame::kSecEncMic32, nonce);
aesCcm.SetKey(Get<KeyManager>().GetCurrentMleKey());
aesCcm.Init(16 + 16 + header.GetHeaderLength(), aMessage.GetLength() - (header.GetLength() - 1), sizeof(tag),
nonce, sizeof(nonce));
aesCcm.Init(sizeof(Ip6::Address) + sizeof(Ip6::Address) + sizeof(SecurityHeader), aMessage.GetLength() - offset,
kMleSecurityTagSize, nonce, sizeof(nonce));
aesCcm.Header(mLinkLocal64.GetAddress());
aesCcm.Header(aDestination);
aesCcm.Header(header.GetBytes() + 1, header.GetHeaderLength());
aesCcm.Header(header);
aMessage.SetOffset(header.GetLength() - 1);
aesCcm.Payload(aMessage, aMessage.GetOffset(), aMessage.GetLength() - aMessage.GetOffset(),
Crypto::AesCcm::kEncrypt);
aesCcm.Payload(aMessage, offset, aMessage.GetLength() - offset, Crypto::AesCcm::kEncrypt);
aesCcm.Finalize(tag);
SuccessOrExit(error = aMessage.Append(tag));
@@ -2753,41 +2765,40 @@ void Mle::HandleUdpReceive(void *aContext, otMessage *aMessage, const otMessageI
void Mle::HandleUdpReceive(Message &aMessage, const Ip6::MessageInfo &aMessageInfo)
{
Error error = kErrorNone;
Header header;
uint32_t keySequence;
const KeyMaterial *mleKey;
uint32_t frameCounter;
uint8_t messageTag[kMleSecurityTagSize];
uint8_t nonce[Crypto::AesCcm::kNonceSize];
Mac::ExtAddress extAddr;
Crypto::AesCcm aesCcm;
uint16_t length;
uint8_t tag[kMleSecurityTagSize];
uint8_t command;
Neighbor * neighbor;
bool skipLoggingError = false;
Error error = kErrorNone;
uint8_t securitySuite;
SecurityHeader header;
uint32_t keySequence;
uint32_t frameCounter;
uint8_t messageTag[kMleSecurityTagSize];
uint8_t nonce[Crypto::AesCcm::kNonceSize];
Mac::ExtAddress extAddr;
Crypto::AesCcm aesCcm;
uint8_t tag[kMleSecurityTagSize];
uint8_t command;
Neighbor * neighbor;
bool skipLoggingError = false;
LogDebg("Receive UDP message");
LogDebg("Receive MLE message");
VerifyOrExit(aMessageInfo.GetLinkInfo() != nullptr);
VerifyOrExit(aMessageInfo.GetHopLimit() == kMleHopLimit, error = kErrorParse);
length = aMessage.ReadBytes(aMessage.GetOffset(), &header, sizeof(header));
VerifyOrExit(header.IsValid() && header.GetLength() <= length, error = kErrorParse);
SuccessOrExit(error = aMessage.Read(aMessage.GetOffset(), securitySuite));
aMessage.MoveOffset(sizeof(securitySuite));
if (header.GetSecuritySuite() == Header::kNoSecurity)
if (securitySuite == kNoSecurity)
{
aMessage.MoveOffset(header.GetLength());
SuccessOrExit(error = aMessage.Read(aMessage.GetOffset(), command));
aMessage.MoveOffset(sizeof(command));
switch (header.GetCommand())
switch (command)
{
#if OPENTHREAD_FTD
case kCommandDiscoveryRequest:
Get<MleRouter>().HandleDiscoveryRequest(aMessage, aMessageInfo);
break;
#endif
case kCommandDiscoveryResponse:
Get<DiscoverScanner>().HandleDiscoveryResponse(aMessage, aMessageInfo);
break;
@@ -2800,38 +2811,36 @@ void Mle::HandleUdpReceive(Message &aMessage, const Ip6::MessageInfo &aMessageIn
}
VerifyOrExit(!IsDisabled(), error = kErrorInvalidState);
VerifyOrExit(header.GetSecuritySuite() == Header::k154Security, error = kErrorParse);
VerifyOrExit(securitySuite == k154Security, error = kErrorParse);
keySequence = header.GetKeyId();
SuccessOrExit(error = aMessage.Read(aMessage.GetOffset(), header));
aMessage.MoveOffset(sizeof(header));
if (keySequence == Get<KeyManager>().GetCurrentKeySequence())
{
mleKey = &Get<KeyManager>().GetCurrentMleKey();
}
else
{
mleKey = &Get<KeyManager>().GetTemporaryMleKey(keySequence);
}
VerifyOrExit(header.IsSecurityControlValid(), error = kErrorParse);
VerifyOrExit(aMessage.GetOffset() + header.GetLength() + sizeof(messageTag) <= aMessage.GetLength(),
keySequence = header.GetKeyId();
frameCounter = header.GetFrameCounter();
VerifyOrExit(aMessage.GetOffset() + sizeof(command) + sizeof(messageTag) <= aMessage.GetLength(),
error = kErrorParse);
aMessage.MoveOffset(header.GetLength() - 1);
IgnoreError(aMessage.Read(aMessage.GetLength() - sizeof(messageTag), messageTag));
SuccessOrExit(error = aMessage.SetLength(aMessage.GetLength() - sizeof(messageTag)));
aMessageInfo.GetPeerAddr().GetIid().ConvertToExtAddress(extAddr);
frameCounter = header.GetFrameCounter();
Crypto::AesCcm::GenerateNonce(extAddr, frameCounter, Mac::Frame::kSecEncMic32, nonce);
aesCcm.SetKey(*mleKey);
aesCcm.Init(sizeof(aMessageInfo.GetPeerAddr()) + sizeof(aMessageInfo.GetSockAddr()) + header.GetHeaderLength(),
aesCcm.SetKey((keySequence == Get<KeyManager>().GetCurrentKeySequence())
? Get<KeyManager>().GetCurrentMleKey()
: Get<KeyManager>().GetTemporaryMleKey(keySequence));
aesCcm.Init(sizeof(Ip6::Address) + sizeof(Ip6::Address) + sizeof(SecurityHeader),
aMessage.GetLength() - aMessage.GetOffset(), sizeof(messageTag), nonce, sizeof(nonce));
aesCcm.Header(aMessageInfo.GetPeerAddr());
aesCcm.Header(aMessageInfo.GetSockAddr());
aesCcm.Header(header.GetBytes() + 1, header.GetHeaderLength());
aesCcm.Header(header);
#ifndef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
aesCcm.Payload(aMessage, aMessage.GetOffset(), aMessage.GetLength() - aMessage.GetOffset(),
+14 -74
View File
@@ -1680,6 +1680,12 @@ private:
kDataRequestActive, // Data Request has been sent, Data Response is expected.
};
enum SecuritySuite : uint8_t
{
k154Security = 0, // Security suite value indicating that MLE message is not secured.
kNoSecurity = 255, // Security suite value indicating that MLE message is secured.
};
struct DelayedResponseMetadata
{
Error AppendTo(Message &aMessage) const { return aMessage.Append(*this); }
@@ -1691,95 +1697,29 @@ private:
};
OT_TOOL_PACKED_BEGIN
class Header
class SecurityHeader
{
public:
enum SecuritySuite : uint8_t
{
k154Security = 0,
kNoSecurity = 255,
};
void InitSecurityControl(void) { mSecurityControl = kKeyIdMode2Mic32; }
bool IsSecurityControlValid(void) const { return (mSecurityControl == kKeyIdMode2Mic32); }
void Init(void)
{
mSecuritySuite = k154Security;
mSecurityControl = Mac::Frame::kSecEncMic32;
}
bool IsValid(void) const
{
return (mSecuritySuite == kNoSecurity) ||
(mSecuritySuite == k154Security &&
mSecurityControl == (Mac::Frame::kKeyIdMode2 | Mac::Frame::kSecEncMic32));
}
uint8_t GetLength(void) const
{
return sizeof(mSecuritySuite) + sizeof(mCommand) +
((mSecuritySuite == k154Security)
? sizeof(mSecurityControl) + sizeof(mFrameCounter) + sizeof(mKeySource) + sizeof(mKeyIndex)
: 0);
}
SecuritySuite GetSecuritySuite(void) const { return static_cast<SecuritySuite>(mSecuritySuite); }
void SetSecuritySuite(SecuritySuite aSecuritySuite) { mSecuritySuite = static_cast<uint8_t>(aSecuritySuite); }
uint8_t GetHeaderLength(void) const
{
return sizeof(mSecurityControl) + sizeof(mFrameCounter) + sizeof(mKeySource) + sizeof(mKeyIndex);
}
const uint8_t *GetBytes(void) const { return reinterpret_cast<const uint8_t *>(&mSecuritySuite); }
uint8_t GetSecurityControl(void) const { return mSecurityControl; }
bool IsKeyIdMode2(void) const
{
return (mSecurityControl & Mac::Frame::kKeyIdModeMask) == Mac::Frame::kKeyIdMode2;
}
void SetKeyIdMode2(void)
{
mSecurityControl = (mSecurityControl & ~Mac::Frame::kKeyIdModeMask) | Mac::Frame::kKeyIdMode2;
}
uint32_t GetFrameCounter(void) const { return Encoding::LittleEndian::HostSwap32(mFrameCounter); }
void SetFrameCounter(uint32_t aCounter) { mFrameCounter = Encoding::LittleEndian::HostSwap32(aCounter); }
uint32_t GetKeyId(void) const { return Encoding::BigEndian::HostSwap32(mKeySource); }
void SetKeyId(uint32_t aKeySequence)
void SetKeyId(uint32_t aKeySequence)
{
mKeySource = Encoding::BigEndian::HostSwap32(aKeySequence);
mKeyIndex = (aKeySequence & 0x7f) + 1;
}
uint32_t GetFrameCounter(void) const { return Encoding::LittleEndian::HostSwap32(mFrameCounter); }
void SetFrameCounter(uint32_t aFrameCounter)
{
mFrameCounter = Encoding::LittleEndian::HostSwap32(aFrameCounter);
}
Command GetCommand(void) const
{
return static_cast<Command>((mSecuritySuite == kNoSecurity) ? mSecurityControl : mCommand);
}
void SetCommand(Command aCommand)
{
if (mSecuritySuite == kNoSecurity)
{
mSecurityControl = static_cast<uint8_t>(aCommand);
}
else
{
mCommand = static_cast<uint8_t>(aCommand);
}
}
private:
uint8_t mSecuritySuite;
static constexpr uint8_t kKeyIdMode2Mic32 = (Mac::Frame::kKeyIdMode2 | Mac::Frame::kSecEncMic32);
uint8_t mSecurityControl;
uint32_t mFrameCounter;
uint32_t mKeySource;
uint8_t mKeyIndex;
uint8_t mCommand;
} OT_TOOL_PACKED_END;
#if OPENTHREAD_CONFIG_TMF_NETDATA_SERVICE_ENABLE