Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[nrf noup] Migrate Operational Keys from mbedTLS to PSA ITS #374

Merged
merged 2 commits into from
Jan 25, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 0 additions & 4 deletions src/app/server/Server.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -554,11 +554,7 @@ void Server::ResumeSubscriptions()
Credentials::IgnoreCertificateValidityPeriodPolicy Server::sDefaultCertValidityPolicy;

KvsPersistentStorageDelegate CommonCaseDeviceServerInitParams::sKvsPersistenStorageDelegate;
#if CHIP_CRYPTO_PSA
PSAOperationalKeystore CommonCaseDeviceServerInitParams::sPSAOperationalKeystore;
#else
PersistentStorageOperationalKeystore CommonCaseDeviceServerInitParams::sPersistentStorageOperationalKeystore;
#endif
Credentials::PersistentStorageOpCertStore CommonCaseDeviceServerInitParams::sPersistentStorageOpCertStore;
Credentials::GroupDataProviderImpl CommonCaseDeviceServerInitParams::sGroupDataProvider;
app::DefaultTimerDelegate CommonCaseDeviceServerInitParams::sTimerDelegate;
Expand Down
12 changes: 0 additions & 12 deletions src/app/server/Server.h
Original file line number Diff line number Diff line change
Expand Up @@ -40,11 +40,7 @@
#include <credentials/PersistentStorageOpCertStore.h>
#include <crypto/DefaultSessionKeystore.h>
#include <crypto/OperationalKeystore.h>
#if CHIP_CRYPTO_PSA
#include <crypto/PSAOperationalKeystore.h>
#else
#include <crypto/PersistentStorageOperationalKeystore.h>
#endif
#include <inet/InetConfig.h>
#include <lib/core/CHIPConfig.h>
#include <lib/support/SafeInt.h>
Expand Down Expand Up @@ -207,14 +203,10 @@ struct CommonCaseDeviceServerInitParams : public ServerInitParams
// PersistentStorageDelegate "software-based" operational key access injection
if (this->operationalKeystore == nullptr)
{
#if CHIP_CRYPTO_PSA
this->operationalKeystore = &sPSAOperationalKeystore;
#else
// WARNING: PersistentStorageOperationalKeystore::Finish() is never called. It's fine for
// for examples and for now.
ReturnErrorOnFailure(sPersistentStorageOperationalKeystore.Init(this->persistentStorageDelegate));
this->operationalKeystore = &sPersistentStorageOperationalKeystore;
#endif
}

// OpCertStore can be injected but default to persistent storage default
Expand Down Expand Up @@ -270,11 +262,7 @@ struct CommonCaseDeviceServerInitParams : public ServerInitParams

private:
static KvsPersistentStorageDelegate sKvsPersistenStorageDelegate;
#if CHIP_CRYPTO_PSA
static PSAOperationalKeystore sPSAOperationalKeystore;
#else
static PersistentStorageOperationalKeystore sPersistentStorageOperationalKeystore;
#endif
static Credentials::PersistentStorageOpCertStore sPersistentStorageOpCertStore;
static Credentials::GroupDataProviderImpl sGroupDataProvider;
static chip::app::DefaultTimerDelegate sTimerDelegate;
Expand Down
41 changes: 41 additions & 0 deletions src/crypto/OperationalKeystore.h
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,47 @@ class OperationalKeystore
*/
virtual CHIP_ERROR CommitOpKeypairForFabric(FabricIndex fabricIndex) = 0;

/**
* @brief Try to read out the permanently committed operational keypair and save it to the buffer.
*
* @param fabricIndex - FabricIndex from which the keypair will be exported
* @param outKeypair - a reference to P256SerializedKeypair object to store the exported key.
* @retval CHIP_ERROR on success.
* @retval CHIP_ERROR_UNSUPPORTED_CHIP_FEATURE if the key cannot be exported due to security restrictions.
* @retval CHIP_ERROR_NOT_IMPLEMENTED if the exporting is not implemented for the cryptography backend.
* @retval CHIP_ERROR_INVALID_FABRIC_INDEX if provided wrong value of `fabricIndex`.
* @retval CHIP_ERROR_PERSISTED_STORAGE_VALUE_NOT_FOUND if there is no keypair found for `fabricIndex`.
* @retval CHIP_ERROR_BUFFER_TOO_SMALL if `outKeyPair` buffer is too small to store the read out keypair.
* @retval other CHIP_ERROR value on internal storage or cryptography backend errors.
*/
virtual CHIP_ERROR ExportOpKeypairForFabric(FabricIndex fabricIndex, Crypto::P256SerializedKeypair & outKeypair)
{
return CHIP_ERROR_NOT_IMPLEMENTED;
};

