Skip to content

Commit

Permalink
Add ability to add pending fabric at a chosen fabric index
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 committed Jun 3, 2024
1 parent 8a64366 commit 5b20da0
Show file tree
Hide file tree
Showing 3 changed files with 97 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
94 changes: 78 additions & 16 deletions src/credentials/tests/TestFabricTable.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,11 @@ class ScopedFabricTable
chip::Credentials::PersistentStorageOpCertStore mOpCertStore;
};

// These two fabric ids are supposed to be the same; only the trust root is
// different.
constexpr FabricId kNode01_01_FabricId = 0xFAB000000000001D;
constexpr FabricId kNode02_01_FabricId = 0xFAB000000000001D;

/**
* Load a single test fabric with with the Root01:ICA01:Node01_01 identity.
*/
Expand Down Expand Up @@ -183,6 +188,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 @@ -2281,14 +2298,7 @@ TEST_F(TestFabricTable, TestFabricLookup)

// 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_FabricId);
ASSERT_NE(fabricInfo, nullptr);

EXPECT_EQ(fabricInfo->GetFabricIndex(), 1);
Expand All @@ -2297,14 +2307,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, kNode02_01_FabricId);
ASSERT_NE(fabricInfo, nullptr);

EXPECT_EQ(fabricInfo->GetFabricIndex(), 2);
Expand All @@ -2317,6 +2320,65 @@ 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, kNode01_01_FabricId);
ASSERT_NE(fabricInfo, nullptr);
EXPECT_EQ(fabricInfo->GetFabricIndex(), 1);
}

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

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

0 comments on commit 5b20da0

Please sign in to comment.