Skip to content

Commit

Permalink
[Android] Added mechanism to override device attestation failure base…
Browse files Browse the repository at this point in the history
…d on client/user; Commissioner attestation delegate should be able to override success
  • Loading branch information
panliming-tuya committed Oct 13, 2022
1 parent 2c9cd92 commit 11b5724
Show file tree
Hide file tree
Showing 10 changed files with 597 additions and 16 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -19,14 +19,19 @@
package com.google.chip.chiptool.provisioning

import android.bluetooth.BluetoothGatt
import android.content.DialogInterface
import android.os.Bundle
import android.util.Log
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.Toast
import androidx.appcompat.app.AlertDialog
import androidx.fragment.app.Fragment
import androidx.lifecycle.lifecycleScope
import chip.devicecontroller.AttestationInfo
import chip.devicecontroller.DeviceAttestationDelegate.DeviceAttestationCompletionCallback
import chip.devicecontroller.DeviceAttestationDelegate.DeviceAttestationFailureCallback
import chip.devicecontroller.NetworkCredentials
import com.google.chip.chiptool.ChipClient
import com.google.chip.chiptool.GenericChipDeviceListener
Expand All @@ -37,6 +42,7 @@ import com.google.chip.chiptool.util.DeviceIdUtil
import com.google.chip.chiptool.util.FragmentUtil
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.Runnable
import kotlinx.coroutines.launch

@ExperimentalCoroutinesApi
Expand Down Expand Up @@ -120,7 +126,37 @@ class DeviceProvisioningFragment : Fragment() {

val deviceId = DeviceIdUtil.getNextAvailableId(requireContext())
val connId = bluetoothManager.connectionId
deviceController.pairDevice(gatt, connId, deviceId, deviceInfo.setupPinCode, networkCredentials)
deviceController.pairDevice(gatt, connId, deviceId, deviceInfo.setupPinCode, null, networkCredentials, object: DeviceAttestationFailureCallback {
override fun onDeviceAttestationFailed(
deviceControllerPtr: Long,
devicePtr: Long,
errorCode: Int
) {
requireActivity().runOnUiThread(Runnable {
val alertDialog: AlertDialog? = activity?.let {
val builder = AlertDialog.Builder(it)
builder.apply {
setPositiveButton("Continue",
DialogInterface.OnClickListener { dialog, id ->
deviceController.continueCommissioning(devicePtr, true)
})
setNegativeButton("No",
DialogInterface.OnClickListener { dialog, id ->
deviceController.continueCommissioning(devicePtr, false)
})
}
builder.setTitle("Device Attestation")
builder.setMessage("Device Attestation failed for device under commissioning. Do you wish to continue pairing?")

// Create the AlertDialog
builder.create()
}
alertDialog?.show()
})
}


}, 600)
DeviceIdUtil.setNextAvailableId(requireContext(), deviceId + 1)
}
}
Expand Down
16 changes: 16 additions & 0 deletions src/controller/java/AndroidDeviceControllerWrapper.h
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
#include <platform/internal/DeviceNetworkInfo.h>

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

