text: /*
   *   Copyright (c) 2020-2021 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.
   *
   */
  #include "AndroidDeviceControllerWrapper.h"
  #include <lib/support/CHIPJNIError.h>
  
  #include <algorithm>
  #include <memory>
  
  #include <lib/support/CodeUtils.h>
  #include <lib/support/JniReferences.h>
  
  #include <controller/CHIPDeviceControllerFactory.h>
  #include <credentials/DeviceAttestationVerifier.h>
  #include <credentials/examples/DeviceAttestationVerifierExample.h>
  #include <lib/core/CHIPTLV.h>
  #include <lib/support/PersistentStorageMacros.h>
  #include <lib/support/SafeInt.h>
  #include <lib/support/ScopedBuffer.h>
  #include <lib/support/ThreadOperationalDataset.h>
  #include <platform/KeyValueStoreManager.h>
  
  using namespace chip;
  using namespace chip::Controller;
  using namespace chip::Credentials;
  using namespace TLV;
  
  constexpr const char kOperationalCredentialsIssuerKeypairStorage[]   = "AndroidDeviceControllerKey";
  constexpr const char kOperationalCredentialsRootCertificateStorage[] = "AndroidCARootCert";
  AndroidDeviceControllerWrapper::~AndroidDeviceControllerWrapper()
  {
      if ((mJavaVM != nullptr) && (mJavaObjectRef != nullptr))
      {
          JniReferences::GetInstance().GetEnvForCurrentThread()->DeleteGlobalRef(mJavaObjectRef);
      }
      mController->Shutdown();
  }
  
  void AndroidDeviceControllerWrapper::SetJavaObjectRef(JavaVM * vm, jobject obj)
  {
      mJavaVM        = vm;
      mJavaObjectRef = JniReferences::GetInstance().GetEnvForCurrentThread()->NewGlobalRef(obj);
  }
  
  void AndroidDeviceControllerWrapper::CallJavaMethod(const char * methodName, jint argument)
  {
      JniReferences::GetInstance().CallVoidInt(JniReferences::GetInstance().GetEnvForCurrentThread(), mJavaObjectRef, methodName,
                                               argument);
  }
  
  CHIP_ERROR AndroidDeviceControllerWrapper::GenerateNOCChainAfterValidation(NodeId nodeId, FabricId fabricId,
                                                                             const Crypto::P256PublicKey & pubkey,
                                                                             MutableByteSpan & rcac, MutableByteSpan & icac,
                                                                             MutableByteSpan & noc)
  {
      ChipLogProgress(Controller, "Generating NOC");
      chip::Credentials::X509CertRequestParams noc_request = { 1, mIssuerId, mNow, mNow + mValidity, true, fabricId, true, nodeId };
      ReturnErrorOnFailure(
          NewNodeOperationalX509Cert(noc_request, chip::Credentials::CertificateIssuerLevel::kIssuerIsRootCA, pubkey, mIssuer, noc));
      icac.reduce_size(0);
  
      uint16_t rcacBufLen = static_cast<uint16_t>(std::min(rcac.size(), static_cast<size_t>(UINT16_MAX)));
      CHIP_ERROR err      = CHIP_NO_ERROR;
      PERSISTENT_KEY_OP(fabricId, kOperationalCredentialsRootCertificateStorage, key,
                        err = SyncGetKeyValue(key, rcac.data(), rcacBufLen));
      if (err == CHIP_NO_ERROR)
      {
          // Found root certificate in the storage.
          rcac.reduce_size(rcacBufLen);
          return CHIP_NO_ERROR;
      }
  
      ChipLogProgress(Controller, "Generating RCAC");
      chip::Credentials::X509CertRequestParams rcac_request = { 0, mIssuerId, mNow, mNow + mValidity, true, fabricId, false, 0 };
      ReturnErrorOnFailure(NewRootX509Cert(rcac_request, mIssuer, rcac));
  
      VerifyOrReturnError(CanCastTo<uint16_t>(rcac.size()), CHIP_ERROR_INTERNAL);
      PERSISTENT_KEY_OP(fabricId, kOperationalCredentialsRootCertificateStorage, key,
                        err = SyncSetKeyValue(key, rcac.data(), static_cast<uint16_t>(rcac.size())));
  
      return err;
  }
  
  // TODO Refactor this API to match latest spec, so that GenerateNodeOperationalCertificate receives the full CSR Elements data
  // payload.
  CHIP_ERROR AndroidDeviceControllerWrapper::GenerateNOCChain(const ByteSpan & csrElements, const ByteSpan & attestationSignature,
                                                              const ByteSpan & DAC, const ByteSpan & PAI, const ByteSpan & PAA,
                                                              Callback::Callback<OnNOCChainGeneration> * onCompletion)
  {
      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: %" CHIP_ERROR_FORMAT, err.Format());
          return err;
      }
  
      NodeId assignedId;
      if (mNodeIdRequested)
      {
          assignedId       = mNextRequestedNodeId;
          mNodeIdRequested = false;
      }
      else
      {
          assignedId = mNextAvailableNodeId++;
      }
  
      TLVReader reader;
      reader.Init(csrElements);
  
      if (reader.GetType() == kTLVType_NotSpecified)
      {
          ReturnErrorOnFailure(reader.Next());
      }
  
      VerifyOrReturnError(reader.GetType() == kTLVType_Structure, CHIP_ERROR_WRONG_TLV_TYPE);
      VerifyOrReturnError(reader.GetTag() == AnonymousTag, CHIP_ERROR_UNEXPECTED_TLV_ELEMENT);
  
      TLVType containerType;
      ReturnErrorOnFailure(reader.EnterContainer(containerType));
      ReturnErrorOnFailure(reader.Next(kTLVType_ByteString, TLV::ContextTag(1)));
  
      ByteSpan csr(reader.GetReadPoint(), reader.GetLength());
      reader.ExitContainer(containerType);
  
      P256PublicKey pubkey;
      ReturnErrorOnFailure(VerifyCertificateSigningRequest(csr.data(), csr.size(), pubkey));
  
      ChipLogProgress(chipTool, "VerifyCertificateSigningRequest");
  
      Platform::ScopedMemoryBuffer<uint8_t> noc;
      ReturnErrorCodeIf(!noc.Alloc(kMaxCHIPDERCertLength), CHIP_ERROR_NO_MEMORY);
      MutableByteSpan nocSpan(noc.Get(), kMaxCHIPDERCertLength);
  
      Platform::ScopedMemoryBuffer<uint8_t> rcac;
      ReturnErrorCodeIf(!rcac.Alloc(kMaxCHIPDERCertLength), CHIP_ERROR_NO_MEMORY);
      MutableByteSpan rcacSpan(rcac.Get(), kMaxCHIPDERCertLength);
  
      MutableByteSpan icacSpan;
  
      ReturnErrorOnFailure(GenerateNOCChainAfterValidation(assignedId, mNextFabricId, pubkey, rcacSpan, icacSpan, nocSpan));
  
      onCompletion->mCall(onCompletion->mContext, CHIP_NO_ERROR, nocSpan, ByteSpan(), rcacSpan);
  
      jbyteArray javaCsr;
      JniReferences::GetInstance().GetEnvForCurrentThread()->ExceptionClear();
      JniReferences::GetInstance().N2J_ByteArray(JniReferences::GetInstance().GetEnvForCurrentThread(), csrElements.data(),
                                                 csrElements.size(), javaCsr);
      JniReferences::GetInstance().GetEnvForCurrentThread()->CallVoidMethod(mJavaObjectRef, method, javaCsr);
      return CHIP_NO_ERROR;
  }
  
  AndroidDeviceControllerWrapper * AndroidDeviceControllerWrapper::AllocateNew(JavaVM * vm, jobject deviceControllerObj,
                                                                               chip::NodeId nodeId, chip::System::Layer * systemLayer,
                                                                               chip::Inet::InetLayer * inetLayer,
                                                                               CHIP_ERROR * errInfoOnFailure)
  {
      if (errInfoOnFailure == nullptr)
      {
          ChipLogError(Controller, "Missing error info");
          return nullptr;
      }
      if (systemLayer == nullptr)
      {
          ChipLogError(Controller, "Missing system layer");
          *errInfoOnFailure = CHIP_ERROR_INVALID_ARGUMENT;
          return nullptr;
      }
      if (inetLayer == nullptr)
      {
          ChipLogError(Controller, "Missing inet layer");
          *errInfoOnFailure = CHIP_ERROR_INVALID_ARGUMENT;
          return nullptr;
      }
  
      *errInfoOnFailure = CHIP_NO_ERROR;
  
      std::unique_ptr<DeviceCommissioner> controller(new DeviceCommissioner());
  
      if (!controller)
      {
          *errInfoOnFailure = CHIP_ERROR_NO_MEMORY;
          return nullptr;
      }
      std::unique_ptr<AndroidDeviceControllerWrapper> wrapper(new AndroidDeviceControllerWrapper(std::move(controller)));
  
      wrapper->SetJavaObjectRef(vm, deviceControllerObj);
  
      // Initialize device attestation verifier
      SetDeviceAttestationVerifier(Examples::GetExampleDACVerifier());
  
      chip::Controller::FactoryInitParams initParams;
      chip::Controller::SetupParams setupParams;
  
      initParams.systemLayer   = systemLayer;
      initParams.inetLayer     = inetLayer;
      initParams.fabricStorage = wrapper.get();
      // move bleLayer into platform/android to share with app server
      initParams.bleLayer                        = DeviceLayer::ConnectivityMgr().GetBleLayer();
      initParams.listenPort                      = CHIP_PORT + 1;
      setupParams.storageDelegate                = wrapper.get();
      setupParams.pairingDelegate                = wrapper.get();
      setupParams.operationalCredentialsDelegate = wrapper.get();
  
      wrapper->InitializeOperationalCredentialsIssuer();
  
      Platform::ScopedMemoryBuffer<uint8_t> noc;
      if (!noc.Alloc(kMaxCHIPDERCertLength))
      {
          *errInfoOnFailure = CHIP_ERROR_NO_MEMORY;
          return nullptr;
      }
      MutableByteSpan nocSpan(noc.Get(), kMaxCHIPDERCertLength);
  
      MutableByteSpan icacSpan;
  
      Platform::ScopedMemoryBuffer<uint8_t> rcac;
      if (!rcac.Alloc(kMaxCHIPDERCertLength))
      {
          *errInfoOnFailure = CHIP_ERROR_NO_MEMORY;
          return nullptr;
      }
      MutableByteSpan rcacSpan(rcac.Get(), kMaxCHIPDERCertLength);
  
      Crypto::P256Keypair ephemeralKey;
      *errInfoOnFailure = ephemeralKey.Initialize();
      if (*errInfoOnFailure != CHIP_NO_ERROR)
      {
          return nullptr;
      }
  
      *errInfoOnFailure = wrapper->GenerateNOCChainAfterValidation(nodeId, 0, ephemeralKey.Pubkey(), rcacSpan, icacSpan, nocSpan);
      if (*errInfoOnFailure != CHIP_NO_ERROR)
      {
          return nullptr;
      }
  
      setupParams.ephemeralKeypair = &ephemeralKey;
      setupParams.controllerRCAC   = rcacSpan;
      setupParams.controllerICAC   = icacSpan;
      setupParams.controllerNOC    = nocSpan;
  
      *errInfoOnFailure = DeviceControllerFactory::GetInstance().Init(initParams);
      if (*errInfoOnFailure != CHIP_NO_ERROR)
      {
          return nullptr;
      }
      *errInfoOnFailure = DeviceControllerFactory::GetInstance().SetupCommissioner(setupParams, *wrapper->Controller());
      if (*errInfoOnFailure != CHIP_NO_ERROR)
      {
          return nullptr;
      }
  
      return wrapper.release();
  }
  
  void AndroidDeviceControllerWrapper::OnStatusUpdate(chip::Controller::DevicePairingDelegate::Status status)
  {
      chip::DeviceLayer::StackUnlock unlock;
      CallJavaMethod("onStatusUpdate", static_cast<jint>(status));
  }
  
  void AndroidDeviceControllerWrapper::OnPairingComplete(CHIP_ERROR error)
  {
      chip::DeviceLayer::StackUnlock unlock;
      CallJavaMethod("onPairingComplete", static_cast<jint>(error.AsInteger()));
  }
  
  void AndroidDeviceControllerWrapper::OnPairingDeleted(CHIP_ERROR error)
  {
      chip::DeviceLayer::StackUnlock unlock;
      CallJavaMethod("onPairingDeleted", static_cast<jint>(error.AsInteger()));
  }
  
  void AndroidDeviceControllerWrapper::OnCommissioningComplete(NodeId deviceId, CHIP_ERROR error)
  {
      chip::DeviceLayer::StackUnlock unlock;
      JNIEnv * env = JniReferences::GetInstance().GetEnvForCurrentThread();
      jmethodID onCommissioningCompleteMethod;
      CHIP_ERROR err = JniReferences::GetInstance().FindMethod(env, mJavaObjectRef, "onCommissioningComplete", "(JI)V",
                                                               &onCommissioningCompleteMethod);
      VerifyOrReturn(err == CHIP_NO_ERROR, ChipLogError(Controller, "Error finding Java method: %" CHIP_ERROR_FORMAT, err.Format()));
      env->CallVoidMethod(mJavaObjectRef, onCommissioningCompleteMethod, static_cast<jlong>(deviceId), error.AsInteger());
  }
  
  CHIP_ERROR AndroidDeviceControllerWrapper::InitializeOperationalCredentialsIssuer()
  {
      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) {}
  
  CHIP_ERROR AndroidDeviceControllerWrapper::SyncGetKeyValue(const char * key, void * value, uint16_t & size)
  {
      ChipLogProgress(chipTool, "KVS: Getting key %s", key);
  
      size_t read_size = 0;
  
      CHIP_ERROR err = chip::DeviceLayer::PersistedStorage::KeyValueStoreMgr().Get(key, value, size, &read_size);
  
      size = static_cast<uint16_t>(read_size);
  
      return err;
  }
  
  CHIP_ERROR AndroidDeviceControllerWrapper::SyncSetKeyValue(const char * key, const void * value, uint16_t size)
  {
      ChipLogProgress(chipTool, "KVS: Setting key %s", key);
      return chip::DeviceLayer::PersistedStorage::KeyValueStoreMgr().Put(key, value, size);
  }
  
  CHIP_ERROR AndroidDeviceControllerWrapper::SyncDeleteKeyValue(const char * key)
  {
      ChipLogProgress(chipTool, "KVS: Deleting key %s", key);
      return chip::DeviceLayer::PersistedStorage::KeyValueStoreMgr().Delete(key);
  }
  
  CHIP_ERROR AndroidDeviceControllerWrapper::SyncStore(chip::FabricIndex fabricIndex, const char * key, const void * buffer,
                                                       uint16_t size)
  {
      return SyncSetKeyValue(key, buffer, size);
  };
  
  CHIP_ERROR AndroidDeviceControllerWrapper::SyncLoad(chip::FabricIndex fabricIndex, const char * key, void * buffer, uint16_t & size)
  {
      return SyncGetKeyValue(key, buffer, size);
  };
  
  CHIP_ERROR AndroidDeviceControllerWrapper::SyncDelete(chip::FabricIndex fabricIndex, const char * key)
  {
      return SyncDeleteKeyValue(key);
  };
  