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
55 changes: 44 additions & 11 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, 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 @@ -1066,35 +1086,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 @@ -1809,15 +1824,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 @@ -724,10 +724,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