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

Add Aliro delegate support to the example lock app. #34302

Merged
merged 1 commit into from
Jul 12, 2024
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
33 changes: 30 additions & 3 deletions examples/lock-app/lock-common/include/LockEndpoint.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,9 @@

#pragma once

#include <app/clusters/door-lock-server/door-lock-delegate.h>
#include <app/clusters/door-lock-server/door-lock-server.h>
#include <crypto/CHIPCryptoPAL.h>
#include <vector>

struct LockUserInfo
Expand All @@ -38,10 +40,10 @@ struct WeekDaysScheduleInfo;
struct YearDayScheduleInfo;
struct HolidayScheduleInfo;

static constexpr size_t DOOR_LOCK_CREDENTIAL_INFO_MAX_DATA_SIZE = 20;
static constexpr size_t DOOR_LOCK_CREDENTIAL_INFO_MAX_TYPES = 6;
static constexpr size_t DOOR_LOCK_CREDENTIAL_INFO_MAX_DATA_SIZE = 65;
static constexpr size_t DOOR_LOCK_CREDENTIAL_INFO_MAX_TYPES = 9;

class LockEndpoint
class LockEndpoint : public chip::app::Clusters::DoorLock::Delegate
{
public:
LockEndpoint(chip::EndpointId endpointId, uint16_t numberOfLockUsersSupported, uint16_t numberOfCredentialsSupported,
Expand All @@ -60,6 +62,7 @@ class LockEndpoint
}
DoorLockServer::Instance().SetDoorState(endpointId, mDoorState);
DoorLockServer::Instance().SetLockState(endpointId, mLockState);
chip::Crypto::DRBG_get_bytes(mAliroReaderGroupSubIdentifier, sizeof(mAliroReaderGroupSubIdentifier));
}

inline chip::EndpointId GetEndpointId() const { return mEndpointId; }
Expand Down Expand Up @@ -100,6 +103,22 @@ class LockEndpoint
DlStatus SetSchedule(uint8_t holidayIndex, DlScheduleStatus status, uint32_t localStartTime, uint32_t localEndTime,
OperatingModeEnum operatingMode);

// DoorLock::Delegate API.
CHIP_ERROR GetAliroReaderVerificationKey(chip::MutableByteSpan & verificationKey) override;
CHIP_ERROR GetAliroReaderGroupIdentifier(chip::MutableByteSpan & groupIdentifier) override;
CHIP_ERROR GetAliroReaderGroupSubIdentifier(chip::MutableByteSpan & groupSubIdentifier) override;
CHIP_ERROR GetAliroExpeditedTransactionSupportedProtocolVersionAtIndex(size_t index,
chip::MutableByteSpan & protocolVersion) override;
CHIP_ERROR GetAliroGroupResolvingKey(chip::MutableByteSpan & groupResolvingKey) override;
CHIP_ERROR GetAliroSupportedBLEUWBProtocolVersionAtIndex(size_t index, chip::MutableByteSpan & protocolVersion) override;
uint8_t GetAliroBLEAdvertisingVersion() override;
uint16_t GetNumberOfAliroCredentialIssuerKeysSupported() override;
uint16_t GetNumberOfAliroEndpointKeysSupported() override;
CHIP_ERROR SetAliroReaderConfig(const chip::ByteSpan & signingKey, const chip::ByteSpan & verificationKey,
const chip::ByteSpan & groupIdentifier,
const chip::Optional<chip::ByteSpan> & groupResolvingKey) override;
CHIP_ERROR ClearAliroReaderConfig() override;

