Skip to content

Commit

Permalink
Implement CASE processing of IPK (#16737)
Browse files Browse the repository at this point in the history
* Implement CASE processing of IPK

Problem:
- IPK processing used placeholder IPK at innermost levels of
  CASE and never used the values set in GroupDataProvider as
  set by Commissioner with AddNOC or KeySetWrite cluster
  commands.
- IPK Processing requires significant state keeping by
  controllers and commissioners to work, and none of the
  plumbing existed

Changes:
- Fixed NOC Cluster setting of IPK in AddNOC that was using
  the wrong compressed fabric ID.
- Properly use GroupDataProvider to get IPK for controllers
  sending Sigma1
- Properly iterate through all IPK on receiving Sigma1, from
  GroupDataProvider
- Add plumbing to properly initialize GroupDataProvider at
  CHIPDeviceControllerFactory and Server
- Added a central point for a default IPK, that is at the very
  outermost level, rather than innermost level. A follow-up
  PR will allow reconfiguration of it for CHIP-tool. Code paths
  will properly use the OperationalCredentialsDelegate's IPK
  value passed in Callback, if you it's provided. Controllers and
  commissioners can setup their GroupDataProvider context to
  properly use the right group keys even without the
  follow-up to allow non-default IPK in chip-tool.
- Cleaned-up the loose ends around all the injection points

Testing done:
- Updated all necessary Unit tests
- Added IPK and Destination ID unit test cases from spec
- All cert tests still pass
- All unit tests still pass

Fixes #15583

* Restyled by clang-format

* Fix a few remaining TODOs

* First pass of fixing leftover CI

* Restyled by clang-format

* More CI fixes

* Restyled by clang-format

* Apply suggestions from code review

Co-authored-by: Michael Sandstedt <[email protected]>

* Restyled by clang-format

* Revert pHYRate change

* Hook up IPKs on Darwin.

* Fix more CI on Python, Android, TV app

* Restyled by clang-format

* Apply review comment

* Fix Python repl

* Restyled by clang-format

* Fix shutdown of group data provider

* Fix Darwin and Android CI

* More fixing of Android CI

Co-authored-by: Restyled.io <[email protected]>
Co-authored-by: Michael Sandstedt <[email protected]>
Co-authored-by: Boris Zbarsky <[email protected]>
  • Loading branch information
4 people authored and pull[bot] committed Jan 19, 2024
1 parent 0797895 commit ad83634
Show file tree
Hide file tree
Showing 49 changed files with 1,269 additions and 513 deletions.
32 changes: 27 additions & 5 deletions examples/chip-tool/commands/common/CHIPCommand.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -72,8 +72,20 @@ CHIP_ERROR CHIPCommand::MaybeSetUpStack()
ReturnLogErrorOnFailure(mDefaultStorage.Init());

chip::Controller::FactoryInitParams factoryInitParams;

factoryInitParams.fabricIndependentStorage = &mDefaultStorage;
uint16_t port = mDefaultStorage.GetListenPort();

// Init group data provider that will be used for all group keys and IPKs for the
// chip-tool-configured fabrics. This is OK to do once since the fabric tables
// and the DeviceControllerFactory all "share" in the same underlying data.
// Different commissioner implementations may want to use alternate implementations
// of GroupDataProvider for injection through factoryInitParams.
mGroupDataProvider.SetStorageDelegate(&mDefaultStorage);
ReturnLogErrorOnFailure(mGroupDataProvider.Init());
chip::Credentials::SetGroupDataProvider(&mGroupDataProvider);
factoryInitParams.groupDataProvider = &mGroupDataProvider;

uint16_t port = mDefaultStorage.GetListenPort();
if (port != 0)
{
// Make sure different commissioners run on different ports.
Expand Down Expand Up @@ -101,8 +113,7 @@ CHIP_ERROR CHIPCommand::MaybeSetUpStack()
ReturnLogErrorOnFailure(InitializeCommissioner(kIdentityBeta, kIdentityBetaFabricId, trustStore));
ReturnLogErrorOnFailure(InitializeCommissioner(kIdentityGamma, kIdentityGammaFabricId, trustStore));

// Initialize Group Data
ReturnLogErrorOnFailure(chip::GroupTesting::InitProvider(mDefaultStorage));
// Initialize Group Data, including IPK
for (auto it = mCommissioners.begin(); it != mCommissioners.end(); it++)
{
chip::FabricInfo * fabric = it->second->GetFabricInfo();
Expand All @@ -111,7 +122,17 @@ CHIP_ERROR CHIPCommand::MaybeSetUpStack()
uint8_t compressed_fabric_id[sizeof(uint64_t)];
chip::MutableByteSpan compressed_fabric_id_span(compressed_fabric_id);
ReturnLogErrorOnFailure(fabric->GetCompressedId(compressed_fabric_id_span));
ReturnLogErrorOnFailure(chip::GroupTesting::InitData(fabric->GetFabricIndex(), compressed_fabric_id_span));

ReturnLogErrorOnFailure(
chip::GroupTesting::InitData(&mGroupDataProvider, fabric->GetFabricIndex(), compressed_fabric_id_span));

// Configure the default IPK for all fabrics used by CHIP-tool. The epoch
// key is the same, but the derived keys will be different for each fabric.
// This has to be done here after we know the Compressed Fabric ID of all
// chip-tool-managed fabrics
chip::ByteSpan defaultIpk = chip::GroupTesting::DefaultIpkValue::GetDefaultIpk();
ReturnLogErrorOnFailure(chip::Credentials::SetSingleIpkEpochKey(&mGroupDataProvider, fabric->GetFabricIndex(),
defaultIpk, compressed_fabric_id_span));
}
}

Expand Down Expand Up @@ -287,7 +308,8 @@ CHIP_ERROR CHIPCommand::InitializeCommissioner(std::string key, chip::FabricId f
commissionerParams.controllerNOC = nocSpan;
}

commissionerParams.storageDelegate = &mCommissionerStorage;
commissionerParams.storageDelegate = &mCommissionerStorage;
// TODO: Initialize IPK epoch key in ExampleOperationalCredentials issuer rather than relying on DefaultIpkValue
commissionerParams.operationalCredentialsDelegate = mCredIssuerCmds->GetCredentialIssuer();
commissionerParams.controllerVendorId = chip::VendorId::TestVendor1;

Expand Down
5 changes: 5 additions & 0 deletions examples/chip-tool/commands/common/CHIPCommand.h
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
#include "Command.h"
#include <commands/common/CredentialIssuerCommands.h>
#include <commands/example/ExampleCredentialIssuerCommands.h>
#include <credentials/GroupDataProviderImpl.h>

#pragma once

Expand Down Expand Up @@ -52,6 +53,9 @@ class CHIPCommand : public Command
using PeerId = ::chip::PeerId;
using PeerAddress = ::chip::Transport::PeerAddress;

static constexpr uint16_t kMaxGroupsPerFabric = 5;
static constexpr uint16_t kMaxGroupKeysPerFabric = 8;

CHIPCommand(const char * commandName, CredentialIssuerCommands * credIssuerCmds) :
Command(commandName), mCredIssuerCmds(credIssuerCmds)
{
Expand Down Expand Up @@ -91,6 +95,7 @@ class CHIPCommand : public Command

PersistentStorage mDefaultStorage;
PersistentStorage mCommissionerStorage;
chip::Credentials::GroupDataProviderImpl mGroupDataProvider{ kMaxGroupsPerFabric, kMaxGroupKeysPerFabric };
CredentialIssuerCommands * mCredIssuerCmds;

std::string GetIdentity();
Expand Down
23 changes: 23 additions & 0 deletions examples/platform/linux/AppMain.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@

#include <lib/support/CHIPMem.h>
#include <lib/support/ScopedBuffer.h>
#include <lib/support/TestGroupData.h>
#include <setup_payload/QRCodeSetupPayloadGenerator.h>
#include <setup_payload/SetupPayload.h>

Expand Down Expand Up @@ -378,6 +379,7 @@ MyCommissionerCallback gCommissionerCallback;
MyServerStorageDelegate gServerStorage;
ExampleOperationalCredentialsIssuer gOpCredsIssuer;
NodeId gLocalId = kMaxOperationalNodeId;
Credentials::GroupDataProviderImpl gGroupDataProvider;

CHIP_ERROR InitCommissioner()
{
Expand All @@ -388,6 +390,10 @@ CHIP_ERROR InitCommissioner()
factoryParams.listenPort = LinuxDeviceOptions::GetInstance().securedCommissionerPort + 10;
factoryParams.fabricIndependentStorage = &gServerStorage;

gGroupDataProvider.SetStorageDelegate(&gServerStorage);
ReturnErrorOnFailure(gGroupDataProvider.Init());
factoryParams.groupDataProvider = &gGroupDataProvider;

params.storageDelegate = &gServerStorage;
params.operationalCredentialsDelegate = &gOpCredsIssuer;

Expand Down Expand Up @@ -427,6 +433,23 @@ CHIP_ERROR InitCommissioner()
auto & factory = Controller::DeviceControllerFactory::GetInstance();
ReturnErrorOnFailure(factory.Init(factoryParams));
ReturnErrorOnFailure(factory.SetupCommissioner(params, gCommissioner));

chip::FabricInfo * fabricInfo = gCommissioner.GetFabricInfo();
VerifyOrReturnError(fabricInfo != nullptr, CHIP_ERROR_INTERNAL);

uint8_t compressedFabricId[sizeof(uint64_t)] = { 0 };
MutableByteSpan compressedFabricIdSpan(compressedFabricId);
ReturnErrorOnFailure(fabricInfo->GetCompressedId(compressedFabricIdSpan));
ChipLogProgress(Support, "Setting up group data for Fabric Index %u with Compressed Fabric ID:",
static_cast<unsigned>(fabricInfo->GetFabricIndex()));
ChipLogByteSpan(Support, compressedFabricIdSpan);

// TODO: Once ExampleOperationalCredentialsIssuer has support, set default IPK on it as well so
// that commissioned devices get the IPK set from real values rather than "test-only" internal hookups.
ByteSpan defaultIpk = chip::GroupTesting::DefaultIpkValue::GetDefaultIpk();
ReturnLogErrorOnFailure(chip::Credentials::SetSingleIpkEpochKey(&gGroupDataProvider, fabricInfo->GetFabricIndex(), defaultIpk,
compressedFabricIdSpan));

gCommissionerDiscoveryController.SetUserDirectedCommissioningServer(gCommissioner.GetUserDirectedCommissioningServer());
gCommissionerDiscoveryController.SetCommissionerCallback(&gCommissionerCallback);

Expand Down
1 change: 1 addition & 0 deletions src/app/CASEClient.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ CHIP_ERROR CASEClient::EstablishSession(PeerId peer, const Transport::PeerAddres
Messaging::ExchangeContext * exchange = mInitParams.exchangeMgr->NewContext(session.Value(), &mCASESession);
VerifyOrReturnError(exchange != nullptr, CHIP_ERROR_INTERNAL);

mCASESession.SetGroupDataProvider(mInitParams.groupDataProvider);
ReturnErrorOnFailure(mCASESession.EstablishSession(peerAddress, mInitParams.fabricInfo, peer.GetNodeId(), keyID, exchange, this,
mInitParams.mrpLocalConfig));
mConnectionSuccessCallback = onConnection;
Expand Down
10 changes: 6 additions & 4 deletions src/app/CASEClient.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@

#pragma once

#include <credentials/GroupDataProvider.h>
#include <messaging/ExchangeMgr.h>
#include <messaging/ReliableMessageProtocolConfig.h>
#include <protocols/secure_channel/CASESession.h>
Expand All @@ -31,10 +32,11 @@ typedef void (*OnCASEConnectionFailure)(void * context, CASEClient * client, CHI

struct CASEClientInitParams
{
SessionManager * sessionManager = nullptr;
Messaging::ExchangeManager * exchangeMgr = nullptr;
SessionIDAllocator * idAllocator = nullptr;
FabricInfo * fabricInfo = nullptr;
SessionManager * sessionManager = nullptr;
Messaging::ExchangeManager * exchangeMgr = nullptr;
SessionIDAllocator * idAllocator = nullptr;
FabricInfo * fabricInfo = nullptr;
Credentials::GroupDataProvider * groupDataProvider = nullptr;

Optional<ReliableMessageProtocolConfig> mrpLocalConfig = Optional<ReliableMessageProtocolConfig>::Missing();
};
Expand Down
4 changes: 3 additions & 1 deletion src/app/CASESessionManager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,10 @@

namespace chip {

CHIP_ERROR CASESessionManager::Init(chip::System::Layer * systemLayer)
CHIP_ERROR CASESessionManager::Init(chip::System::Layer * systemLayer, const CASESessionManagerConfig & params)
{
ReturnErrorOnFailure(params.sessionInitParams.Validate());
mConfig = params;
return AddressResolve::Resolver::Instance().Init(systemLayer);
}

Expand Down
12 changes: 2 additions & 10 deletions src/app/CASESessionManager.h
Original file line number Diff line number Diff line change
Expand Up @@ -52,18 +52,10 @@ struct CASESessionManagerConfig
class CASESessionManager
{
public:
CASESessionManager() = delete;

CASESessionManager(const CASESessionManagerConfig & params)
{
VerifyOrDie(params.sessionInitParams.Validate() == CHIP_NO_ERROR);

mConfig = params;
}

CASESessionManager() = default;
virtual ~CASESessionManager() {}

CHIP_ERROR Init(chip::System::Layer * systemLayer);
CHIP_ERROR Init(chip::System::Layer * systemLayer, const CASESessionManagerConfig & params);
void Shutdown() {}

/**
Expand Down
5 changes: 3 additions & 2 deletions src/app/OperationalDeviceProxy.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -167,8 +167,9 @@ bool OperationalDeviceProxy::GetAddress(Inet::IPAddress & addr, uint16_t & port)

CHIP_ERROR OperationalDeviceProxy::EstablishConnection()
{
mCASEClient = mInitParams.clientPool->Allocate(CASEClientInitParams{
mInitParams.sessionManager, mInitParams.exchangeMgr, mInitParams.idAllocator, mFabricInfo, mInitParams.mrpLocalConfig });
mCASEClient = mInitParams.clientPool->Allocate(
CASEClientInitParams{ mInitParams.sessionManager, mInitParams.exchangeMgr, mInitParams.idAllocator, mFabricInfo,
mInitParams.groupDataProvider, mInitParams.mrpLocalConfig });
ReturnErrorCodeIf(mCASEClient == nullptr, CHIP_ERROR_NO_MEMORY);
CHIP_ERROR err =
mCASEClient->EstablishSession(mPeerId, mDeviceAddress, mMRPConfig, HandleCASEConnected, HandleCASEConnectionFailure, this);
Expand Down
22 changes: 15 additions & 7 deletions src/app/OperationalDeviceProxy.h
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
#include <app/DeviceProxy.h>
#include <app/util/attribute-filter.h>
#include <app/util/basic-types.h>
#include <credentials/GroupDataProvider.h>
#include <lib/address_resolve/AddressResolve.h>
#include <messaging/ExchangeContext.h>
#include <messaging/ExchangeDelegate.h>
Expand All @@ -48,11 +49,12 @@ namespace chip {

struct DeviceProxyInitParams
{
SessionManager * sessionManager = nullptr;
Messaging::ExchangeManager * exchangeMgr = nullptr;
SessionIDAllocator * idAllocator = nullptr;
FabricTable * fabricTable = nullptr;
CASEClientPoolDelegate * clientPool = nullptr;
SessionManager * sessionManager = nullptr;
Messaging::ExchangeManager * exchangeMgr = nullptr;
SessionIDAllocator * idAllocator = nullptr;
FabricTable * fabricTable = nullptr;
CASEClientPoolDelegate * clientPool = nullptr;
Credentials::GroupDataProvider * groupDataProvider = nullptr;

Optional<ReliableMessageProtocolConfig> mrpLocalConfig = Optional<ReliableMessageProtocolConfig>::Missing();

Expand All @@ -62,6 +64,7 @@ struct DeviceProxyInitParams
ReturnErrorCodeIf(exchangeMgr == nullptr, CHIP_ERROR_INCORRECT_STATE);
ReturnErrorCodeIf(idAllocator == nullptr, CHIP_ERROR_INCORRECT_STATE);
ReturnErrorCodeIf(fabricTable == nullptr, CHIP_ERROR_INCORRECT_STATE);
ReturnErrorCodeIf(groupDataProvider == nullptr, CHIP_ERROR_INCORRECT_STATE);
ReturnErrorCodeIf(clientPool == nullptr, CHIP_ERROR_INCORRECT_STATE);

return CHIP_NO_ERROR;
Expand Down Expand Up @@ -91,10 +94,15 @@ class DLL_EXPORT OperationalDeviceProxy : public DeviceProxy,
~OperationalDeviceProxy() override;
OperationalDeviceProxy(DeviceProxyInitParams & params, PeerId peerId) : mSecureSession(*this)
{
VerifyOrReturn(params.Validate() == CHIP_NO_ERROR);
mInitParams = params;
// Do not do worse
if (params.Validate() != CHIP_NO_ERROR)
{
mState = State::Uninitialized;
return;
}

mSystemLayer = params.exchangeMgr->GetSessionManager()->SystemLayer();
mInitParams = params;
mPeerId = peerId;
mFabricInfo = params.fabricTable->FindFabricWithCompressedId(peerId.GetCompressedFabricId());
mState = State::NeedsAddress;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@
#include <credentials/DeviceAttestationConstructor.h>
#include <credentials/DeviceAttestationCredsProvider.h>
#include <credentials/FabricTable.h>
#include <credentials/GroupDataProvider.h>
#include <credentials/examples/DeviceAttestationCredsExample.h>
#include <lib/core/CHIPSafeCasts.h>
#include <lib/core/PeerId.h>
Expand Down Expand Up @@ -589,6 +590,7 @@ bool emberAfOperationalCredentialsClusterAddNOCCallback(app::CommandHandler * co
CHIP_ERROR err = CHIP_NO_ERROR;
FabricIndex fabricIndex = 0;
Credentials::GroupDataProvider::KeySet keyset;
FabricInfo * newFabricInfo = nullptr;

uint8_t compressed_fabric_id_buffer[sizeof(uint64_t)];
MutableByteSpan compressed_fabric_id(compressed_fabric_id_buffer);
Expand Down Expand Up @@ -650,11 +652,17 @@ bool emberAfOperationalCredentialsClusterAddNOCCallback(app::CommandHandler * co
// Set the Identity Protection Key (IPK)
VerifyOrExit(ipkValue.size() == Crypto::CHIP_CRYPTO_SYMMETRIC_KEY_LENGTH_BYTES,
nocResponse = ConvertToNOCResponseStatus(CHIP_ERROR_INVALID_ARGUMENT));
keyset.keyset_id = 0; // The IPK SHALL be the operational group key under GroupKeySetID of 0
// The IPK SHALL be the operational group key under GroupKeySetID of 0
keyset.keyset_id = Credentials::GroupDataProvider::kIdentityProtectionKeySetId;
keyset.policy = GroupKeyManagement::GroupKeySecurityPolicy::kTrustFirst;
keyset.num_keys_used = 1;
memcpy(keyset.epoch_keys[0].key, ipkValue.data(), Crypto::CHIP_CRYPTO_SYMMETRIC_KEY_LENGTH_BYTES);
err = gFabricBeingCommissioned.GetCompressedId(compressed_fabric_id);

newFabricInfo = Server::GetInstance().GetFabricTable().FindFabricWithIndex(fabricIndex);
VerifyOrExit(newFabricInfo != nullptr, nocResponse = ConvertToNOCResponseStatus(CHIP_ERROR_INTERNAL));
err = newFabricInfo->GetCompressedId(compressed_fabric_id);
VerifyOrExit(err == CHIP_NO_ERROR, nocResponse = ConvertToNOCResponseStatus(err));

err = groups->SetKeySet(fabricIndex, compressed_fabric_id, keyset);
VerifyOrExit(err == CHIP_NO_ERROR, nocResponse = ConvertToNOCResponseStatus(err));

Expand Down
43 changes: 22 additions & 21 deletions src/app/server/Server.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@
#include <lib/dnssd/ServiceNaming.h>
#include <lib/support/CodeUtils.h>
#include <lib/support/ErrorStr.h>
#include <lib/support/TestGroupData.h>
#include <lib/support/logging/CHIPLogging.h>
#include <messaging/ExchangeMgr.h>
#include <platform/CHIPDeviceLayer.h>
Expand All @@ -46,7 +47,6 @@
#include <system/SystemPacketBuffer.h>
#include <system/TLVPacketBufferBackingStore.h>
#include <transport/SessionManager.h>

using namespace chip::DeviceLayer;

using chip::kMinValidFabricIndex;
Expand Down Expand Up @@ -94,26 +94,11 @@ static ::chip::PersistedCounter sGlobalEventIdCounter;
static ::chip::app::CircularEventBuffer sLoggingBuffer[CHIP_NUM_EVENT_LOGGING_BUFFERS];
#endif // CHIP_CONFIG_ENABLE_SERVER_IM_EVENT

Server::Server() :
mCASESessionManager(CASESessionManagerConfig {
.sessionInitParams = {
.sessionManager = &mSessions,
.exchangeMgr = &mExchangeMgr,
.idAllocator = &mSessionIDAllocator,
.fabricTable = &mFabrics,
.clientPool = &mCASEClientPool,
},
#if CHIP_CONFIG_MDNS_CACHE_SIZE > 0
.dnsCache = nullptr,
#endif
.devicePool = &mDevicePool,
})
{}

CHIP_ERROR Server::Init(AppDelegate * delegate, uint16_t secureServicePort, uint16_t unsecureServicePort,
Inet::InterfaceId interfaceId)
{
Access::AccessControl::Delegate * accessDelegate = nullptr;
CASESessionManagerConfig caseSessionManagerConfig;

mSecuredServicePort = secureServicePort;
mUnsecuredServicePort = unsecureServicePort;
Expand Down Expand Up @@ -187,7 +172,7 @@ CHIP_ERROR Server::Init(AppDelegate * delegate, uint16_t secureServicePort, uint
err = mSessions.Init(&DeviceLayer::SystemLayer(), &mTransports, &mMessageCounterManager, &mDeviceStorage, &GetFabricTable());
SuccessOrExit(err);

err = mFabricDelegate.Init(&mSessions);
err = mFabricDelegate.Init(this);
SuccessOrExit(err);
mFabrics.AddFabricDelegate(&mFabricDelegate);

Expand Down Expand Up @@ -252,15 +237,31 @@ CHIP_ERROR Server::Init(AppDelegate * delegate, uint16_t secureServicePort, uint
app::DnssdServer::Instance().StartServer();
#endif

caseSessionManagerConfig = {
.sessionInitParams = {
.sessionManager = &mSessions,
.exchangeMgr = &mExchangeMgr,
.idAllocator = &mSessionIDAllocator,
.fabricTable = &mFabrics,
.clientPool = &mCASEClientPool,
.groupDataProvider = &mGroupsProvider,
},
#if CHIP_CONFIG_MDNS_CACHE_SIZE > 0
.dnsCache = nullptr,
#endif
.devicePool = &mDevicePool,
};

err = mCASESessionManager.Init(&DeviceLayer::SystemLayer(), caseSessionManagerConfig);
SuccessOrExit(err);

err = mCASEServer.ListenForSessionEstablishment(&mExchangeMgr, &mTransports,
#if CONFIG_NETWORK_LAYER_BLE
chip::DeviceLayer::ConnectivityMgr().GetBleLayer(),
#endif
&mSessions, &mFabrics);
&mSessions, &mFabrics, &mGroupsProvider);
SuccessOrExit(err);

err = mCASESessionManager.Init(&DeviceLayer::SystemLayer());

// This code is necessary to restart listening to existing groups after a reboot
// Each manufacturer needs to validate that they can rejoin groups by placing this code at the appropriate location for them
//
Expand Down
Loading

0 comments on commit ad83634

Please sign in to comment.