blob: 16a97b74996652e68c99cd8cc71f448efd379ad5 [file] [log] [blame]
/*
* Copyright (c) 2025 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 <credentials/FabricTable.h>
#include <credentials/PersistentStorageOpCertStore.h>
#include <crypto/CHIPCryptoPAL.h>
#include <lib/core/CHIPError.h>
#include <lib/core/CHIPPersistentStorageDelegate.h>
#include <lib/support/logging/CHIPLogging.h>
#include <memory>
#include <optional>
#include <vector>
namespace chip {
namespace Testing {
/**
* @brief Fixture class to manage the lifecycle of a Fabric for testing.
*
* This encapsulates the logic required to initialize a FabricTable,
* create a mock Fabric, and manage related certificate storage.
* It is designed to be used by ClusterTester or a test fixture but not mandatory.
*/
class FabricTestFixture
{
public:
FabricTestFixture(PersistentStorageDelegate * storage) :
mStorage(storage), mRootCertSpan(mRootCertDER, sizeof(mRootCertDER)), mNocSpan(mNocDER, sizeof(mNocDER))
{}
/**
* @brief Initializes the Fabric table and adds a new test fabric.
*
* @param fabricIndexOut Output parameter for the newly created FabricIndex.
* @return CHIP_ERROR
*/
CHIP_ERROR SetUpTestFabric(FabricIndex & fabricIndexOut)
{
ReturnErrorOnFailure(mOpCertStore.Init(mStorage));
initParams.opCertStore = &mOpCertStore;
initParams.storage = mStorage;
initParams.operationalKeystore = nullptr; // Use default
ReturnErrorOnFailure(mfabricTable.Init(initParams));
ReturnErrorOnFailure(mfabricTable.SetFabricIndexForNextAddition(fabricIndexOut));
ReturnErrorOnFailure(SetUpCertificates());
CHIP_ERROR err = mfabricTable.AddNewFabricForTest(
mRootCertSpan, ByteSpan(), mNocSpan, ByteSpan(mSerializedOpKey.Bytes(), mSerializedOpKey.Length()), &fabricIndexOut);
ReturnErrorOnFailure(err);
return mfabricTable.CommitPendingFabricData();
}
/**
* @brief Tears down the created fabric and cleans up storage.
*
* @param fabricIndex The FabricIndex to tear down.
* @return CHIP_ERROR
*/
CHIP_ERROR TearDownTestFabric(FabricIndex & fabricIndex)
{
VerifyOrReturnError(IsValidFabricIndex(fabricIndex), CHIP_ERROR_INVALID_FABRIC_INDEX);
// Credentials::SetGroupDataProvider(nullptr); // Done in the test fixture's TearDown
// GroupDataProviderImpl::RemoveFabric is usually done separately
// However, we just need to ensure the fabric is deleted from FabricTable and storage is cleaned.
CHIP_ERROR err = CHIP_NO_ERROR;
if ((err = mOpCertStore.RemoveOpCertsForFabric(fabricIndex)) != CHIP_NO_ERROR)
{
ChipLogError(Test, "TearDownFabric: RemoveOpCertsForFabric failed: %" CHIP_ERROR_FORMAT, err.Format());
}
if ((err = mfabricTable.Delete(fabricIndex)) != CHIP_NO_ERROR)
{
ChipLogError(Test, "TearDownFabric: Delete fabric failed: %" CHIP_ERROR_FORMAT, err.Format());
}
mfabricTable.Shutdown();
mOpCertStore.Finish();
return CHIP_NO_ERROR;
}
FabricTable & GetFabricTable() { return mfabricTable; }
private:
CHIP_ERROR SetUpCertificates()
{
Crypto::P256Keypair rootCACredentials;
ReturnErrorOnFailure(rootCACredentials.Initialize(Crypto::ECPKeyTarget::ECDSA));
Crypto::P256Keypair deviceOpKey;
ReturnErrorOnFailure(deviceOpKey.Initialize(Crypto::ECPKeyTarget::ECDSA));
ReturnErrorOnFailure(deviceOpKey.Serialize(mSerializedOpKey));
// Create temporary X.509 (DER) buffers
uint8_t rootCertDER_temp[chip::Credentials::kMaxDERCertLength];
MutableByteSpan rootCertDERSpan(rootCertDER_temp);
uint8_t nocDER_temp[chip::Credentials::kMaxDERCertLength];
MutableByteSpan nocDERSpan(nocDER_temp);
mRootCertSpan = MutableByteSpan(mRootCertDER);
mNocSpan = MutableByteSpan(mNocDER);
chip::Credentials::X509CertRequestParams rootRequestParams;
rootRequestParams.SerialNumber = kRootCertSerial;
rootRequestParams.ValidityStart = kCertValidityStart;
rootRequestParams.ValidityEnd = kRootCertValidityDurationSeconds;
const char * rootName = "My Test Root CA";
ReturnErrorOnFailure(rootRequestParams.IssuerDN.AddAttribute(
chip::ASN1::kOID_AttributeType_CommonName, CharSpan(rootName, strlen(rootName)), true /* isPrintableString */
));
ReturnErrorOnFailure(rootRequestParams.IssuerDN.AddAttribute(chip::ASN1::kOID_AttributeType_MatterRCACId, kTestRcacId));
rootRequestParams.SubjectDN = rootRequestParams.IssuerDN;
ReturnErrorOnFailure(chip::Credentials::NewRootX509Cert(rootRequestParams, rootCACredentials, rootCertDERSpan));
// Convert X.509 DER to Matter TLV
ReturnErrorOnFailure(chip::Credentials::ConvertX509CertToChipCert(rootCertDERSpan, mRootCertSpan));
chip::Credentials::X509CertRequestParams nocRequestParams;
nocRequestParams.SerialNumber = kNocSerial;
nocRequestParams.ValidityStart = kCertValidityStart;
nocRequestParams.ValidityEnd = kNocCertValidityDurationSeconds;
nocRequestParams.IssuerDN = rootRequestParams.SubjectDN;
ReturnErrorOnFailure(nocRequestParams.SubjectDN.AddAttribute(chip::ASN1::kOID_AttributeType_MatterFabricId, kTestFabricId));
ReturnErrorOnFailure(nocRequestParams.SubjectDN.AddAttribute(chip::ASN1::kOID_AttributeType_MatterNodeId, kTestNodeId));
ReturnErrorOnFailure(
chip::Credentials::NewNodeOperationalX509Cert(nocRequestParams, deviceOpKey.Pubkey(), rootCACredentials, nocDERSpan));
return chip::Credentials::ConvertX509CertToChipCert(nocDERSpan, mNocSpan);
}
PersistentStorageDelegate * mStorage;
// Certificates and keys
uint8_t mRootCertDER[chip::Credentials::kMaxDERCertLength];
MutableByteSpan mRootCertSpan;
uint8_t mNocDER[chip::Credentials::kMaxDERCertLength];
MutableByteSpan mNocSpan;
Crypto::P256SerializedKeypair mSerializedOpKey;
// Fabric-related storage
chip::Credentials::PersistentStorageOpCertStore mOpCertStore;
FabricTable mfabricTable;
FabricTable::InitParams initParams;
// Test constants (copied from test fixture)
static constexpr FabricId kTestFabricId = 0xDEADBEEF00000001;
static constexpr NodeId kTestNodeId = 0xDEADBEEF00000002;
static constexpr uint64_t kTestRcacId = 0x1111222233334444;
static constexpr uint64_t kRootCertSerial = 1;
static constexpr uint64_t kNocSerial = 2;
static constexpr uint64_t kCertValidityStart = 0;
static constexpr uint32_t kRootCertValidityDurationSeconds = 315360000; // 10 years
static constexpr uint32_t kNocCertValidityDurationSeconds = 31536000; // 1 year
};
} // namespace Testing
} // namespace chip