private:
bool setLockState(const Nullable<chip::FabricIndex> & fabricIdx, const Nullable<chip::NodeId> & nodeId, DlLockState lockState,
const Optional<chip::ByteSpan> & pin, OperationErrorEnum & err,
Expand Down Expand Up @@ -130,6 +149,14 @@ class LockEndpoint
std::vector<std::vector<WeekDaysScheduleInfo>> mWeekDaySchedules;
std::vector<std::vector<YearDayScheduleInfo>> mYearDaySchedules;
std::vector<HolidayScheduleInfo> mHolidaySchedules;

// Actual Aliro state would presumably be stored somewhere else, and persistently; this
// example just stores it in memory for illustration purposes.
uint8_t mAliroReaderVerificationKey[chip::app::Clusters::DoorLock::kAliroReaderVerificationKeySize];
uint8_t mAliroReaderGroupIdentifier[chip::app::Clusters::DoorLock::kAliroReaderGroupIdentifierSize];
uint8_t mAliroReaderGroupSubIdentifier[chip::app::Clusters::DoorLock::kAliroReaderGroupSubIdentifierSize];
uint8_t mAliroGroupResolvingKey[chip::app::Clusters::DoorLock::kAliroGroupResolvingKeySize];
bool mAliroStateInitialized = false;
};

struct LockCredentialInfo
Expand Down
7 changes: 6 additions & 1 deletion examples/lock-app/lock-common/include/LockManager.h
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,12 @@ class LockManager
private:
LockEndpoint * getEndpoint(chip::EndpointId endpointId);

std::vector<LockEndpoint> mEndpoints;
/**
* We store the LockEndpoint instances by pointer, not value, so
* LockEndpoint can have a stable location in memory, which lets it
* implement DoorLock::Delegate.
*/
std::vector<std::unique_ptr<LockEndpoint>> mEndpoints;

static LockManager instance;
};
151 changes: 150 additions & 1 deletion examples/lock-app/lock-common/src/LockEndpoint.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,15 @@
*/
#include "LockEndpoint.h"
#include <app-common/zap-generated/attributes/Accessors.h>
#include <app-common/zap-generated/cluster-enums.h>
#include <cstring>
#include <lib/core/CHIPEncoding.h>
#include <platform/CHIPDeviceLayer.h>
#include <platform/internal/CHIPDeviceLayerInternal.h>

using chip::ByteSpan;
using chip::MutableByteSpan;
using chip::Optional;
using chip::to_underlying;
using chip::app::DataModel::MakeNullable;

