-
Notifications
You must be signed in to change notification settings - Fork 2.1k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[ICD] Refresh key to avoid check-in counter rollover problems. (#31465)
* Refresh key to avoid check-in counter rollover problems. * Restyled by whitespace * Restyled by gn * Added CommandSender callbacks * Addressed review comments. * Modified design for delegate to allocate/deallocate ICDRefreshKeyInfo * Removed newline * Added a comment to suppress lint error * Renamed ICDRefreshKeyInfo to RefreshKeySender * Removed the data structure used for tracking refreshkeysender. * Formatting changes. * Formatting changes. * Formatting changes * Addressed review comments. * Addressed review comments --------- Co-authored-by: Restyled.io <[email protected]>
- Loading branch information
1 parent
b820953
commit 849f882
Showing
7 changed files
with
303 additions
and
5 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,116 @@ | ||
/* | ||
* Copyright (c) 2024 Project CHIP Authors | ||
* All rights reserved. | ||
* | ||
* Licensed under the Apache License, Version 2.0 (the "License"); | ||
* you may not use this file except in compliance with the License. | ||
* You may obtain a copy of the License at | ||
* | ||
* http://www.apache.org/licenses/LICENSE-2.0 | ||
* | ||
* Unless required by applicable law or agreed to in writing, software | ||
* distributed under the License is distributed on an "AS IS" BASIS, | ||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
* See the License for the specific language governing permissions and | ||
* limitations under the License. | ||
*/ | ||
|
||
#include "RefreshKeySender.h" | ||
#include "CheckInDelegate.h" | ||
#include "controller/InvokeInteraction.h" | ||
#include <app-common/zap-generated/cluster-objects.h> | ||
#include <app/CommandPathParams.h> | ||
#include <app/InteractionModelEngine.h> | ||
#include <app/OperationalSessionSetup.h> | ||
#include <memory> | ||
|
||
namespace chip { | ||
namespace app { | ||
|
||
RefreshKeySender::RefreshKeySender(CheckInDelegate * checkInDelegate, const ICDClientInfo & icdClientInfo, | ||
ICDClientStorage * icdClientStorage, const RefreshKeyBuffer & refreshKeyBuffer) : | ||
mICDClientInfo(icdClientInfo), | ||
mpICDClientStorage(icdClientStorage), mpCheckInDelegate(checkInDelegate), mOnConnectedCallback(HandleDeviceConnected, this), | ||
mOnConnectionFailureCallback(HandleDeviceConnectionFailure, this) | ||
|
||
{ | ||
mNewKey = refreshKeyBuffer; | ||
} | ||
|
||
CHIP_ERROR RefreshKeySender::RegisterClientWithNewKey(Messaging::ExchangeManager & exchangeMgr, const SessionHandle & sessionHandle) | ||
{ | ||
auto onSuccess = [&](const ConcreteCommandPath & commandPath, const StatusIB & status, const auto & dataResponse) { | ||
ChipLogProgress(ICD, "RegisterClient command succeeded"); | ||
CHIP_ERROR error; | ||
|
||
// Update the ICDClientInfo with new key and start counter and store it to persistence | ||
mICDClientInfo.start_icd_counter = dataResponse.ICDCounter; | ||
mICDClientInfo.offset = 0; | ||
mpICDClientStorage->RemoveKey(mICDClientInfo); | ||
error = mpICDClientStorage->SetKey(mICDClientInfo, mNewKey.Span()); | ||
if (error != CHIP_NO_ERROR) | ||
{ | ||
ChipLogError(ICD, "Failed to set the new key after re-registration: %" CHIP_ERROR_FORMAT, error.Format()); | ||
mpCheckInDelegate->OnKeyRefreshDone(this, error); | ||
return; | ||
} | ||
|
||
error = mpICDClientStorage->StoreEntry(mICDClientInfo); | ||
if (error != CHIP_NO_ERROR) | ||
{ | ||
ChipLogError(ICD, "Failed to store the new key after re-registration: %" CHIP_ERROR_FORMAT, error.Format()); | ||
mpCheckInDelegate->OnKeyRefreshDone(this, error); | ||
return; | ||
} | ||
|
||
mpCheckInDelegate->OnCheckInComplete(mICDClientInfo); | ||
mpCheckInDelegate->OnKeyRefreshDone(this, CHIP_NO_ERROR); | ||
}; | ||
|
||
auto onFailure = [&](CHIP_ERROR error) { | ||
ChipLogError(ICD, "RegisterClient command failed: %" CHIP_ERROR_FORMAT, error.Format()); | ||
mpCheckInDelegate->OnKeyRefreshDone(this, error); | ||
}; | ||
|
||
EndpointId endpointId = 0; | ||
|
||
Clusters::IcdManagement::Commands::RegisterClient::Type registerClientCommand; | ||
registerClientCommand.checkInNodeID = mICDClientInfo.peer_node.GetNodeId(); | ||
registerClientCommand.monitoredSubject = mICDClientInfo.monitored_subject; | ||
registerClientCommand.key = mNewKey.Span(); | ||
return Controller::InvokeCommandRequest(&exchangeMgr, sessionHandle, endpointId, registerClientCommand, onSuccess, onFailure); | ||
} | ||
|
||
CHIP_ERROR RefreshKeySender::EstablishSessionToPeer() | ||
{ | ||
ChipLogProgress(ICD, "Trying to establish a CASE session for re-registering an ICD client"); | ||
auto * caseSessionManager = InteractionModelEngine::GetInstance()->GetCASESessionManager(); | ||
VerifyOrReturnError(caseSessionManager != nullptr, CHIP_ERROR_INVALID_CASE_PARAMETER); | ||
caseSessionManager->FindOrEstablishSession(mICDClientInfo.peer_node, &mOnConnectedCallback, &mOnConnectionFailureCallback); | ||
return CHIP_NO_ERROR; | ||
} | ||
|
||
void RefreshKeySender::HandleDeviceConnected(void * context, Messaging::ExchangeManager & exchangeMgr, | ||
const SessionHandle & sessionHandle) | ||
{ | ||
RefreshKeySender * const _this = static_cast<RefreshKeySender *>(context); | ||
VerifyOrDie(_this != nullptr); | ||
|
||
CHIP_ERROR err = _this->RegisterClientWithNewKey(exchangeMgr, sessionHandle); | ||
if (CHIP_NO_ERROR != err) | ||
{ | ||
ChipLogError(ICD, "Failed to send register client command"); | ||
_this->mpCheckInDelegate->OnKeyRefreshDone(_this, err); | ||
} | ||
} | ||
|
||
void RefreshKeySender::HandleDeviceConnectionFailure(void * context, const ScopedNodeId & peerId, CHIP_ERROR err) | ||
{ | ||
RefreshKeySender * const _this = static_cast<RefreshKeySender *>(context); | ||
VerifyOrDie(_this != nullptr); | ||
|
||
ChipLogError(ICD, "Failed to establish CASE for re-registration with error '%" CHIP_ERROR_FORMAT "'", err.Format()); | ||
_this->mpCheckInDelegate->OnKeyRefreshDone(_this, err); | ||
} | ||
} // namespace app | ||
} // namespace chip |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,93 @@ | ||
/* | ||
* | ||
* Copyright (c) 2024 Project CHIP Authors | ||
* | ||
* Licensed under the Apache License, Version 2.0 (the "License"); | ||
* you may not use this file except in compliance with the License. | ||
* You may obtain a copy of the License at | ||
* | ||
* http://www.apache.org/licenses/LICENSE-2.0 | ||
* | ||
* Unless required by applicable law or agreed to in writing, software | ||
* distributed under the License is distributed on an "AS IS" BASIS, | ||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
* See the License for the specific language governing permissions and | ||
* limitations under the License. | ||
*/ | ||
|
||
#pragma once | ||
|
||
#include "ICDClientInfo.h" | ||
#include "ICDClientStorage.h" | ||
#include <app-common/zap-generated/cluster-objects.h> | ||
#include <app/CommandSender.h> | ||
#include <app/OperationalSessionSetup.h> | ||
|
||
#include <crypto/CHIPCryptoPAL.h> | ||
#include <lib/core/CHIPConfig.h> | ||
#include <lib/core/DataModelTypes.h> | ||
#include <lib/core/ScopedNodeId.h> | ||
#include <lib/support/CodeUtils.h> | ||
#include <stddef.h> | ||
|
||
namespace chip { | ||
namespace app { | ||
|
||
class CheckInDelegate; | ||
|
||
/** | ||
* @brief RefreshKeySender contains all the data and methods needed for key refresh and re-registration of an ICD client. | ||
*/ | ||
class RefreshKeySender | ||
{ | ||
public: | ||
typedef Crypto::SensitiveDataBuffer<Crypto::kAES_CCM128_Key_Length> RefreshKeyBuffer; | ||
|
||
RefreshKeySender(CheckInDelegate * checkInDelegate, const ICDClientInfo & icdClientInfo, ICDClientStorage * icdClientStorage, | ||
const RefreshKeyBuffer & refreshKeyBuffer); | ||
|
||
/** | ||
* @brief Sets up a CASE session to the peer for re-registering a client with the peer when a key refresh is required to avoid | ||
* ICD counter rollover. Returns error if we did not even manage to kick off a CASE attempt. | ||
*/ | ||
CHIP_ERROR EstablishSessionToPeer(); | ||
|
||
private: | ||
// CASE session callbacks | ||
/** | ||
* @brief Callback received on successfully establishing a CASE session in order to re-register the client with the peer node | ||
* using a new key to avoid counter rollover problems. | ||
* | ||
* @param[in] context - context of the client establishing the CASE session | ||
* @param[in] exchangeMgr - exchange manager to use for the re-registration | ||
* @param[in] sessionHandle - session handle to use for the re-registration | ||
*/ | ||
static void HandleDeviceConnected(void * context, Messaging::ExchangeManager & exchangeMgr, | ||
const SessionHandle & sessionHandle); | ||
/** | ||
* @brief Callback received on failure to establish a CASE session in order to re-register the client with the peer node using a | ||
* new key to avoid counter rollover problems. | ||
* | ||
* @param[in] context - context of the client establishing the CASE session | ||
* @param[in] peerId - Scoped Node ID of the peer node | ||
* @param[in] err - failure reason | ||
*/ | ||
static void HandleDeviceConnectionFailure(void * context, const ScopedNodeId & peerId, CHIP_ERROR err); | ||
|
||
/** | ||
* @brief Used to send a re-registration command to the peer using a new key. | ||
* | ||
* @param[in] exchangeMgr - exchange manager to use for the re-registration | ||
* @param[in] sessionHandle - session handle to use for the re-registration | ||
*/ | ||
CHIP_ERROR RegisterClientWithNewKey(Messaging::ExchangeManager & exchangeMgr, const SessionHandle & sessionHandle); | ||
|
||
ICDClientInfo mICDClientInfo; | ||
ICDClientStorage * mpICDClientStorage = nullptr; | ||
CheckInDelegate * mpCheckInDelegate = nullptr; | ||
RefreshKeyBuffer mNewKey; | ||
Callback::Callback<OnDeviceConnected> mOnConnectedCallback; | ||
Callback::Callback<OnDeviceConnectionFailure> mOnConnectionFailureCallback; | ||
}; | ||
} // namespace app | ||
} // namespace chip |