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

Reset the wrong code retry attempts if a valid credential is presented #25536

Merged
28 changes: 26 additions & 2 deletions src/app/clusters/door-lock-server/door-lock-server.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,13 @@ bool DoorLockServer::SetLockState(chip::EndpointId endpointId, DlLockState newLo
SendLockOperationEvent(endpointId, opType, opSource, OperationErrorEnum::kUnspecified, userIndex, Nullable<chip::FabricIndex>(),
Nullable<chip::NodeId>(), credentials, success);

// Reset code wrong entry attempts (in case there were any incorrect wrong code retries prior) since lock/unlock was a success
// and a valid credential was presented
nivi-apple marked this conversation as resolved.
Show resolved Hide resolved
if (success && !credentials.IsNull() && !(credentials.Value().empty()))
{
ResetWrongCodeEntryAttempts(endpointId);
nivi-apple marked this conversation as resolved.
Show resolved Hide resolved
}

// Schedule auto-relocking
if (success && LockOperationTypeEnum::kUnlock == opType)
{
Expand Down Expand Up @@ -181,7 +188,7 @@ bool DoorLockServer::SetPrivacyModeButton(chip::EndpointId endpointId, bool isEn
return SetAttribute(endpointId, Attributes::EnablePrivacyModeButton::Id, Attributes::EnablePrivacyModeButton::Set, isEnabled);
}

bool DoorLockServer::TrackWrongCodeEntry(chip::EndpointId endpointId)
bool DoorLockServer::HandleWrongCodeEntry(chip::EndpointId endpointId)
{
auto endpointContext = getContext(endpointId);
if (nullptr == endpointContext)
Expand Down Expand Up @@ -209,6 +216,17 @@ bool DoorLockServer::TrackWrongCodeEntry(chip::EndpointId endpointId)
return true;
}

void DoorLockServer::ResetWrongCodeEntryAttempts(chip::EndpointId endpointId)
{
auto endpointContext = getContext(endpointId);
if (nullptr == endpointContext)
{
ChipLogError(Zcl, "Failed to reset wrong code entry attempts. No context for endpoint %d", endpointId);
return;
}
endpointContext->wrongCodeEntryAttempts = 0;
}

bool DoorLockServer::engageLockout(chip::EndpointId endpointId)
{
uint8_t lockoutTimeout;
Expand Down Expand Up @@ -3352,7 +3370,13 @@ bool DoorLockServer::HandleRemoteLockOperation(chip::app::CommandHandler * comma
exit:
if (!success && reason == OperationErrorEnum::kInvalidCredential)
{
TrackWrongCodeEntry(endpoint);
HandleWrongCodeEntry(endpoint);
}

// Reset the wrong code retry attempts if a valid credential is presented during lock/unlock
if ((opType == LockOperationTypeEnum::kUnlock || opType == LockOperationTypeEnum::kLock) && success && pinCode.HasValue())
nivi-apple marked this conversation as resolved.
Show resolved Hide resolved
{
ResetWrongCodeEntryAttempts(endpoint);
nivi-apple marked this conversation as resolved.
Show resolved Hide resolved
}

// Send command response
Expand Down
21 changes: 20 additions & 1 deletion src/app/clusters/door-lock-server/door-lock-server.h
Original file line number Diff line number Diff line change
Expand Up @@ -121,7 +121,16 @@ class DoorLockServer
bool SetOneTouchLocking(chip::EndpointId endpointId, bool isEnabled);
bool SetPrivacyModeButton(chip::EndpointId endpointId, bool isEnabled);

bool TrackWrongCodeEntry(chip::EndpointId endpointId);
/**
* @brief Handles a wrong code entry attempt for the endpoint. If the number of wrong entry attempts exceeds the max limit,
* engage lockout. Otherwise increment the number of incorrect attempts by 1. This is handled automatically for
* remote operations - lock and unlock . Any app that uses SetLockState or sends lock/unlock events via
* SendLockOperationEvent has to handle tracking of wrong retry attempts and needs to call this API to update the wrong entry
* attempt count or engage lockoutif retry limit is exceeded.
nivi-apple marked this conversation as resolved.
Show resolved Hide resolved
*
* @param endpointId
*/
bool HandleWrongCodeEntry(chip::EndpointId endpointId);
nivi-apple marked this conversation as resolved.
Show resolved Hide resolved
nivi-apple marked this conversation as resolved.
Show resolved Hide resolved

bool GetAutoRelockTime(chip::EndpointId endpointId, uint32_t & autoRelockTime);
bool GetNumberOfUserSupported(chip::EndpointId endpointId, uint16_t & numberOfUsersSupported);
Expand Down Expand Up @@ -183,6 +192,16 @@ class DoorLockServer
bool OnFabricRemoved(chip::EndpointId endpointId, chip::FabricIndex fabricIndex);

static void DoorLockOnAutoRelockCallback(chip::System::Layer *, void * callbackContext);
/**
* @brief Resets the wrong code entry attempts to 0 for the endpoint. This API is called from HandleRemoteLockOperation
* to reset the count if we have an lock/unlock remote operation with valid credential automatically. An app that
* calls SetLockState also will have this done automatically on successful unlock operation using valid credential.
* Any app that sends unlock events via SendLockOperationEvent has to handle resetting the wrong retry count by
* calling this API.
nivi-apple marked this conversation as resolved.
Show resolved Hide resolved
*
* @param endpointId
*/
void ResetWrongCodeEntryAttempts(chip::EndpointId endpointId);

private:
chip::FabricIndex getFabricIndex(const chip::app::CommandHandler * commandObj);
Expand Down
98 changes: 93 additions & 5 deletions src/app/tests/suites/DL_LockUnlock.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -238,11 +238,11 @@ tests:
arguments:
value: 0

- label: "Read the lockout timeout"
command: "readAttribute"
attribute: "UserCodeTemporaryDisableTime"
response:
value: 10
# Test resetting wrong code entry retry attempts
# Set the retry limit to 3. Try to unlock with incorrect PIN 2 times followed by a third time
# with correct PIN code. The retry attempts should be reset to 0. Try to unock with incorrect
# PIN 2 times followed by a third time with correct PIN code. We should be able to unlock since
# the count has been reset and we are not in lockout.

- label: "Set the WrongCodeEntryLimit to small value so we can test lockout"
command: "writeAttribute"
Expand Down Expand Up @@ -270,6 +270,94 @@ tests:
response:
error: FAILURE

- label: "Try to unlock the door with valid PIN for the third time"
command: "UnlockDoor"
timedInteractionTimeoutMs: 10000
arguments:
values:
- name: "PINCode"
value: "123456"

- label: "Verify that lock state attribute value is set to Unlocked"
command: "readAttribute"
attribute: "LockState"
response:
value: 2

- label: "Try to unlock the door with invalid PIN for the first time"
command: "UnlockDoor"
nivi-apple marked this conversation as resolved.
Show resolved Hide resolved
timedInteractionTimeoutMs: 10000
arguments:
values:
- name: "PINCode"
value: "000000"
response:
error: FAILURE

- label: "Try to unlock the door with invalid PIN for the second time"
command: "UnlockDoor"
timedInteractionTimeoutMs: 10000
arguments:
values:
- name: "PINCode"
value: "000000"
response:
error: FAILURE

- label: "Try to unlock the door with valid PIN for the third time"
command: "UnlockDoor"
timedInteractionTimeoutMs: 10000
arguments:
values:
- name: "PINCode"
value: "123456"

- label: "Verify that lock state attribute value is set to Unlocked"
command: "readAttribute"
attribute: "LockState"
response:
value: 2

- label: "Lock the door back prior to next tests"
nivi-apple marked this conversation as resolved.
Show resolved Hide resolved
command: "LockDoor"
timedInteractionTimeoutMs: 10000
arguments:
values:
- name: "PINCode"
value: "123456"

- label: "Verify that lock state attribute value is set to Locked"
command: "readAttribute"
attribute: "LockState"
response:
value: 1

- label: "Read the lockout timeout"
command: "readAttribute"
attribute: "UserCodeTemporaryDisableTime"
response:
value: 10

- label: "Try to unlock the door with invalid PIN for the first time"
command: "UnlockDoor"
timedInteractionTimeoutMs: 10000
arguments:
values:
- name: "PINCode"
value: "000000"
response:
error: FAILURE

- label: "Try to unlock the door with invalid PIN for the second time"
command: "UnlockDoor"
timedInteractionTimeoutMs: 10000
arguments:
values:
- name: "PINCode"
value: "000000"
response:
error: FAILURE

- label: "Try to unlock the door with invalid PIN for the third time"
command: "UnlockDoor"
timedInteractionTimeoutMs: 10000
Expand Down
Loading