Skip to content

Commit

Permalink
Support passing csr nonce into commissioning flow (#7696)
Browse files Browse the repository at this point in the history
* 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>
  • Loading branch information
ritikananda27 and RitikaNanda authored Jun 26, 2021
1 parent 0624ee4 commit 7e851e0
Show file tree
Hide file tree
Showing 11 changed files with 166 additions and 29 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -38,4 +38,8 @@ open class GenericChipDeviceListener : ChipDeviceController.CompletionListener {
override fun onError(error: Throwable?) {
// No op
}

override fun onOpCSRGenerationComplete(errorCode: ByteArray) {
// No op
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,10 @@ class DeviceProvisioningFragment : Fragment() {
}
}

override fun onOpCSRGenerationComplete(errorCode: ByteArray) {
Log.d(TAG,String(errorCode))
}

override fun onPairingDeleted(code: Int) {
Log.d(TAG, "onPairingDeleted: $code")
}
Expand Down
7 changes: 6 additions & 1 deletion src/controller/CHIPDevice.h
Original file line number Diff line number Diff line change
Expand Up @@ -353,7 +353,12 @@ class DLL_EXPORT Device : public Messaging::ExchangeDelegate, public SessionEsta

CASESession & GetCASESession() { return mCASESession; }

CHIP_ERROR GenerateCSRNonce() { return Crypto::DRBG_get_bytes(mCSRNonce, sizeof(mCSRNonce)); }
CHIP_ERROR SetCSRNonce(ByteSpan csrNonce)
{
VerifyOrReturnError(csrNonce.size() == sizeof(mCSRNonce), CHIP_ERROR_INVALID_ARGUMENT);
memcpy(mCSRNonce, csrNonce.data(), csrNonce.size());
return CHIP_NO_ERROR;
}

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

Expand Down
13 changes: 12 additions & 1 deletion src/controller/CHIPDeviceController.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -885,6 +885,18 @@ CHIP_ERROR DeviceCommissioner::PairDevice(NodeId remoteDeviceId, RendezvousParam
VerifyOrExit(mDeviceBeingPaired < kNumMaxActiveDevices, err = CHIP_ERROR_NO_MEMORY);
device = &mActiveDevices[mDeviceBeingPaired];

// If the CSRNonce is passed in, using that else using a random one..
if (params.HasCSRNonce())
{
VerifyOrReturnError(device->SetCSRNonce(params.GetCSRNonce().Value()) == CHIP_NO_ERROR, CHIP_ERROR_INVALID_ARGUMENT);
}
else
{
uint8_t mCSRNonce[kOpCSRNonceLength];
Crypto::DRBG_get_bytes(mCSRNonce, sizeof(mCSRNonce));
VerifyOrReturnError(device->SetCSRNonce(ByteSpan(mCSRNonce)) == CHIP_NO_ERROR, CHIP_ERROR_INVALID_ARGUMENT);
}

mIsIPRendezvous = (params.GetPeerAddress().GetTransportType() != Transport::Type::kBle);

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

ReturnErrorOnFailure(device->GenerateCSRNonce());
ReturnErrorOnFailure(cluster.OpCSRRequest(successCallback, failureCallback, device->GetCSRNonce()));
ChipLogDetail(Controller, "Sent OpCSR request, waiting for the CSR");
return CHIP_NO_ERROR;
Expand Down
89 changes: 82 additions & 7 deletions src/controller/java/AndroidDeviceControllerWrapper.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -22,13 +22,17 @@
#include <algorithm>
#include <memory>

#include "JniReferences.h"
#include <support/CodeUtils.h>

#include <platform/KeyValueStoreManager.h>
#include <support/ThreadOperationalDataset.h>

using namespace chip::Controller;

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

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

CHIP_ERROR AndroidDeviceControllerWrapper::GetRootCACertificate(chip::FabricId fabricId, uint8_t * certBuf, uint32_t certBufSize,
uint32_t & outCertLen)
{
Initialize();
VerifyOrReturnError(mInitialized, CHIP_ERROR_INCORRECT_STATE);
chip::X509CertRequestParams newCertParams = { 0, mIssuerId, mNow, mNow + mValidity, true, fabricId, false, 0 };
return NewRootX509Cert(newCertParams, mIssuer, certBuf, certBufSize, outCertLen);
}

AndroidDeviceControllerWrapper * AndroidDeviceControllerWrapper::AllocateNew(JavaVM * vm, jobject deviceControllerObj,
pthread_mutex_t * stackLock, chip::NodeId nodeId,
chip::System::Layer * systemLayer,
Expand Down Expand Up @@ -90,20 +103,19 @@ AndroidDeviceControllerWrapper * AndroidDeviceControllerWrapper::AllocateNew(Jav

chip::Controller::CommissionerInitParams initParams;

initParams.storageDelegate = wrapper.get();
initParams.pairingDelegate = wrapper.get();
initParams.systemLayer = systemLayer;
initParams.inetLayer = inetLayer;
initParams.bleLayer = GetJNIBleLayer();
initParams.storageDelegate = wrapper.get();
initParams.pairingDelegate = wrapper.get();
initParams.operationalCredentialsDelegate = wrapper.get();
initParams.systemLayer = systemLayer;
initParams.inetLayer = inetLayer;
initParams.bleLayer = GetJNIBleLayer();

*errInfoOnFailure = wrapper->OpCredsIssuer().Initialize(*initParams.storageDelegate);
if (*errInfoOnFailure != CHIP_NO_ERROR)
{
return nullptr;
}

initParams.operationalCredentialsDelegate = &wrapper->OpCredsIssuer();

*errInfoOnFailure = wrapper->Controller()->Init(nodeId, initParams);

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

// TODO Refactor this API to match latest spec, so that GenerateNodeOperationalCertificate receives the full CSR Elements data
// payload.
CHIP_ERROR AndroidDeviceControllerWrapper::GenerateNodeOperationalCertificate(const chip::PeerId & peerId,
const chip::ByteSpan & csr, int64_t serialNumber,
uint8_t * certBuf, uint32_t certBufSize,
uint32_t & outCertLen)
{
jmethodID method;
CHIP_ERROR err = CHIP_NO_ERROR;
err = JniReferences::GetInstance().FindMethod(JniReferences::GetInstance().GetEnvForCurrentThread(), mJavaObjectRef,
"onOpCSRGenerationComplete", "([B)V", &method);
if (err != CHIP_NO_ERROR)
{
ChipLogError(Controller, "Error invoking onOpCSRGenerationComplete: %d", err);
return err;
}

// Initializing the KeyPair.
Initialize();

chip::X509CertRequestParams request = { serialNumber, mIssuerId, mNow, mNow + mValidity, true, peerId.GetFabricId(),
true, peerId.GetNodeId() };

chip::P256PublicKey pubkey;
ReturnErrorOnFailure(VerifyCertificateSigningRequest(csr.data(), csr.size(), pubkey));

ChipLogProgress(chipTool, "VerifyCertificateSigningRequest");

CHIP_ERROR generateCert = NewNodeOperationalX509Cert(request, chip::CertificateIssuerLevel::kIssuerIsRootCA, pubkey, mIssuer,
certBuf, certBufSize, outCertLen);
jbyteArray argument;
JniReferences::GetInstance().GetEnvForCurrentThread()->ExceptionClear();
JniReferences::GetInstance().N2J_ByteArray(JniReferences::GetInstance().GetEnvForCurrentThread(), csr.data(), csr.size(),
argument);
JniReferences::GetInstance().GetEnvForCurrentThread()->CallVoidMethod(mJavaObjectRef, method, argument);
return generateCert;
}

CHIP_ERROR AndroidDeviceControllerWrapper::Initialize()
{
chip::Crypto::P256SerializedKeypair serializedKey;
uint16_t keySize = static_cast<uint16_t>(sizeof(serializedKey));

// TODO: Use Android keystore system instead of direct storage of private key and add specific errors to check if a specified
// item is not found in the keystore.
if (SyncGetKeyValue(kOperationalCredentialsIssuerKeypairStorage, &serializedKey, keySize) != CHIP_NO_ERROR)
{
// If storage doesn't have an existing keypair, create one and add it to the storage.
ReturnErrorOnFailure(mIssuer.Initialize());
ReturnErrorOnFailure(mIssuer.Serialize(serializedKey));
keySize = static_cast<uint16_t>(sizeof(serializedKey));
SyncSetKeyValue(kOperationalCredentialsIssuerKeypairStorage, &serializedKey, keySize);
}
else
{
// Use the keypair from the storage
ReturnErrorOnFailure(mIssuer.Deserialize(serializedKey));
}

mInitialized = true;
return CHIP_NO_ERROR;
}

void AndroidDeviceControllerWrapper::OnMessage(chip::System::PacketBufferHandle && msg) {}

void AndroidDeviceControllerWrapper::OnStatusChange(void) {}
Expand Down
15 changes: 15 additions & 0 deletions src/controller/java/AndroidDeviceControllerWrapper.h
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
#include <controller/CHIPDeviceController.h>
#include <controller/ExampleOperationalCredentialsIssuer.h>
#include <platform/internal/DeviceNetworkInfo.h>
#include <support/TimeUtils.h>

/**
* This class contains all relevant information for the JNI view of CHIPDeviceController
Expand All @@ -35,6 +36,7 @@
*/
class AndroidDeviceControllerWrapper : public chip::Controller::DevicePairingDelegate,
public chip::Controller::DeviceStatusDelegate,
public chip::Controller::OperationalCredentialsDelegate,
public chip::PersistentStorageDelegate
{
public:
Expand All @@ -47,12 +49,20 @@ class AndroidDeviceControllerWrapper : public chip::Controller::DevicePairingDel
jlong ToJNIHandle();

void CallJavaMethod(const char * methodName, jint argument);
CHIP_ERROR Initialize();

// DevicePairingDelegate implementation
void OnStatusUpdate(chip::Controller::DevicePairingDelegate::Status status) override;
void OnPairingComplete(CHIP_ERROR error) override;
void OnPairingDeleted(CHIP_ERROR error) override;

// OperationalCredentialsDelegate implementation
CHIP_ERROR GenerateNodeOperationalCertificate(const chip::PeerId & peerId, const chip::ByteSpan & csr, int64_t serialNumber,
uint8_t * certBuf, uint32_t certBufSize, uint32_t & outCertLen) override;

CHIP_ERROR GetRootCACertificate(chip::FabricId fabricId, uint8_t * certBuf, uint32_t certBufSize,
uint32_t & outCertLen) override;

// DeviceStatusDelegate implementation
void OnMessage(chip::System::PacketBufferHandle && msg) override;
void OnStatusChange(void) override;
Expand All @@ -73,6 +83,11 @@ class AndroidDeviceControllerWrapper : public chip::Controller::DevicePairingDel

private:
using ChipDeviceControllerPtr = std::unique_ptr<chip::Controller::DeviceCommissioner>;
chip::Crypto::P256Keypair mIssuer;
bool mInitialized = false;
uint32_t mIssuerId = 0;
uint32_t mNow = chip::CalendarToChipEpochTime(2021, 06, 10, 0, 0, 0, mNow);
uint32_t mValidity = 10 * chip::kSecondsPerStandardYear;

ChipDeviceControllerPtr mController;
chip::Controller::ExampleOperationalCredentialsIssuer mOpCredsIssuer;
Expand Down
27 changes: 7 additions & 20 deletions src/controller/java/CHIPDeviceController-JNI.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,6 @@ static void HandleNewConnection(void * appState, const uint16_t discriminator);
static void ThrowError(JNIEnv * env, CHIP_ERROR errToThrow);
static void ReportError(JNIEnv * env, CHIP_ERROR cbErr, const char * cbName);
static void * IOThreadMain(void * arg);
static CHIP_ERROR N2J_ByteArray(JNIEnv * env, const uint8_t * inArray, uint32_t inArrayLen, jbyteArray & outArray);
static CHIP_ERROR N2J_Error(JNIEnv * env, CHIP_ERROR inErr, jthrowable & outEx);

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

err = N2J_ByteArray(env, svcId, 16, svcIdObj);
err = JniReferences::GetInstance().N2J_ByteArray(env, svcId, 16, svcIdObj);
SuccessOrExit(err);

err = N2J_ByteArray(env, charId, 16, charIdObj);
err = JniReferences::GetInstance().N2J_ByteArray(env, charId, 16, charIdObj);
SuccessOrExit(err);

err = N2J_ByteArray(env, characteristicData, characteristicDataLen, characteristicDataObj);
err = JniReferences::GetInstance().N2J_ByteArray(env, characteristicData, characteristicDataLen, characteristicDataObj);
SuccessOrExit(err);

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

err = N2J_ByteArray(env, svcId, 16, svcIdObj);
err = JniReferences::GetInstance().N2J_ByteArray(env, svcId, 16, svcIdObj);
SuccessOrExit(err);

err = N2J_ByteArray(env, charId, 16, charIdObj);
err = JniReferences::GetInstance().N2J_ByteArray(env, charId, 16, charIdObj);
SuccessOrExit(err);

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

err = N2J_ByteArray(env, svcId, 16, svcIdObj);
err = JniReferences::GetInstance().N2J_ByteArray(env, svcId, 16, svcIdObj);
SuccessOrExit(err);

err = N2J_ByteArray(env, charId, 16, charIdObj);
err = JniReferences::GetInstance().N2J_ByteArray(env, charId, 16, charIdObj);
SuccessOrExit(err);

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

CHIP_ERROR N2J_ByteArray(JNIEnv * env, const uint8_t * inArray, uint32_t inArrayLen, jbyteArray & outArray)
{
outArray = env->NewByteArray((int) inArrayLen);
VerifyOrReturnError(outArray != NULL, CHIP_ERROR_NO_MEMORY);

env->ExceptionClear();
env->SetByteArrayRegion(outArray, 0, inArrayLen, (jbyte *) inArray);
VerifyOrReturnError(!env->ExceptionCheck(), CHIP_JNI_ERROR_EXCEPTION_THROWN);

return CHIP_NO_ERROR;
}

CHIP_ERROR N2J_Error(JNIEnv * env, CHIP_ERROR inErr, jthrowable & outEx)
{
CHIP_ERROR err = CHIP_NO_ERROR;
Expand Down
15 changes: 15 additions & 0 deletions src/controller/java/JniReferences.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,21 @@ CHIP_ERROR JniReferences::GetClassRef(JNIEnv * env, const char * clsType, jclass
return err;
}

CHIP_ERROR JniReferences::N2J_ByteArray(JNIEnv * env, const uint8_t * inArray, uint32_t inArrayLen, jbyteArray & outArray)
{
CHIP_ERROR err = CHIP_NO_ERROR;

outArray = env->NewByteArray((int) inArrayLen);
VerifyOrReturnError(outArray != NULL, CHIP_ERROR_NO_MEMORY);

env->ExceptionClear();
env->SetByteArrayRegion(outArray, 0, inArrayLen, (jbyte *) inArray);
VerifyOrExit(!env->ExceptionCheck(), err = CHIP_JNI_ERROR_EXCEPTION_THROWN);

exit:
return err;
}

CHIP_ERROR JniReferences::FindMethod(JNIEnv * env, jobject object, const char * methodName, const char * methodSignature,
jmethodID * methodId)
{
Expand Down
2 changes: 2 additions & 0 deletions src/controller/java/JniReferences.h
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,8 @@ class JniReferences
jmethodID * methodId);
void CallVoidInt(JNIEnv * env, jobject object, const char * methodName, jint argument);

CHIP_ERROR N2J_ByteArray(JNIEnv * env, const uint8_t * inArray, uint32_t inArrayLen, jbyteArray & outArray);

private:
JniReferences() {}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,12 @@ public void onPairingComplete(int errorCode) {
}
}

public void onOpCSRGenerationComplete(byte[] errorCode) {
if (completionListener != null) {
completionListener.onOpCSRGenerationComplete(errorCode);
}
}

public void onPairingDeleted(int errorCode) {
if (completionListener != null) {
completionListener.onPairingDeleted(errorCode);
Expand Down Expand Up @@ -265,5 +271,8 @@ public interface CompletionListener {

/** Notifies the listener of the error. */
void onError(Throwable error);

/** Notifies the Commissioner when the OpCSR for the Comissionee is generated. */
void onOpCSRGenerationComplete(byte[] errorCode);
}
}
Loading

0 comments on commit 7e851e0

Please sign in to comment.