Persist keypair used by example opcert signer (#6821)

* Persist keypair used by example opcert signer

* Fix Android build
diff --git a/examples/chip-tool/commands/clusters/ModelCommand.cpp b/examples/chip-tool/commands/clusters/ModelCommand.cpp
index 0bd0f29..c556197 100644
--- a/examples/chip-tool/commands/clusters/ModelCommand.cpp
+++ b/examples/chip-tool/commands/clusters/ModelCommand.cpp
@@ -41,10 +41,12 @@
 {
     CHIP_ERROR err = CHIP_NO_ERROR;
 
-    mOpCredsIssuer.Initialize();
-
     chip::Controller::CommissionerInitParams initParams;
-    initParams.storageDelegate                = &storage;
+    initParams.storageDelegate = &storage;
+
+    err = mOpCredsIssuer.Initialize(storage);
+    VerifyOrExit(err == CHIP_NO_ERROR, ChipLogError(Controller, "Init failure! Operational Cred Issuer: %s", ErrorStr(err)));
+
     initParams.operationalCredentialsDelegate = &mOpCredsIssuer;
 
     err = mCommissioner.SetUdpListenPort(storage.GetListenPort());
diff --git a/examples/chip-tool/commands/pairing/PairingCommand.cpp b/examples/chip-tool/commands/pairing/PairingCommand.cpp
index 7521c39..ff54619 100644
--- a/examples/chip-tool/commands/pairing/PairingCommand.cpp
+++ b/examples/chip-tool/commands/pairing/PairingCommand.cpp
@@ -31,12 +31,14 @@
 {
     CHIP_ERROR err = CHIP_NO_ERROR;
 
-    mOpCredsIssuer.Initialize();
-
     chip::Controller::CommissionerInitParams params;
-    params.storageDelegate                = &storage;
-    params.mDeviceAddressUpdateDelegate   = this;
-    params.pairingDelegate                = this;
+    params.storageDelegate              = &storage;
+    params.mDeviceAddressUpdateDelegate = this;
+    params.pairingDelegate              = this;
+
+    err = mOpCredsIssuer.Initialize(storage);
+    VerifyOrExit(err == CHIP_NO_ERROR, ChipLogError(Controller, "Init failure! Operational Cred Issuer: %s", ErrorStr(err)));
+
     params.operationalCredentialsDelegate = &mOpCredsIssuer;
 
     err = mCommissioner.SetUdpListenPort(storage.GetListenPort());
diff --git a/examples/chip-tool/commands/pairing/PairingCommand.h b/examples/chip-tool/commands/pairing/PairingCommand.h
index 871186e..d5e1222 100644
--- a/examples/chip-tool/commands/pairing/PairingCommand.h
+++ b/examples/chip-tool/commands/pairing/PairingCommand.h
@@ -93,7 +93,6 @@
             AddArgument("device-remote-port", 0, UINT16_MAX, &mRemotePort);
             break;
         }
-        mOpCredsIssuer.Initialize();
     }
 
     /////////// Command Interface /////////
diff --git a/examples/chip-tool/commands/reporting/ReportingCommand.cpp b/examples/chip-tool/commands/reporting/ReportingCommand.cpp
index 29d43c7..447c1c8 100644
--- a/examples/chip-tool/commands/reporting/ReportingCommand.cpp
+++ b/examples/chip-tool/commands/reporting/ReportingCommand.cpp
@@ -32,12 +32,14 @@
 {
     CHIP_ERROR err = CHIP_NO_ERROR;
 
-    mOpCredsIssuer.Initialize();
-
     chip::Controller::BasicCluster cluster;
     chip::Controller::CommissionerInitParams initParams;
 
-    initParams.storageDelegate                = &storage;
+    initParams.storageDelegate = &storage;
+
+    err = mOpCredsIssuer.Initialize(storage);
+    VerifyOrExit(err == CHIP_NO_ERROR, ChipLogError(Controller, "Init failure! Operational Cred Issuer: %s", ErrorStr(err)));
+
     initParams.operationalCredentialsDelegate = &mOpCredsIssuer;
 
     err = mCommissioner.SetUdpListenPort(storage.GetListenPort());
diff --git a/src/controller/ExampleOperationalCredentialsIssuer.cpp b/src/controller/ExampleOperationalCredentialsIssuer.cpp
index f0680b1..88da5d8 100644
--- a/src/controller/ExampleOperationalCredentialsIssuer.cpp
+++ b/src/controller/ExampleOperationalCredentialsIssuer.cpp
@@ -22,9 +22,35 @@
 namespace chip {
 namespace Controller {
 
+constexpr const char kOperationalCredentialsIssuerKeypairStorage[] = "ExampleOpCredsCAKey";
+
 using namespace Credentials;
 using namespace Crypto;
 
+CHIP_ERROR ExampleOperationalCredentialsIssuer::Initialize(PersistentStorageDelegate & storage)
+{
+    Crypto::P256SerializedKeypair serializedKey;
+    uint16_t keySize = static_cast<uint16_t>(serializedKey.Capacity());
+
+    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<uint16_t>(serializedKey.Length());
+        ReturnErrorOnFailure(storage.SyncSetKeyValue(kOperationalCredentialsIssuerKeypairStorage, serializedKey, keySize));
+    }
+    else
+    {
+        // Use the keypair from the storage
+        ReturnErrorOnFailure(mIssuer.Deserialize(serializedKey));
+    }
+
+    mInitialized = true;
+    return CHIP_NO_ERROR;
+}
+
 CHIP_ERROR ExampleOperationalCredentialsIssuer::GenerateNodeOperationalCertificate(const PeerId & peerId, const ByteSpan & csr,
                                                                                    int64_t serialNumber, uint8_t * certBuf,
                                                                                    uint32_t certBufSize, uint32_t & outCertLen)
diff --git a/src/controller/ExampleOperationalCredentialsIssuer.h b/src/controller/ExampleOperationalCredentialsIssuer.h
index 00eba94..a8ae6a8 100644
--- a/src/controller/ExampleOperationalCredentialsIssuer.h
+++ b/src/controller/ExampleOperationalCredentialsIssuer.h
@@ -22,12 +22,16 @@
  *    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 <controller/OperationalCredentialsDelegate.h>
 #include <core/CHIPError.h>
+#include <core/CHIPPersistentStorageDelegate.h>
 #include <crypto/CHIPCryptoPAL.h>
 #include <support/CodeUtils.h>
 
@@ -45,36 +49,17 @@
     CHIP_ERROR GetRootCACertificate(FabricId fabricId, uint8_t * certBuf, uint32_t certBufSize, uint32_t & outCertLen) override;
 
     /**
-     * @brief Serialize the issuer's keypair.
+     * @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 Serialize(Crypto::P256SerializedKeypair & issuer)
-    {
-        VerifyOrReturnError(mInitialized, CHIP_ERROR_INCORRECT_STATE);
-        return mIssuer.Serialize(issuer);
-    }
-
-    /**
-     * @brief Deserialize the keypair as issuer's keypair.
-     * @return Returns a CHIP_ERROR on error, CHIP_NO_ERROR otherwise
-     **/
-    CHIP_ERROR Deserialize(Crypto::P256SerializedKeypair & issuer)
-    {
-        ReturnErrorOnFailure(mIssuer.Deserialize(issuer));
-        mInitialized = true;
-        return CHIP_NO_ERROR;
-    }
-
-    /**
-     * @brief Initialize the issuer with a new keypair.
-     * @return Returns a CHIP_ERROR on error, CHIP_NO_ERROR otherwise
-     **/
-    CHIP_ERROR Initialize()
-    {
-        ReturnErrorOnFailure(mIssuer.Initialize());
-        mInitialized = true;
-        return CHIP_NO_ERROR;
-    }
+    [[deprecated("This class stores the encryption key in clear storage. Don't use it for production code.")]] CHIP_ERROR
+    Initialize(PersistentStorageDelegate & storage);
 
     void SetIssuerId(uint32_t id) { mIssuerId = id; }
 
diff --git a/src/controller/java/AndroidDeviceControllerWrapper.cpp b/src/controller/java/AndroidDeviceControllerWrapper.cpp
index bb061f5..f40e519 100644
--- a/src/controller/java/AndroidDeviceControllerWrapper.cpp
+++ b/src/controller/java/AndroidDeviceControllerWrapper.cpp
@@ -143,7 +143,7 @@
     initParams.inetLayer       = inetLayer;
     initParams.bleLayer        = GetJNIBleLayer();
 
-    *errInfoOnFailure = wrapper->OpCredsIssuer().Initialize();
+    *errInfoOnFailure = wrapper->OpCredsIssuer().Initialize(*initParams.storageDelegate);
     if (*errInfoOnFailure != CHIP_NO_ERROR)
     {
         return nullptr;
diff --git a/src/controller/python/ChipDeviceController-ScriptBinding.cpp b/src/controller/python/ChipDeviceController-ScriptBinding.cpp
index dcc5f3e..f497c37 100644
--- a/src/controller/python/ChipDeviceController-ScriptBinding.cpp
+++ b/src/controller/python/ChipDeviceController-ScriptBinding.cpp
@@ -143,7 +143,7 @@
         localDeviceId = kDefaultLocalDeviceId;
     }
 
-    ReturnErrorOnFailure(sOperationalCredentialsIssuer.Initialize());
+    ReturnErrorOnFailure(sOperationalCredentialsIssuer.Initialize(sStorageDelegate));
 
     initParams.storageDelegate                = &sStorageDelegate;
     initParams.mDeviceAddressUpdateDelegate   = &sDeviceAddressUpdateDelegate;
diff --git a/src/controller/python/chip/internal/CommissionerImpl.cpp b/src/controller/python/chip/internal/CommissionerImpl.cpp
index bc1b7c6..0f72231 100644
--- a/src/controller/python/chip/internal/CommissionerImpl.cpp
+++ b/src/controller/python/chip/internal/CommissionerImpl.cpp
@@ -101,8 +101,7 @@
         params.inetLayer       = &chip::DeviceLayer::InetLayer;
         params.pairingDelegate = &gPairingDelegate;
 
-        err = gOperationalCredentialsIssuer.Initialize();
-
+        err = gOperationalCredentialsIssuer.Initialize(gServerStorage);
         if (err != CHIP_NO_ERROR)
         {
             ChipLogError(Controller, "Operational credentials issuer initialization failed: %s", chip::ErrorStr(err));