Skip to content

Commit

Permalink
Add Aliro delegate support to the example lock app. (#34302)
Browse files Browse the repository at this point in the history
  • Loading branch information
bzbarsky-apple authored and pull[bot] committed Nov 28, 2024
1 parent 1f7edd8 commit 0c10275
Show file tree
Hide file tree
Showing 6 changed files with 284 additions and 11 deletions.
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

0 comments on commit 0c10275

Please sign in to comment.