/**
* @brief Migrate the operational keypair from another Operational keystore (`operationalKeystore`) implementation to this one.
*
* This method assumes that the operational key for given `fabricIndex` exists in the `operationalKeystore` storage or it has
* been already migrated to the new Operational Storage. If a key for the given `fabricIndex` does not exist in any of those
* keystores, then the method retuns CHIP_ERROR_PERSISTED_STORAGE_VALUE_NOT_FOUND.
*
* @param fabricIndex - FabricIndex for which to migrate the operational key
* @param operationalKeystore - a reference to the operationalKeystore implementation that may contain saved operational key
* for Fabric
* @retval CHIP_ERROR on success
* @retval CHIP_ERROR_UNSUPPORTED_CHIP_FEATURE if the key cannot be exported due to security restrictions.
* @retval CHIP_ERROR_NOT_IMPLEMENTED if the exporting is not implemented for the cryptography backend.
* @retval CHIP_ERROR_INVALID_FABRIC_INDEX if there is no keypair found for `fabricIndex`.
* @retval CHIP_ERROR_PERSISTED_STORAGE_VALUE_NOT_FOUND if there is no keypair found for `fabricIndex`.
* @retval CHIP_ERROR_BUFFER_TOO_SMALL if `keyPair` buffer is too small to store the read out keypair.
* @retval other CHIP_ERROR value on internal storage or crypto engine errors.
*/
virtual CHIP_ERROR MigrateOpKeypairForFabric(FabricIndex fabricIndex, OperationalKeystore & operationalKeystore) const
{
return CHIP_ERROR_NOT_IMPLEMENTED;
};

/**
* @brief Permanently remove the keypair associated with a fabric
*
Expand Down
90 changes: 90 additions & 0 deletions src/crypto/PSAOperationalKeystore.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
*/

#include "PSAOperationalKeystore.h"
#include "PersistentStorageOperationalKeystore.h"

#include <lib/support/CHIPMem.h>

Expand Down Expand Up @@ -135,6 +136,35 @@ CHIP_ERROR PSAOperationalKeystore::NewOpKeypairForFabric(FabricIndex fabricIndex
return CHIP_NO_ERROR;
}

CHIP_ERROR PSAOperationalKeystore::PersistentP256Keypair::Deserialize(P256SerializedKeypair & input)
{
CHIP_ERROR error = CHIP_NO_ERROR;
psa_status_t status = PSA_SUCCESS;
psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT;
psa_key_id_t keyId = 0;
VerifyOrReturnError(input.Length() == mPublicKey.Length() + kP256_PrivateKey_Length, CHIP_ERROR_INVALID_ARGUMENT);

Destroy();

// Type based on ECC with the elliptic curve SECP256r1 -> PSA_ECC_FAMILY_SECP_R1
psa_set_key_type(&attributes, PSA_KEY_TYPE_ECC_KEY_PAIR(PSA_ECC_FAMILY_SECP_R1));
psa_set_key_bits(&attributes, kP256_PrivateKey_Length * 8);
psa_set_key_algorithm(&attributes, PSA_ALG_ECDSA(PSA_ALG_SHA_256));
psa_set_key_usage_flags(&attributes, PSA_KEY_USAGE_SIGN_MESSAGE);
psa_set_key_lifetime(&attributes, PSA_KEY_LIFETIME_PERSISTENT);
psa_set_key_id(&attributes, GetKeyId());

status = psa_import_key(&attributes, input.ConstBytes() + mPublicKey.Length(), kP256_PrivateKey_Length, &keyId);
VerifyOrExit(status == PSA_SUCCESS, error = CHIP_ERROR_INTERNAL);

memcpy(mPublicKey.Bytes(), input.ConstBytes(), mPublicKey.Length());

exit:
psa_reset_key_attributes(&attributes);

return error;
}

