Skip to content

Commit

Permalink
Add ability to add pending fabric at a chosen fabric index (project-c…
Browse files Browse the repository at this point in the history
…hip#33646)

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 Jun 3, 2024
1 parent 5dd912f commit 9217d22
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 9217d22

Please sign in to comment.