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

Validate CSR in separate commissioning step #16913

Merged
merged 11 commits into from
Apr 4, 2022
2 changes: 2 additions & 0 deletions src/controller/AutoCommissioner.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,8 @@ CommissioningStage AutoCommissioner::GetNextCommissioningStageInternal(Commissio
case CommissioningStage::kAttestationVerification:
return CommissioningStage::kSendOpCertSigningRequest;
case CommissioningStage::kSendOpCertSigningRequest:
return CommissioningStage::kValidateCSR;
case CommissioningStage::kValidateCSR:
return CommissioningStage::kGenerateNOCChain;
case CommissioningStage::kGenerateNOCChain:
return CommissioningStage::kSendTrustedRootCert;
Expand Down
50 changes: 42 additions & 8 deletions src/controller/CHIPDeviceController.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -997,6 +997,26 @@ CHIP_ERROR DeviceCommissioner::ValidateAttestationInfo(const Credentials::Device
return CHIP_NO_ERROR;
}

CHIP_ERROR DeviceCommissioner::ValidateCSR(DeviceProxy * proxy, const ByteSpan & NOCSRElements,
const ByteSpan & AttestationSignature, ByteSpan dac, ByteSpan csrNonce)
{
MATTER_TRACE_EVENT_SCOPE("ValidateCSR", "DeviceCommissioner");
VerifyOrReturnError(mState == State::Initialized, CHIP_ERROR_INCORRECT_STATE);

DeviceAttestationVerifier * dacVerifier = GetDeviceAttestationVerifier();

P256PublicKey dacPubkey;
ReturnErrorOnFailure(ExtractPubkeyFromX509Cert(dac, dacPubkey));

// Retrieve attestation challenge
ByteSpan attestationChallenge =
proxy->GetSecureSession().Value()->AsSecureSession()->GetCryptoContext().GetAttestationChallenge();

// The operational CA should also verify this on its end during NOC generation, if end-to-end attestation is desired.
return dacVerifier->VerifyNodeOperationalCSRInformation(NOCSRElements, attestationChallenge, AttestationSignature, dacPubkey,
csrNonce);
}

CHIP_ERROR DeviceCommissioner::SendOperationalCertificateSigningRequestCommand(DeviceProxy * device, const ByteSpan & csrNonce)
{
MATTER_TRACE_EVENT_SCOPE("SendOperationalCertificateSigningRequestCommand", "DeviceCommissioner");
Expand Down Expand Up @@ -1071,9 +1091,10 @@ CHIP_ERROR DeviceCommissioner::ProcessCSR(DeviceProxy * proxy, const ByteSpan &
MATTER_TRACE_EVENT_SCOPE("ProcessOpCSR", "DeviceCommissioner");
VerifyOrReturnError(mState == State::Initialized, CHIP_ERROR_INCORRECT_STATE);

ChipLogProgress(Controller, "Getting certificate chain for the device from the issuer");
// This will be used once the GenerateNOCChain
cecille marked this conversation as resolved.
Show resolved Hide resolved
(void) csrNonce;

DeviceAttestationVerifier * dacVerifier = GetDeviceAttestationVerifier();
ChipLogProgress(Controller, "Getting certificate chain for the device from the issuer");

P256PublicKey dacPubkey;
ReturnErrorOnFailure(ExtractPubkeyFromX509Cert(dac, dacPubkey));
Expand All @@ -1082,19 +1103,15 @@ CHIP_ERROR DeviceCommissioner::ProcessCSR(DeviceProxy * proxy, const ByteSpan &
ByteSpan attestationChallenge =
proxy->GetSecureSession().Value()->AsSecureSession()->GetCryptoContext().GetAttestationChallenge();

// The operational CA should also verify this on its end during NOC generation, if end-to-end attestation is desired.
ReturnErrorOnFailure(dacVerifier->VerifyNodeOperationalCSRInformation(NOCSRElements, attestationChallenge, AttestationSignature,
dacPubkey, csrNonce));

mOperationalCredentialsDelegate->SetNodeIdForNextNOCRequest(proxy->GetDeviceId());

if (mFabricInfo != nullptr)
{
mOperationalCredentialsDelegate->SetFabricIdForNextNOCRequest(mFabricInfo->GetFabricId());
}

return mOperationalCredentialsDelegate->GenerateNOCChain(NOCSRElements, AttestationSignature, dac, ByteSpan(), ByteSpan(),
&mDeviceNOCChainCallback);
return mOperationalCredentialsDelegate->GenerateNOCChain(NOCSRElements, csrNonce, AttestationSignature, attestationChallenge,
dac, ByteSpan(), ByteSpan(), &mDeviceNOCChainCallback);
cecille marked this conversation as resolved.
Show resolved Hide resolved
}

CHIP_ERROR DeviceCommissioner::SendOperationalCertificate(DeviceProxy * device, const ByteSpan & nocCertBuf,
Expand Down Expand Up @@ -1809,6 +1826,23 @@ void DeviceCommissioner::PerformCommissioningStep(DeviceProxy * proxy, Commissio
}
SendOperationalCertificateSigningRequestCommand(proxy, params.GetCSRNonce().Value());
break;
case CommissioningStage::kValidateCSR: {
if (!params.GetNOCChainGenerationParameters().HasValue() || !params.GetDAC().HasValue() || !params.GetCSRNonce().HasValue())
{
ChipLogError(Controller, "Unable to validate CSR");
return CommissioningStageComplete(CHIP_ERROR_INVALID_ARGUMENT);
}
// This is non-blocking, so send the callback immediately.
CHIP_ERROR err = ValidateCSR(proxy, params.GetNOCChainGenerationParameters().Value().nocsrElements,
params.GetNOCChainGenerationParameters().Value().signature, params.GetDAC().Value(),
params.GetCSRNonce().Value());
if (err != CHIP_NO_ERROR)
{
ChipLogError(Controller, "Unable to validate CSR");
}
CommissioningStageComplete(err);
}
break;
case CommissioningStage::kGenerateNOCChain: {
if (!params.GetNOCChainGenerationParameters().HasValue() || !params.GetDAC().HasValue() || !params.GetCSRNonce().HasValue())
{
Expand Down
14 changes: 14 additions & 0 deletions src/controller/CHIPDeviceController.h
Original file line number Diff line number Diff line change
Expand Up @@ -729,6 +729,20 @@ class DLL_EXPORT DeviceCommissioner : public DeviceController,
CHIP_ERROR ProcessCSR(DeviceProxy * proxy, const ByteSpan & NOCSRElements, const ByteSpan & AttestationSignature, ByteSpan dac,
ByteSpan csrNonce);

/**
* @brief
* This function validates the CSR information from the device.
* (Reference: Specifications section 11.18.5.6. NOCSR Elements)
*
* @param[in] proxy device proxy
* @param[in] NOCSRElements CSR elements as per specifications section 11.22.5.6. NOCSR Elements.
* @param[in] AttestationSignature Cryptographic signature generated for all the above fields.
* @param[in] dac device attestation certificate
* @param[in] csrNonce certificate signing request nonce
*/
CHIP_ERROR ValidateCSR(DeviceProxy * proxy, const ByteSpan & NOCSRElements, const ByteSpan & AttestationSignature, ByteSpan dac,
ByteSpan csrNonce);

/**
* @brief
* This function processes the DAC or PAI certificate sent by the device.
Expand Down
4 changes: 4 additions & 0 deletions src/controller/CommissioningDelegate.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,10 @@ const char * StageToString(CommissioningStage stage)
return "SendOpCertSigningRequest";
break;

case kValidateCSR:
return "ValidateCSR";
break;

case kGenerateNOCChain:
return "GenerateNOCChain";
break;
Expand Down
1 change: 1 addition & 0 deletions src/controller/CommissioningDelegate.h
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ enum CommissioningStage : uint8_t
kSendAttestationRequest,
kAttestationVerification,
kSendOpCertSigningRequest,
kValidateCSR,
kGenerateNOCChain,
kSendTrustedRootCert,
kSendNOC,
Expand Down
9 changes: 7 additions & 2 deletions src/controller/ExampleOperationalCredentialsIssuer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -176,12 +176,17 @@ CHIP_ERROR ExampleOperationalCredentialsIssuer::GenerateNOCChainAfterValidation(
return NewNodeOperationalX509Cert(noc_request, pubkey, mIntermediateIssuer, noc);
}

CHIP_ERROR ExampleOperationalCredentialsIssuer::GenerateNOCChain(const ByteSpan & csrElements,
const ByteSpan & attestationSignature, const ByteSpan & DAC,
CHIP_ERROR ExampleOperationalCredentialsIssuer::GenerateNOCChain(const ByteSpan & csrElements, const ByteSpan & csrNonce,
const ByteSpan & attestationSignature,
const ByteSpan & attestationChallenge, const ByteSpan & DAC,
const ByteSpan & PAI, const ByteSpan & PAA,
cecille marked this conversation as resolved.
Show resolved Hide resolved
Callback::Callback<OnNOCChainGeneration> * onCompletion)
{
VerifyOrReturnError(mInitialized, CHIP_ERROR_INCORRECT_STATE);
// At this point, Credential issuer may wish to validate the CSR information
(void) attestationChallenge;
(void) csrNonce;

NodeId assignedId;
if (mNodeIdRequested)
{
Expand Down
6 changes: 3 additions & 3 deletions src/controller/ExampleOperationalCredentialsIssuer.h
Original file line number Diff line number Diff line change
Expand Up @@ -55,9 +55,9 @@ class DLL_EXPORT ExampleOperationalCredentialsIssuer : public OperationalCredent
ExampleOperationalCredentialsIssuer(uint32_t index = 0) { mIndex = index; }
~ExampleOperationalCredentialsIssuer() override {}

CHIP_ERROR GenerateNOCChain(const ByteSpan & csrElements, const ByteSpan & attestationSignature, const ByteSpan & DAC,
const ByteSpan & PAI, const ByteSpan & PAA,
Callback::Callback<OnNOCChainGeneration> * onCompletion) override;
CHIP_ERROR GenerateNOCChain(const ByteSpan & csrElements, const ByteSpan & csrNonce, const ByteSpan & attestationSignature,
const ByteSpan & attestationChallenge, const ByteSpan & DAC, const ByteSpan & PAI,
const ByteSpan & PAA, Callback::Callback<OnNOCChainGeneration> * onCompletion) override;

void SetNodeIdForNextNOCRequest(NodeId nodeId) override
{
Expand Down
9 changes: 6 additions & 3 deletions src/controller/OperationalCredentialsDelegate.h
Original file line number Diff line number Diff line change
Expand Up @@ -51,17 +51,20 @@ class DLL_EXPORT OperationalCredentialsDelegate
*
* The delegate will call `onCompletion` when the NOC certificate chain is ready.
*
* @param[in] csrElements CSR elements as per specifications section 11.22.5.6. NOCSR Elements.
* @param[in] csrElements CSR elements as per specifications section 11.18.5.6. NOCSR Elements.
* @param[in] csrNonce CSR nonce as described in 6.4.6.1
* @param[in] attestationSignature Attestation signature as per specifications section 11.22.7.6. CSRResponse Command.
* @param[in] attestationChallenge Attestation challenge as per 11.18.5.7
* @param[in] DAC Device attestation certificate received from the device being commissioned
* @param[in] PAI Product Attestation Intermediate certificate
* @param[in] PAA Product Attestation Authority certificate
* @param[in] onCompletion Callback handler to provide generated NOC chain to the caller of GenerateNOCChain()
*
* @return CHIP_ERROR CHIP_NO_ERROR on success, or corresponding error code.
*/
virtual CHIP_ERROR GenerateNOCChain(const ByteSpan & csrElements, const ByteSpan & attestationSignature, const ByteSpan & DAC,
const ByteSpan & PAI, const ByteSpan & PAA,
virtual CHIP_ERROR GenerateNOCChain(const ByteSpan & csrElements, const ByteSpan & csrNonce,
const ByteSpan & attestationSignature, const ByteSpan & attestationChallenge,
const ByteSpan & DAC, const ByteSpan & PAI, const ByteSpan & PAA,
Callback::Callback<OnNOCChainGeneration> * onCompletion) = 0;

/**
Expand Down
5 changes: 3 additions & 2 deletions src/controller/java/AndroidOperationalCredentialsIssuer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -120,8 +120,9 @@ CHIP_ERROR AndroidOperationalCredentialsIssuer::GenerateNOCChainAfterValidation(
return NewNodeOperationalX509Cert(noc_request, pubkey, mIssuer, noc);
}

CHIP_ERROR AndroidOperationalCredentialsIssuer::GenerateNOCChain(const ByteSpan & csrElements,
const ByteSpan & attestationSignature, const ByteSpan & DAC,
CHIP_ERROR AndroidOperationalCredentialsIssuer::GenerateNOCChain(const ByteSpan & csrElements, const ByteSpan & csrNonce,
const ByteSpan & attestationSignature,
const ByteSpan & attestationChallenge, const ByteSpan & DAC,
const ByteSpan & PAI, const ByteSpan & PAA,
Callback::Callback<OnNOCChainGeneration> * onCompletion)
{
Expand Down
6 changes: 3 additions & 3 deletions src/controller/java/AndroidOperationalCredentialsIssuer.h
Original file line number Diff line number Diff line change
Expand Up @@ -47,9 +47,9 @@ class DLL_EXPORT AndroidOperationalCredentialsIssuer : public OperationalCredent
public:
virtual ~AndroidOperationalCredentialsIssuer() {}

CHIP_ERROR GenerateNOCChain(const ByteSpan & csrElements, const ByteSpan & attestationSignature, const ByteSpan & DAC,
const ByteSpan & PAI, const ByteSpan & PAA,
Callback::Callback<OnNOCChainGeneration> * onCompletion) override;
CHIP_ERROR GenerateNOCChain(const ByteSpan & csrElements, const ByteSpan & csrNonce, const ByteSpan & attestationSignature,
const ByteSpan & attestationChallenge, const ByteSpan & DAC, const ByteSpan & PAI,
const ByteSpan & PAA, Callback::Callback<OnNOCChainGeneration> * onCompletion) override;

void SetNodeIdForNextNOCRequest(NodeId nodeId) override
{
Expand Down
9 changes: 5 additions & 4 deletions src/controller/python/OpCredsBinding.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -78,11 +78,12 @@ class OperationalCredentialsAdapter : public OperationalCredentialsDelegate
}

private:
CHIP_ERROR GenerateNOCChain(const ByteSpan & csrElements, const ByteSpan & attestationSignature, const ByteSpan & DAC,
const ByteSpan & PAI, const ByteSpan & PAA,
Callback::Callback<OnNOCChainGeneration> * onCompletion) override
CHIP_ERROR GenerateNOCChain(const ByteSpan & csrElements, const ByteSpan & csrNonce, const ByteSpan & attestationSignature,
const ByteSpan & attestationChallenge, const ByteSpan & DAC, const ByteSpan & PAI,
const ByteSpan & PAA, Callback::Callback<OnNOCChainGeneration> * onCompletion) override
{
return mExampleOpCredsIssuer.GenerateNOCChain(csrElements, attestationSignature, DAC, PAI, PAA, onCompletion);
return mExampleOpCredsIssuer.GenerateNOCChain(csrElements, csrNonce, attestationSignature, attestationChallenge, DAC, PAI,
PAA, onCompletion);
}

void SetNodeIdForNextNOCRequest(NodeId nodeId) override { mExampleOpCredsIssuer.SetNodeIdForNextNOCRequest(nodeId); }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,9 +46,9 @@ class CHIPOperationalCredentialsDelegate : public chip::Controller::OperationalC
*/
CHIP_ERROR init(CHIPPersistentStorageDelegateBridge * storage, ChipP256KeypairPtr nocSigner, NSData * _Nullable ipk);

CHIP_ERROR GenerateNOCChain(const chip::ByteSpan & csrElements, const chip::ByteSpan & attestationSignature,
const chip::ByteSpan & DAC, const chip::ByteSpan & PAI, const chip::ByteSpan & PAA,
chip::Callback::Callback<chip::Controller::OnNOCChainGeneration> * onCompletion) override;
CHIP_ERROR GenerateNOCChain(const ByteSpan & csrElements, const ByteSpan & csrNonce, const ByteSpan & attestationSignature,
const ByteSpan & attestationChallenge, const ByteSpan & DAC, const ByteSpan & PAI, const ByteSpan & PAA,
Callback::Callback<OnNOCChainGeneration> * onCompletion) override;

void SetNodeIdForNextNOCRequest(chip::NodeId nodeId) override
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -351,9 +351,9 @@ static BOOL isRunningTests(void)
return NewNodeOperationalX509Cert(noc_request, pubkey, *mIssuerKey, noc);
}

CHIP_ERROR CHIPOperationalCredentialsDelegate::GenerateNOCChain(const chip::ByteSpan & csrElements,
const chip::ByteSpan & attestationSignature, const chip::ByteSpan & DAC, const chip::ByteSpan & PAI, const chip::ByteSpan & PAA,
chip::Callback::Callback<chip::Controller::OnNOCChainGeneration> * onCompletion)
CHIP_ERROR CHIPOperationalCredentialsDelegate::GenerateNOCChain(const ByteSpan & csrElements, const ByteSpan & csrNonce,
const ByteSpan & attestationSignature, const ByteSpan & attestationChallenge, const ByteSpan & DAC, const ByteSpan & PAI,
const ByteSpan & PAA, Callback::Callback<OnNOCChainGeneration> * onCompletion)
{
chip::NodeId assignedId;
if (mNodeIdRequested) {
Expand Down