CHIP_ERROR PSAOperationalKeystore::ActivateOpKeypairForFabric(FabricIndex fabricIndex, const Crypto::P256PublicKey & nocPublicKey)
{
VerifyOrReturnError(IsValidFabricIndex(fabricIndex) && mPendingFabricIndex == fabricIndex, CHIP_ERROR_INVALID_FABRIC_INDEX);
Expand All @@ -154,6 +184,40 @@ CHIP_ERROR PSAOperationalKeystore::CommitOpKeypairForFabric(FabricIndex fabricIn
return CHIP_NO_ERROR;
}

CHIP_ERROR PSAOperationalKeystore::ExportOpKeypairForFabric(FabricIndex fabricIndex, Crypto::P256SerializedKeypair & outKeypair)
{
// Currently exporting the key is forbidden in PSAOperationalKeystore because the PSA_KEY_USAGE_EXPORT usage flag is not set, so
// there is no need to compile the code for the device, but there should be an implementation for test purposes to verify if
// the psa_export_key returns an error.
#if CHIP_CONFIG_TEST
VerifyOrReturnError(IsValidFabricIndex(fabricIndex), CHIP_ERROR_INVALID_FABRIC_INDEX);
VerifyOrReturnError(HasOpKeypairForFabric(fabricIndex), CHIP_ERROR_PERSISTED_STORAGE_VALUE_NOT_FOUND);

size_t outSize = 0;
psa_status_t status =
psa_export_key(PersistentP256Keypair(fabricIndex).GetKeyId(), outKeypair.Bytes(), outKeypair.Capacity(), &outSize);

if (status == PSA_ERROR_BUFFER_TOO_SMALL)
{
return CHIP_ERROR_BUFFER_TOO_SMALL;
}
else if (status == PSA_ERROR_NOT_PERMITTED)
{
return CHIP_ERROR_UNSUPPORTED_CHIP_FEATURE;
}
else if (status != PSA_SUCCESS)
{
return CHIP_ERROR_INTERNAL;
}

outKeypair.SetLength(outSize);

return CHIP_NO_ERROR;
#else
return CHIP_ERROR_NOT_IMPLEMENTED;
#endif
}

CHIP_ERROR PSAOperationalKeystore::RemoveOpKeypairForFabric(FabricIndex fabricIndex)
{
VerifyOrReturnError(IsValidFabricIndex(fabricIndex), CHIP_ERROR_INVALID_FABRIC_INDEX);
Expand Down Expand Up @@ -209,5 +273,31 @@ void PSAOperationalKeystore::ReleasePendingKeypair()
mIsPendingKeypairActive = false;
}

CHIP_ERROR PSAOperationalKeystore::MigrateOpKeypairForFabric(FabricIndex fabricIndex,
OperationalKeystore & operationalKeystore) const
{
VerifyOrReturnError(IsValidFabricIndex(fabricIndex), CHIP_ERROR_INVALID_FABRIC_INDEX);

P256SerializedKeypair serializedKeypair;

// Do not allow overwriting the existing key and just remove it from the previous Operational Keystore if needed.
if (!HasOpKeypairForFabric(fabricIndex))
{
ReturnErrorOnFailure(operationalKeystore.ExportOpKeypairForFabric(fabricIndex, serializedKeypair));

PersistentP256Keypair keypair(fabricIndex);
ReturnErrorOnFailure(keypair.Deserialize(serializedKeypair));

// Migrated key is not useful anymore, remove it from the previous keystore.
ReturnErrorOnFailure(operationalKeystore.RemoveOpKeypairForFabric(fabricIndex));
}
else if (operationalKeystore.HasOpKeypairForFabric(fabricIndex))
{
ReturnErrorOnFailure(operationalKeystore.RemoveOpKeypairForFabric(fabricIndex));
}

return CHIP_NO_ERROR;
}

} // namespace Crypto
} // namespace chip
5 changes: 5 additions & 0 deletions src/crypto/PSAOperationalKeystore.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@

#include <crypto/CHIPCryptoPALPSA.h>
#include <crypto/OperationalKeystore.h>
#include <lib/core/CHIPPersistentStorageDelegate.h>

namespace chip {
namespace Crypto {
Expand All @@ -31,7 +32,9 @@ class PSAOperationalKeystore final : public OperationalKeystore
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 ExportOpKeypairForFabric(FabricIndex fabricIndex, Crypto::P256SerializedKeypair & outKeypair) override;
CHIP_ERROR RemoveOpKeypairForFabric(FabricIndex fabricIndex) override;
CHIP_ERROR MigrateOpKeypairForFabric(FabricIndex fabricIndex, OperationalKeystore & operationalKeystore) const;
void RevertPendingKeypair() override;
CHIP_ERROR SignWithOpKeypair(FabricIndex fabricIndex, const ByteSpan & message,
Crypto::P256ECDSASignature & outSignature) const override;
Expand All @@ -53,13 +56,15 @@ class PSAOperationalKeystore final : public OperationalKeystore
bool Exists() const;
CHIP_ERROR Generate();
CHIP_ERROR Destroy();
CHIP_ERROR Deserialize(P256SerializedKeypair & input);
};

void ReleasePendingKeypair();

PersistentP256Keypair * mPendingKeypair = nullptr;
FabricIndex mPendingFabricIndex = kUndefinedFabricIndex;
bool mIsPendingKeypairActive = false;
PersistentStorageDelegate * mStorage = nullptr;
};

} // namespace Crypto
Expand Down
Loading
Loading