blob: b194804831c0814a467dd4cf8bb788378ac378a0 [file] [log] [blame]
/*
* 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/DefaultDeviceAttestationVerifier.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::EndPointManager<Inet::TCPEndPoint> * tcpEndPointManager,
chip::Inet::EndPointManager<Inet::UDPEndPoint> * udpEndPointManager, 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 (tcpEndPointManager == nullptr)
{
ChipLogError(Controller, "Missing TCP layer");
*errInfoOnFailure = CHIP_ERROR_INVALID_ARGUMENT;
return nullptr;
}
if (udpEndPointManager == nullptr)
{
ChipLogError(Controller, "Missing UDP 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
// TODO: Replace testingRootStore with a AttestationTrustStore that has the necessary official PAA roots available
const chip::Credentials::AttestationTrustStore * testingRootStore = chip::Credentials::GetTestAttestationTrustStore();
SetDeviceAttestationVerifier(GetDefaultDACVerifier(testingRootStore));
chip::Controller::FactoryInitParams initParams;
chip::Controller::SetupParams setupParams;
initParams.systemLayer = systemLayer;
initParams.tcpEndPointManager = tcpEndPointManager;
initParams.udpEndPointManager = udpEndPointManager;
initParams.fabricStorage = wrapper.get();
// move bleLayer into platform/android to share with app server
#if CONFIG_NETWORK_LAYER_BLE
initParams.bleLayer = DeviceLayer::ConnectivityMgr().GetBleLayer();
#endif
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;
}
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);
};