[border-agent] use separate DTLS transport and CoAP secure session (#11085)

This commit updates `BorderAgent` to utilize its own DTLS `Transport`
and CoAP `SecureSession`, separating it from the shared
`Tmf::SecureAgent` used by `Commissioner` and `Joiner` modules. This
change enables future support for multiple sessions within
`BorderAgent`.
This commit is contained in:
Abtin Keshavarzian
2024-12-27 16:53:29 -08:00
committed by GitHub
parent 6bb4b7c98d
commit 1024a1fdb9
4 changed files with 119 additions and 96 deletions
+81 -56
View File
@@ -50,6 +50,7 @@ BorderAgent::BorderAgent(Instance &aInstance)
, mState(kStateStopped)
, mUdpReceiver(BorderAgent::HandleUdpReceive, this)
, mTimer(aInstance)
, mDtlsTransport(aInstance, kNoLinkSecurity)
#if OPENTHREAD_CONFIG_BORDER_AGENT_ID_ENABLE
, mIdInitialized(false)
#endif
@@ -122,17 +123,20 @@ Error BorderAgent::Start(uint16_t aUdpPort, const uint8_t *aPsk, uint8_t aPskLen
#if OPENTHREAD_CONFIG_BORDER_AGENT_EPHEMERAL_KEY_ENABLE
if (mUsingEphemeralKey)
{
SuccessOrExit(error = Get<Tmf::SecureAgent>().SetMaxConnectionAttempts(kMaxEphemeralKeyConnectionAttempts,
HandleSecureAgentStopped, this));
SuccessOrExit(error = mDtlsTransport.SetMaxConnectionAttempts(kMaxEphemeralKeyConnectionAttempts,
HandleDtlsTransportClosed, this));
}
#endif
SuccessOrExit(error = Get<Tmf::SecureAgent>().Open());
SuccessOrExit(error = Get<Tmf::SecureAgent>().Bind(aUdpPort));
mCoapDtlsSession.Reset(CoapDtlsSession::Allocate(GetInstance(), mDtlsTransport));
VerifyOrExit(mCoapDtlsSession != nullptr, error = kErrorNoBufs);
SuccessOrExit(error = Get<Tmf::SecureAgent>().SetPsk(aPsk, aPskLength));
SuccessOrExit(error = mDtlsTransport.Open());
SuccessOrExit(error = mDtlsTransport.Bind(aUdpPort));
Get<Tmf::SecureAgent>().SetConnectCallback(HandleConnected, this);
SuccessOrExit(error = mDtlsTransport.SetPsk(aPsk, aPskLength));
mCoapDtlsSession->SetConnectCallback(HandleConnected, this);
mState = kStateStarted;
@@ -157,7 +161,8 @@ void BorderAgent::Stop(void)
#endif
mTimer.Stop();
Get<Tmf::SecureAgent>().Close();
mDtlsTransport.Close();
mCoapDtlsSession.Free();
mState = kStateStopped;
LogInfo("Border Agent stopped");
@@ -170,13 +175,13 @@ void BorderAgent::Disconnect(void)
{
VerifyOrExit(mState == kStateConnected || mState == kStateAccepted);
Get<Tmf::SecureAgent>().Disconnect();
mCoapDtlsSession->Disconnect();
exit:
return;
}
uint16_t BorderAgent::GetUdpPort(void) const { return Get<Tmf::SecureAgent>().GetUdpPort(); }
uint16_t BorderAgent::GetUdpPort(void) const { return mDtlsTransport.GetUdpPort(); }
void BorderAgent::HandleNotifierEvents(Events aEvents)
{
@@ -212,7 +217,7 @@ void BorderAgent::HandleNotifierEvents(Events aEvents)
// If there is secure session already established, it won't be impacted,
// new pskc will be applied for next connection.
SuccessOrExit(Get<Tmf::SecureAgent>().SetPsk(pskc.m8, Pskc::kSize));
SuccessOrExit(mDtlsTransport.SetPsk(pskc.m8, Pskc::kSize));
pskc.Clear();
}
}
@@ -223,9 +228,9 @@ exit:
void BorderAgent::HandleTimeout(void)
{
if (Get<Tmf::SecureAgent>().IsConnected())
if (mCoapDtlsSession->IsConnected())
{
Get<Tmf::SecureAgent>().Disconnect();
mCoapDtlsSession->Disconnect();
LogWarn("Reset secure session");
}
}
@@ -287,14 +292,7 @@ void BorderAgent::HandleConnected(Dtls::Session::ConnectEvent aEvent)
}
}
template <>
void BorderAgent::HandleTmf<kUriCommissionerPetition>(Coap::Message &aMessage, const Ip6::MessageInfo &aMessageInfo)
{
IgnoreError(ForwardToLeader(aMessage, aMessageInfo, kUriLeaderPetition));
}
template <>
void BorderAgent::HandleTmf<kUriCommissionerKeepAlive>(Coap::Message &aMessage, const Ip6::MessageInfo &aMessageInfo)
void BorderAgent::HandleTmfCommissionerKeepAlive(Coap::Message &aMessage, const Ip6::MessageInfo &aMessageInfo)
{
VerifyOrExit(mState == kStateAccepted);
@@ -332,7 +330,7 @@ Error BorderAgent::ForwardToLeader(const Coap::Message &aMessage, const Ip6::Mes
if (separate)
{
SuccessOrExit(error = Get<Tmf::SecureAgent>().SendAck(aMessage, aMessageInfo));
SuccessOrExit(error = mCoapDtlsSession->SendAck(aMessage, aMessageInfo));
}
forwardContext.Reset(ForwardContext::AllocateAndInit(GetInstance(), aMessage, petition, separate));
@@ -390,7 +388,7 @@ void BorderAgent::HandleCoapResponse(const ForwardContext &aForwardContext,
Error error;
SuccessOrExit(error = aResult);
VerifyOrExit((message = Get<Tmf::SecureAgent>().NewPriorityMessage()) != nullptr, error = kErrorNoBufs);
VerifyOrExit((message = mCoapDtlsSession->NewPriorityMessage()) != nullptr, error = kErrorNoBufs);
if (aForwardContext.IsPetition() && aResponse->GetCode() == Coap::kCodeChanged)
{
@@ -470,7 +468,7 @@ bool BorderAgent::HandleUdpReceive(const Message &aMessage, const Ip6::MessageIn
VerifyOrExit(aMessage.GetLength() > 0);
message = Get<Tmf::SecureAgent>().NewPriorityNonConfirmablePostMessage(kUriProxyRx);
message = mCoapDtlsSession->NewPriorityNonConfirmablePostMessage(kUriProxyRx);
VerifyOrExit(message != nullptr, error = kErrorNoBufs);
offsetRange.InitFromMessageOffsetToEnd(aMessage);
@@ -487,7 +485,7 @@ bool BorderAgent::HandleUdpReceive(const Message &aMessage, const Ip6::MessageIn
SuccessOrExit(error = Tlv::Append<Ip6AddressTlv>(*message, aMessageInfo.GetPeerAddr()));
SuccessOrExit(error = SendMessage(*message));
SuccessOrExit(error = mCoapDtlsSession->SendMessage(*message));
LogInfo("Sent ProxyRx (c/ur) to commissioner");
@@ -506,7 +504,7 @@ Error BorderAgent::ForwardToCommissioner(Coap::Message &aForwardMessage, const M
offsetRange.InitFromMessageOffsetToEnd(aMessage);
SuccessOrExit(error = aForwardMessage.AppendBytesFromMessage(aMessage, offsetRange));
SuccessOrExit(error = SendMessage(aForwardMessage));
SuccessOrExit(error = mCoapDtlsSession->SendMessage(aForwardMessage));
LogInfo("Sent to commissioner");
@@ -515,16 +513,14 @@ exit:
return error;
}
Error BorderAgent::SendMessage(Coap::Message &aMessage) { return Get<Tmf::SecureAgent>().SendMessage(aMessage); }
void BorderAgent::SendErrorMessage(const ForwardContext &aForwardContext, Error aError)
{
Error error = kErrorNone;
Coap::Message *message = nullptr;
VerifyOrExit((message = Get<Tmf::SecureAgent>().NewPriorityMessage()) != nullptr, error = kErrorNoBufs);
VerifyOrExit((message = mCoapDtlsSession->NewPriorityMessage()) != nullptr, error = kErrorNoBufs);
SuccessOrExit(error = aForwardContext.ToHeader(*message, CoapCodeFromError(aError)));
SuccessOrExit(error = SendMessage(*message));
SuccessOrExit(error = mCoapDtlsSession->SendMessage(*message));
exit:
FreeMessageOnError(message, error);
@@ -536,7 +532,7 @@ void BorderAgent::SendErrorMessage(const Coap::Message &aRequest, bool aSeparate
Error error = kErrorNone;
Coap::Message *message = nullptr;
VerifyOrExit((message = Get<Tmf::SecureAgent>().NewPriorityMessage()) != nullptr, error = kErrorNoBufs);
VerifyOrExit((message = mCoapDtlsSession->NewPriorityMessage()) != nullptr, error = kErrorNoBufs);
if (aRequest.IsNonConfirmable() || aSeparate)
{
@@ -554,7 +550,7 @@ void BorderAgent::SendErrorMessage(const Coap::Message &aRequest, bool aSeparate
SuccessOrExit(error = message->SetTokenFromMessage(aRequest));
SuccessOrExit(error = SendMessage(*message));
SuccessOrExit(error = mCoapDtlsSession->SendMessage(*message));
exit:
FreeMessageOnError(message, error);
@@ -596,7 +592,7 @@ template <> void BorderAgent::HandleTmf<kUriRelayRx>(Coap::Message &aMessage, co
VerifyOrExit(aMessage.IsNonConfirmablePostRequest(), error = kErrorDrop);
message = Get<Tmf::SecureAgent>().NewPriorityNonConfirmablePostMessage(kUriRelayRx);
message = mCoapDtlsSession->NewPriorityNonConfirmablePostMessage(kUriRelayRx);
VerifyOrExit(message != nullptr, error = kErrorNoBufs);
SuccessOrExit(error = ForwardToCommissioner(*message, aMessage));
@@ -606,7 +602,7 @@ exit:
FreeMessageOnError(message, error);
}
template <> void BorderAgent::HandleTmf<kUriProxyTx>(Coap::Message &aMessage, const Ip6::MessageInfo &aMessageInfo)
void BorderAgent::HandleTmfProxyTx(Coap::Message &aMessage, const Ip6::MessageInfo &aMessageInfo)
{
OT_UNUSED_VARIABLE(aMessageInfo);
@@ -643,25 +639,7 @@ exit:
LogWarnOnError(error, "send proxy stream");
}
template <>
void BorderAgent::HandleTmf<kUriCommissionerGet>(Coap::Message &aMessage, const Ip6::MessageInfo &aMessageInfo)
{
HandleTmfDatasetGet(aMessage, aMessageInfo, kUriCommissionerGet);
}
template <> void BorderAgent::HandleTmf<kUriActiveGet>(Coap::Message &aMessage, const Ip6::MessageInfo &aMessageInfo)
{
HandleTmfDatasetGet(aMessage, aMessageInfo, kUriActiveGet);
mCounters.mMgmtActiveGets++;
}
template <> void BorderAgent::HandleTmf<kUriPendingGet>(Coap::Message &aMessage, const Ip6::MessageInfo &aMessageInfo)
{
HandleTmfDatasetGet(aMessage, aMessageInfo, kUriPendingGet);
mCounters.mMgmtPendingGets++;
}
template <> void BorderAgent::HandleTmf<kUriRelayTx>(Coap::Message &aMessage, const Ip6::MessageInfo &aMessageInfo)
void BorderAgent::HandleTmfRelayTx(Coap::Message &aMessage, const Ip6::MessageInfo &aMessageInfo)
{
OT_UNUSED_VARIABLE(aMessageInfo);
@@ -710,10 +688,12 @@ void BorderAgent::HandleTmfDatasetGet(Coap::Message &aMessage, const Ip6::Messag
{
case kUriActiveGet:
response = Get<ActiveDatasetManager>().ProcessGetRequest(aMessage, DatasetManager::kIgnoreSecurityPolicyFlags);
mCounters.mMgmtActiveGets++;
break;
case kUriPendingGet:
response = Get<PendingDatasetManager>().ProcessGetRequest(aMessage, DatasetManager::kIgnoreSecurityPolicyFlags);
mCounters.mMgmtPendingGets++;
break;
case kUriCommissionerGet:
@@ -726,7 +706,7 @@ void BorderAgent::HandleTmfDatasetGet(Coap::Message &aMessage, const Ip6::Messag
VerifyOrExit(response != nullptr, error = kErrorParse);
SuccessOrExit(error = Get<Tmf::SecureAgent>().SendMessage(*response));
SuccessOrExit(error = mCoapDtlsSession->SendMessage(*response));
LogInfo("Sent %s response to non-active commissioner", PathForUri(aUri));
@@ -846,12 +826,12 @@ void BorderAgent::RestartAfterRemovingEphemeralKey(void)
IgnoreError(Start(mOldUdpPort));
}
void BorderAgent::HandleSecureAgentStopped(void *aContext)
void BorderAgent::HandleDtlsTransportClosed(void *aContext)
{
reinterpret_cast<BorderAgent *>(aContext)->HandleSecureAgentStopped();
reinterpret_cast<BorderAgent *>(aContext)->HandleDtlsTransportClosed();
}
void BorderAgent::HandleSecureAgentStopped(void)
void BorderAgent::HandleDtlsTransportClosed(void)
{
LogInfo("Reached max allowed connection attempts with ephemeral key");
mCounters.mEpskcDeactivationMaxAttempts++;
@@ -860,6 +840,51 @@ void BorderAgent::HandleSecureAgentStopped(void)
#endif // OPENTHREAD_CONFIG_BORDER_AGENT_EPHEMERAL_KEY_ENABLE
//----------------------------------------------------------------------------------------------------------------------
// `BorderAgent::CoapDtlsSession
bool BorderAgent::CoapDtlsSession::HandleResource(CoapBase &aCoapBase,
const char *aUriPath,
Coap::Message &aMessage,
const Ip6::MessageInfo &aMessageInfo)
{
return static_cast<CoapDtlsSession &>(aCoapBase).HandleResource(aUriPath, aMessage, aMessageInfo);
}
bool BorderAgent::CoapDtlsSession::HandleResource(const char *aUriPath,
Coap::Message &aMessage,
const Ip6::MessageInfo &aMessageInfo)
{
bool didHandle = true;
Uri uri = UriFromPath(aUriPath);
switch (uri)
{
case kUriCommissionerPetition:
IgnoreError(Get<BorderAgent>().ForwardToLeader(aMessage, aMessageInfo, kUriLeaderPetition));
break;
case kUriCommissionerKeepAlive:
Get<BorderAgent>().HandleTmfCommissionerKeepAlive(aMessage, aMessageInfo);
break;
case kUriRelayTx:
Get<BorderAgent>().HandleTmfRelayTx(aMessage, aMessageInfo);
break;
case kUriCommissionerGet:
case kUriActiveGet:
case kUriPendingGet:
Get<BorderAgent>().HandleTmfDatasetGet(aMessage, aMessageInfo, uri);
break;
case kUriProxyTx:
Get<BorderAgent>().HandleTmfProxyTx(aMessage, aMessageInfo);
break;
default:
didHandle = false;
break;
}
return didHandle;
}
//----------------------------------------------------------------------------------------------------------------------
// `BorderAgent::ForwardContext`
+26 -11
View File
@@ -45,6 +45,7 @@
#include "common/locator.hpp"
#include "common/non_copyable.hpp"
#include "common/notifier.hpp"
#include "common/owned_ptr.hpp"
#include "common/tasklet.hpp"
#include "meshcop/dataset.hpp"
#include "meshcop/secure_transport.hpp"
@@ -64,7 +65,6 @@ class BorderAgent : public InstanceLocator, private NonCopyable
{
friend class ot::Notifier;
friend class Tmf::Agent;
friend class Tmf::SecureAgent;
public:
/**
@@ -258,6 +258,24 @@ private:
static constexpr uint16_t kMaxEphemeralKeyConnectionAttempts = 10;
#endif
class CoapDtlsSession : public Coap::SecureSession, public Heap::Allocatable<CoapDtlsSession>
{
friend Heap::Allocatable<CoapDtlsSession>;
private:
CoapDtlsSession(Instance &aInstance, Dtls::Transport &aDtlsTransport)
: Coap::SecureSession(aInstance, aDtlsTransport)
{
SetResourceHandler(&HandleResource);
}
static bool HandleResource(CoapBase &aCoapBase,
const char *aUriPath,
Coap::Message &aMessage,
const Ip6::MessageInfo &aMessageInfo);
bool HandleResource(const char *aUriPath, Coap::Message &aMessage, const Ip6::MessageInfo &aMessageInfo);
};
class ForwardContext : public InstanceLocatorInit, public Heap::Allocatable<ForwardContext>
{
public:
@@ -281,9 +299,11 @@ private:
void HandleTimeout(void);
Error ForwardToLeader(const Coap::Message &aMessage, const Ip6::MessageInfo &aMessageInfo, Uri aUri);
Error ForwardToCommissioner(Coap::Message &aForwardMessage, const Message &aMessage);
Error SendMessage(Coap::Message &aMessage);
void SendErrorMessage(const ForwardContext &aForwardContext, Error aError);
void SendErrorMessage(const Coap::Message &aRequest, bool aSeparate, Error aError);
void HandleTmfCommissionerKeepAlive(Coap::Message &aMessage, const Ip6::MessageInfo &aMessageInfo);
void HandleTmfRelayTx(Coap::Message &aMessage, const Ip6::MessageInfo &aMessageInfo);
void HandleTmfProxyTx(Coap::Message &aMessage, const Ip6::MessageInfo &aMessageInfo);
void HandleTmfDatasetGet(Coap::Message &aMessage, const Ip6::MessageInfo &aMessageInfo, Uri aUri);
template <Uri kUri> void HandleTmf(Coap::Message &aMessage, const Ip6::MessageInfo &aMessageInfo);
@@ -304,8 +324,8 @@ private:
void RestartAfterRemovingEphemeralKey(void);
void HandleEphemeralKeyTimeout(void);
void InvokeEphemeralKeyCallback(void);
static void HandleSecureAgentStopped(void *aContext);
void HandleSecureAgentStopped(void);
static void HandleDtlsTransportClosed(void *aContext);
void HandleDtlsTransportClosed(void);
#endif
using TimeoutTimer = TimerMilliIn<BorderAgent, &BorderAgent::HandleTimeout>;
@@ -318,6 +338,8 @@ private:
Ip6::Udp::Receiver mUdpReceiver;
Ip6::Netif::UnicastAddress mCommissionerAloc;
TimeoutTimer mTimer;
Dtls::Transport mDtlsTransport;
OwnedPtr<CoapDtlsSession> mCoapDtlsSession;
#if OPENTHREAD_CONFIG_BORDER_AGENT_ID_ENABLE
Id mId;
bool mIdInitialized;
@@ -333,13 +355,6 @@ private:
};
DeclareTmfHandler(BorderAgent, kUriRelayRx);
DeclareTmfHandler(BorderAgent, kUriCommissionerPetition);
DeclareTmfHandler(BorderAgent, kUriCommissionerKeepAlive);
DeclareTmfHandler(BorderAgent, kUriRelayTx);
DeclareTmfHandler(BorderAgent, kUriCommissionerGet);
DeclareTmfHandler(BorderAgent, kUriActiveGet);
DeclareTmfHandler(BorderAgent, kUriPendingGet);
DeclareTmfHandler(BorderAgent, kUriProxyTx);
} // namespace MeshCoP
+10 -29
View File
@@ -276,9 +276,13 @@ SecureAgent::SecureAgent(Instance &aInstance)
: Coap::Dtls::Transport(aInstance, kNoLinkSecurity)
, Coap::SecureSession(aInstance, static_cast<Coap::Dtls::Transport &>(*this))
{
#if OPENTHREAD_FTD && OPENTHREAD_CONFIG_COMMISSIONER_ENABLE
SetResourceHandler(&HandleResource);
#endif
}
#if OPENTHREAD_FTD && OPENTHREAD_CONFIG_COMMISSIONER_ENABLE
bool SecureAgent::HandleResource(CoapBase &aCoapBase,
const char *aUriPath,
Message &aMessage,
@@ -289,43 +293,20 @@ bool SecureAgent::HandleResource(CoapBase &aCoapBase,
bool SecureAgent::HandleResource(const char *aUriPath, Message &aMessage, const Ip6::MessageInfo &aMessageInfo)
{
OT_UNUSED_VARIABLE(aMessage);
OT_UNUSED_VARIABLE(aMessageInfo);
bool didHandle = true;
bool didHandle = false;
Uri uri = UriFromPath(aUriPath);
#define Case(kUri, Type) \
case kUri: \
Get<Type>().HandleTmf<kUri>(aMessage, aMessageInfo); \
break
switch (uri)
if (uri == kUriJoinerFinalize)
{
#if OPENTHREAD_FTD && OPENTHREAD_CONFIG_COMMISSIONER_ENABLE
Case(kUriJoinerFinalize, MeshCoP::Commissioner);
#endif
#if OPENTHREAD_CONFIG_BORDER_AGENT_ENABLE
Case(kUriCommissionerPetition, MeshCoP::BorderAgent);
Case(kUriCommissionerKeepAlive, MeshCoP::BorderAgent);
Case(kUriRelayTx, MeshCoP::BorderAgent);
Case(kUriCommissionerGet, MeshCoP::BorderAgent);
Case(kUriActiveGet, MeshCoP::BorderAgent);
Case(kUriPendingGet, MeshCoP::BorderAgent);
Case(kUriProxyTx, MeshCoP::BorderAgent);
#endif
default:
didHandle = false;
break;
Get<MeshCoP::Commissioner>().HandleTmf<kUriJoinerFinalize>(aMessage, aMessageInfo);
didHandle = true;
}
#undef Case
return didHandle;
}
#endif // OPENTHREAD_FTD && OPENTHREAD_CONFIG_COMMISSIONER_ENABLE
#endif // OPENTHREAD_CONFIG_SECURE_TRANSPORT_ENABLE
} // namespace Tmf
+2
View File
@@ -208,11 +208,13 @@ public:
explicit SecureAgent(Instance &aInstance);
private:
#if OPENTHREAD_FTD && OPENTHREAD_CONFIG_COMMISSIONER_ENABLE
static bool HandleResource(CoapBase &aCoapBase,
const char *aUriPath,
Message &aMessage,
const Ip6::MessageInfo &aMessageInfo);
bool HandleResource(const char *aUriPath, Message &aMessage, const Ip6::MessageInfo &aMessageInfo);
#endif
};
#endif