Expand Down Expand Up @@ -204,7 +209,8 @@ bool LockEndpoint::GetCredential(uint16_t credentialIndex, CredentialTypeEnum cr
if (credentialIndex >= mLockCredentials.at(to_underlying(credentialType)).size() ||
(0 == credentialIndex && CredentialTypeEnum::kProgrammingPIN != credentialType))
{
ChipLogError(Zcl, "Cannot get the credential - index out of range [endpoint=%d,index=%d]", mEndpointId, credentialIndex);
ChipLogError(Zcl, "Cannot get the credential - index out of range [endpoint=%d,index=%d]: %d", mEndpointId, credentialIndex,
static_cast<int>(mLockCredentials.at(to_underlying(credentialType)).size()));
return false;
}

Expand Down Expand Up @@ -407,6 +413,149 @@ DlStatus LockEndpoint::SetSchedule(uint8_t holidayIndex, DlScheduleStatus status
return DlStatus::kSuccess;
}

CHIP_ERROR LockEndpoint::GetAliroReaderVerificationKey(MutableByteSpan & verificationKey)
{
if (!mAliroStateInitialized)
{
verificationKey.reduce_size(0);
return CHIP_NO_ERROR;
}

return chip::CopySpanToMutableSpan(ByteSpan(mAliroReaderVerificationKey), verificationKey);
}

CHIP_ERROR LockEndpoint::GetAliroReaderGroupIdentifier(MutableByteSpan & groupIdentifier)
{
if (!mAliroStateInitialized)
{
groupIdentifier.reduce_size(0);
return CHIP_NO_ERROR;
}

return CopySpanToMutableSpan(ByteSpan(mAliroReaderGroupIdentifier), groupIdentifier);
}

CHIP_ERROR LockEndpoint::GetAliroReaderGroupSubIdentifier(MutableByteSpan & groupSubIdentifier)
{
return CopySpanToMutableSpan(ByteSpan(mAliroReaderGroupSubIdentifier), groupSubIdentifier);
}

namespace {

CHIP_ERROR CopyProtocolVersionIntoSpan(uint16_t protocolVersionValue, MutableByteSpan & protocolVersion)
{
using namespace chip::app::Clusters::DoorLock;

static_assert(sizeof(protocolVersionValue) == kAliroProtocolVersionSize);

if (protocolVersion.size() < kAliroProtocolVersionSize)
{
return CHIP_ERROR_INVALID_ARGUMENT;
}

// Per Aliro spec, protocol version encoding is big-endian
chip::Encoding::BigEndian::Put16(protocolVersion.data(), protocolVersionValue);
protocolVersion.reduce_size(kAliroProtocolVersionSize);
return CHIP_NO_ERROR;
}

} // anonymous namespace

CHIP_ERROR LockEndpoint::GetAliroExpeditedTransactionSupportedProtocolVersionAtIndex(size_t index,
MutableByteSpan & protocolVersion)
{
// Only claim support for the one known protocol version for now: 0x0100.
constexpr uint16_t knownProtocolVersion = 0x0100;

if (index > 0)
{
return CHIP_ERROR_PROVIDER_LIST_EXHAUSTED;
}

return CopyProtocolVersionIntoSpan(knownProtocolVersion, protocolVersion);
}

CHIP_ERROR LockEndpoint::GetAliroGroupResolvingKey(MutableByteSpan & groupResolvingKey)
{
if (!mAliroStateInitialized)
{
groupResolvingKey.reduce_size(0);
return CHIP_NO_ERROR;
}

return CopySpanToMutableSpan(ByteSpan(mAliroGroupResolvingKey), groupResolvingKey);
}

CHIP_ERROR LockEndpoint::GetAliroSupportedBLEUWBProtocolVersionAtIndex(size_t index, MutableByteSpan & protocolVersion)
{
// Only claim support for the one known protocol version for now: 0x0100.
constexpr uint16_t knownProtocolVersion = 0x0100;

if (index > 0)
{
return CHIP_ERROR_PROVIDER_LIST_EXHAUSTED;
}

return CopyProtocolVersionIntoSpan(knownProtocolVersion, protocolVersion);
}

uint8_t LockEndpoint::GetAliroBLEAdvertisingVersion()
{
// For now the only define value of the BLE advertising version for Aliro is 0.
return 0;
}

uint16_t LockEndpoint::GetNumberOfAliroCredentialIssuerKeysSupported()
{
using namespace chip::app::Clusters::DoorLock;

// Our vector has an extra entry at index 0 that is not a valid entry, so
// the actual number of credentials supported is one length than the length.
return static_cast<uint16_t>(mLockCredentials.at(to_underlying(CredentialTypeEnum::kAliroCredentialIssuerKey)).size() - 1);
}

uint16_t LockEndpoint::GetNumberOfAliroEndpointKeysSupported()
{
using namespace chip::app::Clusters::DoorLock;

// Our vector has an extra entry at index 0 that is not a valid entry, so
// the actual number of credentials supported is one length than the length.
//
// Also, our arrays are the same size, so we just return the size of one of
// the arrays: that is the cap on the total number of endpoint keys
// supported, which can be of either type.
return static_cast<uint16_t>(mLockCredentials.at(to_underlying(CredentialTypeEnum::kAliroEvictableEndpointKey)).size() - 1);
}

CHIP_ERROR LockEndpoint::SetAliroReaderConfig(const ByteSpan & signingKey, const ByteSpan & verificationKey,
const ByteSpan & groupIdentifier, const Optional<ByteSpan> & groupResolvingKey)
{
// We ignore the signing key, since we never do anything with it.

VerifyOrReturnError(verificationKey.size() == sizeof(mAliroReaderVerificationKey), CHIP_ERROR_INVALID_ARGUMENT);
memcpy(mAliroReaderVerificationKey, verificationKey.data(), sizeof(mAliroReaderVerificationKey));

VerifyOrReturnError(groupIdentifier.size() == sizeof(mAliroReaderGroupIdentifier), CHIP_ERROR_INVALID_ARGUMENT);
memcpy(mAliroReaderGroupIdentifier, groupIdentifier.data(), sizeof(mAliroReaderGroupIdentifier));

if (groupResolvingKey.HasValue())
{
VerifyOrReturnError(groupResolvingKey.Value().size() == sizeof(mAliroGroupResolvingKey), CHIP_ERROR_INVALID_ARGUMENT);
memcpy(mAliroGroupResolvingKey, groupResolvingKey.Value().data(), sizeof(mAliroGroupResolvingKey));
}

mAliroStateInitialized = true;
return CHIP_NO_ERROR;
}

CHIP_ERROR LockEndpoint::ClearAliroReaderConfig()
{
// A real implementation would clear out key data from the other parts of
// the application that might use it.
mAliroStateInitialized = false;
return CHIP_NO_ERROR;
}

bool LockEndpoint::setLockState(const Nullable<chip::FabricIndex> & fabricIdx, const Nullable<chip::NodeId> & nodeId,
DlLockState lockState, const Optional<chip::ByteSpan> & pin, OperationErrorEnum & err,
OperationSourceEnum opSource)
Expand Down
13 changes: 8 additions & 5 deletions examples/lock-app/lock-common/src/LockManager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@

#include <iostream>
#include <lib/support/logging/CHIPLogging.h>
#include <memory>

using chip::to_underlying;

Expand Down Expand Up @@ -98,15 +99,17 @@ bool LockManager::InitEndpoint(chip::EndpointId endpointId)
numberOfHolidaySchedules = 10;
}

