blob: 09431b701460c7c60bcf7b62bbbec84dfe7ecd12 [file] [log] [blame]
/*
* Copyright (c) 2023 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.
*/
// Do not use the DefaultICDClientStorage class in settings where fabric indices are not stable.
// This class relies on the stability of fabric indices for efficient storage and retrieval of ICD client information.
// If fabric indices are not stable, the functionality of this class will be compromised and can lead to unexpected behavior.
#pragma once
#include <app/icd/client/ICDClientStorage.h>
#include <lib/core/CHIPCore.h>
#include <crypto/CHIPCryptoPAL.h>
#include <crypto/SessionKeystore.h>
#include <lib/core/CHIPConfig.h>
#include <lib/core/CHIPPersistentStorageDelegate.h>
#include <lib/core/DataModelTypes.h>
#include <lib/core/ScopedNodeId.h>
#include <lib/core/TLV.h>
#include <lib/support/CommonIterator.h>
#include <lib/support/Pool.h>
#include <vector>
// TODO: SymmetricKeystore is an alias for SessionKeystore, replace the below when sdk supports SymmetricKeystore
namespace chip {
namespace Crypto {
using SymmetricKeystore = SessionKeystore;
} // namespace Crypto
} // namespace chip
namespace chip {
namespace app {
/**
* A DefaultICDClientStorage implementation of ICDClientStorage.
*/
class DefaultICDClientStorage : public ICDClientStorage
{
public:
using ICDClientInfoIterator = CommonIterator<ICDClientInfo>;
// ICDClientInfoIterator wrapper to release ICDClientInfoIterator when it is out of scope
class ICDClientInfoIteratorWrapper
{
public:
ICDClientInfoIteratorWrapper(ICDClientInfoIterator * apICDClientInfoIterator)
{
mpICDClientInfoIterator = apICDClientInfoIterator;
}
~ICDClientInfoIteratorWrapper()
{
if (mpICDClientInfoIterator != nullptr)
{
mpICDClientInfoIterator->Release();
mpICDClientInfoIterator = nullptr;
}
}
private:
ICDClientInfoIterator * mpICDClientInfoIterator = nullptr;
};
static constexpr size_t kIteratorsMax = CHIP_CONFIG_MAX_ICD_CLIENTS_INFO_STORAGE_CONCURRENT_ITERATORS;
CHIP_ERROR Init(PersistentStorageDelegate * clientInfoStore, Crypto::SymmetricKeystore * keyStore);
/**
* Iterate through persisted ICD Client Info
*
* @return A valid iterator on success. Use CommonIterator accessor to retrieve ICDClientInfo
*/
ICDClientInfoIterator * IterateICDClientInfo();
/**
* When decrypting check-in messages, the system needs to iterate through all keys
* from all ICD clientInfos. In DefaultICDClientStorage, ICDClientInfos for the same fabric are stored in
* storage using the fabricIndex as the key. To retrieve all relevant ICDClientInfos
* from storage, the system needs to know all fabricIndices in advance. The
* `UpdateFabricList` function provides a way to inject newly created fabricIndices
* into a dedicated table. It is recommended to call this function whenever a controller is created
* with a new fabric index.
*
* @param[in] fabricIndex The newly created fabric index.
*/
CHIP_ERROR UpdateFabricList(FabricIndex fabricIndex);
CHIP_ERROR SetKey(ICDClientInfo & clientInfo, const ByteSpan keyData) override;
void RemoveKey(ICDClientInfo & clientInfo) override;
CHIP_ERROR StoreEntry(const ICDClientInfo & clientInfo) override;
CHIP_ERROR DeleteEntry(const ScopedNodeId & peerNode) override;
/**
* Remove all ICDClient persistent information associated with the specified
* fabric index. If no entries for the fabric index exist, this is a no-op
* and is considered successful.
* When the whole fabric is removed, all entries from persistent storage in current fabric index are removed.
*
* @param[in] fabricIndex the index of the fabric for which to remove ICDClient persistent information
*/
CHIP_ERROR DeleteAllEntries(FabricIndex fabricIndex);
CHIP_ERROR ProcessCheckInPayload(const ByteSpan & payload, ICDClientInfo & clientInfo,
Protocols::SecureChannel::CounterType & counter) override;
/**
* Shut down DefaultICDClientStorage
*
*/
void Shutdown();
#if CONFIG_BUILD_FOR_HOST_UNIT_TEST
size_t GetFabricListSize() { return mFabricList.size(); }
PersistentStorageDelegate * GetClientInfoStore() { return mpClientInfoStore; }
#endif // CONFIG_BUILD_FOR_HOST_UNIT_TEST
protected:
enum class ClientInfoTag : uint8_t
{
kPeerNodeId = 1,
kCheckInNodeId = 2,
kFabricIndex = 3,
kStartICDCounter = 4,
kOffset = 5,
kMonitoredSubject = 6,
kAesKeyHandle = 7,
kHmacKeyHandle = 8,
kClientType = 9,
};
enum class CounterTag : uint8_t
{
kCount = 1,
kSize = 2,
};
class ICDClientInfoIteratorImpl : public ICDClientInfoIterator
{
public:
ICDClientInfoIteratorImpl(DefaultICDClientStorage & manager);
size_t Count() override;
bool Next(ICDClientInfo & info) override;
void Release() override;
private:
DefaultICDClientStorage & mManager;
size_t mFabricListIndex = 0;
size_t mClientInfoIndex = 0;
std::vector<ICDClientInfo> mClientInfoVector;
};
static constexpr size_t MaxICDClientInfoSize()
{
// All the fields added together
return TLV::EstimateStructOverhead(
sizeof(NodeId), sizeof(NodeId), sizeof(FabricIndex), sizeof(uint32_t) /*start_icd_counter*/,
sizeof(uint32_t) /*offset*/, sizeof(uint64_t) /*monitored_subject*/,
sizeof(Crypto::Symmetric128BitsKeyByteArray) /*aes_key_handle*/,
sizeof(Crypto::Symmetric128BitsKeyByteArray) /*hmac_key_handle*/, sizeof(uint8_t) /*client_type*/);
}
static constexpr size_t MaxICDCounterSize()
{
// All the fields added together
return TLV::EstimateStructOverhead(sizeof(size_t), sizeof(size_t));
}
private:
friend class ICDClientInfoIteratorImpl;
CHIP_ERROR StoreFabricList();
CHIP_ERROR LoadFabricList();
CHIP_ERROR LoadCounter(FabricIndex fabricIndex, size_t & count, size_t & clientInfoSize);
bool FabricExists(FabricIndex fabricIndex);
CHIP_ERROR IncreaseEntryCountForFabric(FabricIndex fabricIndex);
CHIP_ERROR DecreaseEntryCountForFabric(FabricIndex fabricIndex);
CHIP_ERROR UpdateEntryCountForFabric(FabricIndex fabricIndex, bool increase);
CHIP_ERROR SerializeToTlv(TLV::TLVWriter & writer, const std::vector<ICDClientInfo> & clientInfoVector);
CHIP_ERROR Load(FabricIndex fabricIndex, std::vector<ICDClientInfo> & clientInfoVector, size_t & clientInfoSize);
ObjectPool<ICDClientInfoIteratorImpl, kIteratorsMax> mICDClientInfoIterators;
PersistentStorageDelegate * mpClientInfoStore = nullptr;
Crypto::SymmetricKeystore * mpKeyStore = nullptr;
std::vector<FabricIndex> mFabricList;
};
} // namespace app
} // namespace chip