blob: 89363c57074e45cbe301e5415808cbcb9c9e24e8 [file] [log] [blame]
/*
*
* Copyright (c) 2021 Project CHIP Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#pragma once
#include <app/util/basic-types.h>
#include <lib/core/CHIPError.h>
#include <stdint.h>
#include <sys/types.h>
namespace chip {
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 = (128 / 8);
// 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 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
{
// The endpoint to which a GroupId is mapped.
EndpointId endpoint;
// The GroupId, which, when received in a message will map to the `endpoint`.
GroupId group;
bool operator==(const GroupMapping & other) { return this->endpoint == other.endpoint && this->group == other.group; }
};
// A group state maps the group key set to use for encryption/decryption for a given group ID.
struct GroupState
{
// Fabric Index associated with the group state entry's fabric scoping
chip::FabricIndex fabric_index;
// Identifies the group within the scope of the given fabric
chip::GroupId group;
// References the set of group keys that generate operationa group keys for use with the given group
uint16_t key_set_index;
};
// A operational group key set, usable by many GroupState mappings
struct KeySet
{
enum class SecurityPolicy : uint8_t
{
kStandard = 0,
kLowLatency = 1
};
// The actual keys for the group key set
EpochKey epoch_keys[3];
// Logical index provided by the Administrator that configured the entry
uint16_t key_set_index;
// Security policy to use for groups that use this keyset
SecurityPolicy policy;
// Number of keys present
uint8_t num_keys_used;
};
// Iterator for group mappings under a given endpoint. Associated with
// Groups cluster logic.
class GroupMappingIterator
{
public:
virtual ~GroupMappingIterator() = default;
// Returns the number of entries in total that will be iterated.
virtual size_t Count() = 0;
// Returns true if a groupID is found in the iteration.
virtual bool Next(GroupId & outGroup) = 0;
// Release the memory allocated by this iterator, if any. Must be called before
// losing scope of a `GroupMappingIterator *`
virtual void Release() = 0;
protected:
GroupMappingIterator() = default;
};
// Iterator for group state information mapping a Group ID to a Group Key Set index,
// such as reflected by the Groups attribute of the Group Key Management cluster.
class GroupStateIterator
{
public:
virtual ~GroupStateIterator() = default;
// Returns the number of entries in total that will be iterated.
virtual size_t Count() = 0;
// Returns true if a GroupState is found in the iteration.
virtual bool Next(GroupState & outEntry) = 0;
// Release the memory allocated by this iterator, if any. Must be called before
// losing scope of a `GroupStateIterator *`
virtual void Release() = 0;
protected:
GroupStateIterator() = default;
};
// Iterator for the Group Key Sets related under a given Fabric.
// TODO: Refactor to allow trial decryption and encryption directly, rather than accessing raw keys.
class KeySetIterator
{
public:
virtual ~KeySetIterator() = default;
// Returns the number of entries in total that will be iterated.
virtual size_t Count() = 0;
// Returns true if a KeySet is found in the iteration.
virtual bool Next(KeySet & outSet) = 0;
// Release the memory allocated by this iterator, if any. Must be called before
// losing scope of a `KeySetIterator *`
virtual void Release() = 0;
protected:
KeySetIterator() = default;
};
// Interface for a listener for 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;
};
GroupDataProvider() = default;
virtual ~GroupDataProvider() = default;
// Not copyable
GroupDataProvider(const GroupDataProvider &) = delete;
GroupDataProvider & operator=(const GroupDataProvider &) = delete;
/**
* Initialize the GroupDataProvider, including any persistent data store
* 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.
*/
virtual CHIP_ERROR Init() = 0;
virtual void Finish() = 0;
// Endpoints
virtual bool GroupMappingExists(chip::FabricIndex fabric_index, const GroupMapping & mapping) = 0;
virtual CHIP_ERROR AddGroupMapping(chip::FabricIndex fabric_index, const GroupMapping & mapping, const char * name) = 0;
virtual CHIP_ERROR RemoveGroupMapping(chip::FabricIndex fabric_index, const GroupMapping & mapping) = 0;
virtual CHIP_ERROR RemoveAllGroupMappings(chip::FabricIndex fabric_index) = 0;
virtual GroupMappingIterator * IterateGroupMappings(chip::FabricIndex fabric_index, EndpointId endpoint) = 0;
// States
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 GroupStateIterator * IterateGroupStates() = 0;
virtual GroupStateIterator * IterateGroupStates(chip::FabricIndex fabric_index) = 0;
// Keys
virtual CHIP_ERROR SetKeySet(chip::FabricIndex fabric_index, uint16_t key_set_index, const KeySet & keys) = 0;
virtual CHIP_ERROR GetKeySet(chip::FabricIndex fabric_index, uint16_t key_set_index, KeySet & keys) = 0;
virtual CHIP_ERROR RemoveKeySet(chip::FabricIndex fabric_index, uint16_t key_set_index) = 0;
virtual KeySetIterator * IterateKeySets(chip::FabricIndex fabric_index) = 0;
// Fabrics
virtual CHIP_ERROR RemoveFabric(chip::FabricIndex fabric_index) = 0;
// Listener
void SetListener(GroupListener * listener) { mListener = listener; };
void RemoveListener() { mListener = nullptr; };
protected:
GroupListener * mListener = nullptr;
};
/**
* Instance getter for the global GroupDataProvider.
*
* Callers have to externally synchronize usage of this function.
*
* @return The global Group Data Provider. Assume never null.
*/
GroupDataProvider * GetGroupDataProvider();
/**
* Instance setter for the global GroupDataProvider.
*
* Callers have to externally synchronize usage of this function.
*
* If the `provider` is nullptr, no change is done.
*
* @param[in] provider the Group Data Provider
*/
void SetGroupDataProvider(GroupDataProvider * provider);
} // namespace Credentials
} // namespace chip