Skip to content

Commit

Permalink
Validate CSR in separate commissioning step (#16913)
Browse files Browse the repository at this point in the history
* Vaidate CSR as a separate step

* Pass all validataion parameters to GenerateNOCChain

This will let OperationalCredentialsIssuer impls validate the
CSR before generating the NOC chain.

* Restyled by clang-format

* Update src/controller/ExampleOperationalCredentialsIssuer.cpp

Co-authored-by: Boris Zbarsky <bzbarsky@apple.com>

* Remove PAA from GenerateNOCChain command

It's not available.

* More const is better const

No one's messing around with these things, may as well.

* Pass PAI to noc chain generation.

* Remove stale comment

* Bring back namespasing.

I accidentally removed it.

* Once more.

* And again.

I hate myself.

Co-authored-by: Restyled.io <commits@restyled.io>
Co-authored-by: Boris Zbarsky <bzbarsky@apple.com>
  • Loading branch information
3 people authored Apr 4, 2022
1 parent f86c68c commit a208c3d
Show file tree
Hide file tree
Showing 13 changed files with 100 additions and 36 deletions.
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
55 changes: 44 additions & 11 deletions src/controller/CHIPDeviceController.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -969,6 +969,26 @@ CHIP_ERROR DeviceCommissioner::ValidateAttestationInfo(const Credentials::Device
return CHIP_NO_ERROR;
}

CHIP_ERROR DeviceCommissioner::ValidateCSR(DeviceProxy * proxy, const ByteSpan & NOCSRElements,
const ByteSpan & AttestationSignature, const ByteSpan & dac, const 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 @@ -1038,35 +1058,30 @@ void DeviceCommissioner::OnDeviceNOCChainGeneration(void * context, CHIP_ERROR s
}

CHIP_ERROR DeviceCommissioner::ProcessCSR(DeviceProxy * proxy, const ByteSpan & NOCSRElements,
const ByteSpan & AttestationSignature, ByteSpan dac, ByteSpan csrNonce)
const ByteSpan & AttestationSignature, const ByteSpan & dac, const ByteSpan & pai,
const ByteSpan & csrNonce)
{
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");

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.
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, pai, &mDeviceNOCChainCallback);
}

CHIP_ERROR DeviceCommissioner::SendOperationalCertificate(DeviceProxy * device, const ByteSpan & nocCertBuf,
Expand Down Expand Up @@ -1776,15 +1791,33 @@ void DeviceCommissioner::PerformCommissioningStep(DeviceProxy * proxy, Commissio
}
SendOperationalCertificateSigningRequestCommand(proxy, params.GetCSRNonce().Value());
break;
case CommissioningStage::kGenerateNOCChain: {
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.GetPAI().HasValue() ||
!params.GetCSRNonce().HasValue())
{
ChipLogError(Controller, "Unable to generate NOC chain parameters");
return CommissioningStageComplete(CHIP_ERROR_INVALID_ARGUMENT);
}
CHIP_ERROR err = ProcessCSR(proxy, params.GetNOCChainGenerationParameters().Value().nocsrElements,
params.GetNOCChainGenerationParameters().Value().signature, params.GetDAC().Value(),
params.GetCSRNonce().Value());
params.GetPAI().Value(), params.GetCSRNonce().Value());
if (err != CHIP_NO_ERROR)
{
ChipLogError(Controller, "Unable to process Op CSR");
Expand Down
19 changes: 17 additions & 2 deletions src/controller/CHIPDeviceController.h
Original file line number Diff line number Diff line change
Expand Up @@ -680,10 +680,25 @@ class DLL_EXPORT DeviceCommissioner : public DeviceController,
* @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] pai Product Attestation Intermediate certificate
* @param[in] csrNonce certificate signing request nonce
*/
CHIP_ERROR ProcessCSR(DeviceProxy * proxy, const ByteSpan & NOCSRElements, const ByteSpan & AttestationSignature, ByteSpan dac,
ByteSpan csrNonce);
CHIP_ERROR ProcessCSR(DeviceProxy * proxy, const ByteSpan & NOCSRElements, const ByteSpan & AttestationSignature,
const ByteSpan & dac, const ByteSpan & pai, const 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,
const ByteSpan & dac, const ByteSpan & csrNonce);

