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

[Platform] Implement a DeviceAttestationVerifier in Java to allow user to overwrite the DefaultDACVerifier #24297

Closed
yufengwangca opened this issue Jan 6, 2023 · 4 comments · Fixed by #25471
Assignees
Labels
java Issues in java-matter-controller

Comments

@yufengwangca
Copy link
Contributor

Reproduction steps

Per @tcarmelveilleux

See AndroidDeviceControllerWrapper::AllocateNew in src/controller/java/AndroidDeviceControllerWrapper.cpp:

    // 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));

The Device Attestation Verifier is what could be bridged to Java.

Overall, the flow could be something like:

image

@startuml

participant "Client" as client 
participant "AndroidChipDeviceController" as wrapper
' from AndroidDeviceControllerWrapper
participant "C++ ChipDeviceController" as DevCtrl
' owned by ChipDeviceController
participant "DeviceCommissioner" as Commissioner
' owned by ChipDeviceController
participant "AutoCommissioner" as AutoCommissioner
' Make your custom one
participant "CustomDeviceAttestationVerifier" as Verifier
participant "DCL Client" as DCL

client -> wrapper: <<new ChipDeviceController>>
client <- wrapper: devCtrl
' The following is new
client -> wrapper: SetDeviceAttestationVerifier\n(CustomDeviceAttestationVerifier)
activate wrapper
client -> wrapper: CommissionDevice(...)
wrapper -> DevCtrl: Commission(...)
DevCtrl -> Commissioner: Commission(...)
Commissioner -> AutoCommissioner: StartCommissioning(...)

... some operations pass ...

AutoCommissioner -> Verifier: VerifyAttestationInformation(..., Callback)
Verifier -> DCL: FetchPAA(PAI.authority, PaaFetchedCallback)
Verifier <-- DCL: PaaFetchedCallback(PAA Cert)
Verifier -> Verifier: Bridge to DefaultDeviceAttestationVerifier impl
Note left of Verifier: An ephemeral truststore can be provided\nto DefaultDeviceAttestationVerifier\nthat now has PAA
Note left of Verifier: DefaultDeviceAttestationVerifier does not\nneed to be used, could be custom Java version
AutoCommissioner <-- Verifier: Callback(result)

... more operations pass ...
Commissioner <-- AutoCommissioner: CommissioningStepFinished(kAttestationVerification)
deactivate wrapper

@enduml

The general concept:

  1. It should be possible to implement a DeviceAttestationVerifier in Java fully
  2. That DeviceAttestationVerifier would then NOT need a truststore directly, unless it called into the C++ DefaultDeviceAttestationVerifier with JNI bridging. This should be optional
  3. If we abstract at DeviceAttestationVerifier call, then there is already async implementation from DeviceCommissioner to AutoCommissioner to DeviceAttestationVerifier. You can then take a while to obtain PAA from DCL if needed
  4. We have to make sure not to break existing public API, only make it better. Right now, most Java clients just use the default Device Attestation Verifier and likely know what PAAs they want to trust (e.g. their own). If you are a fully general commissioner, you always need more customization anyway. That is why I was suggesting also bridging the attestation trust store.

Regarding the CD trust store, there is already a set of Well-known keys. The CdWellKnownKeysTrustStore used by default should be good enough for a while.

Overall, I agree that these Java APIs are cumbersome. However, unless someone is willing to help rewrite them to "flow-through" with a frameworked design that works for everyone, we have to keep going incrementally.

Platform

android

Platform Version(s)

No response

Type

Manually tested with SDK

(Optional) If manually tested please explain why this is only manually tested

No response

Anything else?

No response

@panliming-tuya
Copy link
Contributor

panliming-tuya commented Jan 17, 2023

I have refined the process design, we can see if it's ok. @yufengwangca @tennessee-google

DeviceAttestationDelegate.png

@startuml

participant "DCL Client" as DCL
participant "java DeviceAttestationVerifierDelegate" as javaVerifier 
participant "java ChipDeviceController" as client 
participant "ChipDeviceController-JNI" as jni 
participant "C++ AndroidDeviceAttestationVerifier" as Verifier
participant "AndroidChipDeviceController" as wrapper
' from AndroidDeviceControllerWrapper
participant "C++ ChipDeviceController" as DevCtrl
' owned by ChipDeviceController
participant "DeviceCommissioner" as Commissioner
' owned by ChipDeviceController
participant "AutoCommissioner" as AutoCommissioner
' Make your custom one