/**
* This class contains all relevant information for the JNI view of CHIPDeviceController
Expand Down Expand Up @@ -157,6 +158,19 @@ 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;
}
}

private:
using ChipDeviceControllerPtr = std::unique_ptr<chip::Controller::DeviceCommissioner>;

Expand Down Expand Up @@ -187,6 +201,8 @@ class AndroidDeviceControllerWrapper : public chip::Controller::DevicePairingDel

chip::Credentials::PartialDACVerifier mPartialDACVerifier;

DeviceAttestationDelegateBridge * mDeviceAttestationDelegateBridge = nullptr;

AndroidDeviceControllerWrapper(ChipDeviceControllerPtr controller, AndroidOperationalCredentialsIssuerPtr opCredsIssuer) :
mController(std::move(controller)), mOpCredsIssuer(std::move(opCredsIssuer))
{}
Expand Down
8 changes: 7 additions & 1 deletion src/controller/java/BUILD.gn
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,8 @@ shared_library("jni") {
"CHIPDefaultCallbacks.cpp",
"CHIPDefaultCallbacks.h",
"CHIPDeviceController-JNI.cpp",
"DeviceAttestationDelegateBridge.cpp",
"DeviceAttestationDelegateBridge.h",
"zap-generated/CHIPAttributeTLVValueDecoder.cpp",
"zap-generated/CHIPClustersWrite-JNI.cpp",
"zap-generated/CHIPEventTLVValueDecoder.cpp",
Expand Down Expand Up @@ -91,6 +93,7 @@ android_library("java") {
"src/chip/devicecontroller/ChipDeviceController.java",
"src/chip/devicecontroller/ChipDeviceControllerException.java",
"src/chip/devicecontroller/ControllerParams.java",
"src/chip/devicecontroller/DeviceAttestationDelegate.java",
"src/chip/devicecontroller/DiscoveredDevice.java",
"src/chip/devicecontroller/GetConnectedDeviceCallbackJni.java",
"src/chip/devicecontroller/KeypairDelegate.java",
Expand Down Expand Up @@ -122,7 +125,10 @@ android_library("java") {
"zap-generated/chip/devicecontroller/ClusterWriteMapping.java",
]

javac_flags = [ "-Xlint:deprecation" ]
javac_flags = [
"-Xlint:deprecation",
"-parameters", # Store infomation about method parameters
]

# TODO: add classpath support (we likely need to add something like
# ..../platforms/android-21/android.jar to access BLE items)
Expand Down
87 changes: 81 additions & 6 deletions src/controller/java/CHIPDeviceController-JNI.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,8 @@ static CHIP_ERROR ParseAttributePath(jobject attributePath, EndpointId & outEndp
static CHIP_ERROR ParseEventPathList(jobject eventPathList, std::vector<app::EventPathParams> & outEventPathParamsList);
static CHIP_ERROR ParseEventPath(jobject eventPath, EndpointId & outEndpointId, ClusterId & outClusterId, EventId & outEventId);
static CHIP_ERROR IsWildcardChipPathId(jobject chipPathId, bool & isWildcard);
static CHIP_ERROR CreateDeviceAttestationDelegateBridge(JNIEnv * env, jlong handle, jobject deviceAttestationDelegate, jint failSafeExpiryTimeout,
DeviceAttestationDelegateBridge ** deviceAttestationDelegateBridge);

namespace {

Expand Down Expand Up @@ -382,7 +384,8 @@ JNI_METHOD(jlong, newDeviceController)(JNIEnv * env, jobject self, jobject contr
}

JNI_METHOD(void, commissionDevice)
(JNIEnv * env, jobject self, jlong handle, jlong deviceId, jbyteArray csrNonce, jobject networkCredentials)
(JNIEnv * env, jobject self, jlong handle, jlong deviceId, jbyteArray csrNonce, jobject networkCredentials,
jobject deviceAttestationDelegate, jint failSafeExpiryTimeout)
{
chip::DeviceLayer::StackLock lock;
CHIP_ERROR err = CHIP_NO_ERROR;
Expand All @@ -396,7 +399,16 @@ JNI_METHOD(void, commissionDevice)
err = wrapper->ApplyNetworkCredentials(commissioningParams, networkCredentials);
VerifyOrExit(err == CHIP_NO_ERROR, err = CHIP_ERROR_INVALID_ARGUMENT);
}

if (deviceAttestationDelegate != nullptr)
{
wrapper->ClearDeviceAttestationDelegateBridge();
DeviceAttestationDelegateBridge * deviceAttestationDelegateBridge = nullptr;
err = CreateDeviceAttestationDelegateBridge(env, handle, deviceAttestationDelegate,
failSafeExpiryTimeout, &deviceAttestationDelegateBridge);
VerifyOrExit(err == CHIP_NO_ERROR, err = CHIP_JNI_ERROR_EXCEPTION_THROWN);
wrapper->SetDeviceAttestationDelegateBridge(deviceAttestationDelegateBridge);
commissioningParams.SetDeviceAttestationDelegate(wrapper->GetDeviceAttestationDelegateBridge());
}
if (csrNonce != nullptr)
{
JniByteArray jniCsrNonce(env, csrNonce);
Expand All @@ -413,7 +425,7 @@ JNI_METHOD(void, commissionDevice)

JNI_METHOD(void, pairDevice)
(JNIEnv * env, jobject self, jlong handle, jlong deviceId, jint connObj, jlong pinCode, jbyteArray csrNonce,
jobject networkCredentials)
jobject networkCredentials, jobject deviceAttestationDelegate, jint failSafeExpiryTimeout)
{
chip::DeviceLayer::StackLock lock;
CHIP_ERROR err = CHIP_NO_ERROR;
Expand All @@ -436,8 +448,18 @@ JNI_METHOD(void, pairDevice)
JniByteArray jniCsrNonce(env, csrNonce);
commissioningParams.SetCSRNonce(jniCsrNonce.byteSpan());
}
if (deviceAttestationDelegate != nullptr)
{
wrapper->ClearDeviceAttestationDelegateBridge();
DeviceAttestationDelegateBridge * deviceAttestationDelegateBridge = nullptr;
err = CreateDeviceAttestationDelegateBridge(env, handle, deviceAttestationDelegate,
failSafeExpiryTimeout, &deviceAttestationDelegateBridge);
VerifyOrExit(err == CHIP_NO_ERROR, err = CHIP_JNI_ERROR_EXCEPTION_THROWN);
wrapper->SetDeviceAttestationDelegateBridge(deviceAttestationDelegateBridge);
commissioningParams.SetDeviceAttestationDelegate(wrapper->GetDeviceAttestationDelegateBridge());
}
err = wrapper->Controller()->PairDevice(deviceId, rendezvousParams, commissioningParams);

exit:
if (err != CHIP_NO_ERROR)
{
ChipLogError(Controller, "Failed to pair the device.");
Expand All @@ -447,7 +469,7 @@ JNI_METHOD(void, pairDevice)

JNI_METHOD(void, pairDeviceWithAddress)
(JNIEnv * env, jobject self, jlong handle, jlong deviceId, jstring address, jint port, jint discriminator, jlong pinCode,
jbyteArray csrNonce)
jbyteArray csrNonce, jobject deviceAttestationDelegate, jint failSafeExpiryTimeout)
{
chip::DeviceLayer::StackLock lock;
CHIP_ERROR err = CHIP_NO_ERROR;
Expand All @@ -469,8 +491,18 @@ JNI_METHOD(void, pairDeviceWithAddress)
JniByteArray jniCsrNonce(env, csrNonce);
commissioningParams.SetCSRNonce(jniCsrNonce.byteSpan());
}
if (deviceAttestationDelegate != nullptr)
{
wrapper->ClearDeviceAttestationDelegateBridge();
DeviceAttestationDelegateBridge * deviceAttestationDelegateBridge = nullptr;
err = CreateDeviceAttestationDelegateBridge(env, handle, deviceAttestationDelegate,
failSafeExpiryTimeout, &deviceAttestationDelegateBridge);
VerifyOrExit(err == CHIP_NO_ERROR, err = CHIP_JNI_ERROR_EXCEPTION_THROWN);
wrapper->SetDeviceAttestationDelegateBridge(deviceAttestationDelegateBridge);
commissioningParams.SetDeviceAttestationDelegate(wrapper->GetDeviceAttestationDelegateBridge());
}
err = wrapper->Controller()->PairDevice(deviceId, rendezvousParams, commissioningParams);

exit:
if (err != CHIP_NO_ERROR)
{
ChipLogError(Controller, "Failed to pair the device.");
Expand Down Expand Up @@ -521,6 +553,27 @@ JNI_METHOD(void, establishPaseConnectionByAddress)
}
}

JNI_METHOD(void, continueCommissioning)
(JNIEnv * env, jobject self, jlong handle, jlong devicePtr, jboolean ignoreAttestationFailure)
{
chip::DeviceLayer::StackLock lock;
ChipLogProgress(Controller, "continueCommissioning() called.");
CHIP_ERROR err = CHIP_NO_ERROR;
AndroidDeviceControllerWrapper * wrapper = AndroidDeviceControllerWrapper::FromJNIHandle(handle);
DeviceAttestationDelegateBridge * deviceAttestationDelegateBridge = wrapper->GetDeviceAttestationDelegateBridge();
auto lastAttestationResult = deviceAttestationDelegateBridge ? deviceAttestationDelegateBridge->attestationVerificationResult()
: chip::Credentials::AttestationVerificationResult::kSuccess;
chip::DeviceProxy * deviceProxy = reinterpret_cast<chip::DeviceProxy *>(devicePtr);
err = wrapper->Controller()->ContinueCommissioningAfterDeviceAttestation(
deviceProxy, ignoreAttestationFailure ? chip::Credentials::AttestationVerificationResult::kSuccess : lastAttestationResult);

if (err != CHIP_NO_ERROR)
{
ChipLogError(Controller, "Failed to continue commissioning.");
JniReferences::GetInstance().ThrowError(env, sChipDeviceControllerExceptionCls, err);
}
}

JNI_METHOD(void, setUseJavaCallbackForNOCRequest)
(JNIEnv * env, jobject self, jlong handle, jboolean useCallback)
{
Expand Down Expand Up @@ -1367,3 +1420,25 @@ CHIP_ERROR N2J_NetworkLocation(JNIEnv * env, jstring ipAddress, jint port, jint
exit:
return err;
}

CHIP_ERROR CreateDeviceAttestationDelegateBridge(JNIEnv * env, jlong handle, jobject deviceAttestationDelegate, jint failSafeExpiryTimeout,
DeviceAttestationDelegateBridge ** deviceAttestationDelegateBridge)
{
CHIP_ERROR err = CHIP_NO_ERROR;
chip::Optional<uint16_t> timeoutSecs = chip::MakeOptional(static_cast<uint16_t>(failSafeExpiryTimeout));
bool shouldWaitAfterDeviceAttestation = false;
jclass completionCallbackCls = nullptr;
jobject deviceAttestationDelegateRef = env->NewGlobalRef(deviceAttestationDelegate);
VerifyOrExit(deviceAttestationDelegateRef != nullptr, err = CHIP_JNI_ERROR_NULL_OBJECT);
JniReferences::GetInstance().GetClassRef(env, "chip/devicecontroller/DeviceAttestationDelegate$DeviceAttestationCompletionCallback",
completionCallbackCls);
VerifyOrExit(completionCallbackCls != nullptr, err = CHIP_JNI_ERROR_TYPE_NOT_FOUND);

if(env->IsInstanceOf(deviceAttestationDelegate, completionCallbackCls))
{
shouldWaitAfterDeviceAttestation = true;
}
*deviceAttestationDelegateBridge = new DeviceAttestationDelegateBridge(handle, deviceAttestationDelegateRef, timeoutSecs, shouldWaitAfterDeviceAttestation);
exit:
return err;
}
Loading

0 comments on commit 11b5724

Please sign in to comment.