/**
* @brief
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
11 changes: 8 additions & 3 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,
const ByteSpan & PAI, const ByteSpan & PAA,
CHIP_ERROR ExampleOperationalCredentialsIssuer::GenerateNOCChain(const ByteSpan & csrElements, const ByteSpan & csrNonce,
const ByteSpan & attestationSignature,
const ByteSpan & attestationChallenge, const ByteSpan & DAC,
const ByteSpan & PAI,
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
4 changes: 2 additions & 2 deletions src/controller/ExampleOperationalCredentialsIssuer.h
Original file line number Diff line number Diff line change
Expand Up @@ -55,8 +55,8 @@ 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,
CHIP_ERROR GenerateNOCChain(const ByteSpan & csrElements, const ByteSpan & csrNonce, const ByteSpan & attestationSignature,
const ByteSpan & attestationChallenge, const ByteSpan & DAC, const ByteSpan & PAI,
Callback::Callback<OnNOCChainGeneration> * onCompletion) override;

void SetNodeIdForNextNOCRequest(NodeId nodeId) override
Expand Down
10 changes: 6 additions & 4 deletions src/controller/OperationalCredentialsDelegate.h
Original file line number Diff line number Diff line change
Expand Up @@ -51,17 +51,19 @@ 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,
Callback::Callback<OnNOCChainGeneration> * onCompletion) = 0;

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

CHIP_ERROR AndroidOperationalCredentialsIssuer::GenerateNOCChain(const ByteSpan & csrElements,
const ByteSpan & attestationSignature, const ByteSpan & DAC,
const ByteSpan & PAI, const ByteSpan & PAA,
CHIP_ERROR AndroidOperationalCredentialsIssuer::GenerateNOCChain(const ByteSpan & csrElements, const ByteSpan & csrNonce,
const ByteSpan & attestationSignature,
const ByteSpan & attestationChallenge, const ByteSpan & DAC,
const ByteSpan & PAI,
Callback::Callback<OnNOCChainGeneration> * onCompletion)
{
jmethodID method;
Expand Down
4 changes: 2 additions & 2 deletions src/controller/java/AndroidOperationalCredentialsIssuer.h
Original file line number Diff line number Diff line change
Expand Up @@ -47,8 +47,8 @@ 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,
CHIP_ERROR GenerateNOCChain(const ByteSpan & csrElements, const ByteSpan & csrNonce, const ByteSpan & attestationSignature,
const ByteSpan & attestationChallenge, const ByteSpan & DAC, const ByteSpan & PAI,
Callback::Callback<OnNOCChainGeneration> * onCompletion) override;

void SetNodeIdForNextNOCRequest(NodeId nodeId) override
Expand Down
7 changes: 4 additions & 3 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,
CHIP_ERROR GenerateNOCChain(const ByteSpan & csrElements, const ByteSpan & csrNonce, const ByteSpan & attestationSignature,
const ByteSpan & attestationChallenge, const ByteSpan & DAC, const ByteSpan & PAI,
Callback::Callback<OnNOCChainGeneration> * onCompletion) override
{
return mExampleOpCredsIssuer.GenerateNOCChain(csrElements, attestationSignature, DAC, PAI, PAA, onCompletion);
return mExampleOpCredsIssuer.GenerateNOCChain(csrElements, csrNonce, attestationSignature, attestationChallenge, DAC, PAI,
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 chip::ByteSpan & csrElements, const chip::ByteSpan & csrNonce,
const chip::ByteSpan & attestationSignature, const chip::ByteSpan & attestationChallenge, const chip::ByteSpan & DAC,
const chip::ByteSpan & PAI, chip::Callback::Callback<chip::Controller::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 chip::ByteSpan & csrElements, const chip::ByteSpan & csrNonce,
const chip::ByteSpan & attestationSignature, const chip::ByteSpan & attestationChallenge, const chip::ByteSpan & DAC,
const chip::ByteSpan & PAI, chip::Callback::Callback<chip::Controller::OnNOCChainGeneration> * onCompletion)
{
chip::NodeId assignedId;
if (mNodeIdRequested) {
Expand Down

0 comments on commit a208c3d

Please sign in to comment.