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

Group Data Provider updated to newest Group Key Management spec. #12840

Merged
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
269 changes: 104 additions & 165 deletions src/app/clusters/groups-server/groups-server.cpp

Large diffs are not rendered by default.

196 changes: 84 additions & 112 deletions src/credentials/GroupDataProvider.h
Original file line number Diff line number Diff line change
Expand Up @@ -30,34 +30,24 @@ namespace Credentials {
class GroupDataProvider
{
public:
// An EpochKey is a single key usable to determine an operational group key
struct EpochKey
{
static constexpr size_t kLengthBytes = Crypto::CHIP_CRYPTO_SYMMETRIC_KEY_LENGTH_BYTES;
// Validity start time in microseconds since 2000-01-01T00:00:00 UTC ("the Epoch")
uint64_t start_time;
// Actual key bits. Depending on context, it may be a raw epoch key (as seen within `SetKeySet` calls)
// or it may be the derived operational group key (as seen in any other usage).
uint8_t key[kLengthBytes];
};
static constexpr uint16_t kMaxGroupsPerFabric = CHIP_CONFIG_MAX_GROUPS_PER_FABRIC;
static constexpr uint16_t kMaxGroupKeysPerFabric = CHIP_CONFIG_MAX_GROUP_KEYS_PER_FABRIC;

// A GroupMapping maps a controlling GroupId to a given EndpointId. There may be
// multiple GroupMapping having the same `group` value, but each with different
// `endpoint` value.
struct GroupMapping
struct GroupInfo
{
static constexpr size_t kGroupNameMax = CHIP_CONFIG_MAX_GROUP_NAME_LENGTH;

// The endpoint to which a GroupId is mapped.
EndpointId endpoint = kInvalidEndpointId;
// The GroupId, which, when received in a message will map to the `endpoint`.
GroupId group = kUndefinedGroupId;
// Group name
// Identifies group within the scope of the given Fabric
chip::GroupId group_id = kUndefinedGroupId;
// Lastest group name written for a given GroupId on any Endpoint via the Groups cluster
char name[kGroupNameMax + 1] = { 0 };

GroupMapping() = default;
GroupMapping(EndpointId eid, GroupId gid) : GroupMapping(eid, gid, nullptr) {}
GroupMapping(EndpointId eid, GroupId gid, const char * groupName) : endpoint(eid), group(gid)
GroupInfo() { SetName(nullptr); }
GroupInfo(const char * groupName) { SetName(groupName); }
GroupInfo(const CharSpan & groupName) { SetName(groupName); }
GroupInfo(chip::GroupId id, const char * groupName) : group_id(id) { SetName(groupName); }
GroupInfo(chip::GroupId id, const CharSpan & groupName) : group_id(id) { SetName(groupName); }
void SetName(const char * groupName)
{
if (nullptr == groupName)
{
Expand All @@ -70,7 +60,7 @@ class GroupDataProvider
name[size] = 0;
}
}
GroupMapping(EndpointId eid, GroupId gid, const CharSpan & groupName) : endpoint(eid), group(gid)
void SetName(const CharSpan & groupName)
{
if (nullptr == groupName.data())
{
Expand All @@ -83,42 +73,57 @@ class GroupDataProvider
name[size] = 0;
}
}
bool operator==(const GroupMapping & other)
bool operator==(const GroupInfo & other)
{
return (this->endpoint == other.endpoint) && (this->group == other.group) &&
strncmp(this->name, other.name, kGroupNameMax);
return (this->group_id == other.group_id) && !strncmp(this->name, other.name, kGroupNameMax);
}
};

// A group state maps the group key set to use for encryption/decryption for a given group ID.
struct GroupState
struct GroupKey
{
GroupState() = default;
GroupState(chip::FabricIndex fabric, chip::GroupId group_id, uint16_t key_set) :
fabric_index(fabric), group(group_id), keyset_id(key_set)
{}
// Fabric Index associated with the group state entry's fabric scoping
chip::FabricIndex fabric_index = kUndefinedFabricIndex;
// Identifies the group within the scope of the given fabric
chip::GroupId group = kUndefinedGroupId;
// References the set of group keys that generate operationa group keys for use with the given group
uint16_t keyset_id = 0;
bool operator==(const GroupState & other)
GroupKey() = default;
GroupKey(chip::GroupId group, chip::KeysetId keyset) : group_id(group), keyset_id(keyset) {}
// Identifies group within the scope of the given Fabric
chip::GroupId group_id = kUndefinedGroupId;
// Set of group keys that generate operational group keys for use with this group
chip::KeysetId keyset_id = 0;
bool operator==(const GroupKey & other) { return this->group_id == other.group_id && this->keyset_id == other.keyset_id; }
};

struct GroupEndpoint
{
GroupEndpoint() = default;
GroupEndpoint(chip::GroupId group, chip::EndpointId endpoint) : group_id(group), endpoint_id(endpoint) {}
// Identifies group within the scope of the given Fabric
chip::GroupId group_id = kUndefinedGroupId;
// Endpoint on the Node to which messages to this group may be forwarded
chip::EndpointId endpoint_id = kInvalidEndpointId;

bool operator==(const GroupEndpoint & other)
{
return this->fabric_index == other.fabric_index && this->group == other.group && this->keyset_id == other.keyset_id;
return this->group_id == other.group_id && this->endpoint_id == other.endpoint_id;
}
};

// An EpochKey is a single key usable to determine an operational group key
struct EpochKey
{
static constexpr size_t kLengthBytes = Crypto::CHIP_CRYPTO_SYMMETRIC_KEY_LENGTH_BYTES;
// Validity start time in microseconds since 2000-01-01T00:00:00 UTC ("the Epoch")
uint64_t start_time;
// Actual key bits. Depending on context, it may be a raw epoch key (as seen within `SetKeySet` calls)
// or it may be the derived operational group key (as seen in any other usage).
uint8_t key[kLengthBytes];
};

// A operational group key set, usable by many GroupState mappings
struct KeySet
{
using SecurityPolicy = chip::app::Clusters::GroupKeyManagement::GroupKeySecurityPolicy;

KeySet() = default;
KeySet(uint16_t id) : keyset_id(id) {}
KeySet(uint16_t id, SecurityPolicy policy_id, uint8_t num_keys) : keyset_id(id), policy(policy_id), num_keys_used(num_keys)
{}
KeySet(SecurityPolicy policy_id, uint8_t num_keys) : keyset_id(0), policy(policy_id), num_keys_used(num_keys) {}

// The actual keys for the group key set
EpochKey epoch_keys[3];
Expand All @@ -131,11 +136,8 @@ class GroupDataProvider

bool operator==(const KeySet & other)
{
if (this->policy == other.policy && this->num_keys_used == other.num_keys_used)
{
return !memcmp(this->epoch_keys, other.epoch_keys, this->num_keys_used * sizeof(EpochKey));
}
return false;
VerifyOrReturnError(this->policy == other.policy && this->num_keys_used == other.num_keys_used, false);
return !memcmp(this->epoch_keys, other.epoch_keys, this->num_keys_used * sizeof(EpochKey));
}
};

Expand Down Expand Up @@ -167,33 +169,10 @@ class GroupDataProvider
Iterator() = default;
};

using GroupMappingIterator = Iterator<GroupMapping>;
using GroupStateIterator = Iterator<GroupState>;
using KeySetIterator = Iterator<KeySet>;

/**
* Interface for a listener of changes in any Group configuration. Necessary
* to implement attribute subscription for Group Key Management cluster, and
* to react to configuration changes that may impact in-progress functional work.
*/
class GroupListener
{
public:
virtual ~GroupListener() = default;
/**
* Listener callback invoked when a GroupState entry is mutated or added.
*
* @param[in] old_state GroupState reflecting the previous entry. Set to nullptr on appends.
* @param[in] new_state GroupState reflecting the updated/new entry.
*/
virtual void OnGroupStateChanged(const GroupState * old_state, const GroupState * new_state) = 0;
/**
* Listener callback invoked when a GroupState entry is removed from the Groups list.
*
* @param[in] removed_state Copy of GroupState that was just removed. Index included is no longer accessible.
*/
virtual void OnGroupStateRemoved(const GroupState * removed_state) = 0;
};
using GroupInfoIterator = Iterator<GroupInfo>;
using GroupKeyIterator = Iterator<GroupKey>;
using EndpointIterator = Iterator<GroupEndpoint>;
using KeySetIterator = Iterator<KeySet>;

GroupDataProvider() = default;
virtual ~GroupDataProvider() = default;
Expand All @@ -207,68 +186,68 @@ class GroupDataProvider
* initialization. Must be called once before any other API succeeds.
*
* @retval #CHIP_ERROR_INCORRECT_STATE if called when already initialized.
* @retval #CHIP_NO_ERROR on success.
* @retval #CHIP_NO_ERROR on success
*/
virtual CHIP_ERROR Init() = 0;
virtual void Finish() = 0;

//
// Group Mappings
// Group Table
//

virtual bool HasGroupNamesSupport() = 0;
virtual bool GroupMappingExists(chip::FabricIndex fabric_index, const GroupMapping & mapping) = 0;
virtual CHIP_ERROR AddGroupMapping(chip::FabricIndex fabric_index, const GroupMapping & mapping) = 0;
virtual CHIP_ERROR RemoveGroupMapping(chip::FabricIndex fabric_index, const GroupMapping & mapping) = 0;
virtual CHIP_ERROR RemoveAllGroupMappings(chip::FabricIndex fabric_index, EndpointId endpoint) = 0;
// By id
virtual CHIP_ERROR SetGroupInfo(chip::FabricIndex fabric_index, const GroupInfo & info) = 0;
virtual CHIP_ERROR GetGroupInfo(chip::FabricIndex fabric_index, chip::GroupId group_id, GroupInfo & info) = 0;
// By index
virtual CHIP_ERROR SetGroupInfoAt(chip::FabricIndex fabric_index, size_t index, const GroupInfo & info) = 0;
virtual CHIP_ERROR GetGroupInfoAt(chip::FabricIndex fabric_index, size_t index, GroupInfo & info) = 0;
virtual CHIP_ERROR RemoveGroupInfoAt(chip::FabricIndex fabric_index, size_t index) = 0;
// Endpoints
virtual bool HasEndpoint(chip::FabricIndex fabric_index, chip::GroupId group_id, chip::EndpointId endpoint_id) = 0;
virtual CHIP_ERROR AddEndpoint(chip::FabricIndex fabric_index, chip::GroupId group_id, chip::EndpointId endpoint_id) = 0;
virtual CHIP_ERROR RemoveEndpoint(chip::FabricIndex fabric_index, chip::GroupId group_id, chip::EndpointId endpoint_id) = 0;
virtual CHIP_ERROR RemoveEndpoint(chip::FabricIndex fabric_index, chip::EndpointId endpoint_id) = 0;
// Iterators
/**
* Creates an iterator that may be used to obtain the groups associated with the given fabric.
* Creates an iterator that may be used to obtain the list of groups associated with the given fabric.
* The number of concurrent instances of this iterator is limited. In order to release the allocated memory,
* the iterator's Release() method must be called after the iteration is finished.
* @retval An instance of GroupMappingIterator on success
* @retval An instance of EndpointIterator on success
* @retval nullptr if no iterator instances are available.
*/
virtual GroupMappingIterator * IterateGroupMappings(chip::FabricIndex fabric_index) = 0;
virtual GroupInfoIterator * IterateGroupInfo(chip::FabricIndex fabric_index) = 0;
/**
* Creates an iterator that may be used to obtain the groups associated with the given fabric and endpoint.
* Creates an iterator that may be used to obtain the list of (group, endpoint) pairs associated with the given fabric.
* The number of concurrent instances of this iterator is limited. In order to release the allocated memory,
* the iterator's Release() method must be called after the iteration is finished.
* @retval An instance of GroupMappingIterator on success
* @retval An instance of EndpointIterator on success
* @retval nullptr if no iterator instances are available.
*/
virtual GroupMappingIterator * IterateGroupMappings(chip::FabricIndex fabric_index, EndpointId endpoint) = 0;
virtual EndpointIterator * IterateEndpoints(chip::FabricIndex fabric_index) = 0;

//
// Group States
// Group-Key map
//

virtual CHIP_ERROR SetGroupState(size_t state_index, const GroupState & state) = 0;
virtual CHIP_ERROR GetGroupState(size_t state_index, GroupState & state) = 0;
virtual CHIP_ERROR RemoveGroupState(size_t state_index) = 0;
virtual CHIP_ERROR SetGroupKeyAt(chip::FabricIndex fabric_index, size_t index, const GroupKey & info) = 0;
virtual CHIP_ERROR GetGroupKeyAt(chip::FabricIndex fabric_index, size_t index, GroupKey & info) = 0;
virtual CHIP_ERROR RemoveGroupKeyAt(chip::FabricIndex fabric_index, size_t index) = 0;
/**
* Creates an iterator that may be used to obtain the list of group states.
* Creates an iterator that may be used to obtain the list of (group, keyset) pairs associated with the given fabric.
* The number of concurrent instances of this iterator is limited. In order to release the allocated memory,
* the iterator's Release() method must be called after the iteration is finished.
* @retval An instance of GroupStateIterator on success
* @retval An instance of GroupKeyIterator on success
* @retval nullptr if no iterator instances are available.
*/
virtual GroupStateIterator * IterateGroupStates() = 0;
/**
* Creates an iterator that may be used to obtain the list of group states associated with the given fabric.
* The number of concurrent instances of this iterator is limited. In order to release the allocated memory,
* the iterator's Release() method must be called after the iteration is finished.
* @retval An instance of GroupStateIterator on success
* @retval nullptr if no iterator instances are available.
*/
virtual GroupStateIterator * IterateGroupStates(chip::FabricIndex fabric_index) = 0;
virtual GroupKeyIterator * IterateGroupKey(chip::FabricIndex fabric_index) = 0;

//
// Key Sets
//

virtual CHIP_ERROR SetKeySet(chip::FabricIndex fabric_index, uint16_t keyset_id, const KeySet & keys) = 0;
virtual CHIP_ERROR GetKeySet(chip::FabricIndex fabric_index, uint16_t keyset_id, KeySet & keys) = 0;
virtual CHIP_ERROR RemoveKeySet(chip::FabricIndex fabric_index, uint16_t keyset_id) = 0;
virtual CHIP_ERROR SetKeySet(chip::FabricIndex fabric_index, const KeySet & keys) = 0;
virtual CHIP_ERROR GetKeySet(chip::FabricIndex fabric_index, chip::KeysetId keyset_id, KeySet & keys) = 0;
virtual CHIP_ERROR RemoveKeySet(chip::FabricIndex fabric_index, chip::KeysetId keyset_id) = 0;
/**
* Creates an iterator that may be used to obtain the list of key sets associated with the given fabric.
* The number of concurrent instances of this iterator is limited. In order to release the allocated memory,
Expand All @@ -283,13 +262,6 @@ class GroupDataProvider

// General
virtual CHIP_ERROR Decrypt(PacketHeader packetHeader, PayloadHeader & payloadHeader, System::PacketBufferHandle & msg) = 0;

// Listener
void SetListener(GroupListener * listener) { mListener = listener; };
void RemoveListener() { mListener = nullptr; };

protected:
GroupListener * mListener = nullptr;
};

/**
Expand Down
Loading