diff --git a/src/controller/java/AndroidDeviceControllerWrapper.cpp b/src/controller/java/AndroidDeviceControllerWrapper.cpp index a178d8b5c645bd..b206e9ea103161 100644 --- a/src/controller/java/AndroidDeviceControllerWrapper.cpp +++ b/src/controller/java/AndroidDeviceControllerWrapper.cpp @@ -39,8 +39,6 @@ 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)) @@ -62,122 +60,12 @@ void AndroidDeviceControllerWrapper::CallJavaMethod(const char * methodName, jin argument); } -CHIP_ERROR AndroidDeviceControllerWrapper::GenerateNOCChainAfterValidation(NodeId nodeId, FabricId fabricId, - const Crypto::P256PublicKey & pubkey, - MutableByteSpan & rcac, MutableByteSpan & icac, - MutableByteSpan & noc) -{ - ChipDN noc_dn; - noc_dn.AddAttribute(chip::ASN1::kOID_AttributeType_ChipFabricId, fabricId); - noc_dn.AddAttribute(chip::ASN1::kOID_AttributeType_ChipNodeId, nodeId); - ChipDN rcac_dn; - rcac_dn.AddAttribute(chip::ASN1::kOID_AttributeType_ChipRootId, mIssuerId); - rcac_dn.AddAttribute(chip::ASN1::kOID_AttributeType_ChipFabricId, fabricId); - - ChipLogProgress(Controller, "Generating NOC"); - chip::Credentials::X509CertRequestParams noc_request = { 1, mNow, mNow + mValidity, noc_dn, rcac_dn }; - ReturnErrorOnFailure(NewNodeOperationalX509Cert(noc_request, pubkey, mIssuer, noc)); - icac.reduce_size(0); - - uint16_t rcacBufLen = static_cast(std::min(rcac.size(), static_cast(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, mNow, mNow + mValidity, rcac_dn, rcac_dn }; - ReturnErrorOnFailure(NewRootX509Cert(rcac_request, mIssuer, rcac)); - - VerifyOrReturnError(CanCastTo(rcac.size()), CHIP_ERROR_INTERNAL); - PERSISTENT_KEY_OP(fabricId, kOperationalCredentialsRootCertificateStorage, key, - err = SyncSetKeyValue(key, rcac.data(), static_cast(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 * 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 noc; - ReturnErrorCodeIf(!noc.Alloc(kMaxCHIPDERCertLength), CHIP_ERROR_NO_MEMORY); - MutableByteSpan nocSpan(noc.Get(), kMaxCHIPDERCertLength); - - Platform::ScopedMemoryBuffer 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, Optional(), - Optional()); - - 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 * tcpEndPointManager, - chip::Inet::EndPointManager * udpEndPointManager, CHIP_ERROR * errInfoOnFailure) +AndroidDeviceControllerWrapper * +AndroidDeviceControllerWrapper::AllocateNew(JavaVM * vm, jobject deviceControllerObj, chip::NodeId nodeId, + chip::System::Layer * systemLayer, + chip::Inet::EndPointManager * tcpEndPointManager, + chip::Inet::EndPointManager * udpEndPointManager, + AndroidOperationalCredentialsIssuerPtr opCredsIssuerPtr, CHIP_ERROR * errInfoOnFailure) { if (errInfoOnFailure == nullptr) { @@ -212,10 +100,13 @@ AndroidDeviceControllerWrapper * AndroidDeviceControllerWrapper::AllocateNew( *errInfoOnFailure = CHIP_ERROR_NO_MEMORY; return nullptr; } - std::unique_ptr wrapper(new AndroidDeviceControllerWrapper(std::move(controller))); + std::unique_ptr wrapper( + new AndroidDeviceControllerWrapper(std::move(controller), std::move(opCredsIssuerPtr))); wrapper->SetJavaObjectRef(vm, deviceControllerObj); + chip::Controller::AndroidOperationalCredentialsIssuer * opCredsIssuer = wrapper->mOpCredsIssuer.get(); + // 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(); @@ -235,9 +126,9 @@ AndroidDeviceControllerWrapper * AndroidDeviceControllerWrapper::AllocateNew( initParams.listenPort = CHIP_PORT + 1; setupParams.storageDelegate = wrapper.get(); setupParams.pairingDelegate = wrapper.get(); - setupParams.operationalCredentialsDelegate = wrapper.get(); + setupParams.operationalCredentialsDelegate = opCredsIssuer; - wrapper->InitializeOperationalCredentialsIssuer(); + opCredsIssuer->Initialize(*wrapper.get(), wrapper.get()->mJavaObjectRef); Platform::ScopedMemoryBuffer noc; if (!noc.Alloc(kMaxCHIPDERCertLength)) @@ -247,7 +138,14 @@ AndroidDeviceControllerWrapper * AndroidDeviceControllerWrapper::AllocateNew( } MutableByteSpan nocSpan(noc.Get(), kMaxCHIPDERCertLength); - MutableByteSpan icacSpan; + Platform::ScopedMemoryBuffer icac; + if (!icac.Alloc(kMaxCHIPDERCertLength)) + { + *errInfoOnFailure = CHIP_ERROR_NO_MEMORY; + return nullptr; + } + + MutableByteSpan icacSpan(icac.Get(), kMaxCHIPDERCertLength); Platform::ScopedMemoryBuffer rcac; if (!rcac.Alloc(kMaxCHIPDERCertLength)) @@ -264,7 +162,8 @@ AndroidDeviceControllerWrapper * AndroidDeviceControllerWrapper::AllocateNew( return nullptr; } - *errInfoOnFailure = wrapper->GenerateNOCChainAfterValidation(nodeId, 0, ephemeralKey.Pubkey(), rcacSpan, icacSpan, nocSpan); + *errInfoOnFailure = + opCredsIssuer->GenerateNOCChainAfterValidation(nodeId, 0, ephemeralKey.Pubkey(), rcacSpan, icacSpan, nocSpan); if (*errInfoOnFailure != CHIP_NO_ERROR) { return nullptr; @@ -404,31 +303,6 @@ void AndroidDeviceControllerWrapper::OnCommissioningComplete(NodeId deviceId, CH } } -CHIP_ERROR AndroidDeviceControllerWrapper::InitializeOperationalCredentialsIssuer() -{ - chip::Crypto::P256SerializedKeypair serializedKey; - uint16_t keySize = static_cast(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(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); diff --git a/src/controller/java/AndroidDeviceControllerWrapper.h b/src/controller/java/AndroidDeviceControllerWrapper.h index bddf910a077c7a..63d7cf639eb38e 100644 --- a/src/controller/java/AndroidDeviceControllerWrapper.h +++ b/src/controller/java/AndroidDeviceControllerWrapper.h @@ -24,10 +24,11 @@ #include #include -#include #include #include +#include "AndroidOperationalCredentialsIssuer.h" + /** * This class contains all relevant information for the JNI view of CHIPDeviceController * to handle all controller-related processing. @@ -35,7 +36,6 @@ * Generally it contains the DeviceController class itself, plus any related delegates/callbacks. */ class AndroidDeviceControllerWrapper : public chip::Controller::DevicePairingDelegate, - public chip::Controller::OperationalCredentialsDelegate, public chip::PersistentStorageDelegate, public chip::FabricStorage { @@ -61,19 +61,6 @@ class AndroidDeviceControllerWrapper : public chip::Controller::DevicePairingDel void OnPairingDeleted(CHIP_ERROR error) override; void OnCommissioningComplete(chip::NodeId deviceId, CHIP_ERROR error) override; - // OperationalCredentialsDelegate implementation - CHIP_ERROR GenerateNOCChain(const chip::ByteSpan & csrElements, const chip::ByteSpan & attestationSignature, - const chip::ByteSpan & DAC, const chip::ByteSpan & PAI, const chip::ByteSpan & PAA, - chip::Callback::Callback * onCompletion) override; - - void SetNodeIdForNextNOCRequest(chip::NodeId nodeId) override - { - mNextRequestedNodeId = nodeId; - mNodeIdRequested = true; - } - - void SetFabricIdForNextNOCRequest(chip::FabricId fabricId) override { mNextFabricId = fabricId; } - // PersistentStorageDelegate implementation CHIP_ERROR SyncSetKeyValue(const char * key, const void * value, uint16_t size) override; CHIP_ERROR SyncGetKeyValue(const char * key, void * buffer, uint16_t & size) override; @@ -89,36 +76,24 @@ class AndroidDeviceControllerWrapper : public chip::Controller::DevicePairingDel return reinterpret_cast(handle); } + using AndroidOperationalCredentialsIssuerPtr = std::unique_ptr; + static AndroidDeviceControllerWrapper * AllocateNew(JavaVM * vm, jobject deviceControllerObj, chip::NodeId nodeId, chip::System::Layer * systemLayer, chip::Inet::EndPointManager * tcpEndPointManager, chip::Inet::EndPointManager * udpEndPointManager, + AndroidOperationalCredentialsIssuerPtr opCredsIssuer, CHIP_ERROR * errInfoOnFailure); - CHIP_ERROR GenerateNOCChainAfterValidation(chip::NodeId nodeId, chip::FabricId fabricId, - const chip::Crypto::P256PublicKey & ephemeralKey, chip::MutableByteSpan & rcac, - chip::MutableByteSpan & icac, chip::MutableByteSpan & noc); - private: using ChipDeviceControllerPtr = std::unique_ptr; - chip::Crypto::P256Keypair mIssuer; - bool mInitialized = false; - uint32_t mIssuerId = 0; - uint32_t mNow = 0; - uint32_t mValidity = 10 * chip::kSecondsPerStandardYear; ChipDeviceControllerPtr mController; - chip::Controller::ExampleOperationalCredentialsIssuer mOpCredsIssuer; + AndroidOperationalCredentialsIssuerPtr mOpCredsIssuer; JavaVM * mJavaVM = nullptr; jobject mJavaObjectRef = nullptr; - chip::NodeId mNextAvailableNodeId = 1; - - chip::NodeId mNextRequestedNodeId = 1; - chip::FabricId mNextFabricId = 0; - bool mNodeIdRequested = false; - // These fields allow us to release the string/byte array memory later. jstring ssidStr = nullptr; jstring passwordStr = nullptr; @@ -127,10 +102,9 @@ class AndroidDeviceControllerWrapper : public chip::Controller::DevicePairingDel jbyteArray operationalDatasetBytes = nullptr; jbyte * operationalDataset = nullptr; - AndroidDeviceControllerWrapper(ChipDeviceControllerPtr controller) : mController(std::move(controller)) - { - chip::CalendarToChipEpochTime(2021, 06, 10, 0, 0, 0, mNow); - } + AndroidDeviceControllerWrapper(ChipDeviceControllerPtr controller, AndroidOperationalCredentialsIssuerPtr opCredsIssuer) : + mController(std::move(controller)), mOpCredsIssuer(std::move(opCredsIssuer)) + {} }; inline jlong AndroidDeviceControllerWrapper::ToJNIHandle() diff --git a/src/controller/java/AndroidOperationalCredentialsIssuer.cpp b/src/controller/java/AndroidOperationalCredentialsIssuer.cpp new file mode 100644 index 00000000000000..7a6bdf23f29349 --- /dev/null +++ b/src/controller/java/AndroidOperationalCredentialsIssuer.cpp @@ -0,0 +1,189 @@ +/* + * + * Copyright (c) 2021-2022 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 "AndroidOperationalCredentialsIssuer.h" +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +namespace chip { +namespace Controller { +constexpr const char kOperationalCredentialsIssuerKeypairStorage[] = "AndroidDeviceControllerKey"; +constexpr const char kOperationalCredentialsRootCertificateStorage[] = "AndroidCARootCert"; + +using namespace Credentials; +using namespace Crypto; +using namespace TLV; + +CHIP_ERROR AndroidOperationalCredentialsIssuer::Initialize(PersistentStorageDelegate & storage, jobject javaObjectRef) +{ + using namespace ASN1; + ASN1UniversalTime effectiveTime; + + // Initializing the default start validity to start of 2021. The default validity duration is 10 years. + CHIP_ZERO_AT(effectiveTime); + effectiveTime.Year = 2021; + effectiveTime.Month = 6; + effectiveTime.Day = 10; + ReturnErrorOnFailure(ASN1ToChipEpochTime(effectiveTime, mNow)); + + Crypto::P256SerializedKeypair serializedKey; + uint16_t keySize = static_cast(sizeof(serializedKey)); + + if (storage.SyncGetKeyValue(kOperationalCredentialsIssuerKeypairStorage, &serializedKey, keySize) != CHIP_NO_ERROR) + { + // Storage doesn't have an existing keypair. Let's create one and add it to the storage. + ReturnErrorOnFailure(mIssuer.Initialize()); + ReturnErrorOnFailure(mIssuer.Serialize(serializedKey)); + + keySize = static_cast(sizeof(serializedKey)); + ReturnErrorOnFailure(storage.SyncSetKeyValue(kOperationalCredentialsIssuerKeypairStorage, &serializedKey, keySize)); + } + else + { + // Use the keypair from the storage + ReturnErrorOnFailure(mIssuer.Deserialize(serializedKey)); + } + + mStorage = &storage; + mJavaObjectRef = javaObjectRef; + + mInitialized = true; + return CHIP_NO_ERROR; +} + +CHIP_ERROR AndroidOperationalCredentialsIssuer::GenerateNOCChainAfterValidation(NodeId nodeId, FabricId fabricId, + const Crypto::P256PublicKey & pubkey, + MutableByteSpan & rcac, MutableByteSpan & icac, + MutableByteSpan & noc) +{ + ChipDN noc_dn; + noc_dn.AddAttribute(chip::ASN1::kOID_AttributeType_ChipFabricId, fabricId); + noc_dn.AddAttribute(chip::ASN1::kOID_AttributeType_ChipNodeId, nodeId); + ChipDN rcac_dn; + rcac_dn.AddAttribute(chip::ASN1::kOID_AttributeType_ChipRootId, mIssuerId); + + ChipLogProgress(Controller, "Generating NOC"); + chip::Credentials::X509CertRequestParams noc_request = { 1, mNow, mNow + mValidity, noc_dn, rcac_dn }; + ReturnErrorOnFailure(NewNodeOperationalX509Cert(noc_request, pubkey, mIssuer, noc)); + icac.reduce_size(0); + + uint16_t rcacBufLen = static_cast(std::min(rcac.size(), static_cast(UINT16_MAX))); + CHIP_ERROR err = CHIP_NO_ERROR; + PERSISTENT_KEY_OP(fabricId, kOperationalCredentialsRootCertificateStorage, key, + err = mStorage->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, mNow, mNow + mValidity, rcac_dn, rcac_dn }; + ReturnErrorOnFailure(NewRootX509Cert(rcac_request, mIssuer, rcac)); + + VerifyOrReturnError(CanCastTo(rcac.size()), CHIP_ERROR_INTERNAL); + PERSISTENT_KEY_OP(fabricId, kOperationalCredentialsRootCertificateStorage, key, + err = mStorage->SyncSetKeyValue(key, rcac.data(), static_cast(rcac.size()))); + + return err; +} + +CHIP_ERROR AndroidOperationalCredentialsIssuer::GenerateNOCChain(const ByteSpan & csrElements, + const ByteSpan & attestationSignature, const ByteSpan & DAC, + const ByteSpan & PAI, const ByteSpan & PAA, + Callback::Callback * 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 noc; + ReturnErrorCodeIf(!noc.Alloc(kMaxCHIPDERCertLength), CHIP_ERROR_NO_MEMORY); + MutableByteSpan nocSpan(noc.Get(), kMaxCHIPDERCertLength); + + Platform::ScopedMemoryBuffer 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, Optional(), + Optional()); + + 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; +} + +} // namespace Controller +} // namespace chip diff --git a/src/controller/java/AndroidOperationalCredentialsIssuer.h b/src/controller/java/AndroidOperationalCredentialsIssuer.h new file mode 100644 index 00000000000000..2365af6e6c4b1d --- /dev/null +++ b/src/controller/java/AndroidOperationalCredentialsIssuer.h @@ -0,0 +1,107 @@ +/* + * + * Copyright (c) 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. + */ + +/** + * @file + * This file contains class definition of an example operational certificate + * issuer for CHIP devices. The class can be used as a guideline on how to + * construct your own certificate issuer. It can also be used in tests and tools + * if a specific signing authority is not required. + * + * NOTE: This class stores the encryption key in clear storage. This is not suited + * for production use. This should only be used in test tools. + */ + +#pragma once + +#include +#include +#include +#include +#include +#include + +#include + +namespace chip { +namespace Controller { + +class DLL_EXPORT AndroidOperationalCredentialsIssuer : public OperationalCredentialsDelegate +{ +public: + virtual ~AndroidOperationalCredentialsIssuer() {} + + CHIP_ERROR GenerateNOCChain(const ByteSpan & csrElements, const ByteSpan & attestationSignature, const ByteSpan & DAC, + const ByteSpan & PAI, const ByteSpan & PAA, + Callback::Callback * onCompletion) override; + + void SetNodeIdForNextNOCRequest(NodeId nodeId) override + { + mNextRequestedNodeId = nodeId; + mNodeIdRequested = true; + } + + void SetFabricIdForNextNOCRequest(FabricId fabricId) override { mNextFabricId = fabricId; } + + /** + * @brief Initialize the issuer with the keypair in the storage. + * If the storage doesn't have one, it'll create one, and it to the storage. + * + * @param[in] storage A reference to the storage, where the keypair is stored. + * The object of ExampleOperationalCredentialsIssuer doesn't hold + * on the reference of storage. + * + * @return Returns a CHIP_ERROR on error, CHIP_NO_ERROR otherwise + **/ + CHIP_ERROR Initialize(PersistentStorageDelegate & storage, jobject javaObjectRef); + + void SetIssuerId(uint32_t id) { mIssuerId = id; } + + void SetCurrentEpoch(uint32_t epoch) { mNow = epoch; } + + void SetCertificateValidityPeriod(uint32_t validity) { mValidity = validity; } + + /** + * This is a utility method that generates a operational certificate chain for the given public key. + * This method is expected to be called once all the checks (e.g. device attestation, CSR verification etc) + * have been completed, or not required (e.g. for self trusted devices such as commissioner apps). + */ + CHIP_ERROR GenerateNOCChainAfterValidation(NodeId nodeId, FabricId fabricId, const Crypto::P256PublicKey & pubkey, + MutableByteSpan & rcac, MutableByteSpan & icac, MutableByteSpan & noc); + +private: + Crypto::P256Keypair mIssuer; + bool mInitialized = false; + uint32_t mIssuerId = 0; + uint32_t mNow = 0; + + // By default, let's set validity to 10 years + uint32_t mValidity = 365 * 24 * 60 * 60 * 10; + + NodeId mNextAvailableNodeId = 1; + PersistentStorageDelegate * mStorage = nullptr; + + NodeId mNextRequestedNodeId = 1; + FabricId mNextFabricId = 0; + bool mNodeIdRequested = false; + + jobject mJavaObjectRef = nullptr; +}; + +} // namespace Controller +} // namespace chip diff --git a/src/controller/java/BUILD.gn b/src/controller/java/BUILD.gn index c8855ed02a75ab..0761d514783953 100644 --- a/src/controller/java/BUILD.gn +++ b/src/controller/java/BUILD.gn @@ -28,6 +28,8 @@ shared_library("jni") { "AndroidClusterExceptions.h", "AndroidDeviceControllerWrapper.cpp", "AndroidDeviceControllerWrapper.h", + "AndroidOperationalCredentialsIssuer.cpp", + "AndroidOperationalCredentialsIssuer.h", "CHIPAttributeTLVValueDecoder.h", "CHIPDefaultCallbacks.cpp", "CHIPDefaultCallbacks.h", diff --git a/src/controller/java/CHIPDeviceController-JNI.cpp b/src/controller/java/CHIPDeviceController-JNI.cpp index 09a79d386677cf..a8009467e41ab4 100644 --- a/src/controller/java/CHIPDeviceController-JNI.cpp +++ b/src/controller/java/CHIPDeviceController-JNI.cpp @@ -154,10 +154,11 @@ JNI_METHOD(jlong, newDeviceController)(JNIEnv * env, jobject self) long result = 0; ChipLogProgress(Controller, "newDeviceController() called"); - - wrapper = - AndroidDeviceControllerWrapper::AllocateNew(sJVM, self, kLocalDeviceId, &DeviceLayer::SystemLayer(), - DeviceLayer::TCPEndPointManager(), DeviceLayer::UDPEndPointManager(), &err); + std::unique_ptr opCredsIssuer( + new chip::Controller::AndroidOperationalCredentialsIssuer()); + wrapper = AndroidDeviceControllerWrapper::AllocateNew(sJVM, self, kLocalDeviceId, &DeviceLayer::SystemLayer(), + DeviceLayer::TCPEndPointManager(), DeviceLayer::UDPEndPointManager(), + std::move(opCredsIssuer), &err); SuccessOrExit(err); // Create and start the IO thread. Must be called after Controller()->Init