Skip to content

Commit

Permalink
Add ability to add pending fabric at a chosen fabric index (#33646)
Browse files Browse the repository at this point in the history
Currently it's only possible to allocate fabric indexes sequentially
starting from 1.

Sparse fabric tables could be produced by adding & removing fabrics,
but not directly.

This allow the application to control the assignment of fabric ids
directly by providing a function that overrides the next index to use.

eg If an application has 3 fabrics, it can recreate the fabric table
from scratch while keeping consistent indexes.
  • Loading branch information
mspang authored and pull[bot] committed Aug 15, 2024
1 parent fbba46a commit 1691108
Show file tree
Hide file tree
Showing 4 changed files with 120 additions and 16 deletions.
12 changes: 12 additions & 0 deletions src/credentials/FabricTable.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2124,4 +2124,16 @@ CHIP_ERROR FabricTable::PeekFabricIndexForNextAddition(FabricIndex & outIndex)
return CHIP_NO_ERROR;
}

CHIP_ERROR FabricTable::SetFabricIndexForNextAddition(FabricIndex fabricIndex)
{
VerifyOrReturnError(!mStateFlags.Has(StateFlags::kIsPendingFabricDataPresent), CHIP_ERROR_INCORRECT_STATE);
VerifyOrReturnError(IsValidFabricIndex(fabricIndex), CHIP_ERROR_INVALID_FABRIC_INDEX);

const FabricInfo * fabricInfo = FindFabricWithIndex(fabricIndex);
VerifyOrReturnError(fabricInfo == nullptr, CHIP_ERROR_FABRIC_EXISTS);

mNextAvailableFabricIndex.SetValue(fabricIndex);
return CHIP_NO_ERROR;
}

} // namespace chip
7 changes: 7 additions & 0 deletions src/credentials/FabricTable.h
Original file line number Diff line number Diff line change
Expand Up @@ -1003,6 +1003,13 @@ class DLL_EXPORT FabricTable
*/
CHIP_ERROR PeekFabricIndexForNextAddition(FabricIndex & outIndex);

/**
* Set the fabric index that will be used fo the next fabric added.
*
* Returns an error if the |fabricIndex| is already in use.
*/
CHIP_ERROR SetFabricIndexForNextAddition(FabricIndex fabricIndex);

