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

Allow partial validation of DAC and CD (for external cloud or custom app based validation) #21725

Merged
merged 9 commits into from
Aug 16, 2022
6 changes: 1 addition & 5 deletions src/controller/java/AndroidDeviceControllerWrapper.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -127,11 +127,6 @@ AndroidDeviceControllerWrapper * AndroidDeviceControllerWrapper::AllocateNew(

chip::Controller::AndroidOperationalCredentialsIssuer * opCredsIssuer = wrapper->mOpCredsIssuer.get();

// Initialize device attestation verifier
// TODO: Replace testingRootStore with a AttestationTrustStore that has the necessary official PAA roots available
const chip::Credentials::AttestationTrustStore * testingRootStore = chip::Credentials::GetTestAttestationTrustStore();
SetDeviceAttestationVerifier(GetDefaultDACVerifier(testingRootStore));

chip::Controller::FactoryInitParams initParams;
chip::Controller::SetupParams setupParams;

Expand All @@ -148,6 +143,7 @@ AndroidDeviceControllerWrapper * AndroidDeviceControllerWrapper::AllocateNew(
setupParams.pairingDelegate = wrapper.get();
setupParams.operationalCredentialsDelegate = opCredsIssuer;
setupParams.defaultCommissioner = &wrapper->mAutoCommissioner;
setupParams.deviceAttestationVerifier = &wrapper->mDACVerifier;
initParams.fabricIndependentStorage = wrapperStorage;

wrapper->mGroupDataProvider.SetStorageDelegate(wrapperStorage);
Expand Down
6 changes: 6 additions & 0 deletions src/controller/java/AndroidDeviceControllerWrapper.h
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
#include <controller/CHIPDeviceController.h>
#include <credentials/GroupDataProviderImpl.h>
#include <credentials/PersistentStorageOpCertStore.h>
#include <credentials/attestation_verifier/DefaultDeviceAttestationVerifier.h>
#include <lib/support/TimeUtils.h>
#include <platform/android/CHIPP256KeypairBridge.h>
#include <platform/internal/DeviceNetworkInfo.h>
Expand Down Expand Up @@ -94,6 +95,8 @@ class AndroidDeviceControllerWrapper : public chip::Controller::DevicePairingDel

chip::Controller::AutoCommissioner * GetAutoCommissioner() { return &mAutoCommissioner; }

chip::Credentials::DefaultDACVerifier * GetDACVerifier() { return &mDACVerifier; }

const chip::Controller::CommissioningParameters & GetCommissioningParameters() const
{
return mAutoCommissioner.GetCommissioningParameters();
Expand Down Expand Up @@ -175,6 +178,9 @@ class AndroidDeviceControllerWrapper : public chip::Controller::DevicePairingDel

chip::Controller::AutoCommissioner mAutoCommissioner;

// TODO: Replace testingRootStore with a AttestationTrustStore that has the necessary official PAA roots available
chip::Credentials::DefaultDACVerifier mDACVerifier{ chip::Credentials::GetTestAttestationTrustStore() };

AndroidDeviceControllerWrapper(ChipDeviceControllerPtr controller, AndroidOperationalCredentialsIssuerPtr opCredsIssuer) :
mController(std::move(controller)), mOpCredsIssuer(std::move(opCredsIssuer))
{}
Expand Down
14 changes: 10 additions & 4 deletions src/controller/java/AndroidOperationalCredentialsIssuer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -151,7 +151,7 @@ CHIP_ERROR AndroidOperationalCredentialsIssuer::GenerateNOCChain(const ByteSpan
}

CHIP_ERROR AndroidOperationalCredentialsIssuer::CallbackGenerateNOCChain(const ByteSpan & csrElements, const ByteSpan & csrNonce,
const ByteSpan & csrSignature,
const ByteSpan & csrElementsSignature,
const ByteSpan & attestationChallenge,
const ByteSpan & DAC, const ByteSpan & PAI,
Callback::Callback<OnNOCChainGeneration> * onCompletion)
Expand All @@ -177,8 +177,9 @@ CHIP_ERROR AndroidOperationalCredentialsIssuer::CallbackGenerateNOCChain(const B
jbyteArray javaCsrNonce;
JniReferences::GetInstance().N2J_ByteArray(env, csrNonce.data(), csrNonce.size(), javaCsrNonce);

jbyteArray javaCsrSignature;
JniReferences::GetInstance().N2J_ByteArray(env, csrSignature.data(), csrSignature.size(), javaCsrSignature);
jbyteArray javaCsrElementsSignature;
JniReferences::GetInstance().N2J_ByteArray(env, csrElementsSignature.data(), csrElementsSignature.size(),
javaCsrElementsSignature);

ChipLogProgress(Controller, "Parsing Certificate Signing Request");
TLVReader reader;
Expand All @@ -202,8 +203,13 @@ CHIP_ERROR AndroidOperationalCredentialsIssuer::CallbackGenerateNOCChain(const B
jbyteArray javaCsr;
JniReferences::GetInstance().N2J_ByteArray(env, csr.data(), csr.size(), javaCsr);

P256PublicKey pubkey;
ReturnErrorOnFailure(VerifyCertificateSigningRequest(csr.data(), csr.size(), pubkey));
// TODO: verify signed by DAC creds?
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this TODO intended to remain?

ChipLogProgress(chipTool, "VerifyCertificateSigningRequest");

jobject csrInfo;
err = N2J_CSRInfo(env, javaCsrNonce, javaCsrElements, javaCsrSignature, javaCsr, csrInfo);
err = N2J_CSRInfo(env, javaCsrNonce, javaCsrElements, javaCsrElementsSignature, javaCsr, csrInfo);
if (err != CHIP_NO_ERROR)
{
ChipLogError(Controller, "Failed to create CSRInfo");
Expand Down
6 changes: 6 additions & 0 deletions src/controller/java/CHIPDeviceController-JNI.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -541,6 +541,12 @@ JNI_METHOD(void, setUseJavaCallbackForNOCRequest)
AndroidDeviceControllerWrapper * wrapper = AndroidDeviceControllerWrapper::FromJNIHandle(handle);

wrapper->GetAndroidOperationalCredentialsIssuer()->SetUseJavaCallbackForNOCRequest(useCallback);

// disable the local PAA Root store since we will be performing validation in the callback
wrapper->GetDACVerifier()->SetUseLocalPAARootStore(!useCallback);

// disable the local CSA store since we will be performing validation in the callback
wrapper->GetDACVerifier()->SetUseLocalCSAStore(!useCallback);
}

JNI_METHOD(void, updateCommissioningNetworkCredentials)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -158,6 +158,11 @@ void DefaultDACVerifier::VerifyAttestationInformation(const DeviceAttestationVer
AttestationCertVidPid paiVidPid;
AttestationCertVidPid paaVidPid;

DeviceInfoForAttestation deviceInfo{
.vendorId = info.vendorId,
.productId = info.productId,
};

VerifyOrExit(!info.attestationElementsBuffer.empty() && !info.attestationChallengeBuffer.empty() &&
!info.attestationSignatureBuffer.empty() && !info.paiDerBuffer.empty() && !info.dacDerBuffer.empty() &&
!info.attestationNonceBuffer.empty() && onCompletion != nullptr,
Expand Down Expand Up @@ -200,29 +205,36 @@ void DefaultDACVerifier::VerifyAttestationInformation(const DeviceAttestationVer
}

{
uint8_t akidBuf[Crypto::kAuthorityKeyIdentifierLength];
MutableByteSpan akid(akidBuf);
MutableByteSpan akid(deviceInfo.paaSKID);
constexpr size_t paaCertAllocatedLen = kMaxDERCertLength;

VerifyOrExit(ExtractAKIDFromX509Cert(info.paiDerBuffer, akid) == CHIP_NO_ERROR,
attestationError = AttestationVerificationResult::kPaiFormatInvalid);

VerifyOrExit(paaCert.Alloc(paaCertAllocatedLen), attestationError = AttestationVerificationResult::kNoMemory);

paaDerBuffer = MutableByteSpan(paaCert.Get(), paaCertAllocatedLen);
VerifyOrExit(mAttestationTrustStore->GetProductAttestationAuthorityCert(akid, paaDerBuffer) == CHIP_NO_ERROR,
attestationError = AttestationVerificationResult::kPaaNotFound);
if (mUseLocalPAARootStore)
{
paaDerBuffer = MutableByteSpan(paaCert.Get(), paaCertAllocatedLen);
VerifyOrExit(mAttestationTrustStore->GetProductAttestationAuthorityCert(akid, paaDerBuffer) == CHIP_NO_ERROR,
attestationError = AttestationVerificationResult::kPaaNotFound);

VerifyOrExit(ExtractVIDPIDFromX509Cert(paaDerBuffer, paaVidPid) == CHIP_NO_ERROR,
attestationError = AttestationVerificationResult::kPaaFormatInvalid);

VerifyOrExit(ExtractVIDPIDFromX509Cert(paaDerBuffer, paaVidPid) == CHIP_NO_ERROR,
attestationError = AttestationVerificationResult::kPaaFormatInvalid);
if (paaVidPid.mVendorId.HasValue())
{
VerifyOrExit(paaVidPid.mVendorId == paiVidPid.mVendorId,
attestationError = AttestationVerificationResult::kPaiVendorIdMismatch);
}

if (paaVidPid.mVendorId.HasValue())
VerifyOrExit(!paaVidPid.mProductId.HasValue(), attestationError = AttestationVerificationResult::kPaaFormatInvalid);
}
else
{
VerifyOrExit(paaVidPid.mVendorId == paiVidPid.mVendorId,
attestationError = AttestationVerificationResult::kPaiVendorIdMismatch);
ChipLogProgress(
Support, "DefaultDACVerifier::VerifyAttestationInformation skipping vid-scoped PAA check - PAARootStore disabled");
}

VerifyOrExit(!paaVidPid.mProductId.HasValue(), attestationError = AttestationVerificationResult::kPaaFormatInvalid);
}

#if !defined(CURRENT_TIME_NOT_IMPLEMENTED)
Expand All @@ -237,11 +249,19 @@ void DefaultDACVerifier::VerifyAttestationInformation(const DeviceAttestationVer
attestationError = AttestationVerificationResult::kPaaExpired);

CertificateChainValidationResult chainValidationResult;
VerifyOrExit(ValidateCertificateChain(paaDerBuffer.data(), paaDerBuffer.size(), info.paiDerBuffer.data(),
info.paiDerBuffer.size(), info.dacDerBuffer.data(), info.dacDerBuffer.size(),
chainValidationResult) == CHIP_NO_ERROR,
attestationError = MapError(chainValidationResult));
if (mUseLocalPAARootStore)
{

VerifyOrExit(ValidateCertificateChain(paaDerBuffer.data(), paaDerBuffer.size(), info.paiDerBuffer.data(),
info.paiDerBuffer.size(), info.dacDerBuffer.data(), info.dacDerBuffer.size(),
chainValidationResult) == CHIP_NO_ERROR,
attestationError = MapError(chainValidationResult));
}
else
{
ChipLogProgress(Support,
"DefaultDACVerifier::VerifyAttestationInformation skipping cert chain validation - PAARootStore disabled");
}
{
ByteSpan certificationDeclarationSpan;
ByteSpan attestationNonceSpan;
Expand All @@ -250,21 +270,26 @@ void DefaultDACVerifier::VerifyAttestationInformation(const DeviceAttestationVer
DeviceAttestationVendorReservedDeconstructor vendorReserved;
ByteSpan certificationDeclarationPayload;

DeviceInfoForAttestation deviceInfo{
.vendorId = info.vendorId,
.productId = info.productId,
.dacVendorId = dacVidPid.mVendorId.Value(),
.dacProductId = dacVidPid.mProductId.Value(),
.paiVendorId = paiVidPid.mVendorId.Value(),
.paiProductId = paiVidPid.mProductId.ValueOr(0),
.paaVendorId = paaVidPid.mVendorId.ValueOr(VendorId::NotSpecified),
};
deviceInfo.dacVendorId = dacVidPid.mVendorId.Value();
deviceInfo.dacProductId = dacVidPid.mProductId.Value();
deviceInfo.paiVendorId = paiVidPid.mVendorId.Value();
deviceInfo.paiProductId = paiVidPid.mProductId.ValueOr(0);
deviceInfo.paaVendorId = paaVidPid.mVendorId.ValueOr(VendorId::NotSpecified);

MutableByteSpan paaSKID(deviceInfo.paaSKID);
VerifyOrExit(ExtractSKIDFromX509Cert(paaDerBuffer, paaSKID) == CHIP_NO_ERROR,
attestationError = AttestationVerificationResult::kPaaFormatInvalid);
VerifyOrExit(paaSKID.size() == sizeof(deviceInfo.paaSKID),
attestationError = AttestationVerificationResult::kPaaFormatInvalid);
if (mUseLocalPAARootStore)
{
MutableByteSpan paaSKID(deviceInfo.paaSKID);
VerifyOrExit(ExtractSKIDFromX509Cert(paaDerBuffer, paaSKID) == CHIP_NO_ERROR,
attestationError = AttestationVerificationResult::kPaaFormatInvalid);
VerifyOrExit(paaSKID.size() == sizeof(deviceInfo.paaSKID),
attestationError = AttestationVerificationResult::kPaaFormatInvalid);
}
else
{
ChipLogProgress(
Support,
"DefaultDACVerifier::VerifyAttestationInformation skipping PAA subject key id extraction - PAARootStore disabled");
}

VerifyOrExit(DeconstructAttestationElements(info.attestationElementsBuffer, certificationDeclarationSpan,
attestationNonceSpan, timestampDeconstructed, firmwareInfoSpan,
Expand All @@ -275,8 +300,19 @@ void DefaultDACVerifier::VerifyAttestationInformation(const DeviceAttestationVer
VerifyOrExit(attestationNonceSpan.data_equal(info.attestationNonceBuffer),
attestationError = AttestationVerificationResult::kAttestationNonceMismatch);

attestationError = ValidateCertificationDeclarationSignature(certificationDeclarationSpan, certificationDeclarationPayload);
VerifyOrExit(attestationError == AttestationVerificationResult::kSuccess, attestationError = attestationError);
if (mUseLocalCSAStore)
{
attestationError =
ValidateCertificationDeclarationSignature(certificationDeclarationSpan, certificationDeclarationPayload);
VerifyOrExit(attestationError == AttestationVerificationResult::kSuccess, attestationError = attestationError);
}
else
{
ChipLogProgress(
Support, "DefaultDACVerifier::VerifyAttestationInformation skipping CD signature check - LocalCSAStore disabled");
VerifyOrExit(CMS_ExtractCDContent(certificationDeclarationSpan, certificationDeclarationPayload) == CHIP_NO_ERROR,
attestationError = AttestationVerificationResult::kPaaFormatInvalid);
}

attestationError = ValidateCertificateDeclarationPayload(certificationDeclarationPayload, firmwareInfoSpan, deviceInfo);
VerifyOrExit(attestationError == AttestationVerificationResult::kSuccess, attestationError = attestationError);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,10 +41,18 @@ class DefaultDACVerifier : public DeviceAttestationVerifier
const ByteSpan & attestationSignatureBuffer,
const Crypto::P256PublicKey & dacPublicKey, const ByteSpan & csrNonce) override;

protected:
bool GetUseLocalPAARootStore() { return mUseLocalPAARootStore; }
void SetUseLocalPAARootStore(bool useLocalPAARootStore) { mUseLocalPAARootStore = useLocalPAARootStore; }

bool GetUseLocalCSAStore() { return mUseLocalCSAStore; }
void SetUseLocalCSAStore(bool useLocalCSAStore) { mUseLocalCSAStore = useLocalCSAStore; }

DefaultDACVerifier() {}

protected:
const AttestationTrustStore * mAttestationTrustStore;
bool mUseLocalPAARootStore = true;
bool mUseLocalCSAStore = true;
};

/**
Expand Down