Skip to content
This repository was archived by the owner on Dec 20, 2023. It is now read-only.

Commit 943121a

Browse files
author
Jay Logue
authored
Merge pull request #577 from openweave/feature/CredentialCaching
Access Control relaxation for fetching device credentials over a PASE session
2 parents 8ddf4c1 + fee08ec commit 943121a

File tree

6 files changed

+263
-6
lines changed

6 files changed

+263
-6
lines changed

src/lib/core/WeaveFabricState.cpp

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -278,6 +278,8 @@ WEAVE_ERROR WeaveFabricState::Init(GroupKeyStoreBase *groupKeyStore)
278278
279279
#endif
280280
281+
sessionEndCallbackList = NULL;
282+
281283
State = kState_Initialized;
282284
283285
return WEAVE_NO_ERROR;
@@ -382,6 +384,8 @@ WEAVE_ERROR WeaveFabricState::RemoveSessionKey(uint16_t keyId, uint64_t peerNode
382384
383385
RemoveSessionKey(sessionKey);
384386
387+
NotifySessionEndSubscribers(keyId, peerNodeId);
388+
385389
exit:
386390
return err;
387391
}
@@ -1312,6 +1316,59 @@ bool WeaveFabricState::FindOrAllocPeerEntry(uint64_t peerNodeId, bool allocEntry
13121316
return retVal;
13131317
}
13141318
1319+
/*
1320+
* This method is used by provisioning servers to register callbacks with the
1321+
* WeaveFabricState to be notified when the current session is closed.
1322+
*
1323+
* @param[in] sessionEndCb The context containing the callback function
1324+
* pointer.
1325+
*
1326+
* @retval WEAVE_ERROR Weave error encountered.
1327+
*
1328+
*/
1329+
WEAVE_ERROR WeaveFabricState::RegisterSessionEndCallback(SessionEndCbCtxt *sessionEndCb)
1330+
{
1331+
WEAVE_ERROR err = WEAVE_NO_ERROR;
1332+
SessionEndCbCtxt *iter = sessionEndCallbackList;
1333+
1334+
VerifyOrExit(sessionEndCb, err = WEAVE_ERROR_INVALID_ARGUMENT);
1335+
1336+
sessionEndCb->next = NULL;
1337+
if (sessionEndCallbackList == NULL)
1338+
{
1339+
sessionEndCallbackList = sessionEndCb;
1340+
ExitNow();
1341+
}
1342+
1343+
while (iter->next)
1344+
{
1345+
iter = iter->next;
1346+
}
1347+
1348+
iter->next = sessionEndCb;
1349+
1350+
exit:
1351+
return err;
1352+
}
1353+
1354+
/*
1355+
* Notify the registered callbacks when the given session is closed and removed
1356+
* from the session table.
1357+
*/
1358+
void WeaveFabricState::NotifySessionEndSubscribers(uint16_t keyId, uint64_t peerNodeId)
1359+
{
1360+
SessionEndCbCtxt *iter = sessionEndCallbackList;
1361+
1362+
while (iter)
1363+
{
1364+
if (iter->OnSessionRemoved)
1365+
{
1366+
iter->OnSessionRemoved(keyId, peerNodeId, iter->context);
1367+
}
1368+
iter = iter->next;
1369+
}
1370+
}
1371+
13151372
WEAVE_ERROR WeaveFabricState::GetPassword(uint8_t pwSrc, const char *& ps, uint16_t& pwLen)
13161373
{
13171374
switch (pwSrc)

src/lib/core/WeaveFabricState.h

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -506,7 +506,6 @@ class NL_DLL_EXPORT WeaveFabricState
506506
IPAddress ListenIPv6Addr;
507507
#endif
508508

509-
510509
WEAVE_ERROR Init(void);
511510
WEAVE_ERROR Init(nl::Weave::Profiles::Security::AppKeys::GroupKeyStoreBase *groupKeyStore);
512511
WEAVE_ERROR Shutdown(void);
@@ -568,6 +567,18 @@ class NL_DLL_EXPORT WeaveFabricState
568567
WEAVE_ERROR CheckMsgEncForAppGroup(const WeaveMessageInfo *msgInfo, uint32_t appGroupGlobalId, uint32_t rootKeyId, bool requireRotatingKey);
569568
#endif // WEAVE_CONFIG_USE_APP_GROUP_KEYS_FOR_MSG_ENC
570569

570+
typedef void (*SessionEndCbFunct)(uint16_t keyId, uint64_t peerNodeId, void *context);
571+
572+
// Callback context provided by provisioning servers when registering with
573+
// WeaveFabricState to be notified when session ends.
574+
struct SessionEndCbCtxt
575+
{
576+
SessionEndCbFunct OnSessionRemoved;
577+
void *context;
578+
SessionEndCbCtxt *next;
579+
};
580+
581+
WEAVE_ERROR RegisterSessionEndCallback(SessionEndCbCtxt *sessionEndCb);
571582
private:
572583
PeerIndexType PeerCount;
573584
MonotonicallyIncreasingCounter NextUnencUDPMsgId;
@@ -619,6 +630,11 @@ class NL_DLL_EXPORT WeaveFabricState
619630
// Record of all active shared session end nodes.
620631
SharedSessionEndNode SharedSessionsNodes[WEAVE_CONFIG_MAX_SHARED_SESSIONS_END_NODES];
621632

633+
// Linked list of registered modules to be notified when session closes
634+
SessionEndCbCtxt *sessionEndCallbackList;
635+
636+
void NotifySessionEndSubscribers(uint16_t keyId, uint64_t peerNodeId);
637+
622638
bool FindSharedSessionEndNode(uint64_t endNodeId, const WeaveSessionKey *sessionKey);
623639

624640
#if WEAVE_CONFIG_USE_APP_GROUP_KEYS_FOR_MSG_ENC

src/lib/profiles/fabric-provisioning/FabricProvisioning.cpp

Lines changed: 72 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -67,14 +67,22 @@ FabricProvisioningServer::FabricProvisioningServer()
6767
*/
6868
WEAVE_ERROR FabricProvisioningServer::Init(WeaveExchangeManager *exchangeMgr)
6969
{
70+
WEAVE_ERROR err = WEAVE_NO_ERROR;
71+
7072
FabricState = exchangeMgr->FabricState;
7173
ExchangeMgr = exchangeMgr;
7274
mDelegate = NULL;
7375
mCurClientOp = NULL;
76+
memset(&mFabricConfigAccessSession, 0, sizeof(mFabricConfigAccessSession));
7477

7578
// Register to receive unsolicited Service Provisioning messages from the exchange manager.
76-
WEAVE_ERROR err =
79+
err =
7780
ExchangeMgr->RegisterUnsolicitedMessageHandler(kWeaveProfile_FabricProvisioning, HandleClientRequest, this);
81+
SuccessOrExit(err);
82+
83+
err = RegisterSessionEndCallbackWithFabricState();
84+
85+
exit:
7886

7987
return err;
8088
}
@@ -152,6 +160,55 @@ WEAVE_ERROR FabricProvisioningServer::SendStatusReport(uint32_t statusProfileId,
152160
return err;
153161
}
154162

163+
/**
164+
* Indicates if the session with the given node id and the session key id is
165+
* authorized to retrieve fabric config information.
166+
*
167+
* @return Returns 'true' if the given peer is privileged, else
168+
* 'false'.
169+
*/
170+
171+
bool FabricProvisioningServer::SessionHasFabricConfigAccessPrivilege(uint16_t keyId, uint64_t peerNodeId) const
172+
{
173+
return (peerNodeId == mFabricConfigAccessSession.PeerNodeId &&
174+
keyId == mFabricConfigAccessSession.SessionKeyId);
175+
}
176+
177+
void FabricProvisioningServer::GrantFabricConfigAccessPrivilege(uint16_t keyId, uint64_t peerNodeId)
178+
{
179+
mFabricConfigAccessSession.PeerNodeId = peerNodeId;
180+
mFabricConfigAccessSession.SessionKeyId = keyId;
181+
}
182+
183+
void FabricProvisioningServer::ClearFabricConfigAccessPrivilege(void)
184+
{
185+
memset(&mFabricConfigAccessSession, 0, sizeof(mFabricConfigAccessSession));
186+
}
187+
188+
void FabricProvisioningServer::HandleSessionEnd(uint16_t keyId, uint64_t peerNodeId, void *context)
189+
{
190+
FabricProvisioningServer *server = static_cast<FabricProvisioningServer *>(context);
191+
192+
// Clear the privileged session when notified of its removal by FabricState
193+
if (server->SessionHasFabricConfigAccessPrivilege(keyId, peerNodeId))
194+
{
195+
server->ClearFabricConfigAccessPrivilege();
196+
}
197+
}
198+
199+
WEAVE_ERROR FabricProvisioningServer::RegisterSessionEndCallbackWithFabricState(void)
200+
{
201+
WEAVE_ERROR err = WEAVE_NO_ERROR;
202+
203+
mSessionEndCbCtxt.OnSessionRemoved = HandleSessionEnd;
204+
mSessionEndCbCtxt.context = this;
205+
mSessionEndCbCtxt.next = NULL;
206+
207+
err = FabricState->RegisterSessionEndCallback(&mSessionEndCbCtxt);
208+
209+
return err;
210+
}
211+
155212
void FabricProvisioningServer::HandleClientRequest(ExchangeContext *ec, const IPPacketInfo *pktInfo, const WeaveMessageInfo *msgInfo,
156213
uint32_t profileId, uint8_t msgType, PacketBuffer *msgBuf)
157214
{
@@ -210,6 +267,13 @@ void FabricProvisioningServer::HandleClientRequest(ExchangeContext *ec, const IP
210267
server->FabricState->ClearFabricState();
211268
SuccessOrExit(err);
212269

270+
if (msgInfo->EncryptionType != kWeaveEncryptionType_None &&
271+
WeaveKeyId::IsSessionKey(msgInfo->KeyId))
272+
{
273+
// Authorize the current session for privileged access to secret fabric config information
274+
server->GrantFabricConfigAccessPrivilege(msgInfo->KeyId, msgInfo->SourceNodeId);
275+
}
276+
213277
break;
214278

215279
case kMsgType_LeaveFabric:
@@ -310,6 +374,10 @@ void FabricProvisioningServer::HandleClientRequest(ExchangeContext *ec, const IP
310374
void FabricProvisioningDelegate::EnforceAccessControl(ExchangeContext *ec, uint32_t msgProfileId, uint8_t msgType,
311375
const WeaveMessageInfo *msgInfo, AccessControlResult& result)
312376
{
377+
#if WEAVE_CONFIG_REQUIRE_AUTH_FABRIC_PROV
378+
FabricProvisioningServer *server = static_cast<FabricProvisioningServer *>(ec->AppState);
379+
#endif
380+
313381
// If the result has not already been determined by a subclass...
314382
if (result == kAccessControlResult_NotDetermined)
315383
{
@@ -328,7 +396,9 @@ void FabricProvisioningDelegate::EnforceAccessControl(ExchangeContext *ec, uint3
328396

329397
case kMsgType_LeaveFabric:
330398
case kMsgType_GetFabricConfig:
331-
if (msgInfo->PeerAuthMode == kWeaveAuthMode_CASE_AccessToken)
399+
if (msgInfo->PeerAuthMode == kWeaveAuthMode_CASE_AccessToken ||
400+
(msgInfo->PeerAuthMode == kWeaveAuthMode_PASE_PairingCode && !IsPairedToAccount() &&
401+
server->SessionHasFabricConfigAccessPrivilege(msgInfo->KeyId, msgInfo->SourceNodeId)))
332402
{
333403
result = kAccessControlResult_Accepted;
334404
}

src/lib/profiles/fabric-provisioning/FabricProvisioning.h

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -187,6 +187,9 @@ class NL_DLL_EXPORT FabricProvisioningServer : public WeaveServerBase
187187

188188
void SetDelegate(FabricProvisioningDelegate *delegate);
189189

190+
// Check if the session is marked as privileged to retrieve fabric config information.
191+
bool SessionHasFabricConfigAccessPrivilege(uint16_t keyId, uint64_t peerNodeId) const;
192+
190193
virtual WEAVE_ERROR SendSuccessResponse(void);
191194
virtual WEAVE_ERROR SendStatusReport(uint32_t statusProfileId, uint16_t statusCode, WEAVE_ERROR sysError = WEAVE_NO_ERROR);
192195

@@ -198,7 +201,27 @@ class NL_DLL_EXPORT FabricProvisioningServer : public WeaveServerBase
198201
static void HandleClientRequest(ExchangeContext *ec, const IPPacketInfo *pktInfo, const WeaveMessageInfo *msgInfo, uint32_t profileId,
199202
uint8_t msgType, PacketBuffer *payload);
200203

204+
// Utility functions for managing registration with/notification from WeaveFabricState
205+
// about whether the current security session is privileged to
206+
// access fabric config information.
207+
void GrantFabricConfigAccessPrivilege(uint16_t keyId, uint64_t peerNodeId);
208+
void ClearFabricConfigAccessPrivilege(void);
209+
static void HandleSessionEnd(uint16_t keyId, uint64_t peerNodeId, void *context);
210+
WEAVE_ERROR RegisterSessionEndCallbackWithFabricState(void);
211+
212+
// Indicates the session that is privileged to
213+
// retrieve fabric config information.
214+
struct FabricConfigAccessSession
215+
{
216+
uint64_t PeerNodeId;
217+
uint16_t SessionKeyId;
218+
};
219+
FabricConfigAccessSession mFabricConfigAccessSession;
220+
221+
nl::Weave::WeaveFabricState::SessionEndCbCtxt mSessionEndCbCtxt;
222+
201223
FabricProvisioningServer(const FabricProvisioningServer&); // not defined
224+
202225
};
203226

204227

src/lib/profiles/network-provisioning/NetworkProvisioning.cpp

Lines changed: 70 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -66,17 +66,25 @@ NetworkProvisioningServer::NetworkProvisioningServer()
6666
*/
6767
WEAVE_ERROR NetworkProvisioningServer::Init(WeaveExchangeManager *exchangeMgr)
6868
{
69+
WEAVE_ERROR err = WEAVE_NO_ERROR;
70+
6971
ExchangeMgr = exchangeMgr;
7072
FabricState = exchangeMgr->FabricState;
7173
mCurOp = NULL;
7274
mDelegate = NULL;
7375
mLastOpResult.StatusProfileId = kWeaveProfile_Common;
7476
mLastOpResult.StatusCode = Common::kStatus_Success;
7577
mLastOpResult.SysError = WEAVE_NO_ERROR;
78+
memset(&mCredentialAccessSession, 0, sizeof(mCredentialAccessSession));
7679

7780
// Register to receive unsolicited Network Provisioning messages from the exchange manager.
78-
WEAVE_ERROR err =
81+
err =
7982
ExchangeMgr->RegisterUnsolicitedMessageHandler(kWeaveProfile_NetworkProvisioning, HandleRequest, this);
83+
SuccessOrExit(err);
84+
85+
err = RegisterSessionEndCallbackWithFabricState();
86+
87+
exit:
8088

8189
return err;
8290
}
@@ -196,6 +204,14 @@ WEAVE_ERROR NetworkProvisioningServer::SendAddNetworkComplete(uint32_t networkId
196204
VerifyOrExit(mDelegate != NULL, err = WEAVE_ERROR_INCORRECT_STATE);
197205
VerifyOrExit(mCurOp != NULL, err = WEAVE_ERROR_INCORRECT_STATE);
198206

207+
// Authorize the current session for privileged access to secret
208+
// credential information.
209+
if (mCurOp->EncryptionType != kWeaveEncryptionType_None &&
210+
WeaveKeyId::IsSessionKey(mCurOp->KeyId))
211+
{
212+
GrantCredentialAccessPrivilege(mCurOp->KeyId, mCurOp->PeerNodeId);
213+
}
214+
199215
respBuf = PacketBuffer::NewWithAvailableSize(respLen);
200216
VerifyOrExit(respBuf != NULL, err = WEAVE_ERROR_NO_MEMORY);
201217

@@ -306,6 +322,55 @@ WEAVE_ERROR NetworkProvisioningServer::SendStatusReport(uint32_t statusProfileId
306322
return err;
307323
}
308324

325+
/**
326+
* Indicates if the session with the given node id and the session key id is
327+
* authorized to retrieve secret credential information.
328+
*
329+
* @return Returns 'true' if the given peer is privileged, else
330+
* 'false'.
331+
*/
332+
333+
bool NetworkProvisioningServer::SessionHasCredentialAccessPrivilege(uint16_t keyId, uint64_t peerNodeId) const
334+
{
335+
return (peerNodeId == mCredentialAccessSession.PeerNodeId &&
336+
keyId == mCredentialAccessSession.SessionKeyId);
337+
}
338+
339+
void NetworkProvisioningServer::GrantCredentialAccessPrivilege(uint16_t keyId, uint64_t peerNodeId)
340+
{
341+
mCredentialAccessSession.PeerNodeId = peerNodeId;
342+
mCredentialAccessSession.SessionKeyId = keyId;
343+
}
344+
345+
void NetworkProvisioningServer::ClearCredentialAccessPrivilege(void)
346+
{
347+
memset(&mCredentialAccessSession, 0, sizeof(mCredentialAccessSession));
348+
}
349+
350+
void NetworkProvisioningServer::HandleSessionEnd(uint16_t keyId, uint64_t peerNodeId, void *context)
351+
{
352+
NetworkProvisioningServer *server = static_cast<NetworkProvisioningServer *>(context);
353+
354+
// Clear the privileged session when notified of its removal by FabricState
355+
if (server->SessionHasCredentialAccessPrivilege(keyId, peerNodeId))
356+
{
357+
server->ClearCredentialAccessPrivilege();
358+
}
359+
}
360+
361+
WEAVE_ERROR NetworkProvisioningServer::RegisterSessionEndCallbackWithFabricState(void)
362+
{
363+
WEAVE_ERROR err = WEAVE_NO_ERROR;
364+
365+
mSessionEndCbCtxt.OnSessionRemoved = HandleSessionEnd;
366+
mSessionEndCbCtxt.context = this;
367+
mSessionEndCbCtxt.next = NULL;
368+
369+
err = FabricState->RegisterSessionEndCallback(&mSessionEndCbCtxt);
370+
371+
return err;
372+
}
373+
309374
void NetworkProvisioningServer::HandleRequest(ExchangeContext *ec, const IPPacketInfo *pktInfo, const WeaveMessageInfo *msgInfo, uint32_t profileId,
310375
uint8_t msgType, PacketBuffer *payload)
311376
{
@@ -406,9 +471,11 @@ void NetworkProvisioningServer::HandleRequest(ExchangeContext *ec, const IPPacke
406471
// According to Weave Device Access Control Policy,
407472
// When servicing a GetNetworks message from a peer that has authenticated using PASE/PairingCode,
408473
// a device in an unpaired state must reject the message with an access denied error if the peer has
409-
// set the IncludeCredentials flag.
474+
// set the IncludeCredentials flag and the current session is not privileged to retrieve secret
475+
// credentials.
410476
if (msgInfo->PeerAuthMode == kWeaveAuthMode_PASE_PairingCode && !delegate->IsPairedToAccount()
411-
&& (flags & kGetNetwork_IncludeCredentials) != 0)
477+
&& (flags & kGetNetwork_IncludeCredentials) != 0
478+
&& !server->SessionHasCredentialAccessPrivilege(msgInfo->KeyId, msgInfo->SourceNodeId))
412479
{
413480
server->SendStatusReport(kWeaveProfile_Common, Common::kStatus_AccessDenied);
414481
break;

0 commit comments

Comments
 (0)