HSM key store to handle AddNOC / UpdateNOC (#21667)

* draft code for hsm integration in key store

* updated crypto build file

* updated keystore hsm file

* updated keystore file

* code cleanup

* code cleanup

* restyler

* using hsm util file

* bug fixes

* removed hsm key store. Will be moved to application specific code.

* reseting pending slot

* restyler

* review comments - update

* draft code for hsm integration in key store

* updated crypto build file

* updated keystore hsm file

* updated keystore file

* code cleanup

* code cleanup

* restyler

* using hsm util file

* bug fixes

* removed hsm key store. Will be moved to application specific code.

* reseting pending slot

* restyler

* review comments - update

* review comments - updated

* declaring variable where it is used
diff --git a/src/credentials/FabricTable.cpp b/src/credentials/FabricTable.cpp
index 5814f91..1bb3b8b 100644
--- a/src/credentials/FabricTable.cpp
+++ b/src/credentials/FabricTable.cpp
@@ -28,9 +28,6 @@
 #include <lib/support/DefaultStorageKeyAllocator.h>
 #include <lib/support/SafeInt.h>
 #include <lib/support/ScopedBuffer.h>
-#if CHIP_CRYPTO_HSM
-#include <crypto/hsm/CHIPCryptoPALHsm.h>
-#endif
 
 namespace chip {
 using namespace Credentials;
@@ -257,11 +254,7 @@
 
     if (mOperationalKey == nullptr)
     {
-#ifdef ENABLE_HSM_CASE_OPS_KEY
-        mOperationalKey = chip::Platform::New<P256KeypairHSM>();
-#else
         mOperationalKey = chip::Platform::New<P256Keypair>();
-#endif
     }
     VerifyOrReturnError(mOperationalKey != nullptr, CHIP_ERROR_NO_MEMORY);
     return mOperationalKey->Deserialize(serialized);
diff --git a/src/credentials/FabricTable.h b/src/credentials/FabricTable.h
index d5c3a39..7dbc84c 100644
--- a/src/credentials/FabricTable.h
+++ b/src/credentials/FabricTable.h
@@ -230,13 +230,8 @@
 
     VendorId mVendorId                                  = VendorId::NotSpecified;
     char mFabricLabel[kFabricLabelMaxLengthInBytes + 1] = { '\0' };
-
-#ifdef ENABLE_HSM_CASE_OPS_KEY
-    mutable Crypto::P256KeypairHSM * mOperationalKey = nullptr;
-#else
-    mutable Crypto::P256Keypair * mOperationalKey = nullptr;
-#endif
-    bool mHasExternallyOwnedOperationalKey = false;
+    mutable Crypto::P256Keypair * mOperationalKey       = nullptr;
+    bool mHasExternallyOwnedOperationalKey              = false;
 
     CHIP_ERROR CommitToStorage(PersistentStorageDelegate * storage) const;
     CHIP_ERROR LoadFromStorage(PersistentStorageDelegate * storage, FabricIndex newFabricIndex, const ByteSpan & rcac,
diff --git a/src/crypto/BUILD.gn b/src/crypto/BUILD.gn
index 61672d3..e06ab28 100644
--- a/src/crypto/BUILD.gn
+++ b/src/crypto/BUILD.gn
@@ -167,6 +167,8 @@
       "hsm/nxp/CHIPCryptoPALHsm_SE05X_PBKDF.cpp",
       "hsm/nxp/CHIPCryptoPALHsm_SE05X_Spake2p.cpp",
       "hsm/nxp/CHIPCryptoPALHsm_SE05X_utils.cpp",
+      "hsm/nxp/PersistentStorageOperationalKeystoreHSM.cpp",
+      "hsm/nxp/PersistentStorageOperationalKeystoreHSM.h",
     ]
     public_deps += [ "${chip_root}/third_party/simw-top-mini:se05x" ]
     public_configs += [ "${chip_root}/third_party/simw-top-mini:se05x_config" ]
diff --git a/src/crypto/hsm/CHIPCryptoPALHsm.h b/src/crypto/hsm/CHIPCryptoPALHsm.h
index 0b1c0a9..a1212da 100644
--- a/src/crypto/hsm/CHIPCryptoPALHsm.h
+++ b/src/crypto/hsm/CHIPCryptoPALHsm.h
@@ -145,8 +145,6 @@
 
     uint32_t GetKeyId(void) { return keyid; }
 
-    CHIP_ERROR CreateOperationalKey(FabricIndex fabricIdx);
-
 private:
     uint32_t keyid;
     P256PublicKeyHSM mPublicKeyHSM;
diff --git a/src/crypto/hsm/CHIPCryptoPALHsm_config.h b/src/crypto/hsm/CHIPCryptoPALHsm_config.h
index 7a4bd41..1c3b611 100644
--- a/src/crypto/hsm/CHIPCryptoPALHsm_config.h
+++ b/src/crypto/hsm/CHIPCryptoPALHsm_config.h
@@ -25,7 +25,7 @@
 /*
  * Enable HSM for SPAKE VERIFIER
  */
-#define ENABLE_HSM_SPAKE_VERIFIER 0
+#define ENABLE_HSM_SPAKE_VERIFIER 1
 
 /*
  * Enable HSM for SPAKE PROVER
@@ -58,8 +58,6 @@
 
 #if ((CHIP_CRYPTO_HSM) && (ENABLE_HSM_GENERATE_EC_KEY))
 #define ENABLE_HSM_EC_KEY
-#define ENABLE_HSM_CASE_EPHEMERAL_KEY
-//#define ENABLE_HSM_CASE_OPS_KEY
 //#define ENABLE_HSM_ECDSA_VERIFY
 #endif
 
diff --git a/src/crypto/hsm/nxp/CHIPCryptoPALHsm_SE05X_P256.cpp b/src/crypto/hsm/nxp/CHIPCryptoPALHsm_SE05X_P256.cpp
index 1007ba2..0d27c5a 100644
--- a/src/crypto/hsm/nxp/CHIPCryptoPALHsm_SE05X_P256.cpp
+++ b/src/crypto/hsm/nxp/CHIPCryptoPALHsm_SE05X_P256.cpp
@@ -693,19 +693,6 @@
     return error;
 }
 
-CHIP_ERROR P256KeypairHSM::CreateOperationalKey(FabricIndex fabricIdx)
-{
-    (void) fabricIdx;
-    // TBD - Map fabric index to operational keys
-    SetKeyId(kKeyId_operational_key_keyid);
-    if (Initialize() == CHIP_NO_ERROR)
-    {
-        provisioned_key = true;
-        return CHIP_NO_ERROR;
-    }
-    return CHIP_ERROR_INTERNAL;
-}
-
 } // namespace Crypto
 } // namespace chip
 
diff --git a/src/crypto/hsm/nxp/CHIPCryptoPALHsm_SE05X_Spake2p.cpp b/src/crypto/hsm/nxp/CHIPCryptoPALHsm_SE05X_Spake2p.cpp
index f62691d..346ff83 100644
--- a/src/crypto/hsm/nxp/CHIPCryptoPALHsm_SE05X_Spake2p.cpp
+++ b/src/crypto/hsm/nxp/CHIPCryptoPALHsm_SE05X_Spake2p.cpp
@@ -27,13 +27,13 @@
 #if ((ENABLE_HSM_SPAKE_VERIFIER) || (ENABLE_HSM_SPAKE_PROVER))
 
 #if ENABLE_HSM_SPAKE_VERIFIER
-const uint32_t w0in_id_v = 0x2347;
-const uint32_t Lin_id_v  = 0x2348;
+const uint32_t w0in_id_v = 0x7D200001;
+const uint32_t Lin_id_v  = 0x7D200002;
 #endif
 
 #if ENABLE_HSM_SPAKE_PROVER
-const uint32_t w0in_id_p = 0x2349;
-const uint32_t w1in_id_p = 0x2350;
+const uint32_t w0in_id_p = 0x7D200003;
+const uint32_t w1in_id_p = 0x7D200004;
 #endif
 
 void Spake2p_Finish_HSM(hsm_pake_context_t * phsm_pake_context)
@@ -71,7 +71,7 @@
     uint8_t create_crypto_obj = 1;
 #endif
 
-    ChipLogProgress(Crypto, "Using Object Id --> %d \n", spakeObjectId);
+    ChipLogProgress(Crypto, "SE05x: Using Object Id --> %d", spakeObjectId);
 
     if (spakeObjectId != 0)
     {
@@ -124,7 +124,7 @@
 {
     SE05x_CryptoObjectID_t spakeObjectId = phsm_pake_context->spake_objId;
 
-    ChipLogProgress(Crypto, "Using HSM for spake2p ComputeRoundOne \n");
+    ChipLogProgress(Crypto, "SE05x: Using HSM for spake2p ComputeRoundOne");
 
     VerifyOrReturnError(out != nullptr, CHIP_ERROR_INVALID_ARGUMENT);
     VerifyOrReturnError(out_len != nullptr, CHIP_ERROR_INVALID_ARGUMENT);
@@ -156,7 +156,7 @@
     VerifyOrReturnError(pKeyKe != nullptr, CHIP_ERROR_INVALID_ARGUMENT);
     VerifyOrReturnError(pkeyKeLen != nullptr, CHIP_ERROR_INVALID_ARGUMENT);
 
-    ChipLogProgress(Crypto, "Using HSM for spake2p ComputeRoundTwo \n");
+    ChipLogProgress(Crypto, "SE05x: Using HSM for spake2p ComputeRoundTwo");
 
     const uint8_t * const pab = (role == chip::Crypto::CHIP_SPAKE2P_ROLE::VERIFIER) ? NULL : in;
     const size_t pab_len      = (role == chip::Crypto::CHIP_SPAKE2P_ROLE::VERIFIER) ? 0 : in_len;
@@ -178,7 +178,7 @@
     VerifyOrReturnError(in != nullptr, CHIP_ERROR_INVALID_ARGUMENT);
     VerifyOrReturnError(gex_sss_chip_ctx.ks.session != NULL, CHIP_ERROR_INTERNAL);
 
-    ChipLogProgress(Crypto, "Using HSM for spake2p KeyConfirm \n");
+    ChipLogProgress(Crypto, "SE05x: Using HSM for spake2p KeyConfirm");
 
     uint8_t presult                            = 0;
     const SE05x_CryptoObjectID_t spakeObjectId = phsm_pake_context->spake_objId;
@@ -251,7 +251,7 @@
         VerifyOrReturnError(peer_identity != nullptr, CHIP_ERROR_INVALID_ARGUMENT);
     }
 
-    ChipLogProgress(Crypto, "HSM - BeginVerifier \n");
+    ChipLogProgress(Crypto, "SE05x: HSM - BeginVerifier");
 
     ReturnErrorOnFailure(FELoad(w0in, w0in_len, w0));
     ReturnErrorOnFailure(FEWrite(w0, w0in_mod, w0in_mod_len));
@@ -309,7 +309,7 @@
 
     VerifyOrReturnError(state == CHIP_SPAKE2P_STATE::INIT, CHIP_ERROR_INTERNAL);
 
-    ChipLogProgress(Crypto, "HSM - BeginProver \n");
+    ChipLogProgress(Crypto, "SE05x: HSM - BeginProver");
 
     ReturnErrorOnFailure(FELoad(w0in, w0in_len, w0));
     ReturnErrorOnFailure(FEWrite(w0, w0in_mod, w0in_mod_len));
diff --git a/src/crypto/hsm/nxp/CHIPCryptoPALHsm_SE05X_utils.h b/src/crypto/hsm/nxp/CHIPCryptoPALHsm_SE05X_utils.h
index 2169ffd..e5e3bb1 100644
--- a/src/crypto/hsm/nxp/CHIPCryptoPALHsm_SE05X_utils.h
+++ b/src/crypto/hsm/nxp/CHIPCryptoPALHsm_SE05X_utils.h
@@ -42,11 +42,11 @@
 enum keyid_values
 {
     kKeyId_NotInitialized           = 0,
-    kKeyId_pbkdf2_sha256_hmac_keyid = 0xBCBCBCBC,
+    kKeyId_pbkdf2_sha256_hmac_keyid = 0x7D000000,
     kKeyId_hkdf_sha256_hmac_keyid,
     kKeyId_hmac_sha256_keyid,
     kKeyId_sha256_ecc_pub_keyid,
-    kKeyId_operational_key_keyid,
+    kKeyId_case_ephemeral_keyid,
 };
 
 // Enable the below macro to make spake HSM imlementation reentrant.
diff --git a/src/crypto/hsm/nxp/PersistentStorageOperationalKeystoreHSM.cpp b/src/crypto/hsm/nxp/PersistentStorageOperationalKeystoreHSM.cpp
new file mode 100644
index 0000000..abe0f8e
--- /dev/null
+++ b/src/crypto/hsm/nxp/PersistentStorageOperationalKeystoreHSM.cpp
@@ -0,0 +1,274 @@
+/*
+ *    Copyright (c) 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 "PersistentStorageOperationalKeystoreHSM.h"
+#include "CHIPCryptoPALHsm_SE05X_utils.h"
+#include <crypto/hsm/CHIPCryptoPALHsm.h>
+
+#if ENABLE_HSM_GENERATE_EC_KEY
+
+namespace chip {
+
+using namespace chip::Crypto;
+
+#define MAX_KEYID_SLOTS_FOR_FABRICS 32
+#define FABRIC_SE05X_KEYID_START 0x7D100000
+
+/**
+ * Known issues:
+ * 1. The current HSM keystore implementation is tested only with one fabric. To be tested with multiple fabrics.
+ * 2. Logic to read the HSM and create the fabricTable from the persistent keys after reboot is missing .
+ */
+
+struct keyidFabIdMapping_t
+{
+    uint32_t keyId;
+    FabricIndex fabricIndex;
+    bool isPending;
+    Crypto::P256KeypairHSM * pkeyPair;
+} keyidFabIdMapping[MAX_KEYID_SLOTS_FOR_FABRICS] = {
+    0,
+};
+
+uint8_t getEmpytSlotId()
+{
+    uint8_t i = 0;
+    for (auto & mapping : keyidFabIdMapping)
+    {
+        if (mapping.keyId == kKeyId_NotInitialized && mapping.isPending == false)
+        {
+            break;
+        }
+        i++;
+    }
+    return i;
+}
+
+void PersistentStorageOperationalKeystoreHSM::ResetPendingSlot()
+{
+    uint32_t slotId = mPendingKeypair->GetKeyId() - FABRIC_SE05X_KEYID_START;
+    if (slotId < MAX_KEYID_SLOTS_FOR_FABRICS)
+    {
+        keyidFabIdMapping[slotId].keyId       = kKeyId_NotInitialized;
+        keyidFabIdMapping[slotId].fabricIndex = kUndefinedFabricIndex;
+        keyidFabIdMapping[slotId].isPending   = false;
+    }
+}
+
+bool PersistentStorageOperationalKeystoreHSM::HasOpKeypairForFabric(FabricIndex fabricIndex) const
+{
+    VerifyOrReturnError(IsValidFabricIndex(fabricIndex), false);
+
+    // If there was a pending keypair, then there's really a usable key
+    if (mIsPendingKeypairActive && (fabricIndex == mPendingFabricIndex) && (mPendingKeypair != nullptr))
+    {
+        ChipLogProgress(Crypto, "SE05x: HasOpKeypairForFabric ==> mPendingKeypair found");
+        return true;
+    }
+
+    for (auto & mapping : keyidFabIdMapping)
+    {
+        if (mapping.fabricIndex == fabricIndex)
+        {
+            ChipLogProgress(Crypto, "SE05x: HasOpKeypairForFabric ==> stored keyPair found");
+            return true;
+        }
+    }
+
+    ChipLogProgress(Crypto, "SE05x: HasOpKeypairForFabric ==> No key found");
+    return false;
+}
+
+CHIP_ERROR PersistentStorageOperationalKeystoreHSM::NewOpKeypairForFabric(FabricIndex fabricIndex,
+                                                                          MutableByteSpan & outCertificateSigningRequest)
+{
+    CHIP_ERROR err = CHIP_NO_ERROR;
+
+    VerifyOrReturnError(IsValidFabricIndex(fabricIndex), CHIP_ERROR_INVALID_FABRIC_INDEX);
+
+    ChipLogProgress(Crypto, "SE05x: New Op Keypair for Fabric %02x", fabricIndex);
+
+    // Replace previous pending keypair, if any was previously allocated
+    ResetPendingKey();
+
+    uint8_t slotId = getEmpytSlotId();
+    VerifyOrReturnError(slotId < MAX_KEYID_SLOTS_FOR_FABRICS, CHIP_ERROR_NO_MEMORY);
+
+    mPendingKeypair = Platform::New<Crypto::P256KeypairHSM>();
+    VerifyOrReturnError(mPendingKeypair != nullptr, CHIP_ERROR_NO_MEMORY);
+
+    // Key id is created as slotid + start offset of ops key id
+    mPendingKeypair->SetKeyId(FABRIC_SE05X_KEYID_START + slotId);
+
+    err = mPendingKeypair->Initialize();
+    VerifyOrReturnError(err == CHIP_NO_ERROR, CHIP_ERROR_NO_MEMORY);
+
+    mPendingFabricIndex = fabricIndex;
+
+    keyidFabIdMapping[slotId].isPending = true;
+
+    size_t csrLength = outCertificateSigningRequest.size();
+    err              = mPendingKeypair->NewCertificateSigningRequest(outCertificateSigningRequest.data(), csrLength);
+    if (err != CHIP_NO_ERROR)
+    {
+        ResetPendingKey();
+        return err;
+    }
+    outCertificateSigningRequest.reduce_size(csrLength);
+
+    return CHIP_NO_ERROR;
+}
+
+CHIP_ERROR PersistentStorageOperationalKeystoreHSM::ActivateOpKeypairForFabric(FabricIndex fabricIndex,
+                                                                               const Crypto::P256PublicKey & nocPublicKey)
+{
+    ChipLogProgress(Crypto, "SE05x: ActivateOpKeypair for Fabric %02x", fabricIndex);
+
+    VerifyOrReturnError(mPendingKeypair != nullptr, CHIP_ERROR_INVALID_FABRIC_INDEX);
+    VerifyOrReturnError(IsValidFabricIndex(fabricIndex) && (fabricIndex == mPendingFabricIndex), CHIP_ERROR_INVALID_FABRIC_INDEX);
+
+    // Validate public key being activated matches last generated pending keypair
+    VerifyOrReturnError(mPendingKeypair->Pubkey().Matches(nocPublicKey), CHIP_ERROR_INVALID_PUBLIC_KEY);
+
+    mIsPendingKeypairActive = true;
+
+    return CHIP_NO_ERROR;
+}
+
+CHIP_ERROR PersistentStorageOperationalKeystoreHSM::CommitOpKeypairForFabric(FabricIndex fabricIndex)
+{
+    VerifyOrReturnError(mPendingKeypair != nullptr, CHIP_ERROR_INVALID_FABRIC_INDEX);
+    VerifyOrReturnError(IsValidFabricIndex(fabricIndex) && (fabricIndex == mPendingFabricIndex), CHIP_ERROR_INVALID_FABRIC_INDEX);
+    VerifyOrReturnError(mIsPendingKeypairActive == true, CHIP_ERROR_INCORRECT_STATE);
+
+    uint32_t slotId = mPendingKeypair->GetKeyId() - FABRIC_SE05X_KEYID_START;
+
+    VerifyOrReturnError(slotId < MAX_KEYID_SLOTS_FOR_FABRICS, CHIP_ERROR_NO_MEMORY);
+
+    ChipLogProgress(Crypto, "SE05x: CommitOpKeypair for Fabric %02x", fabricIndex);
+
+    for (auto & mapping : keyidFabIdMapping)
+    {
+        if (mapping.fabricIndex == fabricIndex)
+        {
+            // Delete the previous keyPair associated with the fabric
+            mapping.isPending = false;
+            Platform::Delete<Crypto::P256KeypairHSM>(mapping.pkeyPair);
+            mapping.pkeyPair    = NULL;
+            mapping.keyId       = kKeyId_NotInitialized;
+            mapping.fabricIndex = kUndefinedFabricIndex;
+        }
+    }
+
+    keyidFabIdMapping[slotId].pkeyPair    = mPendingKeypair;
+    keyidFabIdMapping[slotId].keyId       = mPendingKeypair->GetKeyId();
+    keyidFabIdMapping[slotId].fabricIndex = mPendingFabricIndex;
+    keyidFabIdMapping[slotId].isPending   = false;
+
+    // If we got here, we succeeded and can reset the pending key: next `SignWithOpKeypair` will use the stored key.
+    mPendingKeypair         = nullptr;
+    mIsPendingKeypairActive = false;
+    mPendingFabricIndex     = kUndefinedFabricIndex;
+
+    return CHIP_NO_ERROR;
+}
+
+CHIP_ERROR PersistentStorageOperationalKeystoreHSM::RemoveOpKeypairForFabric(FabricIndex fabricIndex)
+{
+    VerifyOrReturnError(IsValidFabricIndex(fabricIndex), CHIP_ERROR_INVALID_FABRIC_INDEX);
+
+    ChipLogProgress(Crypto, "SE05x: RemoveOpKeypair for Fabric %02x", fabricIndex);
+
+    // Remove pending state if matching
+    if ((mPendingKeypair != nullptr) && (fabricIndex == mPendingFabricIndex))
+    {
+        RevertPendingKeypair();
+    }
+
+    for (auto & mapping : keyidFabIdMapping)
+    {
+        if (mapping.fabricIndex == fabricIndex)
+        {
+            // Delete the keyPair associated with the fabric
+            mapping.isPending = false;
+            Platform::Delete<Crypto::P256KeypairHSM>(mapping.pkeyPair);
+            mapping.pkeyPair    = NULL;
+            mapping.keyId       = kKeyId_NotInitialized;
+            mapping.fabricIndex = kUndefinedFabricIndex;
+        }
+    }
+
+    return CHIP_NO_ERROR;
+}
+
+void PersistentStorageOperationalKeystoreHSM::RevertPendingKeypair()
+{
+    ChipLogProgress(Crypto, "SE05x: RevertPendingKeypair");
+    // Just reset the pending key, we never stored anything
+    ResetPendingKey();
+}
+
+CHIP_ERROR PersistentStorageOperationalKeystoreHSM::SignWithOpKeypair(FabricIndex fabricIndex, const ByteSpan & message,
+                                                                      Crypto::P256ECDSASignature & outSignature) const
+{
+    ChipLogProgress(Crypto, "SE05x: SignWithOpKeypair");
+
+    if (mIsPendingKeypairActive && (fabricIndex == mPendingFabricIndex))
+    {
+        VerifyOrReturnError(mPendingKeypair != nullptr, CHIP_ERROR_INTERNAL);
+        // We have an override key: sign with it!
+        ChipLogProgress(Crypto, "SE05x: SignWithOpKeypair ==> using mPendingKeypair");
+        return mPendingKeypair->ECDSA_sign_msg(message.data(), message.size(), outSignature);
+    }
+    else
+    {
+        for (auto & mapping : keyidFabIdMapping)
+        {
+            if ((mapping.fabricIndex == fabricIndex) && (mapping.isPending == false))
+            {
+                ChipLogProgress(Crypto, "SE05x: SignWithOpKeypair ==> using stored keyPair");
+                return mapping.pkeyPair->ECDSA_sign_msg(message.data(), message.size(), outSignature);
+            }
+        }
+    }
+
+    ChipLogProgress(Crypto, "SE05x: SignWithOpKeypair ==> No keyPair found");
+    return CHIP_ERROR_INVALID_FABRIC_INDEX;
+}
+
+Crypto::P256Keypair * PersistentStorageOperationalKeystoreHSM::AllocateEphemeralKeypairForCASE()
+{
+    ChipLogProgress(Crypto, "SE05x: AllocateEphemeralKeypairForCASE using se05x");
+    Crypto::P256KeypairHSM * pkeyPair = Platform::New<Crypto::P256KeypairHSM>();
+
+    if (pkeyPair != nullptr)
+    {
+        pkeyPair->SetKeyId(kKeyId_case_ephemeral_keyid);
+    }
+
+    return pkeyPair;
+}
+
+void PersistentStorageOperationalKeystoreHSM::ReleaseEphemeralKeypair(Crypto::P256Keypair * keypair)
+{
+    ChipLogProgress(Crypto, "SE05x: ReleaseEphemeralKeypair using se05x");
+    Platform::Delete(static_cast<Crypto::P256KeypairHSM *>(keypair));
+}
+
+} // namespace chip
+
+#endif //#if ENABLE_HSM_GENERATE_EC_KEY
diff --git a/src/crypto/hsm/nxp/PersistentStorageOperationalKeystoreHSM.h b/src/crypto/hsm/nxp/PersistentStorageOperationalKeystoreHSM.h
new file mode 100644
index 0000000..bc00fea
--- /dev/null
+++ b/src/crypto/hsm/nxp/PersistentStorageOperationalKeystoreHSM.h
@@ -0,0 +1,99 @@
+/*
+ *    Copyright (c) 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.
+ */
+
+#pragma once
+
+#include "CHIPCryptoPALHsm_SE05X_utils.h"
+#include <crypto/OperationalKeystore.h>
+#include <lib/core/CHIPError.h>
+#include <lib/core/CHIPPersistentStorageDelegate.h>
+#include <lib/core/DataModelTypes.h>
+#include <lib/support/CHIPMem.h>
+#include <lib/support/CodeUtils.h>
+
+#if ENABLE_HSM_GENERATE_EC_KEY
+
+namespace chip {
+
+class PersistentStorageOperationalKeystoreHSM : public Crypto::OperationalKeystore
+{
+public:
+    PersistentStorageOperationalKeystoreHSM() = default;
+    virtual ~PersistentStorageOperationalKeystoreHSM() { Finish(); }
+
+    // Non-copyable
+    PersistentStorageOperationalKeystoreHSM(PersistentStorageOperationalKeystoreHSM const &) = delete;
+    void operator=(PersistentStorageOperationalKeystoreHSM const &) = delete;
+
+    /**
+     * @brief Initialize the Operational Keystore for HSM.
+     *
+     * @param storage Pointer to persistent storage delegate to use. Must outlive this instance.
+     * @retval CHIP_NO_ERROR on success
+     * @retval CHIP_ERROR_INCORRECT_STATE if already initialized
+     */
+    CHIP_ERROR Init(PersistentStorageDelegate * storage)
+    {
+        IgnoreUnusedVariable(storage);
+        mPendingFabricIndex     = kUndefinedFabricIndex;
+        mPendingKeypair         = nullptr;
+        mIsPendingKeypairActive = false;
+        return CHIP_NO_ERROR;
+    }
+
+    /**
+     * @brief Finalize the keystore, so that subsequent operations fail
+     */
+    void Finish() { ResetPendingKey(); }
+
+    bool HasPendingOpKeypair() const override { return (mPendingKeypair != nullptr); }
+
+    bool HasOpKeypairForFabric(FabricIndex fabricIndex) const override;
+    CHIP_ERROR NewOpKeypairForFabric(FabricIndex fabricIndex, MutableByteSpan & outCertificateSigningRequest) override;
+    CHIP_ERROR ActivateOpKeypairForFabric(FabricIndex fabricIndex, const Crypto::P256PublicKey & nocPublicKey) override;
+    CHIP_ERROR CommitOpKeypairForFabric(FabricIndex fabricIndex) override;
+    CHIP_ERROR RemoveOpKeypairForFabric(FabricIndex fabricIndex) override;
+    void RevertPendingKeypair() override;
+    CHIP_ERROR SignWithOpKeypair(FabricIndex fabricIndex, const ByteSpan & message,
+                                 Crypto::P256ECDSASignature & outSignature) const override;
+    Crypto::P256Keypair * AllocateEphemeralKeypairForCASE() override;
+    void ReleaseEphemeralKeypair(Crypto::P256Keypair * keypair) override;
+
+protected:
+    void ResetPendingSlot();
+
+    void ResetPendingKey()
+    {
+        if (mPendingKeypair != nullptr)
+        {
+            ResetPendingSlot();
+            Platform::Delete(mPendingKeypair);
+        }
+        mPendingKeypair         = nullptr;
+        mIsPendingKeypairActive = false;
+        mPendingFabricIndex     = kUndefinedFabricIndex;
+    }
+
+    // This pending fabric index is `kUndefinedFabricIndex` if there isn't a pending keypair override for a given fabric.
+    FabricIndex mPendingFabricIndex          = kUndefinedFabricIndex;
+    Crypto::P256KeypairHSM * mPendingKeypair = nullptr;
+    bool mIsPendingKeypairActive             = false;
+};
+
+} // namespace chip
+
+#endif //#if ENABLE_HSM_GENERATE_EC_KEY