Skip to content

Commit 1496492

Browse files
ritikananda27RitikaNanda
authored andcommitted
Support passing csr nonce into commissioning flow (#7696)
* Retrieving OpCSR from the Chip Device after passing the CSRNonce. * Retrieving OpCSR from the Chip Device after passing the CSRNonce. Co-authored-by: Ritika Nanda <ritikananda@google.com>
1 parent 0595257 commit 1496492

File tree

11 files changed

+166
-29
lines changed

11 files changed

+166
-29
lines changed

src/android/CHIPTool/app/src/main/java/com/google/chip/chiptool/GenericChipDeviceListener.kt

+4
Original file line numberDiff line numberDiff line change
@@ -38,4 +38,8 @@ open class GenericChipDeviceListener : ChipDeviceController.CompletionListener {
3838
override fun onError(error: Throwable?) {
3939
// No op
4040
}
41+
42+
override fun onOpCSRGenerationComplete(errorCode: ByteArray) {
43+
// No op
44+
}
4145
}

src/android/CHIPTool/app/src/main/java/com/google/chip/chiptool/provisioning/DeviceProvisioningFragment.kt

+4
Original file line numberDiff line numberDiff line change
@@ -135,6 +135,10 @@ class DeviceProvisioningFragment : Fragment() {
135135
}
136136
}
137137

138+
override fun onOpCSRGenerationComplete(errorCode: ByteArray) {
139+
Log.d(TAG,String(errorCode))
140+
}
141+
138142
override fun onPairingDeleted(code: Int) {
139143
Log.d(TAG, "onPairingDeleted: $code")
140144
}

src/controller/CHIPDevice.h

+6-1
Original file line numberDiff line numberDiff line change
@@ -353,7 +353,12 @@ class DLL_EXPORT Device : public Messaging::ExchangeDelegate, public SessionEsta
353353

354354
CASESession & GetCASESession() { return mCASESession; }
355355

356-
CHIP_ERROR GenerateCSRNonce() { return Crypto::DRBG_get_bytes(mCSRNonce, sizeof(mCSRNonce)); }
356+
CHIP_ERROR SetCSRNonce(ByteSpan csrNonce)
357+
{
358+
VerifyOrReturnError(csrNonce.size() == sizeof(mCSRNonce), CHIP_ERROR_INVALID_ARGUMENT);
359+
memcpy(mCSRNonce, csrNonce.data(), csrNonce.size());
360+
return CHIP_NO_ERROR;
361+
}
357362

358363
ByteSpan GetCSRNonce() const { return ByteSpan(mCSRNonce, sizeof(mCSRNonce)); }
359364

src/controller/CHIPDeviceController.cpp

