From 1024a1fdb9e6f3c9cdf2ff2a4141dd4b36905f7c Mon Sep 17 00:00:00 2001 From: Abtin Keshavarzian Date: Fri, 27 Dec 2024 16:53:29 -0800 Subject: [PATCH] [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`. --- src/core/meshcop/border_agent.cpp | 137 ++++++++++++++++++------------ src/core/meshcop/border_agent.hpp | 37 +++++--- src/core/thread/tmf.cpp | 39 +++------ src/core/thread/tmf.hpp | 2 + 4 files changed, 119 insertions(+), 96 deletions(-) diff --git a/src/core/meshcop/border_agent.cpp b/src/core/meshcop/border_agent.cpp index 5fcf60f12..f498aed1c 100644 --- a/src/core/meshcop/border_agent.cpp +++ b/src/core/meshcop/border_agent.cpp @@ -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().SetMaxConnectionAttempts(kMaxEphemeralKeyConnectionAttempts, - HandleSecureAgentStopped, this)); + SuccessOrExit(error = mDtlsTransport.SetMaxConnectionAttempts(kMaxEphemeralKeyConnectionAttempts, + HandleDtlsTransportClosed, this)); } #endif - SuccessOrExit(error = Get().Open()); - SuccessOrExit(error = Get().Bind(aUdpPort)); + mCoapDtlsSession.Reset(CoapDtlsSession::Allocate(GetInstance(), mDtlsTransport)); + VerifyOrExit(mCoapDtlsSession != nullptr, error = kErrorNoBufs); - SuccessOrExit(error = Get().SetPsk(aPsk, aPskLength)); + SuccessOrExit(error = mDtlsTransport.Open()); + SuccessOrExit(error = mDtlsTransport.Bind(aUdpPort)); - Get().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().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().Disconnect(); + mCoapDtlsSession->Disconnect(); exit: return; } -uint16_t BorderAgent::GetUdpPort(void) const { return Get().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().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().IsConnected()) + if (mCoapDtlsSession->IsConnected()) { - Get().Disconnect(); + mCoapDtlsSession->Disconnect(); LogWarn("Reset secure session"); } } @@ -287,14 +292,7 @@ void BorderAgent::HandleConnected(Dtls::Session::ConnectEvent aEvent) } } -template <> -void BorderAgent::HandleTmf(Coap::Message &aMessage, const Ip6::MessageInfo &aMessageInfo) -{ - IgnoreError(ForwardToLeader(aMessage, aMessageInfo, kUriLeaderPetition)); -} - -template <> -void BorderAgent::HandleTmf(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().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().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().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(*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().SendMessage(aMessage); } - void BorderAgent::SendErrorMessage(const ForwardContext &aForwardContext, Error aError) { Error error = kErrorNone; Coap::Message *message = nullptr; - VerifyOrExit((message = Get().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().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(Coap::Message &aMessage, co VerifyOrExit(aMessage.IsNonConfirmablePostRequest(), error = kErrorDrop); - message = Get().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(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(Coap::Message &aMessage, const Ip6::MessageInfo &aMessageInfo) -{ - HandleTmfDatasetGet(aMessage, aMessageInfo, kUriCommissionerGet); -} - -template <> void BorderAgent::HandleTmf(Coap::Message &aMessage, const Ip6::MessageInfo &aMessageInfo) -{ - HandleTmfDatasetGet(aMessage, aMessageInfo, kUriActiveGet); - mCounters.mMgmtActiveGets++; -} - -template <> void BorderAgent::HandleTmf(Coap::Message &aMessage, const Ip6::MessageInfo &aMessageInfo) -{ - HandleTmfDatasetGet(aMessage, aMessageInfo, kUriPendingGet); - mCounters.mMgmtPendingGets++; -} - -template <> void BorderAgent::HandleTmf(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().ProcessGetRequest(aMessage, DatasetManager::kIgnoreSecurityPolicyFlags); + mCounters.mMgmtActiveGets++; break; case kUriPendingGet: response = Get().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().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(aContext)->HandleSecureAgentStopped(); + reinterpret_cast(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(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().ForwardToLeader(aMessage, aMessageInfo, kUriLeaderPetition)); + break; + case kUriCommissionerKeepAlive: + Get().HandleTmfCommissionerKeepAlive(aMessage, aMessageInfo); + break; + case kUriRelayTx: + Get().HandleTmfRelayTx(aMessage, aMessageInfo); + break; + case kUriCommissionerGet: + case kUriActiveGet: + case kUriPendingGet: + Get().HandleTmfDatasetGet(aMessage, aMessageInfo, uri); + break; + case kUriProxyTx: + Get().HandleTmfProxyTx(aMessage, aMessageInfo); + break; + default: + didHandle = false; + break; + } + + return didHandle; +} + //---------------------------------------------------------------------------------------------------------------------- // `BorderAgent::ForwardContext` diff --git a/src/core/meshcop/border_agent.hpp b/src/core/meshcop/border_agent.hpp index a597a1e24..08b62e227 100644 --- a/src/core/meshcop/border_agent.hpp +++ b/src/core/meshcop/border_agent.hpp @@ -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 + { + friend Heap::Allocatable; + + 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 { 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 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; @@ -318,6 +338,8 @@ private: Ip6::Udp::Receiver mUdpReceiver; Ip6::Netif::UnicastAddress mCommissionerAloc; TimeoutTimer mTimer; + Dtls::Transport mDtlsTransport; + OwnedPtr 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 diff --git a/src/core/thread/tmf.cpp b/src/core/thread/tmf.cpp index 89671db9e..d6cf54078 100644 --- a/src/core/thread/tmf.cpp +++ b/src/core/thread/tmf.cpp @@ -276,9 +276,13 @@ SecureAgent::SecureAgent(Instance &aInstance) : Coap::Dtls::Transport(aInstance, kNoLinkSecurity) , Coap::SecureSession(aInstance, static_cast(*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().HandleTmf(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().HandleTmf(aMessage, aMessageInfo); + didHandle = true; } -#undef Case - return didHandle; } +#endif // OPENTHREAD_FTD && OPENTHREAD_CONFIG_COMMISSIONER_ENABLE + #endif // OPENTHREAD_CONFIG_SECURE_TRANSPORT_ENABLE } // namespace Tmf diff --git a/src/core/thread/tmf.hpp b/src/core/thread/tmf.hpp index 869e45c20..386f133bc 100644 --- a/src/core/thread/tmf.hpp +++ b/src/core/thread/tmf.hpp @@ -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