activate jni
activate DevCtrl
client -> jni: SetDeviceAttestationVerifierDelegate\n(DeviceAttestationVerifierDelegate)
activate wrapper
jni -> wrapper: SetDeviceAttestationVerifier\n(AndroidDeviceAttestationVerifier)
client -> jni: commissionDevice(...)
jni -> wrapper: CommissionDevice(...)
deactivate jni
wrapper -> DevCtrl: Commission(...)
DevCtrl -> Commissioner: Commission(...)
activate Commissioner
Commissioner -> AutoCommissioner: StartCommissioning(...)

... some operations pass ...


AutoCommissioner -> Verifier: VerifyAttestationInformation(..., Callback)
activate Verifier
Verifier -> javaVerifier: FetchPAA(SKID, PaaFetchedCallback)
activate javaVerifier
javaVerifier -> DCL: Fetch PAA cert
DCL --> javaVerifier: Response PAA cert
Verifier <-- javaVerifier: PaaFetchedCallback(PAA Cert)
deactivate javaVerifier
Verifier -> Verifier: Validate certificate chain and CD
AutoCommissioner <-- Verifier: Callback(result)
deactivate Verifier

... more operations pass ...
Commissioner <-- AutoCommissioner: CommissioningStepFinished(kAttestationVerification)
deactivate wrapper

@enduml

Interface Design Description

ChipDeviceController.java add a new method

void setDeviceAttestationVerifierDelegate(DeviceAttestationVerifierDelegate deviceAttestationVerifierDelegate);

DeviceAttestationVerifierDelegate.java

public interface DeviceAttestationVerifierDelegate {
    /**
     * Fetch product attestation authority cert from DCL.
     *
     * @param skid               Subject key identifier (SKID)
     * @param paaFetchedCallback
     */
    void fetchProductAttestationAuthorityCert(byte[] skid, PaaFetchedCallback paaFetchedCallback);
}

PaaFetchedCallback.java

public interface PaaFetchedCallback {
    void onComplete(@Nullable byte[] paaCert);
}

AndroidDeviceAttestationVerifier.h

class AndroidDeviceAttestationVerifier : public chip::Credentials::DeviceAttestationVerifier
{
public:
    AndroidDeviceAttestationVerifier(jobject deviceAttestationVerifierDelegate) :
        mDeviceAttestationVerifierDelegate(deviceAttestationVerifierDelegate)
    {}
    ~AndroidDeviceAttestationVerifier();

    void VerifyAttestationInformation(const DeviceAttestationVerifier::AttestationInfo & info,
                                          Callback::Callback<OnAttestationInformationVerification> * onCompletion) override;

protected:
    jobject mDeviceAttestationVerifierDelegate = nullptr;
};

AndroidDeviceAttestationVerifier.cpp pseudocode

void AndroidDeviceAttestationVerifier::VerifyAttestationInformation(const DeviceAttestationVerifier::AttestationInfo & info,
                                                      Callback::Callback<OnAttestationInformationVerification> * onCompletion)
{
  // Fetch PAA Cert
  MutableByteSpan paaDerBuffer;
  FetchPaaCert(mDeviceAttestationVerifierDelegate, paaDerBuffer);
  
  // Add PAA cert to truststore
  EphemeralAttestationTrustStore attestationTrustStore(paaDerBuffer);
  
  // Verify attestation information by DefaultDACVerifier
  DefaultDACVerifier defaultDACVerifier(attestationTrustStore);
  defaultDACVerifier.VerifyAttestationInformation(info, onCompletion);
}

For external callers, DeviceAttestationVerifierDelegate and #24381 are mutually exclusive, only one of them needs to be implemented.

@yufengwangca
Copy link
Contributor Author

@panliming-tuya in your refined workflow, is the AndroidDeviceAttestationVerifier new C++ class talk to PaaFetcherDelegate?Why this new flow is better than the one Tennessee proposed? I think both flows do the similar job, allow the client to fetch the PAA from DCL on the fly during attestation process.

@panliming-tuya
Copy link
Contributor

@panliming-tuya in your refined workflow, is the AndroidDeviceAttestationVerifier new C++ class talk to PaaFetcherDelegate?Why this new flow is better than the one Tennessee proposed? I think both flows do the similar job, allow the client to fetch the PAA from DCL on the fly during attestation process.

@yufengwangca It has been modified and the interface design has been added

@luobosu
Copy link

luobosu commented Mar 10, 2023

how about provide a path which store the PAA files from java-layer to native-layer .
then we can new a FileAttestationTrustStore.cpp with the paa path.
then set the FileAttestationTrustStore into the DefaultDevieAttestationVerifier

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
java Issues in java-matter-controller
Projects
Archived in project
Development

Successfully merging a pull request may close this issue.

4 participants