diff --git a/examples/android/CHIPTool/app/src/main/java/com/google/chip/chiptool/GenericChipDeviceListener.kt b/examples/android/CHIPTool/app/src/main/java/com/google/chip/chiptool/GenericChipDeviceListener.kt index 1d62115547e305..12e17998fa7c15 100644 --- a/examples/android/CHIPTool/app/src/main/java/com/google/chip/chiptool/GenericChipDeviceListener.kt +++ b/examples/android/CHIPTool/app/src/main/java/com/google/chip/chiptool/GenericChipDeviceListener.kt @@ -51,4 +51,12 @@ open class GenericChipDeviceListener : ChipDeviceController.CompletionListener { override fun onOpCSRGenerationComplete(csr: ByteArray) { // No op } + + override fun onICDRegistrationInfoRequired() { + // No op + } + + override fun onICDRegistrationComplete(icdNodeId: Long, icdCounter: Long) { + // No op + } } diff --git a/examples/android/CHIPTool/app/src/main/java/com/google/chip/chiptool/provisioning/DeviceProvisioningFragment.kt b/examples/android/CHIPTool/app/src/main/java/com/google/chip/chiptool/provisioning/DeviceProvisioningFragment.kt index 999bc6bc1b5513..16a411bc5eba05 100644 --- a/examples/android/CHIPTool/app/src/main/java/com/google/chip/chiptool/provisioning/DeviceProvisioningFragment.kt +++ b/examples/android/CHIPTool/app/src/main/java/com/google/chip/chiptool/provisioning/DeviceProvisioningFragment.kt @@ -32,6 +32,7 @@ import androidx.lifecycle.lifecycleScope import chip.devicecontroller.AttestationInfo import chip.devicecontroller.ChipDeviceController import chip.devicecontroller.DeviceAttestationDelegate +import chip.devicecontroller.ICDRegistrationInfo import chip.devicecontroller.NetworkCredentials import com.google.chip.chiptool.ChipClient import com.google.chip.chiptool.GenericChipDeviceListener @@ -284,6 +285,17 @@ class DeviceProvisioningFragment : Fragment() { override fun onError(error: Throwable?) { Log.d(TAG, "onError: $error") } + + override fun onICDRegistrationInfoRequired() { + Log.d(TAG, "onICDRegistrationInfoRequired") + deviceController.updateCommissioningICDRegistrationInfo( + ICDRegistrationInfo.newBuilder().build() + ) + } + + override fun onICDRegistrationComplete(icdNodeId: Long, icdCounter: Long) { + Log.d(TAG, "onICDRegistrationComplete - icdNodeId : $icdNodeId, icdCounter : $icdCounter") + } } /** Callback from [DeviceProvisioningFragment] notifying any registered listeners. */ diff --git a/examples/java-matter-controller/java/src/com/matter/controller/commands/pairing/PairingCommand.kt b/examples/java-matter-controller/java/src/com/matter/controller/commands/pairing/PairingCommand.kt index 0fc62cae9187db..572b309f02b74b 100644 --- a/examples/java-matter-controller/java/src/com/matter/controller/commands/pairing/PairingCommand.kt +++ b/examples/java-matter-controller/java/src/com/matter/controller/commands/pairing/PairingCommand.kt @@ -18,6 +18,7 @@ package com.matter.controller.commands.pairing import chip.devicecontroller.ChipDeviceController +import chip.devicecontroller.ICDRegistrationInfo import chip.devicecontroller.NetworkCredentials import com.matter.controller.commands.common.CredentialsIssuer import com.matter.controller.commands.common.IPAddress @@ -178,6 +179,19 @@ abstract class PairingCommand( } } + override fun onICDRegistrationInfoRequired() { + logger.log(Level.INFO, "onICDRegistrationInfoRequired") + currentCommissioner() + .updateCommissioningICDRegistrationInfo(ICDRegistrationInfo.newBuilder().build()) + } + + override fun onICDRegistrationComplete(icdNodeId: Long, icdCounter: Long) { + logger.log( + Level.INFO, + "onICDRegistrationComplete with icdNodeId: $icdNodeId, icdCounter: $icdCounter" + ) + } + fun getNodeId(): Long { return nodeId.get() } diff --git a/examples/kotlin-matter-controller/java/src/com/matter/controller/commands/pairing/PairingCommand.kt b/examples/kotlin-matter-controller/java/src/com/matter/controller/commands/pairing/PairingCommand.kt index 96b856568ccbc5..0e84ff7ceabf41 100644 --- a/examples/kotlin-matter-controller/java/src/com/matter/controller/commands/pairing/PairingCommand.kt +++ b/examples/kotlin-matter-controller/java/src/com/matter/controller/commands/pairing/PairingCommand.kt @@ -173,6 +173,17 @@ abstract class PairingCommand( } } + override fun onICDRegistrationInfoRequired() { + logger.log(Level.INFO, "onICDRegistrationInfoRequired") + } + + override fun onICDRegistrationComplete(icdNodeId: Long, icdCounter: Long) { + logger.log( + Level.INFO, + "onICDRegistrationComplete with icdNodeId: $icdNodeId, icdCounter: $icdCounter" + ) + } + fun getNodeId(): Long { return nodeId.get() } diff --git a/kotlin-detect-config.yaml b/kotlin-detect-config.yaml index 5dcc9f99a6b3cd..4dee3c56abb918 100644 --- a/kotlin-detect-config.yaml +++ b/kotlin-detect-config.yaml @@ -300,6 +300,7 @@ complexity: - "**/src/controller/java/src/matter/tlv/TlvWriter.kt" - "**/src/controller/java/src/matter/controller/MatterControllerImpl.kt" - "**/src/controller/java/src/matter/controller/CompletionListenerAdapter.kt" + - "**/src/controller/java/src/matter/controller/MatterController.kt" - "**/src/controller/java/tests/matter/jsontlv/JsonToTlvToJsonTest.kt" - "**/src/controller/java/tests/matter/onboardingpayload/ManualCodeTest.kt" - "**/src/controller/java/tests/matter/onboardingpayload/QRCodeTest.kt" diff --git a/src/controller/java/AndroidDeviceControllerWrapper.cpp b/src/controller/java/AndroidDeviceControllerWrapper.cpp index 1a601ba8504dbc..55cfbb0b8293b0 100644 --- a/src/controller/java/AndroidDeviceControllerWrapper.cpp +++ b/src/controller/java/AndroidDeviceControllerWrapper.cpp @@ -444,6 +444,68 @@ CHIP_ERROR AndroidDeviceControllerWrapper::ApplyNetworkCredentials(chip::Control return err; } +CHIP_ERROR AndroidDeviceControllerWrapper::ApplyICDRegistrationInfo(chip::Controller::CommissioningParameters & params, + jobject icdRegistrationInfo) +{ + chip::DeviceLayer::StackUnlock unlock; + CHIP_ERROR err = CHIP_NO_ERROR; + + VerifyOrReturnError(icdRegistrationInfo != nullptr, CHIP_ERROR_INVALID_ARGUMENT); + + JNIEnv * env = chip::JniReferences::GetInstance().GetEnvForCurrentThread(); + jmethodID getCheckInNodeIdMethod; + err = chip::JniReferences::GetInstance().FindMethod(env, icdRegistrationInfo, "getCheckInNodeId", "()Ljava/lang/Long;", + &getCheckInNodeIdMethod); + VerifyOrReturnError(err == CHIP_NO_ERROR, err); + jobject jCheckInNodeId = env->CallObjectMethod(icdRegistrationInfo, getCheckInNodeIdMethod); + + jmethodID getMonitoredSubjectMethod; + err = chip::JniReferences::GetInstance().FindMethod(env, icdRegistrationInfo, "getMonitoredSubject", "()Ljava/lang/Long;", + &getMonitoredSubjectMethod); + VerifyOrReturnError(err == CHIP_NO_ERROR, err); + jobject jMonitoredSubject = env->CallObjectMethod(icdRegistrationInfo, getMonitoredSubjectMethod); + + jmethodID getSymmetricKeyMethod; + err = + chip::JniReferences::GetInstance().FindMethod(env, icdRegistrationInfo, "getSymmetricKey", "()[B", &getSymmetricKeyMethod); + VerifyOrReturnError(err == CHIP_NO_ERROR, err); + jbyteArray jSymmetricKey = (jbyteArray) env->CallObjectMethod(icdRegistrationInfo, getSymmetricKeyMethod); + + params.SetICDRegistrationStrategy(ICDRegistrationStrategy::kBeforeComplete); + + chip::NodeId checkInNodeId = chip::kUndefinedNodeId; + if (jCheckInNodeId != nullptr) + { + checkInNodeId = static_cast(chip::JniReferences::GetInstance().LongToPrimitive(jCheckInNodeId)); + } + else + { + checkInNodeId = mController->GetNodeId(); + } + params.SetICDCheckInNodeId(checkInNodeId); + + uint64_t monitoredSubject = static_cast(checkInNodeId); + if (jMonitoredSubject != nullptr) + { + monitoredSubject = static_cast(chip::JniReferences::GetInstance().LongToPrimitive(jMonitoredSubject)); + } + params.SetICDMonitoredSubject(monitoredSubject); + + if (jSymmetricKey != nullptr) + { + JniByteArray jniSymmetricKey(env, jSymmetricKey); + VerifyOrReturnError(jniSymmetricKey.size() == sizeof(mICDSymmetricKey), CHIP_ERROR_INVALID_ARGUMENT); + memcpy(mICDSymmetricKey, jniSymmetricKey.data(), sizeof(mICDSymmetricKey)); + } + else + { + chip::Crypto::DRBG_get_bytes(mICDSymmetricKey, sizeof(mICDSymmetricKey)); + } + params.SetICDSymmetricKey(chip::ByteSpan(mICDSymmetricKey)); + + return err; +} + CHIP_ERROR AndroidDeviceControllerWrapper::UpdateCommissioningParameters(const chip::Controller::CommissioningParameters & params) { // this will wipe out any custom attestationNonce and csrNonce that was being used. @@ -814,6 +876,31 @@ void AndroidDeviceControllerWrapper::OnScanNetworksFailure(CHIP_ERROR error) CallJavaMethod("onScanNetworksFailure", static_cast(error.AsInteger())); } +void AndroidDeviceControllerWrapper::OnICDRegistrationInfoRequired() +{ + chip::DeviceLayer::StackUnlock unlock; + JNIEnv * env = JniReferences::GetInstance().GetEnvForCurrentThread(); + jmethodID onICDRegistrationInfoRequiredMethod; + CHIP_ERROR err = JniReferences::GetInstance().FindMethod(env, mJavaObjectRef, "onICDRegistrationInfoRequired", "()V", + &onICDRegistrationInfoRequiredMethod); + VerifyOrReturn(err == CHIP_NO_ERROR, ChipLogError(Controller, "Error finding Java method: %" CHIP_ERROR_FORMAT, err.Format())); + + env->CallVoidMethod(mJavaObjectRef, onICDRegistrationInfoRequiredMethod); +} + +void AndroidDeviceControllerWrapper::OnICDRegistrationComplete(chip::NodeId icdNodeId, uint32_t icdCounter) +{ + chip::DeviceLayer::StackUnlock unlock; + JNIEnv * env = JniReferences::GetInstance().GetEnvForCurrentThread(); + jmethodID onICDRegistrationCompleteMethod; + CHIP_ERROR err = JniReferences::GetInstance().FindMethod(env, mJavaObjectRef, "onICDRegistrationComplete", "(JJ)V", + &onICDRegistrationCompleteMethod); + VerifyOrReturn(err == CHIP_NO_ERROR, ChipLogError(Controller, "Error finding Java method: %" CHIP_ERROR_FORMAT, err.Format())); + + env->CallVoidMethod(mJavaObjectRef, onICDRegistrationCompleteMethod, static_cast(icdNodeId), + static_cast(icdCounter)); +} + CHIP_ERROR AndroidDeviceControllerWrapper::SyncGetKeyValue(const char * key, void * value, uint16_t & size) { ChipLogProgress(chipTool, "KVS: Getting key %s", StringOrNullMarker(key)); diff --git a/src/controller/java/AndroidDeviceControllerWrapper.h b/src/controller/java/AndroidDeviceControllerWrapper.h index d78d4803a697c0..6594c41fcdd66f 100644 --- a/src/controller/java/AndroidDeviceControllerWrapper.h +++ b/src/controller/java/AndroidDeviceControllerWrapper.h @@ -87,6 +87,11 @@ class AndroidDeviceControllerWrapper : public chip::Controller::DevicePairingDel */ CHIP_ERROR ApplyNetworkCredentials(chip::Controller::CommissioningParameters & params, jobject networkCredentials); + /** + * Convert ICD Registration Infomations from Java, and apply them to the commissioning parameters object. + */ + CHIP_ERROR ApplyICDRegistrationInfo(chip::Controller::CommissioningParameters & params, jobject icdRegistrationInfo); + /** * Update the CommissioningParameters used by the active device commissioner */ @@ -103,6 +108,8 @@ class AndroidDeviceControllerWrapper : public chip::Controller::DevicePairingDel void OnScanNetworksSuccess( const chip::app::Clusters::NetworkCommissioning::Commands::ScanNetworksResponse::DecodableType & dataResponse) override; void OnScanNetworksFailure(CHIP_ERROR error) override; + void OnICDRegistrationInfoRequired() override; + void OnICDRegistrationComplete(chip::NodeId icdNodeId, uint32_t icdCounter) override; // PersistentStorageDelegate implementation CHIP_ERROR SyncSetKeyValue(const char * key, const void * value, uint16_t size) override; @@ -242,6 +249,7 @@ class AndroidDeviceControllerWrapper : public chip::Controller::DevicePairingDel #if CHIP_DEVICE_CONFIG_DYNAMIC_SERVER OTAProviderDelegateBridge * mOtaProviderBridge = nullptr; #endif + uint8_t mICDSymmetricKey[chip::Crypto::kAES_CCM128_Key_Length]; AndroidDeviceControllerWrapper(ChipDeviceControllerPtr controller, #ifdef JAVA_MATTER_CONTROLLER_TEST diff --git a/src/controller/java/BUILD.gn b/src/controller/java/BUILD.gn index 1a3b05c73f7ce2..a538afefc744c5 100644 --- a/src/controller/java/BUILD.gn +++ b/src/controller/java/BUILD.gn @@ -444,6 +444,7 @@ android_library("java") { "src/chip/devicecontroller/DiscoveredDevice.java", "src/chip/devicecontroller/GetConnectedDeviceCallbackJni.java", "src/chip/devicecontroller/GroupKeySecurityPolicy.java", + "src/chip/devicecontroller/ICDRegistrationInfo.java", "src/chip/devicecontroller/InvokeCallback.java", "src/chip/devicecontroller/InvokeCallbackJni.java", "src/chip/devicecontroller/KeypairDelegate.java", diff --git a/src/controller/java/CHIPDeviceController-JNI.cpp b/src/controller/java/CHIPDeviceController-JNI.cpp index 93a4e239a9b9ae..2c068ea99a996c 100644 --- a/src/controller/java/CHIPDeviceController-JNI.cpp +++ b/src/controller/java/CHIPDeviceController-JNI.cpp @@ -627,7 +627,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 icdRegistrationInfo) { chip::DeviceLayer::StackLock lock; CHIP_ERROR err = CHIP_NO_ERROR; @@ -656,6 +656,12 @@ JNI_METHOD(void, pairDevice) JniByteArray jniCsrNonce(env, csrNonce); commissioningParams.SetCSRNonce(jniCsrNonce.byteSpan()); } + + if (icdRegistrationInfo != nullptr) + { + wrapper->ApplyICDRegistrationInfo(commissioningParams, icdRegistrationInfo); + } + if (wrapper->GetDeviceAttestationDelegateBridge() != nullptr) { commissioningParams.SetDeviceAttestationDelegate(wrapper->GetDeviceAttestationDelegateBridge()); @@ -671,7 +677,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 icdRegistrationInfo) { chip::DeviceLayer::StackLock lock; CHIP_ERROR err = CHIP_NO_ERROR; @@ -699,6 +705,12 @@ JNI_METHOD(void, pairDeviceWithAddress) JniByteArray jniCsrNonce(env, csrNonce); commissioningParams.SetCSRNonce(jniCsrNonce.byteSpan()); } + + if (icdRegistrationInfo != nullptr) + { + wrapper->ApplyICDRegistrationInfo(commissioningParams, icdRegistrationInfo); + } + if (wrapper->GetDeviceAttestationDelegateBridge() != nullptr) { commissioningParams.SetDeviceAttestationDelegate(wrapper->GetDeviceAttestationDelegateBridge()); @@ -714,7 +726,7 @@ JNI_METHOD(void, pairDeviceWithAddress) JNI_METHOD(void, pairDeviceWithCode) (JNIEnv * env, jobject self, jlong handle, jlong deviceId, jstring setUpCode, jboolean discoverOnce, - jboolean useOnlyOnNetworkDiscovery, jbyteArray csrNonce, jobject networkCredentials) + jboolean useOnlyOnNetworkDiscovery, jbyteArray csrNonce, jobject networkCredentials, jobject icdRegistrationInfo) { chip::DeviceLayer::StackLock lock; CHIP_ERROR err = CHIP_NO_ERROR; @@ -748,6 +760,11 @@ JNI_METHOD(void, pairDeviceWithCode) wrapper->ApplyNetworkCredentials(commissioningParams, networkCredentials); } + if (icdRegistrationInfo != nullptr) + { + wrapper->ApplyICDRegistrationInfo(commissioningParams, icdRegistrationInfo); + } + if (wrapper->GetDeviceAttestationDelegateBridge() != nullptr) { commissioningParams.SetDeviceAttestationDelegate(wrapper->GetDeviceAttestationDelegateBridge()); @@ -899,6 +916,41 @@ JNI_METHOD(void, updateCommissioningNetworkCredentials) } } +JNI_METHOD(void, updateCommissioningICDRegistrationInfo) +(JNIEnv * env, jobject self, jlong handle, jobject icdRegistrationInfo) +{ + ChipLogProgress(Controller, "updateCommissioningICDRegistrationInfo() called"); + chip::DeviceLayer::StackLock lock; + AndroidDeviceControllerWrapper * wrapper = AndroidDeviceControllerWrapper::FromJNIHandle(handle); + + CommissioningParameters commissioningParams = wrapper->GetCommissioningParameters(); + CHIP_ERROR err = wrapper->ApplyICDRegistrationInfo(commissioningParams, icdRegistrationInfo); + if (err != CHIP_NO_ERROR) + { + ChipLogError(Controller, "ApplyICDRegistrationInfo failed. Err = %" CHIP_ERROR_FORMAT, err.Format()); + JniReferences::GetInstance().ThrowError(env, sChipDeviceControllerExceptionCls, err); + return; + } + err = wrapper->UpdateCommissioningParameters(commissioningParams); + if (err != CHIP_NO_ERROR) + { + ChipLogError(Controller, "UpdateCommissioningParameters failed. Err = %" CHIP_ERROR_FORMAT, err.Format()); + JniReferences::GetInstance().ThrowError(env, sChipDeviceControllerExceptionCls, err); + return; + } + + // Only invoke ICDRegistrationInfoReady when called in ICDRegistartionInfo stage. + if (wrapper->Controller()->GetCommissioningStage() == CommissioningStage::kICDGetRegistrationInfo) + { + err = wrapper->Controller()->ICDRegistrationInfoReady(); + if (err != CHIP_NO_ERROR) + { + ChipLogError(Controller, "ICDRegistrationInfoReady failed. Err = %" CHIP_ERROR_FORMAT, err.Format()); + JniReferences::GetInstance().ThrowError(env, sChipDeviceControllerExceptionCls, err); + } + } +} + jint GetCalendarFieldID(JNIEnv * env, const char * method) { jclass calendarCls = env->FindClass("java/util/Calendar"); diff --git a/src/controller/java/src/chip/devicecontroller/ChipDeviceController.java b/src/controller/java/src/chip/devicecontroller/ChipDeviceController.java index 846ed32a84c6b1..4a6959c89a7607 100644 --- a/src/controller/java/src/chip/devicecontroller/ChipDeviceController.java +++ b/src/controller/java/src/chip/devicecontroller/ChipDeviceController.java @@ -141,7 +141,28 @@ public void pairDevice( long deviceId, long setupPincode, NetworkCredentials networkCredentials) { - pairDevice(bleServer, connId, deviceId, setupPincode, null, networkCredentials); + pairDevice(bleServer, connId, deviceId, setupPincode, null, networkCredentials, null); + } + + public void pairDevice( + BluetoothGatt bleServer, + int connId, + long deviceId, + long setupPincode, + NetworkCredentials networkCredentials, + ICDRegistrationInfo registrationInfo) { + pairDevice( + bleServer, connId, deviceId, setupPincode, null, networkCredentials, registrationInfo); + } + + public void pairDevice( + BluetoothGatt bleServer, + int connId, + long deviceId, + long setupPincode, + @Nullable byte[] csrNonce, + NetworkCredentials networkCredentials) { + pairDevice(bleServer, connId, deviceId, setupPincode, csrNonce, networkCredentials, null); } /** @@ -153,6 +174,9 @@ public void pairDevice( * @param setupPincode the pincode for the device * @param csrNonce the 32-byte CSR nonce to use, or null if we want to use an internally randomly * generated CSR nonce. + * @param networkCredentials the credentials (Wi-Fi or Thread) to be provisioned + * @param icdRegistrationInfo the informations for ICD registration. For detailed information + * {@link ICDRegistrationInfo}. */ public void pairDevice( BluetoothGatt bleServer, @@ -160,7 +184,8 @@ public void pairDevice( long deviceId, long setupPincode, @Nullable byte[] csrNonce, - NetworkCredentials networkCredentials) { + NetworkCredentials networkCredentials, + @Nullable ICDRegistrationInfo icdRegistrationInfo) { if (connectionId == 0) { connectionId = connId; @@ -173,7 +198,13 @@ public void pairDevice( Log.d(TAG, "Bluetooth connection added with ID: " + connectionId); Log.d(TAG, "Pairing device with ID: " + deviceId); pairDevice( - deviceControllerPtr, deviceId, connectionId, setupPincode, csrNonce, networkCredentials); + deviceControllerPtr, + deviceId, + connectionId, + setupPincode, + csrNonce, + networkCredentials, + icdRegistrationInfo); } else { Log.e(TAG, "Bluetooth connection already in use."); completionListener.onError(new Exception("Bluetooth connection already in use.")); @@ -188,7 +219,57 @@ public void pairDeviceWithAddress( long pinCode, @Nullable byte[] csrNonce) { pairDeviceWithAddress( - deviceControllerPtr, deviceId, address, port, discriminator, pinCode, csrNonce); + deviceControllerPtr, deviceId, address, port, discriminator, pinCode, csrNonce, null); + } + + /** + * Pair a device connected using IP Address. + * + * @param deviceId the node ID to assign to the device + * @param address IP Address of the connecting device + * @param port the port of the connecting device + * @param discriminator the discriminator for connecting device + * @param pinCode the pincode for connecting device + * @param csrNonce the 32-byte CSR nonce to use, or null if we want to use an internally randomly + * generated CSR nonce. + * @param icdRegistrationInfo the informations for ICD registration. For detailed information + * {@link ICDRegistrationInfo}. + */ + public void pairDeviceWithAddress( + long deviceId, + String address, + int port, + int discriminator, + long pinCode, + @Nullable byte[] csrNonce, + @Nullable ICDRegistrationInfo icdRegistrationInfo) { + pairDeviceWithAddress( + deviceControllerPtr, + deviceId, + address, + port, + discriminator, + pinCode, + csrNonce, + icdRegistrationInfo); + } + + public void pairDeviceWithCode( + long deviceId, + String setupCode, + boolean discoverOnce, + boolean useOnlyOnNetworkDiscovery, + @Nullable byte[] csrNonce, + @Nullable NetworkCredentials networkCredentials) { + pairDeviceWithCode( + deviceControllerPtr, + deviceId, + setupCode, + discoverOnce, + useOnlyOnNetworkDiscovery, + csrNonce, + networkCredentials, + null); } /** @@ -202,6 +283,8 @@ public void pairDeviceWithAddress( * @param csrNonce the 32-byte CSR nonce to use, or null if we want to use an internally randomly * generated CSR nonce. * @param networkCredentials the credentials (Wi-Fi or Thread) to be provisioned + * @param icdRegistrationInfo the informations for ICD registration. For detailed information + * {@link ICDRegistrationInfo}. */ public void pairDeviceWithCode( long deviceId, @@ -209,7 +292,8 @@ public void pairDeviceWithCode( boolean discoverOnce, boolean useOnlyOnNetworkDiscovery, @Nullable byte[] csrNonce, - @Nullable NetworkCredentials networkCredentials) { + @Nullable NetworkCredentials networkCredentials, + @Nullable ICDRegistrationInfo icdRegistrationInfo) { pairDeviceWithCode( deviceControllerPtr, deviceId, @@ -217,7 +301,8 @@ public void pairDeviceWithCode( discoverOnce, useOnlyOnNetworkDiscovery, csrNonce, - networkCredentials); + networkCredentials, + icdRegistrationInfo); } public void establishPaseConnection(long deviceId, int connId, long setupPincode) { @@ -325,6 +410,19 @@ public void updateCommissioningNetworkCredentials(NetworkCredentials networkCred updateCommissioningNetworkCredentials(deviceControllerPtr, networkCredentials); } + /** + * Update the ICD registration information held by the commissioner for the current commissioning + * session. + * + *

Its expected that this method will be called in response the onICDRegistrationInfoRequired + * callbacks. + * + * @param ICDRegistrationInfo the ICD registration information to use in commissioning + */ + public void updateCommissioningICDRegistrationInfo(ICDRegistrationInfo icdRegistrationInfo) { + updateCommissioningICDRegistrationInfo(deviceControllerPtr, icdRegistrationInfo); + } + public void unpairDevice(long deviceId) { unpairDevice(deviceControllerPtr, deviceId); } @@ -496,6 +594,18 @@ public void onError(Throwable error) { completionListener.onError(error); } + public void onICDRegistrationInfoRequired() { + if (completionListener != null) { + completionListener.onICDRegistrationInfoRequired(); + } + } + + public void onICDRegistrationComplete(long icdNodeId, long icdCounter) { + if (completionListener != null) { + completionListener.onICDRegistrationComplete(icdNodeId, icdCounter); + } + } + public void onNOCChainGenerationNeeded(CSRInfo csrInfo, AttestationInfo attestationInfo) { if (nocChainIssuer != null) { nocChainIssuer.onNOCChainGenerationNeeded(csrInfo, attestationInfo); @@ -1248,7 +1358,8 @@ private native void pairDevice( int connectionId, long pinCode, @Nullable byte[] csrNonce, - NetworkCredentials networkCredentials); + NetworkCredentials networkCredentials, + @Nullable ICDRegistrationInfo icdRegistrationInfo); private native void pairDeviceWithAddress( long deviceControllerPtr, @@ -1257,7 +1368,8 @@ private native void pairDeviceWithAddress( int port, int discriminator, long pinCode, - @Nullable byte[] csrNonce); + @Nullable byte[] csrNonce, + @Nullable ICDRegistrationInfo icdRegistrationInfo); private native void pairDeviceWithCode( long deviceControllerPtr, @@ -1266,7 +1378,8 @@ private native void pairDeviceWithCode( boolean discoverOnce, boolean useOnlyOnNetworkDiscovery, @Nullable byte[] csrNonce, - @Nullable NetworkCredentials networkCredentials); + @Nullable NetworkCredentials networkCredentials, + @Nullable ICDRegistrationInfo icdRegistrationInfo); private native void establishPaseConnection( long deviceControllerPtr, long deviceId, int connId, long setupPincode); @@ -1364,6 +1477,9 @@ private native void setUseJavaCallbackForNOCRequest( private native void updateCommissioningNetworkCredentials( long deviceControllerPtr, NetworkCredentials networkCredentials); + private native void updateCommissioningICDRegistrationInfo( + long deviceControllerPtr, ICDRegistrationInfo icdRegistrationInfo); + private native int onNOCChainGeneration(long deviceControllerPtr, ControllerParams params); private native int getFabricIndex(long deviceControllerPtr); @@ -1475,5 +1591,14 @@ void onReadCommissioningInfo( /** Notifies the Commissioner when the OpCSR for the Comissionee is generated. */ void onOpCSRGenerationComplete(byte[] csr); + + /** + * Nodifies when the ICD registration information (ICD symmetric key, check-in node ID and + * monitored subject) is required. + */ + void onICDRegistrationInfoRequired(); + + /** Nodifies when the registration flow for the ICD completes. */ + void onICDRegistrationComplete(long icdNodeId, long icdCounter); } } diff --git a/src/controller/java/src/chip/devicecontroller/ICDRegistrationInfo.java b/src/controller/java/src/chip/devicecontroller/ICDRegistrationInfo.java new file mode 100644 index 00000000000000..f93073fb3da5ca --- /dev/null +++ b/src/controller/java/src/chip/devicecontroller/ICDRegistrationInfo.java @@ -0,0 +1,84 @@ +/* + * Copyright (c) 2020-2023 Project CHIP Authors + * All rights reserved. + * + * 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. + * + */ +package chip.devicecontroller; + +import javax.annotation.Nullable; + +public class ICDRegistrationInfo { + @Nullable private final Long checkInNodeId; + @Nullable private final Long monitoredSubject; + @Nullable private final byte[] symmetricKey; + + private ICDRegistrationInfo(Builder builder) { + this.checkInNodeId = builder.checkInNodeId; + this.monitoredSubject = builder.monitoredSubject; + this.symmetricKey = builder.symmetricKey; + } + + public Long getCheckInNodeId() { + return checkInNodeId; + } + + public Long getMonitoredSubject() { + return monitoredSubject; + } + + public byte[] getSymmetricKey() { + return symmetricKey; + } + + public static Builder newBuilder() { + return new Builder(); + } + + /** Builder for {@link ICDRegistrationInfo}. */ + public static class Builder { + @Nullable private Long checkInNodeId = null; + @Nullable private Long monitoredSubject = null; + @Nullable private byte[] symmetricKey = null; + + private Builder() {} + + /** The check-in node id for the ICD. If not set this value, node id of the commissioner. */ + public Builder setCheckInNodeId(long checkInNodeId) { + this.checkInNodeId = checkInNodeId; + return this; + } + + /** + * The monitored subject of the ICD. If not set this value, the node id used for + * icd-check-in-nodeid + */ + public Builder setMonitoredSubject(long monitoredSubject) { + this.monitoredSubject = monitoredSubject; + return this; + } + + /** + * The 16 bytes ICD symmetric key, If not set this value, this value will be randomly generated. + */ + public Builder setSymmetricKey(byte[] symmetricKey) { + this.symmetricKey = symmetricKey; + return this; + } + + public ICDRegistrationInfo build() { + return new ICDRegistrationInfo(this); + } + } +} diff --git a/src/controller/java/src/matter/controller/CompletionListenerAdapter.kt b/src/controller/java/src/matter/controller/CompletionListenerAdapter.kt index c1956154115d89..f536fae311edaf 100644 --- a/src/controller/java/src/matter/controller/CompletionListenerAdapter.kt +++ b/src/controller/java/src/matter/controller/CompletionListenerAdapter.kt @@ -49,6 +49,11 @@ class CompletionListenerAdapter(val listener: MatterController.CompletionListene override fun onOpCSRGenerationComplete(csr: ByteArray) = listener.onOpCSRGenerationComplete(csr) + override fun onICDRegistrationInfoRequired() = listener.onICDRegistrationInfoRequired() + + override fun onICDRegistrationComplete(icdNodeId: Long, icdCounter: Long) = + listener.onICDRegistrationComplete(icdNodeId, icdCounter) + override fun onError(error: Throwable) = listener.onError(error) override fun onCloseBleComplete() { diff --git a/src/controller/java/src/matter/controller/MatterController.kt b/src/controller/java/src/matter/controller/MatterController.kt index 5ac5a85020db98..c20c9eabadbb89 100644 --- a/src/controller/java/src/matter/controller/MatterController.kt +++ b/src/controller/java/src/matter/controller/MatterController.kt @@ -57,6 +57,15 @@ interface MatterController : Closeable, InteractionClient { /** Notifies the Commissioner when the OpCSR for the Comissionee is generated. */ fun onOpCSRGenerationComplete(csr: ByteArray) + + /** + * Nodifies when the ICD registration information (ICD symmetric key, check-in node ID and + * monitored subject) is required. + */ + fun onICDRegistrationInfoRequired() + + /** Nodifies when the registration flow for the ICD completes. */ + fun onICDRegistrationComplete(icdNodeId: Long, icdCounter: Long) } /**