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

Restyle Added mechanism to override device attestation failure based on client/user #17078

Closed
Closed
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
5 changes: 5 additions & 0 deletions src/controller/AutoCommissioner.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,11 @@ CHIP_ERROR AutoCommissioner::SetCommissioningParameters(const CommissioningParam
return CHIP_NO_ERROR;
}

const CommissioningParameters & AutoCommissioner::GetCommissioningParameters() const
{
return mParams;
}

CommissioningStage AutoCommissioner::GetNextCommissioningStage(CommissioningStage currentStage, CHIP_ERROR & lastErr)
{
auto nextStage = GetNextCommissioningStageInternal(currentStage, lastErr);
Expand Down
1 change: 1 addition & 0 deletions src/controller/AutoCommissioner.h
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ class AutoCommissioner : public CommissioningDelegate
AutoCommissioner();
~AutoCommissioner() override;
CHIP_ERROR SetCommissioningParameters(const CommissioningParameters & params) override;
const CommissioningParameters & GetCommissioningParameters() const override;
void SetOperationalCredentialsDelegate(OperationalCredentialsDelegate * operationalCredentialsDelegate) override;

CHIP_ERROR StartCommissioning(DeviceCommissioner * commissioner, CommissioneeDeviceProxy * proxy) override;
Expand Down
126 changes: 123 additions & 3 deletions src/controller/CHIPDeviceController.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -802,6 +802,50 @@ CHIP_ERROR DeviceCommissioner::Commission(NodeId remoteDeviceId)
return CHIP_NO_ERROR;
}

CHIP_ERROR
DeviceCommissioner::ContinueCommissioningAfterDeviceAttestationFailure(NodeId remoteDeviceId,
Credentials::AttestationVerificationResult attestationResult)
{
MATTER_TRACE_EVENT_SCOPE("continueCommissioningDevice", "DeviceCommissioner");
CommissioneeDeviceProxy * device = FindCommissioneeDevice(remoteDeviceId);
if (device == nullptr || !device->IsSecureConnected() || device != mDeviceBeingCommissioned)
{
ChipLogError(Controller, "Invalid device for commissioning af" ChipLogFormatX64, ChipLogValueX64(remoteDeviceId));
return CHIP_ERROR_INCORRECT_STATE;
}

if (mCommissioningStage != CommissioningStage::kAttestationVerification)
{
ChipLogError(Controller, "Commissioning is not attestation verification phase");
return CHIP_ERROR_INCORRECT_STATE;
}

if (mDefaultCommissioner == nullptr)
{
ChipLogError(Controller, "No default commissioner is specified");
return CHIP_ERROR_INCORRECT_STATE;
}

ChipLogProgress(Controller, "Continuing commissioning after attestation failure for node ID 0x" ChipLogFormatX64,
ChipLogValueX64(remoteDeviceId));

if (attestationResult != AttestationVerificationResult::kSuccess)
{
ChipLogError(Controller, "Client selected error: %hu for failed 'Attestation Information' for device",
static_cast<uint16_t>(attestationResult));

CommissioningDelegate::CommissioningReport report;
report.Set<AdditionalErrorInfo>(attestationResult);
CommissioningStageComplete(CHIP_ERROR_INTERNAL, report);
}
else
{
ChipLogProgress(Controller, "Overriding attestation failure per client and continuing commissioning");
CommissioningStageComplete(CHIP_NO_ERROR);
}
return CHIP_NO_ERROR;
}

CHIP_ERROR DeviceCommissioner::GetAttestationChallenge(ByteSpan & attestationChallenge)
{
Optional<SessionHandle> secureSessionHandle;
Expand Down Expand Up @@ -990,12 +1034,87 @@ void DeviceCommissioner::OnDeviceAttestationInformationVerification(void * conte
static_cast<uint16_t>(result));
// Go look at AttestationVerificationResult enum in src/credentials/attestation_verifier/DeviceAttestationVerifier.h to
// understand the errors.
commissioner->CommissioningStageComplete(CHIP_ERROR_INTERNAL, report);

auto params = commissioner->mDefaultCommissioner->GetCommissioningParameters();
Credentials::DeviceAttestationDelegate * deviceAttestationDelegate = params.GetDeviceAttestationDelegate();

// If a device attestation status delegate is installed, delegate handling of failure to the client and let them
// decide on whether to proceed further or not.
if (deviceAttestationDelegate)
{
commissioner->ExtendArmFailSafeForFailedDeviceAttestation(result);
}
else
{
commissioner->CommissioningStageComplete(CHIP_ERROR_INTERNAL, report);
}
}
else
{
ChipLogProgress(Controller, "Successfully validated 'Attestation Information' command received from the device.");
commissioner->CommissioningStageComplete(CHIP_NO_ERROR);
}
}

