Skip to content

Commit b253aab

Browse files
PDC/NETIM: Align implementation with latest spec (project-chip#72074)
* Update cluster XML based on latest spec updates See CHIP-Specifications/connectedhomeip-spec#12939 * zap regen * PDC/NETIM: Align implementation with latest spec - Add ClientIndex as a query option to QueryIdentity - Add ClientIdentityType to ClientStruct and store in the storage layer - Reject future NASS timestamps in ImportAdminSecret if the clock is synchronized * Make ClangTidy happy and use MockClock for all cluster test cases Also do time math in Seconds32 and factor out a named constant for max skew.
1 parent a015d5c commit b253aab

34 files changed

Lines changed: 360 additions & 81 deletions

File tree

examples/network-manager-app/network-manager-common/network-manager-app.matter

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1507,7 +1507,7 @@ provisional cluster NetworkIdentityManagement = 1104 {
15071507
revision 1;
15081508

15091509
enum IdentityTypeEnum : enum8 {
1510-
kECDSA = 0 [spec_name = "ECDSA"];
1510+
kECDSA = 1 [spec_name = "ECDSA"];
15111511
}
15121512

15131513
struct ActiveNetworkIdentityStruct {
@@ -1522,7 +1522,8 @@ provisional cluster NetworkIdentityManagement = 1104 {
15221522
struct ClientStruct {
15231523
int16u clientIndex = 0;
15241524
octet_string<20> clientIdentifier = 1;
1525-
nullable int16u networkIdentityIndex = 2;
1525+
IdentityTypeEnum clientIdentityType = 2;
1526+
nullable int16u networkIdentityIndex = 3;
15261527
}
15271528

15281529
readonly attribute access(read: manage) ActiveNetworkIdentityStruct activeNetworkIdentities[] = 0;
@@ -1550,7 +1551,8 @@ provisional cluster NetworkIdentityManagement = 1104 {
15501551
request struct QueryIdentityRequest {
15511552
optional int16u networkIdentityIndex = 0;
15521553
optional IdentityTypeEnum networkIdentityType = 1;
1553-
optional octet_string<20> identifier = 2;
1554+
optional int16u clientIndex = 2;
1555+
optional octet_string<20> identifier = 3;
15541556
}
15551557

15561558
response struct QueryIdentityResponse = 4 {

src/app/clusters/network-identity-management-server/DefaultNetworkIdentityStorage.cpp

Lines changed: 21 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -115,9 +115,10 @@
115115
// [2] allocBitmap bytes (256 bytes, bit i = index i is allocated)
116116
//
117117
// * g/nim/c/<index> detail record
118-
// [1] identifier bytes 20-byte client identifier
119-
// [2] compactIdentity bytes client identity certificate (compact, max 140)
120-
// [3] niIndex uint16 NI index, or 0xFFFF (= kNullNetworkIdentityIndex, never authenticated)
118+
// [1] identityType uint8 identity type (e.g. kEcdsa)
119+
// [2] identifier bytes 20-byte client identifier
120+
// [3] compactIdentity bytes client identity certificate (compact, max 140)
121+
// [4] niIndex uint16 NI index, or 0xFFFF (= kNullNetworkIdentityIndex, never authenticated)
121122
//
122123
// * g/nim/@<base85-identifier> client identifier -> index mapping (raw uint16)
123124

@@ -169,10 +170,12 @@ struct DefaultNetworkIdentityStorage::TLVConstants
169170
sizeof(mClientAllocBitmap)); // allocBitmap
170171

171172
// Client detail record (g/nim/c/<index>)
172-
static constexpr TLV::Tag kClientDetail_Identifier = TLV::ContextTag(1);
173-
static constexpr TLV::Tag kClientDetail_CompactIdentity = TLV::ContextTag(2);
174-
static constexpr TLV::Tag kClientDetail_NIIndex = TLV::ContextTag(3);
173+
static constexpr TLV::Tag kClientDetail_IdentityType = TLV::ContextTag(1);
174+
static constexpr TLV::Tag kClientDetail_Identifier = TLV::ContextTag(2);
175+
static constexpr TLV::Tag kClientDetail_CompactIdentity = TLV::ContextTag(3);
176+
static constexpr TLV::Tag kClientDetail_NIIndex = TLV::ContextTag(4);
175177
static constexpr size_t kClientDetail_Size = TLV::EstimateStructOverhead( //
178+
sizeof(uint8_t), // identityType
176179
Credentials::kKeyIdentifierLength, // identifier
177180
Credentials::kMaxCHIPCompactNetworkIdentityLength, // compactIdentity
178181
sizeof(uint16_t)); // niIndex
@@ -511,9 +514,13 @@ CHIP_ERROR DefaultNetworkIdentityStorage::LoadNetworkIdentity(const NetworkIdent
511514

512515
// Copy fields that are embedded in the table index entry
513516
outEntry.index = meta.index;
514-
outEntry.type = meta.type;
515517
outEntry.current = (FindCurrentNIIndexEntry(meta.type) == &meta);
516518

519+
if (flags.Has(NetworkIdentityFlags::kPopulateIdentityType))
520+
{
521+
outEntry.type = meta.type;
522+
}
523+
517524
// Client count is stored in the index but may need rebuilding
518525
if (flags.Has(NetworkIdentityFlags::kPopulateClientCount))
519526
{
@@ -885,6 +892,7 @@ CHIP_ERROR DefaultNetworkIdentityStorage::StoreClientDetail(uint16_t index, cons
885892

886893
TLV::TLVType outerType;
887894
ReturnErrorOnFailure(writer.StartContainer(TLV::AnonymousTag(), TLV::kTLVType_Structure, outerType));
895+
ReturnErrorOnFailure(writer.Put(TLVConstants::kClientDetail_IdentityType, info.identityType));
888896
ReturnErrorOnFailure(writer.Put(TLVConstants::kClientDetail_Identifier, ByteSpan(info.identifier)));
889897
ReturnErrorOnFailure(writer.Put(TLVConstants::kClientDetail_CompactIdentity, info.compactIdentity));
890898
ReturnErrorOnFailure(writer.Put(TLVConstants::kClientDetail_NIIndex, networkIdentityIndex));
@@ -917,6 +925,12 @@ CHIP_ERROR DefaultNetworkIdentityStorage::LoadClient(uint16_t index, ClientEntry
917925
ReturnErrorOnFailure(reader.Next(TLV::kTLVType_Structure, TLV::AnonymousTag()));
918926
ReturnErrorOnFailure(reader.EnterContainer(outerType));
919927

928+
ReturnErrorOnFailure(reader.Next(TLVConstants::kClientDetail_IdentityType));
929+
if (flags.Has(ClientFlags::kPopulateIdentityType))
930+
{
931+
ReturnErrorOnFailure(reader.Get(outEntry.identityType));
932+
}
933+
920934
ReturnErrorOnFailure(reader.Next(TLVConstants::kClientDetail_Identifier));
921935
if (flags.Has(ClientFlags::kPopulateIdentifier))
922936
{

src/app/clusters/network-identity-management-server/NetworkIdentityManagementCluster.cpp

Lines changed: 37 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@
3030
#include <lib/support/CodeUtils.h>
3131
#include <lib/support/SafeInt.h>
3232
#include <protocols/interaction_model/StatusCode.h>
33+
#include <system/SystemClock.h>
3334

3435
using namespace chip;
3536
using namespace chip::app;
@@ -42,6 +43,8 @@ using Protocols::InteractionModel::Status;
4243

4344
namespace chip::app::Clusters {
4445

46+
static constexpr System::Clock::Seconds32 kImportAdminSecretMaxClockSkew(60); // per Matter spec
47+
4548
NetworkIdentityManagementCluster::NetworkIdentityManagementCluster(EndpointId endpoint, NetworkIdentityStorage & storage,
4649
Crypto::NetworkIdentityKeystore & keystore,
4750
NetworkIdentityManagement::AuthenticatorDriver & authenticator) :
@@ -86,9 +89,9 @@ DataModel::ActionReturnStatus NetworkIdentityManagementCluster::ReadActiveNetwor
8689
{
8790
using NetworkIdentityFlags = NetworkIdentityStorage::NetworkIdentityFlags;
8891
return encoder.EncodeList([this](const auto & listEncoder) -> CHIP_ERROR {
89-
constexpr BitFlags<NetworkIdentityFlags> flags(NetworkIdentityFlags::kPopulateIdentifier,
90-
NetworkIdentityFlags::kPopulateCreatedTimestamp,
91-
NetworkIdentityFlags::kPopulateClientCount);
92+
constexpr BitFlags<NetworkIdentityFlags> flags(
93+
NetworkIdentityFlags::kPopulateIdentityType, NetworkIdentityFlags::kPopulateIdentifier,
94+
NetworkIdentityFlags::kPopulateCreatedTimestamp, NetworkIdentityFlags::kPopulateClientCount);
9295
NetworkIdentityStorage::NetworkIdentityIterator::AutoReleasing iterator(
9396
mStorage.IterateNetworkIdentities(flags, MutableByteSpan()));
9497
VerifyOrReturnError(iterator.IsValid(), CHIP_ERROR_INTERNAL);
@@ -255,6 +258,23 @@ NetworkIdentityManagementCluster::HandleImportAdminSecret(const DataModel::Invok
255258
VerifyOrReturnValue(newSecretData.created > oldSecretInfo.createdTimestamp, Status::DynamicConstraintError);
256259
}
257260

261+
// If we have a trusted real-time clock, reject a NASS whose timestamp is more than 1 minute in the future.
262+
uint32_t currentTime;
263+
if ((err = System::Clock::GetClock_MatterEpochS(currentTime)) == CHIP_NO_ERROR)
264+
{
265+
VerifyOrReturnValue(newSecretData.created <= System::Clock::Seconds32(currentTime) + kImportAdminSecretMaxClockSkew,
266+
Status::DynamicConstraintError);
267+
}
268+
else if (err == CHIP_ERROR_REAL_TIME_NOT_SYNCED)
269+
{
270+
ChipLogProgress(Zcl, "ImportAdminSecret: Skipping check for future NASS timestamp, real-time clock is not synchronized");
271+
}
272+
else
273+
{
274+
ChipLogFailure(err, Zcl, "ImportAdminSecret: Failed to read real-time clock");
275+
return err;
276+
}
277+
258278
// Find retirable (non-current, zero-client) Network Identities so we can work out
259279
// if there will be enough capacity (including retirements) before making any changes.
260280
uint16_t networkIdentityCount;
@@ -399,10 +419,11 @@ NetworkIdentityManagementCluster::HandleQueryIdentity(const DataModel::InvokeReq
399419
QueryIdentity::DecodableType commandData;
400420
VerifyOrReturnError(DataModel::Decode(input_arguments, commandData) == CHIP_NO_ERROR, Status::InvalidCommand);
401421

402-
// Exactly one of the three optional fields must be present
422+
// Exactly one of the optional fields must be present
403423
int fieldCount = //
404424
commandData.networkIdentityIndex.HasValue() + //
405425
commandData.networkIdentityType.HasValue() + //
426+
commandData.clientIndex.HasValue() + //
406427
commandData.identifier.HasValue();
407428
VerifyOrReturnValue(fieldCount == 1, Status::InvalidCommand);
408429

@@ -425,6 +446,12 @@ NetworkIdentityManagementCluster::HandleQueryIdentity(const DataModel::InvokeReq
425446
err = mStorage.FindCurrentNetworkIdentity(commandData.networkIdentityType.Value(), entry, kPopulateNetworkIdentity, buffer);
426447
identity = entry.compactIdentity; // points into identityBuf
427448
}
449+
else if (commandData.clientIndex.HasValue())
450+
{
451+
NetworkIdentityStorage::ClientEntry entry;
452+
err = mStorage.FindClient(commandData.clientIndex.Value(), entry, kPopulateClientIdentity, buffer);
453+
identity = entry.compactIdentity; // points into identityBuf
454+
}
428455
else if (commandData.identifier.HasValue())
429456
{
430457
ByteSpan identifierSpan = commandData.identifier.Value();
@@ -457,16 +484,18 @@ DataModel::ActionReturnStatus NetworkIdentityManagementCluster::ReadClients(Attr
457484
{
458485
using ClientFlags = NetworkIdentityStorage::ClientFlags;
459486
return encoder.EncodeList([this](const auto & listEncoder) -> CHIP_ERROR {
460-
constexpr BitFlags<ClientFlags> flags(ClientFlags::kPopulateIdentifier, ClientFlags::kPopulateNetworkIdentityIndex);
487+
constexpr BitFlags<ClientFlags> flags(ClientFlags::kPopulateIdentityType, ClientFlags::kPopulateIdentifier,
488+
ClientFlags::kPopulateNetworkIdentityIndex);
461489
NetworkIdentityStorage::ClientIterator::AutoReleasing iterator(mStorage.IterateClients(flags, MutableByteSpan()));
462490
VerifyOrReturnError(iterator.IsValid(), CHIP_ERROR_INTERNAL);
463491

464492
NetworkIdentityStorage::ClientEntry entry;
465493
while (iterator.Next(entry))
466494
{
467495
Structs::ClientStruct::Type item;
468-
item.clientIndex = entry.index;
469-
item.clientIdentifier = entry.identifier;
496+
item.clientIndex = entry.index;
497+
item.clientIdentifier = entry.identifier;
498+
item.clientIdentityType = entry.identityType;
470499
if (entry.networkIdentityIndex != NetworkIdentityStorage::kNullNetworkIdentityIndex)
471500
{
472501
item.networkIdentityIndex.SetNonNull(entry.networkIdentityIndex);
@@ -515,6 +544,7 @@ NetworkIdentityManagementCluster::HandleAddClient(const DataModel::InvokeRequest
515544
// Build the ClientInfo for storage. Use ClientEntry so the convenience overload
516545
// populates index and lets us directly pass it on to the authenticator.
517546
NetworkIdentityStorage::ClientEntry entry;
547+
entry.identityType = IdentityTypeEnum::kEcdsa; // will be derived from clientIdentity if/when there are multiple types
518548
entry.identifier = identifier;
519549
entry.compactIdentity = commandData.clientIdentity;
520550

src/app/clusters/network-identity-management-server/NetworkIdentityStorage.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -117,6 +117,7 @@ CHIP_ERROR NetworkIdentityStorage::FindCurrentNetworkIdentityByIterating(Network
117117
BitFlags<NetworkIdentityFlags> flags,
118118
MutableByteSpan buffer)
119119
{
120+
flags.Set(NetworkIdentityFlags::kPopulateIdentityType); // needed for the predicate
120121
return FindNetworkIdentityByIterating(
121122
outEntry, flags, buffer,
122123
[](const NetworkIdentityEntry & entry, const void * ctx) {

src/app/clusters/network-identity-management-server/NetworkIdentityStorage.h

Lines changed: 22 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -72,14 +72,15 @@ class ReadOnlyNetworkIdentityStorage
7272

7373
enum class NetworkIdentityFlags : uint8_t
7474
{
75-
kPopulateIdentifier = (1 << 0),
76-
kPopulateCreatedTimestamp = (1 << 1),
77-
kPopulateCompactIdentity = (1 << 2),
78-
kPopulateKeypairHandle = (1 << 3),
79-
kPopulateClientCount = (1 << 4),
80-
81-
kPopulateAll = kPopulateIdentifier | kPopulateCreatedTimestamp | kPopulateCompactIdentity | kPopulateKeypairHandle |
82-
kPopulateClientCount
75+
kPopulateIdentityType = (1 << 0),
76+
kPopulateIdentifier = (1 << 1),
77+
kPopulateCreatedTimestamp = (1 << 2),
78+
kPopulateCompactIdentity = (1 << 3),
79+
kPopulateKeypairHandle = (1 << 4),
80+
kPopulateClientCount = (1 << 5),
81+
82+
kPopulateAll = kPopulateIdentityType | kPopulateIdentifier | kPopulateCreatedTimestamp | kPopulateCompactIdentity |
83+
kPopulateKeypairHandle | kPopulateClientCount
8384
};
8485

8586
static constexpr size_t NetworkIdentityBufferSize(BitFlags<NetworkIdentityFlags> flags = NetworkIdentityFlags::kPopulateAll)
@@ -92,10 +93,10 @@ class ReadOnlyNetworkIdentityStorage
9293
/// Input data for storing a Network Identity
9394
struct NetworkIdentityInfo
9495
{
95-
NetworkIdentityManagement::IdentityTypeEnum type;
96-
Credentials::CertificateKeyIdStorage identifier;
97-
ByteSpan compactIdentity;
98-
ByteSpan keypairHandle; ///< Opaque bytes at storage layer
96+
NetworkIdentityManagement::IdentityTypeEnum type; ///< type of identity, retrieved only if kPopulateIdentityType
97+
Credentials::CertificateKeyIdStorage identifier; ///< 20-byte identifier, retrieved only if kPopulateIdentifier
98+
ByteSpan compactIdentity; ///< identity certificate, retrieved only if kPopulateCompactIdentity
99+
ByteSpan keypairHandle; ///< opaque bytes at storage layer, retrieved only if kPopulateKeypairHandle
99100

100101
CHIP_ERROR GetKeypairHandle(Crypto::P256KeypairHandle & outHandle);
101102
};
@@ -169,11 +170,12 @@ class ReadOnlyNetworkIdentityStorage
169170

170171
enum class ClientFlags : uint8_t
171172
{
172-
kPopulateIdentifier = (1 << 0),
173-
kPopulateCompactIdentity = (1 << 1),
174-
kPopulateNetworkIdentityIndex = (1 << 2),
173+
kPopulateIdentityType = (1 << 0),
174+
kPopulateIdentifier = (1 << 1),
175+
kPopulateCompactIdentity = (1 << 2),
176+
kPopulateNetworkIdentityIndex = (1 << 3),
175177

176-
kPopulateAll = kPopulateIdentifier | kPopulateCompactIdentity | kPopulateNetworkIdentityIndex
178+
kPopulateAll = kPopulateIdentityType | kPopulateIdentifier | kPopulateCompactIdentity | kPopulateNetworkIdentityIndex
177179
};
178180

179181
static constexpr size_t ClientBufferSize(BitFlags<ClientFlags> flags = ClientFlags::kPopulateAll)
@@ -184,13 +186,14 @@ class ReadOnlyNetworkIdentityStorage
184186

185187
struct ClientInfo
186188
{
187-
Credentials::CertificateKeyIdStorage identifier; ///< 20-byte client identifier, retrieved only if kPopulateIdentifier
188-
ByteSpan compactIdentity; ///< Client Identity certificate, retrieved only if kPopulateCompactIdentity
189+
NetworkIdentityManagement::IdentityTypeEnum identityType; ///< type of identity, retrieved only if kPopulateIdentityType
190+
Credentials::CertificateKeyIdStorage identifier; ///< 20-byte identifier, retrieved only if kPopulateIdentifier
191+
ByteSpan compactIdentity; ///< identity certificate, retrieved only if kPopulateCompactIdentity
189192
};
190193

191194
struct ClientEntry : public ClientInfo
192195
{
193-
uint16_t index; ///< always populated
196+
uint16_t index; ///< always retrieved
194197
uint16_t networkIdentityIndex; ///< retrieved only if kPopulateNetworkIdentityIndex
195198
};
196199

0 commit comments

Comments
 (0)