private:
enum class StateFlags : uint16_t
{
Expand Down
20 changes: 20 additions & 0 deletions src/credentials/tests/CHIPCert_test_vectors.h
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,8 @@ extern const ByteSpan sTestCert_Node01_01_PublicKey;
extern const ByteSpan sTestCert_Node01_01_PrivateKey;
extern const ByteSpan sTestCert_Node01_01_SubjectKeyId;
extern const ByteSpan sTestCert_Node01_01_AuthorityKeyId;
inline constexpr NodeId kTestCert_Node01_01_NodeId = 0xDEDEDEDE00010001;
inline constexpr FabricId kTestCert_Node01_01_FabricId = 0xFAB000000000001D;

extern const ByteSpan sTestCert_Node01_01_Err01_Chip;

Expand All @@ -149,62 +151,80 @@ extern const ByteSpan sTestCert_Node01_02_PublicKey;
extern const ByteSpan sTestCert_Node01_02_PrivateKey;
extern const ByteSpan sTestCert_Node01_02_SubjectKeyId;
extern const ByteSpan sTestCert_Node01_02_AuthorityKeyId;
inline constexpr NodeId kTestCert_Node01_02_NodeId = 0xDEDEDEDE00010002;
inline constexpr FabricId kTestCert_Node01_02_FabricId = 0xFAB000000000001D;

extern const ByteSpan sTestCert_Node02_01_Chip;
extern const ByteSpan sTestCert_Node02_01_DER;
extern const ByteSpan sTestCert_Node02_01_PublicKey;
extern const ByteSpan sTestCert_Node02_01_PrivateKey;
extern const ByteSpan sTestCert_Node02_01_SubjectKeyId;
extern const ByteSpan sTestCert_Node02_01_AuthorityKeyId;
inline constexpr NodeId kTestCert_Node02_01_NodeId = 0xDEDEDEDE00020001;
inline constexpr FabricId kTestCert_Node02_01_FabricId = 0xFAB000000000001D;

extern const ByteSpan sTestCert_Node02_02_Chip;
extern const ByteSpan sTestCert_Node02_02_DER;
extern const ByteSpan sTestCert_Node02_02_PublicKey;
extern const ByteSpan sTestCert_Node02_02_PrivateKey;
extern const ByteSpan sTestCert_Node02_02_SubjectKeyId;
extern const ByteSpan sTestCert_Node02_02_AuthorityKeyId;
inline constexpr NodeId kTestCert_Node02_02_NodeId = 0xDEDEDEDE00020002;
inline constexpr FabricId kTestCert_Node02_02_FabricId = 0xFAB000000000001D;

extern const ByteSpan sTestCert_Node02_03_Chip;
extern const ByteSpan sTestCert_Node02_03_DER;
extern const ByteSpan sTestCert_Node02_03_PublicKey;
extern const ByteSpan sTestCert_Node02_03_PrivateKey;
extern const ByteSpan sTestCert_Node02_03_SubjectKeyId;
extern const ByteSpan sTestCert_Node02_03_AuthorityKeyId;
inline constexpr NodeId kTestCert_Node02_03_NodeId = 0xDEDEDEDE00020003;
inline constexpr FabricId kTestCert_Node02_03_FabricId = 0xFAB000000000001D;

extern const ByteSpan sTestCert_Node02_04_Chip;
extern const ByteSpan sTestCert_Node02_04_DER;
extern const ByteSpan sTestCert_Node02_04_PublicKey;
extern const ByteSpan sTestCert_Node02_04_PrivateKey;
extern const ByteSpan sTestCert_Node02_04_SubjectKeyId;
extern const ByteSpan sTestCert_Node02_04_AuthorityKeyId;
inline constexpr NodeId kTestCert_Node02_04_NodeId = 0xDEDEDEDE00020004;
inline constexpr FabricId kTestCert_Node02_04_FabricId = 0xFAB000000000001D;

extern const ByteSpan sTestCert_Node02_05_Chip;
extern const ByteSpan sTestCert_Node02_05_DER;
extern const ByteSpan sTestCert_Node02_05_PublicKey;
extern const ByteSpan sTestCert_Node02_05_PrivateKey;
extern const ByteSpan sTestCert_Node02_05_SubjectKeyId;
extern const ByteSpan sTestCert_Node02_05_AuthorityKeyId;
inline constexpr NodeId kTestCert_Node02_05_NodeId = 0xDEDEDEDE00020005;
inline constexpr FabricId kTestCert_Node02_05_FabricId = 0xFAB000000000001D;

extern const ByteSpan sTestCert_Node02_06_Chip;
extern const ByteSpan sTestCert_Node02_06_DER;
extern const ByteSpan sTestCert_Node02_06_PublicKey;
extern const ByteSpan sTestCert_Node02_06_PrivateKey;
extern const ByteSpan sTestCert_Node02_06_SubjectKeyId;
extern const ByteSpan sTestCert_Node02_06_AuthorityKeyId;
inline constexpr NodeId kTestCert_Node02_06_NodeId = 0xDEDEDEDE00020006;
inline constexpr FabricId kTestCert_Node02_06_FabricId = 0xFAB000000000001D;

extern const ByteSpan sTestCert_Node02_07_Chip;
extern const ByteSpan sTestCert_Node02_07_DER;
extern const ByteSpan sTestCert_Node02_07_PublicKey;
extern const ByteSpan sTestCert_Node02_07_PrivateKey;
extern const ByteSpan sTestCert_Node02_07_SubjectKeyId;
extern const ByteSpan sTestCert_Node02_07_AuthorityKeyId;
inline constexpr NodeId kTestCert_Node02_07_NodeId = 0xDEDEDEDE00020007;
inline constexpr FabricId kTestCert_Node02_07_FabricId = 0xFAB000000000001D;

extern const ByteSpan sTestCert_Node02_08_Chip;
extern const ByteSpan sTestCert_Node02_08_DER;
extern const ByteSpan sTestCert_Node02_08_PublicKey;
extern const ByteSpan sTestCert_Node02_08_PrivateKey;
extern const ByteSpan sTestCert_Node02_08_SubjectKeyId;
extern const ByteSpan sTestCert_Node02_08_AuthorityKeyId;
inline constexpr NodeId kTestCert_Node02_08_NodeId = 0xDEDEDEDE00020008;
inline constexpr FabricId kTestCert_Node02_08_FabricId = 0xFAB000000000001D;

extern const ByteSpan sTestCert_PDCID01_Chip;
extern const ByteSpan sTestCert_PDCID01_ChipCompact;
Expand Down
97 changes: 81 additions & 16 deletions src/credentials/tests/TestFabricTable.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -183,6 +183,18 @@ static CHIP_ERROR LoadTestFabric_Node02_01(FabricTable & fabricTable, bool doCom
return err;
}

const FabricInfo * FindFabric(FabricTable & fabricTable, ByteSpan rootPublicKey, FabricId fabricId)
{
Crypto::P256PublicKey key;
EXPECT_GE(key.Length(), rootPublicKey.size());
if (key.Length() < rootPublicKey.size())
{
return nullptr;
}
memcpy(key.Bytes(), rootPublicKey.data(), rootPublicKey.size());
return fabricTable.FindFabric(key, fabricId);
}

struct TestFabricTable : public ::testing::Test
{

Expand Down Expand Up @@ -2279,16 +2291,13 @@ TEST_F(TestFabricTable, TestFabricLookup)
EXPECT_EQ(LoadTestFabric_Node01_01(fabricTable, /* doCommit = */ true), CHIP_NO_ERROR);
EXPECT_EQ(LoadTestFabric_Node02_01(fabricTable, /* doCommit = */ true, FabricTable::AdvertiseIdentity::No), CHIP_NO_ERROR);

// These two NOCs have the same fabric id on purpose; only the trust root is
// different.
constexpr FabricId kNode01_01_and_02_01_FabricId = 0xFAB000000000001D;

// Attempt lookup of the Root01 fabric.
{
Crypto::P256PublicKey key;
EXPECT_GE(key.Length(), TestCerts::sTestCert_Root01_PublicKey.size());
if (key.Length() < TestCerts::sTestCert_Root01_PublicKey.size())
{
return;
}
memcpy(key.Bytes(), TestCerts::sTestCert_Root01_PublicKey.data(), TestCerts::sTestCert_Root01_PublicKey.size());
auto fabricInfo = fabricTable.FindFabric(key, 0xFAB000000000001D);
auto fabricInfo = FindFabric(fabricTable, TestCerts::sTestCert_Root01_PublicKey, kNode01_01_and_02_01_FabricId);
ASSERT_NE(fabricInfo, nullptr);

EXPECT_EQ(fabricInfo->GetFabricIndex(), 1);
Expand All @@ -2297,14 +2306,7 @@ TEST_F(TestFabricTable, TestFabricLookup)

// Attempt lookup of the Root02 fabric.
{
Crypto::P256PublicKey key;
EXPECT_GE(key.Length(), TestCerts::sTestCert_Root02_PublicKey.size());
if (key.Length() < TestCerts::sTestCert_Root02_PublicKey.size())
{
return;
}
memcpy(key.Bytes(), TestCerts::sTestCert_Root02_PublicKey.data(), TestCerts::sTestCert_Root02_PublicKey.size());
auto fabricInfo = fabricTable.FindFabric(key, 0xFAB000000000001D);
auto fabricInfo = FindFabric(fabricTable, TestCerts::sTestCert_Root02_PublicKey, kNode01_01_and_02_01_FabricId);
ASSERT_NE(fabricInfo, nullptr);

EXPECT_EQ(fabricInfo->GetFabricIndex(), 2);
Expand All @@ -2317,6 +2319,69 @@ TEST_F(TestFabricTable, TestFabricLookup)
}
}

TEST_F(TestFabricTable, ShouldFailSetFabricIndexWithInvalidIndex)
{
chip::TestPersistentStorageDelegate testStorage;
ScopedFabricTable fabricTableHolder;
EXPECT_EQ(fabricTableHolder.Init(&testStorage), CHIP_NO_ERROR);
FabricTable & fabricTable = fabricTableHolder.GetFabricTable();

EXPECT_EQ(fabricTable.SetFabricIndexForNextAddition(kUndefinedFabricIndex), CHIP_ERROR_INVALID_FABRIC_INDEX);
}

TEST_F(TestFabricTable, ShouldFailSetFabricIndexWithPendingFabric)
{
chip::TestPersistentStorageDelegate testStorage;
ScopedFabricTable fabricTableHolder;
EXPECT_EQ(fabricTableHolder.Init(&testStorage), CHIP_NO_ERROR);
FabricTable & fabricTable = fabricTableHolder.GetFabricTable();

EXPECT_EQ(fabricTable.AddNewPendingTrustedRootCert(ByteSpan(TestCerts::sTestCert_Root01_Chip)), CHIP_NO_ERROR);

EXPECT_EQ(fabricTable.SetFabricIndexForNextAddition(1), CHIP_ERROR_INCORRECT_STATE);
}

TEST_F(TestFabricTable, ShouldFailSetFabricIndexWhenInUse)
{
chip::TestPersistentStorageDelegate testStorage;
ScopedFabricTable fabricTableHolder;
EXPECT_EQ(fabricTableHolder.Init(&testStorage), CHIP_NO_ERROR);
FabricTable & fabricTable = fabricTableHolder.GetFabricTable();

EXPECT_EQ(LoadTestFabric_Node01_01(fabricTable, /* doCommit = */ true), CHIP_NO_ERROR);
EXPECT_EQ(fabricTable.SetFabricIndexForNextAddition(1), CHIP_ERROR_FABRIC_EXISTS);
}

TEST_F(TestFabricTable, ShouldAddFabricAtRequestedIndex)
{
chip::TestPersistentStorageDelegate testStorage;
ScopedFabricTable fabricTableHolder;
EXPECT_EQ(fabricTableHolder.Init(&testStorage), CHIP_NO_ERROR);
FabricTable & fabricTable = fabricTableHolder.GetFabricTable();

EXPECT_EQ(fabricTable.SetFabricIndexForNextAddition(2), CHIP_NO_ERROR);
EXPECT_EQ(LoadTestFabric_Node02_01(fabricTable, /* doCommit = */ true), CHIP_NO_ERROR);

EXPECT_EQ(fabricTable.SetFabricIndexForNextAddition(1), CHIP_NO_ERROR);
EXPECT_EQ(LoadTestFabric_Node01_01(fabricTable, /* doCommit = */ true), CHIP_NO_ERROR);

{
auto fabricInfo = FindFabric(fabricTable, TestCerts::sTestCert_Root01_PublicKey, TestCerts::kTestCert_Node01_01_FabricId);
ASSERT_NE(fabricInfo, nullptr);
EXPECT_EQ(fabricInfo->GetFabricIndex(), 1);
EXPECT_EQ(fabricInfo->GetNodeId(), TestCerts::kTestCert_Node01_01_NodeId);
EXPECT_EQ(fabricInfo->GetFabricId(), TestCerts::kTestCert_Node01_01_FabricId);
}

{
auto fabricInfo = FindFabric(fabricTable, TestCerts::sTestCert_Root02_PublicKey, TestCerts::kTestCert_Node02_01_FabricId);
ASSERT_NE(fabricInfo, nullptr);
EXPECT_EQ(fabricInfo->GetFabricIndex(), 2);
EXPECT_EQ(fabricInfo->GetNodeId(), TestCerts::kTestCert_Node02_01_NodeId);
EXPECT_EQ(fabricInfo->GetFabricId(), TestCerts::kTestCert_Node02_01_FabricId);
}
}

TEST_F(TestFabricTable, TestFetchCATs)
{
// Initialize a fabric table.
Expand Down

0 comments on commit 1691108

Please sign in to comment.