void DeviceCommissioner::OnArmFailSafeExtendedForFailedDeviceAttestation(
void * context, const GeneralCommissioning::Commands::ArmFailSafeResponse::DecodableType & data)
{
DeviceCommissioner * commissioner = static_cast<DeviceCommissioner *>(context);

if (!commissioner->mDeviceBeingCommissioned)
{
return;
}

ChipLogProgress(Controller, "Successfully validated 'Attestation Information' command received from the device.");
commissioner->CommissioningStageComplete(CHIP_NO_ERROR);
auto params = commissioner->mDefaultCommissioner->GetCommissioningParameters();
Credentials::DeviceAttestationDelegate * deviceAttestationDelegate = params.GetDeviceAttestationDelegate();
if (deviceAttestationDelegate)
{
ChipLogProgress(Controller, "Device attestation failed, delegating error handling to client");
NodeId remoteNodeId = commissioner->mDeviceBeingCommissioned->GetDeviceId();
deviceAttestationDelegate->OnDeviceAttestionFailed(commissioner, remoteNodeId, commissioner->mAttestationResult);
}
else
{
ChipLogProgress(Controller, "Device attestation failed and no delegate set, failing commissioning");
CommissioningDelegate::CommissioningReport report;
report.Set<AdditionalErrorInfo>(commissioner->mAttestationResult);
commissioner->CommissioningStageComplete(CHIP_ERROR_INTERNAL, report);
}
}

void DeviceCommissioner::OnFailedToExtendedArmFailSafeFailedDeviceAttestation(void * context, CHIP_ERROR error)
{
ChipLogProgress(Controller, "Failed to extend fail-safe timer to handle attestation failure %s", chip::ErrorStr(error));
DeviceCommissioner * commissioner = static_cast<DeviceCommissioner *>(context);

CommissioningDelegate::CommissioningReport report;
report.Set<AdditionalErrorInfo>(commissioner->mAttestationResult);
commissioner->CommissioningStageComplete(CHIP_ERROR_INTERNAL, report);
}

void DeviceCommissioner::ExtendArmFailSafeForFailedDeviceAttestation(AttestationVerificationResult result)
{
mAttestationResult = result;

auto params = mDefaultCommissioner->GetCommissioningParameters();
Credentials::DeviceAttestationDelegate * deviceAttestationDelegate = params.GetDeviceAttestationDelegate();
auto expiryLengthSeconds = deviceAttestationDelegate->FailSafeExpiryTimeoutSecs();
if (expiryLengthSeconds.HasValue())
{
GeneralCommissioning::Commands::ArmFailSafe::Type request;
request.expiryLengthSeconds = expiryLengthSeconds.Value();
request.breadcrumb = mCommissioningStage;
ChipLogProgress(Controller, "Changing fail-safe timer to %u seconds to handle DA failure", request.expiryLengthSeconds);
SendCommand<GeneralCommissioningCluster>(mDeviceBeingCommissioned, request, OnArmFailSafeExtendedForFailedDeviceAttestation,
OnFailedToExtendedArmFailSafeFailedDeviceAttestation);
}
else
{
ChipLogProgress(Controller, "Proceeding without changing fail-safe timer value as delegate has not set it");
const GeneralCommissioning::Commands::ArmFailSafeResponse::DecodableType data;
OnArmFailSafeExtendedForFailedDeviceAttestation(this, data);
}
}

