From d773528a10aa92d5ffb2c1288900f48fb17308d2 Mon Sep 17 00:00:00 2001 From: Yufeng Wang Date: Tue, 7 Mar 2023 07:57:10 -0800 Subject: [PATCH] [Java] Implement the trust store delegate API for customized device attestation (#25471) * [Java]Implement truststore delegate API * Address the review comments --- .../com/google/chip/chiptool/ChipClient.kt | 7 ++ .../ExampleAttestationTrustStoreDelegate.kt | 43 +++++++ .../java/AndroidDeviceControllerWrapper.cpp | 73 +++++++++++- .../java/AndroidDeviceControllerWrapper.h | 22 ++-- .../java/AttestationTrustStoreBridge.cpp | 93 +++++++++++++++ .../java/AttestationTrustStoreBridge.h | 36 ++++++ src/controller/java/BUILD.gn | 3 + .../java/CHIPDeviceController-JNI.cpp | 108 ++++++++++++------ .../AttestationTrustStoreDelegate.java | 25 ++++ .../ChipDeviceController.java | 24 ++++ 10 files changed, 385 insertions(+), 49 deletions(-) create mode 100644 examples/android/CHIPTool/app/src/main/java/com/google/chip/chiptool/attestation/ExampleAttestationTrustStoreDelegate.kt create mode 100644 src/controller/java/AttestationTrustStoreBridge.cpp create mode 100644 src/controller/java/AttestationTrustStoreBridge.h create mode 100644 src/controller/java/src/chip/devicecontroller/AttestationTrustStoreDelegate.java diff --git a/examples/android/CHIPTool/app/src/main/java/com/google/chip/chiptool/ChipClient.kt b/examples/android/CHIPTool/app/src/main/java/com/google/chip/chiptool/ChipClient.kt index 6e3833820716a3..3d130f835de459 100644 --- a/examples/android/CHIPTool/app/src/main/java/com/google/chip/chiptool/ChipClient.kt +++ b/examples/android/CHIPTool/app/src/main/java/com/google/chip/chiptool/ChipClient.kt @@ -30,6 +30,7 @@ import chip.platform.NsdManagerServiceBrowser import chip.platform.NsdManagerServiceResolver import chip.platform.PreferencesConfigurationManager import chip.platform.PreferencesKeyValueStoreManager +import com.google.chip.chiptool.attestation.ExampleAttestationTrustStoreDelegate import kotlin.coroutines.resume import kotlin.coroutines.resumeWithException import kotlin.coroutines.suspendCoroutine @@ -47,7 +48,12 @@ object ChipClient { if (!this::chipDeviceController.isInitialized) { chipDeviceController = ChipDeviceController(ControllerParams.newBuilder().setControllerVendorId(VENDOR_ID).build()) + + // Set delegate for attestation trust store for device attestation verifier. + // It will replace the default attestation trust store. + chipDeviceController.setAttestationTrustStoreDelegate(ExampleAttestationTrustStoreDelegate(chipDeviceController)) } + return chipDeviceController } @@ -57,6 +63,7 @@ object ChipClient { ChipDeviceController.loadJni() androidPlatform = AndroidChipPlatform(AndroidBleManager(), PreferencesKeyValueStoreManager(context), PreferencesConfigurationManager(context), NsdManagerServiceResolver(context), NsdManagerServiceBrowser(context), ChipMdnsCallbackImpl(), DiagnosticDataProviderImpl(context)) } + return androidPlatform } diff --git a/examples/android/CHIPTool/app/src/main/java/com/google/chip/chiptool/attestation/ExampleAttestationTrustStoreDelegate.kt b/examples/android/CHIPTool/app/src/main/java/com/google/chip/chiptool/attestation/ExampleAttestationTrustStoreDelegate.kt new file mode 100644 index 00000000000000..4e723faeffecd3 --- /dev/null +++ b/examples/android/CHIPTool/app/src/main/java/com/google/chip/chiptool/attestation/ExampleAttestationTrustStoreDelegate.kt @@ -0,0 +1,43 @@ +package com.google.chip.chiptool.attestation + +import android.util.Base64 +import chip.devicecontroller.AttestationTrustStoreDelegate +import chip.devicecontroller.ChipDeviceController +import java.util.* + +class ExampleAttestationTrustStoreDelegate(val chipDeviceController: ChipDeviceController) : + AttestationTrustStoreDelegate { + + private val paaCerts = arrayListOf(TEST_PAA_FFF1_Cert, TEST_PAA_NOVID_CERT) + + override fun getProductAttestationAuthorityCert(skid: ByteArray): ByteArray? { + return paaCerts + .map { Base64.decode(it, Base64.DEFAULT) } + .firstOrNull { cert -> chipDeviceController.extractSkidFromPaaCert(cert) == skid } + } + + companion object { + const val TEST_PAA_FFF1_Cert = + "MIIBvTCCAWSgAwIBAgIITqjoMYLUHBwwCgYIKoZIzj0EAwIwMDEYMBYGA1UEAwwP\n" + + "TWF0dGVyIFRlc3QgUEFBMRQwEgYKKwYBBAGConwCAQwERkZGMTAgFw0yMTA2Mjgx\n" + + "NDIzNDNaGA85OTk5MTIzMTIzNTk1OVowMDEYMBYGA1UEAwwPTWF0dGVyIFRlc3Qg\n" + + "UEFBMRQwEgYKKwYBBAGConwCAQwERkZGMTBZMBMGByqGSM49AgEGCCqGSM49AwEH\n" + + "A0IABLbLY3KIfyko9brIGqnZOuJDHK2p154kL2UXfvnO2TKijs0Duq9qj8oYShpQ\n" + + "NUKWDUU/MD8fGUIddR6Pjxqam3WjZjBkMBIGA1UdEwEB/wQIMAYBAf8CAQEwDgYD\n" + + "VR0PAQH/BAQDAgEGMB0GA1UdDgQWBBRq/SJ3H1Ef7L8WQZdnENzcMaFxfjAfBgNV\n" + + "HSMEGDAWgBRq/SJ3H1Ef7L8WQZdnENzcMaFxfjAKBggqhkjOPQQDAgNHADBEAiBQ\n" + + "qoAC9NkyqaAFOPZTaK0P/8jvu8m+t9pWmDXPmqdRDgIgI7rI/g8j51RFtlM5CBpH\n" + + "mUkpxyqvChVI1A0DTVFLJd4=" + + const val TEST_PAA_NOVID_CERT = + "MIIBkTCCATegAwIBAgIHC4+6qN2G7jAKBggqhkjOPQQDAjAaMRgwFgYDVQQDDA9N\n" + + "YXR0ZXIgVGVzdCBQQUEwIBcNMjEwNjI4MTQyMzQzWhgPOTk5OTEyMzEyMzU5NTla\n" + + "MBoxGDAWBgNVBAMMD01hdHRlciBUZXN0IFBBQTBZMBMGByqGSM49AgEGCCqGSM49\n" + + "AwEHA0IABBDvAqgah7aBIfuo0xl4+AejF+UKqKgoRGgokUuTPejt1KXDnJ/3Gkzj\n" + + "ZH/X9iZTt9JJX8ukwPR/h2iAA54HIEqjZjBkMBIGA1UdEwEB/wQIMAYBAf8CAQEw\n" + + "DgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBR4XOcFuGuPTm/Hk6pgy0PqaWiC1TAf\n" + + "BgNVHSMEGDAWgBR4XOcFuGuPTm/Hk6pgy0PqaWiC1TAKBggqhkjOPQQDAgNIADBF\n" + + "AiEAue/bPqBqUuwL8B5h2u0sLRVt22zwFBAdq3mPrAX6R+UCIGAGHT411g2dSw1E\n" + + "ja12EvfoXFguP8MS3Bh5TdNzcV5d" + } +} diff --git a/src/controller/java/AndroidDeviceControllerWrapper.cpp b/src/controller/java/AndroidDeviceControllerWrapper.cpp index b9fe506bb2d617..d6fadc7926c19b 100644 --- a/src/controller/java/AndroidDeviceControllerWrapper.cpp +++ b/src/controller/java/AndroidDeviceControllerWrapper.cpp @@ -67,6 +67,18 @@ AndroidDeviceControllerWrapper::~AndroidDeviceControllerWrapper() delete mDeviceAttestationDelegateBridge; mDeviceAttestationDelegateBridge = nullptr; } + + if (mDeviceAttestationVerifier != nullptr) + { + delete mDeviceAttestationVerifier; + mDeviceAttestationVerifier = nullptr; + } + + if (mAttestationTrustStoreBridge != nullptr) + { + delete mAttestationTrustStoreBridge; + mAttestationTrustStoreBridge = nullptr; + } } void AndroidDeviceControllerWrapper::SetJavaObjectRef(JavaVM * vm, jobject obj) @@ -156,9 +168,8 @@ AndroidDeviceControllerWrapper * AndroidDeviceControllerWrapper::AllocateNew( #endif // 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::Credentials::SetDeviceAttestationVerifier(GetDefaultDACVerifier(testingRootStore)); chip::Controller::FactoryInitParams initParams; chip::Controller::SetupParams setupParams; @@ -428,6 +439,64 @@ CHIP_ERROR AndroidDeviceControllerWrapper::UpdateCommissioningParameters(const c return mAutoCommissioner.SetCommissioningParameters(params); } +CHIP_ERROR AndroidDeviceControllerWrapper::UpdateDeviceAttestationDelegateBridge(jobject deviceAttestationDelegate, + chip::Optional expiryTimeoutSecs, + bool shouldWaitAfterDeviceAttestation) +{ + CHIP_ERROR err = CHIP_NO_ERROR; + + DeviceAttestationDelegateBridge * delegateBridge = + new DeviceAttestationDelegateBridge(deviceAttestationDelegate, expiryTimeoutSecs, shouldWaitAfterDeviceAttestation); + VerifyOrExit(delegateBridge != nullptr, err = CHIP_ERROR_NO_MEMORY); + + if (mDeviceAttestationDelegateBridge != nullptr) + { + delete mDeviceAttestationDelegateBridge; + } + + mDeviceAttestationDelegateBridge = delegateBridge; + +exit: + return err; +} + +CHIP_ERROR AndroidDeviceControllerWrapper::UpdateAttestationTrustStoreBridge(jobject attestationTrustStoreDelegate) +{ + CHIP_ERROR err = CHIP_NO_ERROR; + + DeviceAttestationVerifier * deviceAttestationVerifier = nullptr; + AttestationTrustStoreBridge * attestationTrustStoreBridge = new AttestationTrustStoreBridge(attestationTrustStoreDelegate); + VerifyOrExit(attestationTrustStoreBridge != nullptr, err = CHIP_ERROR_NO_MEMORY); + + deviceAttestationVerifier = new Credentials::DefaultDACVerifier(attestationTrustStoreBridge); + VerifyOrExit(deviceAttestationVerifier != nullptr, err = CHIP_ERROR_NO_MEMORY); + + if (mAttestationTrustStoreBridge != nullptr) + { + delete mAttestationTrustStoreBridge; + } + mAttestationTrustStoreBridge = attestationTrustStoreBridge; + + if (mDeviceAttestationVerifier != nullptr) + { + delete mDeviceAttestationVerifier; + } + mDeviceAttestationVerifier = deviceAttestationVerifier; + + mController->SetDeviceAttestationVerifier(mDeviceAttestationVerifier); + +exit: + if (err != CHIP_NO_ERROR) + { + if (attestationTrustStoreBridge != nullptr) + { + delete attestationTrustStoreBridge; + } + } + + return err; +} + void AndroidDeviceControllerWrapper::OnStatusUpdate(chip::Controller::DevicePairingDelegate::Status status) { chip::DeviceLayer::StackUnlock unlock; diff --git a/src/controller/java/AndroidDeviceControllerWrapper.h b/src/controller/java/AndroidDeviceControllerWrapper.h index 0700591bf77580..3f87e13a34e4a3 100644 --- a/src/controller/java/AndroidDeviceControllerWrapper.h +++ b/src/controller/java/AndroidDeviceControllerWrapper.h @@ -41,6 +41,7 @@ #endif // JAVA_MATTER_CONTROLLER_TEST #include "AndroidOperationalCredentialsIssuer.h" +#include "AttestationTrustStoreBridge.h" #include "DeviceAttestationDelegateBridge.h" /** @@ -181,21 +182,12 @@ class AndroidDeviceControllerWrapper : public chip::Controller::DevicePairingDel return mOpCredsIssuer.get(); } - void SetDeviceAttestationDelegateBridge(DeviceAttestationDelegateBridge * deviceAttestationDelegateBridge) - { - mDeviceAttestationDelegateBridge = deviceAttestationDelegateBridge; - } - DeviceAttestationDelegateBridge * GetDeviceAttestationDelegateBridge() { return mDeviceAttestationDelegateBridge; } - void ClearDeviceAttestationDelegateBridge() - { - if (mDeviceAttestationDelegateBridge != nullptr) - { - delete mDeviceAttestationDelegateBridge; - mDeviceAttestationDelegateBridge = nullptr; - } - } + CHIP_ERROR UpdateDeviceAttestationDelegateBridge(jobject deviceAttestationDelegate, chip::Optional expiryTimeoutSecs, + bool shouldWaitAfterDeviceAttestation); + + CHIP_ERROR UpdateAttestationTrustStoreBridge(jobject attestationTrustStoreDelegate); private: using ChipDeviceControllerPtr = std::unique_ptr; @@ -235,7 +227,9 @@ class AndroidDeviceControllerWrapper : public chip::Controller::DevicePairingDel chip::Credentials::PartialDACVerifier mPartialDACVerifier; - DeviceAttestationDelegateBridge * mDeviceAttestationDelegateBridge = nullptr; + DeviceAttestationDelegateBridge * mDeviceAttestationDelegateBridge = nullptr; + AttestationTrustStoreBridge * mAttestationTrustStoreBridge = nullptr; + chip::Credentials::DeviceAttestationVerifier * mDeviceAttestationVerifier = nullptr; AndroidDeviceControllerWrapper(ChipDeviceControllerPtr controller, #ifdef JAVA_MATTER_CONTROLLER_TEST diff --git a/src/controller/java/AttestationTrustStoreBridge.cpp b/src/controller/java/AttestationTrustStoreBridge.cpp new file mode 100644 index 00000000000000..d5915543fa0be0 --- /dev/null +++ b/src/controller/java/AttestationTrustStoreBridge.cpp @@ -0,0 +1,93 @@ +/** + * + * Copyright (c) 2023 Project CHIP Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "AttestationTrustStoreBridge.h" +#include +#include +#include +#include +#include +#include + +using namespace chip; + +AttestationTrustStoreBridge::~AttestationTrustStoreBridge() +{ + if (mAttestationTrustStoreDelegate != nullptr) + { + JNIEnv * env = JniReferences::GetInstance().GetEnvForCurrentThread(); + VerifyOrReturn(env != nullptr, ChipLogError(Controller, "Could not get JNIEnv for current thread")); + env->DeleteGlobalRef(mAttestationTrustStoreDelegate); + mAttestationTrustStoreDelegate = nullptr; + } +} + +CHIP_ERROR AttestationTrustStoreBridge::GetProductAttestationAuthorityCert(const chip::ByteSpan & skid, + chip::MutableByteSpan & outPaaDerBuffer) const +{ + VerifyOrReturnError(skid.size() == chip::Crypto::kSubjectKeyIdentifierLength, CHIP_ERROR_INVALID_ARGUMENT); + + constexpr size_t paaCertAllocatedLen = chip::Credentials::kMaxDERCertLength; + Platform::ScopedMemoryBuffer paaCert; + VerifyOrReturnError(paaCert.Alloc(paaCertAllocatedLen), CHIP_ERROR_NO_MEMORY); + + MutableByteSpan paaDerBuffer{ paaCert.Get(), paaCertAllocatedLen }; + ReturnErrorOnFailure(GetPaaCertFromJava(skid, paaDerBuffer)); + + uint8_t skidBuf[chip::Crypto::kSubjectKeyIdentifierLength] = { 0 }; + chip::MutableByteSpan candidateSkidSpan{ skidBuf }; + VerifyOrReturnError(CHIP_NO_ERROR == chip::Crypto::ExtractSKIDFromX509Cert(paaDerBuffer, candidateSkidSpan), + CHIP_ERROR_INTERNAL); + + // Make sure the skid of the paa cert is match. + if (skid.data_equal(candidateSkidSpan)) + { + // Found a match + return CopySpanToMutableSpan(paaDerBuffer, outPaaDerBuffer); + } + return CHIP_ERROR_CA_CERT_NOT_FOUND; +} + +CHIP_ERROR AttestationTrustStoreBridge::GetPaaCertFromJava(const chip::ByteSpan & skid, + chip::MutableByteSpan & outPaaDerBuffer) const +{ + JNIEnv * env = JniReferences::GetInstance().GetEnvForCurrentThread(); + jclass attestationTrustStoreDelegateCls = nullptr; + jbyteArray javaSkid = nullptr; + jmethodID getProductAttestationAuthorityCertMethod = nullptr; + + JniReferences::GetInstance().GetClassRef(env, "chip/devicecontroller/AttestationTrustStoreDelegate", + attestationTrustStoreDelegateCls); + VerifyOrReturnError(attestationTrustStoreDelegateCls != nullptr, CHIP_JNI_ERROR_TYPE_NOT_FOUND); + JniClass attestationTrustStoreDelegateJniCls(attestationTrustStoreDelegateCls); + + JniReferences::GetInstance().FindMethod(env, mAttestationTrustStoreDelegate, "getProductAttestationAuthorityCert", "([B)[B", + &getProductAttestationAuthorityCertMethod); + VerifyOrReturnError(getProductAttestationAuthorityCertMethod != nullptr, CHIP_JNI_ERROR_METHOD_NOT_FOUND); + + JniReferences::GetInstance().N2J_ByteArray(env, skid.data(), static_cast(skid.size()), javaSkid); + VerifyOrReturnError(javaSkid != nullptr, CHIP_ERROR_NO_MEMORY); + + jbyteArray javaPaaCert = + (jbyteArray) env->CallObjectMethod(mAttestationTrustStoreDelegate, getProductAttestationAuthorityCertMethod, javaSkid); + VerifyOrReturnError(javaPaaCert != nullptr, CHIP_ERROR_CA_CERT_NOT_FOUND); + + JniByteArray paaCertBytes(env, javaPaaCert); + CopySpanToMutableSpan(paaCertBytes.byteSpan(), outPaaDerBuffer); + + return CHIP_NO_ERROR; +} diff --git a/src/controller/java/AttestationTrustStoreBridge.h b/src/controller/java/AttestationTrustStoreBridge.h new file mode 100644 index 00000000000000..be84be2f530307 --- /dev/null +++ b/src/controller/java/AttestationTrustStoreBridge.h @@ -0,0 +1,36 @@ +/** + * + * Copyright (c) 2023 Project CHIP Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include +#include +#include + +class AttestationTrustStoreBridge : public chip::Credentials::AttestationTrustStore +{ +public: + AttestationTrustStoreBridge(jobject attestationTrustStoreDelegate) : + mAttestationTrustStoreDelegate(attestationTrustStoreDelegate) + {} + ~AttestationTrustStoreBridge(); + + CHIP_ERROR GetProductAttestationAuthorityCert(const chip::ByteSpan & skid, + chip::MutableByteSpan & outPaaDerBuffer) const override; + +protected: + jobject mAttestationTrustStoreDelegate = nullptr; + + CHIP_ERROR GetPaaCertFromJava(const chip::ByteSpan & skid, chip::MutableByteSpan & outPaaDerBuffer) const; +}; diff --git a/src/controller/java/BUILD.gn b/src/controller/java/BUILD.gn index 6cbdb46912c92e..29226c87ba38d5 100644 --- a/src/controller/java/BUILD.gn +++ b/src/controller/java/BUILD.gn @@ -43,6 +43,8 @@ shared_library("jni") { "AndroidDeviceControllerWrapper.h", "AndroidOperationalCredentialsIssuer.cpp", "AndroidOperationalCredentialsIssuer.h", + "AttestationTrustStoreBridge.cpp", + "AttestationTrustStoreBridge.h", "BaseCHIPCluster-JNI.cpp", "CHIPAttributeTLVValueDecoder.h", "CHIPDefaultCallbacks.cpp", @@ -174,6 +176,7 @@ android_library("java") { "src/chip/clusterinfo/DelegatedClusterCallback.java", "src/chip/clusterinfo/InteractionInfo.java", "src/chip/devicecontroller/AttestationInfo.java", + "src/chip/devicecontroller/AttestationTrustStoreDelegate.java", "src/chip/devicecontroller/CSRInfo.java", "src/chip/devicecontroller/ChipClusterException.java", "src/chip/devicecontroller/ChipCommandType.java", diff --git a/src/controller/java/CHIPDeviceController-JNI.cpp b/src/controller/java/CHIPDeviceController-JNI.cpp index 566832d59e5020..c70511c4366bf9 100644 --- a/src/controller/java/CHIPDeviceController-JNI.cpp +++ b/src/controller/java/CHIPDeviceController-JNI.cpp @@ -87,9 +87,6 @@ static CHIP_ERROR ParseEventPathList(jobject eventPathList, std::vectorClearDeviceAttestationDelegateBridge(); - DeviceAttestationDelegateBridge * deviceAttestationDelegateBridge = nullptr; - err = CreateDeviceAttestationDelegateBridge(env, handle, deviceAttestationDelegate, failSafeExpiryTimeoutSecs, - &deviceAttestationDelegateBridge); - VerifyOrExit(err == CHIP_NO_ERROR, err = CHIP_JNI_ERROR_EXCEPTION_THROWN); - wrapper->SetDeviceAttestationDelegateBridge(deviceAttestationDelegateBridge); + chip::Optional timeoutSecs = chip::MakeOptional(static_cast(failSafeExpiryTimeoutSecs)); + bool shouldWaitAfterDeviceAttestation = false; + jclass deviceAttestationDelegateCls = nullptr; + jobject deviceAttestationDelegateRef = env->NewGlobalRef(deviceAttestationDelegate); + + VerifyOrExit(deviceAttestationDelegateRef != nullptr, err = CHIP_JNI_ERROR_NULL_OBJECT); + JniReferences::GetInstance().GetClassRef(env, "chip/devicecontroller/DeviceAttestationDelegate", + deviceAttestationDelegateCls); + VerifyOrExit(deviceAttestationDelegateCls != nullptr, err = CHIP_JNI_ERROR_TYPE_NOT_FOUND); + + if (env->IsInstanceOf(deviceAttestationDelegate, deviceAttestationDelegateCls)) + { + shouldWaitAfterDeviceAttestation = true; + } + + err = wrapper->UpdateDeviceAttestationDelegateBridge(deviceAttestationDelegateRef, timeoutSecs, + shouldWaitAfterDeviceAttestation); + SuccessOrExit(err); } + +exit: + if (err != CHIP_NO_ERROR) + { + ChipLogError(Controller, "Failed to set device attestation delegate."); + JniReferences::GetInstance().ThrowError(env, sChipDeviceControllerExceptionCls, err); + } +} + +JNI_METHOD(void, setAttestationTrustStoreDelegate) +(JNIEnv * env, jobject self, jlong handle, jobject attestationTrustStoreDelegate) +{ + chip::DeviceLayer::StackLock lock; + CHIP_ERROR err = CHIP_NO_ERROR; + AndroidDeviceControllerWrapper * wrapper = AndroidDeviceControllerWrapper::FromJNIHandle(handle); + + ChipLogProgress(Controller, "setAttestationTrustStoreDelegate() called"); + + if (attestationTrustStoreDelegate != nullptr) + { + jobject attestationTrustStoreDelegateRef = env->NewGlobalRef(attestationTrustStoreDelegate); + err = wrapper->UpdateAttestationTrustStoreBridge(attestationTrustStoreDelegateRef); + SuccessOrExit(err); + } + exit: if (err != CHIP_NO_ERROR) { @@ -793,6 +827,38 @@ JNI_METHOD(jbyteArray, convertX509CertToMatterCert) return outJbytes; } +JNI_METHOD(jbyteArray, extractSkidFromPaaCert) +(JNIEnv * env, jobject self, jbyteArray paaCert) +{ + uint32_t allocatedCertLength = chip::Credentials::kMaxCHIPCertLength; + chip::Platform::ScopedMemoryBuffer outBuf; + jbyteArray outJbytes = nullptr; + JniByteArray paaCertBytes(env, paaCert); + + CHIP_ERROR err = CHIP_NO_ERROR; + VerifyOrExit(outBuf.Alloc(allocatedCertLength), err = CHIP_ERROR_NO_MEMORY); + { + MutableByteSpan outBytes(outBuf.Get(), allocatedCertLength); + + err = chip::Crypto::ExtractSKIDFromX509Cert(paaCertBytes.byteSpan(), outBytes); + SuccessOrExit(err); + + VerifyOrExit(chip::CanCastTo(outBytes.size()), err = CHIP_ERROR_INTERNAL); + + err = JniReferences::GetInstance().N2J_ByteArray(env, outBytes.data(), static_cast(outBytes.size()), outJbytes); + SuccessOrExit(err); + } + +exit: + if (err != CHIP_NO_ERROR) + { + ChipLogError(Controller, "Failed to extract skid frome X509 cert. Err = %" CHIP_ERROR_FORMAT, err.Format()); + JniReferences::GetInstance().ThrowError(env, sChipDeviceControllerExceptionCls, err); + } + + return outJbytes; +} + JNI_METHOD(void, unpairDevice)(JNIEnv * env, jobject self, jlong handle, jlong deviceId) { chip::DeviceLayer::StackLock lock; @@ -1860,27 +1926,3 @@ CHIP_ERROR N2J_NetworkLocation(JNIEnv * env, jstring ipAddress, jint port, jint exit: return err; } - -CHIP_ERROR CreateDeviceAttestationDelegateBridge(JNIEnv * env, jlong handle, jobject deviceAttestationDelegate, - jint failSafeExpiryTimeoutSecs, - DeviceAttestationDelegateBridge ** deviceAttestationDelegateBridge) -{ - CHIP_ERROR err = CHIP_NO_ERROR; - chip::Optional timeoutSecs = chip::MakeOptional(static_cast(failSafeExpiryTimeoutSecs)); - bool shouldWaitAfterDeviceAttestation = false; - jclass deviceAttestationDelegateCls = nullptr; - jobject deviceAttestationDelegateRef = env->NewGlobalRef(deviceAttestationDelegate); - - VerifyOrExit(deviceAttestationDelegateRef != nullptr, err = CHIP_JNI_ERROR_NULL_OBJECT); - JniReferences::GetInstance().GetClassRef(env, "chip/devicecontroller/DeviceAttestationDelegate", deviceAttestationDelegateCls); - VerifyOrExit(deviceAttestationDelegateCls != nullptr, err = CHIP_JNI_ERROR_TYPE_NOT_FOUND); - - if (env->IsInstanceOf(deviceAttestationDelegate, deviceAttestationDelegateCls)) - { - shouldWaitAfterDeviceAttestation = true; - } - *deviceAttestationDelegateBridge = - new DeviceAttestationDelegateBridge(deviceAttestationDelegateRef, timeoutSecs, shouldWaitAfterDeviceAttestation); -exit: - return err; -} diff --git a/src/controller/java/src/chip/devicecontroller/AttestationTrustStoreDelegate.java b/src/controller/java/src/chip/devicecontroller/AttestationTrustStoreDelegate.java new file mode 100644 index 00000000000000..e30bfdbdea774b --- /dev/null +++ b/src/controller/java/src/chip/devicecontroller/AttestationTrustStoreDelegate.java @@ -0,0 +1,25 @@ +package chip.devicecontroller; + +import javax.annotation.Nullable; + +/** + * Delegate for attestation trust store for device attestation verifiers. + * + *

API is synchronous. This implementation will replace the built-in attestation trust store, + * please make sure you have the required paa certificates before commissioning. + */ +public interface AttestationTrustStoreDelegate { + /** + * Look-up a product attestation authority (PAA) cert by subject key identifier (SKID). + * + *

The implementations of this interface must have access to a set of PAAs to trust. + * + *

Interface is synchronous, and therefore this should not be used unless to expose a PAA store + * that is both fully local and quick to access. + * + * @param skid Buffer containing the subject key identifier (SKID) of the PAA to look-up + * @return If found, the result should return paa cert in x.509 format, if not found, return null. + */ + @Nullable + byte[] getProductAttestationAuthorityCert(byte[] skid); +} diff --git a/src/controller/java/src/chip/devicecontroller/ChipDeviceController.java b/src/controller/java/src/chip/devicecontroller/ChipDeviceController.java index 15e3ea64ae2644..277090685f5a4b 100644 --- a/src/controller/java/src/chip/devicecontroller/ChipDeviceController.java +++ b/src/controller/java/src/chip/devicecontroller/ChipDeviceController.java @@ -106,6 +106,19 @@ public void setDeviceAttestationDelegate( deviceControllerPtr, failSafeExpiryTimeoutSecs, deviceAttestationDelegate); } + /** + * Set the delegate of attestation trust store for device attestation. + * + *

It will replace the built-in attestation trust store, please make sure you have the required + * paa certificates before commissioning. + * + * @param attestationTrustStoreDelegate Delegate for attestation trust store + */ + public void setAttestationTrustStoreDelegate( + AttestationTrustStoreDelegate attestationTrustStoreDelegate) { + setAttestationTrustStoreDelegate(deviceControllerPtr, attestationTrustStoreDelegate); + } + public void pairDevice( BluetoothGatt bleServer, int connId, @@ -661,6 +674,14 @@ public void invoke( */ public native byte[] convertX509CertToMatterCert(byte[] x509Cert); + /** + * Extract skid from paa cert. + * + * @param paaCert The product attestation authority (PAA) cert + * @return The subject key identifier (SKID) + */ + public native byte[] extractSkidFromPaaCert(byte[] paaCert); + /** * Generates a new PASE verifier for the given setup PIN code. * @@ -721,6 +742,9 @@ private native void invoke( private native void setDeviceAttestationDelegate( long deviceControllerPtr, int failSafeExpiryTimeoutSecs, DeviceAttestationDelegate delegate); + private native void setAttestationTrustStoreDelegate( + long deviceControllerPtr, AttestationTrustStoreDelegate delegate); + private native void pairDevice( long deviceControllerPtr, long deviceId,