Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Remove direct operational certs access from FabricInfo #19531

Merged
merged 8 commits into from
Jun 13, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ using namespace ::chip::Transport;
using namespace chip::app;
using namespace chip::app::Clusters;
using namespace chip::app::Clusters::OperationalCredentials;
using namespace chip::Credentials;
using namespace chip::Protocols::InteractionModel;

namespace {
Expand Down Expand Up @@ -125,22 +126,28 @@ CHIP_ERROR OperationalCredentialsAttrAccess::ReadNOCs(EndpointId endpoint, Attri
auto accessingFabricIndex = aEncoder.AccessingFabricIndex();

return aEncoder.EncodeList([accessingFabricIndex](const auto & encoder) -> CHIP_ERROR {
for (auto & fabricInfo : Server::GetInstance().GetFabricTable())
const auto & fabricTable = Server::GetInstance().GetFabricTable();
for (auto & fabricInfo : fabricTable)
{
Clusters::OperationalCredentials::Structs::NOCStruct::Type noc;
uint8_t nocBuf[kMaxCHIPCertLength];
tcarmelveilleux marked this conversation as resolved.
Show resolved Hide resolved
uint8_t icacBuf[kMaxCHIPCertLength];
MutableByteSpan nocSpan{ nocBuf };
MutableByteSpan icacSpan{ icacBuf };
FabricIndex fabricIndex = fabricInfo.GetFabricIndex();

noc.fabricIndex = fabricInfo.GetFabricIndex();
noc.fabricIndex = fabricIndex;

if (accessingFabricIndex == fabricInfo.GetFabricIndex())
if (accessingFabricIndex == fabricIndex)
{
ByteSpan icac;

ReturnErrorOnFailure(fabricInfo.GetNOCCert(noc.noc));
ReturnErrorOnFailure(fabricInfo.GetICACert(icac));
ReturnErrorOnFailure(fabricTable.FetchNOCCert(fabricIndex, nocSpan));
ReturnErrorOnFailure(fabricTable.FetchICACert(fabricIndex, icacSpan));

if (!icac.empty())
noc.noc = nocSpan;
if (!icacSpan.empty())
{
noc.icac.SetNonNull(icac);
noc.icac.SetNonNull(icacSpan);
}
}

Expand All @@ -166,20 +173,23 @@ CHIP_ERROR OperationalCredentialsAttrAccess::ReadCommissionedFabrics(EndpointId
CHIP_ERROR OperationalCredentialsAttrAccess::ReadFabricsList(EndpointId endpoint, AttributeValueEncoder & aEncoder)
{
return aEncoder.EncodeList([](const auto & encoder) -> CHIP_ERROR {
for (auto & fabricInfo : Server::GetInstance().GetFabricTable())
const auto & fabricTable = Server::GetInstance().GetFabricTable();

for (auto & fabricInfo : fabricTable)
{
Clusters::OperationalCredentials::Structs::FabricDescriptor::Type fabricDescriptor;
FabricIndex fabricIndex = fabricInfo.GetFabricIndex();

fabricDescriptor.fabricIndex = fabricInfo.GetFabricIndex();
fabricDescriptor.fabricIndex = fabricIndex;
fabricDescriptor.nodeId = fabricInfo.GetPeerId().GetNodeId();
fabricDescriptor.vendorId = static_cast<chip::VendorId>(fabricInfo.GetVendorId());
fabricDescriptor.fabricId = fabricInfo.GetFabricId();

fabricDescriptor.label = fabricInfo.GetFabricLabel();

Credentials::P256PublicKeySpan pubKey;
ReturnErrorOnFailure(fabricInfo.GetRootPubkey(pubKey));
fabricDescriptor.rootPublicKey = pubKey;
Crypto::P256PublicKey pubKey;
ReturnErrorOnFailure(fabricTable.FetchRootPubkey(fabricIndex, pubKey));
fabricDescriptor.rootPublicKey = ByteSpan{ pubKey.ConstBytes(), pubKey.Length() };

ReturnErrorOnFailure(encoder.Encode(fabricDescriptor));
}
Expand All @@ -192,11 +202,14 @@ CHIP_ERROR OperationalCredentialsAttrAccess::ReadRootCertificates(EndpointId end
{
// It is OK to have duplicates.
return aEncoder.EncodeList([](const auto & encoder) -> CHIP_ERROR {
for (auto & fabricInfo : Server::GetInstance().GetFabricTable())
const auto & fabricTable = Server::GetInstance().GetFabricTable();

for (auto & fabricInfo : fabricTable)
{
ByteSpan cert;
ReturnErrorOnFailure(fabricInfo.GetRootCert(cert));
ReturnErrorOnFailure(encoder.Encode(cert));
uint8_t certBuf[kMaxCHIPCertLength];
MutableByteSpan cert{ certBuf };
ReturnErrorOnFailure(fabricTable.FetchRootCert(fabricInfo.GetFabricIndex(), cert));
ReturnErrorOnFailure(encoder.Encode(ByteSpan{ cert }));
}

return CHIP_NO_ERROR;
Expand Down Expand Up @@ -842,8 +855,7 @@ bool emberAfOperationalCredentialsClusterUpdateNOCCallback(app::CommandHandler *

auto & fabricTable = Server::GetInstance().GetFabricTable();
FailSafeContext & failSafeContext = DeviceControlServer::DeviceControlSvr().GetFailSafeContext();
FabricInfo * fabric = RetrieveCurrentFabric(commandObj);
ByteSpan rcac;
FabricInfo * fabricInfo = RetrieveCurrentFabric(commandObj);

VerifyOrExit(NOCValue.size() <= Credentials::kMaxCHIPCertLength, nonDefaultStatus = Status::InvalidCommand);
VerifyOrExit(!ICACValue.HasValue() || ICACValue.Value().size() <= Credentials::kMaxCHIPCertLength,
Expand All @@ -858,8 +870,8 @@ bool emberAfOperationalCredentialsClusterUpdateNOCCallback(app::CommandHandler *
VerifyOrExit(failSafeContext.IsCsrRequestForUpdateNoc(), nonDefaultStatus = Status::ConstraintError);

// If current fabric is not available, command was invoked over PASE which is not legal
VerifyOrExit(fabric != nullptr, nocResponse = ConvertToNOCResponseStatus(CHIP_ERROR_INSUFFICIENT_PRIVILEGE));
fabricIndex = fabric->GetFabricIndex();
VerifyOrExit(fabricInfo != nullptr, nocResponse = ConvertToNOCResponseStatus(CHIP_ERROR_INSUFFICIENT_PRIVILEGE));
fabricIndex = fabricInfo->GetFabricIndex();

// Initialize fields of gFabricBeingCommissioned:
// - the root certificate, fabric label, and vendor id are copied from the existing fabric record
Expand All @@ -868,16 +880,19 @@ bool emberAfOperationalCredentialsClusterUpdateNOCCallback(app::CommandHandler *
// The remaining operation id and fabric id fields will be extracted from the new operational
// credentials and set by following SetFabricInfo() call.
{
err = fabric->GetRootCert(rcac);
uint8_t rcacBuf[kMaxCHIPCertLength];
MutableByteSpan rcac{ rcacBuf };

err = fabricTable.FetchRootCert(fabricIndex, rcac);
VerifyOrExit(err == CHIP_NO_ERROR, nocResponse = ConvertToNOCResponseStatus(err));

err = gFabricBeingCommissioned.SetRootCert(rcac);
VerifyOrExit(err == CHIP_NO_ERROR, nocResponse = ConvertToNOCResponseStatus(err));

err = gFabricBeingCommissioned.SetFabricLabel(fabric->GetFabricLabel());
err = gFabricBeingCommissioned.SetFabricLabel(fabricInfo->GetFabricLabel());
VerifyOrExit(err == CHIP_NO_ERROR, nocResponse = ConvertToNOCResponseStatus(err));

gFabricBeingCommissioned.SetVendorId(fabric->GetVendorId());
gFabricBeingCommissioned.SetVendorId(fabricInfo->GetVendorId());

err = gFabricBeingCommissioned.SetNOCCert(NOCValue);
VerifyOrExit(err == CHIP_NO_ERROR, nocResponse = ConvertToNOCResponseStatus(err));
Expand Down
5 changes: 3 additions & 2 deletions src/controller/CHIPDeviceController.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -149,7 +149,7 @@ CHIP_ERROR DeviceController::InitControllerNOCChain(const ControllerInitParams &
FabricInfo newFabric;
constexpr uint32_t chipCertAllocatedLen = kMaxCHIPCertLength;
chip::Platform::ScopedMemoryBuffer<uint8_t> chipCert;
Credentials::P256PublicKeySpan rootPublicKey;
Credentials::P256PublicKeySpan rootPublicKeySpan;
FabricId fabricId;

// There are three possibilities here in terms of what happens with our
Expand All @@ -175,6 +175,8 @@ CHIP_ERROR DeviceController::InitControllerNOCChain(const ControllerInitParams &

ReturnErrorOnFailure(ConvertX509CertToChipCert(params.controllerRCAC, chipCertSpan));
ReturnErrorOnFailure(newFabric.SetRootCert(chipCertSpan));
ReturnErrorOnFailure(Credentials::ExtractPublicKeyFromChipCert(chipCertSpan, rootPublicKeySpan));
Crypto::P256PublicKey rootPublicKey{ rootPublicKeySpan };

if (params.controllerICAC.empty())
{
Expand All @@ -194,7 +196,6 @@ CHIP_ERROR DeviceController::InitControllerNOCChain(const ControllerInitParams &
ReturnErrorOnFailure(newFabric.SetNOCCert(chipCertSpan));
ReturnErrorOnFailure(ExtractFabricIdFromCert(chipCertSpan, &fabricId));

ReturnErrorOnFailure(newFabric.GetRootPubkey(rootPublicKey));
mFabricInfo = params.systemState->Fabrics()->FindFabric(rootPublicKey, fabricId);
if (mFabricInfo != nullptr)
{
Expand Down
9 changes: 9 additions & 0 deletions src/controller/CHIPDeviceController.h
Original file line number Diff line number Diff line change
Expand Up @@ -240,6 +240,15 @@ class DLL_EXPORT DeviceController : public AbstractDnssdDiscoveryController

FabricInfo * GetFabricInfo() { return mFabricInfo; }

const FabricTable * GetFabricTable() const
{
if (mSystemState == nullptr)
{
return nullptr;
}
return mSystemState->Fabrics();
}

void ReleaseOperationalDevice(NodeId remoteDeviceId);

OperationalCredentialsDelegate * GetOperationalCredentialsDelegate() { return mOperationalCredentialsDelegate; }
Expand Down
91 changes: 69 additions & 22 deletions src/credentials/FabricTable.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -435,11 +435,23 @@ CHIP_ERROR FabricInfo::VerifyCredentials(const ByteSpan & noc, const ByteSpan &
}

ReturnErrorOnFailure(GeneratePeerId(rcac, fabricId, nodeId, &nocPeerId));
nocPubkey = P256PublicKey(certificates.GetLastCert()[0].mPublicKey);
nocPubkey = certificates.GetLastCert()[0].mPublicKey;

return CHIP_NO_ERROR;
}

CHIP_ERROR FabricInfo::FetchRootPubkey(Crypto::P256PublicKey & outPublicKey) const
{
P256PublicKeySpan publicKeySpan;
CHIP_ERROR err = Credentials::ExtractPublicKeyFromChipCert(mRootCert, publicKeySpan);
if (err == CHIP_NO_ERROR)
{
outPublicKey = publicKeySpan;
}

return err;
}

FabricTable::~FabricTable()
{
// Remove all links to every delegate
Expand All @@ -452,24 +464,25 @@ FabricTable::~FabricTable()
}
}

FabricInfo * FabricTable::FindFabric(P256PublicKeySpan rootPubKey, FabricId fabricId)
FabricInfo * FabricTable::FindFabric(const Crypto::P256PublicKey & rootPubKey, FabricId fabricId)
{
for (auto & fabric : mStates)
{
if (!fabric.IsInitialized())
{
continue;
}
P256PublicKeySpan candidatePubKey;
if (fabric.GetRootPubkey(candidatePubKey) != CHIP_NO_ERROR)
P256PublicKey candidatePubKey;
if (fabric.FetchRootPubkey(candidatePubKey) != CHIP_NO_ERROR)
{
continue;
}
if (rootPubKey.data_equal(candidatePubKey) && fabricId == fabric.GetFabricId())
if (rootPubKey.Matches(candidatePubKey) && fabricId == fabric.GetFabricId())
{
return &fabric;
}
}

return nullptr;
}

Expand Down Expand Up @@ -526,6 +539,34 @@ FabricInfo * FabricTable::FindFabricWithCompressedId(CompressedFabricId fabricId
return nullptr;
}

CHIP_ERROR FabricTable::FetchRootCert(FabricIndex fabricIndex, MutableByteSpan & outCert) const
{
const FabricInfo * fabricInfo = FindFabricWithIndex(fabricIndex);
ReturnErrorCodeIf(fabricInfo == nullptr, CHIP_ERROR_INVALID_FABRIC_INDEX);
return fabricInfo->FetchRootCert(outCert);
}

CHIP_ERROR FabricTable::FetchICACert(FabricIndex fabricIndex, MutableByteSpan & outCert) const
{
const FabricInfo * fabricInfo = FindFabricWithIndex(fabricIndex);
ReturnErrorCodeIf(fabricInfo == nullptr, CHIP_ERROR_INVALID_FABRIC_INDEX);
return fabricInfo->FetchICACert(outCert);
}

CHIP_ERROR FabricTable::FetchNOCCert(FabricIndex fabricIndex, MutableByteSpan & outCert) const
{
const FabricInfo * fabricInfo = FindFabricWithIndex(fabricIndex);
ReturnErrorCodeIf(fabricInfo == nullptr, CHIP_ERROR_INVALID_FABRIC_INDEX);
return fabricInfo->FetchNOCCert(outCert);
}

CHIP_ERROR FabricTable::FetchRootPubkey(FabricIndex fabricIndex, Crypto::P256PublicKey & outPublicKey) const
{
const FabricInfo * fabricInfo = FindFabricWithIndex(fabricIndex);
ReturnErrorCodeIf(fabricInfo == nullptr, CHIP_ERROR_INVALID_FABRIC_INDEX);
return fabricInfo->FetchRootPubkey(outPublicKey);
}

CHIP_ERROR FabricTable::Store(FabricIndex fabricIndex)
{
CHIP_ERROR err = CHIP_NO_ERROR;
Expand Down Expand Up @@ -658,19 +699,22 @@ CHIP_ERROR FabricTable::AddNewFabric(FabricInfo & newFabric, FabricIndex * outpu
// comparison.
FabricId fabricId;
{
ByteSpan noc;
ReturnErrorOnFailure(newFabric.GetNOCCert(noc));
uint8_t nocBuf[kMaxCHIPCertLength];
MutableByteSpan nocSpan{ nocBuf };
ReturnErrorOnFailure(newFabric.FetchNOCCert(nocSpan));
NodeId unused;
ReturnErrorOnFailure(ExtractNodeIdFabricIdFromOpCert(noc, &unused, &fabricId));
ReturnErrorOnFailure(ExtractNodeIdFabricIdFromOpCert(nocSpan, &unused, &fabricId));
}

for (auto & existingFabric : *this)
{
if (existingFabric.GetFabricId() == fabricId)
{
P256PublicKeySpan existingRootKey, newRootKey;
ReturnErrorOnFailure(existingFabric.GetRootPubkey(existingRootKey));
ReturnErrorOnFailure(newFabric.GetRootPubkey(newRootKey));
if (existingRootKey.data_equal(newRootKey))
P256PublicKey existingRootKey, newRootKey;
ReturnErrorOnFailure(existingFabric.FetchRootPubkey(existingRootKey));
ReturnErrorOnFailure(newFabric.FetchRootPubkey(newRootKey));

if (existingRootKey.Matches(newRootKey))
{
return CHIP_ERROR_FABRIC_EXISTS;
}
Expand Down Expand Up @@ -973,27 +1017,30 @@ CHIP_ERROR FabricTable::SetLastKnownGoodChipEpochTime(System::Clock::Seconds32 l
continue;
}
{
ByteSpan rcac;
SuccessOrExit(err = fabric.GetRootCert(rcac));
uint8_t rcacBuf[kMaxCHIPCertLength];
MutableByteSpan rcacSpan{ rcacBuf };
SuccessOrExit(err = fabric.FetchRootCert(rcacSpan));
chip::System::Clock::Seconds32 rcacNotBefore;
SuccessOrExit(err = Credentials::ExtractNotBeforeFromChipCert(rcac, rcacNotBefore));
SuccessOrExit(err = Credentials::ExtractNotBeforeFromChipCert(rcacSpan, rcacNotBefore));
latestNotBefore = rcacNotBefore > latestNotBefore ? rcacNotBefore : latestNotBefore;
}
{
ByteSpan icac;
SuccessOrExit(err = fabric.GetICACert(icac));
if (!icac.empty())
uint8_t icacBuf[kMaxCHIPCertLength];
MutableByteSpan icacSpan{ icacBuf };
SuccessOrExit(err = fabric.FetchICACert(icacSpan));
if (!icacSpan.empty())
{
chip::System::Clock::Seconds32 icacNotBefore;
ReturnErrorOnFailure(Credentials::ExtractNotBeforeFromChipCert(icac, icacNotBefore));
ReturnErrorOnFailure(Credentials::ExtractNotBeforeFromChipCert(icacSpan, icacNotBefore));
latestNotBefore = icacNotBefore > latestNotBefore ? icacNotBefore : latestNotBefore;
}
}
{
ByteSpan noc;
SuccessOrExit(err = fabric.GetNOCCert(noc));
uint8_t nocBuf[kMaxCHIPCertLength];
MutableByteSpan nocSpan{ nocBuf };
SuccessOrExit(err = fabric.FetchNOCCert(nocSpan));
chip::System::Clock::Seconds32 nocNotBefore;
ReturnErrorOnFailure(Credentials::ExtractNotBeforeFromChipCert(noc, nocNotBefore));
ReturnErrorOnFailure(Credentials::ExtractNotBeforeFromChipCert(nocSpan, nocNotBefore));
latestNotBefore = nocNotBefore > latestNotBefore ? nocNotBefore : latestNotBefore;
}
}
Expand Down
Loading