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

[Java] Implement the trust store delegate API for customized device attestation #25471

Merged
merged 2 commits into from
Mar 7, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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
}

Expand All @@ -57,6 +63,7 @@ object ChipClient {
ChipDeviceController.loadJni()
androidPlatform = AndroidChipPlatform(AndroidBleManager(), PreferencesKeyValueStoreManager(context), PreferencesConfigurationManager(context), NsdManagerServiceResolver(context), NsdManagerServiceBrowser(context), ChipMdnsCallbackImpl(), DiagnosticDataProviderImpl(context))
}

return androidPlatform
}

Expand Down
Original file line number Diff line number Diff line change
@@ -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"
}
}
73 changes: 71 additions & 2 deletions src/controller/java/AndroidDeviceControllerWrapper.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -428,6 +439,64 @@ CHIP_ERROR AndroidDeviceControllerWrapper::UpdateCommissioningParameters(const c
return mAutoCommissioner.SetCommissioningParameters(params);
}

CHIP_ERROR AndroidDeviceControllerWrapper::UpdateDeviceAttestationDelegateBridge(jobject deviceAttestationDelegate,
chip::Optional<uint16_t> 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;
Expand Down
22 changes: 8 additions & 14 deletions src/controller/java/AndroidDeviceControllerWrapper.h
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@
#endif // JAVA_MATTER_CONTROLLER_TEST

#include "AndroidOperationalCredentialsIssuer.h"
#include "AttestationTrustStoreBridge.h"
#include "DeviceAttestationDelegateBridge.h"

/**
Expand Down Expand Up @@ -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<uint16_t> expiryTimeoutSecs,
bool shouldWaitAfterDeviceAttestation);

CHIP_ERROR UpdateAttestationTrustStoreBridge(jobject attestationTrustStoreDelegate);

private:
using ChipDeviceControllerPtr = std::unique_ptr<chip::Controller::DeviceCommissioner>;
Expand Down Expand Up @@ -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
Expand Down
93 changes: 93 additions & 0 deletions src/controller/java/AttestationTrustStoreBridge.cpp
Original file line number Diff line number Diff line change
@@ -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 <credentials/CHIPCert.h>
#include <lib/support/CHIPJNIError.h>
#include <lib/support/CodeUtils.h>
#include <lib/support/JniReferences.h>
#include <lib/support/JniTypeWrappers.h>
#include <lib/support/logging/CHIPLogging.h>

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<uint8_t> 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<jsize>(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;
}
36 changes: 36 additions & 0 deletions src/controller/java/AttestationTrustStoreBridge.h
Original file line number Diff line number Diff line change
@@ -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 <credentials/attestation_verifier/DeviceAttestationVerifier.h>
#include <lib/support/JniReferences.h>
#include <lib/support/Span.h>

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;
};
3 changes: 3 additions & 0 deletions src/controller/java/BUILD.gn
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,8 @@ shared_library("jni") {
"AndroidDeviceControllerWrapper.h",
"AndroidOperationalCredentialsIssuer.cpp",
"AndroidOperationalCredentialsIssuer.h",
"AttestationTrustStoreBridge.cpp",
"AttestationTrustStoreBridge.h",
"BaseCHIPCluster-JNI.cpp",
"CHIPAttributeTLVValueDecoder.h",
"CHIPDefaultCallbacks.cpp",
Expand Down Expand Up @@ -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",
Expand Down
Loading