+12-1
Original file line numberDiff line numberDiff line change
@@ -885,6 +885,18 @@ CHIP_ERROR DeviceCommissioner::PairDevice(NodeId remoteDeviceId, RendezvousParam
885885
VerifyOrExit(mDeviceBeingPaired < kNumMaxActiveDevices, err = CHIP_ERROR_NO_MEMORY);
886886
device = &mActiveDevices[mDeviceBeingPaired];
887887

888+
// If the CSRNonce is passed in, using that else using a random one..
889+
if (params.HasCSRNonce())
890+
{
891+
VerifyOrReturnError(device->SetCSRNonce(params.GetCSRNonce().Value()) == CHIP_NO_ERROR, CHIP_ERROR_INVALID_ARGUMENT);
892+
}
893+
else
894+
{
895+
uint8_t mCSRNonce[kOpCSRNonceLength];
896+
Crypto::DRBG_get_bytes(mCSRNonce, sizeof(mCSRNonce));
897+
VerifyOrReturnError(device->SetCSRNonce(ByteSpan(mCSRNonce)) == CHIP_NO_ERROR, CHIP_ERROR_INVALID_ARGUMENT);
898+
}
899+
888900
mIsIPRendezvous = (params.GetPeerAddress().GetTransportType() != Transport::Type::kBle);
889901

890902
err = mPairingSession.MessageDispatch().Init(mTransportMgr);
@@ -1171,7 +1183,6 @@ CHIP_ERROR DeviceCommissioner::SendOperationalCertificateSigningRequestCommand(D
11711183
Callback::Cancelable * successCallback = mOpCSRResponseCallback.Cancel();
11721184
Callback::Cancelable * failureCallback = mOnCSRFailureCallback.Cancel();
11731185

1174-
ReturnErrorOnFailure(device->GenerateCSRNonce());
11751186
ReturnErrorOnFailure(cluster.OpCSRRequest(successCallback, failureCallback, device->GetCSRNonce()));
11761187
ChipLogDetail(Controller, "Sent OpCSR request, waiting for the CSR");
11771188
return CHIP_NO_ERROR;

src/controller/java/AndroidDeviceControllerWrapper.cpp

+82-7
Original file line numberDiff line numberDiff line change
@@ -22,13 +22,17 @@
2222
#include <algorithm>
2323
#include <memory>
2424

25+
#include "JniReferences.h"
26+
#include <support/CodeUtils.h>
27+
2528
#include <platform/KeyValueStoreManager.h>
2629
#include <support/ThreadOperationalDataset.h>
2730

2831
using namespace chip::Controller;
2932

3033
extern chip::Ble::BleLayer * GetJNIBleLayer();
3134

35+
constexpr const char kOperationalCredentialsIssuerKeypairStorage[] = "AndroidDeviceControllerKey";
3236
AndroidDeviceControllerWrapper::~AndroidDeviceControllerWrapper()
3337
{
3438
if ((mJavaVM != nullptr) && (mJavaObjectRef != nullptr))
@@ -50,6 +54,15 @@ void AndroidDeviceControllerWrapper::CallJavaMethod(const char * methodName, jin
5054
argument);
5155
}
5256

57+
CHIP_ERROR AndroidDeviceControllerWrapper::GetRootCACertificate(chip::FabricId fabricId, uint8_t * certBuf, uint32_t certBufSize,
58+
uint32_t & outCertLen)
59+
{
60+
Initialize();
61+
VerifyOrReturnError(mInitialized, CHIP_ERROR_INCORRECT_STATE);
62+
chip::X509CertRequestParams newCertParams = { 0, mIssuerId, mNow, mNow + mValidity, true, fabricId, false, 0 };
63+
return NewRootX509Cert(newCertParams, mIssuer, certBuf, certBufSize, outCertLen);
64+
}
65+
5366
AndroidDeviceControllerWrapper * AndroidDeviceControllerWrapper::AllocateNew(JavaVM * vm, jobject deviceControllerObj,
5467
pthread_mutex_t * stackLock, chip::NodeId nodeId,
5568
chip::System::Layer * systemLayer,
@@ -90,20 +103,19 @@ AndroidDeviceControllerWrapper * AndroidDeviceControllerWrapper::AllocateNew(Jav
90103

91104
chip::Controller::CommissionerInitParams initParams;
92105

93-
initParams.storageDelegate = wrapper.get();
94-
initParams.pairingDelegate = wrapper.get();
95-
initParams.systemLayer = systemLayer;
96-
initParams.inetLayer = inetLayer;
97-
initParams.bleLayer = GetJNIBleLayer();
106+
initParams.storageDelegate = wrapper.get();
107+
initParams.pairingDelegate = wrapper.get();
108+
initParams.operationalCredentialsDelegate = wrapper.get();
109+
initParams.systemLayer = systemLayer;
110+
initParams.inetLayer = inetLayer;
111+
initParams.bleLayer = GetJNIBleLayer();
98112

99113
*errInfoOnFailure = wrapper->OpCredsIssuer().Initialize(*initParams.storageDelegate);
100114
if (*errInfoOnFailure != CHIP_NO_ERROR)
101115
{
102116
return nullptr;
103117
}
104118

105-
initParams.operationalCredentialsDelegate = &wrapper->OpCredsIssuer();
106-
107119
*errInfoOnFailure = wrapper->Controller()->Init(nodeId, initParams);
108120

109121
if (*errInfoOnFailure != CHIP_NO_ERROR)
@@ -139,6 +151,69 @@ void AndroidDeviceControllerWrapper::OnPairingDeleted(CHIP_ERROR error)
139151
CallJavaMethod("onPairingDeleted", static_cast<jint>(error));
140152
}
141153

154+
// TODO Refactor this API to match latest spec, so that GenerateNodeOperationalCertificate receives the full CSR Elements data
155+
// payload.
156+
CHIP_ERROR AndroidDeviceControllerWrapper::GenerateNodeOperationalCertificate(const chip::PeerId & peerId,
157+
const chip::ByteSpan & csr, int64_t serialNumber,
158+
uint8_t * certBuf, uint32_t certBufSize,
159+
uint32_t & outCertLen)
160+
{
161+
jmethodID method;
162+
CHIP_ERROR err = CHIP_NO_ERROR;
163+
err = JniReferences::GetInstance().FindMethod(JniReferences::GetInstance().GetEnvForCurrentThread(), mJavaObjectRef,
164+
"onOpCSRGenerationComplete", "([B)V", &method);
165+
if (err != CHIP_NO_ERROR)
166+
{
167+
ChipLogError(Controller, "Error invoking onOpCSRGenerationComplete: %d", err);
168+
return err;
169+
}
170+
171+
// Initializing the KeyPair.
172+
Initialize();
173+
174+
chip::X509CertRequestParams request = { serialNumber, mIssuerId, mNow, mNow + mValidity, true, peerId.GetFabricId(),
175+
true, peerId.GetNodeId() };
176+
177+
chip::P256PublicKey pubkey;
178+
ReturnErrorOnFailure(VerifyCertificateSigningRequest(csr.data(), csr.size(), pubkey));
179+
180+
ChipLogProgress(chipTool, "VerifyCertificateSigningRequest");
181+
182+
CHIP_ERROR generateCert = NewNodeOperationalX509Cert(request, chip::CertificateIssuerLevel::kIssuerIsRootCA, pubkey, mIssuer,
183+
certBuf, certBufSize, outCertLen);
184+
jbyteArray argument;
185+
JniReferences::GetInstance().GetEnvForCurrentThread()->ExceptionClear();
186+
JniReferences::GetInstance().N2J_ByteArray(JniReferences::GetInstance().GetEnvForCurrentThread(), csr.data(), csr.size(),
187+
argument);
188+
JniReferences::GetInstance().GetEnvForCurrentThread()->CallVoidMethod(mJavaObjectRef, method, argument);
189+
return generateCert;
190+
}
191+
192+
CHIP_ERROR AndroidDeviceControllerWrapper::Initialize()
193+
{
194+
chip::Crypto::P256SerializedKeypair serializedKey;
195+
uint16_t keySize = static_cast<uint16_t>(sizeof(serializedKey));
196+
197+
// TODO: Use Android keystore system instead of direct storage of private key and add specific errors to check if a specified
198+
// item is not found in the keystore.
199+
if (SyncGetKeyValue(kOperationalCredentialsIssuerKeypairStorage, &serializedKey, keySize) != CHIP_NO_ERROR)
200+
{
201+
// If storage doesn't have an existing keypair, create one and add it to the storage.
202+
ReturnErrorOnFailure(mIssuer.Initialize());
203+
ReturnErrorOnFailure(mIssuer.Serialize(serializedKey));
204+
keySize = static_cast<uint16_t>(sizeof(serializedKey));
205+
SyncSetKeyValue(kOperationalCredentialsIssuerKeypairStorage, &serializedKey, keySize);
206+
}
207+
else
208+
{
209+
// Use the keypair from the storage
210+
ReturnErrorOnFailure(mIssuer.Deserialize(serializedKey));
211+
}
212+
213+
mInitialized = true;
214+
return CHIP_NO_ERROR;
215+
}
216+
142217
void AndroidDeviceControllerWrapper::OnMessage(chip::System::PacketBufferHandle && msg) {}
143218

144219
void AndroidDeviceControllerWrapper::OnStatusChange(void) {}

src/controller/java/AndroidDeviceControllerWrapper.h

+15
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
#include <controller/CHIPDeviceController.h>
2727
#include <controller/ExampleOperationalCredentialsIssuer.h>
2828
#include <platform/internal/DeviceNetworkInfo.h>
29+
#include <support/TimeUtils.h>
2930

3031
/**
3132
* This class contains all relevant information for the JNI view of CHIPDeviceController
@@ -35,6 +36,7 @@
3536
*/
3637
class AndroidDeviceControllerWrapper : public chip::Controller::DevicePairingDelegate,
3738
public chip::Controller::DeviceStatusDelegate,
39+
public chip::Controller::OperationalCredentialsDelegate,
3840
public chip::PersistentStorageDelegate
3941
{
4042
public:
@@ -47,12 +49,20 @@ class AndroidDeviceControllerWrapper : public chip::Controller::DevicePairingDel
4749
jlong ToJNIHandle();
4850

4951
void CallJavaMethod(const char * methodName, jint argument);
52+
CHIP_ERROR Initialize();
5053

5154
// DevicePairingDelegate implementation
5255
void OnStatusUpdate(chip::Controller::DevicePairingDelegate::Status status) override;
5356
void OnPairingComplete(CHIP_ERROR error) override;
5457
void OnPairingDeleted(CHIP_ERROR error) override;
5558

59+
// OperationalCredentialsDelegate implementation
60+
CHIP_ERROR GenerateNodeOperationalCertificate(const chip::PeerId & peerId, const chip::ByteSpan & csr, int64_t serialNumber,
61+
uint8_t * certBuf, uint32_t certBufSize, uint32_t & outCertLen) override;
62+
63+
CHIP_ERROR GetRootCACertificate(chip::FabricId fabricId, uint8_t * certBuf, uint32_t certBufSize,
64+
uint32_t & outCertLen) override;
65+
5666
// DeviceStatusDelegate implementation
5767
void OnMessage(chip::System::PacketBufferHandle && msg) override;
5868
void OnStatusChange(void) override;
@@ -73,6 +83,11 @@ class AndroidDeviceControllerWrapper : public chip::Controller::DevicePairingDel
7383

7484
private:
7585
using ChipDeviceControllerPtr = std::unique_ptr<chip::Controller::DeviceCommissioner>;
86+
chip::Crypto::P256Keypair mIssuer;
87+
bool mInitialized = false;
88+
uint32_t mIssuerId = 0;
89+
uint32_t mNow = chip::CalendarToChipEpochTime(2021, 06, 10, 0, 0, 0, mNow);
90+
uint32_t mValidity = 10 * chip::kSecondsPerStandardYear;
7691

7792
ChipDeviceControllerPtr mController;
7893
chip::Controller::ExampleOperationalCredentialsIssuer mOpCredsIssuer;

src/controller/java/CHIPDeviceController-JNI.cpp

+7-20
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,6 @@ static void HandleNewConnection(void * appState, const uint16_t discriminator);
8080
static void ThrowError(JNIEnv * env, CHIP_ERROR errToThrow);
8181
static void ReportError(JNIEnv * env, CHIP_ERROR cbErr, const char * cbName);
8282
static void * IOThreadMain(void * arg);
83-
static CHIP_ERROR N2J_ByteArray(JNIEnv * env, const uint8_t * inArray, uint32_t inArrayLen, jbyteArray & outArray);
8483
static CHIP_ERROR N2J_Error(JNIEnv * env, CHIP_ERROR inErr, jthrowable & outEx);
8584

8685
namespace {
@@ -782,13 +781,13 @@ bool HandleSendCharacteristic(BLE_CONNECTION_OBJECT connObj, const uint8_t * svc
782781
ChipLogProgress(Controller, "Received SendCharacteristic");
783782
VerifyOrExit(env != NULL, err = CHIP_JNI_ERROR_NO_ENV);
784783

785-
err = N2J_ByteArray(env, svcId, 16, svcIdObj);
784+
err = JniReferences::GetInstance().N2J_ByteArray(env, svcId, 16, svcIdObj);
786785
SuccessOrExit(err);
787786

788-
err = N2J_ByteArray(env, charId, 16, charIdObj);
787+
err = JniReferences::GetInstance().N2J_ByteArray(env, charId, 16, charIdObj);
789788
SuccessOrExit(err);
790789

791-
err = N2J_ByteArray(env, characteristicData, characteristicDataLen, characteristicDataObj);
790+
err = JniReferences::GetInstance().N2J_ByteArray(env, characteristicData, characteristicDataLen, characteristicDataObj);
792791
SuccessOrExit(err);
793792

794793
method = env->GetStaticMethodID(sAndroidChipStackCls, "onSendCharacteristic", "(I[B[B[B)Z");
@@ -829,10 +828,10 @@ bool HandleSubscribeCharacteristic(BLE_CONNECTION_OBJECT connObj, const uint8_t
829828
ChipLogProgress(Controller, "Received SubscribeCharacteristic");
830829
VerifyOrExit(env != NULL, err = CHIP_JNI_ERROR_NO_ENV);
831830

832-
err = N2J_ByteArray(env, svcId, 16, svcIdObj);
831+
err = JniReferences::GetInstance().N2J_ByteArray(env, svcId, 16, svcIdObj);
833832
SuccessOrExit(err);
834833

835-
err = N2J_ByteArray(env, charId, 16, charIdObj);
834+
err = JniReferences::GetInstance().N2J_ByteArray(env, charId, 16, charIdObj);
836835
SuccessOrExit(err);
837836

838837
{
@@ -872,10 +871,10 @@ bool HandleUnsubscribeCharacteristic(BLE_CONNECTION_OBJECT connObj, const uint8_
872871
ChipLogProgress(Controller, "Received UnsubscribeCharacteristic");
873872
VerifyOrExit(env != NULL, err = CHIP_JNI_ERROR_NO_ENV);
874873

875-
err = N2J_ByteArray(env, svcId, 16, svcIdObj);
874+
err = JniReferences::GetInstance().N2J_ByteArray(env, svcId, 16, svcIdObj);
876875
SuccessOrExit(err);
877876

878-
err = N2J_ByteArray(env, charId, 16, charIdObj);
877+
err = JniReferences::GetInstance().N2J_ByteArray(env, charId, 16, charIdObj);
879878
SuccessOrExit(err);
880879

881880
method = env->GetStaticMethodID(sAndroidChipStackCls, "onUnsubscribeCharacteristic", "(I[B[B)Z");
@@ -1102,18 +1101,6 @@ void ThrowError(JNIEnv * env, CHIP_ERROR errToThrow)
11021101
}
11031102
}
11041103

1105-
CHIP_ERROR N2J_ByteArray(JNIEnv * env, const uint8_t * inArray, uint32_t inArrayLen, jbyteArray & outArray)
1106-
{
1107-
outArray = env->NewByteArray((int) inArrayLen);
1108-
VerifyOrReturnError(outArray != NULL, CHIP_ERROR_NO_MEMORY);
1109-
1110-
env->ExceptionClear();
1111-
env->SetByteArrayRegion(outArray, 0, inArrayLen, (jbyte *) inArray);
1112-
VerifyOrReturnError(!env->ExceptionCheck(), CHIP_JNI_ERROR_EXCEPTION_THROWN);
1113-
1114-
return CHIP_NO_ERROR;
1115-
}
1116-
11171104
CHIP_ERROR N2J_Error(JNIEnv * env, CHIP_ERROR inErr, jthrowable & outEx)
11181105
{
11191106
CHIP_ERROR err = CHIP_NO_ERROR;

src/controller/java/JniReferences.cpp

+15
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,21 @@ CHIP_ERROR JniReferences::GetClassRef(JNIEnv * env, const char * clsType, jclass
9595
return err;
9696
}
9797

98+
CHIP_ERROR JniReferences::N2J_ByteArray(JNIEnv * env, const uint8_t * inArray, uint32_t inArrayLen, jbyteArray & outArray)
99+
{
100+
CHIP_ERROR err = CHIP_NO_ERROR;
101+
102+
outArray = env->NewByteArray((int) inArrayLen);
103+
VerifyOrReturnError(outArray != NULL, CHIP_ERROR_NO_MEMORY);
104+
105+
env->ExceptionClear();
106+
env->SetByteArrayRegion(outArray, 0, inArrayLen, (jbyte *) inArray);
107+
VerifyOrExit(!env->ExceptionCheck(), err = CHIP_JNI_ERROR_EXCEPTION_THROWN);
108+
109+
exit:
110+
return err;
111+
}
112+
98113
CHIP_ERROR JniReferences::FindMethod(JNIEnv * env, jobject object, const char * methodName, const char * methodSignature,
99114
jmethodID * methodId)
100115
{

src/controller/java/JniReferences.h

+2
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,8 @@ class JniReferences
7373
jmethodID * methodId);
7474
void CallVoidInt(JNIEnv * env, jobject object, const char * methodName, jint argument);
7575

76+
CHIP_ERROR N2J_ByteArray(JNIEnv * env, const uint8_t * inArray, uint32_t inArrayLen, jbyteArray & outArray);
77+
7678
private:
7779
JniReferences() {}
7880

src/controller/java/src/chip/devicecontroller/ChipDeviceController.java

+9
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,12 @@ public void onPairingComplete(int errorCode) {
106106
}
107107
}
108108

109+
public void onOpCSRGenerationComplete(byte[] errorCode) {
110+
if (completionListener != null) {
111+
completionListener.onOpCSRGenerationComplete(errorCode);
112+
}
113+
}
114+
109115
public void onPairingDeleted(int errorCode) {
110116
if (completionListener != null) {
111117
completionListener.onPairingDeleted(errorCode);
@@ -265,5 +271,8 @@ public interface CompletionListener {
265271

266272
/** Notifies the listener of the error. */
267273
void onError(Throwable error);
274+
275+
/** Notifies the Commissioner when the OpCSR for the Comissionee is generated. */
276+
void onOpCSRGenerationComplete(byte[] errorCode);
268277
}
269278
}

0 commit comments

Comments
 (0)