CHIP_ERROR DeviceCommissioner::ValidateAttestationInfo(const Credentials::DeviceAttestationVerifier::AttestationInfo & info)
Expand Down Expand Up @@ -1682,6 +1801,7 @@ void DeviceCommissioner::OnDone()
report.Set<ReadCommissioningInfo>(info);
CommissioningStageComplete(return_err, report);
}

void DeviceCommissioner::OnArmFailSafe(void * context,
const GeneralCommissioning::Commands::ArmFailSafeResponse::DecodableType & data)
{
Expand Down
19 changes: 19 additions & 0 deletions src/controller/CHIPDeviceController.h
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@
#include <controller/OperationalCredentialsDelegate.h>
#include <controller/SetUpCodePairer.h>
#include <credentials/FabricTable.h>
#include <credentials/attestation_verifier/DeviceAttestationDelegate.h>
#include <credentials/attestation_verifier/DeviceAttestationVerifier.h>
#include <lib/core/CHIPConfig.h>
#include <lib/core/CHIPCore.h>
Expand Down Expand Up @@ -414,6 +415,19 @@ class DLL_EXPORT DeviceCommissioner : public DeviceController,
CHIP_ERROR Commission(NodeId remoteDeviceId, CommissioningParameters & params);
CHIP_ERROR Commission(NodeId remoteDeviceId);

/**
* @brief
* This function instructs the commissioner to proceed to the next stage of commissioning after
* attestation failure is reported to an installed attestation delegate.
*
* @param[in] remoteDeviceId The remote device Id.
* @param[in] attestationResult The attestation result to use instead of whatever the device
* attestation verifier came up with. May be a success or an error result.
*/
CHIP_ERROR
ContinueCommissioningAfterDeviceAttestationFailure(NodeId remoteDeviceId,
chip::Credentials::AttestationVerificationResult attestationResult);

CHIP_ERROR GetDeviceBeingCommissioned(NodeId deviceId, CommissioneeDeviceProxy ** device);

/**
Expand Down Expand Up @@ -615,6 +629,7 @@ class DLL_EXPORT DeviceCommissioner : public DeviceController,
/* Callback when the previously sent CSR request results in failure */
static void OnCSRFailureResponse(void * context, CHIP_ERROR error);

void ExtendArmFailSafeForFailedDeviceAttestation(Credentials::AttestationVerificationResult result);
static void OnCertificateChainFailureResponse(void * context, CHIP_ERROR error);
static void OnCertificateChainResponse(
void * context, const app::Clusters::OperationalCredentials::Commands::CertificateChainResponse::DecodableType & response);
Expand Down Expand Up @@ -674,6 +689,9 @@ class DLL_EXPORT DeviceCommissioner : public DeviceController,
const app::Clusters::GeneralCommissioning::Commands::ArmFailSafeResponse::DecodableType & data);
static void OnDisarmFailsafeFailure(void * context, CHIP_ERROR error);
void DisarmDone();
static void OnArmFailSafeExtendedForFailedDeviceAttestation(
void * context, const chip::app::Clusters::GeneralCommissioning::Commands::ArmFailSafeResponse::DecodableType & data);
static void OnFailedToExtendedArmFailSafeFailedDeviceAttestation(void * context, CHIP_ERROR error);