mEndpoints.emplace_back(endpointId, numberOfSupportedUsers, numberOfSupportedCredentials, numberOfWeekDaySchedulesPerUser,
numberOfYearDaySchedulesPerUser, numberOfCredentialsSupportedPerUser, numberOfHolidaySchedules);
mEndpoints.emplace_back(std::make_unique<LockEndpoint>(endpointId, numberOfSupportedUsers, numberOfSupportedCredentials,
numberOfWeekDaySchedulesPerUser, numberOfYearDaySchedulesPerUser,
numberOfCredentialsSupportedPerUser, numberOfHolidaySchedules));

ChipLogProgress(Zcl,
"Initialized new lock door endpoint "
"[id=%d,users=%d,credentials=%d,weekDaySchedulesPerUser=%d,yearDaySchedulesPerUser=%d,"
"numberOfCredentialsSupportedPerUser=%d,holidaySchedules=%d]",
endpointId, numberOfSupportedUsers, numberOfSupportedCredentials, numberOfWeekDaySchedulesPerUser,
numberOfYearDaySchedulesPerUser, numberOfCredentialsSupportedPerUser, numberOfHolidaySchedules);
DoorLockServer::Instance().SetDelegate(endpointId, mEndpoints.back().get());

return true;
}
Expand Down Expand Up @@ -303,11 +306,11 @@ DlStatus LockManager::SetSchedule(chip::EndpointId endpointId, uint8_t holidayIn

LockEndpoint * LockManager::getEndpoint(chip::EndpointId endpointId)
{
for (auto & mEndpoint : mEndpoints)
for (auto & endpoint : mEndpoints)
{
if (mEndpoint.GetEndpointId() == endpointId)
if (endpoint->GetEndpointId() == endpointId)
{
return &mEndpoint;
return endpoint.get();
}
}
return nullptr;
Expand Down
Loading
Loading