/**
* @brief
Expand Down Expand Up @@ -767,6 +785,7 @@ class DLL_EXPORT DeviceCommissioner : public DeviceController,

Platform::UniquePtr<app::AttributeCache> mAttributeCache;
Platform::UniquePtr<app::ReadClient> mReadClient;
Credentials::AttestationVerificationResult mAttestationResult;
};

} // namespace Controller
Expand Down
12 changes: 12 additions & 0 deletions src/controller/CommissioningDelegate.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
#pragma once
#include <app/OperationalDeviceProxy.h>
#include <controller/CommissioneeDeviceProxy.h>
#include <credentials/attestation_verifier/DeviceAttestationDelegate.h>
#include <credentials/attestation_verifier/DeviceAttestationVerifier.h>
#include <lib/support/Variant.h>

Expand Down Expand Up @@ -323,6 +324,14 @@ class CommissioningParameters
}
void SetCompletionStatus(const CompletionStatus & status) { completionStatus = status; }

CommissioningParameters & SetDeviceAttestationDelegate(Credentials::DeviceAttestationDelegate * deviceAttestationDelegate)
{
mDeviceAttestationDelegate = deviceAttestationDelegate;
return *this;
}

Credentials::DeviceAttestationDelegate * GetDeviceAttestationDelegate() const { return mDeviceAttestationDelegate; }

private:
// Items that can be set by the commissioner
Optional<uint16_t> mFailsafeTimerSeconds;
Expand All @@ -347,6 +356,8 @@ class CommissioningParameters
Optional<app::Clusters::GeneralCommissioning::RegulatoryLocationType> mDefaultRegulatoryLocation;
Optional<app::Clusters::GeneralCommissioning::RegulatoryLocationType> mLocationCapability;
CompletionStatus completionStatus;
Credentials::DeviceAttestationDelegate * mDeviceAttestationDelegate =
nullptr; // Delegate to handle device attestation failures during commissioning
};

struct RequestedCertificate
Expand Down Expand Up @@ -460,6 +471,7 @@ class CommissioningDelegate
CommissioningStage stageCompleted;
};
virtual CHIP_ERROR SetCommissioningParameters(const CommissioningParameters & params) = 0;
virtual const CommissioningParameters & GetCommissioningParameters() const = 0;
virtual void SetOperationalCredentialsDelegate(OperationalCredentialsDelegate * operationalCredentialsDelegate) = 0;
virtual CHIP_ERROR StartCommissioning(DeviceCommissioner * commissioner, CommissioneeDeviceProxy * proxy) = 0;
virtual CHIP_ERROR CommissioningStepFinished(CHIP_ERROR err, CommissioningReport report) = 0;
Expand Down
2 changes: 2 additions & 0 deletions src/credentials/BUILD.gn
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ static_library("credentials") {
"GenerateChipX509Cert.cpp",
"GroupDataProvider.h",
"GroupDataProviderImpl.cpp",
"attestation_verifier/DeviceAttestationDelegate.h",
"attestation_verifier/DeviceAttestationVerifier.cpp",
"attestation_verifier/DeviceAttestationVerifier.h",
"examples/DeviceAttestationCredsExample.cpp",
Expand Down Expand Up @@ -85,6 +86,7 @@ static_library("default_attestation_verifier") {
sources = [
"attestation_verifier/DefaultDeviceAttestationVerifier.cpp",
"attestation_verifier/DefaultDeviceAttestationVerifier.h",
"attestation_verifier/DeviceAttestationDelegate.h",
]

if (chip_device_platform == "esp32" || chip_device_platform == "nrfconnect") {
Expand Down
60 changes: 60 additions & 0 deletions src/credentials/attestation_verifier/DeviceAttestationDelegate.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
/*
*
* Copyright (c) 2021 Project CHIP Authors
* All rights reserved.
*
* 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 <credentials/attestation_verifier/DeviceAttestationVerifier.h>
#include <lib/core/Optional.h>

namespace chip {

namespace Controller {
class DeviceCommissioner;
} // namespace Controller

namespace Credentials {

/// Callbacks for CHIP device attestation status
class DeviceAttestationDelegate
{
public:
virtual ~DeviceAttestationDelegate() {}

/**
* @brief
* If valid, value to set for the fail-safe timer before the delegate's OnDeviceAttestionFailed is invoked.
*
* @return Optional value for the fail-safe timer in seconds.
*/
virtual Optional<uint16_t> FailSafeExpiryTimeoutSecs() const = 0;

/**
* @brief
* This method is invoked when device attestation fails for a device that is being commissioned. The client
* handling the failure has the option to continue commissionning or fail the operation.
*
* @param deviceCommissioner The commissioner object that is commissioning the device
* @param remoteNodeId The NodeId of the Commissionee device
* @param attestationResult The failure code for the device attestation validation operation
*/
virtual void OnDeviceAttestionFailed(chip::Controller::DeviceCommissioner * deviceCommissioner, chip::NodeId remoteNodeId,
chip::Credentials::AttestationVerificationResult attestationResult) = 0;
};

} // namespace Credentials
} // namespace chip
Loading